1

Background

I am working with prolog in emacs and using prolog-inferior-mode which has comint-mode as a parent mode.

The default completion in comint-modes is rather terrible, and I was hoping to be able to use helm to do tab completion on the history. I discovered tab-always-indent and set it to complete, which triggers completion when appropriate upon hitting the tab key. I also discovered completion-at-point-functions and wrote a helm source that grabs the previous comint history, which is stored in comint-input-ring. This variable only exists locally in comint buffers, it seems.

I wrote the following code:

(defun get-comint-candidates ()
  (interactive)
  (let ((start (car comint-input-ring)) 
        (end (car (cdr comint-input-ring)))
        (completed (append (nthcdr 2 comint-input-ring) nil)))
    (butlast (nthcdr start completed) (- (length completed) end)))
  )

(defun comint-completion-source ()
  (interactive)
  (helm :sources '((name . "helm comint-mode")
                   (candidates . get-comint-candidates)
                   (action . (lambda (cand) (insert cand)))
                   )
        :input (thing-at-point 'word)
        )
  )

(add-hook 'comint-mode-hook (lambda () (setq completion-at-point-functions 'comint-completion-source)))
(setq tab-always-indent 'complete)

The problem

If I am inside the prolog comint buffer and call get-comint-candidates, it returns the candidates as it should. However, whenever I call comint-completion-source either manually or using the tab key, the completion buffer is empty. Moreover, I'm not sure if this is the right solution. I would prefer to be able to basically tell helm that it's supposed to complete from my source and use the default helm completion-at-point functionality, such that I don't have to manually take care of inserting only the parts of the chosen completion that I haven't already typed(that is to say, if I have typed fo and complete foobar, I want it to result in foobar, not fofoobar).

I would be very grateful for any hints or tips on how to solve this, as well as any on working with comint-mode and its children modes in general.

1

I write tcl code rather than prolog, so I tried your idea on inferior-tcl-mode and it works as expected:

(defun helm-inferior-tcl-complete ()
  (interactive)
  (helm :sources (helm-build-sync-source "inferior tcl completion"
                   :candidates (ring-elements comint-input-ring))))

(add-hook 'inferior-tcl-mode-hook
          (lambda ()
            (define-key inferior-tcl-mode-map
              [remap completion-at-point] #'helm-inferior-tcl-complete)))

PS. Building helm source manually is the old way, nowadays, you might want to use the built-in macro/function/class provided by helm since it is easier to write and more readable. (related doc https://github.com/emacs-helm/helm/wiki#254-building-sources)

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.