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 | |
---|
448 |
|
---|
449 | /*
|
---|
450 |
|
---|