Skip to content

Commit 7a1f127

Browse files
committed
Test and fix the dynamic table function that's returned.
This change attempts to make the dynamic table function behave in a way that more closely matches: https://www.gnu.org/software/emacs/manual/html_node/elisp/Programmed-Completion.html It doesn't follow the spec in all ways, as it assumes that all-complete and try-complete understand how the completion function works, whereas completion is arbitrary with bash. To work around that problem, the dynamic table deviates from spec when passed as a string the original, unmodified word that was completed and returns returns all completion, without filtering them. Otherwise, it follows spec. Before this change, the completion function never really followed spec, which was ok for the default completion functions, but confused custom completion functions. This is a follow-up to issue #43 and should allow helm completion to behave more sanely when backed by bash-completion.
1 parent 72e9fce commit 7a1f127

File tree

2 files changed

+158
-19
lines changed

2 files changed

+158
-19
lines changed

bash-completion.el

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,10 +1563,9 @@ using the current Emacs completion style."
15631563
(dir default-directory)
15641564
(use-separate-process bash-completion-use-separate-processes)
15651565
(nospace bash-completion-nospace))
1566-
(lambda (_str predicate action)
1567-
(if (or (eq (car-safe action) 'boundaries)
1568-
(eq action 'metadata))
1569-
nil
1566+
(lambda (str predicate action)
1567+
(when (or (null action) (eq action t) (eq action 'lambda))
1568+
nil
15701569
(when last-error (signal (car last-error) (cdr last-error)))
15711570
(let ((result
15721571
(or last-result
@@ -1580,17 +1579,21 @@ using the current Emacs completion style."
15801579
(setq last-error err)
15811580
(signal (car err) (cdr err)))))))))
15821581
(setq last-result result)
1583-
(let ((filtered-result (if predicate
1584-
(delq nil (mapcar
1585-
(lambda (elt)
1586-
(when (funcall predicate elt) elt))
1587-
result))
1588-
result))
1589-
(completion-ignore-case (process-get process 'completion-ignore-case)))
1582+
(let ((completion-ignore-case (process-get process 'completion-ignore-case))
1583+
(completion-string (if (equal str
1584+
(bash-completion--unparsed-stub comp)) "" str)))
15901585
(cond
1591-
((null action) (try-completion "" filtered-result))
1592-
((eq action t) filtered-result)
1593-
(t (test-completion "" filtered-result)))))))))
1586+
((null action) (try-completion completion-string result predicate))
1587+
((and (eq action t) (equal "" completion-string) predicate)
1588+
(delq nil (mapcar
1589+
(lambda (elt)
1590+
(when (funcall predicate elt) elt))
1591+
result)))
1592+
((and (eq action t) (equal "" completion-string))
1593+
result)
1594+
((eq action t)
1595+
(all-completions completion-string result predicate))
1596+
(t (test-completion str result predicate)))))))))
15941597

15951598
(provide 'bash-completion)
15961599

test/bash-completion-integration-test.el

Lines changed: 141 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -141,17 +141,15 @@
141141
(1+ (search-forward bash-completion_test-start-mark end))))
142142
(or end (point-max))))
143143

144-
(defun bash-completion_test-candidates (complete-me)
144+
(defun bash-completion_test-candidates (complete-me &optional dynamic-table)
145145
"Complete COMPLETE-ME and returns the candidates.
146146
147147
The result is sorted to avoid hardcoding arbitrary order in the test."
148148
(goto-char (point-max))
149149
(delete-region (line-beginning-position) (line-end-position))
150150
(insert complete-me)
151-
(sort
152-
(nth 2 (bash-completion-dynamic-complete-nocomint
153-
(line-beginning-position) (point) nil))
154-
'string<))
151+
(nth 2 (bash-completion-dynamic-complete-nocomint
152+
(line-beginning-position) (point) dynamic-table)))
155153

156154
(defun bash-completion_test-setup-env (bashrc)
157155
"Sets up a directory that contains a bashrc file other files
@@ -585,4 +583,142 @@ $ ")))))
585583
(regexp-quote "$ dummy libra\ncount: 1.")
586584
(bash-completion_test-buffer-string)))))
587585

