haskell-mode icon indicating copy to clipboard operation
haskell-mode copied to clipboard

Extend haskell-build-type to look for .nix files

Open doyougnu opened this issue 1 year ago • 0 comments

This is not a bug but a missed edge case, the problem is:

  1. I run nixos and use nix for haskell projects
  2. because of (1) I do not have cabal, stack or ghc globally installed
  3. So I have flake.nix and shell.nix and friends in root directories of project.

Now the traditional way to run inferior-haskell-process is with haskell-process-wrapper like so (this uses the nix-sandbox emacs package):

    (setq default-nix-wrapper
          (lambda (args)
            (append
             (append (list "nix-shell" "--command")
                     (list (mapconcat 'identity args " ")))
             (list (nix-current-sandbox))))

(setq  haskell-process-wrapper-function
          (lambda (args)
            (apply 'nix-shell-command (nix-current-sandbox) args)))

However, this doesn't work because haskell-build-type in haskell-customize.el looks for a cabal cabal.project stack file and an executable on path:

(defun haskell-build-type ()
  "Looks for cabal and stack spec files.
   When found, returns a pair (TAG . DIR)
   where TAG is 'cabal-project, 'cabal-sandbox. 'cabal, or 'stack;
   and DIR is the directory containing cabal or stack file.
   When none found, DIR is nil, and TAG is 'ghc"
  ;; REVIEW maybe just 'cabal is enough.
  (let ((cabal-project (locate-dominating-file default-directory "cabal.project"))
        (cabal-sandbox (locate-dominating-file default-directory "cabal.sandbox.config"))
        (stack         (locate-dominating-file default-directory "stack.yaml"))
        (cabal         (locate-dominating-file
                        default-directory
                        (lambda (d)
                          (cl-find-if
                           (lambda (f) (string-match-p ".\\.cabal\\'" f))
                           (directory-files d))))))
    (cond
     ((and cabal-project (executable-find "cabal"))
      (cons 'cabal-project cabal-project))
     ((and cabal-sandbox (executable-find "cabal"))
      (cons 'cabal-sandbox cabal-sandbox))
     ((and stack (executable-find "stack"))
      (cons 'stack stack))
     ((and cabal (executable-find "cabal")) ;; <---------------------------------------------- right here
      (cons 'cabal cabal))
     ((executable-find "ghc") (cons 'ghc nil))
     (t (error "Could not find any installation of GHC.")))))

This means that when I try run-haskell or haskell-process-load-file I get Could not find any installation of GHC even though ghc cabal and friends are accessible from my nix shell.

So to summarize:

  1. the current implementation of haskell-build-type assumes I have stack or cabal globally installed.
  2. However, the user could not have these globally installed and instead choose to provide them in a nix shell. In this scenario haskell-build-type does not realize this and prematurely errors out, even though if it ran inside the nix shell everything would be fine.

So I think there are two paths forward:

  1. add .nix files to the cond expression in haskell-build-type, or
  2. detect if haskell-process-wrapper-function is set, if so run executable-find "foo"` through that.

I think 2 likely makes more sense.

doyougnu avatar Sep 30 '22 17:09 doyougnu