ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
completions.c File Reference

Implementation of shell completion generation from options registry. More...

Go to the source code of this file.

Functions

asciichat_error_t completions_generate_bash (FILE *output)
 
asciichat_error_t completions_generate_fish (FILE *output)
 
asciichat_error_t completions_generate_zsh (FILE *output)
 
asciichat_error_t completions_generate_powershell (FILE *output)
 
asciichat_error_t completions_generate_for_shell (completion_format_t format, FILE *output)
 
const char * completions_get_shell_name (completion_format_t format)
 
completion_format_t completions_parse_shell_name (const char *shell_name)
 
option_descriptor_t * completions_collect_all_modes_unique (size_t *count)
 Collect options from all modes with deduplication.
 

Detailed Description

Implementation of shell completion generation from options registry.

Definition in file completions.c.

Function Documentation

◆ completions_collect_all_modes_unique()

option_descriptor_t * completions_collect_all_modes_unique ( size_t *  count)

Collect options from all modes with deduplication.

Iterates through all completion modes (MODE_DISCOVERY, MODE_SERVER, MODE_CLIENT, MODE_MIRROR, MODE_DISCOVERY_SERVICE) and collects unique options by long_name. Useful for generators that need to show completions for options across multiple modes.

Parameters
[out]countPointer to receive the count of unique options
Returns
Dynamically allocated array of option_descriptor_t, must be freed by caller. Returns NULL if no options found.
Note
The caller must free the returned pointer with SAFE_FREE()

Definition at line 96 of file completions.c.

96 {
97 if (!count) {
98 return NULL;
99 }
100
101 option_descriptor_t *combined_opts = NULL;
102 size_t combined_count = 0;
103
104 /* All completion modes to iterate through */
105 asciichat_mode_t modes[] = {MODE_DISCOVERY, MODE_SERVER, MODE_CLIENT, MODE_MIRROR, MODE_DISCOVERY_SERVICE};
106 const size_t modes_len = sizeof(modes) / sizeof(modes[0]);
107
108 for (size_t m = 0; m < modes_len; m++) {
109 size_t mode_count = 0;
110 const option_descriptor_t *mode_opts = options_registry_get_for_mode(modes[m], &mode_count);
111 if (mode_opts) {
112 /* Collect unique options by long_name */
113 for (size_t i = 0; i < mode_count; i++) {
114 bool already_has = false;
115 for (size_t j = 0; j < combined_count; j++) {
116 if (strcmp(combined_opts[j].long_name, mode_opts[i].long_name) == 0) {
117 already_has = true;
118 break;
119 }
120 }
121 if (!already_has) {
122 combined_count++;
123 option_descriptor_t *temp = (option_descriptor_t *)SAFE_REALLOC(
124 combined_opts, combined_count * sizeof(option_descriptor_t), option_descriptor_t *);
125 if (temp) {
126 combined_opts = temp;
127 combined_opts[combined_count - 1] = mode_opts[i];
128 }
129 }
130 }
131 SAFE_FREE(mode_opts);
132 }
133 }
134
135 *count = combined_count;
136 return combined_opts;
137}
const option_descriptor_t * options_registry_get_for_mode(asciichat_mode_t mode, size_t *num_options)
Definition public_api.c:217

References options_registry_get_for_mode().

◆ completions_generate_bash()

asciichat_error_t completions_generate_bash ( FILE *  output)

Definition at line 367 of file bash.c.

367 {
368 if (!output) {
369 return SET_ERRNO(ERROR_INVALID_PARAM, "Output stream cannot be NULL");
370 }
371
372 bash_write_header(output);
373 asciichat_error_t err = bash_write_all_options(output);
374 if (err != ASCIICHAT_OK) {
375 return err;
376 }
377 bash_write_completion_logic(output);
378 bash_write_footer(output);
379
380 return ASCIICHAT_OK;
381}

Referenced by completions_generate_for_shell().

◆ completions_generate_fish()

asciichat_error_t completions_generate_fish ( FILE *  output)

Definition at line 130 of file fish.c.

