diff options
author | Stefan Monnier <monnier@iro.umontreal.ca> | 2022-09-25 16:15:16 -0400 |
---|---|---|
committer | Stefan Monnier <monnier@iro.umontreal.ca> | 2022-09-25 16:15:16 -0400 |
commit | 650c20f1ca4e07591a727e1cfcc74b3363d15985 (patch) | |
tree | 85d11f6437cde22f410c25e0e5f71a3131ebd07d /lisp/eshell/esh-var.el | |
parent | 8869332684c2302b5ba1ead4568bbc7ba1c0183e (diff) | |
parent | 4b85ae6a24380fb67a3315eaec9233f17a872473 (diff) | |
download | emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.gz emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.bz2 emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.zip |
Merge 'master' into noverlay
Diffstat (limited to 'lisp/eshell/esh-var.el')
-rw-r--r-- | lisp/eshell/esh-var.el | 484 |
1 files changed, 283 insertions, 201 deletions
diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el index d038609d957..36e59cd5a41 100644 --- a/lisp/eshell/esh-var.el +++ b/lisp/eshell/esh-var.el @@ -1,6 +1,6 @@ ;;; esh-var.el --- handling of variables -*- lexical-binding:t -*- -;; Copyright (C) 1999-2017 Free Software Foundation, Inc. +;; Copyright (C) 1999-2022 Free Software Foundation, Inc. ;; Author: John Wiegley <johnw@gnu.org> @@ -34,18 +34,14 @@ ;; ;; "-" is a valid part of a variable name. ;; -;; $<MYVAR>-TOO +;; $\"MYVAR\"-TOO +;; $'MYVAR'-TOO ;; ;; Only "MYVAR" is part of the variable name in this case. ;; -;; $#VARIABLE -;; -;; Returns the length of the value of VARIABLE. This could also be -;; done using the `length' Lisp function. -;; ;; $(lisp) ;; -;; Returns result of lisp evaluation. Note: Used alone like this, it +;; Returns result of Lisp evaluation. Note: Used alone like this, it ;; is identical to just saying (lisp); but with the variable expansion ;; form, the result may be interpolated a larger string, such as ;; '$(lisp)/other'. @@ -55,38 +51,40 @@ ;; Returns the value of an eshell subcommand. See the note above ;; regarding Lisp evaluations. ;; -;; $ANYVAR[10] +;; $<command> +;; +;; Evaluates an eshell subcommand, redirecting the output to a +;; temporary file, and returning the file name. +;; +;; $EXPR[10] ;; -;; Return the 10th element of ANYVAR. If ANYVAR's value is a string, -;; it will be split in order to make it a list. The splitting will -;; occur at whitespace. +;; Return the 10th element of $EXPR, which can be any dollar +;; expression. If $EXPR's value is a string, it will be split in +;; order to make it a list. The splitting will occur at whitespace. ;; -;; $ANYVAR[: 10] +;; $EXPR[10 20] ;; -;; As above, except that splitting occurs at the colon now. +;; As above, but instead of returning a single element, it now returns a +;; list of two elements. ;; -;; $ANYVAR[: 10 20] +;; $EXPR[: 10] ;; -;; As above, but instead of returning just a string, it now returns a -;; list of two strings. If the result is being interpolated into a -;; larger string, this list will be flattened into one big string, -;; with each element separated by a space. +;; Like $EXPR[10], except that splitting occurs at the colon now. ;; -;; $ANYVAR["\\\\" 10] +;; $EXPR["\\\\" 10] ;; ;; Separate on backslash characters. Actually, the first argument -- -;; if it doesn't have the form of a number, or a plain variable name -;; -- can be any regular expression. So to split on numbers, use -;; '$ANYVAR["[0-9]+" 10 20]'. +;; if it doesn't have the form of a number -- can be any regular +;; expression. So to split on numbers, use '$EXPR["[0-9]+" 10 20]'. ;; -;; $ANYVAR[hello] +;; $EXPR[hello] ;; -;; Calls `assoc' on ANYVAR with 'hello', expecting it to be an alist. +;; Calls `assoc' on $EXPR with 'hello', expecting it to be an alist. ;; -;; $#ANYVAR[hello] +;; $#EXPR ;; -;; Returns the length of the cdr of the element of ANYVAR who car is -;; equal to "hello". +;; Returns the length of the value of $EXPR. This could also be +;; done using the `length' Lisp function. ;; ;; There are also a few special variables defined by Eshell. '$$' is ;; the value of the last command (t or nil, in the case of an external @@ -105,16 +103,19 @@ ;;; Code: -(provide 'esh-var) - (require 'esh-util) (require 'esh-cmd) (require 'esh-opt) +(require 'esh-module) +(require 'esh-arg) +(require 'esh-io) (require 'pcomplete) -(require 'env) (require 'ring) +(defconst eshell-inside-emacs (format "%s,eshell" emacs-version) + "Value for the `INSIDE_EMACS' environment variable.") + (defgroup eshell-var nil "Variable interpolation is introduced whenever the `$' character appears unquoted in any argument (except when that argument is @@ -128,107 +129,127 @@ variable value, a subcommand, or even the result of a Lisp form." (defcustom eshell-var-load-hook nil "A list of functions to call when loading `eshell-var'." :version "24.1" ; removed eshell-var-initialize - :type 'hook - :group 'eshell-var) + :type 'hook) (defcustom eshell-prefer-lisp-variables nil "If non-nil, prefer Lisp variables to environment variables." - :type 'boolean - :group 'eshell-var) + :type 'boolean) (defcustom eshell-complete-export-definition t "If non-nil, completing names for `export' shows current definition." - :type 'boolean - :group 'eshell-var) + :type 'boolean) (defcustom eshell-modify-global-environment nil "If non-nil, using `export' changes Emacs's global environment." - :type 'boolean - :group 'eshell-var) + :type 'boolean) (defcustom eshell-variable-name-regexp "[A-Za-z0-9_-]+" "A regexp identifying what constitutes a variable name reference. Note that this only applies for `$NAME'. If the syntax `$<NAME>' is used, then NAME can contain any character, including angle brackets, if they are quoted with a backslash." - :type 'regexp - :group 'eshell-var) + :type 'regexp) (defcustom eshell-variable-aliases-list - '(;; for eshell.el - ("COLUMNS" (lambda (indices) (window-width)) t) - ("LINES" (lambda (indices) (window-height)) t) + `(;; for eshell.el + ("COLUMNS" ,(lambda () (window-body-width nil 'remap)) t t) + ("LINES" ,(lambda () (window-body-height nil 'remap)) t t) + ("INSIDE_EMACS" eshell-inside-emacs t) ;; for eshell-cmd.el - ("_" (lambda (indices) - (if (not indices) - (car (last eshell-last-arguments)) - (eshell-apply-indices eshell-last-arguments - indices)))) + ("_" ,(lambda (indices quoted) + (if (not indices) + (car (last eshell-last-arguments)) + (eshell-apply-indices eshell-last-arguments + indices quoted)))) ("?" eshell-last-command-status) ("$" eshell-last-command-result) + + ;; for em-alias.el and em-script.el ("0" eshell-command-name) - ("1" (lambda (indices) (nth 0 eshell-command-arguments))) - ("2" (lambda (indices) (nth 1 eshell-command-arguments))) - ("3" (lambda (indices) (nth 2 eshell-command-arguments))) - ("4" (lambda (indices) (nth 3 eshell-command-arguments))) - ("5" (lambda (indices) (nth 4 eshell-command-arguments))) - ("6" (lambda (indices) (nth 5 eshell-command-arguments))) - ("7" (lambda (indices) (nth 6 eshell-command-arguments))) - ("8" (lambda (indices) (nth 7 eshell-command-arguments))) - ("9" (lambda (indices) (nth 8 eshell-command-arguments))) - ("*" (lambda (indices) - (if (not indices) - eshell-command-arguments - (eshell-apply-indices eshell-command-arguments - indices))))) + ("1" ,(lambda () (nth 0 eshell-command-arguments)) nil t) + ("2" ,(lambda () (nth 1 eshell-command-arguments)) nil t) + ("3" ,(lambda () (nth 2 eshell-command-arguments)) nil t) + ("4" ,(lambda () (nth 3 eshell-command-arguments)) nil t) + ("5" ,(lambda () (nth 4 eshell-command-arguments)) nil t) + ("6" ,(lambda () (nth 5 eshell-command-arguments)) nil t) + ("7" ,(lambda () (nth 6 eshell-command-arguments)) nil t) + ("8" ,(lambda () (nth 7 eshell-command-arguments)) nil t) + ("9" ,(lambda () (nth 8 eshell-command-arguments)) nil t) + ("*" eshell-command-arguments)) "This list provides aliasing for variable references. -It is very similar in concept to what `eshell-user-aliases-list' does -for commands. Each member of this defines the name of a command, -and the Lisp value to return for that variable if it is accessed -via the syntax `$NAME'. - -If the value is a function, that function will be called with two -arguments: the list of the indices that was used in the reference, and -whether the user is requesting the length of the ultimate element. -For example, a reference of `$NAME[10][20]' would result in the -function for alias `NAME' being called (assuming it were aliased to a -function), and the arguments passed to this function would be the list -'(10 20)', and nil." +Each member is of the following form: + + (NAME VALUE [COPY-TO-ENVIRONMENT] [SIMPLE-FUNCTION]) + +NAME defines the name of the variable, VALUE is a Lisp value used to +compute the string value that will be returned when the variable is +accessed via the syntax `$NAME'. + +If VALUE is a function, its behavior depends on the value of +SIMPLE-FUNCTION. If SIMPLE-FUNCTION is nil, call VALUE with two +arguments: the list of the indices that were used in the reference, +and either t or nil depending on whether or not the variable was +quoted with double quotes. For example, if `NAME' were aliased +to a function, a reference of `$NAME[10][20]' would result in that +function being called with the arguments `((\"10\") (\"20\"))' and +nil. +If SIMPLE-FUNCTION is non-nil, call the function with no arguments +and then pass its return value to `eshell-apply-indices'. + +If VALUE is a string, return the value for the variable with that +name in the current environment. If no variable with that name exists +in the environment, but if a symbol with that same name exists and has +a value bound to it, return that symbol's value instead. You can +prefer symbol values over environment values by setting the value +of `eshell-prefer-lisp-variables' to t. + +If VALUE is a symbol, return the value bound to it. + +If VALUE has any other type, signal an error. + +Additionally, if COPY-TO-ENVIRONMENT is non-nil, the alias should be +copied (a.k.a. \"exported\") to the environment of created subprocesses." :type '(repeat (list string sexp (choice (const :tag "Copy to environment" t) - (const :tag "Use only in Eshell" nil)))) - :group 'eshell-var) + (const :tag "Use only in Eshell" nil)) + (choice (const :tag "Call without argument" t) + (const :tag "Call with 2 arguments" nil)))) + :risky t) -(put 'eshell-variable-aliases-list 'risky-local-variable t) +(defvar-keymap eshell-var-mode-map + "C-c M-v" #'eshell-insert-envvar) ;;; Functions: -(defun eshell-var-initialize () +(define-minor-mode eshell-var-mode + "Minor mode for the esh-var module. + +\\{eshell-var-mode-map}" + :keymap eshell-var-mode-map) + +(defun eshell-var-initialize () ;Called from `eshell-mode' via intern-soft! "Initialize the variable handle code." ;; Break the association with our parent's environment. Otherwise, ;; changing a variable will affect all of Emacs. (unless eshell-modify-global-environment - (set (make-local-variable 'process-environment) - (eshell-copy-environment))) - - (define-key eshell-command-map [(meta ?v)] 'eshell-insert-envvar) + (setq-local process-environment (eshell-copy-environment))) - (set (make-local-variable 'eshell-special-chars-inside-quoting) + (setq-local eshell-special-chars-inside-quoting (append eshell-special-chars-inside-quoting '(?$))) - (set (make-local-variable 'eshell-special-chars-outside-quoting) + (setq-local eshell-special-chars-outside-quoting (append eshell-special-chars-outside-quoting '(?$))) - (add-hook 'eshell-parse-argument-hook 'eshell-interpolate-variable t t) + (add-hook 'eshell-parse-argument-hook #'eshell-interpolate-variable t t) (add-hook 'eshell-prepare-command-hook - 'eshell-handle-local-variables nil t) + #'eshell-handle-local-variables nil t) (when (eshell-using-module 'eshell-cmpl) (add-hook 'pcomplete-try-first-hook - 'eshell-complete-variable-reference nil t) + #'eshell-complete-variable-reference nil t) (add-hook 'pcomplete-try-first-hook - 'eshell-complete-variable-assignment nil t))) + #'eshell-complete-variable-assignment nil t))) (defun eshell-handle-local-variables () "Allow for the syntax `VAR=val <command> <args>'." @@ -340,9 +361,11 @@ This function is explicit for adding to `eshell-parse-argument-hook'." (defun pcomplete/eshell-mode/setq () "Completion function for Eshell's `setq'." (while (and (pcomplete-here (all-completions pcomplete-stub - obarray 'boundp)) + obarray #'boundp)) (pcomplete-here)))) +;; FIXME the real "env" command does more than this, it runs a program +;; in a modified environment. (defun eshell/env (&rest args) "Implementation of `env' in Lisp." (eshell-init-print-buffer) @@ -363,9 +386,8 @@ This function is explicit for adding to `eshell-parse-argument-hook'." (defun eshell-envvar-names (&optional environment) "Return a list of currently visible environment variable names." - (mapcar (function - (lambda (x) - (substring x 0 (string-match "=" x)))) + (mapcar (lambda (x) + (substring x 0 (string-search "=" x))) (or environment process-environment))) (defun eshell-environment-variables () @@ -391,44 +413,63 @@ process any indices that come after the variable reference." (let* ((get-len (when (eq (char-after) ?#) (forward-char) t)) value indices) - (setq value (eshell-parse-variable-ref) + (setq value (eshell-parse-variable-ref get-len) indices (and (not (eobp)) (eq (char-after) ?\[) (eshell-parse-indices)) - value `(let ((indices ',indices)) ,value)) - (if get-len - `(length ,value) - value))) - -(defun eshell-parse-variable-ref () + ;; This is an expression that will be evaluated by `eshell-do-eval', + ;; which only support let-binding of dynamically-scoped vars + value `(let ((indices (eshell-eval-indices ',indices))) ,value)) + (when get-len + (setq value `(length ,value))) + (when eshell-current-quoted + (setq value `(eshell-stringify ,value))) + value)) + +(defun eshell-parse-variable-ref (&optional modifier-p) "Eval a variable reference. Returns a Lisp form which, if evaluated, will return the value of the variable. -Possible options are: +If MODIFIER-P is non-nil, the value of the variable will be +modified by some function. If MODIFIER-P is nil, the value will be +used as-is; this allows optimization of some kinds of variable +references. + +Possible variable references are: NAME an environment or Lisp variable value - <LONG-NAME> disambiguates the length of the name + \"LONG-NAME\" disambiguates the length of the name + `LONG-NAME' as above {COMMAND} result of command is variable's value - (LISP-FORM) result of Lisp form is variable's value" + (LISP-FORM) result of Lisp form is variable's value + <COMMAND> write the output of command to a temporary file; + result is the file name" (cond ((eq (char-after) ?{) (let ((end (eshell-find-delimiter ?\{ ?\}))) (if (not end) (throw 'eshell-incomplete ?\{) + (forward-char) (prog1 - (list 'eshell-convert - (list 'eshell-command-to-value - (list 'eshell-as-subcommand - (eshell-parse-command - (cons (1+ (point)) end))))) + `(eshell-apply-indices + (eshell-convert + (eshell-command-to-value + (eshell-as-subcommand + ,(let ((subcmd (or (eshell-unescape-inner-double-quote end) + (cons (point) end))) + (eshell-current-quoted nil)) + (eshell-parse-command subcmd)))) + ;; If this is a simple double-quoted form like + ;; "${COMMAND}" (i.e. no indices after the subcommand + ;; and no `#' modifier before), ensure we convert to a + ;; single string. This avoids unnecessary work + ;; (e.g. splitting the output by lines) when it would + ;; just be joined back together afterwards. + ,(when (and (not modifier-p) eshell-current-quoted) + '(not indices))) + indices ,eshell-current-quoted) (goto-char (1+ end)))))) - ((memq (char-after) '(?\' ?\")) - (let ((name (if (eq (char-after) ?\') - (eshell-parse-literal-quote) - (eshell-parse-double-quote)))) - (if name - (list 'eshell-get-variable (eval name) 'indices)))) ((eq (char-after) ?\<) (let ((end (eshell-find-delimiter ?\< ?\>))) (if (not end) @@ -437,37 +478,53 @@ Possible options are: (cmd (concat (buffer-substring (1+ (point)) end) " > " temp))) (prog1 - (list - 'let (list (list 'eshell-current-handles - (list 'eshell-create-handles temp - (list 'quote 'overwrite)))) - (list - 'progn - (list 'eshell-as-subcommand - (eshell-parse-command cmd)) - (list 'ignore - (list 'nconc 'eshell-this-command-hook - (list 'list - (list 'function - (list 'lambda nil - (list 'delete-file temp)))))) - (list 'quote temp))) + `(let ((eshell-current-handles + (eshell-create-handles ,temp 'overwrite))) + (progn + (eshell-as-subcommand + ,(let ((eshell-current-quoted nil)) + (eshell-parse-command cmd))) + (ignore + (nconc eshell-this-command-hook + ;; Quote this lambda; it will be evaluated + ;; by `eshell-do-eval', which requires very + ;; particular forms in order to work + ;; properly. See bug#54190. + (list (function + (lambda () + (delete-file ,temp) + (when-let ((buffer (get-file-buffer ,temp))) + (kill-buffer buffer))))))) + (eshell-apply-indices ,temp indices ,eshell-current-quoted))) (goto-char (1+ end))))))) ((eq (char-after) ?\() (condition-case nil - (list 'eshell-command-to-value - (list 'eshell-lisp-command - (list 'quote (read (current-buffer))))) + `(eshell-apply-indices + (eshell-command-to-value + (eshell-lisp-command + ',(read (or (eshell-unescape-inner-double-quote (point-max)) + (current-buffer))))) + indices ,eshell-current-quoted) (end-of-file (throw 'eshell-incomplete ?\()))) + ((looking-at (rx-to-string + `(or "'" ,(if eshell-current-quoted "\\\"" "\"")))) + (eshell-with-temp-command + (or (eshell-unescape-inner-double-quote (point-max)) + (cons (point) (point-max))) + (let ((name (if (eq (char-after) ?\') + (eshell-parse-literal-quote) + (eshell-parse-double-quote)))) + (when name + `(eshell-get-variable ,(eval name) indices ,eshell-current-quoted))))) ((assoc (char-to-string (char-after)) eshell-variable-aliases-list) (forward-char) - (list 'eshell-get-variable - (char-to-string (char-before)) 'indices)) + `(eshell-get-variable ,(char-to-string (char-before)) indices + ,eshell-current-quoted)) ((looking-at eshell-variable-name-regexp) (prog1 - (list 'eshell-get-variable (match-string 0) 'indices) + `(eshell-get-variable ,(match-string 0) indices ,eshell-current-quoted) (goto-char (match-end 0)))) (t (error "Invalid variable reference")))) @@ -475,44 +532,64 @@ Possible options are: (defvar eshell-glob-function) (defun eshell-parse-indices () - "Parse and return a list of list of indices." + "Parse and return a list of index-lists. + +For example, \"[0 1][2]\" becomes: + ((\"0\" \"1\") (\"2\")." (let (indices) (while (eq (char-after) ?\[) (let ((end (eshell-find-delimiter ?\[ ?\]))) (if (not end) (throw 'eshell-incomplete ?\[) (forward-char) - (let (eshell-glob-function) - (setq indices (cons (eshell-parse-arguments (point) end) - indices))) + (eshell-with-temp-command (or (eshell-unescape-inner-double-quote end) + (cons (point) end)) + (let (eshell-glob-function (eshell-current-quoted nil)) + (setq indices (cons (eshell-parse-arguments + (point-min) (point-max)) + indices)))) (goto-char (1+ end))))) (nreverse indices))) -(defun eshell-get-variable (name &optional indices) - "Get the value for the variable NAME." - (let* ((alias (assoc name eshell-variable-aliases-list)) - (var (if alias - (cadr alias) - name))) - (if (and alias (functionp var)) - (funcall var indices) - (eshell-apply-indices - (cond - ((stringp var) - (let ((sym (intern-soft var))) - (if (and sym (boundp sym) - (or eshell-prefer-lisp-variables - (memq sym eshell--local-vars) ; bug#15372 - (not (getenv var)))) - (symbol-value sym) - (getenv var)))) - ((symbolp var) - (symbol-value var)) - (t - (error "Unknown variable `%s'" (eshell-stringify var)))) - indices)))) - -(defun eshell-apply-indices (value indices) +(defun eshell-eval-indices (indices) + "Evaluate INDICES, a list of index-lists generated by `eshell-parse-indices'." + (mapcar (lambda (i) (mapcar #'eval i)) indices)) + +(defun eshell-get-variable (name &optional indices quoted) + "Get the value for the variable NAME. +INDICES is a list of index-lists (see `eshell-parse-indices'). +If QUOTED is non-nil, this was invoked inside double-quotes." + (if-let ((alias (assoc name eshell-variable-aliases-list))) + (let ((target (nth 1 alias))) + (cond + ((functionp target) + (if (nth 3 alias) + (eshell-apply-indices (funcall target) indices quoted) + (condition-case nil + (funcall target indices quoted) + (wrong-number-of-arguments + (display-warning + :warning (concat "Function for `eshell-variable-aliases-list' " + "entry should accept two arguments: INDICES " + "and QUOTED.'")) + (funcall target indices))))) + ((symbolp target) + (eshell-apply-indices (symbol-value target) indices quoted)) + (t + (eshell-get-variable target indices quoted)))) + (unless (stringp name) + (error "Unknown variable `%s'" (eshell-stringify name))) + (eshell-apply-indices + (let ((sym (intern-soft name))) + (if (and sym (boundp sym) + (or eshell-prefer-lisp-variables + (memq sym eshell--local-vars) ; bug#15372 + (not (getenv name)))) + (symbol-value sym) + (getenv name))) + indices quoted))) + +(defun eshell-apply-indices (value indices &optional quoted) "Apply to VALUE all of the given INDICES, returning the sub-result. The format of INDICES is: @@ -521,12 +598,18 @@ The format of INDICES is: Each member of INDICES represents a level of nesting. If the first member of a sublist is not an integer or name, and the value it's -reference is a string, that will be used as the regexp with which is -to divide the string into sub-parts. The default is whitespace. +referencing is a string, that will be used as the regexp with which +is to divide the string into sub-parts. The default is whitespace. Otherwise, each INT-OR-NAME refers to an element of the list value. Integers imply a direct index, and names, an associate lookup using `assoc'. +If QUOTED is non-nil, this was invoked inside double-quotes. +This affects the behavior of splitting strings: without quoting, +the split values are converted to numbers via +`eshell-convert-to-number' if possible; with quoting, they're +left as strings. + For example, to retrieve the second element of a user's record in '/etc/passwd', the variable reference would look like: @@ -534,16 +617,14 @@ For example, to retrieve the second element of a user's record in (while indices (let ((refs (car indices))) (when (stringp value) - (let (separator) - (if (not (or (not (stringp (caar indices))) - (string-match - (concat "^" eshell-variable-name-regexp "$") - (caar indices)))) - (setq separator (caar indices) - refs (cdr refs))) - (setq value - (mapcar 'eshell-convert - (split-string value separator))))) + (let (separator (index (caar indices))) + (when (and (stringp index) + (not (get-text-property 0 'number index))) + (setq separator index + refs (cdr refs))) + (setq value (split-string value separator)) + (unless quoted + (setq value (mapcar #'eshell-convert-to-number value))))) (cond ((< (length refs) 0) (error "Invalid array variable index: %s" @@ -565,23 +646,24 @@ For example, to retrieve the second element of a user's record in "Reference VALUE using the given INDEX." (when (and (stringp index) (get-text-property 0 'number index)) (setq index (string-to-number index))) - (if (stringp index) - (cdr (assoc index value)) - (cond - ((ring-p value) - (if (> index (ring-length value)) - (error "Index exceeds length of ring") - (ring-ref value index))) - ((listp value) - (if (> index (length value)) - (error "Index exceeds length of list") - (nth index value))) - ((vectorp value) - (if (> index (length value)) - (error "Index exceeds length of vector") - (aref value index))) - (t - (error "Invalid data type for indexing"))))) + (if (integerp index) + (cond + ((ring-p value) + (if (> index (ring-length value)) + (error "Index exceeds length of ring") + (ring-ref value index))) + ((listp value) + (if (> index (length value)) + (error "Index exceeds length of list") + (nth index value))) + ((vectorp value) + (if (> index (length value)) + (error "Index exceeds length of vector") + (aref value index))) + (t + (error "Invalid data type for indexing"))) + ;; INDEX is some non-integer value, so treat VALUE as an alist. + (cdr (assoc index value)))) ;;;_* Variable name completion @@ -605,14 +687,13 @@ For example, to retrieve the second element of a user's record in (sort (append (mapcar - (function - (lambda (varname) - (let ((value (eshell-get-variable varname))) - (if (and value - (stringp value) - (file-directory-p value)) - (concat varname "/") - varname)))) + (lambda (varname) + (let ((value (eshell-get-variable varname))) + (if (and value + (stringp value) + (file-directory-p value)) + (concat varname "/") + varname))) (eshell-envvar-names (eshell-environment-variables))) (all-completions argname obarray 'boundp) completions) @@ -628,4 +709,5 @@ For example, to retrieve the second element of a user's record in (setq pcomplete-stub (substring arg pos)) (throw 'pcomplete-completions (pcomplete-entries))))) +(provide 'esh-var) ;;; esh-var.el ends here |