586+
(ert-deftest bash-completion_test-dynamic-table ()
587+
(bash-completion_test-with-shell-harness
588+
""
589+
nil ; use-separate-process
590+
(let ((default-directory test-env-dir))
591+
(make-directory "some/file" 'parents)
592+
(make-directory "some/filled" 'parents))
593+
(let ((compfunc-some (bash-completion_test-candidates "ls some/f" 'dynamic-table))
594+
(compfunc-one (bash-completion_test-candidates "ls some/fill" 'dynamic-table)))
595+
596+
;; Behavior of the completion function should match the one
597+
;; described in:
598+
;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Programmed-Completion.html
599+
600+
;; all-completion
601+
(should (equal '("some/file/" "some/filled/") (funcall compfunc-some "some/" nil t)))
602+
(should (equal '("some/filled/") (funcall compfunc-some "some/fill" nil t)))
603+
(should (equal nil (funcall compfunc-some "other" nil t)))
604+
(should (equal '("some/filled/") (funcall compfunc-one "some/fill" nil t)))
605+
606+
;; all-completion with predicate
607+
(should (equal '("some/file/")
608+
(funcall compfunc-some "some/"
609+
(lambda (c) (string= c "some/file/")) t)))
610+
(should (equal nil
611+
(funcall compfunc-some "some/" (lambda (c) nil) t)))
612+
(should (equal '("some/file/" "some/filled/")
613+
(funcall compfunc-some "some/" (lambda (c) t) t)))
614+
615+
;; try-completion
616+
(should (equal "some/filled/" (funcall compfunc-one "some/fill" nil nil)))
617+
(should (equal "some/fil" (funcall compfunc-some "some/" nil nil)))
618+
(should (equal t (funcall compfunc-some "some/file/" nil nil)))
619+
(should (equal t (funcall compfunc-one "some/filled/" nil nil)))
620+
621+
;; try-completion with predicate
622+
(should (equal "some/file/"
623+
(funcall compfunc-some "some/"
624+
(lambda (c) (string= c "some/file/")) nil)))
625+
626+
;; test-completion
627+
(should (equal nil (funcall compfunc-some "some/" nil 'lambda)))
628+
(should (equal t (funcall compfunc-some "some/file/" nil 'lambda)))
629+
(should (equal t (funcall compfunc-some "some/filled/" nil 'lambda)))
630+
(should (equal nil (funcall compfunc-one "some/fill" nil 'lambda)))
631+
(should (equal t (funcall compfunc-one "some/filled/" nil 'lambda)))
632+
633+
;; test-completion with predicate
634+
(should (equal nil (funcall compfunc-some "some/" nil 'lambda)))
635+
(should (equal nil (funcall compfunc-some "some/file/"
636+
(lambda (c) (string= c "some/filled/")) 'lambda)))
637+
(should (equal t (funcall compfunc-some "some/filled/"
638+
(lambda (c) (string= c "some/filled/")) 'lambda)))
639+
640+
;; completion-boundaries (not supported)
641+
(should (equal nil (funcall compfunc-some "some/" nil '(boundaries . "/"))))
642+
(should (equal nil (funcall compfunc-one "some/fill" nil '(boundaries . "/"))))
643+
644+
;; metadata (not supported)
645+
(should (equal nil (funcall compfunc-some "some/" nil 'metadata)))
646+
(should (equal nil (funcall compfunc-one "some/fill" nil 'metadata)))
647+
648+
;; some unknown value
649+
(should (equal nil (funcall compfunc-some "some/" nil 'unknown)))
650+
(should (equal nil (funcall compfunc-one "some/fill" nil 'unknown))))))
651+
652+
(ert-deftest bash-completion_test-dynamic-table-no-results ()
653+
(bash-completion_test-with-shell-harness
654+
""
655+
nil ; use-separate-process
656+
(let ((compfunc-none (bash-completion_test-candidates "ls none/" 'dynamic-table)))
657+
658+
;; all-completion
659+
(should (equal nil (funcall compfunc-none "none/" nil t)))
660+
661+
;; try-completion
662+
(should (equal nil (funcall compfunc-none "none/" nil nil)))
663+
664+
;; test-completion
665+
(should (equal nil (funcall compfunc-none "none/" nil 'lambda))))))
666+
667+
(ert-deftest bash-completion_test-dynamic-table-nonprefix ()
668+
(bash-completion_test-with-shell-harness
669+
(concat "function _myprog {\n"
670+
" COMPREPLY=( \"ba${COMP_WORDS[$COMP_CWORD]}tai\" \n"
671+
" \"ba${COMP_WORDS[$COMP_CWORD]}dai\" )\n"
672+
"}\n"
673+
"complete -F _myprog myprog\n")
674+
nil ; use-separate-process
675+
(let ((compfunc-nonprefix (bash-completion_test-candidates
676+
"myprog bee" 'dynamic-table)))
677+
678+
;; all-completion
679+
;;
680+
;; all-completion doesn't strictly follow spec when the
681+
;; completion doesn't start with the word completed. The goal is
682+
;; for the completion to be displayed unless the user edited the
683+
;; text string, so the first time all-completion is called with
684+
;; the current word, all completions are returned, even the one
685+
;; that don't match the string as prefix.
686+
(should (equal '("babeetai" "babeedai") (funcall compfunc-nonprefix "bee" nil t)))
687+
(should (equal '("babeetai" "babeedai") (funcall compfunc-nonprefix "babee" nil t)))
688+
(should (equal '("babeetai") (funcall compfunc-nonprefix "babeet" nil t)))
689+
690+
;; all-completion with predicate
691+
(should (equal '("babeetai") (funcall compfunc-nonprefix "bee"
692+
(lambda (c) (equal "babeetai" c))
693+
t)))
694+
695+
;; try-completion
696+
;;
697+
;; try-completion behaves in a way that's consistent with
698+
;; all-completion: as long as it's passed the same string that's
699+
;; completed, it won't filter the results.
700+
(should (equal "babee" (funcall compfunc-nonprefix "bee" nil nil)))
701+
(should (equal "babee" (funcall compfunc-nonprefix "bab" nil nil)))
702+
(should (equal "babeetai" (funcall compfunc-nonprefix "babeet" nil nil)))
703+
(should (equal t (funcall compfunc-nonprefix "babeetai" nil nil)))
704+
705+
;; try-completion with predicate
706+
(should (equal "babeetai" (funcall compfunc-nonprefix "bee"
707+
(lambda (c) (equal "babeetai" c)) nil)))
708+
(should (equal "babeetai" (funcall compfunc-nonprefix "bab"
709+
(lambda (c) (equal "babeetai" c)) nil)))
710+
711+
;; test-completion
712+
;;
713+
;; test-completion works according to spec.
714+
(should (equal nil (funcall compfunc-nonprefix "bee" nil 'lambda)))
715+
(should (equal nil (funcall compfunc-nonprefix "bab" nil 'lambda)))
716+
(should (equal t (funcall compfunc-nonprefix "babeetai" nil 'lambda)))
717+
718+
;; test-completion with predicate
719+
(should (equal t (funcall compfunc-nonprefix "babeetai"
720+
(lambda (c) (equal "babeetai" c)) 'lambda)))
721+
(should (equal nil (funcall compfunc-nonprefix "babeetai"
722+
(lambda (c) (equal "babeedai" c)) 'lambda))))))
723+
588724
;;; bash-completion-integration-test.el ends here

0 commit comments

Comments
 (0)