130 {
131 if (!output) {
132 return SET_ERRNO(ERROR_INVALID_PARAM, "Output stream cannot be NULL");
133 }
134
135 fprintf(output,
136 "# Fish completion script for ascii-chat\n"
137 "# Generated from options registry - DO NOT EDIT MANUALLY\n"
138 "\n"
139 "complete -c ascii-chat -f\n"
140 "\n"
141 "function __fish_ascii_chat_using_mode\n"
142 " set -l cmd (commandline -opc)\n"
143 " for arg in $cmd\n"
144 " if contains -- $arg server client mirror\n"
145 " echo $arg\n"
146 " return 0\n"
147 " end\n"
148 " end\n"
149 " return 1\n"
150 "end\n"
151 "\n"
152 "function __fish_ascii_chat_mode_is\n"
153 " test (string match -q $argv[1] (command __fish_ascii_chat_using_mode))\n"
154 "end\n"
155 "\n"
156 "function __fish_ascii_chat_no_mode\n"
157 " not __fish_ascii_chat_using_mode > /dev/null\n"
158 "end\n"
159 "\n"
160 "# Modes\n"
161 "complete -c ascii-chat -n __fish_ascii_chat_no_mode -a server -d 'Run a video chat server'\n"
162 "complete -c ascii-chat -n __fish_ascii_chat_no_mode -a client -d 'Connect to a video chat server'\n"
163 "complete -c ascii-chat -n __fish_ascii_chat_no_mode -a mirror -d 'View webcam locally without network'\n"
164 "\n");
165
166 /* Binary options - use unified display API matching help system */
167 size_t binary_count = 0;
168 const option_descriptor_t *binary_opts = options_registry_get_for_display(MODE_DISCOVERY, true, &binary_count);
169
170 fprintf(output, "# Binary-level options (same as 'ascii-chat --help')\n");
171 if (binary_opts) {
172 for (size_t i = 0; i < binary_count; i++) {
173 fish_write_option(output, &binary_opts[i], "");
174 }
175 SAFE_FREE(binary_opts);
176 }
177 fprintf(output, "\n");
178
179 /* Server options - use unified display API matching help system */
180 size_t server_count = 0;
181 const option_descriptor_t *server_opts = options_registry_get_for_display(MODE_SERVER, false, &server_count);
182
183 fprintf(output, "# Server options (same as 'ascii-chat server --help')\n");
184 if (server_opts) {
185 for (size_t i = 0; i < server_count; i++) {
186 fish_write_option(output, &server_opts[i], "-n '__fish_seen_subcommand_from server'");
187 }
188 SAFE_FREE(server_opts);
189 }
190 fprintf(output, "\n");
191
192 /* Client options - use unified display API matching help system */
193 size_t client_count = 0;
194 const option_descriptor_t *client_opts = options_registry_get_for_display(MODE_CLIENT, false, &client_count);
195
196 fprintf(output, "# Client options (same as 'ascii-chat client --help')\n");
197 if (client_opts) {
198 for (size_t i = 0; i < client_count; i++) {
199 fish_write_option(output, &client_opts[i], "-n '__fish_seen_subcommand_from client'");
200 }
201 SAFE_FREE(client_opts);
202 }
203 fprintf(output, "\n");
204
205 /* Mirror options - use unified display API matching help system */
206 size_t mirror_count = 0;
207 const option_descriptor_t *mirror_opts = options_registry_get_for_display(MODE_MIRROR, false, &mirror_count);
208
209 fprintf(output, "# Mirror options (same as 'ascii-chat mirror --help')\n");
210 if (mirror_opts) {
211 for (size_t i = 0; i < mirror_count; i++) {
212 fish_write_option(output, &mirror_opts[i], "-n '__fish_seen_subcommand_from mirror'");
213 }
214 SAFE_FREE(mirror_opts);
215 }
216 fprintf(output, "\n");
217
218 /* Discovery-service options */
219 size_t discovery_svc_count = 0;
220 const option_descriptor_t *discovery_svc_opts =
221 options_registry_get_for_display(MODE_DISCOVERY_SERVICE, false, &discovery_svc_count);
222
223 fprintf(output, "# Discovery-service options (same as 'ascii-chat discovery-service --help')\n");
224 if (discovery_svc_opts) {
225 for (size_t i = 0; i < discovery_svc_count; i++) {
226 fish_write_option(output, &discovery_svc_opts[i], "-n '__fish_seen_subcommand_from discovery-service'");
227 }
228 SAFE_FREE(discovery_svc_opts);
229 }
230
231 return ASCIICHAT_OK;
232}
const option_descriptor_t * options_registry_get_for_display(asciichat_mode_t mode, bool for_binary_help, size_t *num_options)
Definition public_api.c:323

