Suppose we have a collection of descriptions like this:

("procedural" "functional" "high-level" "low-level" "statically-scoped" "dynamically-scoped")

Suppose that we have a database of programming languages and would like to enable the user to enter queries like this:

(or (and procedural high-level) dynamically-scoped)

with completion aid for the words from the collection. I have looked at (ido-)completing-read, but it seems to match the whole input string instead of individual words. With what tool can I achieve the desired behavior?

  • Have you tried letting the user work in a temporary buffer to construct the query expression, completing individual names in that buffer using completion-at-point? – Drew Aug 1 '17 at 20:19
  • @Drew Why do you say "a temporary buffer"? Can't completion work in the mini-buffer? Please see my post where I report trying this out: emacs.stackexchange.com/q/34593/16048 – AlwaysLearning Aug 1 '17 at 21:52
  • Yes, it can. I just thought it might be less confusing for a user and easier for you, since you don't have to bother with the minibuffer keymaps. – Drew Aug 1 '17 at 23:42
  • @Drew I tried to pass the company mode's keymap to read-from-buffer in the post that I cited in my comment above and it still did not work... – AlwaysLearning Aug 2 '17 at 6:13
  • You may want to look at the source of regexp-builder as the way you describe the interaction is similar to what it does. You may also find sphinxsearch.com to be of interest since it has a query language similar to what you describe and can produce results later useful for completion (it can sort the search results intelligently based on query parameters). – wvxvw Aug 2 '17 at 6:43

Here is a complete solution based on this discussion:

(require 'company)
(require 'cl-lib)

(defconst sample-completions
  '("procedural" "functional" "high-level" "low-level" "statically-scoped" "dynamically-scoped"))

;; This function is based on http://sixty-north.com/blog/writing-the-simplest-emacs-company-mode-backend
(defun company-sample-backend (command &optional arg &rest ignored)
  (interactive (list 'interactive))
  (let ((my-completions (copy-sequence sample-completions)))
    (cl-case command
      (interactive (company-begin-backend 'company-sample-backend))
      (prefix (and t ;(eq major-mode 'fundamental-mode)
    (lambda (c) (string-prefix-p arg c))

(define-key company-mode-map (kbd "TAB") 'company-sample-backend)

(setq resize-mini-windows t)

(defun my-minibuffer-mode ()
  (company-mode 1))

We can now perform the input without altering the normal function of the mini-buffer as follows:

(let ((company-backends (copy-sequence company-backends))
      (minibuffer-setup-hook (copy-sequence minibuffer-setup-hook)))
  (add-to-list 'company-backends 'company-sample-backend)
  (add-hook 'minibuffer-setup-hook 'my-minibuffer-mode)
  (read-from-minibuffer "Prompt: "))

Acknowledgement: thank you very much to everyone for their comments.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.