[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/bash-completion f2ea2b65df 141/313: Detect directories whe
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/bash-completion f2ea2b65df 141/313: Detect directories when expanding commands and add a slash instead of a |
Date: |
Sat, 3 Dec 2022 10:59:24 -0500 (EST) |
branch: elpa/bash-completion
commit f2ea2b65df5e6c7fd1c0aa61f6d80f444692f9ea
Author: Stephane Zermatten <szermatt@gmx.net>
Commit: Stephane Zermatten <szermatt@gmx.net>
Detect directories when expanding commands and add a slash instead of a
space. fixes #11
Before this commit, the parameter -S ' ' was passed to compgen when
expanding a command, which means that it would always append a space.
Adding a space is useful when expanding a command, but annoying when
expanding a directory.
With this commit, the space is added by bash-completion.el instead of
bash commands, allows checking for matching directory.
---
bash-completion-test.el | 107 +++++++++++++++++++-------------
bash-completion.el | 160 ++++++++++++++++++++++++------------------------
2 files changed, 146 insertions(+), 121 deletions(-)
diff --git a/bash-completion-test.el b/bash-completion-test.el
index 95dd55c80d..9454793fa4 100644
--- a/bash-completion-test.el
+++ b/bash-completion-test.el
@@ -411,36 +411,6 @@ garbage
(let ((default-directory "~/x"))
(bash-completion-cd-command-prefix)))))
-(ert-deftest bash-completion-addsuffix-test ()
- (cl-letf (((symbol-function 'file-accessible-directory-p)
- (lambda (a) (error "unexpected"))))
- (should (equal "hello/" (bash-completion-addsuffix nil "hello/")))
- ;; ends with space"
- (should (equal "hello " (bash-completion-addsuffix nil "hello ")))
- ;; ends with separator"
- (should (equal "hello:" (bash-completion-addsuffix nil "hello:"))))
- ;; check directory"
- (cl-letf (((symbol-function 'file-accessible-directory-p)
- (lambda (a) (equal a "/tmp/hello")))
- (default-directory "/tmp"))
- (should (equal "hello/" (bash-completion-addsuffix nil "hello"))))
- (cl-letf (((symbol-function 'file-accessible-directory-p)
- (lambda (a) (equal a "/tmp/hello world")))
- (default-directory "/tmp"))
- (should (equal "hello\\ world/" (bash-completion-addsuffix nil "hello\\
world"))))
- (cl-letf (((symbol-function 'file-accessible-directory-p)
- (lambda (a) (equal a "/tmp/hello \"world\"")))
- (default-directory "/tmp"))
- (should (equal "hello \\\"world\\\"/" (bash-completion-addsuffix ?\"
"hello \\\"world\\\""))))
- (cl-letf (((symbol-function 'file-accessible-directory-p)
- (lambda (a) (equal a "/tmp/d'uh")))
- (default-directory "/tmp"))
- (should (equal "d'\\''uh/" (bash-completion-addsuffix ?' "d'\\''uh"))))
- (cl-letf (((symbol-function 'file-accessible-directory-p)
- (lambda (a) (equal a (concat (expand-file-name "y" "~/x")))))
- (default-directory "~/x"))
- (should (equal "y/" (bash-completion-addsuffix nil "y")))))
-
(ert-deftest bash-completion-starts-with-test ()
(should (equal nil (bash-completion-starts-with "" "hello ")))
(should (equal t (bash-completion-starts-with "hello world" "hello ")))
@@ -487,38 +457,62 @@ garbage
(ert-deftest bash-completion-fix-test ()
;; escape rest
(should (equal "a\\ bc\\ d\\ e"
- (bash-completion-fix "a\\ bc d e" "a\\ b" "a\\ b")))
+ (bash-completion-fix "a\\ bc d e" "a\\ b" "a\\ b" nil nil)))
;; recover original escaping
(should (equal "a' 'bc\\ d\\ e"
- (bash-completion-fix "a\\ bc d e" "a\\ b" "a' 'b")))
+ (bash-completion-fix "a\\ bc d e" "a\\ b" "a' 'b" nil nil)))
;; do not escape final space
(should (equal "ab "
(let ((bash-completion-nospace nil))
- (bash-completion-fix "ab " "a" "a"))))
+ (bash-completion-fix "ab " "a" "a" nil nil))))
;; remove final space
(should (equal "ab"
(let ((bash-completion-nospace t))
- (bash-completion-fix "ab " "a" "a"))))
+ (bash-completion-fix "ab " "a" "a" nil nil))))
;; unexpand home and escape
(should (equal "~/a/hello\\ world"
(bash-completion-fix (expand-file-name "~/a/hello world")
- "~/a/he" "~/a/he")))
+ "~/a/he" "~/a/he" nil nil)))
;; match after wordbreak and escape
(should (equal "a:b:c:hello\\ world"
- (bash-completion-fix "hello world" "a:b:c:he" "a:b:c:he")))
+ (bash-completion-fix "hello world" "a:b:c:he" "a:b:c:he" nil
nil)))
;; just append
(should (equal "hello\\ world"
- (bash-completion-fix " world" "hello" "hello")))
+ (bash-completion-fix " world" "hello" "hello" nil nil)))
+
+ ;; append / for home
+ (should (equal "~/"
+ (bash-completion-fix (expand-file-name "~") "~" "~" nil
nil)))
+
+ (cl-letf (((symbol-function 'file-accessible-directory-p)
+ (lambda (d)
+ (message "check: %s" d)
+ (equal d "/tmp/somedir"))))
+ (let ((default-directory "/tmp/"))
+ ;; append / for directory
+ (should (equal "somedir/"
+ (bash-completion-fix "somedir" "some" "some" nil nil)))
+ ;; append / for initial command that is a directory
+ (should (equal "somedir/"
+ (bash-completion-fix "somedir" "some" "some" nil t)))))
+
+ ;; append a space for initial command that is not a directory
+ (should (let ((bash-completion-nospace nil))
+ (equal "somecmd " (bash-completion-fix "somecmd" "some" "some" nil
t))))
+
+ ;; ... but not if nospace is t.
+ (should (let ((bash-completion-nospace t))
+ (equal "somecmd" (bash-completion-fix "somecmd" "some" "some" nil
t))))
;; subset of the prefix"
(should (equal "Dexter"
- (bash-completion-fix "Dexter" "Dexter'" "Dexter'"))))
+ (bash-completion-fix "Dexter" "Dexter'" "Dexter'" nil nil))))
(ert-deftest bash-completion-extract-candidates-test ()
(should (equal
@@ -528,7 +522,7 @@ garbage
(cl-letf (((symbol-function 'bash-completion-buffer)
(lambda () (current-buffer)))
(bash-completion-nospace nil))
- (bash-completion-extract-candidates "hello" "hello" nil))))))
+ (bash-completion-extract-candidates "hello" "hello" nil nil))))))
(ert-deftest bash-completion-nonsep-test ()
(should (equal "^ \t\n\r;&|'\"#"
@@ -643,7 +637,8 @@ garbage
(let ((comint-dynamic-complete-functions
'(bash-completion-dynamic-complete)))
(completion-at-point))
(bash-completion-dynamic-complete))
- (buffer-substring (comint-line-beginning-position) (point))))
+ (buffer-substring-no-properties
+ (comint-line-beginning-position) (point))))
;; finally
(when (and shell-buffer (buffer-live-p shell-buffer))
(kill-process (get-buffer-process shell-buffer))
@@ -726,6 +721,24 @@ before calling `bash-completion-dynamic-complete-nocomint'.
(should (equal "cd >/dev/null 2>&1 /tmp/test ; compgen -o default he
2>/dev/null"
(pop --captured-commands)))))
+(ert-deftest bash-completion-trailing ()
+ (--with-fake-bash-completion-send
+ (push "without space\nwith space \nwith slash/\n" --send-results)
+ (insert "$ ls with")
+ (let ((bash-completion-nospace nil))
+ (should (equal
+ '("without\\ space" "with\\ space " "with\\ slash/")
+ (nth 2 (bash-completion-dynamic-complete-nocomint 3
(point))))))))
+
+(ert-deftest bash-completion-trailing-nospace ()
+ (--with-fake-bash-completion-send
+ (push "without space\nwith space \nwith slash/\n" --send-results)
+ (insert "$ ls with")
+ (let ((bash-completion-nospace t))
+ (should (equal
+ '("without\\ space" "with\\ space" "with\\ slash/")
+ (nth 2 (bash-completion-dynamic-complete-nocomint 3
(point))))))))
+
(ert-deftest bash-completion-complete-dir-with-spaces-test ()
(--with-fake-bash-completion-send
(push "/tmp/test/Documents" --directories)
@@ -740,7 +753,7 @@ before calling `bash-completion-dynamic-complete-nocomint'.
(push "Documents/Modes d'emplois\n" --send-results)
(should (equal
'("Documents/Modes\\ d\\'emplois/")
- (nth 2(bash-completion-dynamic-complete-nocomint 3 (point)))))
+ (nth 2 (bash-completion-dynamic-complete-nocomint 3 (point)))))
(insert "Modes\\ d\\'emplois/")
(push "Documents/Modes d'emplois/KAR 1.pdf\nDocuments/Modes d'emplois/KAR
2.pdf\n"
--send-results)
@@ -772,4 +785,16 @@ before calling `bash-completion-dynamic-complete-nocomint'.
"Documents/Modes d'\\''emplois/KAR 2.pdf")
(nth 2 (bash-completion-dynamic-complete-nocomint 3 (point)))))))
+(ert-deftest bash-completion-complete-command-with-dir ()
+ (--with-fake-bash-completion-send
+ (push "/tmp/test/bin" --directories)
+ (push "bin\nbind\n" --send-results)
+ (insert "$ b")
+ (should (equal
+ '("bin/" "bind ")
+ (nth 2 (bash-completion-dynamic-complete-nocomint 3 (point)))))
+ (should (equal (concat "cd >/dev/null 2>&1 /tmp/test ; "
+ "compgen -b -c -a -A function b 2>/dev/null")
+ (pop --captured-commands)))))
+
;;; bash-completion_test.el ends here
diff --git a/bash-completion.el b/bash-completion.el
index ea2f173c23..a0e8850ded 100644
--- a/bash-completion.el
+++ b/bash-completion.el
@@ -198,9 +198,6 @@ to remove the extra space bash adds after a completion."
(defvar bash-completion-process nil
"Bash process object.")
-(defvar bash-completion-unparsed-prefix "" "")
-(defvar bash-completion-parsed-prefix "" "")
-(defvar bash-completion-open-quote nil "")
(defvar bash-completion-alist nil
"Maps from command name to the 'complete' arguments.
@@ -392,7 +389,7 @@ This function is not meant to be called outside of
(bash-completion-quote after-wordbreak)))
(let ((completions
(bash-completion-extract-candidates
- after-wordbreak unparsed-after-wordbreak open-quote)))
+ after-wordbreak unparsed-after-wordbreak open-quote nil)))
(list (+ stub-start separator-pos-in-unparsed)
pos
completions)))))
@@ -701,9 +698,9 @@ The result is a list of candidates, which might be empty."
(bash-completion-generate-line line pos words cword nil))))
(when (eq 0 completion-status)
(bash-completion-extract-candidates
- (nth cword words) unparsed-stub open-quote))))
+ (nth cword words) unparsed-stub open-quote (eq cword 0)))))
-(defun bash-completion-extract-candidates (parsed-stub unparsed-stub
open-quote)
+(defun bash-completion-extract-candidates (parsed-stub unparsed-stub
open-quote is-command)
"Extract the completion candidates from the process buffer for PARSED-STUB.
This command takes the content of the completion process buffer,
@@ -716,17 +713,20 @@ for directory name detection to work.
If PARSED-STUB is quoted, the quote character, ' or \", should be
passed in OPEN-QUOTE.
+If IS-COMMAND is t, it is passed down to `bash-completion-suffix'
+
Post-processing includes escaping special characters, adding a /
to directory names, replacing STUB with UNPARSED-STUB in the
result. See `bash-completion-fix' for more details."
- (let ((bash-completion-parsed-prefix parsed-stub)
- (bash-completion-unparsed-prefix unparsed-stub)
- (bash-completion-open-quote open-quote))
- (mapcar 'bash-completion-fix
- (with-current-buffer (bash-completion-buffer)
- (split-string (buffer-string) "\n" t)))))
-
-(defun bash-completion-fix (str &optional parsed-prefix unparsed-prefix
open-quote)
+ (let ((result (list)))
+ (dolist (completion (with-current-buffer (bash-completion-buffer)
+ (split-string (buffer-string) "\n" t)))
+ (push (bash-completion-fix
+ completion parsed-stub unparsed-stub open-quote is-command)
+ result))
+ (nreverse result)))
+
+(defun bash-completion-fix (str parsed-prefix unparsed-prefix open-quote
is-command)
"Fix completion candidate in STR if PREFIX is the current prefix.
STR is the completion candidate to modify.
@@ -743,6 +743,9 @@ character (' or \") or nil. If it is nil, the value of
`bash-completion-open-quote' is used. This allows
calling this function from `mapcar'.
+If IS-COMMAND is t and `bash-completion-nospace' isn't set,
+guarantee the result return with a known suffix or space.
+
Return a modified version of the completion candidate.
Modification include:
@@ -755,42 +758,62 @@ It should be invoked with the comint buffer as the
current buffer
for directory name detection to work."
(let ((parsed-prefix (or parsed-prefix bash-completion-parsed-prefix))
(unparsed-prefix (or unparsed-prefix bash-completion-unparsed-prefix))
- (open-quote (or open-quote (and bash-completion-open-quote)))
- (suffix ""))
- (bash-completion-addsuffix
- open-quote
- (let* (rebuilt
- (rest (cond
- ((bash-completion-starts-with str parsed-prefix)
- (substring str (length parsed-prefix)))
- ;; unexpand the home directory expanded by bash automatically
- ((and (bash-completion-starts-with parsed-prefix "~")
- (bash-completion-starts-with str (expand-file-name
"~")))
- (substring (concat "~" (substring str (length
(expand-file-name "~"))))
- (length parsed-prefix)))
- ((bash-completion-starts-with parsed-prefix str)
- ;; completion is a substring of prefix something's gone
- ;; wrong. Treat it as one (useless) candidate.
- (setq unparsed-prefix "")
- str)
- ;; completion sometimes only applies to the last word, as
- ;; defined by COMP_WORDBREAKS. This detects and works around
- ;; this feature.
- ((bash-completion-starts-with
- (setq rebuilt (concat
(bash-completion-before-last-wordbreak parsed-prefix) str))
- parsed-prefix)
- (substring rebuilt (length parsed-prefix)))
- ;; there is no meaningful link between the prefix and
- ;; the string. just append the string to the prefix and
- ;; hope for the best.
- (t str))))
- (when (bash-completion-ends-with rest " ")
- (setq rest (substring rest 0 -1))
- (unless bash-completion-nospace
- (setq suffix " ")))
- (concat unparsed-prefix
- (bash-completion-escape-candidate rest open-quote)
- suffix)))))
+ (open-quote (or open-quote (and bash-completion-open-quote)))
+ (suffix "")
+ (rest) ; the part between the prefix and the suffix
+ (rebuilt))
+
+ ;; build rest by removing parsed-prefix from str
+ (cond
+ ((bash-completion-starts-with str parsed-prefix)
+ (setq rest (substring str (length parsed-prefix))))
+
+ ;; unexpand the home directory expanded by bash automatically
+ ((and (bash-completion-starts-with parsed-prefix "~")
+ (bash-completion-starts-with str (expand-file-name "~")))
+ (setq rest (substring (concat "~" (substring str (length
(expand-file-name "~"))))
+ (length parsed-prefix))))
+
+ ((bash-completion-starts-with parsed-prefix str)
+ ;; completion is a substring of prefix something's gone
+ ;; wrong. Treat it as one (useless) candidate.
+ (setq unparsed-prefix "")
+ (setq rest str))
+
+ ;; completion sometimes only applies to the last word, as
+ ;; defined by COMP_WORDBREAKS. This detects and works around
+ ;; this feature.
+ ((bash-completion-starts-with
+ (setq rebuilt (concat (bash-completion-before-last-wordbreak
parsed-prefix) str))
+ parsed-prefix)
+ (setq rest (substring rebuilt (length parsed-prefix))))
+
+ ;; there is no meaningful link between the prefix and
+ ;; the string. just append the string to the prefix and
+ ;; hope for the best.
+ (t (setq rest str)))
+
+ ;; build suffix
+ (let ((last-char (bash-completion-last-char rest)))
+ (cond
+ ((eq ?\ last-char)
+ (setq rest (substring rest 0 -1))
+ (setq suffix (if bash-completion-nospace "" " ")))
+ ((or (memq last-char bash-completion-wordbreaks)
+ (eq ?/ last-char))
+ (setq suffix ""))
+ ((file-accessible-directory-p
+ (expand-file-name (bash-completion-unescape
+ open-quote (concat parsed-prefix rest))
+ default-directory))
+ (setq suffix "/"))
+ (is-command
+ (setq suffix (if bash-completion-nospace "" " ")))))
+
+ ;; put everything back together
+ (concat unparsed-prefix
+ (bash-completion-escape-candidate rest open-quote)
+ suffix)))
(defun bash-completion-escape-candidate (completion-candidate open-quote)
"Escapes COMPLETION-CANDIDATE.
@@ -828,24 +851,6 @@ Return a possibly escaped version of COMPLETION-CANDIDATE."
(replace-regexp-in-string "'\\\\''" "'" string)
(replace-regexp-in-string "\\(\\\\\\)\\(.\\)" "\\2" string)))
-(defconst bash-completion-known-suffixes-regexp
- (concat "[" (regexp-quote bash-completion-wordbreaks-str) "/ ]$")
- "Regexp matching known suffixes for `bash-completion-addsuffix'.")
-
-(defun bash-completion-addsuffix (open-quote str)
- "Add a directory suffix to OPEN-QUOTE'd STR if it looks like a directory.
-
-This function looks for a directory called STR relative to the
-buffer-local variable default-directory. If it exists, it returns
-\(concat STR \"/\"). Otherwise it retruns STR."
- (if (and (null (string-match bash-completion-known-suffixes-regexp str))
- (file-accessible-directory-p
- (expand-file-name
- (bash-completion-unescape open-quote str)
- default-directory)))
- (concat str "/")
- str))
-
(defun bash-completion-before-last-wordbreak (str)
"Return the part of STR that comes after the last wordbreak character.
The return value does not include the worbreak character itself.
@@ -891,15 +896,11 @@ Return a CONS containing (before . after)."
(setq end (1- end))))
(list "" str ?\0)))
-(defun bash-completion-ends-with (str suffix)
- "Return t if STR ends with SUFFIX."
- (let ((suffix-len (length suffix))
- (str-len (length str)))
- (or
- (= 0 suffix-len)
- (and
- (>= str-len suffix-len)
- (string= (substring str (- suffix-len)) suffix)))))
+(defun bash-completion-last-char (str)
+ "Returns the last char of STR or nil."
+ (let ((str-len (length str)))
+ (and (>= str-len 1)
+ (aref str (1- str-len)))))
(defun bash-completion-starts-with (str prefix)
"Return t if STR starts with PREFIX."
@@ -1078,9 +1079,8 @@ candidates."
(stub (nth cword words)) )
(cond
((= cword 0)
- ;; a command. let emacs expand executable, let bash
- ;; expand builtins, aliases and functions
- (concat "compgen -S ' ' -b -c -a -A function " stub))
+ ;; a command. let bash expand builtins, aliases and functions
+ (concat "compgen -b -c -a -A function " stub))
((not compgen-args)
;; no completion configured for this command
- [nongnu] elpa/bash-completion cf42ed1057 101/313: add compatibility information for emacs 24.1.1 with OSX 10.7 / 10.8, (continued)
- [nongnu] elpa/bash-completion cf42ed1057 101/313: add compatibility information for emacs 24.1.1 with OSX 10.7 / 10.8, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion f9903d4bd4 079/313: ran checkdoc again, re-ran integration tests, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion bab4cf6e8d 109/313: Merge remote-tracking branch 'origin/master' into complete_D, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion dce43a54c5 119/313: Update comment in bash-completion-test, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 5209200f3b 120/313: Using cl-letf instead of flet., ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 9588a9c0dd 125/313: Updated README, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion c5f2b2756f 129/313: Define sz-testutils as a global variable., ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion f085c41d8d 131/313: Add defcustom for bash-completion-args, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 8ca917f428 133/313: Stop escaping = in completion. fixes #18, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 319886faa9 138/313: Add / after directory names - even if they contain spaces or special, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion f2ea2b65df 141/313: Detect directories when expanding commands and add a slash instead of a,
ELPA Syncer <=
- [nongnu] elpa/bash-completion 44bc73449e 144/313: Fixes strange behavior when completing --., ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion b4757884b0 145/313: Expand the tests to better cover wordbreak and command argument, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 6ab1fe406b 148/313: Always quote the stub before passing it to compgen., ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion a789093cd3 155/313: Run tests on older versions of Emacs., ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 5e05365dc8 153/313: Cleanup tests, split them into unit and integration tests., ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 09c93ffbdb 165/313: Explicitly disable support for Emacs version older than 24.1., ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 62c6567af6 158/313: Complete argument rename, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 5eb85cf1fc 166/313: Remove obsolete functions bash-completion-dynamic-complete-0 and, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 9b94818f88 167/313: Remove support for pre-Emacs24.1 backward compatibility., ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 912e1e8153 170/313: Add an option to disable default Readline completion when no matches are found (#29), ELPA Syncer, 2022/12/03