branch: externals/shell-command+
commit ab6bb0e260ba40315ff22ff9641562d29f7f9ac5
Author: Philip K <[email protected]>
Commit: Philip K <[email protected]>
reworked `.' command
---
bang.el | 70 +++++++++++++++++++++++++++++++++++++++++------------------------
1 file changed, 44 insertions(+), 26 deletions(-)
diff --git a/bang.el b/bang.el
index 8907f37..57cfe4d 100644
--- a/bang.el
+++ b/bang.el
@@ -32,6 +32,27 @@
;;; Code:
+(defconst bang--command-regexp
+ (rx bos (* space)
+ (? (group (or "." "/") (* (not space))) (+ space))
+ (or (group "<") (group ">") (group "|") "!" "")
+ (* space)
+ (group (* not-newline))
+ eos))
+
+(defun bang-expand-path (path)
+ "Expand any PATH into absolute path with additional tricks.
+
+Furthermore, replace each sequence with three or more `.'s with a
+proper upwards directory pointers. This means that '....' becomes
+'../../../..', and so on."
+ (expand-file-name
+ (replace-regexp-in-string
+ (rx (>= 2 "."))
+ (lambda (sub)
+ (mapconcat #'identity (make-list (1- (length sub)) "..") "/"))
+ path)))
+
(defun bang (command beg end)
"Intelligently execute string COMMAND in inferior shell.
@@ -39,10 +60,15 @@ When COMMAND starts with
< the output of COMMAND replaces the current selection
> COMMAND is run with the current selection as input
| the current selection is filtered through COMMAND
- . COMMAND executes in the relative path following the dot
+ ! COMMAND is simply executed (same as without any prefix)
Without any argument, `bang' will behave like `shell-command'.
+Before these characters, one may also place a relative or
+absolute path, which will be the current working directory in
+which the command will be executed. See `bang-expand-path' for
+more details on this expansion.
+
Inside COMMAND, % is replaced with the current file name. To
insert a literal % quote it using a backslash.
@@ -52,18 +78,12 @@ between BEG and END. Otherwise the whole buffer is
processed."
(if (use-region-p) (region-beginning) (point-min))
(if (use-region-p) (region-end) (point-max))))
(save-match-data
- (unless (string-match (rx bos (* space)
- (or (group "<") (group ">") (group "|")
- (group "." (* (not space))) "")
- (* space)
- (group (* not-newline))
- eos)
- command)
+ (unless (string-match bang--command-regexp command)
(error "Invalid command"))
- (let ((has-< (match-string-no-properties 1 command))
- (has-> (match-string-no-properties 2 command))
- (has-| (match-string-no-properties 3 command))
- (has-. (match-string-no-properties 4 command))
+ (let ((path (match-string-no-properties 1 command))
+ (has-< (match-string-no-properties 2 command))
+ (has-> (match-string-no-properties 3 command))
+ (has-| (match-string-no-properties 4 command))
(rest (condition-case nil
(replace-regexp-in-string
(rx (* ?\\ ?\\) (or ?\\ (group "%")))
@@ -71,20 +91,18 @@ between BEG and END. Otherwise the whole buffer is
processed."
(match-string-no-properties 5 command)
nil nil 1)
(error (match-string-no-properties 5 command)))))
- (cond (has-< (delete-region beg end)
- (shell-command rest t shell-command-default-error-buffer)
- (exchange-point-and-mark))
- (has-> (shell-command-on-region
- beg end rest nil nil
- shell-command-default-error-buffer t))
- (has-| (shell-command-on-region
- beg end rest t t
- shell-command-default-error-buffer t))
- (has-. (let ((default-directory (expand-file-name has-.)))
- (shell-command rest (if current-prefix-arg t nil)
- shell-command-default-error-buffer)))
- (t (shell-command command (if current-prefix-arg t nil)
- shell-command-default-error-buffer)))
+ (let ((default-directory (bang-expand-path path)))
+ (cond (has-< (delete-region beg end)
+ (shell-command rest t shell-command-default-error-buffer)
+ (exchange-point-and-mark))
+ (has-> (shell-command-on-region
+ beg end rest nil nil
+ shell-command-default-error-buffer t))
+ (has-| (shell-command-on-region
+ beg end rest t t
+ shell-command-default-error-buffer t))
+ (t (shell-command command (if current-prefix-arg t nil)
+ shell-command-default-error-buffer))))
(when has->
(with-current-buffer "*Shell Command Output*"
(delete-region (point-min) (point-max)))))))