dante icon indicating copy to clipboard operation
dante copied to clipboard

dante does not support multiple targets at once

Open pasunboneleve opened this issue 7 years ago • 20 comments

nix-shell --run "cabal repl --builddir=dist/dante"

is hardcoded into dante. However, it will not work in a project with multiple targets such as qfpl applied fp course. I find that (at least in my system)

nix-shell --run "cabal new-repl --builddir=dist/dante"

works fine in the shell.

Would it be possible to address this limitation in Dante by using new-repl in nix-shell? Dante works fine when I replace cabal repl with cabal new-repl in my system.

pasunboneleve avatar Aug 28 '18 07:08 pasunboneleve

I don't know much about the merits of new-repl vs repl, but instead of using new-repl, you can solve your issue by assigning a value to the dante-target variable. This can be done very conveniently using Emacs' native directory variable feature (https://www.gnu.org/software/emacs/manual/html_node/elisp/Directory-Local-Variables.html).

For an example how I use this, have a look at my project here: https://github.com/sboehler/beans. There is a .dir-locals.el file in each source directory (/app, /src, /test) which defines a target for the cabal repl command issued by dante. So whenever I open a Haskell file in /src, the associated dante process will use lib:beans as target.

In addition, I use a .dir-locals.el file at the project root, to customize general Haskell-mode settings.

Hope this helps!

sboehler avatar Aug 28 '18 19:08 sboehler

Interesting.

cabal repl exe:level02-exe

works as expected.

;; .dir-locals.el
((haskell-mode . (
		  (dante-target . "exe:level02-exe")
		  )))

Does not help. Notice below that Dante does pick up the config from .dir-locals.el.

This is the buffer associated with the GHCi session. This buffer
is normally hidden, but the GHCi process ended.

EXTRA TROUBLESHOOTING INFO

Process state change: exited abnormally with code 1

default-directory "/Users/dmvianna/sandbox/applied-fp-course/"
dante-command-line ("nix-shell" "--run" "cabal repl exe:level02-exe --builddir=dist/dante")
dante-state dead
dante-queue (#[257 "r\302\301!\203\302\301!q\210\212\301b\210\300!*\207" [#[257 "\211\306\307\310\"\304\"\211\303\205\211\211\203\307\311\"\301!\262\202R\302\211\205)\312 ?\313 )\300\2036\314\2027\315\316\317\320\321\322\323\300\301\304%\324\"\325\326%\"\262\262\262\262\262\262\207" [nil #[257 "\303\304p!!\301\305\306\307\310\311\312\313\314\300
\"\315\"\316\317%\"\320\203I@\321!
>\2040\322\323\324D\"\210\211\325H\326=\204=\211B\262\210\211T\262A\262\202\266\211\237\262\"\207" [haskell-dante #[128 "\301\302\300#\207" [#s(flycheck-syntax-check #<buffer Core.hs> haskell-dante nil "/Users/dmvianna/sandbox/applied-fp-course/src/Level02/") apply flycheck-report-buffer-checker-status] 5 "

(fn &rest ARGS)"] cl-struct-flycheck-error-tags dante-local-name buffer-file-name finished nil mapcar make-byte-code 257 "\302\300p\301$\207" vconcat vector [dante-fly-message] 6 "

(fn IT)" 0 type-of signal wrong-type-argument flycheck-error 7 splice] 13 "

(fn MESSAGES)"] 171 nil "/Users/dmvianna/sandbox/applied-fp-course/src/Level02/Core.hs" dante-temp-epoch s-equals\? buffer-local-value dante-loaded-file dante-load-message flycheck-running-p save-buffer ":set -fbyte-code" ":set -fobject-code" dante-async-call make-byte-code 257 "p\211\303q\305\300\204\304\203\306\202\307\300\203\310\202\311\312\302!Q!\313\311\314\315\316\317\320\321\301\302#\322\"\323\324%#\262\262\262\207" vconcat vector [dante-async-write ":r" ":l " "*" "" dante-local-name dante-load-loop nil make-byte-code 257 "\211\211G\305U\203\211A\262\242\202\306\307\310GD\"\211A\262\242@\301\211\266\203\302q\300!\262\262\207" vconcat vector [dante-loaded-file dante-load-message 3 signal wrong-number-of-arguments nil] 7 "

(fn V14)"] 16 "

(fn V9)" flycheck-mode] 20 "

(fn V3)"] #<marker at 1183 in Core.hs> marker-buffer] 3 "

(fn BUFFER)"])
dante-loaded-file "<DANTE:NO-FILE-LOADED>"
dante-load-message nil
lcr-process-callback #[257 "\303\304\305\300#\210r\306\302!\203\306\302!q\210\212\302b\210\301!*\207" [#<buffer  dante:applied-fp-course:exe:level02-exe:/Users/dmvianna/sandbox/applied-fp-course/> #[257 "\302\303\"\210\300\304\305\306#!\210\307\301!\207" [#[257 "\300\242P\300\240\301\304\300\242\"\240\305\302\242!\262\262\207" [("[31;1merror:[0m file 'nixpkgs' was not found in the Nix search path (add it using $NIX_PATH or -I), at [1m/Users/dmvianna/sandbox/applied-fp-course/default.nix[0m:1:20
") (nil) (#[0 "\303\242?\211\203\305\306\307\310\311\312\302\303\304#\313\"\314\315%!\202,\316\302\242\317\320\224SO!\301q\300!\262\262\207" [#[257 "\300\301!\207" [dante-set-state running] 3 "

(fn START-MESSAGES)"] #<buffer Core.hs> ("[31;1merror:[0m file 'nixpkgs' was not found in the Nix search path (add it using $NIX_PATH or -I), at [1m/Users/dmvianna/sandbox/applied-fp-course/default.nix[0m:1:20
") (nil) #6 dante-async-read make-byte-code 257 "\300\242P\300\240\301\304\300\242\"\240\305\302\242!\262\262\207" vconcat vector [dante-ghci-prompt string-match lcr-yield] 7 "

(fn V60)" s-trim-right 0 1] 10]) dante-ghci-prompt string-match lcr-yield] 7 "

(fn V60)"] #<buffer  dante:applied-fp-course:exe:level02-exe:/Users/dmvianna/sandbox/applied-fp-course/> dante-debug inputs s-replace "
" "" dante-schedule-next] 6 "

(fn INPUT)"] #<marker at 1 in  dante:applied-fp-course:exe:level02-exe:/Users/dmvianna/sandbox/applied-fp-course/> lcr-set-local lcr-process-callback nil marker-buffer] 5 "

(fn INPUT)"]

WHAT TO DO NEXT

Verify that the GHCi REPL can be loaded manually, then try to
customize (probably file-locally or directory-locally)
`dante-project-root' and/or `dante-repl-command-line'.  If you
fixed the problem, just kill this buffer, Dante will make a fresh
one and attempt to restart GHCi automatically.

If you do not want Dante will not attempt to restart GHCi, just
leave this buffer around. You can always run `dante-restart' to
make it try again.

pasunboneleve avatar Aug 29 '18 04:08 pasunboneleve

How did you add dante to your emacs? I think I had the same issue with the recommended use-package setup from the README file (https://github.com/jyp/dante#installation). I am now using the code below and it seems to work, my recent key insight was that the flycheck-mode hook has to be enabled before the dante-mode hook:

(use-package dante
  :ensure t
  :after haskell-mode
  :commands 'dante-mode
  :init
  (add-hook 'haskell-mode-hook 'flycheck-mode)
  (add-hook 'haskell-mode-hook 'dante-mode)
  :config
  (flycheck-add-next-checker 'haskell-dante '(warning . haskell-hlint))
  )

Can you test this?

sboehler avatar Aug 29 '18 19:08 sboehler


---

This is the buffer associated with the GHCi session. This buffer
is normally hidden, but the GHCi process ended.

EXTRA TROUBLESHOOTING INFO

Process state change: exited abnormally with code 1

default-directory "/Users/dmvianna/sandbox/applied-fp-course/"
dante-command-line ("nix-shell" "--run" "cabal repl exe:level02-exe --builddir=dist/dante")
dante-state dead
dante-queue (#[257 "r\302\301!\203

pasunboneleve avatar Aug 29 '18 23:08 pasunboneleve

Has new-repl superseded repl? If so I'll switch to that, but my understanding was that "it's not quite ready yet". Now, it should be easy to customize dante-repl-command-line-methods-alist to your liking.

BTW the answer given by @sboehler should work as well. Dante really simply runs the command line that you see, so if it works manually it should work via dante as well.

jyp avatar Sep 01 '18 19:09 jyp

afaik new-repl doesn't support multiple targets, and without a specified target, it defaults to all, which doesn't work.

On Sat, Sep 1, 2018, 3:06 PM Jean-Philippe Bernardy < [email protected]> wrote:

Has new-repl superseded repl? If so I'll switch to that, but my understanding was that "it's not quite ready yet". Now, it should be easy to customize dante-repl-command-line-methods-alist to your liking.

BTW the answer given by @sboehler https://github.com/sboehler should work as well. Dante really simply runs the command line that you see, so if it works manually it should work via dante as well.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/jyp/dante/issues/83#issuecomment-417880669, or mute the thread https://github.com/notifications/unsubscribe-auth/ACNoMSJejKNlSe6iwDoCo3VyQuMRLv3eks5uWtrMgaJpZM4WPB10 .

sboosali avatar Sep 01 '18 19:09 sboosali

@dmvianna the following note might be relevant: #58

themoritz avatar Oct 19 '18 09:10 themoritz

Useless. It works with new-repl and without .dir-locals.el seamlessly. If I just place .dir-locals.el in the directory it simply kills dante. With or without new-repl, and with or without flycheck, and in whatever order. And by the way, I want flycheck to work.

pasunboneleve avatar Oct 19 '18 10:10 pasunboneleve

I made a emacs module which has a feature that returns cabal target based on current buffer . It is not perfect but it works for me at least. I tested it with some of my projects and the applied fp course. It does not need to set .dir-locals.el but the downside is that it requires more memory due to haskell runtime. In order to use below setup, You need to enable emacs dynamic module feature. You can check your emacs build configuration with (print system-configuration-options) in emacs. If you see --with-modules then you are good to go.

Build

git clone https://github.com/templateK/edm-haskell.git
cd edm-haskell
cabal new-build flib:edm-haskell
mkdir -p ~/.emacs.d/native
# in macos
cp $(find . -name "libedm-haskell.dylib" -type f) ~/.emacs.d/native/
# in linux
cp $(find . -name "libedm-haskell.so" -type f) ~/.emacs.d/native/

Emacs dante package configuration

(use-package dante
  :after flycheck
  :init
  (defun dante-dynamic-target ()
    "Return dante-target based on it's cell type."
    ;; check dante-target defined as non-empty string.
    (if (and (boundp 'dante-target)
             dante-target
             (not (numberp dante-target))
             (not (string-empty-p dante-target)))
        dante-target
      ;; otherwise try to get cabal project target through edm-haskell.
      (if-let* ((cabal-file (haskell-cabal-find-file))
                (cabal-target (edm-haskell-cabal-target cabal-file (buffer-file-name))))
          cabal-target
         ;; if all above fails, just return nil or you can change to other default value.
        nil)))
  :config
  ;; emacs must be build with configure option --with-modules
  ;; to see configuration (print system-configuration-options)
  ;; dylib filename must be absolute path otherwise it throws "dlopen: image not found."
  (let ((edm-filename (concat (getenv "HOME") "/.emacs.d/native/libedm-haskell.dylib")))
    (if (and (file-exists-p edm-filename) (file-executable-p edm-filename))
        (progn
          (module-load edm-filename)
          (fset 'dante-target 'dante-dynamic-target)
          (setq-default dante-repl-command-line
                        '("cabal" "new-repl" (dante-target) "--builddir=dist-newstyle/dante")))
      (setq-default dante-repl-command-line '("cabal" "repl" dante-target "--builddir=dist/dante"))))
  (flycheck-add-next-checker 'haskell-dante '(warning . haskell-hlint))
 ) ;; end of dante

Patch dante-buffer-name function in dante.el in order to use edm-haskell

dante.el

@@ -654,7 +654,7 @@
   "Create a dante process buffer name."
   (let* ((root (dante-project-root))
          (package-name (dante-package-name)))
-    (concat "*dante:" package-name ":" dante-target ":" root "*")))
+    (concat "*dante:" package-name ":" (dante-target) ":" root "*")))

After the patch, don't forget to compile dante.el. You can do that with byte-compile-file in emacs.

templateK avatar Oct 19 '18 16:10 templateK

@sboehler You recommend setting dirlocals yet in your repository you have since removed them. What is the way you currently deal with multiple targets? Do you have any recommendations?

cxandru avatar Nov 12 '19 22:11 cxandru

@gregor-alexandru I have stopped using dante in that project.

sboehler avatar Nov 28 '19 08:11 sboehler

@sboehler did you find any replacement for it?

qrilka avatar Nov 28 '19 08:11 qrilka

Not sure if this is still relevant for others. However, in my case, I forgot to add a .ghci file to the project root and seems like I've encounter the same issue (not being able to load the executable target). Adding the following line solved the issue: :set -iapp/. app here is the directory where my executable module lives.

monoidcat avatar Feb 22 '20 01:02 monoidcat

Can multiple-targets work yet? I'd simply like to be able to work on tests and a library simultaneously.

freckletonj avatar Apr 14 '20 01:04 freckletonj

The relevant intero: https://github.com/chrisdone/intero/blob/master/elisp/intero.el#L621

The relevant stack docs: https://docs.haskellstack.org/en/stable/build_command/#target-syntax

I still have no clue how to use dante's targets, and just would like them to work on my tests.

freckletonj avatar Apr 14 '20 02:04 freckletonj

I'm on spacemacs but I did not have trouble getting this to work with .dir-locals.el for sbv's benchmarking suite library.

;; SBVBenchSuite/.dir-locals.el
((nil . ((dante-project-root . "~/Programming/sbv")
         (dante-target . "sbv:SBVBench"))))

I even have another dir-locals.el at the library level:

~/Programming/sbv:master? λ pwd
/home/doyougnu/Programming/sbv

~/Programming/sbv:master? λ ls -a
.               .hlint.yaml    LICENSE               buildUtils            release.nix
..              .travis.yml    Makefile              cabal.project.local   sbv.cabal
.appveyor.yml   CHANGES.md     README.md             cabal.project.local~  shell.nix
.dir-locals.el  COPYRIGHT      SBVBenchSuite         default.nix           
.ghci           Data           SBVTestSuite          dist                  
.git            Documentation  SMTSolverVersions.md  dist-newstyle         
.gitignore      INSTALL        Setup.hs              profile-shell.nix     

doyougnu avatar May 25 '20 17:05 doyougnu

@doyougnu how specifying 1 target makes it work with multiple targets?

qrilka avatar May 25 '20 18:05 qrilka

There are two .dir-locals.el files: one for sbv:SBVBench in the SBVBenchSuite/ directory, and another for just sbv in the project's root directory. So if I open a file in the SBVBenchSuite directory then dante finds the first .dir-locals.el file, namely the one I posted above. However, if I open a file in src then it finds the .dir-locals.el file in the root directory.

This setup is discussed in detail in the emacs manual, you'll want to check out Directory Variables and File Local Variables. This is an example of using directory variables, you could set any of these variables as a local file variable in some Foo.hs file. Here is my project root .dir-locals.el

;; sbv/.dir-locals.el
((nil . ((dante-methods . (nix-ghci)))))

I only set the dante-methods here and let dante use the default sbv target it finds from the project root. If you really had to you could just overwrite dante-repl-command-line to change the entire dante repl call.

doyougnu avatar May 25 '20 19:05 doyougnu

got it working (using dante-repl-command-line on doom emacs):

(use-package dante
  :ensure t
  :after haskell-mode
  :commands 'dante-mode
  :init
  (add-hook 'haskell-mode-hook 'flycheck-mode)
  (add-hook 'haskell-mode-hook 'company-mode)
  (add-hook 'haskell-mode-hook 'dante-mode)
  :config
  (setq-default dante-repl-command-line
                ;; Edit this if you use stack. Also set dante-target as needed (maybe "--test").
                '("cabal" "new-repl" dante-target "--builddir=dist-newstyle/dante"))
  )
;; stand-in-language/src/.dir-locals.el
((nil . ((dante-project-root . "/home/hhefesto/src/stand-in-language/")
         ;; (dante-target . "")
         )))
;; stand-in-language/test/.dir-locals.el
((nil . ((dante-project-root . "/home/hhefesto/src/stand-in-language/")
         (dante-target . "sil:sil-parser-test"))))

hhefesto avatar Jun 18 '20 21:06 hhefesto

Thanks, @hhefesto.

Also if you struggle to get dante working with flycheck and Haskell hlint, as i did, you can add

(use-package dante
  :ensure t
  :after haskell-mode
  :commands 'dante-mode
  :init
  (add-hook 'haskell-mode-hook 'flycheck-mode)
  (add-hook 'haskell-mode-hook 'company-mode)
  (add-hook 'haskell-mode-hook 'dante-mode)
  :config
  (setq-default dante-repl-command-line
                '("cabal" "new-repl" dante-target "--builddir=dist-newstyle/dante"))
  (flycheck-add-next-checker 'haskell-dante '(warning . haskell-hlint))
  )

to your Doom Emacs config.el

malteneuss avatar Dec 20 '20 14:12 malteneuss

I've put more information regarding this in the doc.

jyp avatar Oct 12 '22 19:10 jyp