References options_registry_get_for_display().

Referenced by completions_generate_for_shell().

◆ completions_generate_for_shell()

asciichat_error_t completions_generate_for_shell ( completion_format_t  format,
FILE *  output 
)

Definition at line 20 of file completions.c.

20 {
21 if (!output) {
22 return SET_ERRNO(ERROR_INVALID_PARAM, "Output stream cannot be NULL");
23 }
24
25 switch (format) {
26 case COMPLETION_FORMAT_BASH:
27 return completions_generate_bash(output);
28 case COMPLETION_FORMAT_FISH:
29 return completions_generate_fish(output);
30 case COMPLETION_FORMAT_ZSH:
31 return completions_generate_zsh(output);
32 case COMPLETION_FORMAT_POWERSHELL:
34 default:
35 return SET_ERRNO(ERROR_INVALID_PARAM, "Unknown completion format: %d", format);
36 }
37}
asciichat_error_t completions_generate_bash(FILE *output)
Definition bash.c:367
asciichat_error_t completions_generate_powershell(FILE *output)
Definition powershell.c:130
asciichat_error_t completions_generate_fish(FILE *output)
Definition fish.c:130
asciichat_error_t completions_generate_zsh(FILE *output)
Definition zsh.c:105

References completions_generate_bash(), completions_generate_fish(), completions_generate_powershell(), and completions_generate_zsh().

Referenced by action_completions().

◆ completions_generate_powershell()

asciichat_error_t completions_generate_powershell ( FILE *  output)

Definition at line 130 of file powershell.c.

