Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve completion in region #261

Merged
merged 10 commits into from
Dec 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ The format is based on [Keep a Changelog].
* The user option `selectrum-extend-current-candidate-highlight`
determines whether to extend the highlighting of the current
candidate until the margin (the default is nil). See [#208].
* The user option `selectrum-complete-in-buffer` can be used to
control whether Selectrum should handle in buffer completion (the
default is t) ([#261]).

### Enhancements
* The argument passed to `selectrum-select-current-candidate` and
Expand All @@ -27,8 +30,17 @@ The format is based on [Keep a Changelog].
first and will also make such prompts behave like in default Emacs
completion where you can immediately submit the initial input
([#253]).
* In buffer file completions act like normal completion now and insert
the candidate without prompting if there is only one. You can drop
into the minibuffer by triggering the completion again ([#261]).
* The mark is pushed at the beginning of the candidate inserted by in
buffer completion so you can easily jump there ([#261]).

### Bugs fixed
* For in buffer file completions s-expression commands for path level
navigation did not work which has been fixed ([#261]).
* Do not insert spaces after path completion in comint buffers
([#261])].
* The return value of `selectrum-completion-in-region` has been fixed
according to the documented API of `completion-in-region` ([#251]).
* When strings of Selectrum display properties or completion table
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,10 @@ matching and case-insensitive matching.
instead of indices, roman numerals, etc.) you can set the
`selectrum-show-indices` to a function that takes in the relative
index of a candidate and returns the string you want to display.
* By default, Selectrum does also handle in buffer completion via
`completion-in-region`. If you would like to disable that you can
unset `selectrum-complete-in-buffer` before activating
`selectrum-mode`.
* The `selectrum-completion-in-region` function can display
annotations if the `completion-in-region-function` backend offers
them. Customize the face `selectrum-completion-annotation` to change
Expand Down
147 changes: 80 additions & 67 deletions selectrum.el
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,12 @@ setting."
Nil (the default) means to only highlight the displayed text."
:type 'boolean)

;;;###autoload
(defcustom selectrum-complete-in-buffer t
"If non-nil, use Selectrum for `completion-in-region'.
This option needs to be set before activating `selectrum-mode'."
:type 'boolean)

;;;; Utility functions

(defun selectrum--clamp (x lower upper)
Expand Down Expand Up @@ -1703,11 +1709,16 @@ COLLECTION, and PREDICATE, see `completion-in-region'."
(prog1 t
(pcase category
('file
(setq result
(selectrum--completing-read-file-name
"Completion: " collection predicate
nil input)
exit-status 'finished))
(let ((try nil))
(setq result
(if (and (not (cdr cands))
(stringp (setq try (try-completion
input collection predicate))))
try
(selectrum--completing-read-file-name
"Completion: " collection predicate
nil input))
exit-status 'sole)))
(_
(setq result
(if (not (cdr cands))
Expand All @@ -1721,6 +1732,7 @@ COLLECTION, and PREDICATE, see `completion-in-region'."
exit-status (cond ((not (member result cands)) 'sole)
(t 'finished)))))
(delete-region bound end)
(push-mark (point) 'no-message)
(insert (substring-no-properties result))
(when exit-func
(funcall exit-func result exit-status))))))
Expand Down Expand Up @@ -1823,73 +1835,73 @@ For PROMPT, COLLECTION, PREDICATE, REQUIRE-MATCH, INITIAL-INPUT,
(quit)))))
`((input . ,ematch)
(candidates . ,cands))))))
(selectrum-read
prompt coll
:default-candidate (or (car-safe def) def)
:initial-input (or (car-safe initial-input) initial-input)
:history hist
:require-match (eq require-match t)
:may-modify-candidates t
:minibuffer-completion-table collection
:minibuffer-completion-predicate predicate)))
(minibuffer-with-setup-hook
(lambda ()
(set-syntax-table
selectrum--minibuffer-local-filename-syntax))
(selectrum-read
prompt coll
:default-candidate (or (car-safe def) def)
:initial-input (or (car-safe initial-input) initial-input)
:history hist
:require-match (eq require-match t)
:may-modify-candidates t
:minibuffer-completion-table collection
:minibuffer-completion-predicate predicate))))

;;;###autoload
(defun selectrum-read-file-name
(prompt &optional dir default-filename mustmatch initial predicate)
"Read file name using Selectrum. Can be used as `read-file-name-function'.
For PROMPT, DIR, DEFAULT-FILENAME, MUSTMATCH, INITIAL, and
PREDICATE, see `read-file-name'."
(minibuffer-with-setup-hook
(lambda ()
(set-syntax-table
selectrum--minibuffer-local-filename-syntax))
(let* ((crf completing-read-function)
;; See <https://github.com/raxod502/selectrum/issues/61>.
;; When you invoke another `completing-read' command
;; recursively then it inherits the
;; `completing-read-function' binding, and unless it's
;; another file reading command using
;; `selectrum--completing-read-file-name' this will cause
;; an error. To circumvent this we use the function to
;; reset the variable when called.
(completing-read-function
(lambda (&rest args)
(setq completing-read-function crf)
(when (and default-filename
;; ./ should be omitted.
(not (equal
(expand-file-name default-filename)
(expand-file-name default-directory))))
(setf (nth 6 args) ; DEFAULT
;; Sort for directories needs any final
;; slash removed.
(directory-file-name
;; The candidate should be sorted by it's
;; relative name.
(file-relative-name default-filename
default-directory))))
(apply #'selectrum--completing-read-file-name args))))
(read-file-name-default
prompt dir
;; We don't pass default-candidate here to avoid that
;; submitting the selected prompt results in the default file
;; name. This is the stock Emacs behavior where there is no
;; concept of an active selection. Instead we pass the initial
;; prompt as default so it gets returned when submitted. In
;; addition to that we adjust the DEF argument passed to
;; `selectrum--completing-read-file-name' above so the actual
;; default gets sorted to the top. This should give the same
;; convenience as in default completion (where you can press
;; RET at the initial prompt to get the default). The downside
;; is that this convenience is gone when sorting is disabled or
;; the default-filename is outside the prompting directory but
;; this should be rare case.
(concat
(expand-file-name
(or dir
default-directory))
initial)
mustmatch initial predicate))))
(let* ((crf completing-read-function)
;; See <https://github.com/raxod502/selectrum/issues/61>.
;; When you invoke another `completing-read' command
;; recursively then it inherits the
;; `completing-read-function' binding, and unless it's
;; another file reading command using
;; `selectrum--completing-read-file-name' this will cause
;; an error. To circumvent this we use the function to
;; reset the variable when called.
(completing-read-function
(lambda (&rest args)
(setq completing-read-function crf)
(when (and default-filename
;; ./ should be omitted.
(not (equal
(expand-file-name default-filename)
(expand-file-name default-directory))))
(setf (nth 6 args) ; DEFAULT
;; Sort for directories needs any final
;; slash removed.
(directory-file-name
;; The candidate should be sorted by it's
;; relative name.
(file-relative-name default-filename
default-directory))))
(apply #'selectrum--completing-read-file-name args))))
(read-file-name-default
prompt dir
;; We don't pass default-candidate here to avoid that
;; submitting the selected prompt results in the default file
;; name. This is the stock Emacs behavior where there is no
;; concept of an active selection. Instead we pass the initial
;; prompt as default so it gets returned when submitted. In
;; addition to that we adjust the DEF argument passed to
;; `selectrum--completing-read-file-name' above so the actual
;; default gets sorted to the top. This should give the same
;; convenience as in default completion (where you can press
;; RET at the initial prompt to get the default). The downside
;; is that this convenience is gone when sorting is disabled or
;; the default-filename is outside the prompting directory but
;; this should be rare case.
(concat
(expand-file-name
(or dir
default-directory))
initial)
mustmatch initial predicate)))

(defvar selectrum--old-read-file-name-function nil
"Previous value of `read-file-name-function'.")
Expand Down Expand Up @@ -2072,8 +2084,9 @@ ARGS are standard as in all `:around' advice."
#'selectrum-read-file-name)
(setq selectrum--old-completion-in-region-function
(default-value 'completion-in-region-function))
(setq-default completion-in-region-function
#'selectrum-completion-in-region)
(when selectrum-complete-in-buffer
(setq-default completion-in-region-function
#'selectrum-completion-in-region))
(advice-add #'completing-read-multiple :override
#'selectrum-completing-read-multiple)
;; No sharp quote because Dired may not be loaded yet.
Expand Down