| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 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 |
|---|
| 31 |
appears unquoted in any argument (except when that argument is |
|---|
| 32 |
surrounded by single quotes). It may be used to interpolate a |
|---|
| 33 |
variable value, a subcommand, or even the result of a Lisp form." |
|---|
| 34 |
:tag "Variable handling" |
|---|
| 35 |
:group 'eshell) |
|---|
| 36 |
|
|---|
| 37 |
|
|---|
| 38 |
|
|---|
| 39 |
|
|---|
| 40 |
|
|---|
| 41 |
|
|---|
| 42 |
|
|---|
| 43 |
|
|---|
| 44 |
|
|---|
| 45 |
|
|---|
| 46 |
|
|---|
| 47 |
|
|---|
| 48 |
|
|---|
| 49 |
|
|---|
| 50 |
|
|---|
| 51 |
|
|---|
| 52 |
|
|---|
| 53 |
|
|---|
| 54 |
|
|---|
| 55 |
|
|---|
| 56 |
|
|---|
| 57 |
|
|---|
| 58 |
|
|---|
| 59 |
|
|---|
| 60 |
|
|---|
| 61 |
|
|---|
| 62 |
|
|---|
| 63 |
|
|---|
| 64 |
|
|---|
| 65 |
|
|---|
| 66 |
|
|---|
| 67 |
|
|---|
| 68 |
|
|---|
| 69 |
|
|---|
| 70 |
|
|---|
| 71 |
|
|---|
| 72 |
|
|---|
| 73 |
|
|---|
| 74 |
|
|---|
| 75 |
|
|---|
| 76 |
|
|---|
| 77 |
|
|---|
| 78 |
|
|---|
| 79 |
|
|---|
| 80 |
|
|---|
| 81 |
|
|---|
| 82 |
|
|---|
| 83 |
|
|---|
| 84 |
|
|---|
| 85 |
|
|---|
| 86 |
|
|---|
| 87 |
|
|---|
| 88 |
|
|---|
| 89 |
|
|---|
| 90 |
|
|---|
| 91 |
|
|---|
| 92 |
|
|---|
| 93 |
|
|---|
| 94 |
|
|---|
| 95 |
|
|---|
| 96 |
|
|---|
| 97 |
|
|---|
| 98 |
|
|---|
| 99 |
|
|---|
| 100 |
|
|---|
| 101 |
|
|---|
| 102 |
|
|---|
| 103 |
|
|---|
| 104 |
|
|---|
| 105 |
|
|---|
| 106 |
|
|---|
| 107 |
|
|---|
| 108 |
|
|---|
| 109 |
|
|---|
| 110 |
|
|---|
| 111 |
|
|---|
| 112 |
|
|---|
| 113 |
|
|---|
| 114 |
|
|---|
| 115 |
|
|---|
| 116 |
|
|---|
| 117 |
|
|---|
| 118 |
|
|---|
| 119 |
|
|---|
| 120 |
|
|---|
| 121 |
(require 'env) |
|---|
| 122 |
(require 'ring) |
|---|
| 123 |
|
|---|
| 124 |
|
|---|
| 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 |
|
|---|
| 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 |
|
|---|
| 146 |
(defcustom eshell-variable-name-regexp "[A-Za-z0-9_-]+" |
|---|
| 147 |
"*A regexp identifying what constitutes a variable name reference. |
|---|
| 148 |
Note that this only applies for '$NAME'. If the syntax '$<NAME>' is |
|---|
| 149 |
used, then NAME can contain any character, including angle brackets, |
|---|
| 150 |
if they are quoted with a backslash." |
|---|
| 151 |
:type 'regexp |
|---|
| 152 |
:group 'eshell-var) |
|---|
| 153 |
|
|---|
| 154 |
(defcustom eshell-variable-aliases-list |
|---|
| 155 |
'( |
|---|
| 156 |
("COLUMNS" (lambda (indices) (window-width)) t) |
|---|
| 157 |
("LINES" (lambda (indices) (window-height)) t) |
|---|
| 158 |
|
|---|
| 159 |
|
|---|
| 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. |
|---|
| 183 |
It is very similar in concept to what `eshell-user-aliases-list' does |
|---|
| 184 |
for commands. Each member of this defines defines the name of a |
|---|
| 185 |
command, and the Lisp value to return for that variable if it is |
|---|
| 186 |
accessed via the syntax '$NAME'. |
|---|
| 187 |
|
|---|
| 188 |
If the value is a function, that function will be called with two |
|---|
| 189 |
arguments: the list of the indices that was used in the reference, and |
|---|
| 190 |
whether the user is requesting the length of the ultimate element. |
|---|
| 191 |
For example, a reference of '$NAME[10][20]' would result in the |
|---|
| 192 |
function for alias `NAME' being called (assuming it were aliased to a |
|---|
| 193 |
function), 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 |
|
|---|
| 203 |
|
|---|
| 204 |
(defun eshell-var-initialize () |
|---|
| 205 |
"Initialize the variable handle code." |
|---|
| 206 |
|
|---|
| 207 |
|
|---|
| 208 |
(unless eshell-modify-global-environment |
|---|
| 209 |
(set (make-local-variable 'process-environment) |
|---|
| 210 |
(eshell-copy-environment))) |
|---|
| 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 |
|
|---|
| 219 |
(add-hook 'eshell-parse-argument-hook 'eshell-interpolate-variable t t) |
|---|
| 220 |
|
|---|
| 221 |
(add-hook 'eshell-prepare-command-hook |
|---|
| 222 |
'eshell-handle-local-variables nil t) |
|---|
| 223 |
|
|---|
| 224 |
(when (eshell-using-module 'eshell-cmpl) |
|---|
| 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 |
|
|---|
| 233 |
|
|---|
| 234 |
|
|---|
| 235 |
|
|---|
| 236 |
|
|---|
| 237 |
|
|---|
| 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 |
|
|---|
| 246 |
|
|---|
| 247 |
|
|---|
| 248 |
|
|---|
| 249 |
|
|---|
| 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. |
|---|
| 272 |
This function is explicit for adding to `eshell-parse-argument-hook'." |
|---|
| 273 |
(when (and (eq (char-after) ?$) |
|---|
| 274 |
(/= (1+ (point)) (point-max))) |
|---|
| 275 |
(forward-char) |
|---|
| 276 |
(list 'eshell-escape-arg |
|---|
| 277 |
(eshell-parse-variable)))) |
|---|
| 278 |
|
|---|
| 279 |
(defun eshell/define (var-alias definition) |
|---|
| 280 |
"Define a VAR-ALIAS using DEFINITION." |
|---|
| 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) |
|---|
| 301 |
"This alias allows the `export' command to act as bash users expect." |
|---|
| 302 |
(while sets |
|---|
| 303 |
(if (and (stringp (car sets)) |
|---|
| 304 |
(string-match "^\\([^=]+\\)=\\(.*\\)" (car sets))) |
|---|
| 305 |
(setenv (match-string 1 (car sets)) |
|---|
| 306 |
(match-string 2 (car sets)))) |
|---|
| 307 |
(setq sets (cdr sets)))) |
|---|
| 308 |
|
|---|
| 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 |
|
|---|
| 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 |
|
|---|
| 323 |
(defun pcomplete/eshell-mode/unset () |
|---|
| 324 |
"Completion function for Eshell's `unset'." |
|---|
| 325 |
(while (pcomplete-here (eshell-envvar-names)))) |
|---|
| 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. |
|---|
| 371 |
This involves setting any variable aliases which affect the |
|---|
| 372 |
environment, 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. |
|---|
| 383 |
The variable name could refer to either an environment variable, or a |
|---|
| 384 |
Lisp variable. The priority order depends on the setting of |
|---|
| 385 |
`eshell-prefer-lisp-variables'. |
|---|
| 386 |
|
|---|
| 387 |
Its purpose is to call `eshell-parse-variable-ref', and then to |
|---|
| 388 |
process 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. |
|---|
| 406 |
Returns a Lisp form which, if evaluated, will return the value of the |
|---|
| 407 |
variable. |
|---|
| 408 |
|
|---|
| 409 |
Possible 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)))) |
|---|
| 434 |
((eq (char-after) ?\<) |
|---|
| 435 |
(let ((end (eshell-find-delimiter ?\< ?\>))) |
|---|
| 436 |
(if (not end) |
|---|
| 437 |
(throw 'eshell-incomplete ?\<) |
|---|
| 438 |
(let* ((temp (make-temp-file temporary-file-directory)) |
|---|
| 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. |
|---|
| 540 |
The format of INDICES is: |
|---|
| 541 |
|
|---|
| 542 |
((INT-OR-NAME-OR-OTHER INT-OR-NAME INT-OR-NAME ...) |
|---|
| 543 |
...) |
|---|
| 544 |
|
|---|
| 545 |
Each member of INDICES represents a level of nesting. If the first |
|---|
| 546 |
member of a sublist is not an integer or name, and the value it's |
|---|
| 547 |
reference is a string, that will be used as the regexp with which is |
|---|
| 548 |
to divide the string into sub-parts. The default is whitespace. |
|---|
| 549 |
Otherwise, each INT-OR-NAME refers to an element of the list value. |
|---|
| 550 |
Integers imply a direct index, and names, an associate lookup using |
|---|
| 551 |
`assoc'. |
|---|
| 552 |
|
|---|
| 553 |
For 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) |
|---|
| 572 |
(error "Invalid array variable index: %s" |
|---|
| 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)) |
|---|
| 635 |
(concat varname "/") |
|---|
| 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 |
|
|---|
| 654 |
;;; arch-tag: 393654fe-bdad-4f27-9a10-b1472ded14cf |
|---|
| 655 |
;;; esh-var.el ends here |
|---|
| 656 |
|
|---|