130 {
131 if (!output) {
132 return SET_ERRNO(ERROR_INVALID_PARAM, "Output stream cannot be NULL");
133 }
134
135 fprintf(output, "# PowerShell completion script for ascii-chat\n"
136 "# Generated from options registry - DO NOT EDIT MANUALLY\n"
137 "# Usage: ascii-chat --completions powershell | Out-String | Invoke-Expression\n"
138 "\n"
139 "$script:AsciiChatCompleter = {\n"
140 " param($wordToComplete, $commandAst, $cursorPosition)\n"
141 "\n"
142 " $words = @($commandAst.CommandElements | ForEach-Object { $_.Value })\n"
143 " $mode = $null\n"
144 "\n"
145 " foreach ($word in $words) {\n"
146 " if ($word -in @('server', 'client', 'mirror')) {\n"
147 " $mode = $word\n"
148 " break\n"
149 " }\n"
150 " }\n"
151 "\n"
152 " $binaryOptions = @(\n");
153
154 /* Binary options - use unified display API matching help system */
155 size_t binary_count = 0;
156 const option_descriptor_t *binary_opts = options_registry_get_for_display(MODE_DISCOVERY, true, &binary_count);
157
158 if (binary_opts) {
159 for (size_t i = 0; i < binary_count; i++) {
160 ps_write_option(output, &binary_opts[i]);
161 }
162 SAFE_FREE(binary_opts);
163 }
164
165 fprintf(output, " )\n\n $serverOptions = @(\n");
166
167 /* Server options - use unified display API matching help system */
168 size_t server_count = 0;
169 const option_descriptor_t *server_opts = options_registry_get_for_display(MODE_SERVER, false, &server_count);
170
171 if (server_opts) {
172 for (size_t i = 0; i < server_count; i++) {
173 ps_write_option(output, &server_opts[i]);
174 }
175 SAFE_FREE(server_opts);
176 }
177
178 fprintf(output, " )\n\n $clientOptions = @(\n");
179
180 /* Client options - use unified display API matching help system */
181 size_t client_count = 0;
182 const option_descriptor_t *client_opts = options_registry_get_for_display(MODE_CLIENT, false, &client_count);
183
184 if (client_opts) {
185 for (size_t i = 0; i < client_count; i++) {
186 ps_write_option(output, &client_opts[i]);
187 }
188 SAFE_FREE(client_opts);
189 }
190
191 fprintf(output, " )\n\n $mirrorOptions = @(\n");
192
193 /* Mirror options - use unified display API matching help system */
194 size_t mirror_count = 0;
195 const option_descriptor_t *mirror_opts = options_registry_get_for_display(MODE_MIRROR, false, &mirror_count);
196
197 if (mirror_opts) {
198 for (size_t i = 0; i < mirror_count; i++) {
199 ps_write_option(output, &mirror_opts[i]);
200 }
201 SAFE_FREE(mirror_opts);
202 }
203
204 fprintf(output, " )\n\n $discoverySvcOptions = @(\n");
205
206 /* Discovery-service options */
207 size_t discovery_svc_count = 0;
208 const option_descriptor_t *discovery_svc_opts =
209 options_registry_get_for_display(MODE_DISCOVERY_SERVICE, false, &discovery_svc_count);
210
211 if (discovery_svc_opts) {
212 for (size_t i = 0; i < discovery_svc_count; i++) {
213 ps_write_option(output, &discovery_svc_opts[i]);
214 }
215 SAFE_FREE(discovery_svc_opts);
216 }
217
218 fprintf(output,
219 " )\n"
220 "\n"
221 " $options = $binaryOptions\n"
222 " \n"
223 " if ($mode -eq 'server') {\n"
224 " $options += $serverOptions\n"
225 " } elseif ($mode -eq 'client') {\n"
226 " $options += $clientOptions\n"
227 " } elseif ($mode -eq 'mirror') {\n"
228 " $options += $mirrorOptions\n"
229 " } elseif ($mode -eq 'discovery-service') {\n"
230 " $options += $discoverySvcOptions\n"
231 " }\n"
232 "\n"
233 " if (-not $mode -and -not $wordToComplete.StartsWith('-')) {\n"
234 " @('server', 'client', 'mirror', 'discovery-service') | Where-Object { $_ -like \"$wordToComplete*\" } | "
235 "ForEach-Object {\n"
236 " [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', \"Mode: $_\")\n"
237 " }\n"
238 " } else {\n"
239 " $options | Where-Object { $_.Name -like \"$wordToComplete*\" } | ForEach-Object {\n"
240 " if ($_.Values) {\n"
241 " $_.Values | ForEach-Object {\n"
242 " [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_.Description)\n"
243 " }\n"
244 " } else {\n"
245 " [System.Management.Automation.CompletionResult]::new($_.Name, $_.Name, 'ParameterValue', "
246 "$_.Description)\n"
247 " }\n"
248 " }\n"
249 " }\n"
250 "}\n"
251 "\n"
252 "Register-ArgumentCompleter -CommandName ascii-chat -ScriptBlock $script:AsciiChatCompleter\n");
253
254 return ASCIICHAT_OK;
255}

References options_registry_get_for_display().

Referenced by completions_generate_for_shell().

◆ completions_generate_zsh()

asciichat_error_t completions_generate_zsh ( FILE *  output)

Definition at line 105 of file zsh.c.

