4

Editing a Bash script I want to assign a filename to a variable.

E.g. inputfile=foo.txt

With std. settings I can't complete the filename without first inserting a space after the '='.

Is there any solution to this?

Rorschach
  • 31,301
  • 5
  • 78
  • 129
jogeba
  • 107
  • 4

2 Answers2

3

First of all, comint-dynamic-complete has been obsolete since Emacs 24.1. The replacement function is completion-at-point.

Now, if you starting looking at what completion-at-point actually does in a shell script buffer, you'll eventually end up in comint anyway. In particular, the function comint--match-partial-filename looks promising for an explanation of the behavior you described.

If I read that correctly, the problem here is that "=" is considered a valid part of a filename, at least on POSIX-like systems (see variable comint-file-name-chars). So, the completion mechanism is trying to complete the filename "inputfile=/..." which it can obviously not find.

If you never use a "=" in your filenames (or you use it so rarely that the working completion outweighs other downsides), you may want to consider doing something like (setq comint-file-name-chars "[]~/A-Za-z0-9+@:_.$#%,{}-") in the shell script mode hook (if you are on a POSIX system; on Windows it would look slightly different).

Hope that helps.

Stefan Kamphausen
  • 1,615
  • 15
  • 20
2

You can use bash-completion assuming your not on windows. It just requires a slight modification to work in sh-mode since it uses a comint function to determine the current completion candidate.

I like this because, in addition to completing filenames there, it also will give you all the nice readline completion like command line switches, etc. Here is an example setup using company, but you could remove the company stuff, since all you really need is to add the modified completion-at-point function.

;; required packages: company bash-completion
(eval-when-compile
  (require cl-lib))

;; locally redefine comint-line-beginning-position so bash-completion
;; can work in sh-mode
(defun sh-bash-completion ()
  (cl-letf (((symbol-function 'comint-line-beginning-position)
             #'(lambda ()
                 (save-excursion
                   (sh-beginning-of-command)
                   (point)))))
    (let ((syntax (syntax-ppss)))
      (and (not (or (nth 3 syntax)
                    (nth 4 syntax)))
           (bash-completion-dynamic-complete)))))

;; put this in your sh-mode hook
(defun sh-completion-setup ()
  ;; add capf function
  (add-hook 'completion-at-point-functions
            'sh-bash-completion nil 'local)
  (company-mode)
  (make-local-variable 'company-backends)
  ;; use company completion-at-point
  (delq 'company-capf company-backends)
  (cl-pushnew 'company-capf company-backends)
  (setq-local company-transformers
              '(company-sort-by-backend-importance)))

(add-hook 'sh-mode-hook 'sh-completion-setup)
Rorschach
  • 31,301
  • 5
  • 78
  • 129