*** empty log message ***
[bpt/emacs.git] / lisp / eshell / esh-var.el
CommitLineData
60370d40 1;;; esh-var.el --- handling of variables
affbf647 2
f2e3589a 3;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004,
8b72699e 4;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
affbf647 5
7de5b421
GM
6;; Author: John Wiegley <johnw@gnu.org>
7
affbf647
GM
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
e0085d62 12;; the Free Software Foundation; either version 3, or (at your option)
affbf647
GM
13;; any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs; see the file COPYING. If not, write to the
3a35cf56
LK
22;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23;; Boston, MA 02110-1301, USA.
affbf647
GM
24
25(provide 'esh-var)
26
27(eval-when-compile (require 'esh-maint))
28
29(defgroup eshell-var nil
30 "Variable interpolation is introduced whenever the '$' character
31appears unquoted in any argument (except when that argument is
eabc24ca 32surrounded by single quotes). It may be used to interpolate a
affbf647
GM
33variable value, a subcommand, or even the result of a Lisp form."
34 :tag "Variable handling"
35 :group 'eshell)
36
37;;; Commentary:
38
39;; These are the possible variable interpolation syntaxes. Also keep
40;; in mind that if an argument looks like a number, it will be
41;; converted to a number. This is not significant when invoking
42;; external commands, but it's important when calling Lisp functions.
43;;
44;; $VARIABLE
45;;
46;; Interval the value of an environment variable, or a Lisp variable
47;;
48;; $ALSO-VAR
49;;
0138efd4 50;; "-" is a valid part of a variable name.
affbf647
GM
51;;
52;; $<MYVAR>-TOO
53;;
54;; Only "MYVAR" is part of the variable name in this case.
55;;
56;; $#VARIABLE
57;;
58;; Returns the length of the value of VARIABLE. This could also be
59;; done using the `length' Lisp function.
60;;
61;; $(lisp)
62;;
63;; Returns result of lisp evaluation. Note: Used alone like this, it
64;; is identical to just saying (lisp); but with the variable expansion
65;; form, the result may be interpolated a larger string, such as
66;; '$(lisp)/other'.
67;;
68;; ${command}
69;;
70;; Returns the value of an eshell subcommand. See the note above
71;; regarding Lisp evaluations.
72;;
73;; $ANYVAR[10]
74;;
75;; Return the 10th element of ANYVAR. If ANYVAR's value is a string,
76;; it will be split in order to make it a list. The splitting will
77;; occur at whitespace.
78;;
79;; $ANYVAR[: 10]
80;;
81;; As above, except that splitting occurs at the colon now.
82;;
83;; $ANYVAR[: 10 20]
84;;
85;; As above, but instead of returning just a string, it now returns a
86;; list of two strings. If the result is being interpolated into a
87;; larger string, this list will be flattened into one big string,
88;; with each element separated by a space.
89;;
90;; $ANYVAR["\\\\" 10]
91;;
92;; Separate on backslash characters. Actually, the first argument --
93;; if it doesn't have the form of a number, or a plain variable name
94;; -- can be any regular expression. So to split on numbers, use
95;; '$ANYVAR["[0-9]+" 10 20]'.
96;;
97;; $ANYVAR[hello]
98;;
99;; Calls `assoc' on ANYVAR with 'hello', expecting it to be an alist.
100;;
101;; $#ANYVAR[hello]
102;;
103;; Returns the length of the cdr of the element of ANYVAR who car is
104;; equal to "hello".
105;;
106;; There are also a few special variables defined by Eshell. '$$' is
107;; the value of the last command (t or nil, in the case of an external
108;; command). This makes it possible to chain results:
109;;
110;; /tmp $ echo /var/spool/mail/johnw
111;; /var/spool/mail/johnw
112;; /tmp $ dirname $$
113;; /var/spool/mail/
114;; /tmp $ cd $$
115;; /var/spool/mail $
116;;
117;; '$_' refers to the last argument of the last command. And $?
118;; contains the exit code of the last command (0 or 1 for Lisp
119;; functions, based on successful completion).
120
121(require 'env)
122(require 'ring)
123
124;;; User Variables:
125
126(defcustom eshell-var-load-hook '(eshell-var-initialize)
127 "*A list of functions to call when loading `eshell-var'."
128 :type 'hook
129 :group 'eshell-var)
130
131(defcustom eshell-prefer-lisp-variables nil
132 "*If non-nil, prefer Lisp variables to environment variables."
133 :type 'boolean
134 :group 'eshell-var)
135
136(defcustom eshell-complete-export-definition t
137 "*If non-nil, completing names for `export' shows current definition."
138 :type 'boolean
139 :group 'eshell-var)
140
6995786d
JW
141(defcustom eshell-modify-global-environment nil
142 "*If non-nil, using `export' changes Emacs's global environment."
143 :type 'boolean
144 :group 'eshell-var)
145
affbf647
GM
146(defcustom eshell-variable-name-regexp "[A-Za-z0-9_-]+"
147 "*A regexp identifying what constitutes a variable name reference.
148Note that this only applies for '$NAME'. If the syntax '$<NAME>' is
149used, then NAME can contain any character, including angle brackets,
150if they are quoted with a backslash."
151 :type 'regexp
152 :group 'eshell-var)
153
154(defcustom eshell-variable-aliases-list
155 '(;; for eshell.el
156 ("COLUMNS" (lambda (indices) (window-width)) t)
157 ("LINES" (lambda (indices) (window-height)) t)
158
159 ;; for eshell-cmd.el
160 ("_" (lambda (indices)
161 (if (not indices)
162 (car (last eshell-last-arguments))
163 (eshell-apply-indices eshell-last-arguments
164 indices))))
165 ("?" eshell-last-command-status)
166 ("$" eshell-last-command-result)
167 ("0" eshell-command-name)
168 ("1" (lambda (indices) (nth 0 eshell-command-arguments)))
169 ("2" (lambda (indices) (nth 1 eshell-command-arguments)))
170 ("3" (lambda (indices) (nth 2 eshell-command-arguments)))
171 ("4" (lambda (indices) (nth 3 eshell-command-arguments)))
172 ("5" (lambda (indices) (nth 4 eshell-command-arguments)))
173 ("6" (lambda (indices) (nth 5 eshell-command-arguments)))
174 ("7" (lambda (indices) (nth 6 eshell-command-arguments)))
175 ("8" (lambda (indices) (nth 7 eshell-command-arguments)))
176 ("9" (lambda (indices) (nth 8 eshell-command-arguments)))
177 ("*" (lambda (indices)
178 (if (not indices)
179 eshell-command-arguments
180 (eshell-apply-indices eshell-command-arguments
181 indices)))))
182 "*This list provides aliasing for variable references.
183It is very similar in concept to what `eshell-user-aliases-list' does
184for commands. Each member of this defines defines the name of a
185command, and the Lisp value to return for that variable if it is
186accessed via the syntax '$NAME'.
187
188If the value is a function, that function will be called with two
189arguments: the list of the indices that was used in the reference, and
190whether the user is requesting the length of the ultimate element.
191For example, a reference of '$NAME[10][20]' would result in the
192function for alias `NAME' being called (assuming it were aliased to a
193function), and the arguments passed to this function would be the list
194'(10 20)', and nil."
195 :type '(repeat (list string sexp
196 (choice (const :tag "Copy to environment" t)
197 (const :tag "Use only in Eshell" nil))))
198 :group 'eshell-var)
199
200(put 'eshell-variable-aliases-list 'risky-local-variable t)
201
202;;; Functions:
203
204(defun eshell-var-initialize ()
205 "Initialize the variable handle code."
206 ;; Break the association with our parent's environment. Otherwise,
207 ;; changing a variable will affect all of Emacs.
6995786d
JW
208 (unless eshell-modify-global-environment
209 (set (make-local-variable 'process-environment)
210 (eshell-copy-environment)))
affbf647
GM
211
212 (define-key eshell-command-map [(meta ?v)] 'eshell-insert-envvar)
213
214 (set (make-local-variable 'eshell-special-chars-inside-quoting)
215 (append eshell-special-chars-inside-quoting '(?$)))
216 (set (make-local-variable 'eshell-special-chars-outside-quoting)
217 (append eshell-special-chars-outside-quoting '(?$)))
218
affbf647
GM
219 (add-hook 'eshell-parse-argument-hook 'eshell-interpolate-variable t t)
220
affbf647
GM
221 (add-hook 'eshell-prepare-command-hook
222 'eshell-handle-local-variables nil t)
223
224 (when (eshell-using-module 'eshell-cmpl)
affbf647
GM
225 (add-hook 'pcomplete-try-first-hook
226 'eshell-complete-variable-reference nil t)
227 (add-hook 'pcomplete-try-first-hook
228 'eshell-complete-variable-assignment nil t)))
229
230(defun eshell-handle-local-variables ()
231 "Allow for the syntax 'VAR=val <command> <args>'."
232 ;; strip off any null commands, which can only happen if a variable
233 ;; evaluates to nil, such as "$var x", where `var' is nil. The
234 ;; command name in that case becomes `x', for compatibility with
235 ;; most regular shells (the difference is that they do an
236 ;; interpolation pass before the argument parsing pass, but Eshell
237 ;; does both at the same time).
238 (while (and (not eshell-last-command-name)
239 eshell-last-arguments)
240 (setq eshell-last-command-name (car eshell-last-arguments)
241 eshell-last-arguments (cdr eshell-last-arguments)))
242 (let ((setvar "\\`\\([A-Za-z_][A-Za-z0-9_]*\\)=\\(.*\\)\\'")
243 (command (eshell-stringify eshell-last-command-name))
244 (args eshell-last-arguments))
245 ;; local variable settings (such as 'CFLAGS=-O2 make') are handled
246 ;; by making the whole command into a subcommand, and calling
247 ;; setenv immediately before the command is invoked. This means
248 ;; that 'BLAH=x cd blah' won't work exactly as expected, but that
249 ;; is by no means a typical use of local environment variables.
250 (if (and command (string-match setvar command))
251 (throw
252 'eshell-replace-command
253 (list
254 'eshell-as-subcommand
255 (append
256 (list 'progn)
257 (let ((l (list t)))
258 (while (string-match setvar command)
259 (nconc
260 l (list
261 (list 'setenv (match-string 1 command)
262 (match-string 2 command)
263 (= (length (match-string 2 command)) 0))))
264 (setq command (eshell-stringify (car args))
265 args (cdr args)))
266 (cdr l))
267 (list (list 'eshell-named-command
268 command (list 'quote args)))))))))
269
270(defun eshell-interpolate-variable ()
271 "Parse a variable interpolation.
272This function is explicit for adding to `eshell-parse-argument-hook'."
273 (when (and (eq (char-after) ?$)
ca7aae91 274 (/= (1+ (point)) (point-max)))
affbf647
GM
275 (forward-char)
276 (list 'eshell-escape-arg
277 (eshell-parse-variable))))
278
279(defun eshell/define (var-alias definition)
012d3cb5 280 "Define a VAR-ALIAS using DEFINITION."
affbf647
GM
281 (if (not definition)
282 (setq eshell-variable-aliases-list
283 (delq (assoc var-alias eshell-variable-aliases-list)
284 eshell-variable-aliases-list))
285 (let ((def (assoc var-alias eshell-variable-aliases-list))
286 (alias-def
287 (list var-alias
288 (list 'quote (if (= (length definition) 1)
289 (car definition)
290 definition)))))
291 (if def
292 (setq eshell-variable-aliases-list
293 (delq (assoc var-alias eshell-variable-aliases-list)
294 eshell-variable-aliases-list)))
295 (setq eshell-variable-aliases-list
296 (cons alias-def
297 eshell-variable-aliases-list))))
298 nil)
299
300(defun eshell/export (&rest sets)
a4fd4556 301 "This alias allows the `export' command to act as bash users expect."
affbf647 302 (while sets
ca7aae91
JW
303 (if (and (stringp (car sets))
304 (string-match "^\\([^=]+\\)=\\(.*\\)" (car sets)))
affbf647
GM
305 (setenv (match-string 1 (car sets))
306 (match-string 2 (car sets))))
307 (setq sets (cdr sets))))
308
79cf8e80
JW
309(defun pcomplete/eshell-mode/export ()
310 "Completion function for Eshell's `export'."
311 (while (pcomplete-here
312 (if eshell-complete-export-definition
313 process-environment
314 (eshell-envvar-names)))))
315
ca7aae91
JW
316(defun eshell/unset (&rest args)
317 "Unset an environment variable."
318 (while args
319 (if (stringp (car args))
320 (setenv (car args) nil t))
321 (setq args (cdr args))))
322
79cf8e80
JW
323(defun pcomplete/eshell-mode/unset ()
324 "Completion function for Eshell's `unset'."
325 (while (pcomplete-here (eshell-envvar-names))))
affbf647
GM
326
327(defun eshell/setq (&rest args)
328 "Allow command-ish use of `setq'."
329 (let (last-value)
330 (while args
331 (let ((sym (intern (car args)))
332 (val (cadr args)))
333 (setq last-value (set sym val)
334 args (cddr args))))
335 last-value))
336
337(defun pcomplete/eshell-mode/setq ()
338 "Completion function for Eshell's `setq'."
339 (while (and (pcomplete-here (all-completions pcomplete-stub
340 obarray 'boundp))
341 (pcomplete-here))))
342
343(defun eshell/env (&rest args)
344 "Implemention of `env' in Lisp."
345 (eshell-init-print-buffer)
346 (eshell-eval-using-options
347 "env" args
348 '((?h "help" nil nil "show this usage screen")
349 :external "env"
350 :usage "<no arguments>")
351 (eshell-for setting (sort (eshell-environment-variables)
352 'string-lessp)
353 (eshell-buffered-print setting "\n"))
354 (eshell-flush)))
355
356(defun eshell-insert-envvar (envvar-name)
357 "Insert ENVVAR-NAME into the current buffer at point."
358 (interactive
359 (list (read-envvar-name "Name of environment variable: " t)))
360 (insert-and-inherit "$" envvar-name))
361
362(defun eshell-envvar-names (&optional environment)
363 "Return a list of currently visible environment variable names."
364 (mapcar (function
365 (lambda (x)
366 (substring x 0 (string-match "=" x))))
367 (or environment process-environment)))
368
369(defun eshell-environment-variables ()
370 "Return a `process-environment', fully updated.
371This involves setting any variable aliases which affect the
372environment, as specified in `eshell-variable-aliases-list'."
373 (let ((process-environment (eshell-copy-environment)))
374 (eshell-for var-alias eshell-variable-aliases-list
375 (if (nth 2 var-alias)
376 (setenv (car var-alias)
377 (eshell-stringify
378 (or (eshell-get-variable (car var-alias)) "")))))
379 process-environment))
380
381(defun eshell-parse-variable ()
382 "Parse the next variable reference at point.
383The variable name could refer to either an environment variable, or a
384Lisp variable. The priority order depends on the setting of
385`eshell-prefer-lisp-variables'.
386
387Its purpose is to call `eshell-parse-variable-ref', and then to
388process any indices that come after the variable reference."
389 (let* ((get-len (when (eq (char-after) ?#)
390 (forward-char) t))
391 value indices)
392 (setq value (eshell-parse-variable-ref)
393 indices (and (not (eobp))
394 (eq (char-after) ?\[)
395 (eshell-parse-indices))
396 value (list 'let
397 (list (list 'indices
398 (list 'quote indices)))
399 value))
400 (if get-len
401 (list 'length value)
402 value)))
403
404(defun eshell-parse-variable-ref ()
405 "Eval a variable reference.
406Returns a Lisp form which, if evaluated, will return the value of the
407variable.
408
409Possible options are:
410
411 NAME an environment or Lisp variable value
412 <LONG-NAME> disambiguates the length of the name
413 {COMMAND} result of command is variable's value
414 (LISP-FORM) result of Lisp form is variable's value"
415 (let (end)
416 (cond
417 ((eq (char-after) ?{)
418 (let ((end (eshell-find-delimiter ?\{ ?\})))
419 (if (not end)
420 (throw 'eshell-incomplete ?\{)
421 (prog1
422 (list 'eshell-convert
423 (list 'eshell-command-to-value
424 (list 'eshell-as-subcommand
425 (eshell-parse-command
426 (cons (1+ (point)) end)))))
427 (goto-char (1+ end))))))
428 ((memq (char-after) '(?\' ?\"))
429 (let ((name (if (eq (char-after) ?\')
430 (eshell-parse-literal-quote)
431 (eshell-parse-double-quote))))
432 (if name
433 (list 'eshell-get-variable (eval name) 'indices))))
f1572159 434 ((eq (char-after) ?\<)
affbf647
GM
435 (let ((end (eshell-find-delimiter ?\< ?\>)))
436 (if (not end)
437 (throw 'eshell-incomplete ?\<)
1ae720ac 438 (let* ((temp (make-temp-file temporary-file-directory))
affbf647
GM
439 (cmd (concat (buffer-substring (1+ (point)) end)
440 " > " temp)))
441 (prog1
442 (list
443 'let (list (list 'eshell-current-handles
444 (list 'eshell-create-handles temp
445 (list 'quote 'overwrite))))
446 (list
447 'progn
448 (list 'eshell-as-subcommand
449 (eshell-parse-command cmd))
450 (list 'ignore
451 (list 'nconc 'eshell-this-command-hook
452 (list 'list
453 (list 'function
454 (list 'lambda nil
455 (list 'delete-file temp))))))
456 (list 'quote temp)))
457 (goto-char (1+ end)))))))
458 ((eq (char-after) ?\()
459 (condition-case err
460 (list 'eshell-command-to-value
461 (list 'eshell-lisp-command
462 (list 'quote (read (current-buffer)))))
463 (end-of-file
464 (throw 'eshell-incomplete ?\())))
465 ((assoc (char-to-string (char-after))
466 eshell-variable-aliases-list)
467 (forward-char)
468 (list 'eshell-get-variable
469 (char-to-string (char-before)) 'indices))
470 ((looking-at eshell-variable-name-regexp)
471 (prog1
472 (list 'eshell-get-variable (match-string 0) 'indices)
473 (goto-char (match-end 0))))
474 (t
475 (error "Invalid variable reference")))))
476
477(eshell-deftest var interp-cmd
478 "Interpolate command result"
479 (eshell-command-result-p "+ ${+ 1 2} 3" "6\n"))
480
481(eshell-deftest var interp-lisp
482 "Interpolate Lisp form evalution"
483 (eshell-command-result-p "+ $(+ 1 2) 3" "6\n"))
484
485(eshell-deftest var interp-concat
486 "Interpolate and concat command"
487 (eshell-command-result-p "+ ${+ 1 2}3 3" "36\n"))
488
489(eshell-deftest var interp-concat-lisp
490 "Interpolate and concat Lisp form"
491 (eshell-command-result-p "+ $(+ 1 2)3 3" "36\n"))
492
493(eshell-deftest var interp-concat2
494 "Interpolate and concat two commands"
495 (eshell-command-result-p "+ ${+ 1 2}${+ 1 2} 3" "36\n"))
496
497(eshell-deftest var interp-concat-lisp2
498 "Interpolate and concat two Lisp forms"
499 (eshell-command-result-p "+ $(+ 1 2)$(+ 1 2) 3" "36\n"))
500
501(defun eshell-parse-indices ()
502 "Parse and return a list of list of indices."
503 (let (indices)
504 (while (eq (char-after) ?\[)
505 (let ((end (eshell-find-delimiter ?\[ ?\])))
506 (if (not end)
507 (throw 'eshell-incomplete ?\[)
508 (forward-char)
509 (let (eshell-glob-function)
510 (setq indices (cons (eshell-parse-arguments (point) end)
511 indices)))
512 (goto-char (1+ end)))))
513 (nreverse indices)))
514
515(defun eshell-get-variable (name &optional indices)
516 "Get the value for the variable NAME."
517 (let* ((alias (assoc name eshell-variable-aliases-list))
518 (var (if alias
519 (cadr alias)
520 name)))
521 (if (and alias (functionp var))
522 (funcall var indices)
523 (eshell-apply-indices
524 (cond
525 ((stringp var)
526 (let ((sym (intern-soft var)))
527 (if (and sym (boundp sym)
528 (or eshell-prefer-lisp-variables
529 (not (getenv var))))
530 (symbol-value sym)
531 (getenv var))))
532 ((symbolp var)
533 (symbol-value var))
534 (t
535 (error "Unknown variable `%s'" (eshell-stringify var))))
536 indices))))
537
538(defun eshell-apply-indices (value indices)
539 "Apply to VALUE all of the given INDICES, returning the sub-result.
540The format of INDICES is:
541
542 ((INT-OR-NAME-OR-OTHER INT-OR-NAME INT-OR-NAME ...)
543 ...)
544
545Each member of INDICES represents a level of nesting. If the first
546member of a sublist is not an integer or name, and the value it's
547reference is a string, that will be used as the regexp with which is
548to divide the string into sub-parts. The default is whitespace.
549Otherwise, each INT-OR-NAME refers to an element of the list value.
550Integers imply a direct index, and names, an associate lookup using
551`assoc'.
552
553For example, to retrieve the second element of a user's record in
554'/etc/passwd', the variable reference would look like:
555
556 ${egrep johnw /etc/passwd}[: 2]"
557 (while indices
558 (let ((refs (car indices)))
559 (when (stringp value)
560 (let (separator)
561 (if (not (or (not (stringp (caar indices)))
562 (string-match
563 (concat "^" eshell-variable-name-regexp "$")
564 (caar indices))))
565 (setq separator (caar indices)
566 refs (cdr refs)))
567 (setq value
568 (mapcar 'eshell-convert
569 (split-string value separator)))))
570 (cond
571 ((< (length refs) 0)
5b423d48 572 (error "Invalid array variable index: %s"
affbf647
GM
573 (eshell-stringify refs)))
574 ((= (length refs) 1)
575 (setq value (eshell-index-value value (car refs))))
576 (t
577 (let ((new-value (list t)))
578 (while refs
579 (nconc new-value
580 (list (eshell-index-value value
581 (car refs))))
582 (setq refs (cdr refs)))
583 (setq value (cdr new-value))))))
584 (setq indices (cdr indices)))
585 value)
586
587(defun eshell-index-value (value index)
588 "Reference VALUE using the given INDEX."
589 (if (stringp index)
590 (cdr (assoc index value))
591 (cond
592 ((ring-p value)
593 (if (> index (ring-length value))
594 (error "Index exceeds length of ring")
595 (ring-ref value index)))
596 ((listp value)
597 (if (> index (length value))
598 (error "Index exceeds length of list")
599 (nth index value)))
600 ((vectorp value)
601 (if (> index (length value))
602 (error "Index exceeds length of vector")
603 (aref value index)))
604 (t
605 (error "Invalid data type for indexing")))))
606
607;;;_* Variable name completion
608
609(defun eshell-complete-variable-reference ()
610 "If there is a variable reference, complete it."
611 (let ((arg (pcomplete-actual-arg)) index)
612 (when (setq index
613 (string-match
614 (concat "\\$\\(" eshell-variable-name-regexp
615 "\\)?\\'") arg))
616 (setq pcomplete-stub (substring arg (1+ index)))
617 (throw 'pcomplete-completions (eshell-variables-list)))))
618
619(defun eshell-variables-list ()
620 "Generate list of applicable variables."
621 (let ((argname pcomplete-stub)
622 completions)
623 (eshell-for alias eshell-variable-aliases-list
624 (if (string-match (concat "^" argname) (car alias))
625 (setq completions (cons (car alias) completions))))
626 (sort
627 (append
628 (mapcar
629 (function
630 (lambda (varname)
631 (let ((value (eshell-get-variable varname)))
632 (if (and value
633 (stringp value)
634 (file-directory-p value))
6b0e3e4d 635 (concat varname "/")
affbf647
GM
636 varname))))
637 (eshell-envvar-names (eshell-environment-variables)))
638 (all-completions argname obarray 'boundp)
639 completions)
640 'string-lessp)))
641
642(defun eshell-complete-variable-assignment ()
643 "If there is a variable assignment, allow completion of entries."
644 (let ((arg (pcomplete-actual-arg)) pos)
645 (when (string-match (concat "\\`" eshell-variable-name-regexp "=") arg)
646 (setq pos (match-end 0))
647 (if (string-match "\\(:\\)[^:]*\\'" arg)
648 (setq pos (match-end 1)))
649 (setq pcomplete-stub (substring arg pos))
650 (throw 'pcomplete-completions (pcomplete-entries)))))
651
652;;; Code:
653
ab5796a9 654;;; arch-tag: 393654fe-bdad-4f27-9a10-b1472ded14cf
affbf647 655;;; esh-var.el ends here