;;; haskell-customize.el --- Customization settings -*- lexical-binding: t -*- ;; Copyright (c) 2014 Chris Done. All rights reserved. ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Code: (require 'cl-lib) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Customization variables (defcustom haskell-process-load-or-reload-prompt nil "Nil means there will be no prompts on starting REPL. Defaults will be accepted." :type 'boolean :group 'haskell-interactive) ;;;###autoload (defgroup haskell nil "Major mode for editing Haskell programs." :link '(custom-manual "(haskell-mode)") :group 'languages :prefix "haskell-") (defvar haskell-mode-pkg-base-dir (file-name-directory load-file-name) "Package base directory of installed `haskell-mode'. Used for locating additional package data files.") (defcustom haskell-completing-read-function 'ido-completing-read "Default function to use for completion." :group 'haskell :type '(choice (function-item :tag "ido" :value ido-completing-read) (function-item :tag "helm" :value helm--completing-read-default) (function-item :tag "completing-read" :value completing-read) (function :tag "Custom function"))) (defcustom haskell-process-type 'auto "The inferior Haskell process type to use. When set to 'auto (the default), the directory contents and available programs will be used to make a best guess at the process type: If the project directory or one of its parents contains a \"cabal.sandbox.config\" file, then cabal-repl will be used. If there's a \"stack.yaml\" file and the \"stack\" executable can 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)) :group 'haskell-interactive) (defcustom haskell-process-wrapper-function #'identity "Wrap or transform haskell process commands using this function. Can be set to a custom function which takes a list of arguments and returns a possibly-modified list. The following example function arranges for all haskell process commands to be started in the current nix-shell environment: (lambda (argv) (append (list \"nix-shell\" \"-I\" \".\" \"--command\" ) (list (mapconcat 'identity argv \" \")))) See Info Node `(emacs)Directory Variables' for a way to set this option on a per-project basis." :group 'haskell-interactive :type '(choice (function-item :tag "None" :value identity) (function :tag "Custom function"))) (defcustom haskell-ask-also-kill-buffers t "Ask whether to kill all associated buffers when a session process is killed." :type 'boolean :group 'haskell-interactive) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Configuration (defcustom haskell-doc-prettify-types t "Replace some parts of types with Unicode characters like \"∷\" when showing type information about symbols." :group 'haskell-doc :type 'boolean :safe 'booleanp) (defvar haskell-process-ended-functions (list 'haskell-process-prompt-restart) "Hook for when the haskell process ends.") ;;;###autoload (defgroup haskell-interactive nil "Settings for REPL interaction via `haskell-interactive-mode'" :link '(custom-manual "(haskell-mode)haskell-interactive-mode") :group 'haskell) (defcustom haskell-process-path-ghci "ghci" "The path for starting ghci. This can either be a single string or a list of strings, where the first elements is a string and the remaining elements are arguments, which will be prepended to `haskell-process-args-ghci'." :group 'haskell-interactive :type '(choice string (repeat string))) (defcustom haskell-process-path-cabal "cabal" "Path to the `cabal' executable. This can either be a single string or a list of strings, where the first elements is a string and the remaining elements are arguments, which will be prepended to `haskell-process-args-cabal-repl'." :group 'haskell-interactive :type '(choice string (repeat string))) (defcustom haskell-process-path-stack "stack" "The path for starting stack. This can either be a single string or a list of strings, where the first elements is a string and the remaining elements are arguments, which will be prepended to `haskell-process-args-stack-ghci'." :group 'haskell-interactive :type '(choice string (repeat string))) (defcustom haskell-process-args-ghci '("-ferror-spans") "Any arguments for starting ghci." :group 'haskell-interactive :type '(repeat (string :tag "Argument"))) (defcustom haskell-process-args-cabal-repl '("--ghc-option=-ferror-spans") "Additional arguments for `cabal repl' invocation. Note: The settings in `haskell-process-path-ghci' and `haskell-process-args-ghci' are not automatically reused as `cabal repl' currently invokes `ghc --interactive'. Use `--with-ghc=' if you want to use a different interactive GHC frontend; use `--ghc-option=' to pass additional flags to `ghc'." :group 'haskell-interactive :type '(repeat (string :tag "Argument"))) (defcustom haskell-process-args-cabal-new-repl '("--ghc-option=-ferror-spans") "Additional arguments for `cabal new-repl' invocation. Note: The settings in `haskell-process-path-ghci' and `haskell-process-args-ghci' are not automatically reused as `cabal new-repl' currently invokes `ghc --interactive'. Use `--with-ghc=' if you want to use a different interactive GHC frontend; use `--ghc-option=' to pass additional flags to `ghc'." :group 'haskell-interactive :type '(repeat (string :tag "Argument"))) (defcustom haskell-process-args-stack-ghci '("--ghci-options=-ferror-spans" "--no-build" "--no-load") "Additional arguments for `stack ghci' invocation." :group 'haskell-interactive :type '(repeat (string :tag "Argument"))) (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. See `haskell-process-do-cabal' for more details." :group 'haskell-interactive :type 'string) (defcustom haskell-process-log nil "Enable debug logging to \"*haskell-process-log*\" buffer." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-show-debug-tips t "Show debugging tips when starting the process." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-show-overlays t "Show in-buffer overlays for errors/warnings. Flycheck users might like to disable this." :type 'boolean :group 'haskell-interactive) (defcustom haskell-notify-p nil "Notify using notifications.el (if loaded)?" :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-no-warn-orphans t "Suggest adding -fno-warn-orphans pragma to file when getting orphan warnings." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-hoogle-imports nil "Suggest to add import statements using Hoogle as a backend." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-hayoo-imports nil "Suggest to add import statements using Hayoo as a backend." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-hayoo-query-url "http://hayoo.fh-wedel.de/json/?query=%s" "Query url for json hayoo results." :type 'string :group 'haskell-interactive) (defcustom haskell-process-suggest-haskell-docs-imports nil "Suggest to add import statements using haskell-docs as a backend." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-add-package t "Suggest to add packages to your .cabal file when Cabal says it is a member of the hidden package, blah blah." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-language-pragmas t "Suggest adding LANGUAGE pragmas recommended by GHC." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-remove-import-lines nil "Suggest removing import lines as warned by GHC." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-overloaded-strings t "Suggest adding OverloadedStrings pragma to file when getting type mismatches with [Char]." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-check-cabal-config-on-load t "Check changes cabal config on loading Haskell files and restart the GHCi process if changed.." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-prompt-restart-on-cabal-change t "Ask whether to restart the GHCi process when the Cabal file has changed?" :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-auto-import-loaded-modules nil "Auto import the modules reported by GHC to have been loaded?" :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-reload-with-fbytecode nil "When using -fobject-code, auto reload with -fbyte-code (and then restore the -fobject-code) so that all module info and imports become available?" :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-use-presentation-mode nil "Use presentation mode to show things like type info instead of printing to the message area." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-restart t "Suggest restarting the process when it has died" :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-popup-errors t "Popup errors in a separate buffer." :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-mode-collapse nil "Collapse printed results." :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-types-for-show-ambiguous t "Show types when there's no Show instance or there's an ambiguous class constraint." :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-prompt "λ> " "The prompt to use." :type 'string :group 'haskell-interactive) (defcustom haskell-interactive-prompt2 (replace-regexp-in-string "> $" "| " haskell-interactive-prompt) "The multi-line prompt to use. The default is `haskell-interactive-prompt' with the last > replaced with |." :type 'string :group 'haskell-interactive) (defcustom haskell-interactive-mode-eval-mode nil "Use the given mode's font-locking to render some text." :type '(choice function (const :tag "None" nil)) :group 'haskell-interactive) (defcustom haskell-interactive-mode-hide-multi-line-errors nil "Hide collapsible multi-line compile messages by default." :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-mode-delete-superseded-errors t "Whether to delete compile messages superseded by recompile/reloads." :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-mode-include-file-name t "Include the file name of the module being compiled when printing compilation messages." :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-mode-read-only t "Non-nil means most GHCi/haskell-interactive-mode output is read-only. This does not include the prompt. Configure `haskell-interactive-prompt-read-only' to change the prompt's read-only property." :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-prompt-read-only haskell-interactive-mode-read-only "Non-nil means the prompt (and prompt2) is read-only." :type 'boolean :group 'haskell-interactive) (defcustom haskell-import-mapping '() "Support a mapping from module to import lines. E.g. '((\"Data.Map\" . \"import qualified Data.Map as M import Data.Map (Map) \")) This will import import qualified Data.Map as M import Data.Map (Map) when Data.Map is the candidate. " :type '(repeat (cons (string :tag "Module name") (string :tag "Import lines"))) :group 'haskell-interactive) (defcustom haskell-language-extensions '() "Language extensions in use. Should be in format: -XFoo, -XNoFoo etc. The idea is that various tools written with HSE (or any haskell-mode code that needs to be aware of syntactical properties; such as an indentation mode) that don't know what extensions to use can use this variable. Examples: hlint, hindent, structured-haskell-mode, tool-de-jour, etc. You can set this per-project with a .dir-locals.el file" :group 'haskell :type '(repeat 'string)) (defcustom haskell-stylish-on-save nil "Whether to run stylish-haskell on the buffer before saving. If this is true, `haskell-add-import' will not sort or align the imports." :group 'haskell :type 'boolean) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 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. 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) ((executable-find "stack") (setq inferior-haskell-root-dir default-directory) 'stack-ghci) (t (error "Could not find any installation of GHC."))) haskell-process-type))) (provide 'haskell-customize)