105 {
106 if (!output) {
107 return SET_ERRNO(ERROR_INVALID_PARAM, "Output stream cannot be NULL");
108 }
109
110 fprintf(output, "#compdef _ascii_chat ascii-chat\n"
111#ifndef NDEBUG
112 "#compdef _ascii_chat build/bin/ascii-chat ./build/bin/ascii-chat\n"
113#endif
114 "# Zsh completion script for ascii-chat\n"
115 "# Generated from options registry - DO NOT EDIT MANUALLY\n"
116 "\n"
117 "_ascii_chat() {\n"
118 " local curcontext=\"$curcontext\" state line\n"
119 " _arguments -C \\\n");
120
121 /* Binary options - use unified display API matching help system */
122 size_t binary_count = 0;
123 const option_descriptor_t *binary_opts = options_registry_get_for_display(MODE_DISCOVERY, true, &binary_count);
124
125 if (binary_opts) {
126 for (size_t i = 0; i < binary_count; i++) {
127 zsh_write_option(output, &binary_opts[i]);
128 }
129 SAFE_FREE(binary_opts);
130 }
131
132 fprintf(output, " '1:mode:(server client mirror discovery-service)' \\\n"
133 " '*::mode args:_ascii_chat_subcommand'\n"
134 "}\n"
135 "\n"
136 "_ascii_chat_subcommand() {\n"
137 " case $line[1] in\n"
138 " server)\n"
139 " _arguments \\\n");
140
141 /* Server options - use unified display API matching help system */
142 size_t server_count = 0;
143 const option_descriptor_t *server_opts = options_registry_get_for_display(MODE_SERVER, false, &server_count);
144
145 if (server_opts) {
146 for (size_t i = 0; i < server_count; i++) {
147 zsh_write_option(output, &server_opts[i]);
148 }
149 SAFE_FREE(server_opts);
150 }
151
152 fprintf(output, " && return 0\n"
153 " ;;\n"
154 " client)\n"
155 " _arguments \\\n");
156
157 /* Client options - use unified display API matching help system */
158 size_t client_count = 0;
159 const option_descriptor_t *client_opts = options_registry_get_for_display(MODE_CLIENT, false, &client_count);
160
161 if (client_opts) {
162 for (size_t i = 0; i < client_count; i++) {
163 zsh_write_option(output, &client_opts[i]);
164 }
165 SAFE_FREE(client_opts);
166 }
167
168 fprintf(output, " && return 0\n"
169 " ;;\n"
170 " mirror)\n"
171 " _arguments \\\n");
172
173 /* Mirror options - use unified display API matching help system */
174 size_t mirror_count = 0;
175 const option_descriptor_t *mirror_opts = options_registry_get_for_display(MODE_MIRROR, false, &mirror_count);
176
177 if (mirror_opts) {
178 for (size_t i = 0; i < mirror_count; i++) {
179 zsh_write_option(output, &mirror_opts[i]);
180 }
181 SAFE_FREE(mirror_opts);
182 }
183
184 fprintf(output, " && return 0\n"
185 " ;;\n"
186 " discovery-service)\n"
187 " _arguments \\\n");
188
189 /* Discovery-service options */
190 size_t discovery_svc_count = 0;
191 const option_descriptor_t *discovery_svc_opts =
192 options_registry_get_for_display(MODE_DISCOVERY_SERVICE, false, &discovery_svc_count);
193
194 if (discovery_svc_opts) {
195 for (size_t i = 0; i < discovery_svc_count; i++) {
196 zsh_write_option(output, &discovery_svc_opts[i]);
197 }
198 SAFE_FREE(discovery_svc_opts);
199 }
200
201 fprintf(output, " && return 0\n"
202 " ;;\n"
203 " esac\n"
204 "}\n"
205 "\n"
206 "_ascii_chat \"$@\"\n");
207
208 return ASCIICHAT_OK;
209}

References options_registry_get_for_display().

Referenced by completions_generate_for_shell().

◆ completions_get_shell_name()

const char * completions_get_shell_name ( completion_format_t  format)

Definition at line 39 of file completions.c.

39 {
40 switch (format) {
41 case COMPLETION_FORMAT_BASH:
42 return "bash";
43 case COMPLETION_FORMAT_FISH:
44 return "fish";
45 case COMPLETION_FORMAT_ZSH:
46 return "zsh";
47 case COMPLETION_FORMAT_POWERSHELL:
48 return "powershell";
49 default:
50 return "unknown";
51 }
52}

Referenced by action_completions().

◆ completions_parse_shell_name()

completion_format_t completions_parse_shell_name ( const char *  shell_name)

Definition at line 54 of file completions.c.

54 {
55 if (!shell_name) {
56 return COMPLETION_FORMAT_UNKNOWN;
57 }
58
59 /* Convert to lowercase for case-insensitive matching */
60 char lower[32] = {0};
61 size_t len = strlen(shell_name);
62 if (len >= sizeof(lower)) {
63 return COMPLETION_FORMAT_UNKNOWN;
64 }
65
66 for (size_t i = 0; i < len; i++) {
67 lower[i] = tolower((unsigned char)shell_name[i]);
68 }
69
70 if (strcmp(lower, "bash") == 0) {
71 return COMPLETION_FORMAT_BASH;
72 } else if (strcmp(lower, "fish") == 0) {
73 return COMPLETION_FORMAT_FISH;
74 } else if (strcmp(lower, "zsh") == 0) {
75 return COMPLETION_FORMAT_ZSH;
76 } else if (strcmp(lower, "powershell") == 0 || strcmp(lower, "ps") == 0) {
77 return COMPLETION_FORMAT_POWERSHELL;
78 }
79
80 return COMPLETION_FORMAT_UNKNOWN;
81}

Referenced by action_completions().