]>
Commit | Line | Data |
---|---|---|
ccc6cda3 JA |
1 | From jwe@che.utexas.edu Wed Sep 21 17:23:40 1994 |
2 | Flags: 10 | |
3 | Return-Path: jwe@che.utexas.edu | |
4 | Received: from po.CWRU.Edu (root@po.CWRU.Edu [129.22.4.2]) by odin.INS.CWRU.Edu with ESMTP (8.6.8.1+cwru/CWRU-2.1-ins) | |
5 | id RAA04010; Wed, 21 Sep 1994 17:23:39 -0400 (from jwe@che.utexas.edu for <chet@odin.INS.CWRU.Edu>) | |
6 | Received: from life.ai.mit.edu (life.ai.mit.edu [128.52.32.80]) by po.CWRU.Edu with SMTP (8.6.8.1+cwru/CWRU-2.2) | |
7 | id RAA02121; Wed, 21 Sep 1994 17:23:28 -0400 (from jwe@che.utexas.edu for <chet@po.cwru.edu>) | |
8 | Received: from schoch.che.utexas.edu by life.ai.mit.edu (4.1/AI-4.10) for chet@po.cwru.edu id AA09989; Wed, 21 Sep 94 17:23:17 EDT | |
9 | Received: from localhost (jwe@localhost) by schoch.che.utexas.edu (8.6.8.1/8.6) with SMTP id QAA05737; Wed, 21 Sep 1994 16:22:01 -0500 | |
10 | Message-Id: <199409212122.QAA05737@schoch.che.utexas.edu> | |
11 | To: march@tudor.com | |
12 | Cc: bug-bash@prep.ai.mit.edu | |
13 | Subject: Re: Completion feature possible? | |
14 | In-Reply-To: Your message of 21 Sep 94 13:30:22 EDT | |
15 | Date: Wed, 21 Sep 94 16:22:00 EDT | |
16 | From: John Eaton <jwe@che.utexas.edu> | |
17 | ||
18 | Gregory F. March <march@tudor.com> wrote: | |
19 | ||
20 | : I was having a discussion about MH with one of my friends the other | |
21 | : day and I got to thinking that the +folder/subfolder scheme for naming | |
22 | : mail folders is a real pain because completion doesn't work on | |
23 | : them. Someone then mentioned that zsh (I think) has the ability to | |
24 | : specify how to complete (I guess where to look for the files) for | |
25 | : different prefixes. Bash right now knows about '@', '~', and '$' (any | |
26 | : others?). It would be really helpful if one could define something | |
27 | : like: | |
28 | : | |
29 | : completion '+' "$HOME/Mail" | |
30 | : | |
31 | : in a config file someplace. Would this be easy? Is there a list of | |
32 | : TODO item that someone might want to add this to? | |
33 | ||
34 | It would be nice to have a general completion feature like this. | |
35 | ||
36 | Until that happens, maybe you will find the following patch useful. | |
37 | It makes MH folder name completion work with bash. The diffs are | |
38 | relative to version 1.14.2. | |
39 | ||
40 | I realize that changes to readline.c and and complete.c are not good | |
41 | since they add some MH-specific stuff to the readline code and not to | |
42 | bash, but when I first wrote this, I had no idea what else to do. | |
43 | ||
44 | Chet, would you consider adding this if it were cleaned up a bit? | |
45 | Made optional with cpp conditionals? | |
46 | ||
47 | This feature has been very useful to me for the last several years | |
48 | (since about 1.05 or 1.06, I think). | |
49 | ||
50 | Thanks, | |
51 | ||
52 | -- | |
53 | John W. Eaton | 4.3BSD is not perfect. -- Leffler, et al. (1989). | |
54 | jwe@che.utexas.edu | | |
55 | ||
56 | ||
57 | -------------------------------cut here------------------------------- | |
58 | diff -rc bash-1.14.2/bashline.c bash-1.14.2.local/bashline.c | |
59 | *** bash-1.14.2/bashline.c Wed Aug 3 09:32:45 1994 | |
60 | --- bash-1.14.2.local/bashline.c Wed Sep 21 15:39:04 1994 | |
61 | *************** | |
62 | *** 58,63 **** | |
63 | --- 58,64 ---- | |
64 | static char *hostname_completion_function (); | |
65 | static char *command_word_completion_function (); | |
66 | static char *command_subst_completion_function (); | |
67 | + static char *mh_folder_completion_function (); | |
68 | ||
69 | static void snarf_hosts_from_file (), add_host_name (); | |
70 | static void sort_hostname_list (); | |
71 | *************** | |
72 | *** 90,95 **** | |
73 | --- 91,98 ---- | |
74 | bash_complete_username_internal (), | |
75 | bash_complete_hostname (), bash_possible_hostname_completions (), | |
76 | bash_complete_hostname_internal (), | |
77 | + bash_complete_mh_folder (), bash_possible_mh_folder_completions (), | |
78 | + bash_complete_mh_folder_internal (), | |
79 | bash_complete_variable (), bash_possible_variable_completions (), | |
80 | bash_complete_variable_internal (), | |
81 | bash_complete_command (), bash_possible_command_completions (), | |
82 | *************** | |
83 | *** 134,140 **** | |
84 | rl_terminal_name = get_string_value ("TERM"); | |
85 | rl_instream = stdin; | |
86 | rl_outstream = stderr; | |
87 | ! rl_special_prefixes = "$@"; | |
88 | ||
89 | /* Allow conditional parsing of the ~/.inputrc file. */ | |
90 | rl_readline_name = "Bash"; | |
91 | --- 137,143 ---- | |
92 | rl_terminal_name = get_string_value ("TERM"); | |
93 | rl_instream = stdin; | |
94 | rl_outstream = stderr; | |
95 | ! rl_special_prefixes = "$@+"; | |
96 | ||
97 | /* Allow conditional parsing of the ~/.inputrc file. */ | |
98 | rl_readline_name = "Bash"; | |
99 | *************** | |
100 | *** 193,198 **** | |
101 | --- 196,207 ---- | |
102 | rl_bind_key_in_map ('@', bash_possible_hostname_completions, | |
103 | emacs_ctlx_keymap); | |
104 | ||
105 | + rl_add_defun ("complete-mh-folder", bash_complete_mh_folder, META('+')); | |
106 | + rl_add_defun ("possible-mh-folder-completions", | |
107 | + bash_possible_mh_folder_completions, -1); | |
108 | + rl_bind_key_in_map ('+', bash_possible_mh_folder_completions, | |
109 | + emacs_ctlx_keymap); | |
110 | + | |
111 | rl_add_defun ("complete-variable", bash_complete_variable, -1); | |
112 | rl_bind_key_in_map ('$', bash_complete_variable, emacs_meta_keymap); | |
113 | rl_add_defun ("possible-variable-completions", | |
114 | *************** | |
115 | *** 656,661 **** | |
116 | --- 665,677 ---- | |
117 | if (!matches && *text == '@') | |
118 | matches = completion_matches (text, hostname_completion_function); | |
119 | ||
120 | + /* Another one. Why not? If the word starts in '+', then look for | |
121 | + matching mh folders for completion first. */ | |
122 | + if (!matches && *text == '+') | |
123 | + { | |
124 | + matches = completion_matches (text, mh_folder_completion_function); | |
125 | + } | |
126 | + | |
127 | /* And last, (but not least) if this word is in a command position, then | |
128 | complete over possible command names, including aliases, functions, | |
129 | and command names. */ | |
130 | *************** | |
131 | *** 1077,1082 **** | |
132 | --- 1093,1185 ---- | |
133 | return ((char *)NULL); | |
134 | } | |
135 | ||
136 | + /* How about a completion function for mh folders? */ | |
137 | + static char * | |
138 | + mh_folder_completion_function (text, state) | |
139 | + int state; | |
140 | + char *text; | |
141 | + { | |
142 | + extern int rl_filename_completion_desired; | |
143 | + | |
144 | + extern char *get_mh_path (); | |
145 | + | |
146 | + static char *mh_path = (char *)NULL; | |
147 | + static int len; | |
148 | + static int istate; | |
149 | + static char *val; | |
150 | + char *hint; | |
151 | + | |
152 | + static char *mh_folder_hint = (char *)NULL; | |
153 | + | |
154 | + /* If we don't have any state, make some. */ | |
155 | + if (!state) | |
156 | + { | |
157 | + val = (char *)NULL; | |
158 | + | |
159 | + if (mh_path) | |
160 | + free (mh_path); | |
161 | + | |
162 | + mh_path = get_mh_path (); | |
163 | + if (!mh_path && !(hint[1] == '/' || hint[1] == '.')) | |
164 | + return ((char *)NULL); | |
165 | + | |
166 | + len = strlen (mh_path); | |
167 | + } | |
168 | + | |
169 | + if (mh_folder_hint) | |
170 | + free (mh_folder_hint); | |
171 | + | |
172 | + hint = text; | |
173 | + if (*hint == '+') | |
174 | + hint++; | |
175 | + | |
176 | + mh_folder_hint = (char *)xmalloc (2 + len + strlen (hint)); | |
177 | + if (*hint == '/' || *hint == '.') { | |
178 | + len = -1; | |
179 | + sprintf (mh_folder_hint, "%s", hint); | |
180 | + } else | |
181 | + sprintf (mh_folder_hint, "%s/%s", mh_path, hint); | |
182 | + | |
183 | + istate = (val != (char *)NULL); | |
184 | + | |
185 | + again: | |
186 | + val = filename_completion_function (mh_folder_hint, istate); | |
187 | + istate = 1; | |
188 | + | |
189 | + if (!val) | |
190 | + { | |
191 | + return ((char *)NULL); | |
192 | + } | |
193 | + else | |
194 | + { | |
195 | + char *ptr = val + len + 1, *temp; | |
196 | + struct stat sb; | |
197 | + int status = stat (val, &sb); | |
198 | + | |
199 | + if (status != 0) | |
200 | + return ((char *)NULL); | |
201 | + | |
202 | + if ((sb.st_mode & S_IFDIR) == S_IFDIR) | |
203 | + { | |
204 | + temp = (char *)xmalloc (2 + strlen (ptr)); | |
205 | + *temp = '+'; | |
206 | + strcpy (temp + 1, ptr); | |
207 | + | |
208 | + free (val); | |
209 | + val = ""; | |
210 | + | |
211 | + rl_filename_completion_desired = 1; | |
212 | + | |
213 | + return (temp); | |
214 | + } | |
215 | + else | |
216 | + { | |
217 | + free (val); | |
218 | + } | |
219 | + goto again; | |
220 | + } | |
221 | + } | |
222 | + | |
223 | /* History and alias expand the line. */ | |
224 | static char * | |
225 | history_expand_line_internal (line) | |
226 | *************** | |
227 | *** 1628,1633 **** | |
228 | --- 1731,1773 ---- | |
229 | { | |
230 | bash_specific_completion | |
231 | (what_to_do, (Function *)username_completion_function); | |
232 | + } | |
233 | + | |
234 | + static void | |
235 | + bash_complete_mh_folder (ignore, ignore2) | |
236 | + int ignore, ignore2; | |
237 | + { | |
238 | + bash_complete_mh_folder_internal (TAB); | |
239 | + } | |
240 | + | |
241 | + static void | |
242 | + bash_possible_mh_folder_completions (ignore, ignore2) | |
243 | + int ignore, ignore2; | |
244 | + { | |
245 | + bash_complete_mh_folder_internal ('?'); | |
246 | + } | |
247 | + | |
248 | + static void | |
249 | + bash_complete_mh_folder_internal (what_to_do) | |
250 | + int what_to_do; | |
251 | + { | |
252 | + Function *orig_func; | |
253 | + CPPFunction *orig_attempt_func; | |
254 | + char *orig_rl_completer_word_break_characters; | |
255 | + extern char *rl_completer_word_break_characters; | |
256 | + | |
257 | + orig_func = rl_completion_entry_function; | |
258 | + orig_attempt_func = rl_attempted_completion_function; | |
259 | + orig_rl_completer_word_break_characters = rl_completer_word_break_characters; | |
260 | + rl_completion_entry_function = (Function *)mh_folder_completion_function; | |
261 | + rl_attempted_completion_function = (CPPFunction *)NULL; | |
262 | + rl_completer_word_break_characters = " \t\n\"\'"; | |
263 | + | |
264 | + rl_complete_internal (what_to_do); | |
265 | + | |
266 | + rl_completion_entry_function = orig_func; | |
267 | + rl_attempted_completion_function = orig_attempt_func; | |
268 | + rl_completer_word_break_characters = orig_rl_completer_word_break_characters; | |
269 | } | |
270 | ||
271 | static void | |
272 | Only in bash-1.14.2.local: bashline.c.orig | |
273 | diff -rc bash-1.14.2/lib/readline/complete.c bash-1.14.2.local/lib/readline/complete.c | |
274 | *** bash-1.14.2/lib/readline/complete.c Tue Jul 26 12:59:57 1994 | |
275 | --- bash-1.14.2.local/lib/readline/complete.c Wed Sep 21 15:41:19 1994 | |
276 | *************** | |
277 | *** 733,751 **** | |
278 | if (rl_filename_completion_desired) | |
279 | { | |
280 | struct stat finfo; | |
281 | ! char *filename = tilde_expand (matches[0]); | |
282 | ||
283 | ! if ((stat (filename, &finfo) == 0) && S_ISDIR (finfo.st_mode)) | |
284 | { | |
285 | ! if (rl_line_buffer[rl_point] != '/') | |
286 | ! rl_insert_text ("/"); | |
287 | } | |
288 | ! else | |
289 | { | |
290 | ! if (rl_point == rl_end) | |
291 | ! rl_insert_text (temp_string); | |
292 | } | |
293 | - free (filename); | |
294 | } | |
295 | else | |
296 | { | |
297 | --- 733,768 ---- | |
298 | if (rl_filename_completion_desired) | |
299 | { | |
300 | struct stat finfo; | |
301 | ! char *tilde_expand (); | |
302 | ! char *plus_expand (); | |
303 | ! char *filename = (char *) NULL; | |
304 | ||
305 | ! switch (*matches[0]) | |
306 | { | |
307 | ! case '+': | |
308 | ! filename = plus_expand (matches[0]); | |
309 | ! break; | |
310 | ! case '~': | |
311 | ! default: | |
312 | ! filename = tilde_expand (matches[0]); | |
313 | ! break; | |
314 | } | |
315 | ! | |
316 | ! if (filename) | |
317 | { | |
318 | ! if ((stat (filename, &finfo) == 0) | |
319 | ! && S_ISDIR (finfo.st_mode)) | |
320 | ! { | |
321 | ! if (rl_line_buffer[rl_point] != '/') | |
322 | ! rl_insert_text ("/"); | |
323 | ! } | |
324 | ! else | |
325 | ! { | |
326 | ! if (rl_point == rl_end) | |
327 | ! rl_insert_text (temp_string); | |
328 | ! } | |
329 | ! free (filename); | |
330 | } | |
331 | } | |
332 | else | |
333 | { | |
334 | Only in bash-1.14.2.local/lib/readline: diffs | |
335 | diff -rc bash-1.14.2/lib/readline/readline.c bash-1.14.2.local/lib/readline/readline.c | |
336 | *** bash-1.14.2/lib/readline/readline.c Fri Aug 12 12:47:46 1994 | |
337 | --- bash-1.14.2.local/lib/readline/readline.c Wed Sep 21 15:36:07 1994 | |
338 | *************** | |
339 | *** 23,28 **** | |
340 | --- 23,29 ---- | |
341 | #define READLINE_LIBRARY | |
342 | ||
343 | #include <stdio.h> | |
344 | + #include <string.h> | |
345 | #include <sys/types.h> | |
346 | #include <fcntl.h> | |
347 | #if !defined (NO_SYS_FILE) | |
348 | *************** | |
349 | *** 3518,3523 **** | |
350 | --- 3519,3616 ---- | |
351 | } | |
352 | ||
353 | #endif /* TEST */ | |
354 | + | |
355 | + #define cr_whitespace(c) ((c) == '\r' || (c) == '\n' || whitespace(c)) | |
356 | + | |
357 | + char * | |
358 | + get_mh_path () | |
359 | + { | |
360 | + static FILE *fp = (FILE *)NULL; | |
361 | + char buf[512]; /* XXX */ | |
362 | + char profile[512]; /* XXX */ | |
363 | + char *bp; | |
364 | + char *temp_home; | |
365 | + char *temp_path; | |
366 | + | |
367 | + temp_home = (char *)getenv ("HOME"); | |
368 | + if (!temp_home) | |
369 | + return ((char *)NULL); | |
370 | + | |
371 | + strcpy (profile, temp_home); | |
372 | + strcat (profile, "/.mh_profile"); | |
373 | + | |
374 | + if (fp) | |
375 | + fclose (fp); | |
376 | + | |
377 | + fp = fopen (profile, "r"); | |
378 | + if (fp == (FILE *)NULL) | |
379 | + return ((char *)NULL); | |
380 | + | |
381 | + while (fgets (buf, 512, fp) != (char *)NULL) /* XXX */ | |
382 | + { | |
383 | + if ((bp = strstr (buf, "Path:")) != (char *)NULL) | |
384 | + { | |
385 | + bp += 5; | |
386 | + while (whitespace (*bp)) | |
387 | + bp++; | |
388 | + | |
389 | + if (*bp == '\0') | |
390 | + return ((char *)NULL); | |
391 | + | |
392 | + temp_path = (char *)xmalloc (3 + strlen (bp) + strlen (temp_home)); | |
393 | + | |
394 | + strcpy (temp_path, temp_home); | |
395 | + strcat (temp_path, "/"); | |
396 | + strcat (temp_path, bp); | |
397 | + | |
398 | + bp = temp_path; | |
399 | + | |
400 | + while (!(cr_whitespace (*bp))) | |
401 | + bp++; | |
402 | + | |
403 | + *bp = '\0'; | |
404 | + | |
405 | + return temp_path; | |
406 | + } | |
407 | + } | |
408 | + | |
409 | + return ((char *)NULL); | |
410 | + } | |
411 | + | |
412 | + /* Expand FILENAME if it begins with a plus. This always returns | |
413 | + a new string. */ | |
414 | + char * | |
415 | + plus_expand (filename) | |
416 | + char *filename; | |
417 | + { | |
418 | + static char *dirname = (char *)NULL; | |
419 | + | |
420 | + if (filename && *filename == '+') | |
421 | + { | |
422 | + char *mh_path = get_mh_path (); | |
423 | + | |
424 | + if (filename[1] == '/' || filename[1] == '.') | |
425 | + { | |
426 | + dirname = (char *)xmalloc (1 + strlen (filename)); | |
427 | + | |
428 | + strcpy(dirname, filename+1); | |
429 | + | |
430 | + return dirname; | |
431 | + } | |
432 | + | |
433 | + if (mh_path) | |
434 | + { | |
435 | + dirname = (char *)xmalloc (1 + strlen (filename) + strlen (mh_path)); | |
436 | + | |
437 | + strcpy (dirname, mh_path); | |
438 | + strcat (dirname, "/"); | |
439 | + strcat (dirname, filename+1); | |
440 | + | |
441 | + return dirname; | |
442 | + } | |
443 | + } | |
444 | + return (char *)NULL; | |
445 | + } | |
446 | ||
447 | \f | |
448 | /* | |
449 |