ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
zsh.c
Go to the documentation of this file.
1
7#include <string.h>
8#include <stdio.h>
9#include <ascii-chat/options/completions/zsh.h>
10#include <ascii-chat/options/registry.h>
11#include <ascii-chat/common.h>
12
17static void zsh_escape_help(FILE *output, const char *text) {
18 if (!text) {
19 return;
20 }
21
22 for (const char *p = text; *p; p++) {
23 switch (*p) {
24 case '[':
25 case ']':
26 // Escape square brackets for zsh _arguments
27 fprintf(output, "\\%c", *p);
28 break;
29 case '\'':
30 // Escape single quotes
31 fprintf(output, "'\\''");
32 break;
33 case '\n':
34 // Convert newlines to spaces in help text
35 fprintf(output, " ");
36 break;
37 case '\t':
38 // Convert tabs to spaces in help text
39 fprintf(output, " ");
40 break;
41 default:
42 fputc(*p, output);
43 }
44 }
45}
46
47static void zsh_write_option(FILE *output, const option_descriptor_t *opt) {
48 if (!opt) {
49 return;
50 }
51
52 // Get completion metadata for this option
53 const option_metadata_t *meta = options_registry_get_metadata(opt->long_name);
54
55 // Build completion spec based on metadata
56 char completion_spec[512] = "";
57 if (meta) {
58 if (meta->input_type == OPTION_INPUT_ENUM && meta->enum_values && meta->enum_values[0] != NULL) {
59 // Enum completion: "(value1 value2 value3)"
60 size_t pos = 0;
61 pos += safe_snprintf(completion_spec + pos, sizeof(completion_spec) - pos, ":(");
62 for (size_t i = 0; meta->enum_values[i] != NULL && pos < sizeof(completion_spec) - 1; i++) {
63 if (i > 0)
64 pos += safe_snprintf(completion_spec + pos, sizeof(completion_spec) - pos, " ");
65 pos += safe_snprintf(completion_spec + pos, sizeof(completion_spec) - pos, "%s", meta->enum_values[i]);
66 }
67 safe_snprintf(completion_spec + pos, sizeof(completion_spec) - pos, ")");
68 } else if (meta->input_type == OPTION_INPUT_FILEPATH) {
69 // File path completion
70 SAFE_STRNCPY(completion_spec, ":_files", sizeof(completion_spec));
71 } else if (meta->examples && meta->examples[0] != NULL) {
72 // Examples: "(example1 example2)" - practical values, higher priority than calculated ranges
73 size_t pos = 0;
74 pos += safe_snprintf(completion_spec + pos, sizeof(completion_spec) - pos, ":(");
75 for (size_t i = 0; meta->examples[i] != NULL && pos < sizeof(completion_spec) - 1; i++) {
76 if (i > 0)
77 pos += safe_snprintf(completion_spec + pos, sizeof(completion_spec) - pos, " ");
78 pos += safe_snprintf(completion_spec + pos, sizeof(completion_spec) - pos, "%s", meta->examples[i]);
79 }
80 safe_snprintf(completion_spec + pos, sizeof(completion_spec) - pos, ")");
81 } else if (meta->input_type == OPTION_INPUT_NUMERIC) {
82 // Numeric completion with range - only if no examples
83 if (meta->numeric_range.min > 0 || meta->numeric_range.max > 0) {
84 safe_snprintf(completion_spec, sizeof(completion_spec), ":(numeric %d-%d)", meta->numeric_range.min,
85 meta->numeric_range.max);
86 } else {
87 SAFE_STRNCPY(completion_spec, ":(numeric)", sizeof(completion_spec));
88 }
89 }
90 }
91
92 // Write short option if present
93 if (opt->short_name != '\0') {
94 fprintf(output, " '-%c[", opt->short_name);
95 zsh_escape_help(output, opt->help_text);
96 fprintf(output, "]%s' \\\n", completion_spec);
97 }
98
99 // Write long option
100 fprintf(output, " '--%s[", opt->long_name);
101 zsh_escape_help(output, opt->help_text);
102 fprintf(output, "]%s' \\\n", completion_spec);
103}
104
105asciichat_error_t completions_generate_zsh(FILE *output) {
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}
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
const option_metadata_t * options_registry_get_metadata(const char *long_name)
Definition public_api.c:369
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.
Definition system.c:456
asciichat_error_t completions_generate_zsh(FILE *output)
Definition zsh.c:105