ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
zsh.h File Reference

Zsh shell completion generator. More...

Go to the source code of this file.

Functions

asciichat_error_t completions_generate_zsh (FILE *output)
 Generate zsh completion script.
 

Detailed Description

Zsh shell completion generator.

Definition in file zsh.h.

Function Documentation

◆ completions_generate_zsh()

asciichat_error_t completions_generate_zsh ( FILE *  output)

Generate zsh completion script.

Definition at line 210 of file zsh.c.

210 {
211 if (!output) {
212 return SET_ERRNO(ERROR_INVALID_PARAM, "Output stream cannot be NULL");
213 }
214
215 /* Load binary-level and discovery options for binary-level completion.
216 * Binary-level completion (options before mode name like --color-mode) uses
217 * _arguments with -n -S flags to establish proper zsh completion context.
218 * Without _arguments, completion functions fail with "can only be called from
219 * completion function" error, causing zsh to display "corrections (errors: N)"
220 * messages. The -n flag disables defaults and -S disables short option
221 * processing, allowing safe context establishment. */
222 size_t binary_count = 0;
223 const option_descriptor_t *binary_opts = options_registry_get_for_display(MODE_DISCOVERY, true, &binary_count);
224
225 size_t discovery_count = 0;
226 const option_descriptor_t *discovery_opts = options_registry_get_for_display(MODE_DISCOVERY, false, &discovery_count);
227
228 fprintf(output, "# Zsh completion script for ascii-chat\n"
229 "# Generated from options registry - DO NOT EDIT MANUALLY\n"
230 "\n"
231 "# Configure completion for ascii-chat\n"
232 "# Use only _complete (no corrections or approximate matching)\n"
233 "zstyle ':completion:*:ascii-chat:*' completer _complete\n"
234 "\n"
235 "# Device index completion helpers\n"
236 "_ascii_chat_webcam_indices() {\n"
237 " local -a indices\n"
238 " local output\n"
239 " output=$(\"${words[1]}\" --list-webcams 2>/dev/null) || return\n"
240 " while IFS= read -r line; do\n"
241 " [[ \"$line\" =~ ^[[:space:]]*([0-9]+)[[:space:]]+(.+)$ ]] && \\\n"
242 " indices+=(\"${match[1]}:${match[2]}\")\n"
243 " done <<< \"$output\"\n"
244 " _describe 'webcam' indices\n"
245 "}\n"
246 "\n"
247 "_ascii_chat_microphone_indices() {\n"
248 " local -a indices\n"
249 " local output\n"
250 " output=$(\"${words[1]}\" --list-microphones 2>/dev/null) || return\n"
251 " while IFS= read -r line; do\n"
252 " [[ \"$line\" =~ ^[[:space:]]*([0-9-]+)[[:space:]]+(.+)$ ]] && \\\n"
253 " indices+=(\"${match[1]}:${match[2]}\")\n"
254 " done <<< \"$output\"\n"
255 " _describe 'microphone' indices\n"
256 "}\n"
257 "\n"
258 "_ascii_chat_speakers_indices() {\n"
259 " local -a indices\n"
260 " local output\n"
261 " output=$(\"${words[1]}\" --list-speakers 2>/dev/null) || return\n"
262 " while IFS= read -r line; do\n"
263 " [[ \"$line\" =~ ^[[:space:]]*([0-9-]+)[[:space:]]+(.+)$ ]] && \\\n"
264 " indices+=(\"${match[1]}:${match[2]}\")\n"
265 " done <<< \"$output\"\n"
266 " _describe 'speakers' indices\n"
267 "}\n"
268 "\n"
269 "_ascii_chat_binary() {\n"
270 " local -a binary_opts=(\n");
271
272 /* Add discovery options to binary-level completion */
273 if (discovery_opts) {
274 for (size_t i = 0; i < discovery_count; i++) {
275 fprintf(output, " '--%s:", discovery_opts[i].long_name);
276 zsh_escape_desc(output, discovery_opts[i].help_text);
277 fprintf(output, "'\n");
278 }
279 }
280
281 fprintf(output, " )\n"
282 " _values 'option' \"${binary_opts[@]}\"\n"
283 "}\n"
284 "\n"
285 "_ascii_chat_binary_grouped() {\n"
286 " local curcontext=$curcontext\n"
287 " local -a context line state state_descr args\n"
288 " local -A opt_args\n\n");
289
290 /* Write binary-level options in grouped format */
291 if (binary_opts) {
292 zsh_write_combined_args(output, binary_opts, binary_count);
293 }
294
295 fprintf(output, "}\n"
296 "\n"
297 "_ascii_chat() {\n"
298 " if [[ ${words[2]} == -* ]]; then\n"
299 " # Binary-level options: show both binary and discovery mode options\n"
300 " # (since discovery is the default mode that runs at binary level)\n"
301 " _ascii_chat_binary_grouped\n"
302 " _ascii_chat_discovery\n"
303 " return\n"
304 " fi\n"
305 "\n"
306 " # Mode routing: check words[2] to determine which mode function to call\n"
307 " case $words[2] in\n"
308 " # Server-like modes\n"
309 " server)\n"
310 " _ascii_chat_server\n"
311 " return\n"
312 " ;;\n"
313 " discovery-service)\n"
314 " _ascii_chat_discovery_service\n"
315 " return\n"
316 " ;;\n"
317 "\n"
318 " # Client-like modes\n"
319 " client)\n"
320 " _ascii_chat_client\n"
321 " return\n"
322 " ;;\n"
323 " mirror)\n"
324 " _ascii_chat_mirror\n"
325 " return\n"
326 " ;;\n"
327 " # Default/unknown input - show mode selection only if truly empty, otherwise discovery\n"
328 " *)\n"
329 " # If words[2] is empty AND we're at position 2, show mode selection\n"
330 " # Otherwise (even for partial input like 'disc'), use discovery mode (the default)\n"
331 " if [[ -z \"${words[2]}\" && $CURRENT -eq 2 ]]; then\n"
332 " # Completing the mode name itself - show available modes\n"
333 " local -a server_modes client_modes\n"
334 " server_modes=(\n");
335
336 /* Generate server-like modes from registry */
337 size_t mode_server_count = 0;
338 const mode_descriptor_t *mode_server_descs = get_modes_by_group("server-like", &mode_server_count);
339 if (mode_server_descs) {
340 for (size_t i = 0; i < mode_server_count; i++) {
341 fprintf(output, " '%s:%s'\n", mode_server_descs[i].name, mode_server_descs[i].description);
342 }
343 SAFE_FREE(mode_server_descs);
344 }
345
346 fprintf(output, " )\n"
347 " client_modes=(\n");
348
349 /* Generate client-like modes from registry (exclude discovery since it's the default mode) */
350 size_t mode_client_count = 0;
351 const mode_descriptor_t *mode_client_descs = get_modes_by_group("client-like", &mode_client_count);
352 if (mode_client_descs) {
353 for (size_t i = 0; i < mode_client_count; i++) {
354 /* Skip discovery mode - it's the default when no mode is specified */
355 if (strcmp(mode_client_descs[i].name, "discovery") == 0) {
356 continue;
357 }
358 fprintf(output, " '%s:%s'\n", mode_client_descs[i].name, mode_client_descs[i].description);
359 }
360 SAFE_FREE(mode_client_descs);
361 }
362
363 fprintf(output, " )\n"
364 " _describe -t server-modes 'server-like modes' server_modes\n"
365 " _describe -t client-modes 'client-like modes' client_modes\n"
366 " else\n"
367 " # Default mode (discovery) - complete its options\n"
368 " _ascii_chat_discovery\n"
369 " fi\n"
370 " ;;\n"
371 " esac\n"
372 "}\n"
373 "\n"
374 "# Server-like modes: handle incoming connections and stream management\n"
375 "_ascii_chat_server() {\n"
376 " local curcontext=$curcontext\n"
377 " local -a context line state state_descr args\n"
378 " local -A opt_args\n\n");
379
380 /* Server options - grouped by category */
381 size_t server_count = 0;
382 const option_descriptor_t *server_opts = options_registry_get_for_display(MODE_SERVER, false, &server_count);
383
384 if (server_opts) {
385 zsh_write_combined_args(output, server_opts, server_count);
386 SAFE_FREE(server_opts);
387 }
388
389 fprintf(output, "}\n"
390 "\n"
391 "_ascii_chat_discovery_service() {\n"
392 " local curcontext=$curcontext\n"
393 " local -a context line state state_descr args\n"
394 " local -A opt_args\n\n");
395
396 /* Discovery-service options - grouped by category */
397 size_t discovery_svc_count = 0;
398 const option_descriptor_t *discovery_svc_opts =
399 options_registry_get_for_display(MODE_DISCOVERY_SERVICE, false, &discovery_svc_count);
400
401 if (discovery_svc_opts) {
402 zsh_write_combined_args(output, discovery_svc_opts, discovery_svc_count);
403 SAFE_FREE(discovery_svc_opts);
404 }
405
406 fprintf(output, "}\n"
407 "\n"
408 "# Client-like modes: connect to servers or render local media\n"
409 "_ascii_chat_client() {\n"
410 " local curcontext=$curcontext\n"
411 " local -a context line state state_descr args\n"
412 " local -A opt_args\n\n");
413
414 /* Client options - grouped by category */
415 size_t client_count = 0;
416 const option_descriptor_t *client_opts = options_registry_get_for_display(MODE_CLIENT, false, &client_count);
417
418 if (client_opts) {
419 zsh_write_combined_args(output, client_opts, client_count);
420 SAFE_FREE(client_opts);
421 }
422
423 fprintf(output, "}\n"
424 "\n"
425 "_ascii_chat_mirror() {\n"
426 " local curcontext=$curcontext\n"
427 " local -a context line state state_descr args\n"
428 " local -A opt_args\n\n");
429
430 /* Mirror options - grouped by category */
431 size_t mirror_count = 0;
432 const option_descriptor_t *mirror_opts = options_registry_get_for_display(MODE_MIRROR, false, &mirror_count);
433
434 if (mirror_opts) {
435 zsh_write_combined_args(output, mirror_opts, mirror_count);
436 SAFE_FREE(mirror_opts);
437 }
438
439 fprintf(output, "}\n"
440 "\n"
441 "# Discovery mode: find sessions via discovery service (default mode when no mode specified)\n"
442 "_ascii_chat_discovery() {\n"
443 " local curcontext=$curcontext\n"
444 " local -a context line state state_descr args\n"
445 " local -A opt_args\n\n");
446
447 /* Discovery options - grouped by category (reuse already-loaded options) */
448 if (discovery_opts) {
449 zsh_write_combined_args(output, discovery_opts, discovery_count);
450 }
451
452 fprintf(output, "}\n"
453 "\n"
454 "# Register completion functions (must come after definitions)\n"
455 "compdef _ascii_chat ascii-chat\n"
456 "compdef _ascii_chat 'build/bin/ascii-chat'\n");
457
458 SAFE_FREE(binary_opts);
459 SAFE_FREE(discovery_opts);
460
461 return ASCIICHAT_OK;
462}
#define SAFE_FREE(ptr)
Definition common.h:376
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it, returning the error code.
@ ASCIICHAT_OK
Definition error_codes.h:51
@ ERROR_INVALID_PARAM
@ MODE_CLIENT
Client mode - network client options.
@ MODE_DISCOVERY_SERVICE
Discovery server mode - session management and WebRTC signaling.
@ MODE_SERVER
Server mode - network server options.
@ MODE_MIRROR
Mirror mode - local webcam viewing (no network)
@ MODE_DISCOVERY
Discovery mode - participant that can dynamically become host.
const mode_descriptor_t * get_modes_by_group(const char *group, size_t *out_count)
Get all mode descriptors grouped by category.
const option_descriptor_t * options_registry_get_for_display(asciichat_mode_t mode, bool for_binary_help, size_t *num_options)
Get options for help/completions display with unified filtering.
Definition public_api.c:324
Metadata for a mode.
Definition main.c:366
Option descriptor.
Definition builder.h:241