emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/bash-completion 6b1be0da4c 048/313: from split to tokenize


From: ELPA Syncer
Subject: [nongnu] elpa/bash-completion 6b1be0da4c 048/313: from split to tokenize and parse
Date: Sat, 3 Dec 2022 10:59:15 -0500 (EST)

branch: elpa/bash-completion
commit 6b1be0da4ce2d8cbaf4acdd69ddb8b449ac17dee
Author: Stephane Zermatten <szermatt@gmx.net>
Commit: Stephane Zermatten <szermatt@gmx.net>

    from split to tokenize and parse
---
 bash-completion.el      | 171 ++++++++++++++++++++++++++++++------------------
 bash-completion_test.el | 130 ++++++++++++++++++++----------------
 2 files changed, 180 insertions(+), 121 deletions(-)

diff --git a/bash-completion.el b/bash-completion.el
index 61f37f2301..7466c859bd 100644
--- a/bash-completion.el
+++ b/bash-completion.el
@@ -48,19 +48,14 @@ Call bash to do the completion."
   (let* ( (pos (point))
          (start (bash-completion-line-beginning-position))
          (end (line-end-position))
-         (line (buffer-substring-no-properties start end))
-         (wordsplit)
-         (cword)
-         (words)
-         (stub)
+         (parsed (bash-completion-parse-line start end pos))
+         (line (cdr (assq 'line parsed)))
+         (cword (cdr (assq 'cword parsed)))
+         (words (cdr (assq 'words parsed)))
+         (stub (nth cword words))
          ;; Override configuration for comint-dynamic-simple-complete.
          ;; Bash adds a space suffix automatically.
          (comint-completion-addsuffix nil) )
-    (save-excursion
-      (setq wordsplit (bash-completion-split start end pos))
-      (setq cword (car wordsplit))
-      (setq words (cdr wordsplit))
-      (setq stub (nth cword words)))
     (let ((completions (bash-completion-comm line (- pos start) words cword)))
       (if completions
          (comint-dynamic-simple-complete stub completions)
@@ -99,103 +94,146 @@ Call bash to do the completion."
       word
     (replace-regexp-in-string "\\([ '\"]\\)" "\\\\\\1" word)))
 
-(defun bash-completion-split (start end pos)
-  "Split LINE like bash would do, keep track of current word at POS.
-
-Return a list containing the words and the number of the word
-at POS, the current word: ( (word1 word2 ...) . wordnum )"
-  (bash-completion-split-postprocess
-   (bash-completion-split-raw start end) start pos))
-
-(defun bash-completion-split-strings (accum)
-  (mapcar 'bash-completion-split-raw-get-str accum))
-
-(defun bash-completion-split-postprocess (accum start pos)
-  (if (null pos)
-      (cons nil (bash-completion-split-strings accum))
-    ;; find position
-    (let ((index 0) (strings nil) (current nil) (accum-rest accum) (cword nil))
-      (while accum-rest
-       (setq current (car accum-rest))
-       (setq accum-rest (cdr accum-rest))
-       (unless cword
-         (let ((range (bash-completion-split-raw-get-range current)))
-           (cond
-            ((and (>= pos (car range))
-                  (<= pos (cdr range)))
-             (setq cword index))
-            ((< pos (car range))
-             (setq cword index)
-             (push "" strings)))))
-       (push (bash-completion-split-raw-get-str current) strings)
-       (setq index (1+ index)))
-      (unless cword
-       (setq cword index)
-       (push "" strings))
-      (cons cword (nreverse strings)))))
+(defun bash-completion-parse-line (start end pos)
+  (bash-completion-parse-line-postprocess
+   (bash-completion-parse-current-command
+    (bash-completion-tokenize start end) pos) pos))
 
-(defsubst bash-completion-split-raw-get-range (current)
+(defun bash-completion-strings-from-tokens (accum)
+  (mapcar 'bash-completion-tokenize-get-str accum))
+
+(defun bash-completion-parse-line-postprocess (accum pos)
+  (let ((index 0) (strings nil) (current nil) (accum-rest accum) (cword nil)
+       (start (car (bash-completion-tokenize-get-range (car accum)))))
+    (while accum-rest
+      (setq current (car accum-rest))
+      (setq accum-rest (cdr accum-rest))
+      (unless cword
+       (let ((range (bash-completion-tokenize-get-range current)))
+         (cond
+          ((and (>= pos (car range))
+                (<= pos (cdr range)))
+           (setq cword index))
+          ((< pos (car range))
+           (setq cword index)
+           (push "" strings)))))
+      (push (bash-completion-tokenize-get-str current) strings)
+      (setq index (1+ index)))
+    (unless cword
+      (setq cword index)
+      (push "" strings))
+    (list
+     (cons 'line (buffer-substring-no-properties start (cdr 
(bash-completion-tokenize-get-range current))))
+     (cons 'cword cword)
+     (cons 'words (nreverse strings)))))
+
+(defun bash-completion-parse-current-command (accum pos)
+  (nreverse (catch 'bash-completion-return
+    (let ((command nil) (state 'initial))
+      (dolist (current accum)
+       (let* ((position (bash-completion-tokenize-range-check current pos))
+              (string (bash-completion-tokenize-get-str current))
+              (is-terminal (member string '(";" "&" "|" "&&" "||"))))
+         (cond
+          ((and is-terminal
+                (eq position 'after))
+           (setq state 'initial)
+           (setq command nil))
+
+          (is-terminal
+           (throw 'bash-completion-return command))
+
+          ((and (eq state 'initial)
+                (null (string-match "=" string)))
+           (setq state 'args)
+           (push current command))
+
+          ((and (eq state 'initial)
+                (eq position 'after)))
+
+          ((eq state 'initial)
+           (push current command)
+           (throw 'bash-completion-return command))
+
+          ((eq state 'args)
+           (push current command)))))
+      command))))
+
+(defun bash-completion-tokenize-range-check (current pos)
+  (let ((range (bash-completion-tokenize-get-range current)))
+    (cond
+     ((< pos (car range))
+      'before)
+
+     ((and (>= pos (car range))
+          (<= pos (cdr range)))
+      'contains)
+
+     ((> pos (cdr range))
+      'after))))
+
+(defsubst bash-completion-tokenize-get-range (current)
   (cdr current))
 
-(defsubst bash-completion-split-raw-set-end (current)
+(defsubst bash-completion-tokenize-set-end (current)
   (setcdr (cdr current) (point)))
 
-(defsubst bash-completion-split-raw-append-str (current str)
+(defsubst bash-completion-tokenize-append-str (current str)
   (setcar current (concat (car current) str)))
 
-(defsubst bash-completion-split-raw-get-str (current)
+(defsubst bash-completion-tokenize-get-str (current)
   (car current))
 
-(defun bash-completion-split-raw (start end)
+(defun bash-completion-tokenize (start end)
   (save-excursion
     (goto-char start)
-    (nreverse (bash-completion-split-raw-new-element end nil))))
+    (nreverse (bash-completion-tokenize-new-element end nil))))
 
-(defun bash-completion-split-raw-new-element (end accum)
+(defun bash-completion-tokenize-new-element (end accum)
   (skip-chars-forward " \t\n\r" end)
   (if (< (point) end)
-      (bash-completion-split-raw-0 end accum (list "" (point)))
+      (bash-completion-tokenize-0 end accum (list "" (point)))
     accum))
 
-(defun bash-completion-split-raw-0 (end accum current)
+(defun bash-completion-tokenize-0 (end accum current)
   (let ( (char-start (char-after))
         (quote nil) )
     (when (and char-start (or (= char-start ?') (= char-start ?\")))
       (forward-char)
       (setq quote char-start))
-    (bash-completion-split-raw-1 end quote accum current)))
+    (bash-completion-tokenize-1 end quote accum current)))
 
-(defun bash-completion-split-raw-1 (end quote accum current)
+(defun bash-completion-tokenize-1 (end quote accum current)
   (let ((local-start (point)))
     (when (= (skip-chars-forward "[;&|]" end) 0)
       (skip-chars-forward (bash-completion-nonsep quote) end))
-    (bash-completion-split-raw-append-str
+    (bash-completion-tokenize-append-str
      current
      (buffer-substring-no-properties local-start (point))))
   (cond
    ;; an escaped char, skip, whatever it is
    ((and (char-before) (= ?\\ (char-before)))
     (forward-char)
-    (let ((straccum (bash-completion-split-raw-get-str current)))
+    (let ((straccum (bash-completion-tokenize-get-str current)))
       (aset straccum (1- (length straccum)) (char-before)))
-    (bash-completion-split-raw-1 end quote accum current))
+    (bash-completion-tokenize-1 end quote accum current))
    ;; opening quote
    ((and (not quote) (char-after) (or (= ?' (char-after)) (= ?\" 
(char-after))))
-    (bash-completion-split-raw-0 end accum current))
+    (bash-completion-tokenize-0 end accum current))
    ;; closing quote
    ((and quote (char-after) (= quote (char-after)))
     (forward-char)
-    (bash-completion-split-raw-0 end accum current))
+    (bash-completion-tokenize-0 end accum current))
    ;; space inside a quote
    ((and quote (char-after) (not (= quote (char-after))))
     (forward-char)
-    (bash-completion-split-raw-append-str current (char-to-string 
(char-before)))
-    (bash-completion-split-raw-1 end quote accum current))
+    (bash-completion-tokenize-append-str current (char-to-string 
(char-before)))
+    (bash-completion-tokenize-1 end quote accum current))
    ;; word end
    (t
-    (bash-completion-split-raw-set-end current)
+    (bash-completion-tokenize-set-end current)
     (push current accum)
-    (bash-completion-split-raw-new-element end accum))))
+    (bash-completion-tokenize-new-element end accum))))
 
 (defconst bash-completion-nonsep-alist
   '((nil . "^ \t\n\r;&|'\"")
@@ -411,7 +449,10 @@ Return `bash-completion-alist'."
       (goto-char (point-max))
       (while (= 0 (forward-line -1))
        (bash-completion-add-to-alist
-        (cdr (bash-completion-split (line-beginning-position) 
(line-end-position) nil))))))
+        (bash-completion-strings-from-tokens
+         (bash-completion-tokenize
+          (line-beginning-position)
+          (line-end-position)))))))
   bash-completion-alist)
 
 (defun bash-completion-add-to-alist (words)
diff --git a/bash-completion_test.el b/bash-completion_test.el
index bfa6dea1ab..edc28eff1c 100644
--- a/bash-completion_test.el
+++ b/bash-completion_test.el
@@ -48,94 +48,106 @@ cases. That's why they need to be enabled manually.")
       (bash-completion-join '("a" "hello world" "b" "c"))
       "a 'hello world' b c")
 
-     ("bash-completion-split simple"
+     ("bash-completion-tokenize simple"
       (sz-testutils-with-buffer
        '("a hello world b c")
-       (bash-completion-split 1 (line-end-position) nil))
-      '(nil . ("a" "hello" "world" "b" "c")))
+       (bash-completion-strings-from-tokens
+       (bash-completion-tokenize 1 (line-end-position))))
+      '("a" "hello" "world" "b" "c"))
 
-     ("bash-completion-split simple extra spaces"
+     ("bash-completion-tokenize simple extra spaces"
       (sz-testutils-with-buffer
        '("  a  hello \n world \t b \r c  ")
-       (bash-completion-split 1 (line-end-position 2) nil))
-      '(nil . ("a" "hello" "world" "b" "c")))
+       (bash-completion-strings-from-tokens
+       (bash-completion-tokenize 1 (line-end-position 2))))
+      '("a" "hello" "world" "b" "c"))
 
-     ("bash-completion-split escaped space"
+     ("bash-completion-tokenize escaped space"
       (sz-testutils-with-buffer
        '("a hello\\ world b c")
-       (bash-completion-split 1 (line-end-position) nil))
-      '(nil . ("a" "hello world" "b" "c")))
+       (bash-completion-strings-from-tokens
+       (bash-completion-tokenize 1 (line-end-position))))
+      '("a" "hello world" "b" "c"))
 
-     ("bash-completion-split double quotes"
+     ("bash-completion-tokenize double quotes"
       (sz-testutils-with-buffer
        '("a \"hello world\" b c")
-       (bash-completion-split 1 (line-end-position) nil))
-      '(nil . ("a" "hello world" "b" "c")))
+       (bash-completion-strings-from-tokens
+       (bash-completion-tokenize 1 (line-end-position))))
+      '("a" "hello world" "b" "c"))
 
-     ("bash-completion-split double quotes escaped"
+     ("bash-completion-tokenize double quotes escaped"
       (sz-testutils-with-buffer
        '("a \"-\\\"hello world\\\"-\" b c")
-       (bash-completion-split 1 (line-end-position) nil))
-      '(nil . ("a" "-\"hello world\"-" "b" "c")))
+       (bash-completion-strings-from-tokens
+       (bash-completion-tokenize 1 (line-end-position))))
+      '("a" "-\"hello world\"-" "b" "c"))
 
-     ("bash-completion-split single quotes"
+     ("bash-completion-tokenize single quotes"
       (sz-testutils-with-buffer
        '("a \"hello world\" b c")
-       (bash-completion-split 1 (line-end-position) nil))
-      '(nil . ("a" "hello world" "b" "c")))
+       (bash-completion-strings-from-tokens
+       (bash-completion-tokenize 1 (line-end-position))))
+      '("a" "hello world" "b" "c"))
 
-     ("bash-completion-split single quotes escaped"
+     ("bash-completion-tokenize single quotes escaped"
       (sz-testutils-with-buffer
        '("a '-\\'hello world\\'-' b c")
-       (bash-completion-split 1 (line-end-position) nil))
-      '(nil . ("a" "-'hello world'-" "b" "c")))
+       (bash-completion-strings-from-tokens
+       (bash-completion-tokenize 1 (line-end-position))))
+      '("a" "-'hello world'-" "b" "c"))
 
-     ("bash-completion-split complex quote mix"
+     ("bash-completion-tokenize complex quote mix"
       (sz-testutils-with-buffer
        '("a hel\"lo w\"o'rld b'c d")
-       (bash-completion-split 1 (line-end-position) nil))
-      '(nil . ("a" "hello world bc" "d")))
+       (bash-completion-strings-from-tokens
+       (bash-completion-tokenize 1 (line-end-position))))
+      '("a" "hello world bc" "d"))
 
-     ("bash-completion-split cursor at end of word"
-      (sz-testutils-with-buffer
-       '("a hello world" cursor " b c")
-       (bash-completion-split 1 (line-end-position) (point)))
-      '(2 . ("a" "hello" "world" "b" "c")))
-
-     ("bash-completion-split cursor in the middle of a word"
-      (sz-testutils-with-buffer
-       '("a hello wo" cursor "rld b c")
-       (bash-completion-split 1 (line-end-position) (point)))
-      '(2 . ("a" "hello" "world" "b" "c")))
-
-     ("bash-completion-split-raw unescaped semicolon"
+     ("bash-completion-tokenize unescaped semicolon"
       (sz-testutils-with-buffer
        "to infinity;and\\ beyond"
-       (bash-completion-split-strings
-       (bash-completion-split-raw 1 (line-end-position))))
+       (bash-completion-strings-from-tokens
+       (bash-completion-tokenize 1 (line-end-position))))
       '("to" "infinity" ";" "and beyond"))
 
-     ("bash-completion-split-raw unescaped &&"
+     ("bash-completion-tokenize unescaped &&"
       (sz-testutils-with-buffer
        "to infinity&&and\\ beyond"
-       (bash-completion-split-strings
-       (bash-completion-split-raw 1 (line-end-position))))
+       (bash-completion-strings-from-tokens
+       (bash-completion-tokenize 1 (line-end-position))))
       '("to" "infinity" "&&" "and beyond"))
 
-     ("bash-completion-split-raw unescaped ||"
+     ("bash-completion-tokenize unescaped ||"
       (sz-testutils-with-buffer
        "to infinity||and\\ beyond"
-       (bash-completion-split-strings
-       (bash-completion-split-raw 1 (line-end-position))))
+       (bash-completion-strings-from-tokens
+       (bash-completion-tokenize 1 (line-end-position))))
       '("to" "infinity" "||" "and beyond"))
 
-     ("bash-completion-split-raw quoted ;&|"
+     ("bash-completion-tokenize quoted ;&|"
       (sz-testutils-with-buffer
        "to \"infinity;&|and\" beyond"
-       (bash-completion-split-strings
-       (bash-completion-split-raw 1 (line-end-position))))
+       (bash-completion-strings-from-tokens
+       (bash-completion-tokenize 1 (line-end-position))))
       '("to" "infinity;&|and" "beyond"))
 
+     ("bash-completion-parse-line cursor at end of word"
+      (sz-testutils-with-buffer
+       '("a hello world" cursor " b c")
+       (bash-completion-parse-line 1 (line-end-position) (point)))
+      '((line . "a hello world b c")
+       (cword . 2)
+       (words . ("a" "hello" "world" "b" "c"))))
+
+     ("bash-completion-parse-line cursor in the middle of a word"
+      (sz-testutils-with-buffer
+       '("a hello wo" cursor "rld b c")
+       (bash-completion-parse-line 1 (line-end-position) (point)))
+      '((line . "a hello world b c")
+       (cword . 2)
+       (words . ("a" "hello" "world" "b" "c"))))
+
 ;;      ("bash-completion-split cursor at the beginning"
 ;;       (sz-testutils-with-buffer
 ;;        '(" " cursor " a hello world b c")
@@ -148,23 +160,29 @@ cases. That's why they need to be enabled manually.")
 ;;        (bash-completion-split 1 (line-end-position) (point)))
 ;;       '(2 . ("a" "hello" "" "world" "b" "c")))
 
-     ("bash-completion-split cursor at end"
+     ("bash-completion-parse-line cursor at end"
       (sz-testutils-with-buffer
        '("a hello world b c" cursor)
-       (bash-completion-split 1 (line-end-position) (point)))
-      '(4 . ("a" "hello" "world" "b" "c")))
+       (bash-completion-parse-line 1 (line-end-position) (point)))
+      '((line . "a hello world b c")
+       (cword . 4)
+       (words . ("a" "hello" "world" "b" "c"))))
 
      ("bash-completion-split cursor after end"
       (sz-testutils-with-buffer
        '("a hello world b c " cursor)
-       (bash-completion-split 1 (line-end-position) (point)))
-      '(5 . ("a" "hello" "world" "b" "c" "")))
+       (bash-completion-parse-line 1 (line-end-position) (point)))
+      '((line . "a hello world b c")
+       (cword . 5)
+       (words . ("a" "hello" "world" "b" "c" ""))))
 
      ("bash-completion-split with escaped quote"
       (sz-testutils-with-buffer
-       '("cd /vcr/shows/Dexter\\'" cursor)
-       (bash-completion-split 1 (line-end-position) (point)))
-      '(1 . ("cd" "/vcr/shows/Dexter'")))
+       '("cd /vcr/shows/Dexter\\'s" cursor)
+       (bash-completion-parse-line 1 (line-end-position) (point)))
+      '((line . "cd /vcr/shows/Dexter\\'s")
+       (cword . 1)
+       (words . ("cd" "/vcr/shows/Dexter's"))))
 
      ("bash-completion-add-to-alist garbage"
       (let ((bash-completion-alist nil))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]