[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/bash-completion 0aed19067b 188/313: When using Bash 4, sp
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/bash-completion 0aed19067b 188/313: When using Bash 4, split words as Bash 4 does. |
Date: |
Sat, 3 Dec 2022 10:59:29 -0500 (EST) |
branch: elpa/bash-completion
commit 0aed19067b203878891a603e2743a41688f12a6e
Author: Stephane Zermatten <szermatt@gmx.net>
Commit: Stephane Zermatten <szermatt@gmx.net>
When using Bash 4, split words as Bash 4 does.
Bash 3 doesn't apply COMP_WORDBREAKS to the words, just to the stub.
Bash 4 applies it to both.
This commit makes emacs-bash-completion behave in a way that's
compatible with the current bash major version. This fixes wordbreak
completion when on bash 4, when using the _minimal function.
Issue #32
---
bash-completion.el | 80 ++++++++++++++++++----------------
test/bash-completion-test.el | 100 +++++++++++++++++++++++++++++--------------
2 files changed, 112 insertions(+), 68 deletions(-)
diff --git a/bash-completion.el b/bash-completion.el
index bce01221f7..1d9652eb37 100644
--- a/bash-completion.el
+++ b/bash-completion.el
@@ -202,6 +202,9 @@ to remove the extra space bash adds after a completion."
"Shell files that, if they exist, will be sourced at the
beginning of a bash completion subprocess.")
+(defvar bash-completion-wordbreaks ""
+ "Extra wordbreaks to use when tokenizing, in `bash-completion-tokenize'")
+
;;; ---------- Internal variables and constants
(defvar bash-completion-processes nil
@@ -378,7 +381,8 @@ Returns (list stub-start stub-end completions) with
(let* ((process (bash-completion-require-process))
(comp (bash-completion--parse
comp-start comp-pos
- (process-get process 'wordbreaks)))
+ (process-get process 'wordbreaks)
+ (process-get process 'bash-major-version)))
(stub-start (bash-completion--stub-start comp)))
(bash-completion--customize comp process)
(list
@@ -426,7 +430,7 @@ functions adds single quotes around it and return the
result."
(replace-regexp-in-string "'" "'\\''" word nil t)
"'")))
-(defun bash-completion--parse (comp-start comp-pos wordbreaks)
+(defun bash-completion--parse (comp-start comp-pos wordbreaks
bash-major-version)
"Process a command line split into TOKENS that end at POS.
WORDBREAK is the value of COMP_WORDBREAKS to use for this completion,
@@ -437,7 +441,9 @@ This function takes a list of tokens built by
function expect in an association list.
Returns a completion struct."
- (let* ((all-tokens (bash-completion-tokenize comp-start comp-pos))
+ (let* ((all-tokens (bash-completion-tokenize
+ comp-start comp-pos (if (>= bash-major-version 4)
+ wordbreaks "")))
(line-tokens (bash-completion-parse-current-command all-tokens))
(first-token (car line-tokens))
(last-token (car (last line-tokens)))
@@ -451,21 +457,12 @@ Returns a completion struct."
unparsed-stub ""
parsed-stub ""
words (append words '("")))
- (let* ((last-word-start (car (bash-completion-tokenize-get-range
last-token)))
- (last-word (bash-completion-tokenize-get-str last-token))
- (last-word-unparsed (buffer-substring-no-properties
last-word-start comp-pos))
- (last-word-unparsed-split (bash-completion-last-wordbreak-split
- last-word-unparsed wordbreaks))
- (last-word-unparsed-separator (nth 2 last-word-unparsed-split))
- (last-word-unparsed-before (if (zerop
last-word-unparsed-separator)
- ""
- (nth 0 last-word-unparsed-split))))
- (setq stub-start (+ last-word-start (length last-word-unparsed-before))
- unparsed-stub (buffer-substring-no-properties stub-start
comp-pos)
- parsed-stub (substring last-word
- (1+ (or (bash-completion--find-last
- last-word-unparsed-separator
last-word)
- -1))))))
+ (if (< bash-major-version 4)
+ (setq last-token (car (last (bash-completion-tokenize
+ comp-start comp-pos wordbreaks)))))
+ (setq stub-start (car (bash-completion-tokenize-get-range last-token))
+ parsed-stub (bash-completion-tokenize-get-str last-token)
+ unparsed-stub (buffer-substring-no-properties stub-start
comp-pos)))
(bash-completion--make
:line (buffer-substring-no-properties start comp-pos)
:point (- comp-pos start)
@@ -526,12 +523,13 @@ list of strings.
TOKENS should be in the format returned by `bash-completion-tokenize'."
(mapcar 'bash-completion-tokenize-get-str tokens))
-(defun bash-completion-tokenize (start end)
+(defun bash-completion-tokenize (start end &optional wordbreaks)
"Tokenize the portion of the current buffer between START and END.
This function splits a BASH command line into tokens. It knows
about quotes, escape characters and special command separators such
-as ;, | and &&.
+as ;, | and &&. If specified WORDBREAKS contains extra word breaks,
+usually taken from COMP_WORDBREAKS, to apply while tokenizing.
This method returns a list of tokens found between START and END,
ordered by position. Tokens contain a string and a range.
@@ -554,9 +552,16 @@ set using `bash-completion-tokenize-set-end'.
Tokens should always be accessed using the functions specified above,
never directly as they're likely to change as this code evolves.
The current format of a token is '(string . (start . end))."
- (save-excursion
- (goto-char start)
- (nreverse (bash-completion-tokenize-new-element end nil))))
+ (let ((bash-completion-wordbreaks
+ (mapconcat 'char-to-string
+ (delq nil (mapcar
+ (lambda (c)
+ (if (memq c '(?\; ?& ?| ?' ?\")) nil c))
+ (or wordbreaks "")))
+ "")))
+ (save-excursion
+ (goto-char start)
+ (nreverse (bash-completion-tokenize-new-element end nil)))))
(defun bash-completion-tokenize-new-element (end tokens)
"Tokenize the rest of the line until END and complete TOKENS.
@@ -626,8 +631,12 @@ Return TOKENS with new tokens prepended to it."
;; parse the token elements at the current position and
;; append them
(let ((local-start (point)))
- (when (= (skip-chars-forward "[;&|]" end) 0)
- (skip-chars-forward (bash-completion-nonsep quote) end))
+ (when (= (skip-chars-forward
+ (concat "[;&|" bash-completion-wordbreaks "]")
+ end)
+ 0)
+ (skip-chars-forward
+ (bash-completion-nonsep quote bash-completion-wordbreaks) end))
(bash-completion-tokenize-append-str
token
(buffer-substring-no-properties local-start (point))))
@@ -658,20 +667,14 @@ Return TOKENS with new tokens prepended to it."
(push token tokens)
(bash-completion-tokenize-new-element end tokens))))
-(defconst bash-completion-nonsep-alist
- '((nil . "^ \t\n\r;&|'\"#")
- (?' . "^ \t\n\r'")
- (?\" . "^ \t\n\r\""))
- "Alist of sets of non-breaking characters.
-Keeps a regexp specifying the set of non-breaking characters for
-all quoting environment (no quote, single quote and double
-quote). Get it using `bash-completion-nonsep'.")
-
-(defun bash-completion-nonsep (quote)
+(defun bash-completion-nonsep (quote wordbreaks)
"Return the set of non-breaking characters when QUOTE is the current quote.
QUOTE should be nil, ?' or ?\"."
- (cdr (assq quote bash-completion-nonsep-alist)))
+ (concat
+ "^ \t\n\r"
+ (if (null quote) (concat ";&|'\"" wordbreaks)
+ (char-to-string quote))))
;;; ---------- Functions: getting candidates from bash
@@ -965,6 +968,11 @@ is set to t."
(bash-completion-send "complete -p" process)
(process-put process 'complete-p
(bash-completion-build-alist (process-buffer
process)))
+ (bash-completion-send "echo -n ${BASH_VERSINFO[0]}" process)
+ (process-put process 'bash-major-version
+ (with-current-buffer (process-buffer process)
+ (string-to-number (buffer-substring-no-properties
+ (point-min) (point-max)))))
(bash-completion-send "echo -n ${COMP_WORDBREAKS}" process)
(process-put process 'wordbreaks
(with-current-buffer (process-buffer process)
diff --git a/test/bash-completion-test.el b/test/bash-completion-test.el
index 7472d75edc..c3f3b78974 100644
--- a/test/bash-completion-test.el
+++ b/test/bash-completion-test.el
@@ -76,13 +76,6 @@ The return value is the one returned by BODY."
(bash-completion-strings-from-tokens
(bash-completion-tokenize 1 (line-end-position))))))
- ;; escaped #
- (should (equal '("a" "hello" "#world#" "b")
- (bash-completion-test-with-buffer
- "a hello \\#world\\# b"
- (bash-completion-strings-from-tokens
- (bash-completion-tokenize 1 (line-end-position))))))
-
;; double quotes
(should (equal '("a" "hello world" "b" "c")
(bash-completion-test-with-buffer
@@ -147,7 +140,7 @@ The return value is the one returned by BODY."
(bash-completion-tokenize 1 (line-end-position)))))))
(ert-deftest bash-completion--parse-test ()
- (let ((wordbreaks "@><=;|&(:"))
+ (let ((wordbreaks "@><=;|&(:'\""))
;; cursor at end of word
(should (equal
(bash-completion--make
@@ -161,7 +154,7 @@ The return value is the one returned by BODY."
:wordbreaks wordbreaks)
(bash-completion-test-with-buffer
"a hello world"
- (bash-completion--parse (point-min) 14 wordbreaks))))
+ (bash-completion--parse (point-min) 14 wordbreaks 3))))
;; some words separated by spaces, cursor after the last space
(should (equal
@@ -176,7 +169,7 @@ The return value is the one returned by BODY."
:wordbreaks wordbreaks)
(bash-completion-test-with-buffer
"a hello "
- (bash-completion--parse (point-min) 9 wordbreaks))))
+ (bash-completion--parse (point-min) 9 wordbreaks 3))))
;; complex multi-command line
(should (equal
@@ -191,7 +184,7 @@ The return value is the one returned by BODY."
:wordbreaks wordbreaks)
(bash-completion-test-with-buffer
"cd /var/tmp ; ZORG=t make -"
- (bash-completion--parse (point-min) 28 wordbreaks))))
+ (bash-completion--parse (point-min) 28 wordbreaks 3))))
;; pipe
(should (equal
@@ -206,7 +199,7 @@ The return value is the one returned by BODY."
:wordbreaks wordbreaks)
(bash-completion-test-with-buffer
"ls /var/tmp | sort -"
- (bash-completion--parse (point-min) 21 wordbreaks))))
+ (bash-completion--parse (point-min) 21 wordbreaks 3))))
;; escaped semicolon
(should (equal
@@ -221,7 +214,7 @@ The return value is the one returned by BODY."
:wordbreaks wordbreaks)
(bash-completion-test-with-buffer
"find -name '*.txt' -exec echo {} ';' -"
- (bash-completion--parse (point-min) 39 wordbreaks))))
+ (bash-completion--parse (point-min) 39 wordbreaks 3))))
;; at var assignment
(should (equal
@@ -236,9 +229,9 @@ The return value is the one returned by BODY."
:wordbreaks wordbreaks)
(bash-completion-test-with-buffer
"cd /var/tmp ; A=f ZORG=t"
- (bash-completion--parse (point-min) 25 wordbreaks))))
+ (bash-completion--parse (point-min) 25 wordbreaks 3))))
- ;; stub is a subset of last word
+ ;; stub is a subset of last word (bash 3)
(should (equal
(bash-completion--make
:line "export PATH=/bin:/usr/bi"
@@ -251,7 +244,22 @@ The return value is the one returned by BODY."
:wordbreaks wordbreaks)
(bash-completion-test-with-buffer
"export PATH=/bin:/usr/bi"
- (bash-completion--parse (point-min) (point-max) wordbreaks))))
+ (bash-completion--parse (point-min) (point-max) wordbreaks 3))))
+
+ ;; last word is split according to COMP_WORDBREAKS (bash 4)
+ (should (equal
+ (bash-completion--make
+ :line "export PATH=/bin:/usr/bi"
+ :point 24
+ :cword 5
+ :words '("export" "PATH" "=" "/bin" ":" "/usr/bi")
+ :stub-start 18
+ :stub "/usr/bi"
+ :unparsed-stub "/usr/bi"
+ :wordbreaks wordbreaks)
+ (bash-completion-test-with-buffer
+ "export PATH=/bin:/usr/bi"
+ (bash-completion--parse (point-min) (point-max) wordbreaks 4))))
;; with escaped quote
(should (equal
@@ -266,7 +274,22 @@ The return value is the one returned by BODY."
:wordbreaks wordbreaks)
(bash-completion-test-with-buffer
"cd /vcr/shows/Dexter\\'s"
- (bash-completion--parse (point-min) 24 wordbreaks))))
+ (bash-completion--parse (point-min) 24 wordbreaks 3))))
+
+ ;; with escaped quote, bash 4
+ (should (equal
+ (bash-completion--make
+ :line "cd /vcr/shows/Dexter\\'s"
+ :point 23
+ :cword 1
+ :words '("cd" "/vcr/shows/Dexter's")
+ :stub-start 4
+ :stub "/vcr/shows/Dexter's"
+ :unparsed-stub "/vcr/shows/Dexter\\'s"
+ :wordbreaks wordbreaks)
+ (bash-completion-test-with-buffer
+ "cd /vcr/shows/Dexter\\'s"
+ (bash-completion--parse (point-min) 24 wordbreaks 4))))
;; with double quote
(should (equal
@@ -282,7 +305,7 @@ The return value is the one returned by BODY."
:wordbreaks wordbreaks)
(bash-completion-test-with-buffer
"cd \"/vcr/shows/Dexter's"
- (bash-completion--parse (point-min) 24 wordbreaks))))
+ (bash-completion--parse (point-min) 24 wordbreaks 3))))
;; with single quote
(should (equal
@@ -298,7 +321,7 @@ The return value is the one returned by BODY."
:wordbreaks wordbreaks)
(bash-completion-test-with-buffer
"cd '/vcr/shows/Dexter'\\''s"
- (bash-completion--parse (point-min) 27 wordbreaks))))
+ (bash-completion--parse (point-min) 27 wordbreaks 3))))
;; just one space, cursor after it
(should (equal
@@ -313,7 +336,7 @@ The return value is the one returned by BODY."
:wordbreaks wordbreaks)
(bash-completion-test-with-buffer
" "
- (bash-completion--parse (point-min) 2 wordbreaks))))))
+ (bash-completion--parse (point-min) 2 wordbreaks 3))))))
(ert-deftest bash-completion-build-alist ()
(should (equal
@@ -429,11 +452,17 @@ garbage
(ert-deftest bash-completion-customize-test ()
(cl-letf (((symbol-function 'process-get)
(lambda (process prop)
- (if (and (eq 'process process)
- (eq 'complete-p prop))
- '((nil "-F" "__default")
- ("zorg" "-F" "__zorg"))
- (error "unexpected call")))))
+ (cond
+ ((and (eq 'process process)
+ (eq 'complete-p prop))
+ '((nil "-F" "__default")
+ ("zorg" "-F" "__zorg")))
+ ((and (eq 'process process)
+ (eq 'bash-major-version prop)) 3)
+ ((and (eq 'process process)
+ (eq 'wordbreaks prop)) "\"'@><=;|&(:")
+ (t (error "unexpected: (process-get %s %s)"
+ process prop))))))
(let ((comp (bash-completion--make :cword 1)))
(setf (bash-completion--words comp) '("zorg" "world"))
(bash-completion--customize comp 'process)
@@ -765,12 +794,14 @@ Return (const return-value new-buffer-content)"
(current-buffer)))))))
(ert-deftest bash-completion-nonsep-test ()
- (should (equal "^ \t\n\r;&|'\"#"
- (bash-completion-nonsep nil)))
+ (should (equal "^ \t\n\r;&|'\""
+ (bash-completion-nonsep nil "")))
+ (should (equal "^ \t\n\r;&|'\":="
+ (bash-completion-nonsep nil ":=")))
(should (equal "^ \t\n\r'"
- (bash-completion-nonsep ?')))
+ (bash-completion-nonsep ?' "")))
(should (equal "^ \t\n\r\""
- (bash-completion-nonsep ?\"))))
+ (bash-completion-nonsep ?\" ""))))
(ert-deftest bash-completion-escape-candidate-test ()
;; empty string - no quote
@@ -863,6 +894,7 @@ before calling `bash-completion-dynamic-complete-nocomint'.
`(let ((default-directory "/tmp/test")
(bash-completion-alist '())
(wordbreaks "@><=;|&(:")
+ (bash-major-version 3)
(bash-completion-nospace nil))
(lexical-let ((--process-buffer)
(--test-buffer)
@@ -876,9 +908,11 @@ before calling `bash-completion-dynamic-complete-nocomint'.
(cl-letf (((symbol-function 'bash-completion-require-process)
(lambda () 'process))
((symbol-function 'process-put)
(lambda (process prop value)
- (if (and (eq 'process process) (eq 'complete-p prop))
- (setq bash-completion-alist value)
- (error "unexpected call"))))
+ (cond ((and (eq 'process process) (eq 'complete-p
prop))
+ (setq bash-completion-alist value))
+ ((and (eq 'process process) (eq
'bash-major-version prop))
+ (setq bash-major-version value))
+ (t (error "unexpected: (process-put %s %s)"
process prop)))))
((symbol-function 'process-get)
(lambda (process prop)
(cond
@@ -886,6 +920,8 @@ before calling `bash-completion-dynamic-complete-nocomint'.
bash-completion-alist)
((and (eq 'process process) (eq 'wordbreaks prop))
wordbreaks)
+ ((and (eq 'process process) (eq 'bash-major-version
prop))
+ bash-major-version)
(t (error "unexpected call")))))
((symbol-function 'bash-completion-buffer) (lambda ()
--process-buffer))
((symbol-function 'process-buffer) (lambda (p)
--process-buffer))
- [nongnu] elpa/bash-completion 7965b914da 160/313: Re-enable directory expansion for custom completion. fixes #23, (continued)
- [nongnu] elpa/bash-completion 7965b914da 160/313: Re-enable directory expansion for custom completion. fixes #23, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 2c0b8d6a6e 163/313: Merge pull request #27 from vorburger/patch-1, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 0c77c64b50 174/313: Disable bash-completion-enable-caching if completion-table-with-cache, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion b281e1e181 008/313: bash-complete-add-to-alist, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 1144ae69a9 056/313: documented the tokenizer, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 376dd532e2 057/313: modre documentation, up until wordbreak, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion fd7e0e6fbe 078/313: added documentation, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion dd34b278bf 069/313: stopping at point; the easy way, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 8756e80737 184/313: Replace 'options' in the completion struct with 'nospace'., ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 2c4cb6edd2 186/313: Replace bash-completion-integration-test with a higher-level test for, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 0aed19067b 188/313: When using Bash 4, split words as Bash 4 does.,
ELPA Syncer <=
- [nongnu] elpa/bash-completion 4581a7823f 189/313: Bash 4: set COMP_TYPE and COMP_KEY to TAB, to let completion functions, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 802eb4e5a8 194/313: Set EMACS_BASH_COMPLETE even on remote (tramp) completion., ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion fbdc78b877 198/313: Support compopt when using Bash 4., ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion f1bd3d528f 201/313: Improve some docstrings, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion fa49dbb382 209/313: Improve status code retrieval, ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 7822d84812 223/313: Added Cask with ert-runner to compile and run test., ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 31a01859b2 227/313: Do not run tests under Emacs 24.1., ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 21471cc542 228/313: Report result of running the test workflow on README.md., ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 98a2a21be7 234/313: Provide a way of refreshing the completion table., ELPA Syncer, 2022/12/03
- [nongnu] elpa/bash-completion 4fcddf83c9 242/313: Make /etc/bash_completion scripts work with escaped spaces., ELPA Syncer, 2022/12/03