Skip to content

inf-haskell #1543

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 124 additions & 45 deletions doc/haskell-mode.texi
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ interpreter (e.g. GHCi).
* Module templates:: Module templates
* Declaration scanning:: How to navigate in a source file
* Compilation:: How to compile
* Inferior Haskell interpreter:: How to interact with GHCi (1)
* Interactive Haskell:: How to interact with GHCi (2)
* Interactive Haskell:: How to interact with GHCi
* Editing Cabal files:: Cabal support
* Browsing Haddocks:: Using @code{w3m} to browse documentation
* Spell checking strings and comments:: Using @code{flyspell-prog-mode}
* Aligning code:: Aligning code using @code{align-regexp}
* Rectangular commands:: Manage indentation manually
* REPL:: GHCi REPL
* Collapsing Haskell code:: View more code on screen
* Getting Help and Reporting Bugs:: How to improve Haskell Mode
* Concept index:: Index of Haskell Mode concepts
Expand Down Expand Up @@ -1148,49 +1148,6 @@ temporarily by invoking @code{haskell-compile} with a prefix argument
same customized compile command, invoke @code{recompile} (bound to
@kbd{g}) inside the @samp{*haskell-compilation*} buffer.

@node Inferior Haskell interpreter
@chapter Inferior Haskell interpreter

@findex inferior-haskell-find-definition
@findex inferior-haskell-find-haddock
@findex inferior-haskell-info
@findex inferior-haskell-load-and-run
@findex inferior-haskell-load-file
@findex inferior-haskell-mode
@findex inferior-haskell-reload-file
@findex inferior-haskell-start-process
@findex inferior-haskell-type
@vindex haskell-program-name
@vindex inferior-haskell-mode-hook

The major mode @code{inferior-haskell-mode} provides support for
interacting with an inferior Haskell process based on
@code{comint-mode}.

By default the @code{haskell-mode-map} keymap is setup to use this mode:

@table @kbd
@item C-c C-z
is bound to @code{switch-to-haskell}
@item C-c C-b
is bound to @code{switch-to-haskell}
@item C-c C-l
is bound to @code{inferior-haskell-load-file}
@item C-c C-t
is bound to @code{inferior-haskell-type}
@item C-c C-i
is bound to @code{inferior-haskell-info}
@end table

The Haskell interpreter used by the inferior Haskell mode is
auto-detected by default, but is customizable via the
@code{haskell-program-name} variable.

Currently, GHCi and Hugs are support as Haskell interpreter.

TODO/WRITEME
@c write about supported features

@node Interactive Haskell
@chapter Interactive Haskell

Expand Down Expand Up @@ -2593,6 +2550,128 @@ This will insert the contents of the last killed rectangle.
As with all Emacs modifier combos, you can type @kbd{C-x r C-h} to find
out what keys are bound beginning with the @kbd{C-x r} prefix.

@node REPL
@chapter Using GHCi REPL within Emacs

To start the REPL you can run one of the following:

@itemize
@item @kbd{M-x run-haskell}
@item @kbd{M-x switch-to-haskell}
@end itemize

