ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
fish.c
Go to the documentation of this file.
1
7#include <string.h>
8#include <stdio.h>
9#include <ascii-chat/options/completions/fish.h>
10#include <ascii-chat/options/registry.h>
11#include <ascii-chat/options/enums.h>
12#include <ascii-chat/common.h>
13
18static void fish_escape_help(FILE *output, const char *text) {
19 if (!text) {
20 return;
21 }
22
23 for (const char *p = text; *p; p++) {
24 if (*p == '\'') {
25 // Escape single quotes by ending quote, adding escaped quote, starting quote again
26 fprintf(output, "'\\''");
27 } else if (*p == '\n' || *p == '\t') {
28 // Convert newlines and tabs to spaces
29 fprintf(output, " ");
30 } else {
31 fputc(*p, output);
32 }
33 }
34}
35
36static void fish_write_option(FILE *output, const option_descriptor_t *opt, const char *condition) {
37 if (!opt) {
38 return;
39 }
40
41 // Get completion metadata for this option
42 const option_metadata_t *meta = options_registry_get_metadata(opt->long_name);
43
44 // Determine if we should exclude file completion
45 bool exclusive = false;
46
47 if (meta) {
48 if (meta->input_type == OPTION_INPUT_ENUM && meta->enum_values && meta->enum_values[0] != NULL) {
49 exclusive = true;
50 // Enum values as completions
51 // Output short option once with first value
52 if (opt->short_name != '\0') {
53 fprintf(output, "complete -c ascii-chat %s -s %c -x -a '%s' -d '", condition, opt->short_name,
54 meta->enum_values[0]);
55 fish_escape_help(output, opt->help_text);
56 fprintf(output, "'\n");
57 }
58 // Output long option with all values
59 for (size_t i = 0; meta->enum_values[i] != NULL; i++) {
60 fprintf(output, "complete -c ascii-chat %s -l %s -x -a '%s' -d '", condition, opt->long_name,
61 meta->enum_values[i]);
62 fish_escape_help(output, opt->help_text);
63 fprintf(output, "'\n");
64 }
65 return;
66 } else if (meta->input_type == OPTION_INPUT_FILEPATH) {
67 // File paths use default fish file completion
68 exclusive = false;
69 } else if (meta->examples && meta->examples[0] != NULL) {
70 exclusive = true;
71 // Example values as completions (practical values, higher priority than calculated ranges)
72 // Output short option once with first example
73 if (opt->short_name != '\0') {
74 fprintf(output, "complete -c ascii-chat %s -s %c -x -a '%s' -d '", condition, opt->short_name,
75 meta->examples[0]);
76 fish_escape_help(output, opt->help_text);
77 fprintf(output, "'\n");
78 }
79 // Output long option with all examples
80 for (size_t i = 0; meta->examples[i] != NULL; i++) {
81 fprintf(output, "complete -c ascii-chat %s -l %s -x -a '%s' -d '", condition, opt->long_name,
82 meta->examples[i]);
83 fish_escape_help(output, opt->help_text);
84 fprintf(output, "'\n");
85 }
86 return;
87 } else if (meta->input_type == OPTION_INPUT_NUMERIC) {
88 exclusive = true;
89 // Numeric range - suggest min, middle, max values
90 if (opt->short_name != '\0') {
91 fprintf(output, "complete -c ascii-chat %s -s %c -x -a '%d' -d 'numeric (%d-%d)'\n", condition, opt->short_name,
92 meta->numeric_range.min, meta->numeric_range.min, meta->numeric_range.max);
93 }
94 fprintf(output, "complete -c ascii-chat %s -l %s -x -a '%d' -d 'numeric (%d-%d)'\n", condition, opt->long_name,
95 meta->numeric_range.min, meta->numeric_range.min, meta->numeric_range.max);
96 if (meta->numeric_range.max > meta->numeric_range.min) {
97 int middle = (meta->numeric_range.min + meta->numeric_range.max) / 2;
98 fprintf(output, "complete -c ascii-chat %s -l %s -x -a '%d' -d 'numeric (middle)'\n", condition, opt->long_name,
99 middle);
100 fprintf(output, "complete -c ascii-chat %s -l %s -x -a '%d' -d 'numeric (max)'\n", condition, opt->long_name,
101 meta->numeric_range.max);
102 }
103 return;
104 }
105 }
106
107 // Basic completion without values
108 if (opt->short_name != '\0') {
109 if (exclusive) {
110 fprintf(output, "complete -c ascii-chat %s -s %c -x -d '", condition, opt->short_name);
111 fish_escape_help(output, opt->help_text);
112 fprintf(output, "'\n");
113 } else {
114 fprintf(output, "complete -c ascii-chat %s -s %c -d '", condition, opt->short_name);
115 fish_escape_help(output, opt->help_text);
116 fprintf(output, "'\n");
117 }
118 }
119 if (exclusive) {
120 fprintf(output, "complete -c ascii-chat %s -l %s -x -d '", condition, opt->long_name);
121 fish_escape_help(output, opt->help_text);
122 fprintf(output, "'\n");
123 } else {
124 fprintf(output, "complete -c ascii-chat %s -l %s -d '", condition, opt->long_name);
125 fish_escape_help(output, opt->help_text);
126 fprintf(output, "'\n");
127 }
128}
129
130asciichat_error_t completions_generate_fish(FILE *output) {
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}
asciichat_error_t completions_generate_fish(FILE *output)
Definition fish.c:130
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