2

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?

8
  • 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
    Commented Aug 1, 2017 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 Commented Aug 1, 2017 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
    Commented Aug 1, 2017 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... Commented Aug 2, 2017 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
    Commented Aug 2, 2017 at 6:43

1 Answer 1

1

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)
           (company-grab-symbol)))
      (candidates
       (cl-remove-if-not
    (lambda (c) (string-prefix-p arg c))
    my-completions)))))

(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 and acknowledge you have read our privacy policy.

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