travisbhartwell/nix-emacs

nix-shell-command might need to do more complicated processing? (suggested flycheck config fails on elisp files)

cumber opened this issue · 2 comments

The readme suggests this configuration for flycheck wrappers to find nix shells:

(setq flycheck-command-wrapper-function
        (lambda (command) (apply 'nix-shell-command (nix-current-sandbox) command))
      flycheck-executable-find
        (lambda (cmd) (nix-executable-find (nix-current-sandbox) cmd)))

This has been working great for my Haskell development. But when I edit an elisp file (such as ~/.emacs.d/init.el) I get this error:

Suspicious state from syntax checker emacs-lisp-checkdoc: Flycheck checker emacs-lisp-checkdoc returned non-zero exit code 1, but its output contained no errors: /run/current-system/sw/bin/bash: -c: line 0: syntax error near unexpected token `('

The command its running appears to be this:

"bash" "-c" "source /tmp/nix-sandbox-rc-8480dqC; /nix/store/1v2ral91bd58w3rawxb1p4a6dwdmz1fd-emacs-25.3/bin/.emacs-wrapped -Q --batch --eval (progn (setq-default sentence-end-double-space t)) --eval (progn (defvar jka-compr-inhibit) (unwind-protect (let ((jka-compr-inhibit t)) (when (equal (car command-line-args-left) "--") (setq command-line-args-left (cdr command-line-args-left))) (unless (require 'elisp-mode nil 'no-error) (require 'lisp-mode)) (require 'checkdoc) (let ((source (car command-line-args-left)) (process-default-directory default-directory)) (with-temp-buffer (insert-file-contents source 'visit) (setq buffer-file-name source) (setq default-directory process-default-directory) (with-demoted-errors "Error in checkdoc: %S" (delay-mode-hooks (emacs-lisp-mode)) (setq delayed-mode-hooks nil) (checkdoc-current-buffer t) (with-current-buffer checkdoc-diagnostic-buffer (princ (buffer-substring-no-properties (point-min) (point-max))) (kill-buffer)))))) (setq command-line-args-left nil))) -- /tmp/flycheck8480q0I/foo.el"

The problem being that quotes have been added around all the outer strings, but since we're calling bash -c the last string is another bash command, and the arguments inside that command aren't quoted properly.

I think what's going on is that nix-shell-command is taking a list of shell parameters in command, and in order to embed them into a bash command that sources the sandbox environment it's pasting them in a string. That works provided all the arguments are "simple" enough, but the emacs-lisp checker wants to invoke emacs with a bunch of lisp code as --eval arguments; all the parentheses and single quotes in the lisp arguments are being interpreted as bash syntax.

While it's not for elisp, I did following to fix the flycheck for YAML files:

  (setq-default
   flycheck-yaml-ruby-executable '("ruby" "-ryaml" "-e"
                                   "'begin;
                                       YAML.load(STDIN);
                                     rescue Exception => e;
                                       STDERR.puts %(stdin:#{e});
                                     end'"))

Maybe something similar could work for you?

I think this ought to work:

(setq flycheck-command-wrapper-function
      (lambda (cmd)
        (list "bash" "-c" (format "source %s; %s"
                                  (nix-sandbox-rc (nix-current-sandbox))
                                  (mapconcat 'shell-quote-argument cmd " ")))))

Or this, I guess:

(setq flycheck-command-wrapper-function
      (lambda (cmd)
        (apply 'nix-shell-command (nix-current-sandbox)
               (list (mapconcat 'shell-quote-argument cmd " ")))))

Or just replace the definition of nix-shell-command:

(defun nix-shell-command (sandbox &rest args)
  "Assemble a command from ARGS that can be executed in the specified SANDBOX."
  (list "bash" "-c" (format "source %s; %s" (nix-sandbox-rc sandbox)
                            (mapconcat 'shell-quote-argument args " "))))