Skip to content

Commit

Permalink
Merge pull request #56 from wyuenho/defcustoms-take-effect-immediately
Browse files Browse the repository at this point in the history
  • Loading branch information
creichert committed Feb 5, 2021
2 parents 2252225 + 9485b25 commit b1659e9
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 119 deletions.
82 changes: 58 additions & 24 deletions ido-vertical-mode.el
Expand Up @@ -44,32 +44,46 @@
;; Remember if current directory is 'huge' (so we don't want to do completion).
(defvar ido-directory-too-big)

(defcustom ido-vertical-indicator "->"
"Indicator displayed next to the candidate that will be selected."
:type 'string
:group 'ido-vertical-mode)

(defvar ido-vertical-decorations
`(,(format "\n%s " ido-vertical-indicator) ; left bracket around prospect list
"" ; right bracket around prospect list
"\n " ; separator between prospects, depends on `ido-separator`
"\n ..." ; inserted at the end of a truncated list of prospects
"[" ; left bracket around common match string
"]" ; right bracket around common match string
" [No match]"
" [Matched]"
" [Not readable]"
" [Too big]"
" [Confirm]"
,(format "\n%s " ido-vertical-indicator) ; left bracket around the sole remaining completion
"" ; right bracket around the sole remaining completion
)

(defvar ido-vertical-decorations nil
"Changing the decorations does most of the work for ido-vertical
This sets up newlines and arrows before, between, and after the
prospects. For additional information, see `ido-decorations'.")

(defcustom ido-vertical-padding " "
"How many spaces to pad the completion candidates.
When setting this variable in ELISP, you must also make sure
`ido-vertical-decorations' is updated. In addition, if
`ido-vertical-mode' is on, it must be set to the new value of
`ido-vertical-decorations' for this variable to take effect in
the next ido completion event."
:type 'string
:group 'ido-vertical
:initialize 'custom-initialize-default
:set (lambda (symbol value)
(set-default symbol value)
(setq ido-vertical-decorations (ido-vertical-make-decorations :padding value))
(when (bound-and-true-p ido-vertical-mode)
(setq ido-decorations ido-vertical-decorations))))

(defcustom ido-vertical-indicator "->"
"Indicator displayed next to the candidate that will be selected.
When setting this variable in ELISP, you must also make sure
`ido-vertical-decorations' is updated. In addition, if
`ido-vertical-mode' is on, it must be set to the new value of
`ido-vertical-decorations' for this variable to take effect in
the next ido completion event."
:type 'string
:group 'ido-vertical
:initialize 'custom-initialize-default
:set (lambda (symbol value)
(set-default symbol value)
(setq ido-vertical-decorations (ido-vertical-make-decorations :indicator value))
(when (bound-and-true-p ido-vertical-mode)
(setq ido-decorations ido-vertical-decorations))))

(defvar ido-vertical-old-decorations nil
"The original `ido-decorations' variable
Expand Down Expand Up @@ -128,6 +142,25 @@ so we can restore it when turning `ido-vertical-mode' off")
"Face used by Ido Vertical for the matched part."
:group 'ido-vertical)

(cl-defun ido-vertical-make-decorations (&key (padding ido-vertical-padding)
(indicator ido-vertical-indicator))
"Construct a new `ido-decorations' format."
(list
(concat "\n" indicator padding) ; left bracket around prospect list
"" ; right bracket around prospect list
(concat (format (format "\n%%-%ds" (length indicator)) "") padding) ; separator between prospects, depends on `ido-separator`
(concat (format (format "\n%%-%ds" (length indicator)) "") padding "...") ; inserted at the end of a truncated list of prospects
"[" ; left bracket around common match string
"]" ; right bracket around common match string
" [No match]"
" [Matched]"
" [Not readable]"
" [Too big]"
" [Confirm]"
(concat "\n" indicator padding) ; left bracket around the sole remaining completion
"" ; right bracket around the sole remaining completion
))

(defun ido-vertical-or-horizontal-completions (name)
(if (and ido-vertical-disable-if-short
(<= (length ido-matches) ido-max-prospects))
Expand Down Expand Up @@ -192,11 +225,12 @@ so we can restore it when turning `ido-vertical-mode' off")
(put-text-property 0 1 'face 'ido-indicator ind))

(when ido-vertical-show-count
(setcar ido-vertical-decorations (format " [%d]\n%s " lencomps ido-vertical-indicator))
(setcar ido-vertical-decorations (concat (format " [%d]\n%s" lencomps ido-vertical-indicator)
ido-vertical-padding))
(setq ido-vertical-count-active t))
(when (and (not ido-vertical-show-count)
ido-vertical-count-active)
(setcar ido-vertical-decorations (format "\n%s "ido-vertical-indicator))
(setcar ido-vertical-decorations (concat "\n" ido-vertical-indicator ido-vertical-padding))
(setq ido-vertical-count-active nil))

(if (and ido-use-faces comps)
Expand Down Expand Up @@ -293,7 +327,7 @@ so we can restore it when turning `ido-vertical-mode' off")
(setq ido-vertical-old-decorations ido-decorations)
(setq ido-vertical-old-completions (symbol-function 'ido-completions))))

(setq ido-decorations ido-vertical-decorations)
(setq ido-vertical-decorations (ido-vertical-make-decorations) ido-decorations ido-vertical-decorations)
(fset 'ido-completions 'ido-vertical-or-horizontal-completions)

(add-hook 'ido-minibuffer-setup-hook 'ido-vertical-disable-line-truncation)
Expand Down
217 changes: 122 additions & 95 deletions test/ido-vertical-mode-test.el
@@ -1,54 +1,75 @@
(require 'cl-lib)
(require 'ert)
(require 'ido)
(require 'ido-vertical-mode)

(ido-mode 1)
(ido-vertical-mode 1)

;;; invoke ido-switch-buffer to initialize ido variables that would
;;; otherwise throw void error
(execute-kbd-macro [24 98 return] 1)
(cl-defmacro ivm-fixture (test-body &key (setup nil) (teardown nil))
`(unwind-protect
(progn
,setup
(ido-mode 1)
(ido-vertical-mode 1)
;;; invoke ido-switch-buffer to initialize ido variables that would
;;; otherwise throw void error
(execute-kbd-macro [24 98 return] 1)
,test-body)
(ido-vertical-mode -1)
(ido-mode -1)
,teardown))

(ert-deftest ivm-should-install-decorations ()
(ido-vertical-mode 1)
(let ((prospects (ido-completions "")))
(should (string-match "->" prospects))
(should (string-match "\n" prospects))))
(ivm-fixture
(let ((prospects (ido-completions "")))
(should (string-match "->" prospects))
(should (string-match "\n" prospects)))))

(ert-deftest ivm-should-update-decorations ()
(ivm-fixture
(let ((prospects (ido-completions "")))
(should (string-match "\\$" prospects))
(should (string-match "\n" prospects))
(should (string-match "-" (car (split-string prospects)))))
:setup
(setq ido-vertical-indicator "$" ido-vertical-padding "-")
:teardown
(setq ido-vertical-indicator (default-toplevel-value 'ido-vertical-indicator)
ido-vertical-padding (default-toplevel-value 'ido-vertical-padding))))

(ert-deftest ivm-should-indicate-more-results ()
(ido-vertical-mode 1)
(let ((buffers (mapcar (lambda (num)
(get-buffer-create
(format "ivm-test-buffer-%s" num)))
(number-sequence 1 11)))
prospects)
(save-window-excursion
(execute-kbd-macro [24 98 ?i ?v ?m ?- ?t ?e ?s ?t])
(setq prospects (ido-completions "ivm-test"))
(should (string-match "\.\.\.$" prospects)))
(mapc 'kill-buffer buffers)))
(ivm-fixture
(let ((buffers (mapcar (lambda (num)
(get-buffer-create
(format "ivm-test-buffer-%s" num)))
(number-sequence 1 11)))
prospects)
(save-window-excursion
(execute-kbd-macro [24 98 ?i ?v ?m ?- ?t ?e ?s ?t])
(setq prospects (ido-completions "ivm-test"))
(should (string-match "\.\.\.$" prospects)))
(mapc 'kill-buffer buffers))))

(ert-deftest ivm-should-properly-disable-itself ()
(ido-vertical-mode 1)
(ido-vertical-mode -1)
(should (not (string-match "\n" (ido-completions "")))))
(let ((old-ido-decorations ido-decorations))
(ivm-fixture nil)
(should (equal old-ido-decorations ido-decorations))))

(ert-deftest ivm-should-show-confirm-dialog ()
(ido-vertical-mode 1)
(let* ((no-results [24 98 ?t ?h ?i ?s ?s ?h ?o ?u ?l ?d ?n ?o ?t ?m ?a ?t ?c ?h])
(confirm (vconcat no-results [return])))
(execute-kbd-macro no-results 1)
(should (string-match "No Match" (buffer-name (current-buffer))))
(kill-buffer (current-buffer))
(execute-kbd-macro confirm 1)
(should (string-match "Confirm" (buffer-name (current-buffer))))
(kill-buffer (current-buffer))))
(ivm-fixture
(let* ((no-results [24 98 ?t ?h ?i ?s ?s ?h ?o ?u ?l ?d ?n ?o ?t ?m ?a ?t ?c ?h])
(confirm (vconcat no-results [return])))
(execute-kbd-macro no-results 1)
(should (string-match "No Match" (buffer-name (current-buffer))))
(kill-buffer (current-buffer))
(execute-kbd-macro confirm 1)
(should (string-match "Confirm" (buffer-name (current-buffer))))
(kill-buffer (current-buffer)))))

(ert-deftest ivm-should-handle-fontified-candidates ()
(let ((ido-matches '((#(".ido.last" 1 4 (face ido-vertical-match-face)) "/Users/JS/")
""
(#("200-ido.el" 4 7 (face ido-vertical-match-face)) "/Users/JS/.emacs.d/configs/" "~/.emacs.d/configs/"))))
(should (ido-vertical-completions "ido"))))
(ivm-fixture
(let ((ido-matches '((#(".ido.last" 1 4 (face ido-vertical-match-face)) "/Users/JS/")
""
(#("200-ido.el" 4 7 (face ido-vertical-match-face)) "/Users/JS/.emacs.d/configs/" "~/.emacs.d/configs/"))))
(should (ido-vertical-completions "ido")))))

;;; The following tests are pretty fragile. ido-vertical-completions
;;; depends on the global value of ido-matches, which we set. It
Expand All @@ -57,71 +78,77 @@
;;; have the expected faces.

(ert-deftest ivm-should-highlight-matched-candidates ()
(let* ((ido-use-faces t)
(ido-matches '("ido" "ido-vertical"))
(ido-query (ido-vertical-completions "ido"))
(first-comp-pos (string-match "ido" ido-query))
(ido-query-first-comp-face (get-text-property first-comp-pos 'face ido-query))
(ido-query-second-comp-face (get-text-property (+ first-comp-pos 7) 'face ido-query))
(debug nil))
(when debug (prin1 ido-query))
(should (and (memq 'ido-vertical-match-face ido-query-first-comp-face)
(memq 'ido-vertical-first-match-face ido-query-first-comp-face)))
(should (and (memq 'ido-vertical-match-face `(,ido-query-second-comp-face))
(eq nil (get-text-property 19 'face ido-query))))))
(ivm-fixture
(let* ((ido-use-faces t)
(ido-matches '("ido" "ido-vertical"))
(ido-query (ido-vertical-completions "ido"))
(first-comp-pos (string-match "ido" ido-query))
(ido-query-first-comp-face (get-text-property first-comp-pos 'face ido-query))
(ido-query-second-comp-face (get-text-property (+ first-comp-pos 7) 'face ido-query))
(debug nil))
(when debug (prin1 ido-query))
(should (and (memq 'ido-vertical-match-face ido-query-first-comp-face)
(memq 'ido-vertical-first-match-face ido-query-first-comp-face)))
(should (and (memq 'ido-vertical-match-face `(,ido-query-second-comp-face))
(eq nil (get-text-property 19 'face ido-query)))))))

(ert-deftest ivm-should-not-highlight-without-ido-use-faces ()
(let* ((ido-use-faces nil)
(ido-matches '("ido"))
(ido-query (ido-vertical-completions "ido"))
(first-comp-pos (string-match "ido" ido-query))
(ido-query-first-comp-face (get-text-property first-comp-pos 'face ido-query))
(debug nil))
(when debug (prin1 ido-query))
(should (eq nil ido-query-first-comp-face))))
(ivm-fixture
(let* ((ido-use-faces nil)
(ido-matches '("ido"))
(ido-query (ido-vertical-completions "ido"))
(first-comp-pos (string-match "ido" ido-query))
(ido-query-first-comp-face (get-text-property first-comp-pos 'face ido-query))
(debug nil))
(when debug (prin1 ido-query))
(should (eq nil ido-query-first-comp-face)))))

(ert-deftest ivm-should-not-highlight-missed-candidates ()
(let* ((ido-use-faces t)
(ido-matches '("ido" "ido-vertical"))
(ido-query (ido-vertical-completions "no results"))
(first-comp-pos (string-match "ido" ido-query))
(second-comp-pos (+ 7 first-comp-pos))
(ido-query-first-comp-face (get-text-property first-comp-pos 'face ido-query))
(ido-query-second-comp-face (get-text-property second-comp-pos 'face ido-query))
(debug nil))
(when debug (prin1 ido-query))
(should (memq 'ido-vertical-first-match-face `(,ido-query-first-comp-face)))
(should (and (eq nil ido-query-second-comp-face)))))
(ivm-fixture
(let* ((ido-use-faces t)
(ido-matches '("ido" "ido-vertical"))
(ido-query (ido-vertical-completions "no results"))
(first-comp-pos (string-match "ido" ido-query))
(second-comp-pos (+ 7 first-comp-pos))
(ido-query-first-comp-face (get-text-property first-comp-pos 'face ido-query))
(ido-query-second-comp-face (get-text-property second-comp-pos 'face ido-query))
(debug nil))
(when debug (prin1 ido-query))
(should (memq 'ido-vertical-first-match-face `(,ido-query-first-comp-face)))
(should (and (eq nil ido-query-second-comp-face))))))

(ert-deftest ivm-should-highlight-only-candidate ()
(let* ((ido-use-faces t)
(ido-matches '("ido"))
(ido-query (ido-vertical-completions "no results"))
(first-comp-pos (string-match "ido" ido-query))
(ido-query-first-comp-face (get-text-property first-comp-pos 'face ido-query))
(debug nil))
(when debug (prin1 ido-query))
(should (memq 'ido-vertical-only-match-face `(,ido-query-first-comp-face)))))
(ivm-fixture
(let* ((ido-use-faces t)
(ido-matches '("ido"))
(ido-query (ido-vertical-completions "no results"))
(first-comp-pos (string-match "ido" ido-query))
(ido-query-first-comp-face (get-text-property first-comp-pos 'face ido-query))
(debug nil))
(when debug (prin1 ido-query))
(should (memq 'ido-vertical-only-match-face `(,ido-query-first-comp-face))))))

(ert-deftest ivm-should-show-count ()
(let* ((ido-matches '("1" "2" "3" "4" "5"))
(ido-vertical-show-count t)
(ido-use-faces nil)
(query (ido-vertical-completions "")))
;; Exposes a bug where we were toggling the count on and off
;; instead of keeping it on
(setq query (ido-vertical-completions ""))
(should (string= " [5]\n" (substring query 0 5)))
;; Count should update when filtering completions
(setq ido-matches '("1"))
(setq query (ido-vertical-completions "1"))
(should (string= " [1]" (substring query 0 4)))))
(ivm-fixture
(let* ((ido-matches '("1" "2" "3" "4" "5"))
(ido-vertical-show-count t)
(ido-use-faces nil)
(query (ido-vertical-completions "")))
;; Exposes a bug where we were toggling the count on and off
;; instead of keeping it on
(setq query (ido-vertical-completions ""))
(should (string= " [5]\n" (substring query 0 5)))
;; Count should update when filtering completions
(setq ido-matches '("1"))
(setq query (ido-vertical-completions "1"))
(should (string= " [1]" (substring query 0 4))))))

(ert-deftest ivm-should-turn-off-count ()
(let* ((ido-matches '("1"))
(ido-vertical-show-count nil)
(query (ido-vertical-completions "")))
(should (string= "\n-> " (substring-no-properties query 0 4)))))
(ivm-fixture
(let* ((ido-matches '("1"))
(ido-vertical-show-count nil)
(query (ido-vertical-completions "")))
(should (string= "\n-> " (substring-no-properties query 0 4))))))


;; Test that valid regexp characters are handled properly
Expand All @@ -132,6 +159,6 @@
;; (should-error (ido-vertical-completions "[") :type 'invalid-regexp)
;;
(ert-deftest ivm-should-allow-regexp ()
(ido-vertical-mode 1)
(let ((query (ido-vertical-completions "scratch")))
(should (string= "\n-> *Messages*\n" (substring-no-properties query 0 15)))))
(ivm-fixture
(let ((query (ido-vertical-completions "scratch")))
(should (string= "\n-> *Messages*\n" (substring-no-properties query 0 15))))))

0 comments on commit b1659e9

Please sign in to comment.