This repl works with @uref{https://www.emacswiki.org/emacs/ComintMode, Comint}.
So you will feel at home if you are already using @kbd{M-x Shell} or @kbd{M-x ielm}.

@code{Inf-Haskell} is a Major mode for running GHCi, with comint.

Important key bindings in @code{Inf-haskell}:

@table @kbd
@item RET
invokes @kbd{comint-send-input}. Sends the input to the GHCi process, evaluates
the line and returns the output.

@item C-d or <delete>
deletes the forward character

@item <C-up> or M-p
invokes @kbd{comint-previous-input}. Cycle backwards through input history,
saving input.

@item <C-down> or M-n
invokes @kbd{comint-next-input}. Cycle forwards through input history.

@item C-c C-c
invokes @kbd{comint-interrupt-subjob}. Sends KeyboardInterrupt signal.

@item C-c C-\
invokes @kbd{comint-quit-subjob}. Sends KeyboardInterrupt signal.

@item C-c C-z
invokes @kbd{comint-stop-subjob}. Kills the GHCi process.

@item C-c M-r
invokes @kbd{comint-previous-matching-input-from-input}. If you are familiar
with @kbd{C-r} in bash. This is the same as that. Searches backwards through
input history for match for current input.

@item C-c M-s
invokes @kbd{comint-next-matching-input-from-input}. Searches forwards through
input history for match for current input.

@item C-c C-l
invokes @kbd{comint-dynamic-list-input-ring}. Displays a list of recent inputs
entered into the current buffer.

@item C-c M-o
invokes @kbd{comint-clear-buffer}. Clears the buffer (Only with Emacs 25.X and above)

@item C-c C-n
invokes @kbd{comint-next-prompt}. Goes to the start of the previous REPL prompt.

@item C-c C-p
invokes @kbd{comint-previous-prompt}. Goes to the start of the next REPL prompt.

@item C-c C-o
invokes @kbd{comint-delete-output}. Clears the output of the most recently evaluated
expression.

@item C-c C-e
invokes @kbd{comint-show-maximum-output}. Moves the point to the end of the buffer.

@item C-c C-u
invokes @kbd{comint-kill-input}. Kills backward, the line at point. (Use this when you have typed in an expression into the prompt
but you dont want to evaluate it.)

@item C-c C-w
invokes @kbd{backward-kill-word}. Kills backward, the word at point

@item C-c C-s
invokes @kbd{comint-write-output}. Write output from interpreter since last
input to FILENAME. Any prompt at the end of the output is not written.
@end table

@section Relevant defcustoms:

@multitable @columnfractions .40 .20 .40
@headitem Interpreter (defcustom) @tab Default Value @tab Possible Values
@item @code{haskell-process-type} @tab @code{'auto} @tab @code{'stack-ghci, 'cabal-repl, 'ghci, 'auto}
@item @code{inferior-haskell-hook} @tab @code{nil} @tab -
@item @code{haskell-process-path-ghci} @tab @code{ghci} @tab -
@item @code{haskell-process-args-ghci} @tab @code{-ferror-spans} @tab -
@item @code{haskell-process-path-cabal} @tab @code{cabal} @tab -
@item @code{haskell-process-args-cabal-repl} @tab @code{--ghc-option=-ferror-spans} @tab -
@item @code{haskell-process-path-stack} @tab @code{stack} @tab -
@item @code{haskell-process-args-stack-ghci} @tab @code{--ghci-options=-ferror-spans --no-build --no-load} @tab -
@end multitable

@section More on @code{haskell-process-type}

The Haskell interpreter used by @code{Inf-Haskell} is auto-detected by default,
but is customizable with defcustom @code{haskell-process-type}. The values
recognized by it are (default is 'auto):

@itemize
@item @code{'stack-ghci}
@item @code{'cabal-repl}
@item @code{'ghci}
@item @code{'auto}
@end itemize

if the @code{haskell-process-type} is @code{'auto}, the directories are searched for
@code{cabal.sandbox.config} or @code{stack.yaml} or @code{*.cabal} file.
If the file is present, then appropriate process is started.

When @code{cabal.sandbox.config} is found @code{haskell-process-type} is @code{'cabal-repl}.
Similarly, when @code{stack.yaml} is found @code{haskell-process-type} is @code{'stack-ghci}.
Similarly, when @code{xyz.cabal} is found @code{haskell-process-type} is @code{'cabal-repl}.
When nothing is found @code{haskell-process-type} is @code{'ghci}. When more than one
file such as @code{cabal.sandbox.config} and @code{stack.yaml} are found the following
preference is followed.

@code{cabal.sandbox.config} > @code{stack.yaml} > @code{*.cabal}

@node Collapsing Haskell code
@chapter Collapsing Haskell code

Expand Down
75 changes: 58 additions & 17 deletions haskell-customize.el
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ be located, then stack-ghci will be used.
Otherwise if there's a *.cabal file, cabal-repl will be used.

If none of the above apply, ghci will be used."
:type '(choice (const auto) (const ghci) (const cabal-repl) (const stack-ghci) (const cabal-new-repl))
:type '(choice (const auto)
(const ghci)
(const cabal-repl)
(const stack-ghci)
(const cabal-new-repl))
:group 'haskell-interactive)

(defcustom haskell-process-wrapper-function
Expand Down Expand Up @@ -177,6 +181,22 @@ pass additional flags to `ghc'."
:group 'haskell-interactive
:type '(repeat (string :tag "Argument")))

(defcustom haskell-process-path-ghc
"ghc"
"Path for The Glorious Glasgow Haskell Compiler")

(defcustom haskell-process-args-ghc
"--make -ferror-spans -Wall -fforce-recomp"
"Any arguments for starting ghc.")

(defcustom haskell-process-args-cabal-build
"--ghc-options=\"-ferror-spans -Wall -fforce-recomp\""
"Arguments while doing cabal build.")

(defcustom haskell-process-args-stack-build
"--ghc-options=\"-ferror-spans -Wall\""
"Additional arguments for `stack build' invocation.")

(defcustom haskell-process-do-cabal-format-string
":!cd %s && %s"
"The way to run cabal comands. It takes two arguments -- the directory and the command.
Expand Down Expand Up @@ -415,22 +435,43 @@ imports."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Accessor functions

(defvar inferior-haskell-root-dir nil
"The path which is considered as project root, this is determined by the
presence of a *.cabal file or stack.yaml file or something similar.")

(defun haskell-process-type ()
"Return `haskell-process-type', or a guess if that variable is 'auto."
(if (eq 'auto haskell-process-type)
(cond
;; User has explicitly initialized this project with cabal
((locate-dominating-file default-directory "cabal.sandbox.config")
'cabal-repl)
((and (locate-dominating-file default-directory "stack.yaml")
(executable-find "stack"))
'stack-ghci)
((locate-dominating-file
default-directory
(lambda (d)
(cl-find-if (lambda (f) (string-match-p ".\\.cabal\\'" f)) (directory-files d))))
'cabal-repl)
(t 'ghci))
haskell-process-type))
"Return `haskell-process-type', or a guess if that variable is 'auto.
This function also sets the `inferior-haskell-root-dir'"
(let ((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))))))
(if (eq 'auto haskell-process-type)
(cond
;; User has explicitly initialized this project with cabal
((and cabal-sandbox
(executable-find "cabal"))
(setq inferior-haskell-root-dir cabal-sandbox)
'cabal-repl)
((and stack
(executable-find "stack"))
(setq inferior-haskell-root-dir stack)
'stack-ghci)
((and cabal
(executable-find "cabal"))
(setq inferior-haskell-root-dir cabal)
'cabal-repl)
((executable-find "ghc")
(setq inferior-haskell-root-dir default-directory)
'ghci)
(t
(error "Could not find any installation of GHC.")))
haskell-process-type)))

(provide 'haskell-customize)
8 changes: 8 additions & 0 deletions haskell-doc.el
Original file line number Diff line number Diff line change
Expand Up @@ -1848,6 +1848,14 @@ This function switches to and potentially loads many buffers."
;; return the result
doc ))))

(defun inferior-haskell-kind (sym)
"Find the kind of SYM with `:kind' ghci feature."
(inferior-haskell-get-result (format ":kind %s" sym)))

(defun inferior-haskell-type (sym)
"Find the type of SYM with `:type' ghci feature."
(inferior-haskell-get-result (format ":type (%s)" sym)))

(provide 'haskell-doc)

;;; haskell-doc.el ends here
Loading