branch: elpa/haskell-tng-mode commit dbcef7179301cedd88bded7b07801808497f1809 Author: Tseen She <ts33n....@gmail.com> Commit: Tseen She <ts33n....@gmail.com>
workaround the env file situation --- README.md | 8 +++- haskell-tng-contrib-company.el | 3 +- haskell-tng-hsinspect.el | 83 +++++++++++++++++++++++------------------- 3 files changed, 54 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 2723450..d31d2a2 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Built-in navigation commands such as `forward-symbol`, `forward-sexp` and `imenu The optional command line tool `hsinspect` provides semantic information by using the `ghc` api. -`hsinspect` must be installed separately for each version of `ghc` that you are using. +<!-- `hsinspect` must be installed separately for each version of `ghc` that you are using. --> At the moment only one version of `ghc` is supported at a time (change `ghc-8.4.4` to your current `ghc` version): @@ -92,6 +92,12 @@ with recommended binding ("C-c C-i s" . haskell-tng-fqn-at-point)) ``` +### Known Problems + +To use `hsinspect` commands, generate a `.hsinspect.env` file by running `M-x haskell-tng-hsinspect` for a project. This is only needed when the dependencies change, but the project must be compilable. + +See [the gory details](https://gitlab.com/tseenshe/hsinspect) for more information and known caveats. Hopefully there will be no need for `haskell-tng-hsinspect` in a future release. + ## Contrib Integrations are provided for common libraries and external applications (installed separately), enable them from `use-package` with diff --git a/haskell-tng-contrib-company.el b/haskell-tng-contrib-company.el index c53baae..06e50cc 100644 --- a/haskell-tng-contrib-company.el +++ b/haskell-tng-contrib-company.el @@ -26,8 +26,7 @@ (defcustom haskell-tng-company-backends '(company-files - (company-dabbrev-code company-keywords) - haskell-tng--company-hsinspect) + (haskell-tng--company-hsinspect company-dabbrev-code company-keywords)) "The company mode backends to use for haskell files" :type 'listp :group 'haskell-tng) diff --git a/haskell-tng-hsinspect.el b/haskell-tng-hsinspect.el index f6fbbae..fbc905a 100644 --- a/haskell-tng-hsinspect.el +++ b/haskell-tng-hsinspect.el @@ -13,23 +13,8 @@ (require 'haskell-tng-compile) -;; TODO automatically installing hsinspect under hsinspect-ghc-X - -(defcustom haskell-tng-hsinspect - ;; TODO https://github.com/haskell/cabal/issues/6182 - ;; - ;; all flags (optimisations, compiler, tests, etc) must match what the user - ;; typed or else local packages aren't visible. - ;;'("cabal" "v2-exec" "-v0" "-O0" "--enable-tests" "--") - '() ;; best to use environment files, less fragile - "Launch command for the `hsinspect' external tool." - :type 'listp - :group 'haskell-tng) - (defvar-local haskell-tng-hsinspect-langexts nil) ;; TODO improve the validity checker -;;;###autoload -(put 'haskell-tng-hsinspect-langexts 'safe-local-variable #'listp) ;;;###autoload (defun haskell-tng-fqn-at-point () @@ -44,7 +29,27 @@ name of the symbol at point in the minibuffer." (message "%s" (car (last found))) (message "<not imported>"))) -;; FIXME implement the `.hsinspect.env' hack and document the workflow +(defvar haskell-tng-hsinspect + (concat + ;; no need to compile tests, use O0 so it is faster + "hsinspect-init () {\n" + " cabal v2-build -O0 :all &&\n" + " cabal v2-exec -O0 -- sh -c 'cat $GHC_ENVIRONMENT > .hsinspect.env'\n" + "}\n" + "hsinspect-init")) +;;;###autoload +(defun haskell-tng-hsinspect () + "Required (for now) to initialise a project for use with `hsinspect'. +Only needs to be performed once every time the dependencies +change." + (interactive) + (when-let ((default-directory + (or + ;; prefer the full project before packages + (locate-dominating-file "project.cabal" "project.cabal.local") + (haskell-tng--util-locate-dominating-file + haskell-tng--compile-dominating-file)))) + (async-shell-command haskell-tng-hsinspect))) ;; TODO invalidate cache when imports section has changed ;; TODO is there a way to tell Emacs not to render this in `C-h v'? @@ -58,27 +63,31 @@ t means the process failed.") haskell-tng--hsinspect-imports) (setq haskell-tng--hsinspect-imports t) ;; avoid races (ignore-errors (kill-buffer "*hsinspect*")) - (let ((default-directory - (or - (haskell-tng--util-locate-dominating-file - haskell-tng--compile-dominating-file) - default-directory))) - (if (/= 0 (apply - #'call-process - ;; TODO launching the correct hsinspect-ghc-X version - ;; TODO is there a way to pipe into a string not a buffer? - ;; TODO async - "hsinspect" - nil "*hsinspect*" nil - (append `("imports" ,buffer-file-name) - haskell-tng-hsinspect-langexts))) - (user-error "`hsinspect' failed. See the *hsinspect* buffer for more information") - (setq haskell-tng--hsinspect-imports - (with-current-buffer "*hsinspect*" - (goto-char (point-min)) - (re-search-forward (rx bol "(") nil t) ;; sometimes there is junk from the launcher - (goto-char (match-beginning 0)) - (or (ignore-errors (read (current-buffer))) t))))))) + (let ((envdir (locate-dominating-file default-directory ".hsinspect.env"))) + (if (not envdir) + (user-error "could not find `.hsinspect.env'. Run `M-x haskell-tng-hsinspect'") + (if (/= 0 + (let* ((ghcenv + (concat "GHC_ENVIRONMENT=" + (expand-file-name envdir) ".hsinspect.env")) + (process-environment + (cons ghcenv process-environment))) + (apply + #'call-process + ;; TODO launching the correct hsinspect-ghc-X version + ;; TODO is there a way to pipe into a string not a buffer? + ;; TODO async + "hsinspect" + nil "*hsinspect*" nil + (append `("imports" ,buffer-file-name) + haskell-tng-hsinspect-langexts)))) + (user-error "`hsinspect' failed. See the *hsinspect* buffer for more information") + (setq haskell-tng--hsinspect-imports + (with-current-buffer "*hsinspect*" + (goto-char (point-min)) + (re-search-forward (rx bol "(") nil t) ;; sometimes there is junk from the launcher + (goto-char (match-beginning 0)) + (or (ignore-errors (read (current-buffer))) t)))))))) (provide 'haskell-tng-hsinspect) ;;; haskell-tng-hsinspect.el ends here