diff options
Diffstat (limited to 'configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143')
88 files changed, 23470 insertions, 0 deletions
diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/NEWS b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/NEWS new file mode 100644 index 000000000000..e4d1a9940099 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/NEWS @@ -0,0 +1,600 @@ +Haskell Mode NEWS -*- org -*- + +This file uses Org mode. Some useful (default) key-bindings: + - Use "C-c C-n"/"C-c C-p" to jump to next/prev heading + - Use "<tab>" to expand/collapse nodes + - Use "<backtab>" to cycle visibility of all nodes + - Use "C-c C-o" to open links + +* Changes in 16.1 + +- Require at least Emacs 24.3 + +- Implemented standalone deriving indentation + +- Removed haskell-indentation-ifte-offset + +- Implemented electric characters + +- Added LiquidHaskell annotation highlight + +- Introduced haskell-hasktags-path defcustom + +- Added font lock tests for pattern synonyms + +- Hardcoded haskell-ghc-supported-extensions/options + +- Added multi-line input in haskell-interactive + +- Added haskell-mode-stylish-haskell-path + +- Added Windows CI builds + +- Added syntax highlight to Yesod rules quasi quote + +- Added support for line continuation in #define's + +- Added support unterminated strings in indentation + +- Implemented /italic/ and *bold* for haddock + +- Added significant speedups in font-lock engine + +- Added support for full complexity of backtick syntax + +- Operators at the end or beggining of line force expression continuation in indentation + +- Map haskell-mode-format-imports to C-c C-, to avoid conflict with haskell-indent + +- Improve auto add dependencies in cabal + +- Fix inferior-haskell warning font lock for GHC 8.0 + +* Changes in 13.20 + +- Require at least Emacs 24.1 + +- Honor equals on its own line in data decl + +- Honor equals on separate line after guards + +- Allow haskell-process-path-* to be lists + +- Fontify True/False in cabal mode + +- Align | with = in data declarations + +- Remove haskell-package.el + +- Run stylish-haskell before save + +- Improved lexeme parsing in haskell-lexeme + +- Add haskell-interactive-copy-to-prompt + +- Remove haskell-mode-contextual-space and related var + +- Make haskell-indent-region do nothing + +- Add c2hs mode + +- Improve hasktags handling + +- Move documentation from wiki to haskell-mode manual + +* Changes in 13.18 + +- Removed haskell-bot + +- Implement shallow indentation + +- Removed haskell-simple-indent + +- Removed haskell-indentation show dynamic positions + +- Improved indentation inside multiline strings + +- Implemented font-lock for quasi quoted XML, HTML and JavaScript + +- Added '{type|data} family' to font-lock-keywords-create + +- Started using undercover.el for emacs lisp coverage + +- Added keybinding for `haskell-cabal-visit-file` + +- Added type role to font lock + +- Detect and respect the comma style of a section in cabal files + +* Changes in 13.16 + +- Improved parsing of comma lists in haskell indentation + +- Declared turn-on-haskell-indentation as obsolete + +- Improved QuasiQuote font lock + +- Fixed indentation for Unicode symbols + +- Improved completion engine + +- Added support for interaction with stack ghci + +- Added haskell-forward-sexp + +- Added overlays to haskell load + +- Made use of lexical binding for all emacs lisp sources + +- Improved indentation of guards with commas + +- Made three indentation modes mutually turn each other off + +- Added an additional trigger for pragma suggestions + +- Improved and documented `toggle-scc-at-point` in manual + +* Changes in 13.14 + +- Add official Haskell Mode logo + +- Add auto deploy for html manual + +- Improve presentation mode + +- Font Lock refactoring and improvements + +- Properly delimit operators in prettify mode + +- OPTIONS and LANGUAGE completion using ghci + +- Merge hi2 (haskell-indentation attempt 2) in place of haskell-indentation + +- Prompt to reconfigure when Cabal demands it + +- Fontify pragmas while fontifying comments + +- Operators are fontified + +- Remove all mentions of cabal-dev + +- Merge hsc-mode into haskell-mode + +- Get type information from ghci in interaction-mode + +- Prettify Haskell types in eldoc support + +- Added haskell-hoogle-url + +- Fix w3m-haddock in the case of no local files + +* Changes in 13.12 + +- Added haskell-bot.el + +- Added support for cabal repl build targets + +- Automatically add import lines via Hoogle + +- Automatically add package to cabal file + +- Added w3m-haddock.el + +- Added debugger mode + +- Added preliminary :present support + +- Added haskell-sort-imports + +- Added haskell-complete-module + +- Support if and multi-way if in indentation + +- Add support to generate tags on windows + +- Add haskell-language-extensions variable + +- Improve haskell-simple-indent mode + +- Improve test cases + +* Changes in 13.10 + +- Small fix for haskell-simple-indent: Certain indentation situations + cause valname-string to be nil, which haskell-trim did not handle + gracefully (naturally, since nil != ""). + +- Luke Hoersten's Shnippet merged in under snippets/. + +- haskell-presentation-mode is now a haskell-mode derived mode. + +- Small improvement to haskell-process-do-info (works on constructors + now and underscored names). + +- Add haskell-indent-spaces configuration variable. + +- The command string to run cabal commands is slightly more + configurable. See: C-h f haskell-process-do-cabal-format-string + +* Changes in 13.8 + +See also [[https://github.com/haskell/haskell-mode/compare/v13.07...v13.08][detailed Git history]]. + +- Make `haskell-simple-indent-mode' a proper minor mode with `SInd` as + mode-line lighter + +- Support popular "λ> " prompt in inf-haskell by default + +- Hide internal `*print-haskell-mode*' buffers + (used when `haskell-interactive-mode-eval-mode' is active) + +- Add tab-completion support for haskell-interactive-mode + (requires `:complete' command support in GHCi) + +- Add support to `haskell-process-do-info` to perform `:browse!` query + on module name when called on import statement line + +- `haskell-decl-scan-mode': + - New customize group `haskell-decl-scan' + - New flag `haskell-decl-scan-bindings-as-variables' for controlling + whether to put value bindings into the "Variables" category. + - New flag `haskell-decl-scan-add-to-menubar' for controlling + whether to add "Declarations" menu entry to menu bar. + - New manual section node `(haskell-mode)haskell-decl-scan-mode' + +- Add support for [[http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#lambda-case][LambdaCase]] syntax extension to `haskell-indentation` + +- Change `haskell-indentation-mode' to never jump back a whole line + when pressing DEL. The old behavior can be restored by setting + `haskell-indentation-delete-backward-jump-line' to t + +- New convenience function `haskell-cabal-visit-file' for locating and + visiting most likely `.cabal` file associated with current buffer + +- Add support for [[http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#package-import][PackageImports]] and [[http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#safe-imports-ext][SafeHaskell]] syntax extensions to + `haskell-decl-scan-mode' parser + +- Add `turn-{on,off}-haskell-doc' commands as aliases for the existing + `turn-{on,off}-haskell-doc-mode' commands + +- Add support for "cabal repl" process type to `haskell-interactive-mode' + +- Add new Haskell compilation sub-mode and associated `haskell-compile' + command + +* Changes in 13.7 + +See also [[https://github.com/haskell/haskell-mode/compare/v13.06...v13.07][detailed Git history]]. + +- Convert NEWS (this file) to Org mode style and include NEWS file in + package and add command for visiting NEWS file + (M-x haskell-mode-view-news) + +- Officially drop support for versions prior to Emacs 23 + +- New work-in-progress Info manual for haskell-mode + +- Remove deprecated `haskell-{hugs,ghci}' modules + +- Font-locking changes: + - Remove deprecated `turn-on-haskell-font-lock` function + - Improve font-locking of type-signatures in presence of newlines + - Use `font-lock-preprocessor-face' instead of the previously used + `font-lock-warning-face` for CPP directives + - Use `font-lock-warning-face` instead of the previously used + `font-lock-preprocessor-face` for Git merge conflict annotations. + +- Improvements to `haskell-move-nested' module: + - Add support for operating on active regions + - New interactive commands `haskell-move-nested-{left,right}` which + support numeric prefix arguments for controlling the amount of + shifting to apply. + +- Add `haskell-unicode-input-method.el` to distribution + (enable with `turn-on-haskell-unicode-input-method`) + +- Fix all byte-compilation warnings + +- Build-system: + - For in-place installation, `haskell-site-file.el' is renamed + to `haskell-mode-autoloads.el` + - Auto-generate ELPA compatible README file by extracting header of + haskell-mode.el + - New "make check" target + - Add Travis-CI build jobs for testing byte-compilation with + multiple Emacs versions + +- Reorganize customize settings + - Add new convenience function for browsing all Haskell Mode settings + (M-x haskell-customize) + - Add `:link' keywords pointing to the new Info manual + - Add `:group' keywords to modes to make (M-x customize-mode) work + - Create new customization groups `haskell-interactive' and `inferior-haskell' + to clean up namespace + - Create new customization group `ghc-core` containing the two new + customization variables `ghc-core-program` and `ghc-core-program-args`. + +- Improvements to haskell-interactive-mode + - Add support for deleting compile messages superseded by recompile/reloads + (M-x customize-variable RET haskell-interactive-mode-delete-superseded-errors) + - Fix `C-u M-x haskell-process-do-type` inserting bad signatures + - Integrate with Emacs' `next-error` subsystem + - Add "C-c C-f" binding to REPL keymap for enabling `next-error-follow-minor-mode' + - Add support for `-ferror-spans`-style compile messages + - Add `-ferror-spans` as default for `haskell-process-args-ghci` + - Add optional argument to + `haskell-session-{all,installed,project}-modules' to suppress + session-creation. This is useful for yasnippet usage, see commit + 517fd7e for an example. + - Change default for `haskell-process-path-ghci` to a static "ghci" + - Fix `haskell-interactive-switch` not selecting the REPL window + - Make `*haskell-process-log*` buffer configurable + (controlled via new `haskell-process-log` customize option) + +* Changes in 13.6 + +See also [[https://github.com/haskell/haskell-mode/compare/2_9_1...v13.06][detailed Git history]]. + +- Switch to new versioning scheme + +- Switch to MELPA/Marmalade based packaging + +- Cleanup/refactor build-system + +- Enhance `M-x haskell-version` to report more detailed versioning + information + +- Make haskell-interactive-mode emulate comint/eshell history navigation + (see commit 0e96843 for more details) + +- Improvements to haskell-interactive-mode + - Improve killing/restarting haskell-interactive sessions + - Improve directory prompting and resolution + - Fix redundant-import suggest trigger to support qualified imports + - Detect all abbreviations of an user-inputted ":quit" + - Fix regexps for recent GHC 7.x compiler messages + - Customizable commandline args for GHCi + (M-x customize-variable RET haskell-process-args-ghci) + - New command to load or reload via prefix argument + (M-x haskell-process-load-or-reload) + - Fix haskell-interactive-mode prompt detection + - Add cabal-ghci as supported process mode + - Add a customization option for the visibility of multi-line errors + (M-x customize-variable RET haskell-interactive-mode-hide-multi-line-errors) + +- Add forward declarations to reduce Elisp bytecompile warnings + +- Improvements to `haskell-indentation` + - Add support for the UnicodeSyntax tokens `→`, `←`, and `∷`. + - Indent "=" following data/type/newtype declarations. + - Align "->"/"→" arrows in types under "::"/"∷" + - Make customizable whether "<backspace>" deletes indentation too + (via `haskell-indentation-delete-backward-indentation` and + `haskell-indentation-delete-indentation`) + - Properly indent 'rec' keyword, same as 'mdo' + - Minor optimizations. + +- Add support for "'"-prefixed constructors (-> DataKinds) to font-locking + +- New experimental haskell session menu mode (M-x haskell-menu) + +- Various minor cleanups/fixes/improvements... + +* Changes in 2.9.1 + +See also [[https://github.com/haskell/haskell-mode/compare/2_9_0...2_9_1][detailed Git history]]. + +- Bugfix release adding missing autoload declaration + +* Changes in 2.9.0 + +See also [[https://github.com/haskell/haskell-mode/compare/2_8_0...2_9_0][detailed Git history]]. + +- This is the first release after haskell-mode was migrated to GitHub + +- New experimental `haskell-interactive-mode' module implementing a + new REPL interaction mode for GHCi sessions to eventually replace + the existing "inf-haskell" mode. + +- New `haskell-process-cabal' command for interaction with cabal-install + +- New `haskell-checkers' module + +- Update haskell-cabal-mode font-lock keywords + +- Improve scrolling of hoogle output (haskell-mode.el) + +- Derive `haskell-mode` from `prog-mode` for Emacs 24+ + +- Add new binding for "<backtab>" to haskell-mode's keymap which + unindents current line + +- New modules `haskell-navigate-imports`, `haskell-sort-imports' and + `haskell-align-imports' for operating on module import lines in + Haskell source code + +- Add new binding for "C-c C-." to haskell-mode's keymap to sort and + realign Haskell module imports + +- Add new binding for "C-c i" to haskell-mode's keymap to jump back and + forth from/to the current Haskell module's module import section. + +- New `inferior-haskell-kind' function for querying kind via GHCi's ":kind" + +- New `inferior-haskell-send-decl' for sending declarations to GHCi + (bound to "C-x C-d" by default) + +- Add new `haskell-doc-use-inf-haskell` customization variable + +- Add support for bird-style literate haskell editing and a new + related customization variable + `haskell-indentation-birdtrack-extra-space' + +- Font locking improvements + - Add support for Git's merge annotation + (with `font-lock-preprocessor-face') + - Improve `import', `foreign import' and `foreign export' font + locking + - Add support for `rec', `proc' and `mdo` as keywords + - Make whitespace within `-- |' and `{- |' optional when possible + +- New `haskell-move-nested` module providing utilities for + interactively {in,de}denting nested "hanging" blocks. + +- Add stylish-haskell support + (enable via `haskell-stylish-on-save` customization variable) + +- Add support for generating tags on save + (enable via `haskell-tags-on-save' customization variable) + +- Set sensible dabbrev defaults in haskell-mode + +- Added `SCC` pragma insert/delete commands + (`haskell-mode-insert-scc-at-point` and `haskell-mode-kill-scc-at-point') + +- New experimental `haskell-mode-contextual-space' command + +- And a couple more cleanups/fixes/improvements... + +* Changes in 2.8.0 (since 2.7.0) + +See also [[https://github.com/haskell/haskell-mode/compare/2_7_0...2_8_0][detailed Git history]]. + +- Minimal indentation support for arrow syntax + +- Avoid opening a new inf-haskell window if one is already visible. + Windows on other virtual desktops or iconified frames don't count. + +- Force comint-process-echoes to nil + +- Autolaunch haskell-mode for files starting with #!/usr/bin/runghc + and similar + +- Added minimal major mode for parsing GHC core files, courtesy of Johan Tibell. + There is a corresponding Haskell menu entry. + +- Allow configuration of where-clause indentation; M-x customize-group + haskell-indentation. + +* Changes since 2.6.4 + +- fill-paragraph (M-q) now only affects comments, and correctly + handles Haddock commentary. adaptive-fill-mode is turned off, as it + was interfering. + +- Yet more unicode symbols + +- Better support for unicode encoding of haskell source files + +- mdo correctly indented + +- Indentation fixes, fixes to the fixes, and fixes to the fixes to the + fixes + +- New command: M-x haskell-check, calls (by default) hlint on the + current file. Also bound to C-c C-v. + + You can also use the flymake minor mode with this. + +* Changes since 2.5.1 + +- Parser corrections for haskell-indentation and haskell-decl-scan + +- haskell-indentation: Pressing tab in the rightmost position now + moves to the leftmost, by default with a warning. + +- Typo fix: One haskell-indentation variable had ended up in the + haskell-ntation customize group. + +- haskell-hoogle aliased to hoogle, haskell-hayoo aliased to hayoo + +- Courtesy of Alex Ott: + - Additional unicode symbols for font-lock-symbols: () == /= >= <= !! && || sqrt + - M-x haskell-hayoo search added, opens using browse-url + - Bug-fix for inferior-haskell-type + +- If haskell-indentation errors out, it now fail-safes to inserting + a literal newline or deleting one character, for return and + backspace respectively. + +* Changes since 2.4: + +- haskell-indentation, a new minor mode for indentation. + +* Changes since 2.3: + +- Update license to GPLv3. + +- New derived major mode for .hsc files. + +- Removed the C-c C-r binding to reload a file. You can still call + inferior-haskell-reload-file (and/or bind it to your favorite key, + including C-c C-r) or you can now use C-u C-c C-l. + +- C-c C-d looks up the symbol at point in the Haddock docs. + +- Haddock comments are highlighted with font-lock-doc-face if it exists. + +- Use `tex' rather than `latex' for haskell-literate. + +- inf-haskell.el tries to find the root of the module hierarchy to determine + the root of a project (either by looking for a Cabal file or relying on + the `module' declaration line). If all works well, this will make C-c C-l + automatically switch to the root dir, so that dependencies in other + directories are automatically found. If it doesn't, complain and/or set + inferior-haskell-find-project-root to nil. + +- The new command haskell-hoogle helps you query Hoogle from Emacs. + +* Changes since 2.2: + +- Trivial support for Cabal package description files. + +- Minor bug fixes. + +* Changes since 2.1: + +- There are now commands to find type and info of identifiers by querying an + inferior haskell process. Available under C-c C-t, C-c C-i, and C-c M-. + +- Indentation now looks back further, until a line that has no indentation. + To recover the earlier behavior of stopping at the first empty line + instead, configure haskell-indent-look-past-empty-line. + +- inf-haskell can wait until a file load completes and jump directly to the + first error, like haskell-ghci and haskell-hugs used to do. See the var + inferior-haskell-wait-and-jump. + +* Changes since 2.0: + +- inf-haskell uses ghci if hugs is absent. + +- Fix up some binding conflicts (C-c C-o in haskell-doc) + +- Many (hopefully minor) changes to the indentation. + +- New symbols in haskell-font-lock-symbols-alist. + +* Changes since 1.45: + +- keybindings C-c <char> have been replaced by C-c C-<char> so as not + to collide with minor modes. + +- The following modules are now automatically activated without having to + add anything to haskell-mode-hook: + haskell-font-lock (just turn on global-font-lock-mode). + haskell-decl-scan (just bind `imenu' to some key). + +- In recent Emacsen, haskell-doc hooks into eldoc-mode. + +- haskell-hugs and haskell-ghci are superceded by inf-haskell. + +- Indentation rules have been improved when using layout inside parens/braces. + +- Symbols like -> and \ can be displayed as actual arrows and lambdas. + See haskell-font-lock-symbols. + +- Tweaks to the font-lock settings. Among other things paren-matching + with things like \(x,y) should work correctly now. + +- New maintainer <monnier@gnu.org>. diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/dir b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/dir new file mode 100644 index 000000000000..de046d84b067 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/dir @@ -0,0 +1,18 @@ +This is the file .../info/dir, which contains the +topmost node of the Info hierarchy, called (dir)Top. +The first time you invoke Info you start off looking at this node. + +File: dir, Node: Top This is the top of the INFO tree + + This (the Directory node) gives a menu of major topics. + Typing "q" exits, "?" lists all Info commands, "d" returns here, + "h" gives a primer for first-timers, + "mEmacs<Return>" visits the Emacs manual, etc. + + In Emacs, you can click mouse button 2 on a menu item or cross reference + to select it. + +* Menu: + +Emacs +* Haskell Mode: (haskell-mode). Haskell Development Environment for Emacs(en) diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/ghc-core.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/ghc-core.el new file mode 100644 index 000000000000..34ee781e11c5 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/ghc-core.el @@ -0,0 +1,123 @@ +;;; ghc-core.el --- Syntax highlighting module for GHC Core -*- lexical-binding: t -*- + +;; Copyright (C) 2010 Johan Tibell + +;; Author: Johan Tibell <johan.tibell@gmail.com> + +;; This file is not part of GNU Emacs. + +;; 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 GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; Purpose: +;; +;; To make it easier to read GHC Core output by providing highlighting +;; and removal of commonly ignored annotations. + +;;; Code: +(require 'haskell-mode) +(require 'haskell-font-lock) + +;;;###autoload +(defgroup ghc-core nil + "Major mode for viewing pretty printed GHC Core output." + :link '(custom-manual "(haskell-mode)") + :group 'haskell + :prefix "ghc-core-") + +(defcustom ghc-core-program + "ghc" + "Name of the GHC executable (excluding any arguments)." + :type 'string + :group 'ghc-core) + +(defcustom ghc-core-program-args + '("-O2") + "Additional options to be passed to GHC when generating core output. +GHC (see variable `ghc-core-program') is invoked with the basic +command line options \"-ddump-simpl -c <source-file>\" +followed by the additional options defined here. + +The following `-ddump-simpl` options might be of interest: + + - `-dsuppress-all' + - `-dsuppress-uniques' + - `-dsuppress-idinfo' + - `-dsuppress-module-prefixes' + - `-dsuppress-type-signatures' + - `-dsuppress-type-applications' + - `-dsuppress-coercions' + +See `M-x manual-entry RET ghc' for more details." + :type '(repeat (string :tag "Argument")) + :group 'ghc-core) + +(define-obsolete-variable-alias 'ghc-core-create-options 'ghc-core-program-args + "haskell-mode 13.7") + +(defun ghc-core-clean-region (start end) + "Remove commonly ignored annotations and namespace prefixes +in the region between START and END." + (interactive "r") + (save-restriction + (narrow-to-region start end) + (goto-char (point-min)) + (while (search-forward-regexp "GHC\.[^\.]*\." nil t) + (replace-match "" nil t)) + (goto-char (point-min)) + (while (flush-lines "^ *GblId *$" nil)) + (goto-char (point-min)) + (while (flush-lines "^ *LclId *$" nil)) + (goto-char (point-min)) + (while (flush-lines (concat "^ *\\[\\(?:Arity [0-9]+\\|NoCafRefs\\|" + "Str: DmdType\\|Worker \\)" + "\\([^]]*\\n?\\).*\\] *$") nil)) + (goto-char (point-min)) + (while (search-forward "Main." nil t) (replace-match "" nil t)))) + +(defun ghc-core-clean-buffer () + "Remove commonly ignored annotations and namespace prefixes +in the current buffer." + (interactive) + (ghc-core-clean-region (point-min) (point-max))) + +;;;###autoload +(defun ghc-core-create-core () + "Compile and load the current buffer as tidy core." + (interactive) + (save-buffer) + (let* ((core-buffer (generate-new-buffer "ghc-core")) + (neh (lambda () (kill-buffer core-buffer)))) + (add-hook 'next-error-hook neh) + (apply #'call-process ghc-core-program nil core-buffer nil + "-ddump-simpl" "-c" (buffer-file-name) ghc-core-program-args) + (display-buffer core-buffer) + (with-current-buffer core-buffer + (ghc-core-mode)) + (remove-hook 'next-error-hook neh))) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.hcr\\'" . ghc-core-mode)) +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.dump-simpl\\'" . ghc-core-mode)) + +;;;###autoload +(define-derived-mode ghc-core-mode haskell-mode "GHC-Core" + "Major mode for GHC Core files.") + +(provide 'ghc-core) +;;; ghc-core.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/ghc-core.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/ghc-core.elc new file mode 100644 index 000000000000..e42eb93fffc2 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/ghc-core.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/ghci-script-mode.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/ghci-script-mode.el new file mode 100644 index 000000000000..2ec905cd14ca --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/ghci-script-mode.el @@ -0,0 +1,66 @@ +;;; ghci-script-mode.el --- GHCi scripts major mode -*- 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 <http://www.gnu.org/licenses/>. + +;;; Code: + +(require 'haskell) + +(defvar ghci-script-mode-keywords + ;; The comment syntax can't be described simply in syntax-table. + ;; We could use font-lock-syntactic-keywords, but is it worth it? + '(("^[ \t]*--.*" . font-lock-comment-face) + ("^ *\\([^ \t:]+\\):" (1 font-lock-keyword-face)) + ("^:[a-z{]+ *\\+" . font-lock-keyword-face) + ("^:[a-z{]+ " . font-lock-keyword-face))) + +;;;###autoload +(define-derived-mode ghci-script-mode text-mode "GHCi-Script" + "Major mode for working with .ghci files." + (setq-local adaptive-fill-mode nil) + (setq-local comment-start "-- ") + (setq-local comment-padding 0) + (setq-local comment-start-skip "[-{]-[ \t]*") + (setq-local comment-end "") + (setq-local comment-end-skip "[ \t]*\\(-}\\|\\s>\\)") + (setq-local font-lock-defaults '(ghci-script-mode-keywords t t nil nil)) + (setq-local indent-tabs-mode nil) + (setq-local tab-width 8) + (when (boundp 'electric-indent-inhibit) + (setq electric-indent-inhibit t)) + (setq-local dabbrev-case-fold-search nil) + (setq-local dabbrev-case-distinction nil) + (setq-local dabbrev-case-replace nil) + (setq-local dabbrev-abbrev-char-regexp "\\sw\\|[.]") + (setq haskell-literate nil)) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.ghci\\'" . ghci-script-mode)) + +(define-key ghci-script-mode-map (kbd "C-c C-l") 'ghci-script-mode-load) + +(defun ghci-script-mode-load () + "Load the current script file into the GHCi session." + (interactive) + (let ((buffer (haskell-session-interactive-buffer (haskell-session))) + (filename (buffer-file-name))) + (save-buffer) + (with-current-buffer buffer + (set-marker haskell-interactive-mode-prompt-start (point-max)) + (haskell-interactive-mode-run-expr + (concat ":script " filename))))) + +(provide 'ghci-script-mode) diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/ghci-script-mode.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/ghci-script-mode.elc new file mode 100644 index 000000000000..1359354eb6ce --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/ghci-script-mode.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-align-imports.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-align-imports.el new file mode 100644 index 000000000000..694ee259295b --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-align-imports.el @@ -0,0 +1,231 @@ +;;; haskell-align-imports.el --- Align the import lines in a Haskell file -*- lexical-binding: t -*- + +;; Copyright (C) 2010 Chris Done + +;; Author: Chris Done <chrisdone@gmail.com> + +;; This file is not part of GNU Emacs. + +;; This program 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 of +;; the License, or (at your option) any later version. + +;; This program 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 +;; <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Consider the following imports list: +;; +;; import One +;; import Two as A +;; import qualified Three +;; import qualified Four as PRELUDE +;; import Five (A) +;; import Six (A,B) +;; import qualified Seven (A,B) +;; import "abc" Eight +;; import "abc" Nine as TWO +;; import qualified "abc" Ten +;; import qualified "defg" Eleven as PRELUDE +;; import "barmu" Twelve (A) +;; import "zotconpop" Thirteen (A,B) +;; import qualified "z" Fourteen (A,B) +;; import Fifteen hiding (A) +;; import Sixteen as TWO hiding (A) +;; import qualified Seventeen hiding (A) +;; import qualified Eighteen as PRELUDE hiding (A) +;; import "abc" Nineteen hiding (A) +;; import "abc" Twenty as TWO hiding (A) +;; +;; When haskell-align-imports is run within the same buffer, the +;; import list is transformed to: +;; +;; import "abc" Eight +;; import qualified Eighteen as PRELUDE hiding (A) +;; import qualified "defg" Eleven as PRELUDE +;; import Fifteen hiding (A) +;; import Five (A) +;; import qualified Four as PRELUDE +;; import qualified "z" Fourteen (A,B) +;; import "abc" Nine as TWO +;; import "abc" Nineteen hiding (A) +;; import One +;; import qualified Seven (A,B) +;; import qualified Seventeen hiding (A) +;; import Six (A,B) +;; import Sixteen as TWO hiding (A) +;; import qualified "abc" Ten +;; import "zotconpop" Thirteen (A,B) +;; import qualified Three +;; import "barmu" Twelve (A) +;; import "abc" Twenty as TWO hiding (A) +;; import Two as A +;; +;; If you want everything after module names to be padded out, too, +;; customize `haskell-align-imports-pad-after-name', and you'll get: +;; +;; import One +;; import Two as A +;; import qualified Three +;; import qualified Four as PRELUDE +;; import Five (A) +;; import Six (A,B) +;; import qualified Seven (A,B) +;; import "abc" Eight +;; import "abc" Nine as TWO +;; import qualified "abc" Ten +;; import qualified "defg" Eleven as PRELUDE +;; import "barmu" Twelve (A) +;; import "zotconpop" Thirteen (A,B) +;; import qualified "z" Fourteen (A,B) +;; import Fifteen hiding (A) +;; import Sixteen as TWO hiding (A) +;; import qualified Seventeen hiding (A) +;; import qualified Eighteen as PRELUDE hiding (A) +;; import "abc" Nineteen hiding (A) +;; import "abc" Twenty as TWO hiding (A) + +;;; Code: + +(require 'cl-lib) + +(defvar haskell-align-imports-regexp + (concat "^\\(import[ ]+\\)" + "\\(qualified \\)?" + "[ ]*\\(\"[^\"]*\" \\)?" + "[ ]*\\([A-Za-z0-9_.']+\\)" + "[ ]*\\([ ]*as [A-Z][^ ]*\\)?" + "[ ]*\\((.*)\\)?" + "\\([ ]*hiding (.*)\\)?" + "\\( -- .*\\)?[ ]*$") + "Regex used for matching components of an import.") + +(defcustom haskell-align-imports-pad-after-name + nil + "Pad layout after the module name also." + :type 'boolean + :group 'haskell-interactive) + +;;;###autoload +(defun haskell-align-imports () + "Align all the imports in the buffer." + (interactive) + (when (haskell-align-imports-line-match) + (save-excursion + (goto-char (point-min)) + (let* ((imports (haskell-align-imports-collect)) + (padding (haskell-align-imports-padding imports))) + (mapc (lambda (x) + (goto-char (cdr x)) + (delete-region (point) (line-end-position)) + (insert (haskell-align-imports-chomp + (haskell-align-imports-fill padding (car x))))) + imports)))) + nil) + +(defun haskell-align-imports-line-match () + "Try to match the current line as a regexp." + (let ((line (buffer-substring-no-properties (line-beginning-position) + (line-end-position)))) + (if (string-match "^import " line) + line + nil))) + +(defun haskell-align-imports-collect () + "Collect a list of mark / import statement pairs." + (let ((imports '())) + (while (not (or (equal (point) (point-max)) (haskell-align-imports-after-imports-p))) + (let ((line (haskell-align-imports-line-match-it))) + (when line + (let ((match + (haskell-align-imports-merge-parts + (cl-loop for i from 1 to 8 + collect (haskell-align-imports-chomp (match-string i line)))))) + (setq imports (cons (cons match (line-beginning-position)) + imports))))) + (forward-line)) + imports)) + +(defun haskell-align-imports-merge-parts (l) + "Merge together parts of an import statement that shouldn't be separated." + (let ((parts (apply #'vector l)) + (join (lambda (ls) + (cl-reduce (lambda (a b) + (concat a + (if (and (> (length a) 0) + (> (length b) 0)) + " " + "") + b)) + ls)))) + (if haskell-align-imports-pad-after-name + (list (funcall join (list (aref parts 0) + (aref parts 1) + (aref parts 2))) + (aref parts 3) + (funcall join (list (aref parts 4) + (aref parts 5) + (aref parts 6))) + (aref parts 7)) + (list (funcall join (list (aref parts 0) + (aref parts 1) + (aref parts 2))) + (funcall join (list (aref parts 3) + (aref parts 4) + (aref parts 5) + (aref parts 6) + (aref parts 7))))))) + +(defun haskell-align-imports-chomp (str) + "Chomp leading and tailing whitespace from STR." + (if str + (replace-regexp-in-string "\\(^[[:space:]\n]*\\|[[:space:]\n]*$\\)" "" + str) + "")) + +(defun haskell-align-imports-padding (imports) + "Find the padding for each part of the import statements." + (if (null imports) + imports + (cl-reduce (lambda (a b) (cl-mapcar #'max a b)) + (mapcar (lambda (x) (mapcar #'length (car x))) + imports)))) + +(defun haskell-align-imports-fill (padding line) + "Fill an import line using the padding worked out from all statements." + (mapconcat #'identity + (cl-mapcar (lambda (pad part) + (if (> (length part) 0) + (concat part (make-string (- pad (length part)) ? )) + (make-string pad ? ))) + padding + line) + " ")) + +(defun haskell-align-imports-line-match-it () + "Try to match the current line as a regexp." + (let ((line (buffer-substring-no-properties (line-beginning-position) + (line-end-position)))) + (if (string-match haskell-align-imports-regexp line) + line + nil))) + +(defun haskell-align-imports-after-imports-p () + "Are we after the imports list?" + (save-excursion + (goto-char (line-beginning-position)) + (let ((case-fold-search nil)) + (not (not (search-forward-regexp "\\( = \\|\\<instance\\>\\| :: \\| ∷ \\)" + (line-end-position) t 1)))))) + +(provide 'haskell-align-imports) + +;;; haskell-align-imports.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-align-imports.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-align-imports.elc new file mode 100644 index 000000000000..44947d28803a --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-align-imports.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-c2hs.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-c2hs.el new file mode 100644 index 000000000000..c4cb41ec3759 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-c2hs.el @@ -0,0 +1,207 @@ +;; haskell-c2hs.el --- -*- lexical-binding: t; -*- + +;; Copyright (C) 2016 Sergey Vinokurov +;; +;; Author: Sergey Vinokurov <serg.foo@gmail.com> +;; Created: Monday, 7 March 2016 + +;; This program 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 of the License, or +;; (at your option) any later version. + +;; This program 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: +;; This mode is mostly intended for highlighting {#...#} hooks. +;; +;; Quick setup: +;; (autoload 'haskell-c2hs-mode "haskell-c2hs-mode" nil t) +;; (add-to-list 'auto-mode-alist '("\\.chs\\'" . haskell-c2hs-mode)) +;; + +(require 'haskell-mode) +(require 'haskell-font-lock) +(require 'haskell-utils) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.chs\\'" . haskell-c2hs-mode)) + +(defface haskell-c2hs-hook-pair-face + '((t (:inherit 'font-lock-preprocessor-face))) + "Face for highlighting {#...#} pairs." + :group 'haskell) + +(defface haskell-c2hs-hook-name-face + '((t (:inherit 'font-lock-keyword-face))) + "Face for highlighting c2hs hook names." + :group 'haskell) + +(defvar haskell-c2hs-font-lock-keywords + `((,(eval-when-compile + (let* ((ws '(any ?\s ?\t ?\n ?\r)) + (anychar '(or (not (any ?#)) + (seq "#" + (not (any ?\}))))) + (any-nonquote '(or (not (any ?# ?\")) + (seq "#" + (not (any ?\} ?\"))))) + (cid '(seq (any (?a . ?z) (?A . ?Z) ?_) + (* (any (?a . ?z) (?A . ?Z) (?0 . ?9) ?_)))) + (hsid-type '(seq (? "'") + (any (?A . ?Z)) + (* (any (?a . ?z) (?A . ?Z) (?0 . ?9) ?_ ?')))) + (equals-str-val `(seq (* ,ws) + "=" + (* ,ws) + "\"" + (* ,any-nonquote) + "\""))) + (eval + `(rx + (seq + (group-n 1 "{#") + (* ,ws) + (or (seq (group-n 2 + "import" + (opt (+ ,ws) + "qualified")) + (+ ,ws)) + (seq (group-n 2 + "context") + (opt (+ ,ws) + (group-n 3 + "lib") + ,equals-str-val) + (opt (+ ,ws) + (group-n 4 + "prefix") + ,equals-str-val) + (opt (+ ,ws) + (group-n 5 + "add" + (+ ,ws) + "prefix") + ,equals-str-val)) + (seq (group-n 2 + "type") + (+ ,ws) + ,cid) + (seq (group-n 2 + "sizeof") + (+ ,ws) + ,cid) + (seq (group-n 2 + "enum" + (+ ,ws) + "define") + (+ ,ws) + ,cid) + ;; TODO: vanilla enum fontification is incomplete + (seq (group-n 2 + "enum") + (+ ,ws) + ,cid + (opt (+ ,ws) + (group-n 3 + "as"))) + ;; TODO: fun hook highlighting is incompelete + (seq (group-n 2 + (or "call" + "fun") + (opt (+ ,ws) + "pure") + (opt (+ ,ws) + "unsafe")) + (+ ,ws) + ,cid + (opt (+ ,ws) + (group-n 3 + "as") + (opt (+ ,ws) + (group-n 8 + "^")))) + (group-n 2 + "get") + (group-n 2 + "set") + (seq (group-n 2 + "pointer") + (or (seq (* ,ws) + (group-n 3 "*") + (* ,ws)) + (+ ,ws)) + ,cid + (opt (+ ,ws) + (group-n 4 "as") + (+ ,ws) + ,hsid-type) + (opt (+ ,ws) + (group-n 5 + (or "foreign" + "stable"))) + (opt + (or (seq (+ ,ws) + (group-n 6 + "newtype")) + (seq (* ,ws) + "->" + (* ,ws) + ,hsid-type))) + (opt (+ ,ws) + (group-n 7 + "nocode"))) + (group-n 2 + "class") + (group-n 2 + "alignof") + (group-n 2 + "offsetof") + (seq (group-n 2 + "const") + (+ ,ws) + ,cid) + (seq (group-n 2 + "typedef") + (+ ,ws) + ,cid + (+ ,ws) + ,hsid-type) + (group-n 2 + "nonGNU") + ;; TODO: default hook not implemented + ) + (* ,anychar) + (group-n 9 "#}")))))) + ;; Override highlighting for pairs in order to always distinguish them. + (1 'haskell-c2hs-hook-pair-face t) + (2 'haskell-c2hs-hook-name-face) + ;; Make matches lax, i.e. do not signal error if nothing + ;; matched. + (3 'haskell-c2hs-hook-name-face nil t) + (4 'haskell-c2hs-hook-name-face nil t) + (5 'haskell-c2hs-hook-name-face nil t) + (6 'haskell-c2hs-hook-name-face nil t) + (7 'haskell-c2hs-hook-name-face nil t) + (8 'font-lock-negation-char-face nil t) + ;; Override highlighting for pairs in order to always distinguish them. + (9 'haskell-c2hs-hook-pair-face t)) + ,@(haskell-font-lock-keywords))) + +;;;###autoload +(define-derived-mode haskell-c2hs-mode haskell-mode "C2HS" + "Mode for editing *.chs files of the c2hs haskell tool." + (setq-local font-lock-defaults + (cons 'haskell-c2hs-font-lock-keywords + (cdr font-lock-defaults)))) + + +(provide 'haskell-c2hs) + +;; haskell-c2hs.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-c2hs.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-c2hs.elc new file mode 100644 index 000000000000..20f7e72763d9 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-c2hs.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-cabal.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-cabal.el new file mode 100644 index 000000000000..35dcca6c597a --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-cabal.el @@ -0,0 +1,1178 @@ +;;; haskell-cabal.el --- Support for Cabal packages -*- lexical-binding: t -*- + +;; Copyright © 2007, 2008 Stefan Monnier +;; 2016 Arthur Fayzrakhmanov + +;; Author: Stefan Monnier <monnier@iro.umontreal.ca> + +;; This file is not part of GNU Emacs. + +;; 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 GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; Todo: + +;; - distinguish continued lines from indented lines. +;; - indent-line-function. +;; - outline-minor-mode. + +;;; Code: + +;; (defun haskell-cabal-extract-fields-from-doc () +;; (require 'xml) +;; (let ((section (completing-read +;; "Section: " +;; '("general-fields" "library" "executable" "buildinfo")))) +;; (goto-char (point-min)) +;; (search-forward (concat "<sect3 id=\"" section "\">"))) +;; (let* ((xml (xml-parse-region +;; (progn (search-forward "<variablelist>") (match-beginning 0)) +;; (progn (search-forward "</variablelist>") (point)))) +;; (varlist (cl-remove-if-not 'consp (cl-cddar xml))) +;; (syms (mapcar (lambda (entry) (cl-caddr (assq 'literal (assq 'term entry)))) +;; varlist)) +;; (fields (mapcar (lambda (sym) (substring-no-properties sym 0 -1)) syms))) +;; fields)) + +(require 'cl-lib) +(require 'haskell-utils) + +(defcustom haskell-hasktags-path "hasktags" + "Path to `hasktags' executable." + :group 'haskell + :type 'string) + +(defcustom haskell-hasktags-arguments '("-e" "-x") + "Additional arguments for `hasktags' executable. +By default these are: + +-e - generate ETAGS file +-x - generate additional information in CTAGS file." + :group 'haskell + :type '(list string)) + +(defconst haskell-cabal-general-fields + ;; Extracted with (haskell-cabal-extract-fields-from-doc "general-fields") + '("name" "version" "cabal-version" "license" "license-file" "copyright" + "author" "maintainer" "stability" "homepage" "package-url" "synopsis" + "description" "category" "tested-with" "build-depends" "data-files" + "extra-source-files" "extra-tmp-files")) + +(defconst haskell-cabal-library-fields + ;; Extracted with (haskell-cabal-extract-fields-from-doc "library") + '("exposed-modules")) + +(defconst haskell-cabal-executable-fields + ;; Extracted with (haskell-cabal-extract-fields-from-doc "executable") + '("executable" "main-is")) + +(defconst haskell-cabal-buildinfo-fields + ;; Extracted with (haskell-cabal-extract-fields-from-doc "buildinfo") + '("buildable" "other-modules" "hs-source-dirs" "extensions" "ghc-options" + "ghc-prof-options" "hugs-options" "nhc-options" "includes" + "install-includes" "include-dirs" "c-sources" "extra-libraries" + "extra-lib-dirs" "cc-options" "ld-options" "frameworks")) + +(defvar haskell-cabal-mode-syntax-table + (let ((st (make-syntax-table))) + ;; The comment syntax can't be described simply in syntax-table. + ;; We could use font-lock-syntactic-keywords, but is it worth it? + ;; (modify-syntax-entry ?- ". 12" st) + (modify-syntax-entry ?\n ">" st) + (modify-syntax-entry ?- "w" st) + st)) + +(defvar haskell-cabal-font-lock-keywords + ;; The comment syntax can't be described simply in syntax-table. + ;; We could use font-lock-syntactic-keywords, but is it worth it? + '(("^[ \t]*--.*" . font-lock-comment-face) + ("^ *\\([^ \t:]+\\):" (1 font-lock-keyword-face)) + ("^\\(Library\\)[ \t]*\\({\\|$\\)" (1 font-lock-keyword-face)) + ("^\\(Executable\\|Test-Suite\\|Benchmark\\)[ \t]+\\([^\n \t]*\\)" + (1 font-lock-keyword-face) (2 font-lock-function-name-face)) + ("^\\(Flag\\)[ \t]+\\([^\n \t]*\\)" + (1 font-lock-keyword-face) (2 font-lock-constant-face)) + ("^\\(Source-Repository\\)[ \t]+\\(head\\|this\\)" + (1 font-lock-keyword-face) (2 font-lock-constant-face)) + ("^ *\\(if\\)[ \t]+.*\\({\\|$\\)" (1 font-lock-keyword-face)) + ("^ *\\(}[ \t]*\\)?\\(else\\)[ \t]*\\({\\|$\\)" + (2 font-lock-keyword-face)) + ("\\<\\(?:True\\|False\\)\\>" + (0 font-lock-constant-face)))) + +(defvar haskell-cabal-buffers nil + "List of Cabal buffers.") + +(defun haskell-cabal-buffers-clean (&optional buffer) + "Refresh list of known cabal buffers. + +Check each buffer in variable `haskell-cabal-buffers' and remove +it from list if one of the following conditions are hold: ++ buffer is killed; ++ buffer's mode is not derived from `haskell-cabal-mode'; ++ buffer is a BUFFER (if given)." + (let ((bufs ())) + (dolist (buf haskell-cabal-buffers) + (if (and (buffer-live-p buf) + (not (eq buf buffer)) + (with-current-buffer buf (derived-mode-p 'haskell-cabal-mode))) + (push buf bufs))) + (setq haskell-cabal-buffers bufs))) + +(defun haskell-cabal-unregister-buffer () + "Exclude current buffer from global list of known cabal buffers." + (haskell-cabal-buffers-clean (current-buffer))) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.cabal\\'" . haskell-cabal-mode)) + +(defvar haskell-cabal-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-c C-s") 'haskell-cabal-subsection-arrange-lines) + (define-key map (kbd "C-M-n") 'haskell-cabal-next-section) + (define-key map (kbd "C-M-p") 'haskell-cabal-previous-section) + (define-key map (kbd "M-n") 'haskell-cabal-next-subsection) + (define-key map (kbd "M-p") 'haskell-cabal-previous-subsection) + (define-key map (kbd "C-<down>") 'haskell-cabal-next-subsection) + (define-key map (kbd "C-<up>") 'haskell-cabal-previous-subsection) + (define-key map (kbd "C-c C-f") 'haskell-cabal-find-or-create-source-file) + (define-key map (kbd "M-g l") 'haskell-cabal-goto-library-section) + (define-key map (kbd "M-g e") 'haskell-cabal-goto-executable-section) + (define-key map (kbd "M-g b") 'haskell-cabal-goto-benchmark-section) + (define-key map (kbd "M-g t") 'haskell-cabal-goto-test-suite-section) + map)) + +;;;###autoload +(define-derived-mode haskell-cabal-mode fundamental-mode "Haskell-Cabal" + "Major mode for Cabal package description files." + (setq-local font-lock-defaults + '(haskell-cabal-font-lock-keywords t t nil nil)) + (add-to-list 'haskell-cabal-buffers (current-buffer)) + (add-hook 'change-major-mode-hook 'haskell-cabal-unregister-buffer nil 'local) + (add-hook 'kill-buffer-hook 'haskell-cabal-unregister-buffer nil 'local) + (setq-local comment-start "-- ") + (setq-local comment-start-skip "\\(^[ \t]*\\)--[ \t]*") + (setq-local comment-end "") + (setq-local comment-end-skip "[ \t]*\\(\\s>\\|\n\\)") + (setq-local indent-line-function 'haskell-cabal-indent-line) + (setq indent-tabs-mode nil) + ) + +(make-obsolete 'haskell-cabal-get-setting + 'haskell-cabal--get-field + "March 14, 2016") +(defalias 'haskell-cabal-get-setting 'haskell-cabal--get-field + "Try to read value of field with NAME from current buffer. +Obsolete function. Defined for backward compatibility. Use +`haskell-cabal--get-field' instead.") + +(defun haskell-cabal--get-field (name) + "Try to read value of field with NAME from current buffer." + (save-excursion + (let ((case-fold-search t)) + (goto-char (point-min)) + (when (re-search-forward + (concat "^[ \t]*" (regexp-quote name) + ":[ \t]*\\(.*\\(\n[ \t]+[ \t\n].*\\)*\\)") + nil t) + (let ((val (match-string 1)) + (start 1)) + (when (match-end 2) ;Multiple lines. + ;; The documentation is not very precise about what to do about + ;; the \n and the indentation: are they part of the value or + ;; the encoding? I take the point of view that \n is part of + ;; the value (so that values can span multiple lines as well), + ;; and that only the first char in the indentation is part of + ;; the encoding, the rest is part of the value (otherwise, lines + ;; in the value cannot start with spaces or tabs). + (while (string-match "^[ \t]\\(?:\\.$\\)?" val start) + (setq start (1+ (match-beginning 0))) + (setq val (replace-match "" t t val)))) + val))))) + + +(make-obsolete 'haskell-cabal-guess-setting + 'haskell-cabal-get-field + "March 14, 2016") +(defalias 'haskell-cabal-guess-setting 'haskell-cabal-get-field + "Read the value of field with NAME from project's cabal file. +Obsolete function. Defined for backward compatibility. Use +`haskell-cabal-get-field' instead.") + +;;;###autoload +(defun haskell-cabal-get-field (name) + "Read the value of field with NAME from project's cabal file. +If there is no valid .cabal file to get the setting from (or +there is no corresponding setting with that name in the .cabal +file), then this function returns nil." + (interactive) + (when (and name buffer-file-name) + (let ((cabal-file (haskell-cabal-find-file))) + (when (and cabal-file (file-readable-p cabal-file)) + (with-temp-buffer + (insert-file-contents cabal-file) + (haskell-cabal--get-field name)))))) + +;;;###autoload +(defun haskell-cabal-get-dir (&optional use-defaults) + "Get the Cabal dir for a new project. Various ways of figuring this out, + and indeed just prompting the user. Do them all." + (let* ((file (haskell-cabal-find-file)) + (dir (if file (file-name-directory file) default-directory))) + (if use-defaults + dir + (haskell-utils-read-directory-name + (format "Cabal dir%s: " (if file (format " (guessed from %s)" (file-relative-name file)) "")) + dir)))) + +(defun haskell-cabal-compute-checksum (dir) + "Compute MD5 checksum of package description file in DIR. +Return nil if no Cabal description file could be located via +`haskell-cabal-find-pkg-desc'." + (let ((cabal-file (haskell-cabal-find-pkg-desc dir))) + (when cabal-file + (with-temp-buffer + (insert-file-contents cabal-file) + (md5 (buffer-string)))))) + +(defun haskell-cabal-find-file (&optional dir) + "Search for package description file upwards starting from DIR. +If DIR is nil, `default-directory' is used as starting point for +directory traversal. Upward traversal is aborted if file owner +changes. Uses `haskell-cabal-find-pkg-desc' internally." + (let ((use-dir (or dir default-directory))) + (while (and use-dir (not (file-directory-p use-dir))) + (setq use-dir (file-name-directory (directory-file-name use-dir)))) + (when use-dir + (catch 'found + (let ((user (nth 2 (file-attributes use-dir))) + ;; Abbreviate, so as to stop when we cross ~/. + (root (abbreviate-file-name use-dir))) + ;; traverse current dir up to root as long as file owner doesn't change + (while (and root (equal user (nth 2 (file-attributes root)))) + (let ((cabal-file (haskell-cabal-find-pkg-desc root))) + (when cabal-file + (throw 'found cabal-file))) + + (let ((proot (file-name-directory (directory-file-name root)))) + (if (equal proot root) ;; fix-point reached? + (throw 'found nil) + (setq root proot)))) + nil))))) + +(defun haskell-cabal-find-pkg-desc (dir &optional allow-multiple) + "Find a package description file in the directory DIR. +Returns nil if none or multiple \".cabal\" files were found. If +ALLOW-MULTIPLE is non nil, in case of multiple \".cabal\" files, +a list is returned instead of failing with a nil result." + ;; This is basically a port of Cabal's + ;; Distribution.Simple.Utils.findPackageDesc function + ;; http://hackage.haskell.org/packages/archive/Cabal/1.16.0.3/doc/html/Distribution-Simple-Utils.html + ;; but without the exception throwing. + (let* ((cabal-files + (cl-remove-if 'file-directory-p + (cl-remove-if-not 'file-exists-p + (directory-files dir t ".\\.cabal\\'"))))) + (cond + ((= (length cabal-files) 1) (car cabal-files)) ;; exactly one candidate found + (allow-multiple cabal-files) ;; pass-thru multiple candidates + (t nil)))) + +(defun haskell-cabal-find-dir (&optional dir) + "Like `haskell-cabal-find-file' but returns directory instead. +See `haskell-cabal-find-file' for meaning of DIR argument." + (let ((cabal-file (haskell-cabal-find-file dir))) + (when cabal-file + (file-name-directory cabal-file)))) + +;;;###autoload +(defun haskell-cabal-visit-file (other-window) + "Locate and visit package description file for file visited by current buffer. +This uses `haskell-cabal-find-file' to locate the closest +\".cabal\" file and open it. This command assumes a common Cabal +project structure where the \".cabal\" file is in the top-folder +of the project, and all files related to the project are in or +below the top-folder. If called with non-nil prefix argument +OTHER-WINDOW use `find-file-other-window'." + (interactive "P") + ;; Note: We aren't allowed to rely on haskell-session here (which, + ;; in pathological cases, can have a different .cabal file + ;; associated with the current buffer) + (if buffer-file-name + (let ((cabal-file (haskell-cabal-find-file (file-name-directory buffer-file-name)))) + (if cabal-file + (if other-window + (find-file-other-window cabal-file) + (find-file cabal-file)) + (error "Could not locate \".cabal\" file for %S" buffer-file-name))) + (error "Cannot locate \".cabal\" file for buffers not visiting any file"))) + +(defvar haskell-cabal-commands + '("install" + "update" + "list" + "info" + "upgrade" + "fetch" + "unpack" + "check" + "sdist" + "upload" + "report" + "init" + "configure" + "build" + "copy" + "haddock" + "clean" + "hscolour" + "register" + "test" + "help" + "run")) + +;;;###autoload +(defgroup haskell-cabal nil + "Haskell cabal files" + :group 'haskell +) + +(defconst haskell-cabal-section-header-regexp "^[[:alnum:]]" ) +(defconst haskell-cabal-subsection-header-regexp "^[ \t]*[[:alnum:]]\\w*:") +(defconst haskell-cabal-comment-regexp "^[ \t]*--") +(defconst haskell-cabal-empty-regexp "^[ \t]*$") +(defconst haskell-cabal-conditional-regexp "^[ \t]*\\(\\if\\|else\\|}\\)") + +(defun haskell-cabal-classify-line () + "Classify the current line into 'section-header 'subsection-header 'section-data 'comment and 'empty '" + (save-excursion + (beginning-of-line) + (cond + ((looking-at haskell-cabal-subsection-header-regexp ) 'subsection-header) + ((looking-at haskell-cabal-section-header-regexp) 'section-header) + ((looking-at haskell-cabal-comment-regexp) 'comment) + ((looking-at haskell-cabal-empty-regexp ) 'empty) + ((looking-at haskell-cabal-conditional-regexp ) 'conditional) + (t 'section-data)))) + +(defun haskell-cabal-header-p () + "Is the current line a section or subsection header?" + (cl-case (haskell-cabal-classify-line) + ((section-header subsection-header) t))) + +(defun haskell-cabal-section-header-p () + "Is the current line a section or subsection header?" + (cl-case (haskell-cabal-classify-line) + ((section-header) t))) + + +(defun haskell-cabal-section-beginning () + "Find the beginning of the current section" + (save-excursion + (while (not (or (bobp) (haskell-cabal-section-header-p))) + (forward-line -1)) + (point))) + +(defun haskell-cabal-beginning-of-section () + "go to the beginning of the section" + (interactive) + (goto-char (haskell-cabal-section-beginning)) +) + +(defun haskell-cabal-section-end () + "Find the end of the current section" + (interactive) + (save-excursion + (if (re-search-forward "\n\\([ \t]*\n\\)*[[:alnum:]]" nil t) + (match-beginning 0) + (point-max)))) + +(defun haskell-cabal-end-of-section () + "go to the end of the section" + (interactive) + (goto-char (haskell-cabal-section-end))) + +(defun haskell-cabal-next-section () + "Go to the next section" + (interactive) + (when (haskell-cabal-section-header-p) (forward-line)) + (while (not (or (eobp) (haskell-cabal-section-header-p))) + (forward-line))) + +(defun haskell-cabal-previous-section () + "Go to the next section" + (interactive) + (when (haskell-cabal-section-header-p) (forward-line -1)) + (while (not (or (bobp) (haskell-cabal-section-header-p))) + (forward-line -1))) + +(defun haskell-cabal-subsection-end () + "find the end of the current subsection" + (save-excursion + (haskell-cabal-beginning-of-subsection) + (forward-line) + (while (and (not (eobp)) + (member (haskell-cabal-classify-line) '(empty section-data))) + (forward-line)) + (unless (eobp) (forward-line -1)) + (while (and (equal (haskell-cabal-classify-line) 'empty) + (not (bobp))) + (forward-line -1)) + (end-of-line) + (point))) + +(defun haskell-cabal-end-of-subsection () + "go to the end of the current subsection" + (interactive) + (goto-char (haskell-cabal-subsection-end))) + +(defun haskell-cabal-section () + "Get the name and data of the associated section" + (save-excursion + (haskell-cabal-beginning-of-section) + (when (and (haskell-cabal-section-header-p) + (looking-at "^\\(\\w+\\)[ \t]*\\(.*\\)$")) + (list :name (match-string-no-properties 1) + :value (match-string-no-properties 2) + :beginning (match-beginning 0) + :end (haskell-cabal-section-end))))) + + +(defun haskell-cabal-subsection () + "Get the name and bounds of of the current subsection" + (save-excursion + (haskell-cabal-beginning-of-subsection) + (when (looking-at "\\([ \t]*\\(\\w*\\):\\)[ \t]*") + (list :name (match-string-no-properties 2) + :beginning (match-end 0) + :end (save-match-data (haskell-cabal-subsection-end)) + :data-start-column (save-excursion (goto-char (match-end 0)) + (current-column) + ))))) + + +(defun haskell-cabal-section-name (section) + (plist-get section :name)) + +(defun haskell-cabal-section-value (section) + (plist-get section :value)) + +(defun haskell-cabal-section-start (section) + (plist-get section :beginning)) + +(defun haskell-cabal-section-data-start-column (section) + (plist-get section :data-start-column)) + +(defun haskell-cabal-map-component-type (component-type) + "Map from cabal file COMPONENT-TYPE to build command component-type." + (let ((component-type (downcase component-type))) + (cond ((equal component-type "executable") "exe") + ((equal component-type "test-suite") "test") + ((equal component-type "benchmark") "bench")))) + +(defun haskell-cabal-enum-targets (&optional process-type) + "Enumerate .cabal targets. PROCESS-TYPE determines the format of the returned target." + (let ((cabal-file (haskell-cabal-find-file)) + (process-type (if process-type process-type 'ghci))) + (when (and cabal-file (file-readable-p cabal-file)) + (with-temp-buffer + (insert-file-contents cabal-file) + (haskell-cabal-mode) + (goto-char (point-min)) + (let ((matches) + (package-name (haskell-cabal--get-field "name"))) + (haskell-cabal-next-section) + (while (not (eobp)) + (if (haskell-cabal-source-section-p (haskell-cabal-section)) + (let* ((section (haskell-cabal-section)) + (component-type (haskell-cabal-section-name section)) + (val (car (split-string + (haskell-cabal-section-value section))))) + (if (equal (downcase component-type) "library") + (let ((lib-target (if (eq 'stack-ghci process-type) + (concat package-name ":lib") + (concat "lib:" package-name)))) + (push lib-target matches)) + (push (concat (when (eq 'stack-ghci process-type) + (concat package-name ":")) + (haskell-cabal-map-component-type component-type) + ":" + val) + matches)))) + (haskell-cabal-next-section)) + (reverse matches)))))) + +(defmacro haskell-cabal-with-subsection (subsection replace &rest funs) + "Copy subsection data into a temporary buffer, save indentation +and execute FORMS + +If REPLACE is non-nil the subsection data is replaced with the +resulting buffer-content" + (let ((section (make-symbol "section")) + (beg (make-symbol "beg")) + (end (make-symbol "end")) + (start-col (make-symbol "start-col")) + (section-data (make-symbol "section-data"))) + `(let* ((,section ,subsection) + (,beg (plist-get ,section :beginning)) + (,end (plist-get ,section :end)) + (,start-col (plist-get ,section :data-start-column)) + (,section-data (buffer-substring ,beg ,end))) + (save-excursion + (prog1 + (with-temp-buffer + (setq indent-tabs-mode nil) + (indent-to ,start-col) + (insert ,section-data) + (goto-char (point-min)) + (prog1 + (progn (haskell-cabal-save-indentation ,@funs)) + (goto-char (point-min)) + (when (looking-at (format "[ ]\\{0,%d\\}" (1+ ,start-col))) + (replace-match "")) + + (setq ,section-data (buffer-substring (point-min) (point-max))))) + ,@(when replace + `((delete-region ,beg ,end) + (goto-char ,beg) + (insert ,section-data)))))))) + +(defmacro haskell-cabal-each-line (&rest fun) + "Execute FORMS on each line" + `(save-excursion + (while (< (point) (point-max)) + ,@fun + (forward-line)))) + +(defun haskell-cabal-chomp-line () + "Remove leading and trailing whitespaces from current line" + (beginning-of-line) + (when (looking-at "^[ \t]*\\([^ \t]\\|\\(?:[^ \t].*[^ \t]\\)\\)[ \t]*$") + (replace-match (match-string 1) nil t) + t)) + + +(defun haskell-cabal-min-indentation (&optional beg end) + "Compute largest common whitespace prefix of each line in between BEG and END" + (save-excursion + (goto-char (or beg (point-min))) + (let ((min-indent nil)) + (while (< (point) (or end (point-max))) + (let ((indent (current-indentation))) + (if (and (not (haskell-cabal-ignore-line-p)) + (or (not min-indent) + (< indent min-indent))) + (setq min-indent indent))) + (forward-line)) + min-indent))) + +(defun haskell-cabal-ignore-line-p () + "Does line only contain whitespaces and comments?" + (save-excursion + (beginning-of-line) + (looking-at "^[ \t]*\\(?:--.*\\)?$"))) + +(defun haskell-cabal-kill-indentation () + "Remove longest common whitespace prefix from each line" + (goto-char (point-min)) + (let ((indent (haskell-cabal-min-indentation))) + (haskell-cabal-each-line (unless (haskell-cabal-ignore-line-p) + (delete-char indent)) ) + indent)) + +(defun haskell-cabal-add-indentation (indent) + (goto-char (point-min)) + (haskell-cabal-each-line + (unless (haskell-cabal-ignore-line-p) + (indent-to indent)))) + + +(defmacro haskell-cabal-save-indentation (&rest funs) + "Strip indentation from each line, execute FORMS and reinstate indentation + so that the indentation of the FIRST LINE matches" + (let ((old-l1-indent (make-symbol "new-l1-indent")) + (new-l1-indent (make-symbol "old-l1-indent"))) + `(let ( (,old-l1-indent (save-excursion + (goto-char (point-min)) + (current-indentation)))) + (unwind-protect + (progn + (haskell-cabal-kill-indentation) + ,@funs) + (progn + (goto-char (point-min)) + (let ((,new-l1-indent (current-indentation))) + (haskell-cabal-add-indentation (- ,old-l1-indent + ,new-l1-indent)))))))) + +(defun haskell-cabal-comma-separatorp (pos) + "Return non-nil when the char at POS is a comma separator. +Characters that are not a comma, or commas inside a commment or +string, are not comma separators." + (when (eq (char-after pos) ?,) + (let ((ss (syntax-ppss pos))) + (not + (or + ;; inside a string + (nth 3 ss) + ;; inside a comment + (nth 4 ss)))))) + +(defun haskell-cabal-strip-list-and-detect-style () + "Strip commas from a comma-separated list. +Detect and return the comma style. The possible options are: + +before: a comma at the start of each line (except the first), e.g. + Foo + , Bar + +after: a comma at the end of each line (except the last), e.g. + Foo, + Bar + +single: everything on a single line, but comma-separated, e.g. + Foo, Bar + +nil: no commas, e.g. + Foo Bar + +If the styles are mixed, the position of the first comma +determines the style. If there is only one element then `after' +style is assumed." + (let (comma-style) + ;; split list items on single line + (goto-char (point-min)) + (while (re-search-forward + "\\([^ \t,\n]\\)[ \t]*\\(,\\)[ \t]*\\([^ \t,\n]\\)" nil t) + (when (haskell-cabal-comma-separatorp (match-beginning 2)) + (setq comma-style 'single) + (replace-match "\\1\n\\3" nil nil))) + ;; remove commas before + (goto-char (point-min)) + (while (re-search-forward "^\\([ \t]*\\),\\([ \t]*\\)" nil t) + (setq comma-style 'before) + (replace-match "" nil nil)) + ;; remove trailing commas + (goto-char (point-min)) + (while (re-search-forward ",[ \t]*$" nil t) + (unless (eq comma-style 'before) + (setq comma-style 'after)) + (replace-match "" nil nil)) + + ;; if there is just one line then set default as 'after + (unless comma-style + (goto-char (point-min)) + (forward-line) + (when (eobp) + (setq comma-style 'after))) + (goto-char (point-min)) + + (haskell-cabal-each-line (haskell-cabal-chomp-line)) + comma-style)) + +(defun haskell-cabal-listify (comma-style) + "Add commas so that the buffer contains a comma-separated list. +Respect the COMMA-STYLE, see +`haskell-cabal-strip-list-and-detect-style' for the possible +styles." + (cl-case comma-style + ('before + (goto-char (point-min)) + (while (haskell-cabal-ignore-line-p) (forward-line)) + (indent-to 2) + (forward-line) + (haskell-cabal-each-line + (unless (haskell-cabal-ignore-line-p) + (insert ", ")))) + ('after + (goto-char (point-max)) + (while (equal 0 (forward-line -1)) + (unless (haskell-cabal-ignore-line-p) + (end-of-line) + (insert ",") + (beginning-of-line)))) + ('single + (goto-char (point-min)) + (while (not (eobp)) + (end-of-line) + (unless (eobp) + (insert ", ") + (delete-char 1) + (just-one-space)))))) + +(defmacro haskell-cabal-with-cs-list (&rest funs) + "Format the buffer so that each line contains a list element. +Respect the comma style." + (let ((comma-style (make-symbol "comma-style"))) + `(let ((,comma-style + (save-excursion + (haskell-cabal-strip-list-and-detect-style)))) + (unwind-protect (progn ,@funs) + (haskell-cabal-listify ,comma-style))))) + + +(defun haskell-cabal-sort-lines-key-fun () + (when (looking-at "[ \t]*--[ \t,]*") + (goto-char (match-end 0))) + nil) + +(defmacro haskell-cabal-save-position (&rest forms) + "Save position as mark, execute FORMs and go back to mark" + `(prog2 + (haskell-cabal-mark) + (progn ,@forms) + (haskell-cabal-goto-mark) + (haskell-cabal-remove-mark))) + +(defun haskell-cabal-sort-lines-depends-compare (key1 key2) + (let* ((key1str (buffer-substring (car key1) (cdr key1))) + (key2str (buffer-substring (car key2) (cdr key2))) + (base-regex "^[ \t]*base\\($\\|[^[:alnum:]-]\\)")) + (cond + ((string-match base-regex key1str) t) + ((string-match base-regex key2str) nil) + (t (string< key1str key2str))))) + +(defun haskell-cabal-subsection-arrange-lines () + "Sort lines of current subsection" + (interactive) + (haskell-cabal-save-position + (let* ((subsection (haskell-cabal-section-name (haskell-cabal-subsection))) + (compare-lines (if (string= (downcase subsection) "build-depends") + 'haskell-cabal-sort-lines-depends-compare + nil))) + (haskell-cabal-with-subsection + (haskell-cabal-subsection) t + (haskell-cabal-with-cs-list + (sort-subr nil 'forward-line 'end-of-line + 'haskell-cabal-sort-lines-key-fun + 'end-of-line + compare-lines + )))))) + +(defun haskell-cabal-subsection-beginning () + "find the beginning of the current subsection" + (save-excursion + (while (and (not (bobp)) + (not (haskell-cabal-header-p))) + (forward-line -1)) + (back-to-indentation) + (point))) + +(defun haskell-cabal-beginning-of-subsection () + "go to the beginning of the current subsection" + (interactive) + (goto-char (haskell-cabal-subsection-beginning))) + +(defun haskell-cabal-next-subsection () + "go to the next subsection" + (interactive) + (if (haskell-cabal-header-p) (forward-line)) + (while (and (not (eobp)) + (not (haskell-cabal-header-p))) + (forward-line)) + (haskell-cabal-forward-to-line-entry)) + +(defun haskell-cabal-previous-subsection () + "go to the previous subsection" + (interactive) + (if (haskell-cabal-header-p) (forward-line -1)) + (while (and (not (bobp)) + (not (haskell-cabal-header-p))) + (forward-line -1)) + (haskell-cabal-forward-to-line-entry) + ) + + +(defun haskell-cabal-find-subsection-by (section pred) + "Find subsection with name NAME" + (save-excursion + (when section (goto-char (haskell-cabal-section-start section))) + (let* ((end (if section (haskell-cabal-section-end) (point-max))) + (found nil)) + (while (and (< (point) end) + (not found)) + (let ((subsection (haskell-cabal-subsection))) + (when (and subsection (funcall pred subsection)) + (setq found subsection))) + (haskell-cabal-next-subsection)) + found))) + +(defun haskell-cabal-find-subsection (section name) + "Find subsection with name NAME" + (let ((downcase-name (downcase name))) + (haskell-cabal-find-subsection-by + section + `(lambda (subsection) + (string= (downcase (haskell-cabal-section-name subsection)) + ,downcase-name))))) + +(defun haskell-cabal-goto-subsection (name) + (let ((subsection (haskell-cabal-find-subsection (haskell-cabal-section) name))) + (when subsection + (goto-char (haskell-cabal-section-start subsection))))) + +(defun haskell-cabal-goto-exposed-modules () + (interactive) + (haskell-cabal-goto-subsection "exposed-modules")) + +(defun haskell-cabal-subsection-entry-list (section name) + "Get the data of a subsection as a list" + (let ((subsection (haskell-cabal-find-subsection section name))) + (when subsection + (haskell-cabal-with-subsection + subsection nil + (haskell-cabal-with-cs-list + (delete-matching-lines + (format "\\(?:%s\\)\\|\\(?:%s\\)" + haskell-cabal-comment-regexp + haskell-cabal-empty-regexp) + (point-min) (point-max)) + (split-string (buffer-substring-no-properties (point-min) (point-max)) + "\n" t)))))) + +(defun haskell-cabal-remove-mark () + (remove-list-of-text-properties (point-min) (point-max) + '(haskell-cabal-marker))) + + +(defun haskell-cabal-mark () + "Mark the current position with the text property haskell-cabal-marker" + (haskell-cabal-remove-mark) + (put-text-property (line-beginning-position) (line-end-position) + 'haskell-cabal-marker 'marked-line) + (put-text-property (point) (1+ (point)) + 'haskell-cabal-marker 'marked)) + + +(defun haskell-cabal-goto-mark () + "Go to marked line" + (let ((marked-pos (text-property-any (point-min) (point-max) + 'haskell-cabal-marker + 'marked)) + (marked-line (text-property-any (point-min) (point-max) + 'haskell-cabal-marker + 'marked-line) ) + ) + (cond (marked-pos (goto-char marked-pos)) + (marked-line (goto-char marked-line))))) + +(defmacro haskell-cabal-with-subsection-line (replace &rest forms) + "Mark line, copy subsection data into a temporary buffer, save indentation +and execute FORMS at the marked line. + +If REPLACE is non-nil the subsection data is replaced with the +resulting buffer-content. Unmark line at the end." + `(progn + (haskell-cabal-mark) + (unwind-protect + (haskell-cabal-with-subsection (haskell-cabal-subsection) ,replace + (haskell-cabal-goto-mark) + ,@forms) + (haskell-cabal-remove-mark)))) + + +(defun haskell-cabal-get-line-content () + (haskell-cabal-with-subsection-line + nil + (haskell-cabal-with-cs-list + (haskell-cabal-goto-mark) + (buffer-substring-no-properties (line-beginning-position) + (line-end-position))))) + +(defun haskell-cabal-module-to-filename (module) + (concat (replace-regexp-in-string "[.]" "/" module ) ".hs")) + +(defconst haskell-cabal-module-sections '("exposed-modules" "other-modules") + "List of sections that contain module names" +) + +(defconst haskell-cabal-file-sections + '("main-is" "c-sources" "data-files" "extra-source-files" + "extra-doc-files" "extra-tmp-files" ) + "List of subsections that contain filenames" + ) + +(defconst haskell-cabal-source-bearing-sections + '("library" "executable" "test-suite" "benchmark")) + +(defun haskell-cabal-source-section-p (section) + (not (not (member (downcase (haskell-cabal-section-name section)) + haskell-cabal-source-bearing-sections)))) + +(defun haskell-cabal-line-filename () + "Expand filename in current line according to the subsection type + +Module names in exposed-modules and other-modules are expanded by replacing each dot (.) in the module name with a foward slash (/) and appending \".hs\" + +Example: Foo.Bar.Quux ==> Foo/Bar/Quux.hs + +Source names from main-is and c-sources sections are left untouched + +" + (let ((entry (haskell-cabal-get-line-content)) + (subsection (downcase (haskell-cabal-section-name + (haskell-cabal-subsection))))) + (cond ((member subsection haskell-cabal-module-sections) + (haskell-cabal-module-to-filename entry)) + ((member subsection haskell-cabal-file-sections) entry)))) + +(defun haskell-cabal-join-paths (&rest args) + "Crude hack to replace f-join" + (mapconcat 'identity args "/") +) + +(defun haskell-cabal-find-or-create-source-file () + "Open the source file this line refers to." + (interactive) + (let* ((src-dirs (append (haskell-cabal-subsection-entry-list + (haskell-cabal-section) "hs-source-dirs") + '(""))) + (base-dir (file-name-directory (buffer-file-name))) + (filename (haskell-cabal-line-filename))) + (when filename + (let ((candidates + (delq nil (mapcar + (lambda (dir) + (let ((file (haskell-cabal-join-paths base-dir + dir + filename))) + (when (and (file-readable-p file) + (not (file-directory-p file))) + file))) + src-dirs)))) + (if (null candidates) + (unwind-protect + (progn + (haskell-mode-toggle-interactive-prompt-state) + (let* ((src-dir + (haskell-cabal-join-paths base-dir + (or (car src-dirs) ""))) + (newfile (haskell-cabal-join-paths src-dir filename)) + (do-create-p (y-or-n-p (format "Create file %s ?" newfile)))) + (when do-create-p + (find-file-other-window newfile )))) + (haskell-mode-toggle-interactive-prompt-state t)) + (find-file-other-window (car candidates))))))) + + +(defun haskell-cabal-find-section-type (type &optional wrap) + (save-excursion + (haskell-cabal-next-section) + (while + (not + (or + (eobp) + (string= + (downcase type) + (downcase (haskell-cabal-section-name (haskell-cabal-section)))))) + (haskell-cabal-next-section)) + (if (eobp) + (if wrap (progn + (goto-char (point-min)) + (haskell-cabal-find-section-type type nil) ) + nil) + (point)))) + +(defun haskell-cabal-goto-section-type (type) + (let ((section (haskell-cabal-find-section-type type t))) + (if section (goto-char section) + (message "No %s section found" type)))) + +(defun haskell-cabal-goto-library-section () + (interactive) + (haskell-cabal-goto-section-type "library")) + +(defun haskell-cabal-goto-test-suite-section () + (interactive) + (haskell-cabal-goto-section-type "test-suite")) + +(defun haskell-cabal-goto-executable-section () + (interactive) + (haskell-cabal-goto-section-type "executable")) + +(defun haskell-cabal-goto-benchmark-section () + (interactive) + (haskell-cabal-goto-section-type "benchmark")) + + + +(defun haskell-cabal-line-entry-column () + "Column at which the line entry starts" + (save-excursion + (cl-case (haskell-cabal-classify-line) + (section-data (beginning-of-line) + (when (looking-at "[ ]*\\(?:,[ ]*\\)?") + (goto-char (match-end 0)) + (current-column))) + (subsection-header + (haskell-cabal-section-data-start-column (haskell-cabal-subsection)))))) + +(defun haskell-cabal-forward-to-line-entry () + "go forward to the beginning of the line entry (but never move backwards)" + (let ((col (haskell-cabal-line-entry-column))) + (when (and col (< (current-column) col)) + (beginning-of-line) + (forward-char col)))) + +(defun haskell-cabal-indent-line () + "Indent current line according to subsection" + (interactive) + (cl-case (haskell-cabal-classify-line) + (section-data + (save-excursion + (let ((indent (haskell-cabal-section-data-start-column + (haskell-cabal-subsection)))) + (indent-line-to indent) + (beginning-of-line) + (when (looking-at "[ ]*\\([ ]\\{2\\},[ ]*\\)") + (replace-match ", " t t nil 1))))) + (empty + (indent-relative))) + (haskell-cabal-forward-to-line-entry)) + +(defun haskell-cabal-map-sections (fun) + "Execute fun over each section, collecting the result" + (save-excursion + (goto-char (point-min)) + (let ((results nil)) + (while (not (eobp)) + (let* ((section (haskell-cabal-section)) + (result (and section (funcall fun (haskell-cabal-section))))) + (when section (setq results (cons result results)))) + (haskell-cabal-next-section)) + (nreverse results)))) + +(defun haskell-cabal-section-add-build-dependency (dependency &optional sort sec) + "Add a build dependency to the build-depends section" + (let* ((section (or sec (haskell-cabal-section))) + (subsection (and section + (haskell-cabal-find-subsection section "build-depends")))) + (when subsection + (haskell-cabal-with-subsection + subsection t + (haskell-cabal-with-cs-list + (insert dependency) + (insert "\n") + (when sort + (goto-char (point-min)) + (sort-subr nil 'forward-line 'end-of-line + 'haskell-cabal-sort-lines-key-fun))))))) + +(defun haskell-cabal-add-build-dependency (dependency &optional sort silent) + "Add the given DEPENDENCY to every section in cabal file. +If SORT argument is given sort dependencies in section after update. +Pass SILENT argument to update all sections without asking user." + (haskell-cabal-map-sections + (lambda (section) + (when (haskell-cabal-source-section-p section) + (unwind-protect + (progn + (when + (or silent + (y-or-n-p (format "Add dependency %s to %s section %s?" + dependency + (haskell-cabal-section-name section) + (haskell-cabal-section-value section)))) + (haskell-cabal-section-add-build-dependency dependency + sort + section)) + nil) + (haskell-mode-toggle-interactive-prompt-state t)))))) + +(defun haskell-cabal-add-dependency + (package &optional version no-prompt sort silent) + "Add PACKAGE to the cabal file. +If VERSION is non-nil it will be appended as a minimum version. +If NO-PROMPT is nil the minimum package version is read from the +minibuffer. When SORT is non-nil the package entries are sorted +afterwards. If SILENT is non-nil the user is prompted for each +source-section." + (interactive + (list (read-from-minibuffer "Package entry: ") nil t t nil)) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (save-window-excursion + (find-file-other-window (haskell-cabal-find-file)) + (let ((entry (if no-prompt package + (read-from-minibuffer + "Package entry: " + (concat package + (if version (concat " >= " version) "")))))) + (haskell-cabal-add-build-dependency entry sort silent) + (when (or silent (y-or-n-p "Save cabal file? ")) + (save-buffer)))) + ;; unwind + (haskell-mode-toggle-interactive-prompt-state t))) + + +(defun haskell-cabal--find-tags-dir () + "Return a directory where TAGS file will be generated. +Tries to find cabal file first and if succeeds uses its location. +If cabal file not found uses current file directory. If current +buffer not visiting a file returns nil." + (or (haskell-cabal-find-dir) + (when buffer-file-name + (file-name-directory buffer-file-name)))) + +(defun haskell-cabal--compose-hasktags-command (dir) + "Prepare command to execute `hasktags` command in DIR folder. + +To customise the command executed, see `haskell-hasktags-path' +and `haskell-hasktags-arguments'. + +This function takes into account the user's operating system: in case +of Windows it generates a simple command, relying on Hasktags +itself to find source files: + +hasktags --output=DIR\TAGS -x -e DIR + +In other cases it uses `find` command to find all source files +recursively avoiding visiting unnecessary heavy directories like +.git, .svn, _darcs and build directories created by +cabal-install, stack, etc and passes list of found files to Hasktags." + (if (eq system-type 'windows-nt) + (format "%s --output=%s %s %s" + haskell-hasktags-path + (shell-quote-argument (expand-file-name "TAGS" dir)) + (mapconcat #'identity haskell-hasktags-arguments " ") + (shell-quote-argument dir)) + (format "cd %s && %s | %s" + (shell-quote-argument dir) + (concat "find . " + "-type d \\( " + "-path ./.git " + "-o -path ./.svn " + "-o -path ./_darcs " + "-o -path ./.stack-work " + "-o -path ./dist " + "-o -path ./.cabal-sandbox " + "\\) -prune " + "-o -type f \\( " + "-name '*.hs' " + "-or -name '*.lhs' " + "-or -name '*.hsc' " + "\\) -not \\( " + "-name '#*' " + "-or -name '.*' " + "\\) -print0") + (format "xargs -0 %s %s" + (shell-quote-argument haskell-hasktags-path) + (mapconcat #'identity haskell-hasktags-arguments " "))))) + +(provide 'haskell-cabal) +;;; haskell-cabal.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-cabal.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-cabal.elc new file mode 100644 index 000000000000..7609bc3bc102 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-cabal.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-collapse.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-collapse.el new file mode 100644 index 000000000000..8a73fa3887fc --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-collapse.el @@ -0,0 +1,114 @@ +;;; haskell-collapse.el --- Collapse expressions -*- lexical-binding: t -*- + +;; Copyright (c) 2014 Chris Done. All rights reserved. +;; Copyright (c) 2017 Vasantha Ganesh Kanniappan <vasanthaganesh.k@tuta.io>. + +;; 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 <http://www.gnu.org/licenses/>. + +;;; Code: + +(require 'hideshow) + +;;; TODO: +;;; -> Make it work for braces + +(defun haskell-hide-toggle () + "Toggle visibility of existing forms at point. " + (interactive) + (hs-minor-mode 1) + (save-excursion + (let* ((modified (buffer-modified-p)) + (inhibit-read-only t) + (position (haskell-indented-block)) + (beg (car position)) + (end (cdr position))) + (if (and beg end) + (if (overlays-in beg end) + (hs-discard-overlays beg end) + (hs-make-overlay beg end 'code))) + (set-buffer-modified-p modified)))) + +(defun haskell-blank-line-p () + "Returns `t' if line is empty or composed only of whitespace." + (save-excursion + (beginning-of-line) + (= (point-at-eol) + (progn (skip-chars-forward "[:blank:]") (point))))) + +(defun haskell-indented-block () + "return (start-of-indentation . end-of-indentation)" + (let ((cur-indent (current-indentation)) + (nxt-line-indent (haskell-next-line-indentation 1)) + (prev-line-indent (haskell-next-line-indentation -1)) + (beg-of-line (save-excursion (end-of-line) + (point)))) + (cond ((and (= cur-indent 0) + (= nxt-line-indent 0)) nil) + ((haskell-blank-line-p) nil) + ((> nxt-line-indent cur-indent) + (cons beg-of-line + (haskell-find-line-with-indentation '> 1))) + ((or (= nxt-line-indent cur-indent) + (<= prev-line-indent cur-indent)) + (cons (haskell-find-line-with-indentation '>= -1) + (haskell-find-line-with-indentation '>= 1))) + (t nil)))) + +(defun haskell-next-line-indentation (dir) + "returns (integer) indentation of the next if dir=1, previous line +indentation if dir=-1" + (save-excursion + (progn + (while (and (zerop (forward-line dir)) + (haskell-blank-line-p))) + (current-indentation)))) + +(defun haskell-find-line-with-indentation (comparison direction) + "comparison is >= or >, direction if 1 finds forward, if -1 finds backward" + (save-excursion + (let ((start-indent (current-indentation))) + (progn + (while (and (zerop (forward-line direction)) + (or (haskell-blank-line-p) + (funcall comparison (current-indentation) start-indent)))) + (when (= direction 1) (forward-line -1)) + (end-of-line) + (point))))) + +(defun haskell-hide-toggle-all () + "hides all top level functions" + (interactive) + (save-excursion + (goto-char (point-max)) + (while (zerop (forward-line -1)) + (goto-char (point-at-bol)) + (when (= (current-indentation) 0) (haskell-hide-toggle))))) + +(defvar haskell-collapse-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-c @ C-c") 'haskell-hide-toggle) + (define-key map (kbd "C-c @ C-M-c") 'haskell-hide-toggle-all) + (define-key map (kbd "C-c @ C-M-s") 'haskell-hide-toggle-all) + (define-key map (kbd "C-c @ C-M-h") 'haskell-hide-toggle-all) + map) + "Keymap for using `haskell-collapse-mode'.") + +;;;###autoload +(define-minor-mode haskell-collapse-mode + "Minor mode to collapse and expand haskell expressions" + :init-value nil + :lighter " Haskell-Collapse" + :keymap haskell-collapse-mode-map) + +(provide 'haskell-collapse) diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-collapse.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-collapse.elc new file mode 100644 index 000000000000..2d6b9b82867c --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-collapse.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-commands.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-commands.el new file mode 100644 index 000000000000..b0898553d206 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-commands.el @@ -0,0 +1,961 @@ +;;; haskell-commands.el --- Commands that can be run on the process -*- lexical-binding: t -*- + +;;; Commentary: + +;;; This module provides varoius `haskell-mode' and `haskell-interactive-mode' +;;; specific commands such as show type signature, show info, haskell process +;;; commands and etc. + +;; Copyright © 2014 Chris Done. All rights reserved. +;; 2016 Arthur Fayzrakhmanov + +;; 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 <http://www.gnu.org/licenses/>. + +;;; Code: + +(require 'cl-lib) +(require 'etags) +(require 'haskell-mode) +(require 'haskell-compat) +(require 'haskell-process) +(require 'haskell-font-lock) +(require 'haskell-interactive-mode) +(require 'haskell-session) +(require 'haskell-string) +(require 'haskell-presentation-mode) +(require 'haskell-utils) +(require 'highlight-uses-mode) +(require 'haskell-cabal) + +(defcustom haskell-mode-stylish-haskell-path "stylish-haskell" + "Path to `stylish-haskell' executable." + :group 'haskell + :type 'string) + +(defcustom haskell-interactive-set-+c + t + "Issue ':set +c' in interactive session to support type introspection." + :group 'haskell-interactive + :type 'boolean) + +;;;###autoload +(defun haskell-process-restart () + "Restart the inferior Haskell process." + (interactive) + (haskell-process-reset (haskell-interactive-process)) + (haskell-process-set (haskell-interactive-process) 'command-queue nil) + (haskell-process-start (haskell-interactive-session))) + +(defun haskell-process-start (session) + "Start the inferior Haskell process with a given SESSION. +You can create new session using function `haskell-session-make'." + (let ((existing-process (get-process (haskell-session-name (haskell-interactive-session))))) + (when (processp existing-process) + (haskell-interactive-mode-echo session "Restarting process ...") + (haskell-process-set (haskell-session-process session) 'is-restarting t) + (delete-process existing-process))) + (let ((process (or (haskell-session-process session) + (haskell-process-make (haskell-session-name session)))) + (old-queue (haskell-process-get (haskell-session-process session) + 'command-queue))) + (haskell-session-set-process session process) + (haskell-process-set-session process session) + (haskell-process-set-cmd process nil) + (haskell-process-set (haskell-session-process session) 'is-restarting nil) + (let ((default-directory (haskell-session-cabal-dir session)) + (log-and-command (haskell-process-compute-process-log-and-command session (haskell-process-type)))) + (haskell-session-prompt-set-current-dir session (not haskell-process-load-or-reload-prompt)) + (haskell-process-set-process + process + (progn + (haskell-process-log (propertize (format "%S" log-and-command))) + (apply #'start-process (cdr log-and-command))))) + (progn (set-process-sentinel (haskell-process-process process) 'haskell-process-sentinel) + (set-process-filter (haskell-process-process process) 'haskell-process-filter)) + (haskell-process-send-startup process) + (unless (or (eq 'cabal-repl (haskell-process-type)) + (eq 'cabal-new-repl (haskell-process-type)) + (eq 'stack-ghci (haskell-process-type))) ;; Both "cabal repl" and "stack ghci" set the proper CWD. + (haskell-process-change-dir session + process + (haskell-session-current-dir session))) + (haskell-process-set process 'command-queue + (append (haskell-process-get (haskell-session-process session) + 'command-queue) + old-queue)) + process)) + +(defun haskell-process-send-startup (process) + "Send the necessary start messages to haskell PROCESS." + (haskell-process-queue-command + process + (make-haskell-command + :state process + + :go (lambda (process) + ;; We must set the prompt last, so that this command as a + ;; whole produces only one prompt marker as a response. + (haskell-process-send-string process + (mapconcat #'identity + (append '("Prelude.putStrLn \"\"" + ":set -v1") + (when haskell-interactive-set-+c + '(":set +c"))) ; :type-at in GHC 8+ + "\n")) + (haskell-process-send-string process ":set prompt \"\\4\"") + (haskell-process-send-string process (format ":set prompt2 \"%s\"" + haskell-interactive-prompt2))) + + :live (lambda (process buffer) + (when (haskell-process-consume + process + "^\*\*\* WARNING: \\(.+\\) is writable by someone else, IGNORING!$") + (let ((path (match-string 1 buffer))) + (haskell-session-modify + (haskell-process-session process) + 'ignored-files + (lambda (files) + (cl-remove-duplicates (cons path files) :test 'string=))) + (haskell-interactive-mode-compile-warning + (haskell-process-session process) + (format "GHCi is ignoring: %s (run M-x haskell-process-unignore)" + path))))) + + :complete (lambda (process _) + (haskell-interactive-mode-echo + (haskell-process-session process) + (concat (nth (random (length haskell-process-greetings)) + haskell-process-greetings) + (when haskell-process-show-debug-tips + " +If I break, you can: + 1. Restart: M-x haskell-process-restart + 2. Configure logging: C-h v haskell-process-log (useful for debugging) + 3. General config: M-x customize-mode + 4. Hide these tips: C-h v haskell-process-show-debug-tips"))) + (with-current-buffer (haskell-interactive-buffer) + (goto-char haskell-interactive-mode-prompt-start)))))) + +(defun haskell-commands-process () + "Get the Haskell session, throws an error if not available." + (or (haskell-session-process (haskell-session-maybe)) + (error "No Haskell session/process associated with this + buffer. Maybe run M-x haskell-session-change?"))) + +;;;###autoload +(defun haskell-process-clear () + "Clear the current process." + (interactive) + (haskell-process-reset (haskell-commands-process)) + (haskell-process-set (haskell-commands-process) 'command-queue nil)) + +;;;###autoload +(defun haskell-process-interrupt () + "Interrupt the process (SIGINT)." + (interactive) + (interrupt-process (haskell-process-process (haskell-commands-process)))) + +(defun haskell-process-reload-with-fbytecode (process module-buffer) + "Query a PROCESS to reload MODULE-BUFFER with -fbyte-code set. +Restores -fobject-code after reload finished. +MODULE-BUFFER is the actual Emacs buffer of the module being loaded." + (haskell-process-queue-without-filters process ":set -fbyte-code") + ;; We prefix the module's filename with a "*", which asks ghci to + ;; ignore any existing object file and interpret the module. + ;; Dependencies will still use their object files as usual. + (haskell-process-queue-without-filters + process + (format ":load \"*%s\"" + (replace-regexp-in-string + "\"" + "\\\\\"" + (buffer-file-name module-buffer)))) + (haskell-process-queue-without-filters process ":set -fobject-code")) + +(defvar url-http-response-status) +(defvar url-http-end-of-headers) +(defvar haskell-cabal-targets-history nil + "History list for session targets.") + +(defun haskell-process-hayoo-ident (ident) + "Hayoo for IDENT, return a list of modules" + ;; We need a real/simulated closure, because otherwise these + ;; variables will be unbound when the url-retrieve callback is + ;; called. + ;; TODO: Remove when this code is converted to lexical bindings by + ;; default (Emacs 24.1+) + (let ((url (format haskell-process-hayoo-query-url (url-hexify-string ident)))) + (with-current-buffer (url-retrieve-synchronously url) + (if (= 200 url-http-response-status) + (progn + (goto-char url-http-end-of-headers) + (let* ((res (json-read)) + (results (assoc-default 'result res))) + ;; TODO: gather packages as well, and when we choose a + ;; given import, check that we have the package in the + ;; cabal file as well. + (cl-mapcan (lambda (r) + ;; append converts from vector -> list + (append (assoc-default 'resultModules r) nil)) + results))) + (warn "HTTP error %s fetching %s" url-http-response-status url))))) + +(defun haskell-process-hoogle-ident (ident) + "Hoogle for IDENT, return a list of modules." + (with-temp-buffer + (let ((hoogle-error (call-process "hoogle" nil t nil "search" "--exact" ident))) + (goto-char (point-min)) + (unless (or (/= 0 hoogle-error) + (looking-at "^No results found") + (looking-at "^package ")) + (while (re-search-forward "^\\([^ ]+\\).*$" nil t) + (replace-match "\\1" nil nil)) + (cl-remove-if (lambda (a) (string= "" a)) + (split-string (buffer-string) + "\n")))))) + +(defun haskell-process-haskell-docs-ident (ident) + "Search with haskell-docs for IDENT, return a list of modules." + (cl-remove-if-not + (lambda (a) (string-match "^[[:upper:]][[:alnum:]_'.]+$" a)) + (split-string + (with-output-to-string + (with-current-buffer + standard-output + (call-process "haskell-docs" + nil ; no infile + t ; output to current buffer (that is string) + nil ; do not redisplay + "--modules" ident))) + "\n"))) + +(defun haskell-process-import-modules (process modules) + "Query PROCESS `:m +' command to import MODULES." + (when haskell-process-auto-import-loaded-modules + (haskell-process-queue-command + process + (make-haskell-command + :state (cons process modules) + :go (lambda (state) + (haskell-process-send-string + (car state) + (format ":m + %s" (mapconcat 'identity (cdr state) " ")))))))) + +;;;###autoload +(defun haskell-describe (ident) + "Describe the given identifier IDENT." + (interactive (list (read-from-minibuffer "Describe identifier: " + (haskell-ident-at-point)))) + (let ((results (read (shell-command-to-string + (concat "haskell-docs --sexp " + ident))))) + (help-setup-xref (list #'haskell-describe ident) + (called-interactively-p 'interactive)) + (save-excursion + (with-help-window (help-buffer) + (with-current-buffer (help-buffer) + (if results + (cl-loop for result in results + do (insert (propertize ident 'font-lock-face + '((:inherit font-lock-type-face + :underline t))) + " is defined in " + (let ((module (cadr (assoc 'module result)))) + (if module + (concat module " ") + "")) + (cadr (assoc 'package result)) + "\n\n") + do (let ((type (cadr (assoc 'type result)))) + (when type + (insert (haskell-fontify-as-mode type 'haskell-mode) + "\n"))) + do (let ((args (cadr (assoc 'type results)))) + (cl-loop for arg in args + do (insert arg "\n")) + (insert "\n")) + do (insert (cadr (assoc 'documentation result))) + do (insert "\n\n")) + (insert "No results for " ident))))))) + +;;;###autoload +(defun haskell-rgrep (&optional prompt) + "Grep the effective project for the symbol at point. +Very useful for codebase navigation. + +Prompts for an arbitrary regexp given a prefix arg PROMPT." + (interactive "P") + (let ((sym (if prompt + (read-from-minibuffer "Look for: ") + (haskell-ident-at-point)))) + (rgrep sym + "*.hs *.lhs *.hsc *.chs *.hs-boot *.lhs-boot" + (haskell-session-current-dir (haskell-interactive-session))))) + +;;;###autoload +(defun haskell-process-do-info (&optional prompt-value) + "Print info on the identifier at point. +If PROMPT-VALUE is non-nil, request identifier via mini-buffer." + (interactive "P") + (let ((at-point (haskell-ident-at-point))) + (when (or prompt-value at-point) + (let* ((ident (replace-regexp-in-string + "^!\\([A-Z_a-z]\\)" + "\\1" + (if prompt-value + (read-from-minibuffer "Info: " at-point) + at-point))) + (modname (unless prompt-value + (haskell-utils-parse-import-statement-at-point))) + (command (cond + (modname + (format ":browse! %s" modname)) + ((string= ident "") ; For the minibuffer input case + nil) + (t (format (if (string-match "^[a-zA-Z_]" ident) + ":info %s" + ":info (%s)") + (or ident + at-point)))))) + (when command + (haskell-process-show-repl-response command)))))) + +;;;###autoload +(defun haskell-process-do-type (&optional insert-value) + "Print the type of the given expression. + +Given INSERT-VALUE prefix indicates that result type signature +should be inserted." + (interactive "P") + (if insert-value + (haskell-process-insert-type) + (let* ((expr + (if (use-region-p) + (buffer-substring-no-properties (region-beginning) (region-end)) + (haskell-ident-at-point))) + (expr-okay (and expr + (not (string-match-p "\\`[[:space:]]*\\'" expr)) + (not (string-match-p "\n" expr))))) + ;; No newlines in expressions, and surround with parens if it + ;; might be a slice expression + (when expr-okay + (haskell-process-show-repl-response + (format + (if (or (string-match-p "\\`(" expr) + (string-match-p "\\`[_[:alpha:]]" expr)) + ":type %s" + ":type (%s)") + expr)))))) + +;;;###autoload +(defun haskell-mode-jump-to-def-or-tag (&optional _next-p) + ;; FIXME NEXT-P arg is not used + "Jump to the definition. +Jump to definition of identifier at point by consulting GHCi, or +tag table as fallback. + +Remember: If GHCi is busy doing something, this will delay, but +it will always be accurate, in contrast to tags, which always +work but are not always accurate. +If the definition or tag is found, the location from which you jumped +will be pushed onto `xref--marker-ring', so you can return to that +position with `xref-pop-marker-stack'." + (interactive "P") + (if (haskell-session-maybe) + (let ((initial-loc (point-marker)) + (loc (haskell-mode-find-def (haskell-ident-at-point)))) + (haskell-mode-handle-generic-loc loc) + (unless (equal initial-loc (point-marker)) + (xref-push-marker-stack initial-loc))) + (call-interactively 'haskell-mode-tag-find))) + +;;;###autoload +(defun haskell-mode-goto-loc () + "Go to the location of the thing at point. +Requires the :loc-at command from GHCi." + (interactive) + (let ((loc (haskell-mode-loc-at))) + (when loc + (haskell-mode-goto-span loc)))) + +(defun haskell-mode-goto-span (span) + "Jump to the SPAN, whatever file and line and column it needs to get there." + (xref-push-marker-stack) + (find-file (expand-file-name (plist-get span :path) + (haskell-session-cabal-dir (haskell-interactive-session)))) + (goto-char (point-min)) + (forward-line (1- (plist-get span :start-line))) + (forward-char (plist-get span :start-col))) + +(defun haskell-process-insert-type () + "Get the identifier at the point and insert its type. +Use GHCi's :type if it's possible." + (let ((ident (haskell-ident-at-point))) + (when ident + (let ((process (haskell-interactive-process)) + (query (format (if (string-match "^[_[:lower:][:upper:]]" ident) + ":type %s" + ":type (%s)") + ident))) + (haskell-process-queue-command + process + (make-haskell-command + :state (list process query (current-buffer)) + :go (lambda (state) + (haskell-process-send-string (nth 0 state) + (nth 1 state))) + :complete (lambda (state response) + (cond + ;; TODO: Generalize this into a function. + ((or (string-match "^Top level" response) + (string-match "^<interactive>" response)) + (message "%s" response)) + (t + (with-current-buffer (nth 2 state) + (goto-char (line-beginning-position)) + (insert (format "%s\n" (replace-regexp-in-string "\n$" "" response))))))))))))) + +(defun haskell-mode-find-def (ident) + ;; TODO Check if it possible to exploit `haskell-process-do-info' + "Find definition location of identifier IDENT. +Uses the GHCi process to find the location. Returns nil if it +can't find the identifier or the identifier isn't a string. + +Returns: + + (library <package> <module>) + (file <path> <line> <col>) + (module <name>) + nil" + (when (stringp ident) + (let ((reply (haskell-process-queue-sync-request + (haskell-interactive-process) + (format (if (string-match "^[a-zA-Z_]" ident) + ":info %s" + ":info (%s)") + ident)))) + (let ((match (string-match "-- Defined \\(at\\|in\\) \\(.+\\)$" reply))) + (when match + (let ((defined (match-string 2 reply))) + (let ((match (string-match "\\(.+?\\):\\([0-9]+\\):\\([0-9]+\\)$" defined))) + (cond + (match + (list 'file + (expand-file-name (match-string 1 defined) + (haskell-session-current-dir (haskell-interactive-session))) + (string-to-number (match-string 2 defined)) + (string-to-number (match-string 3 defined)))) + (t + (let ((match (string-match "`\\(.+?\\):\\(.+?\\)'$" defined))) + (if match + (list 'library + (match-string 1 defined) + (match-string 2 defined)) + (let ((match (string-match "`\\(.+?\\)'$" defined))) + (if match + (list 'module + (match-string 1 defined))))))))))))))) + +;;;###autoload +(defun haskell-mode-jump-to-def (ident) + "Jump to definition of identifier IDENT at point." + (interactive + (list + (haskell-string-drop-qualifier + (haskell-ident-at-point)))) + (let ((loc (haskell-mode-find-def ident))) + (when loc + (haskell-mode-handle-generic-loc loc)))) + +(defun haskell-mode-handle-generic-loc (loc) + "Either jump to or echo a generic location LOC. +Either a file or a library." + (cl-case (car loc) + (file (progn + (find-file (elt loc 1)) + (goto-char (point-min)) + (forward-line (1- (elt loc 2))) + (goto-char (+ (line-beginning-position) + (1- (elt loc 3)))))) + (library (message "Defined in `%s' (%s)." + (elt loc 2) + (elt loc 1))) + (module (message "Defined in `%s'." + (elt loc 1))))) + +(defun haskell-mode-loc-at () + "Get the location at point. +Requires the :loc-at command from GHCi." + (let ((pos (or (when (region-active-p) + (cons (region-beginning) + (region-end))) + (haskell-spanable-pos-at-point) + (cons (point) + (point))))) + (when pos + (let ((reply (haskell-process-queue-sync-request + (haskell-interactive-process) + (save-excursion + (format ":loc-at %s %d %d %d %d %s" + (buffer-file-name) + (progn (goto-char (car pos)) + (line-number-at-pos)) + (1+ (current-column)) ;; GHC uses 1-based columns. + (progn (goto-char (cdr pos)) + (line-number-at-pos)) + (1+ (current-column)) ;; GHC uses 1-based columns. + (buffer-substring-no-properties (car pos) + (cdr pos))))))) + (if reply + (if (string-match "\\(.*?\\):(\\([0-9]+\\),\\([0-9]+\\))-(\\([0-9]+\\),\\([0-9]+\\))" + reply) + (list :path (match-string 1 reply) + :start-line (string-to-number (match-string 2 reply)) + ;; ;; GHC uses 1-based columns. + :start-col (1- (string-to-number (match-string 3 reply))) + :end-line (string-to-number (match-string 4 reply)) + ;; GHC uses 1-based columns. + :end-col (1- (string-to-number (match-string 5 reply)))) + (error (propertize reply 'face 'compilation-error))) + (error (propertize "No reply. Is :loc-at supported?" + 'face 'compilation-error))))))) + +;;;###autoload +(defun haskell-process-cd (&optional _not-interactive) + ;; FIXME optional arg is not used + "Change directory." + (interactive) + (let* ((session (haskell-interactive-session)) + (dir (haskell-session-prompt-set-current-dir session))) + (haskell-process-log + (propertize (format "Changing directory to %s ...\n" dir) + 'face font-lock-comment-face)) + (haskell-process-change-dir session + (haskell-interactive-process) + dir))) + +(defun haskell-session-buffer-default-dir (session &optional buffer) + "Try to deduce a sensible default directory for SESSION and BUFFER, +of which the latter defaults to the current buffer." + (or (haskell-session-get session 'current-dir) + (haskell-session-get session 'cabal-dir) + (if (buffer-file-name buffer) + (file-name-directory (buffer-file-name buffer)) + "~/"))) + +(defun haskell-session-prompt-set-current-dir (session &optional use-default) + "Prompt for the current directory. +Return current working directory for SESSION." + (let ((default (haskell-session-buffer-default-dir session))) + (haskell-session-set-current-dir + session + (if use-default + default + (haskell-utils-read-directory-name "Set current directory: " default)))) + (haskell-session-get session 'current-dir)) + +(defun haskell-process-change-dir (session process dir) + "Change SESSION's current directory. +Query PROCESS to `:cd` to directory DIR." + (haskell-process-queue-command + process + (make-haskell-command + :state (list session process dir) + :go + (lambda (state) + (haskell-process-send-string + (cadr state) (format ":cd %s" (cl-caddr state)))) + + :complete + (lambda (state _) + (haskell-session-set-current-dir (car state) (cl-caddr state)) + (haskell-interactive-mode-echo (car state) + (format "Changed directory: %s" + (cl-caddr state))))))) + +;;;###autoload +(defun haskell-process-cabal-macros () + "Send the cabal macros string." + (interactive) + (haskell-process-queue-without-filters (haskell-interactive-process) + ":set -optP-include -optPdist/build/autogen/cabal_macros.h")) + +(defun haskell-process-do-try-info (sym) + "Get info of SYM and echo in the minibuffer." + (let ((process (haskell-interactive-process))) + (haskell-process-queue-command + process + (make-haskell-command + :state (cons process sym) + :go (lambda (state) + (haskell-process-send-string + (car state) + (if (string-match "^[A-Za-z_]" (cdr state)) + (format ":info %s" (cdr state)) + (format ":info (%s)" (cdr state))))) + :complete (lambda (_state response) + (unless (or (string-match "^Top level" response) + (string-match "^<interactive>" response)) + (haskell-mode-message-line response))))))) + +(defun haskell-process-do-try-type (sym) + "Get type of SYM and echo in the minibuffer." + (let ((process (haskell-interactive-process))) + (haskell-process-queue-command + process + (make-haskell-command + :state (cons process sym) + :go (lambda (state) + (haskell-process-send-string + (car state) + (if (string-match "^[A-Za-z_]" (cdr state)) + (format ":type %s" (cdr state)) + (format ":type (%s)" (cdr state))))) + :complete (lambda (_state response) + (unless (or (string-match "^Top level" response) + (string-match "^<interactive>" response)) + (haskell-mode-message-line response))))))) + +;;;###autoload +(defun haskell-mode-show-type-at (&optional insert-value) + "Show type of the thing at point or within active region asynchronously. +This function requires GHCi 8+ or GHCi-ng. + +\\<haskell-interactive-mode-map> +To make this function works sometimes you need to load the file in REPL +first using command `haskell-process-load-file' bound to +\\[haskell-process-load-file]. + +Optional argument INSERT-VALUE indicates that +recieved type signature should be inserted (but only if nothing +happened since function invocation)." + (interactive "P") + (let* ((pos (haskell-command-capture-expr-bounds)) + (req (haskell-utils-compose-type-at-command pos)) + (process (haskell-interactive-process)) + (buf (current-buffer)) + (pos-reg (cons pos (region-active-p)))) + (haskell-process-queue-command + process + (make-haskell-command + :state (list process req buf insert-value pos-reg) + :go + (lambda (state) + (let* ((prc (car state)) + (req (nth 1 state))) + (haskell-utils-async-watch-changes) + (haskell-process-send-string prc req))) + :complete + (lambda (state response) + (let* ((init-buffer (nth 2 state)) + (insert-value (nth 3 state)) + (pos-reg (nth 4 state)) + (wrap (cdr pos-reg)) + (min-pos (caar pos-reg)) + (max-pos (cdar pos-reg)) + (sig (haskell-utils-reduce-string response)) + (res-type (haskell-utils-repl-response-error-status sig))) + + (cl-case res-type + ;; neither popup presentation buffer + ;; nor insert response in error case + ('unknown-command + (message "This command requires GHCi 8+ or GHCi-ng. Please read command description for details.")) + ('option-missing + (message "Could not infer type signature. You need to load file first. Also :set +c is required, see customization `haskell-interactive-set-+c'. Please read command description for details.")) + ('interactive-error (message "Wrong REPL response: %s" sig)) + (otherwise + (if insert-value + ;; Only insert type signature and do not present it + (if (= (length haskell-utils-async-post-command-flag) 1) + (if wrap + ;; Handle region case + (progn + (deactivate-mark) + (save-excursion + (delete-region min-pos max-pos) + (goto-char min-pos) + (insert (concat "(" sig ")")))) + ;; Non-region cases + (haskell-command-insert-type-signature sig)) + ;; Some commands registered, prevent insertion + (message "Type signature insertion was prevented. These commands were registered: %s" + (cdr (reverse haskell-utils-async-post-command-flag)))) + ;; Present the result only when response is valid and not asked + ;; to insert result + (haskell-command-echo-or-present response))) + + (haskell-utils-async-stop-watching-changes init-buffer)))))))) + +(make-obsolete 'haskell-process-generate-tags + 'haskell-mode-generate-tags + "2016-03-14") +(defun haskell-process-generate-tags (&optional and-then-find-this-tag) + "Regenerate the TAGS table. +If optional AND-THEN-FIND-THIS-TAG argument is present it is used with +function `xref-find-definitions' after new table was generated." + (interactive) + (let ((process (haskell-interactive-process))) + (haskell-process-queue-command + process + (make-haskell-command + :state (cons process and-then-find-this-tag) + :go + (lambda (state) + (let* ((process (car state)) + (cabal-dir (haskell-session-cabal-dir + (haskell-process-session process))) + (command (haskell-cabal--compose-hasktags-command cabal-dir))) + (haskell-process-send-string process command))) + :complete (lambda (state _response) + (when (cdr state) + (let ((tags-file-name + (haskell-session-tags-filename + (haskell-process-session (car state))))) + (xref-find-definitions (cdr state)))) + (haskell-mode-message-line "Tags generated.")))))) + +(defun haskell-process-add-cabal-autogen () + "Add cabal's autogen dir to the GHCi search path. +Add <cabal-project-dir>/dist/build/autogen/ to GHCi seatch path. +This allows modules such as 'Path_...', generated by cabal, to be +loaded by GHCi." + (unless (or (eq 'cabal-repl (haskell-process-type)) + (eq 'cabal-new-repl (haskell-process-type))) ;; redundant with "cabal repl" + (let* + ((session (haskell-interactive-session)) + (cabal-dir (haskell-session-cabal-dir session)) + (ghci-gen-dir (format "%sdist/build/autogen/" cabal-dir))) + (haskell-process-queue-without-filters + (haskell-interactive-process) + (format ":set -i%s" ghci-gen-dir))))) + +;;;###autoload +(defun haskell-process-unignore () + "Unignore any ignored files. +Do not ignore files that were specified as being ignored by the +inferior GHCi process." + (interactive) + (let ((session (haskell-interactive-session)) + (changed nil)) + (if (null (haskell-session-get session 'ignored-files)) + (message "Nothing to unignore!") + (cl-loop for file in (haskell-session-get session 'ignored-files) + do + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (progn + (cl-case + (read-event + (propertize + (format "Set permissions? %s (y, n, v: stop and view file)" + file) + 'face + 'minibuffer-prompt)) + (?y + (haskell-process-unignore-file session file) + (setq changed t)) + (?v + (find-file file) + (cl-return))) + (when (and changed + (y-or-n-p "Restart GHCi process now? ")) + (haskell-process-restart))) + ;; unwind + (haskell-mode-toggle-interactive-prompt-state t)))))) + +;;;###autoload +(defun haskell-session-change-target (target) + "Set the build TARGET for cabal REPL." + (interactive + (list + (completing-read "New build target: " + (haskell-cabal-enum-targets (haskell-process-type)) + nil + nil + nil + 'haskell-cabal-targets-history))) + (let* ((session haskell-session) + (old-target (haskell-session-get session 'target))) + (when session + (haskell-session-set-target session target) + (when (not (string= old-target target)) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (when (y-or-n-p "Target changed, restart haskell process?") + (haskell-process-start session))) + (haskell-mode-toggle-interactive-prompt-state t))))) + +;;;###autoload +(defun haskell-mode-stylish-buffer () + "Apply stylish-haskell to the current buffer. + +Use `haskell-mode-stylish-haskell-path' to know where to find +stylish-haskell executable. This function tries to preserve +cursor position and markers by using +`haskell-mode-buffer-apply-command'." + (interactive) + (haskell-mode-buffer-apply-command haskell-mode-stylish-haskell-path)) + +(defun haskell-mode-buffer-apply-command (cmd) + "Execute shell command CMD with current buffer as input and output. +Use buffer as input and replace the whole buffer with the +output. If CMD fails the buffer remains unchanged." + (set-buffer-modified-p t) + (let* ((out-file (make-temp-file "stylish-output")) + (err-file (make-temp-file "stylish-error"))) + (unwind-protect + (let* ((_errcode + (call-process-region (point-min) (point-max) cmd nil + `((:file ,out-file) ,err-file) + nil)) + (err-file-empty-p + (equal 0 (nth 7 (file-attributes err-file)))) + (out-file-empty-p + (equal 0 (nth 7 (file-attributes out-file))))) + (if err-file-empty-p + (if out-file-empty-p + (message "Error: %s produced no output and no error information, leaving buffer alone" cmd) + ;; Command successful, insert file with replacement to preserve + ;; markers. + (insert-file-contents out-file nil nil nil t)) + (progn + ;; non-null stderr, command must have failed + (with-current-buffer + (get-buffer-create "*haskell-mode*") + (insert-file-contents err-file) + (buffer-string)) + (message "Error: %s ended with errors, leaving buffer alone, see *haskell-mode* buffer for stderr" cmd) + (with-temp-buffer + (insert-file-contents err-file) + ;; use (warning-minimum-level :debug) to see this + (display-warning cmd + (buffer-substring-no-properties (point-min) (point-max)) + :debug))))) + (ignore-errors + (delete-file err-file)) + (ignore-errors + (delete-file out-file))))) + +;;;###autoload +(defun haskell-mode-find-uses () + "Find use cases of the identifier at point and highlight them all." + (interactive) + (let ((spans (haskell-mode-uses-at))) + (unless (null spans) + (highlight-uses-mode 1) + (cl-loop for span in spans + do (haskell-mode-make-use-highlight span))))) + +(defun haskell-mode-make-use-highlight (span) + "Make a highlight overlay at the given SPAN." + (save-window-excursion + (save-excursion + (haskell-mode-goto-span span) + (save-excursion + (highlight-uses-mode-highlight + (progn + (goto-char (point-min)) + (forward-line (1- (plist-get span :start-line))) + (forward-char (plist-get span :start-col)) + (point)) + (progn + (goto-char (point-min)) + (forward-line (1- (plist-get span :end-line))) + (forward-char (plist-get span :end-col)) + (point))))))) + +(defun haskell-mode-uses-at () + "Get the locations of use cases for the ident at point. +Requires the :uses command from GHCi." + (let ((pos (or (when (region-active-p) + (cons (region-beginning) + (region-end))) + (haskell-ident-pos-at-point) + (cons (point) + (point))))) + (when pos + (let ((reply (haskell-process-queue-sync-request + (haskell-interactive-process) + (save-excursion + (format ":uses %s %d %d %d %d %s" + (buffer-file-name) + (progn (goto-char (car pos)) + (line-number-at-pos)) + (1+ (current-column)) ;; GHC uses 1-based columns. + (progn (goto-char (cdr pos)) + (line-number-at-pos)) + (1+ (current-column)) ;; GHC uses 1-based columns. + (buffer-substring-no-properties (car pos) + (cdr pos))))))) + (if reply + (let ((lines (split-string reply "\n" t))) + (cl-remove-if + #'null + (mapcar (lambda (line) + (if (string-match "\\(.*?\\):(\\([0-9]+\\),\\([0-9]+\\))-(\\([0-9]+\\),\\([0-9]+\\))" + line) + (list :path (match-string 1 line) + :start-line (string-to-number (match-string 2 line)) + ;; ;; GHC uses 1-based columns. + :start-col (1- (string-to-number (match-string 3 line))) + :end-line (string-to-number (match-string 4 line)) + ;; GHC uses 1-based columns. + :end-col (1- (string-to-number (match-string 5 line)))) + (error (propertize line 'face 'compilation-error)))) + lines))) + (error (propertize "No reply. Is :uses supported?" + 'face 'compilation-error))))))) + +(defun haskell-command-echo-or-present (msg) + "Present message in some manner depending on configuration. +If variable `haskell-process-use-presentation-mode' is NIL it will output +modified message MSG to echo area." + (if haskell-process-use-presentation-mode + (let ((session (haskell-process-session (haskell-interactive-process)))) + (haskell-presentation-present session msg)) + (let ((m (haskell-utils-reduce-string msg))) + (message "%s" m)))) + +(defun haskell-command-capture-expr-bounds () + "Capture position bounds of expression at point. +If there is an active region then it returns region +bounds. Otherwise it uses `haskell-spanable-pos-at-point` to +capture identifier bounds. If latter function returns NIL this function +will return cons cell where min and max positions both are equal +to point." + (or (when (region-active-p) + (cons (region-beginning) + (region-end))) + (haskell-spanable-pos-at-point) + (cons (point) (point)))) + +(defun haskell-command-insert-type-signature (signature) + "Insert type signature. +In case of active region is present, wrap it by parentheses and +append SIGNATURE to original expression. Otherwise tries to +carefully insert SIGNATURE above identifier at point. Removes +newlines and extra whitespace in signature before insertion." + (let* ((ident-pos (or (haskell-ident-pos-at-point) + (cons (point) (point)))) + (min-pos (car ident-pos)) + (sig (haskell-utils-reduce-string signature))) + (save-excursion + (goto-char min-pos) + (let ((col (current-column))) + (insert sig "\n") + (indent-to col))))) + +(provide 'haskell-commands) +;;; haskell-commands.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-commands.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-commands.elc new file mode 100644 index 000000000000..d236651b7c16 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-commands.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-compat.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-compat.el new file mode 100644 index 000000000000..c023ca60753a --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-compat.el @@ -0,0 +1,65 @@ +;;; haskell-compat.el --- legacy/compatibility backports for haskell-mode -*- lexical-binding: t -*- +;; +;; Filename: haskell-compat.el +;; Description: legacy/compatibility backports for haskell-mode + +;; This file is not part of GNU Emacs. + +;; 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;;; Code: +(require 'etags) +(require 'ring) +(require 'outline) +(require 'xref nil t) + +(eval-when-compile + (setq byte-compile-warnings '(not cl-functions obsolete))) + + +;; Cross-referencing commands have been replaced since Emacs 25.1. +;; These aliases are required to provide backward compatibility. +(unless (fboundp 'xref-push-marker-stack) + (defalias 'xref-pop-marker-stack 'pop-tag-mark) + + (defun xref-push-marker-stack (&optional m) + "Add point M (defaults to `point-marker') to the marker stack." + (ring-insert find-tag-marker-ring (or m (point-marker))))) + +(unless (fboundp 'outline-hide-sublevels) + (defalias 'outline-hide-sublevels 'hide-sublevels)) + +(unless (fboundp 'outline-show-subtree) + (defalias 'outline-show-subtree 'show-subtree)) + +(unless (fboundp 'outline-hide-sublevels) + (defalias 'outline-hide-sublevels 'hide-sublevels)) + +(unless (fboundp 'outline-show-subtree) + (defalias 'outline-show-subtree 'show-subtree)) + +(unless (fboundp 'xref-find-definitions) + (defun xref-find-definitions (ident) + (let ((next-p (and (boundp 'xref-prompt-for-identifier) + xref-prompt-for-identifier))) + (find-tag ident next-p)))) + +(unless (fboundp 'font-lock-ensure) + (defalias 'font-lock-ensure 'font-lock-fontify-buffer)) + +(provide 'haskell-compat) + +;;; haskell-compat.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-compat.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-compat.elc new file mode 100644 index 000000000000..c07ad194cdee --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-compat.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-compile.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-compile.el new file mode 100644 index 000000000000..2f4224032a23 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-compile.el @@ -0,0 +1,154 @@ +;;; haskell-compile.el --- Haskell/GHC compilation sub-mode -*- lexical-binding: t -*- + +;; Copyright (C) 2013 Herbert Valerio Riedel + +;; Author: Herbert Valerio Riedel <hvr@gnu.org> + +;; This file is not part of GNU Emacs. + +;; 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 of the License, 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Simple GHC-centric compilation sub-mode; see info node +;; `(haskell-mode)compilation' for more information + +;;; Code: + +(require 'compile) +(require 'haskell-cabal) + +;;;###autoload +(defgroup haskell-compile nil + "Settings for Haskell compilation mode" + :link '(custom-manual "(haskell-mode)compilation") + :group 'haskell) + +(defcustom haskell-compile-cabal-build-command + "cd %s && cabal build --ghc-option=-ferror-spans" + "Default build command to use for `haskell-cabal-build' when a cabal file is detected. +The `%s' placeholder is replaced by the cabal package top folder." + :group 'haskell-compile + :type 'string) + +(defcustom haskell-compile-cabal-build-alt-command + "cd %s && cabal clean -s && cabal build --ghc-option=-ferror-spans" + "Alternative build command to use when `haskell-cabal-build' is called with a negative prefix argument. +The `%s' placeholder is replaced by the cabal package top folder." + :group 'haskell-compile + :type 'string) + +(defcustom haskell-compile-command + "ghc -Wall -ferror-spans -fforce-recomp -c %s" + "Default build command to use for `haskell-cabal-build' when no cabal file is detected. +The `%s' placeholder is replaced by the current buffer's filename." + :group 'haskell-compile + :type 'string) + +(defcustom haskell-compile-ghc-filter-linker-messages + t + "Filter out unremarkable \"Loading package...\" linker messages during compilation." + :group 'haskell-compile + :type 'boolean) + +(defconst haskell-compilation-error-regexp-alist + `((,(concat + "^ *\\(?1:[^\t\r\n]+?\\):" + "\\(?:" + "\\(?2:[0-9]+\\):\\(?4:[0-9]+\\)\\(?:-\\(?5:[0-9]+\\)\\)?" ;; "121:1" & "12:3-5" + "\\|" + "(\\(?2:[0-9]+\\),\\(?4:[0-9]+\\))-(\\(?3:[0-9]+\\),\\(?5:[0-9]+\\))" ;; "(289,5)-(291,36)" + "\\)" + ":\\(?6:\n?[ \t]+[Ww]arning:\\)?") + 1 (2 . 3) (4 . 5) (6 . nil)) ;; error/warning locus + + ;; multiple declarations + ("^ \\(?:Declared at:\\| \\) \\(?1:[^ \t\r\n]+\\):\\(?2:[0-9]+\\):\\(?4:[0-9]+\\)$" + 1 2 4 0) ;; info locus + + ;; this is the weakest pattern as it's subject to line wrapping et al. + (" at \\(?1:[^ \t\r\n]+\\):\\(?2:[0-9]+\\):\\(?4:[0-9]+\\)\\(?:-\\(?5:[0-9]+\\)\\)?[)]?$" + 1 2 (4 . 5) 0)) ;; info locus + "Regexps used for matching GHC compile messages. +See `compilation-error-regexp-alist' for semantics.") + +(defvar haskell-compilation-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map compilation-mode-map)) + "Keymap for `haskell-compilation-mode' buffers. +This is a child of `compilation-mode-map'.") + +(defun haskell-compilation-filter-hook () + "Local `compilation-filter-hook' for `haskell-compilation-mode'." + + (when haskell-compile-ghc-filter-linker-messages + (delete-matching-lines "^ *Loading package [^ \t\r\n]+ [.]+ linking [.]+ done\\.$" + (save-excursion (goto-char compilation-filter-start) + (line-beginning-position)) + (point)))) + +(define-compilation-mode haskell-compilation-mode "HsCompilation" + "Haskell/GHC specific `compilation-mode' derivative. +This mode provides support for GHC 7.[46]'s compile +messages. Specifically, also the `-ferror-spans` source location +format is supported, as well as info-locations within compile +messages pointing to additional source locations." + (setq-local compilation-error-regexp-alist + haskell-compilation-error-regexp-alist) + + (add-hook 'compilation-filter-hook + 'haskell-compilation-filter-hook nil t) + ) + +;;;###autoload +(defun haskell-compile (&optional edit-command) + "Compile the Haskell program including the current buffer. +Tries to locate the next cabal description in current or parent +folders via `haskell-cabal-find-dir' and if found, invoke +`haskell-compile-cabal-build-command' from the cabal package root +folder. If no cabal package could be detected, +`haskell-compile-command' is used instead. + +If prefix argument EDIT-COMMAND is non-nil (and not a negative +prefix `-'), `haskell-compile' prompts for custom compile +command. + +If EDIT-COMMAND contains the negative prefix argument `-', +`haskell-compile' calls the alternative command defined in +`haskell-compile-cabal-build-alt-command' if a cabal package was +detected. + +`haskell-compile' uses `haskell-compilation-mode' which is +derived from `compilation-mode'. See Info +node `(haskell-mode)compilation' for more details." + (interactive "P") + (save-some-buffers (not compilation-ask-about-save) + compilation-save-buffers-predicate) + (let* ((cabdir (haskell-cabal-find-dir)) + (command1 (if (eq edit-command '-) + haskell-compile-cabal-build-alt-command + haskell-compile-cabal-build-command)) + (srcname (buffer-file-name)) + (command (if cabdir + (format command1 cabdir) + (if (and srcname (derived-mode-p 'haskell-mode)) + (format haskell-compile-command srcname) + command1)))) + (when (and edit-command (not (eq edit-command '-))) + (setq command (compilation-read-command command))) + + (compilation-start command 'haskell-compilation-mode))) + +(provide 'haskell-compile) +;;; haskell-compile.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-compile.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-compile.elc new file mode 100644 index 000000000000..a1626cc1cca8 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-compile.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-complete-module.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-complete-module.el new file mode 100644 index 000000000000..ce165348f70a --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-complete-module.el @@ -0,0 +1,131 @@ +;;; haskell-complete-module.el --- A fast way to complete Haskell module names -*- 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 <http://www.gnu.org/licenses/>. + +;;; Code: + +(require 'cl-lib) + +(defcustom haskell-complete-module-preferred + '() + "Override ordering of module results by specifying preferred modules." + :group 'haskell + :type '(repeat string)) + +(defcustom haskell-complete-module-max-display + 10 + "Maximum items to display in minibuffer." + :group 'haskell + :type 'number) + +(defun haskell-complete-module-read (prompt candidates) + "Interactively auto-complete from a list of candidates." + (let ((stack (list)) + (pattern "") + (result nil)) + (delete-dups candidates) + (setq candidates + (sort candidates + (lambda (a b) + (let ((a-mem (member a haskell-complete-module-preferred)) + (b-mem (member b haskell-complete-module-preferred))) + (cond + ((and a-mem (not b-mem)) + t) + ((and b-mem (not a-mem)) + nil) + (t + (string< a b))))))) + (while (not result) + (let ((key + (key-description + (vector + (read-key + (concat (propertize prompt 'face 'minibuffer-prompt) + (propertize pattern 'face 'font-lock-type-face) + "{" + (mapconcat #'identity + (let* ((i 0)) + (cl-loop for candidate in candidates + while (<= i haskell-complete-module-max-display) + do (cl-incf i) + collect (cond ((> i haskell-complete-module-max-display) + "...") + ((= i 1) + (propertize candidate 'face 'ido-first-match-face)) + (t candidate)))) + " | ") + "}")))))) + (cond + ((string= key "C-g") + (keyboard-quit)) + ((string= key "DEL") + (unless (null stack) + (setq candidates (pop stack))) + (unless (string= "" pattern) + (setq pattern (substring pattern 0 -1)))) + ((string= key "RET") + (setq result (or (car candidates) + pattern))) + ((string= key "<left>") + (setq candidates + (append (last candidates) + (butlast candidates)))) + ((string= key "<right>") + (setq candidates + (append (cdr candidates) + (list (car candidates))))) + (t + (when (string-match "[A-Za-z0-9_'.]+" key) + (push candidates stack) + (setq pattern (concat pattern key)) + (setq candidates (haskell-complete-module pattern candidates))))))) + result)) + +(defun haskell-complete-module (pattern candidates) + "Filter the CANDIDATES using PATTERN." + (let ((case-fold-search t)) + (cl-loop for candidate in candidates + when (haskell-complete-module-match pattern candidate) + collect candidate))) + +(defun haskell-complete-module-match (pattern text) + "Match PATTERN against TEXT." + (string-match (haskell-complete-module-regexp pattern) + text)) + +(defun haskell-complete-module-regexp (pattern) + "Make a regular expression for the given module pattern. Example: + +\"c.m.s\" -> \"^c[^.]*\\.m[^.]*\\.s[^.]*\" + +" + (let ((components (mapcar #'haskell-complete-module-component + (split-string pattern "\\." t)))) + (concat "^" + (mapconcat #'identity + components + "\\.")))) + +(defun haskell-complete-module-component (component) + "Make a regular expression for the given component. Example: + +\"co\" -> \"c[^.]*o[^.]*\" + +" + (replace-regexp-in-string "\\(.\\)" "\\1[^.]*" component)) + +(provide 'haskell-complete-module) diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-complete-module.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-complete-module.elc new file mode 100644 index 000000000000..bb8c572f248a --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-complete-module.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-completions.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-completions.el new file mode 100644 index 000000000000..59d2e2413048 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-completions.el @@ -0,0 +1,393 @@ +;;; haskell-completions.el --- Haskell Completion package -*- lexical-binding: t -*- + +;; Copyright © 2015-2016 Athur Fayzrakhmanov. All rights reserved. + +;; This file is part of haskell-mode package. +;; You can contact with authors using GitHub issue tracker: +;; https://github.com/haskell/haskell-mode/issues + +;; 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 GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; This package provides completions related functionality for +;; Haskell Mode such grab completion prefix at point, and etc.. + +;; Some description +;; ================ +;; +;; For major use function `haskell-completions-grab-prefix' is supposed, and +;; other prefix grabbing functions are used internally by it. So, only this +;; funciton have prefix minimal length functionality and invokes predicate +;; function `haskell-completions-can-grab-prefix'. + +;;; Code: + +(require 'haskell-mode) +(require 'haskell-process) +(require 'haskell-interactive-mode) + +;;;###autoload +(defgroup haskell-completions nil + "Settings for completions provided by `haskell-mode'" + :link '(custom-manual "(haskell-mode)Completion support") + :group 'haskell) + +(defcustom haskell-completions-complete-operators + t + "Should `haskell-completions-sync-repl-completion-at-point' complete operators. + +Note: GHCi prior to version 8.0.1 have bug in `:complete` + command: when completing operators it returns a list of all + imported identifiers (see Track ticket URL + `https://ghc.haskell.org/trac/ghc/ticket/10576'). This leads to + significant Emacs slowdown. To aviod slowdown you should set + this variable to `nil'." + :group 'haskell-completions + :type 'boolean) + +(defvar haskell-completions--pragma-names + (list "DEPRECATED" + "INCLUDE" + "INCOHERENT" + "INLINABLE" + "INLINE" + "LANGUAGE" + "LINE" + "MINIMAL" + "NOINLINE" + "NOUNPACK" + "OPTIONS" + "OPTIONS_GHC" + "OVERLAPPABLE" + "OVERLAPPING" + "OVERLAPS" + "RULES" + "SOURCE" + "SPECIALIZE" + "UNPACK" + "WARNING") + "A list of supported pragmas. +This list comes from GHC documentation (URL +`https://downloads.haskell.org/~ghc/7.10.1/docs/html/users_guide/pragmas.html'.") + +(defvar haskell-completions--keywords + (list + "as" + "case" + "class" + "data family" + "data instance" + "data" + "default" + "deriving instance" + "deriving" + "do" + "else" + "family" + "forall" + "foreign import" + "foreign" + "hiding" + "if" + "import qualified" + "import" + "in" + "infix" + "infixl" + "infixr" + "instance" + "let" + "mdo" + "module" + "newtype" + "of" + "proc" + "qualified" + "rec" + "signature" + "then" + "type family" + "type instance" + "type" + "where") + "A list of Haskell's keywords (URL `https://wiki.haskell.org/Keywords'). +Single char keywords and operator like keywords are not included +in this list.") + + +(defun haskell-completions-can-grab-prefix () + "Check if the case is appropriate for grabbing completion prefix. +Returns t if point is either at whitespace character, or at +punctuation, or at line end and preceeding character is not a +whitespace or new line, otherwise returns nil. + + Returns nil in presence of active region." + (when (not (region-active-p)) + (when (looking-at-p (rx (| space line-end punct))) + (when (not (bobp)) + (save-excursion + (backward-char) + (not (looking-at-p (rx (| space line-end))))))))) + +(defun haskell-completions-grab-pragma-prefix () + "Grab completion prefix for pragma completions. +Returns a list of form '(prefix-start-position +prefix-end-position prefix-value prefix-type) for pramga names +such as WARNING, DEPRECATED, LANGUAGE etc. Also returns +completion prefixes for options in case OPTIONS_GHC pragma, or +language extensions in case of LANGUAGE pragma. Obsolete OPTIONS +pragma is supported also." + (when (nth 4 (syntax-ppss)) + ;; We're inside comment + (let ((p (point)) + (comment-start (nth 8 (syntax-ppss))) + (case-fold-search nil) + prefix-start + prefix-end + prefix-type + prefix-value) + (save-excursion + (goto-char comment-start) + (when (looking-at (rx "{-#" (1+ (| space "\n")))) + (let ((pragma-start (match-end 0))) + (when (> p pragma-start) + ;; point stands after `{-#` + (goto-char pragma-start) + (when (looking-at (rx (1+ (| upper "_")))) + ;; found suitable sequence for pragma name + (let ((pragma-end (match-end 0)) + (pragma-value (match-string-no-properties 0))) + (if (eq p pragma-end) + ;; point is at the end of (in)complete pragma name + ;; prepare resulting values + (progn + (setq prefix-start pragma-start) + (setq prefix-end pragma-end) + (setq prefix-value pragma-value) + (setq prefix-type + 'haskell-completions-pragma-name-prefix)) + (when (and (> p pragma-end) + (or (equal "OPTIONS_GHC" pragma-value) + (equal "OPTIONS" pragma-value) + (equal "LANGUAGE" pragma-value))) + ;; point is after pragma name, so we need to check + ;; special cases of `OPTIONS_GHC` and `LANGUAGE` pragmas + ;; and provide a completion prefix for possible ghc + ;; option or language extension. + (goto-char pragma-end) + (when (re-search-forward + (rx (* anything) + (1+ (regexp "\\S-"))) + p + t) + (let* ((str (match-string-no-properties 0)) + (split (split-string str (rx (| space "\n")) t)) + (val (car (last split))) + (end (point))) + (when (and (equal p end) + (not (string-match-p "#" val))) + (setq prefix-value val) + (backward-char (length val)) + (setq prefix-start (point)) + (setq prefix-end end) + (setq + prefix-type + (if (not (equal "LANGUAGE" pragma-value)) + 'haskell-completions-ghc-option-prefix + 'haskell-completions-language-extension-prefix + ))))))))))))) + (when prefix-value + (list prefix-start prefix-end prefix-value prefix-type))))) + +(defun haskell-completions-grab-identifier-prefix () + "Grab completion prefix for identifier at point. +Returns a list of form '(prefix-start-position +prefix-end-position prefix-value prefix-type) for haskell +identifier at point depending on result of function +`haskell-ident-pos-at-point'." + (let ((pos-at-point (haskell-ident-pos-at-point)) + (p (point))) + (when pos-at-point + (let* ((start (car pos-at-point)) + (end (cdr pos-at-point)) + (type 'haskell-completions-identifier-prefix) + (case-fold-search nil) + value) + ;; we need end position of result, becase of + ;; `haskell-ident-pos-at-point' ignores trailing whitespace, e.g. the + ;; result will be same for `map|` and `map |` invocations. + (when (<= p end) + (setq end p) + (setq value (buffer-substring-no-properties start end)) + (when (string-match-p (rx bos upper) value) + ;; we need to check if found identifier is a module name + (save-excursion + (goto-char (line-beginning-position)) + (when (re-search-forward + (rx "import" + (? (1+ space) "qualified") + (1+ space) + upper + (1+ (| alnum "."))) + p ;; bound + t) ;; no-error + (if (equal p (point)) + (setq type 'haskell-completions-module-name-prefix) + (when (re-search-forward + (rx (| " as " "(")) + start + t) + ;; but uppercase ident could occur after `as` keyword, or in + ;; module imports after opening parenthesis, in this case + ;; restore identifier type again, it's neccessary to + ;; distinguish the means of completions retrieval + (setq type 'haskell-completions-identifier-prefix)))))) + (when (nth 8 (syntax-ppss)) + ;; eighth element of syntax-ppss result is string or comment start, + ;; so when it's not nil word at point is inside string or comment, + ;; return special literal prefix type + (setq type 'haskell-completions-general-prefix)) + ;; finally take in account minlen if given and return the result + (when value (list start end value type))))))) + +(defun haskell-completions-grab-prefix (&optional minlen) + "Grab prefix at point for possible completion. +Returns a list of form '(prefix-start-position +prefix-end-position prefix-value prefix-type) depending on +situation, e.g. is it needed to complete pragma, module name, +arbitrary identifier, etc. Returns nil in case it is +impossible to grab prefix. + +Possible prefix types are: + +* haskell-completions-pragma-name-prefix +* haskell-completions-ghc-option-prefix +* haskell-completions-language-extension-prefix +* haskell-completions-module-name-prefix +* haskell-completions-identifier-prefix +* haskell-completions-general-prefix + +the last type is used in cases when completing things inside comments. + +If provided optional MINLEN parameter this function will return +result only if prefix length is not less than MINLEN." + (when (haskell-completions-can-grab-prefix) + (let ((prefix (cond + ((haskell-completions-grab-pragma-prefix)) + ((haskell-completions-grab-identifier-prefix))))) + (cond ((and minlen prefix) + (when (>= (length (nth 2 prefix)) minlen) + prefix)) + (prefix prefix))))) + +(defun haskell-completions--simple-completions (prefix) + "Provide a list of completion candidates for given PREFIX. +This function is used internally in +`haskell-completions-completion-at-point' and +`haskell-completions-sync-repl-completion-at-point'. + +It provides completions for haskell keywords, language pragmas, +GHC's options, and language extensions. + +PREFIX should be a list such one returned by +`haskell-completions-grab-identifier-prefix'." + (cl-destructuring-bind (beg end _pfx typ) prefix + (when (not (eql typ 'haskell-completions-general-prefix)) + (let ((candidates + (cl-case typ + ('haskell-completions-pragma-name-prefix + haskell-completions--pragma-names) + ('haskell-completions-ghc-option-prefix + haskell-ghc-supported-options) + ('haskell-completions-language-extension-prefix + haskell-ghc-supported-extensions) + (otherwise + (append (when (bound-and-true-p haskell-tags-on-save) + tags-completion-table) + haskell-completions--keywords))))) + (list beg end candidates))))) + +;;;###autoload +(defun haskell-completions-completion-at-point () + "Provide completion list for thing at point. +This function is used in non-interactive `haskell-mode'. It +provides completions for haskell keywords, language pragmas, +GHC's options, and language extensions, but not identifiers." + (let ((prefix (haskell-completions-grab-prefix))) + (when prefix + (haskell-completions--simple-completions prefix)))) + +(defun haskell-completions-sync-repl-completion-at-point () + "A completion function used in `interactive-haskell-mode'. +Completion candidates are provided quering current haskell +process, that is sending `:complete repl' command. + +Completes all possible things: everything that can be completed +with non-interactive function +`haskell-completions-completion-at-point' plus identifier +completions. + +Returns nil if no completions available." + (let ((prefix-data (haskell-completions-grab-prefix))) + (when prefix-data + (cl-destructuring-bind (beg end pfx typ) prefix-data + (when (and (not (eql typ 'haskell-completions-general-prefix)) + (or haskell-completions-complete-operators + (not (save-excursion + (goto-char (1- end)) + (haskell-mode--looking-at-varsym))))) + ;; do not complete things in comments + (if (cl-member + typ + '(haskell-completions-pragma-name-prefix + haskell-completions-ghc-option-prefix + haskell-completions-language-extension-prefix)) + ;; provide simple completions + (haskell-completions--simple-completions prefix-data) + ;; only two cases left: haskell-completions-module-name-prefix + ;; and haskell-completions-identifier-prefix + (let* ((is-import (eql typ 'haskell-completions-module-name-prefix)) + (candidates + (when (and (haskell-session-maybe) + (not (haskell-process-cmd + (haskell-interactive-process))) + ;; few possible extra checks would be: + ;; (haskell-process-get 'is-restarting) + ;; (haskell-process-get 'evaluating) + ) + ;; if REPL is available and not busy try to query it for + ;; completions list in case of module name or identifier + ;; prefixes + (haskell-completions-sync-complete-repl pfx is-import)))) + ;; append candidates with keywords + (list beg end (append + candidates + haskell-completions--keywords))))))))) + +(defun haskell-completions-sync-complete-repl (prefix &optional import) + "Return completion list for given PREFIX querying REPL synchronously. +When optional IMPORT argument is non-nil complete PREFIX +prepending \"import \" keyword (useful for module names). This +function is supposed for internal use." + (haskell-process-get-repl-completions + (haskell-interactive-process) + (if import + (concat "import " prefix) + prefix))) + +(provide 'haskell-completions) +;;; haskell-completions.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-completions.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-completions.elc new file mode 100644 index 000000000000..dd79847383cc --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-completions.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-customize.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-customize.el new file mode 100644 index 000000000000..2b00751c0faa --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-customize.el @@ -0,0 +1,466 @@ +;;; 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 <http://www.gnu.org/licenses/>. + +;;; 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=<path-to-executable>' if you want to use a different +interactive GHC frontend; use `--ghc-option=<ghc-argument>' 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=<path-to-executable>' if you want to use a different +interactive GHC frontend; use `--ghc-option=<ghc-argument>' 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) + (t + (error "Could not find any installation of GHC."))) + haskell-process-type))) + +(provide 'haskell-customize) diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-customize.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-customize.elc new file mode 100644 index 000000000000..a286303e7aa6 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-customize.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-debug.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-debug.el new file mode 100644 index 000000000000..38a6859bbd2f --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-debug.el @@ -0,0 +1,757 @@ +;;; haskell-debug.el --- Debugging mode via GHCi -*- lexical-binding: t -*- + +;; Copyright © 2014 Chris Done. All rights reserved. +;; 2016 Arthur Fayzrakhmanov + +;; 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 <http://www.gnu.org/licenses/>. + +;;; Code: + +(require 'cl-lib) +(require 'haskell-session) +(require 'haskell-process) +(require 'haskell-interactive-mode) +(require 'haskell-font-lock) +(require 'haskell-utils) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Configuration + +;;;###autoload +(defgroup haskell-debug nil + "Settings for debugging support." + :link '(custom-manual "(haskell-mode)haskell-debug") + :group 'haskell) + +;;;###autoload +(defface haskell-debug-warning-face + '((t :inherit 'compilation-warning)) + "Face for warnings." + :group 'haskell-debug) + +;;;###autoload +(defface haskell-debug-trace-number-face + '((t :weight bold :background "#f5f5f5")) + "Face for numbers in backtrace." + :group 'haskell-debug) + +;;;###autoload +(defface haskell-debug-newline-face + '((t :weight bold :background "#f0f0f0")) + "Face for newlines in trace steps." + :group 'haskell-debug) + +;;;###autoload +(defface haskell-debug-keybinding-face + '((t :inherit 'font-lock-type-face :weight bold)) + "Face for keybindings." + :group 'haskell-debug) + +;;;###autoload +(defface haskell-debug-heading-face + '((t :inherit 'font-lock-keyword-face)) + "Face for headings." + :group 'haskell-debug) + +;;;###autoload +(defface haskell-debug-muted-face + '((t :foreground "#999")) + "Face for muteds." + :group 'haskell-debug) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Mode + +(defvar haskell-debug-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "g") 'haskell-debug/refresh) + (define-key map (kbd "s") 'haskell-debug/step) + (define-key map (kbd "t") 'haskell-debug/trace) + (define-key map (kbd "d") 'haskell-debug/delete) + (define-key map (kbd "b") 'haskell-debug/break-on-function) + (define-key map (kbd "a") 'haskell-debug/abandon) + (define-key map (kbd "c") 'haskell-debug/continue) + (define-key map (kbd "p") 'haskell-debug/previous) + (define-key map (kbd "n") 'haskell-debug/next) + (define-key map (kbd "RET") 'haskell-debug/select) + map) + "Keymap for `haskell-debug-mode'.") + +(define-derived-mode haskell-debug-mode + text-mode "Debug" + "Major mode for debugging Haskell via GHCi.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Globals + +(defvar haskell-debug-history-cache nil + "Cache of the tracing history.") + +(defvar haskell-debug-bindings-cache nil + "Cache of the current step's bindings.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Macros + +(defmacro haskell-debug-with-breakpoints (&rest body) + "Breakpoints need to exist to start stepping." + `(if (haskell-debug-get-breakpoints) + ,@body + (error "No breakpoints to step into!"))) + +(defmacro haskell-debug-with-modules (&rest body) + "Modules need to exist to do debugging stuff." + `(if (haskell-debug-get-modules) + ,@body + (error "No modules loaded!"))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Interactive functions + +(defun haskell-debug/select () + "Select whatever is at point." + (interactive) + (cond + ((get-text-property (point) 'break) + (let ((break (get-text-property (point) 'break))) + (haskell-debug-highlight (plist-get break :path) + (plist-get break :span)))) + ((get-text-property (point) 'module) + (let ((break (get-text-property (point) 'module))) + (haskell-debug-highlight (plist-get break :path)))))) + +(defun haskell-debug/abandon () + "Abandon the current computation." + (interactive) + (haskell-debug-with-breakpoints + (haskell-process-queue-sync-request (haskell-debug-process) ":abandon") + (message "Computation abandoned.") + (setq haskell-debug-history-cache nil) + (setq haskell-debug-bindings-cache nil) + (haskell-debug/refresh))) + +(defun haskell-debug/continue () + "Continue the current computation." + (interactive) + (haskell-debug-with-breakpoints + (haskell-process-queue-sync-request (haskell-debug-process) ":continue") + (message "Computation continued.") + (setq haskell-debug-history-cache nil) + (setq haskell-debug-bindings-cache nil) + (haskell-debug/refresh))) + +(defun haskell-debug/break-on-function () + "Break on function IDENT." + (interactive) + (haskell-debug-with-modules + (let ((ident (read-from-minibuffer "Function: " + (haskell-ident-at-point)))) + (haskell-process-queue-sync-request + (haskell-debug-process) + (concat ":break " + ident)) + (message "Breaking on function: %s" ident) + (haskell-debug/refresh)))) + +(defun haskell-debug/start-step (expr) + "Start stepping EXPR." + (interactive (list (read-from-minibuffer "Expression to step through: "))) + (haskell-debug/step expr)) + +(defun haskell-debug/breakpoint-numbers () + "List breakpoint numbers." + (interactive) + (let ((breakpoints (mapcar (lambda (breakpoint) + (number-to-string (plist-get breakpoint :number))) + (haskell-debug-get-breakpoints)))) + (if (null breakpoints) + (message "No breakpoints.") + (message "Breakpoint(s): %s" + (mapconcat #'identity + breakpoints + ", "))))) + +(defun haskell-debug/next () + "Go to next step to inspect bindings." + (interactive) + (haskell-debug-with-breakpoints + (haskell-debug-navigate "forward"))) + +(defun haskell-debug/previous () + "Go to previous step to inspect the bindings." + (interactive) + (haskell-debug-with-breakpoints + (haskell-debug-navigate "back"))) + +(defun haskell-debug/refresh () + "Refresh the debugger buffer." + (interactive) + (with-current-buffer (haskell-debug-buffer-name (haskell-debug-session)) + (cd (haskell-session-current-dir (haskell-debug-session))) + (let ((inhibit-read-only t) + (p (point))) + (erase-buffer) + (insert (propertize (concat "Debugging " + (haskell-session-name (haskell-debug-session)) + "\n\n") + 'face `((:weight bold)))) + (let ((modules (haskell-debug-get-modules)) + (breakpoints (haskell-debug-get-breakpoints)) + (context (haskell-debug-get-context)) + (history (haskell-debug-get-history))) + (unless modules + (insert (propertize "You have to load a module to start debugging." + 'face + 'haskell-debug-warning-face) + "\n\n")) + (haskell-debug-insert-bindings modules breakpoints context) + (when modules + (haskell-debug-insert-current-context context history) + (haskell-debug-insert-breakpoints breakpoints)) + (haskell-debug-insert-modules modules)) + (insert "\n") + (goto-char (min (point-max) p))))) + +(defun haskell-debug/delete () + "Delete whatever's at the point." + (interactive) + (cond + ((get-text-property (point) 'break) + (let ((break (get-text-property (point) 'break))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (when (y-or-n-p (format "Delete breakpoint #%d?" + (plist-get break :number))) + (haskell-process-queue-sync-request + (haskell-debug-process) + (format ":delete %d" + (plist-get break :number))) + (haskell-debug/refresh)) + (haskell-mode-toggle-interactive-prompt-state t)))))) + +(defun haskell-debug/trace () + "Trace the expression." + (interactive) + (haskell-debug-with-modules + (haskell-debug-with-breakpoints + (let ((expr (read-from-minibuffer "Expression to trace: " + (haskell-ident-at-point)))) + (haskell-process-queue-sync-request + (haskell-debug-process) + (concat ":trace " expr)) + (message "Tracing expression: %s" expr) + (haskell-debug/refresh))))) + +(defun haskell-debug/step (&optional expr) + "Step into the next function." + (interactive) + (haskell-debug-with-breakpoints + (let* ((breakpoints (haskell-debug-get-breakpoints)) + (context (haskell-debug-get-context)) + (string + (haskell-process-queue-sync-request + (haskell-debug-process) + (if expr + (concat ":step " expr) + ":step")))) + (cond + ((string= string "not stopped at a breakpoint\n") + (if haskell-debug-bindings-cache + (progn (setq haskell-debug-bindings-cache nil) + (haskell-debug/refresh)) + (call-interactively 'haskell-debug/start-step))) + (t (let ((maybe-stopped-at (haskell-debug-parse-stopped-at string))) + (cond + (maybe-stopped-at + (setq haskell-debug-bindings-cache + maybe-stopped-at) + (message "Computation paused.") + (haskell-debug/refresh)) + (t + (if context + (message "Computation finished.") + (progn + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (when (y-or-n-p "Computation completed without breaking. Reload the module and retry?") + (message "Reloading and resetting breakpoints...") + (haskell-interactive-mode-reset-error (haskell-debug-session)) + (cl-loop for break in breakpoints + do (haskell-process-queue-sync-request + (haskell-debug-process) + (concat ":load " (plist-get break :path)))) + (cl-loop for break in breakpoints + do (haskell-debug-break break)) + (haskell-debug/step expr)) + (haskell-mode-toggle-interactive-prompt-state t)))))))))) + (haskell-debug/refresh))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Internal functions + +(defun haskell-debug-session () + "Get the Haskell session." + (or (haskell-session-maybe) + (error "No Haskell session associated with this debug + buffer. Please just close the buffer and start again."))) + +(defun haskell-debug-process () + "Get the Haskell session." + (or (haskell-session-process (haskell-session-maybe)) + (error "No Haskell session associated with this debug + buffer. Please just close the buffer and start again."))) + +(defun haskell-debug-buffer-name (session) + "The debug buffer name for the current session." + (format "*debug:%s*" + (haskell-session-name session))) + +(defun haskell-debug-get-breakpoints () + "Get the list of breakpoints currently set." + (let ((string (haskell-process-queue-sync-request + (haskell-debug-process) + ":show breaks"))) + (if (string= string "No active breakpoints.\n") + (list) + (mapcar #'haskell-debug-parse-break-point + (haskell-debug-split-string string))))) + +(defun haskell-debug-get-modules () + "Get the list of modules currently set." + (let ((string (haskell-process-queue-sync-request + (haskell-debug-process) + ":show modules"))) + (if (string= string "") + (list) + (mapcar #'haskell-debug-parse-module + (haskell-debug-split-string string))))) + +(defun haskell-debug-get-context () + "Get the current context." + (let ((string (haskell-process-queue-sync-request + (haskell-debug-process) + ":show context"))) + (if (string= string "") + nil + (haskell-debug-parse-context string)))) + +(defun haskell-debug-get-history () + "Get the step history." + (let ((string (haskell-process-queue-sync-request + (haskell-debug-process) + ":history"))) + (if (or (string= string "") + (string= string "Not stopped at a breakpoint\n")) + nil + (if (string= string "Empty history. Perhaps you forgot to use :trace?\n") + nil + (let ((entries (mapcar #'haskell-debug-parse-history-entry + (cl-remove-if (lambda (line) (or (string= "<end of history>" line) + (string= "..." line))) + (haskell-debug-split-string string))))) + (setq haskell-debug-history-cache + entries) + entries))))) + +(defun haskell-debug-insert-bindings (modules breakpoints context) + "Insert a list of bindings." + (if breakpoints + (progn (haskell-debug-insert-binding "t" "trace an expression") + (haskell-debug-insert-binding "s" "step into an expression") + (haskell-debug-insert-binding "b" "breakpoint" t)) + (progn + (when modules + (haskell-debug-insert-binding "b" "breakpoint")) + (when breakpoints + (haskell-debug-insert-binding "s" "step into an expression" t)))) + (when breakpoints + (haskell-debug-insert-binding "d" "delete breakpoint")) + (when context + (haskell-debug-insert-binding "a" "abandon context") + (haskell-debug-insert-binding "c" "continue" t)) + (when context + (haskell-debug-insert-binding "p" "previous step") + (haskell-debug-insert-binding "n" "next step" t)) + (haskell-debug-insert-binding "g" "refresh" t) + (insert "\n")) + +(defun haskell-debug-insert-current-context (context history) + "Insert the current context." + (haskell-debug-insert-header "Context") + (if context + (haskell-debug-insert-context context history) + (haskell-debug-insert-debug-finished)) + (insert "\n")) + +(defun haskell-debug-insert-breakpoints (breakpoints) + "insert the list of breakpoints." + (haskell-debug-insert-header "Breakpoints") + (if (null breakpoints) + (haskell-debug-insert-muted "No active breakpoints.") + (cl-loop for break in breakpoints + do (insert (propertize (format "%d" + (plist-get break :number)) + 'face `((:weight bold)) + 'break break) + (haskell-debug-muted " - ") + (propertize (plist-get break :module) + 'break break + 'break break) + (haskell-debug-muted + (format " (%d:%d)" + (plist-get (plist-get break :span) :start-line) + (plist-get (plist-get break :span) :start-col))) + "\n"))) + (insert "\n")) + +(defun haskell-debug-insert-modules (modules) + "Insert the list of modules." + (haskell-debug-insert-header "Modules") + (if (null modules) + (haskell-debug-insert-muted "No loaded modules.") + (progn (cl-loop for module in modules + do (insert (propertize (plist-get module :module) + 'module module + 'face `((:weight bold))) + (haskell-debug-muted " - ") + (propertize (file-name-nondirectory (plist-get module :path)) + 'module module)) + do (insert "\n"))))) + +(defun haskell-debug-split-string (string) + "Split GHCi's line-based output, stripping the trailing newline." + (split-string string "\n" t)) + +(defun haskell-debug-parse-context (string) + "Parse the context." + (cond + ((string-match "^--> \\(.+\\)\n \\(.+\\)" string) + (let ((name (match-string 1 string)) + (stopped (haskell-debug-parse-stopped-at (match-string 2 string)))) + (list :name name + :path (plist-get stopped :path) + :span (plist-get stopped :span)))))) + +(defun haskell-debug-insert-binding (binding desc &optional end) + "Insert a helpful keybinding." + (insert (propertize binding 'face 'haskell-debug-keybinding-face) + (haskell-debug-muted " - ") + desc + (if end + "\n" + (haskell-debug-muted ", ")))) + +(defun haskell-debug-insert-header (title) + "Insert a header title." + (insert (propertize title + 'face 'haskell-debug-heading-face) + "\n\n")) + +(defun haskell-debug-insert-context (context history) + "Insert the context and history." + (when context + (insert (propertize (plist-get context :name) 'face `((:weight bold))) + (haskell-debug-muted " - ") + (file-name-nondirectory (plist-get context :path)) + (haskell-debug-muted " (stopped)") + "\n")) + (when haskell-debug-bindings-cache + (insert "\n") + (let ((bindings haskell-debug-bindings-cache)) + (insert + (haskell-debug-get-span-string + (plist-get bindings :path) + (plist-get bindings :span))) + (insert "\n\n") + (cl-loop for binding in (plist-get bindings :types) + do (insert (haskell-fontify-as-mode binding 'haskell-mode) + "\n")))) + (let ((history (or history + (list (haskell-debug-make-fake-history context))))) + (when history + (insert "\n") + (haskell-debug-insert-history history)))) + +(defun haskell-debug-insert-debug-finished () + "Insert message that no debugging is happening, but if there is +some old history, then display that." + (if haskell-debug-history-cache + (progn (haskell-debug-insert-muted "Finished debugging.") + (insert "\n") + (haskell-debug-insert-history haskell-debug-history-cache)) + (haskell-debug-insert-muted "Not debugging right now."))) + +(defun haskell-debug-insert-muted (text) + "Insert some muted text." + (insert (haskell-debug-muted text) + "\n")) + +(defun haskell-debug-muted (text) + "Make some muted text." + (propertize text 'face 'haskell-debug-muted-face)) + +(defun haskell-debug-parse-logged (string) + "Parse the logged breakpoint." + (cond + ((string= "no more logged breakpoints\n" string) + nil) + ((string= "already at the beginning of the history\n" string) + nil) + (t + (with-temp-buffer + (insert string) + (goto-char (point-min)) + (list :path (progn (search-forward " at ") + (buffer-substring-no-properties + (point) + (1- (search-forward ":")))) + :span (haskell-debug-parse-span + (buffer-substring-no-properties + (point) + (line-end-position))) + :types (progn (forward-line) + (haskell-debug-split-string + (buffer-substring-no-properties + (point) + (point-max))))))))) + +(defun haskell-debug-parse-stopped-at (string) + "Parse the location stopped at from the given string. + +For example: + +Stopped at /home/foo/project/src/x.hs:6:25-36 + +" + (let ((index (string-match "Stopped at \\([^:]+\\):\\(.+\\)\n?" + string))) + (when index + (list :path (match-string 1 string) + :span (haskell-debug-parse-span (match-string 2 string)) + :types (cdr (haskell-debug-split-string (substring string index))))))) + +(defun haskell-debug-get-span-string (path span) + "Get the string from the PATH and the SPAN." + (save-window-excursion + (find-file path) + (buffer-substring + (save-excursion + (goto-char (point-min)) + (forward-line (1- (plist-get span :start-line))) + (forward-char (1- (plist-get span :start-col))) + (point)) + (save-excursion + (goto-char (point-min)) + (forward-line (1- (plist-get span :end-line))) + (forward-char (plist-get span :end-col)) + (point))))) + +(defun haskell-debug-make-fake-history (context) + "Make a fake history item." + (list :index -1 + :path (plist-get context :path) + :span (plist-get context :span))) + +(defun haskell-debug-insert-history (history) + "Insert tracing HISTORY." + (let ((i (length history))) + (cl-loop for span in history + do (let ((string (haskell-debug-get-span-string + (plist-get span :path) + (plist-get span :span)))) + (insert (propertize (format "%4d" i) + 'face 'haskell-debug-trace-number-face) + " " + (haskell-debug-preview-span + (plist-get span :span) + string + t) + "\n") + (setq i (1- i)))))) + +(defun haskell-debug-parse-span (string) + "Parse a source span from a string. + +Examples: + + (5,1)-(6,37) + 6:25-36 + 5:20 + +People like to make other people's lives interesting by making +variances in source span notation." + (cond + ((string-match "\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\)" + string) + (list :start-line (string-to-number (match-string 1 string)) + :start-col (string-to-number (match-string 2 string)) + :end-line (string-to-number (match-string 1 string)) + :end-col (string-to-number (match-string 3 string)))) + ((string-match "\\([0-9]+\\):\\([0-9]+\\)" + string) + (list :start-line (string-to-number (match-string 1 string)) + :start-col (string-to-number (match-string 2 string)) + :end-line (string-to-number (match-string 1 string)) + :end-col (string-to-number (match-string 2 string)))) + ((string-match "(\\([0-9]+\\),\\([0-9]+\\))-(\\([0-9]+\\),\\([0-9]+\\))" + string) + (list :start-line (string-to-number (match-string 1 string)) + :start-col (string-to-number (match-string 2 string)) + :end-line (string-to-number (match-string 3 string)) + :end-col (string-to-number (match-string 4 string)))) + (t (error "Unable to parse source span from string: %s" + string)))) + +(defun haskell-debug-preview-span (span string &optional collapsed) + "Make a one-line preview of the given expression." + (with-temp-buffer + (haskell-mode) + (insert string) + (when (/= 0 (plist-get span :start-col)) + (indent-rigidly (point-min) + (point-max) + 1)) + (if (fboundp 'font-lock-ensure) + (font-lock-ensure) + (with-no-warnings (font-lock-fontify-buffer))) + (when (/= 0 (plist-get span :start-col)) + (indent-rigidly (point-min) + (point-max) + -1)) + (goto-char (point-min)) + (if collapsed + (replace-regexp-in-string + "\n[ ]*" + (propertize " " 'face 'haskell-debug-newline-face) + (buffer-substring (point-min) + (point-max))) + (buffer-string)))) + +(defun haskell-debug-start (session) + "Start the debug mode." + (setq buffer-read-only t) + (haskell-session-assign session) + (haskell-debug/refresh)) + +(defun haskell-debug () + "Start the debugger for the current Haskell (GHCi) session." + (interactive) + (let ((session (haskell-debug-session))) + (switch-to-buffer-other-window (haskell-debug-buffer-name session)) + (unless (eq major-mode 'haskell-debug-mode) + (haskell-debug-mode) + (haskell-debug-start session)))) + +(defun haskell-debug-break (break) + "Set BREAK breakpoint in module at line/col." + (haskell-process-queue-without-filters + (haskell-debug-process) + (format ":break %s %s %d" + (plist-get break :module) + (plist-get (plist-get break :span) :start-line) + (plist-get (plist-get break :span) :start-col)))) + +(defun haskell-debug-navigate (direction) + "Navigate in DIRECTION \"back\" or \"forward\"." + (let ((string (haskell-process-queue-sync-request + (haskell-debug-process) + (concat ":" direction)))) + (let ((bindings (haskell-debug-parse-logged string))) + (setq haskell-debug-bindings-cache + bindings) + (when (not bindings) + (message "No more %s results!" direction))) + (haskell-debug/refresh))) + +(defun haskell-debug-session-debugging-p (session) + "Does the session have a debugging buffer open?" + (not (not (get-buffer (haskell-debug-buffer-name session))))) + +(defun haskell-debug-highlight (path &optional span) + "Highlight the file at span." + (let ((p (make-overlay + (line-beginning-position) + (line-end-position)))) + (overlay-put p 'face `((:background "#eee"))) + (with-current-buffer + (if span + (save-window-excursion + (find-file path) + (current-buffer)) + (find-file path) + (current-buffer)) + (let ((o (when span + (make-overlay + (save-excursion + (goto-char (point-min)) + (forward-line (1- (plist-get span :start-line))) + (forward-char (1- (plist-get span :start-col))) + (point)) + (save-excursion + (goto-char (point-min)) + (forward-line (1- (plist-get span :end-line))) + (forward-char (plist-get span :end-col)) + (point)))))) + (when o + (overlay-put o 'face `((:background "#eee")))) + (sit-for 0.5) + (when o + (delete-overlay o)) + (delete-overlay p))))) + +(defun haskell-debug-parse-history-entry (string) + "Parse a history entry." + (if (string-match "^\\([-0-9]+\\)[ ]+:[ ]+\\([A-Za-z0-9_':]+\\)[ ]+(\\([^:]+\\):\\(.+?\\))$" + string) + (list :index (string-to-number (match-string 1 string)) + :name (match-string 2 string) + :path (match-string 3 string) + :span (haskell-debug-parse-span (match-string 4 string))) + (error "Unable to parse history entry: %s" string))) + +(defun haskell-debug-parse-module (string) + "Parse a module and path. + +For example: + +X ( /home/foo/X.hs, interpreted ) +Main ( /home/foo/X.hs, /home/foo/X.o ) +" + (if (string-match "\\([^ ]+\\)[ ]+( \\([^ ]+?\\), [/a-zA-Z0-9\.]+ )$" + string) + (list :module (match-string 1 string) + :path (match-string 2 string)) + (error "Unable to parse module from string: %s" + string))) + +(defun haskell-debug-parse-break-point (string) + "Parse a breakpoint number, module and location from a string. + +For example: + +[13] Main /home/foo/src/x.hs:(5,1)-(6,37) + +" + (if (string-match "^\\[\\([0-9]+\\)\\] \\([^ ]+\\) \\([^:]+\\):\\(.+\\)$" + string) + (list :number (string-to-number (match-string 1 string)) + :module (match-string 2 string) + :path (match-string 3 string) + :span (haskell-debug-parse-span (match-string 4 string))) + (error "Unable to parse breakpoint from string: %s" + string))) + +(provide 'haskell-debug) + +;;; haskell-debug.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-debug.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-debug.elc new file mode 100644 index 000000000000..4eb01e9eecf1 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-debug.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-decl-scan.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-decl-scan.el new file mode 100644 index 000000000000..75da0a9d6b92 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-decl-scan.el @@ -0,0 +1,687 @@ +;;; haskell-decl-scan.el --- Declaration scanning module for Haskell Mode -*- lexical-binding: t -*- + +;; Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. +;; Copyright (C) 1997-1998 Graeme E Moss +;; Copyright (C) 2016 Chris Gregory + +;; Author: 1997-1998 Graeme E Moss <gem@cs.york.ac.uk> +;; Maintainer: Stefan Monnier <monnier@gnu.org> +;; Keywords: declarations menu files Haskell +;; URL: http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/CONTRIB/haskell-modes/emacs/haskell-decl-scan.el?rev=HEAD + +;; This file is not part of GNU Emacs. + +;; 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Purpose: +;; +;; Top-level declarations are scanned and placed in a menu. Supports +;; full Latin1 Haskell 1.4 as well as literate scripts. +;; +;; +;; Installation: +;; +;; To turn declaration scanning on for all Haskell buffers under the +;; Haskell mode of Moss&Thorn, add this to .emacs: +;; +;; (add-hook 'haskell-mode-hook 'haskell-decl-scan-mode) +;; +;; Otherwise, call `haskell-decl-scan-mode'. +;; +;; +;; Customisation: +;; +;; M-x customize-group haskell-decl-scan +;; +;; +;; History: +;; +;; If you have any problems or suggestions, after consulting the list +;; below, email gem@cs.york.ac.uk quoting the version of the library +;; you are using, the version of Emacs you are using, and a small +;; example of the problem or suggestion. Note that this library +;; requires a reasonably recent version of Emacs. +;; +;; Uses `imenu' under Emacs. +;; +;; Version 1.2: +;; Added support for LaTeX-style literate scripts. +;; +;; Version 1.1: +;; Use own syntax table. Fixed bug for very small buffers. Use +;; markers instead of pointers (markers move with the text). +;; +;; Version 1.0: +;; Brought over from Haskell mode v1.1. +;; +;; +;; Present Limitations/Future Work (contributions are most welcome!): +;; +;; . Declarations requiring information extending beyond starting line +;; don't get scanned properly, eg. +;; > class Eq a => +;; > Test a +;; +;; . Comments placed in the midst of the first few lexemes of a +;; declaration will cause havoc, eg. +;; > infixWithComments :: Int -> Int -> Int +;; > x {-nastyComment-} `infixWithComments` y = x + y +;; but are not worth worrying about. +;; +;; . Would be nice to scan other top-level declarations such as +;; methods of a class, datatype field labels... any more? +;; +;; . Support for GreenCard? +;; +;; . Re-running (literate-)haskell-imenu should not cause the problems +;; that it does. The ability to turn off scanning would also be +;; useful. (Note that re-running (literate-)haskell-mode seems to +;; cause no problems.) + +;; All functions/variables start with +;; `(turn-(on/off)-)haskell-decl-scan' or `haskell-ds-'. + +;; The imenu support is based on code taken from `hugs-mode', +;; thanks go to Chris Van Humbeeck. + +;; Version. + +;;; Code: + +(require 'cl-lib) +(require 'haskell-mode) +(require 'syntax) +(require 'imenu) + +;;;###autoload +(defgroup haskell-decl-scan nil + "Haskell declaration scanning (`imenu' support)." + :link '(custom-manual "(haskell-mode)haskell-decl-scan-mode") + :group 'haskell + :prefix "haskell-decl-scan-") + +(defcustom haskell-decl-scan-bindings-as-variables nil + "Whether to put top-level value bindings into a \"Variables\" category." + :group 'haskell-decl-scan + :type 'boolean) + +(defcustom haskell-decl-scan-add-to-menubar t + "Whether to add a \"Declarations\" menu entry to menu bar." + :group 'haskell-decl-scan + :type 'boolean) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; General declaration scanning functions. + +(defvar haskell-ds-start-keywords-re + (concat "\\(\\<" + "class\\|data\\|i\\(mport\\|n\\(fix\\(\\|[lr]\\)\\|stance\\)\\)\\|" + "module\\|primitive\\|type\\|newtype" + "\\)\\>") + "Keywords that may start a declaration.") + +(defvar haskell-ds-syntax-table + (let ((table (copy-syntax-table haskell-mode-syntax-table))) + (modify-syntax-entry ?\' "w" table) + (modify-syntax-entry ?_ "w" table) + (modify-syntax-entry ?\\ "_" table) + table) + "Syntax table used for Haskell declaration scanning.") + + +(defun haskell-ds-get-variable (prefix) + "Return variable involved in value binding or type signature. +Assumes point is looking at the regexp PREFIX followed by the +start of a declaration (perhaps in the middle of a series of +declarations concerning a single variable). Otherwise return nil. +Point is not changed." + ;; I think I can now handle all declarations bar those with comments + ;; nested before the second lexeme. + (save-excursion + (with-syntax-table haskell-ds-syntax-table + (if (looking-at prefix) (goto-char (match-end 0))) + ;; Keyword. + (if (looking-at haskell-ds-start-keywords-re) + nil + (or ;; Parenthesized symbolic variable. + (and (looking-at "(\\(\\s_+\\))") (match-string-no-properties 1)) + ;; General case. + (if (looking-at + (if (eq ?\( (char-after)) + ;; Skip paranthesised expression. + (progn + (forward-sexp) + ;; Repeating this code and avoiding moving point if + ;; possible speeds things up. + "\\(\\'\\)?\\s-*\\(\\s_+\\|`\\(\\sw+\\)`\\)") + "\\(\\sw+\\)?\\s-*\\(\\s_+\\|`\\(\\sw+\\)`\\)")) + (let ((match2 (match-string-no-properties 2))) + ;; Weed out `::', `∷',`=' and `|' from potential infix + ;; symbolic variable. + (if (member match2 '("::" "∷" "=" "|")) + ;; Variable identifier. + (match-string-no-properties 1) + (if (eq (aref match2 0) ?\`) + ;; Infix variable identifier. + (match-string-no-properties 3) + ;; Infix symbolic variable. + match2)))) + ;; Variable identifier. + (and (looking-at "\\sw+") (match-string-no-properties 0))))))) + +(defun haskell-ds-move-to-start-regexp (inc regexp) + "Move to beginning of line that succeeds/precedes (INC = 1/-1) +current line that starts with REGEXP and is not in `font-lock-comment-face'." + ;; Making this defsubst instead of defun appears to have little or + ;; no effect on efficiency. It is probably not called enough to do + ;; so. + (while (and (= (forward-line inc) 0) + (or (not (looking-at regexp)) + (eq (get-text-property (point) 'face) + 'font-lock-comment-face))))) + +(defun haskell-ds-move-to-start-regexp-skipping-comments (inc regexp) + "Like haskell-ds-move-to-start-regexp, but uses syntax-ppss to + skip comments" + (let (p) + (cl-loop + do (setq p (point)) + (haskell-ds-move-to-start-regexp inc regexp) + while (and (nth 4 (syntax-ppss)) + (/= p (point)))))) + +(defvar literate-haskell-ds-line-prefix "> ?" + "Regexp matching start of a line of Bird-style literate code. +Current value is \"> \" as we assume top-level declarations start +at column 3. Must not contain the special \"^\" regexp as we may +not use the regexp at the start of a regexp string. Note this is +only for `imenu' support.") + +(defvar haskell-ds-start-decl-re "\\(\\sw\\|(\\)" + "The regexp that starts a Haskell declaration.") + +(defvar literate-haskell-ds-start-decl-re + (concat literate-haskell-ds-line-prefix haskell-ds-start-decl-re) + "The regexp that starts a Bird-style literate Haskell declaration.") + +(defun haskell-ds-whitespace-p (char) + "Test if CHAR is a whitespace character." + ;; the nil is a bob/eob test + (member char '(nil ?\t ?\n ?\ ))) + +(defun haskell-ds-move-to-decl (direction bird-literate fix) + "General function for moving to the start of a declaration, +either forwards or backwards from point, with normal or with Bird-style +literate scripts. If DIRECTION is t, then forward, else backward. If +BIRD-LITERATE is t, then treat as Bird-style literate scripts, else +normal scripts. Returns point if point is left at the start of a +declaration, and nil otherwise, ie. because point is at the beginning +or end of the buffer and no declaration starts there. If FIX is t, +then point does not move if already at the start of a declaration." + ;; As `haskell-ds-get-variable' cannot separate an infix variable + ;; identifier out of a value binding with non-alphanumeric first + ;; argument, this function will treat such value bindings as + ;; separate from the declarations surrounding it. + (let ( ;; The variable typed or bound in the current series of + ;; declarations. + name + ;; The variable typed or bound in the new declaration. + newname + ;; Hack to solve hard problem for Bird-style literate scripts + ;; that start with a declaration. We are in the abyss if + ;; point is before start of this declaration. + abyss + (line-prefix (if bird-literate literate-haskell-ds-line-prefix "")) + ;; The regexp to match for the start of a declaration. + (start-decl-re (if bird-literate + literate-haskell-ds-start-decl-re + haskell-ds-start-decl-re)) + (increment (if direction 1 -1)) + (bound (if direction (point-max) (point-min)))) + ;; Change syntax table. + (with-syntax-table haskell-ds-syntax-table + ;; move to beginning of line that starts the "current + ;; declaration" (dependent on DIRECTION and FIX), and then get + ;; the variable typed or bound by this declaration, if any. + (let ( ;; Where point was at call of function. + (here (point)) + ;; Where the declaration on this line (if any) starts. + (start (progn + (beginning-of-line) + ;; Checking the face to ensure a declaration starts + ;; here seems to be the only addition to make this + ;; module support LaTeX-style literate scripts. + (if (and (looking-at start-decl-re) + (not (elt (syntax-ppss) 4))) + (match-beginning 1))))) + (if (and start + ;; This complicated boolean determines whether we + ;; should include the declaration that starts on the + ;; current line as the "current declaration" or not. + (or (and (or (and direction (not fix)) + (and (not direction) fix)) + (>= here start)) + (and (or (and direction fix) + (and (not direction) (not fix))) + (> here start)))) + ;; If so, we are already at start of the current line, so + ;; do nothing. + () + ;; If point was before start of a declaration on the first + ;; line of the buffer (possible for Bird-style literate + ;; scripts) then we are in the abyss. + (if (and start (bobp)) + (setq abyss t) + ;; Otherwise we move to the start of the first declaration + ;; on a line preceding the current one, skipping comments + (haskell-ds-move-to-start-regexp-skipping-comments -1 start-decl-re)))) + ;; If we are in the abyss, position and return as appropriate. + (if abyss + (if (not direction) + nil + (re-search-forward (concat "\\=" line-prefix) nil t) + (point)) + ;; Get the variable typed or bound by this declaration, if any. + (setq name (haskell-ds-get-variable line-prefix)) + (if (not name) + ;; If no such variable, stop at the start of this + ;; declaration if moving backward, or move to the next + ;; declaration if moving forward. + (if direction + (haskell-ds-move-to-start-regexp-skipping-comments 1 start-decl-re)) + ;; If there is a variable, find the first + ;; succeeding/preceding declaration that does not type or + ;; bind it. Check for reaching start/end of buffer and + ;; comments. + (haskell-ds-move-to-start-regexp-skipping-comments increment start-decl-re) + (while (and (/= (point) bound) + (and (setq newname (haskell-ds-get-variable line-prefix)) + (string= name newname))) + (setq name newname) + (haskell-ds-move-to-start-regexp-skipping-comments increment start-decl-re)) + ;; If we are going backward, and have either reached a new + ;; declaration or the beginning of a buffer that does not + ;; start with a declaration, move forward to start of next + ;; declaration (which must exist). Otherwise, we are done. + (if (and (not direction) + (or (and (looking-at start-decl-re) + (not (string= name + ;; Note we must not use + ;; newname here as this may + ;; not have been set if we + ;; have reached the beginning + ;; of the buffer. + (haskell-ds-get-variable + line-prefix)))) + (and (not (looking-at start-decl-re)) + (bobp)))) + (haskell-ds-move-to-start-regexp-skipping-comments 1 start-decl-re))) + ;; Store whether we are at the start of a declaration or not. + ;; Used to calculate final result. + (let ((at-start-decl (looking-at start-decl-re))) + ;; If we are at the beginning of a line, move over + ;; line-prefix, if present at point. + (if (bolp) + (re-search-forward (concat "\\=" line-prefix) (point-max) t)) + ;; Return point if at the start of a declaration and nil + ;; otherwise. + (if at-start-decl (point) nil)))))) + +(defun haskell-ds-bird-p () + (and (boundp 'haskell-literate) (eq haskell-literate 'bird))) + +(defun haskell-ds-backward-decl () + "Move backward to the first character that starts a top-level declaration. +A series of declarations concerning one variable is treated as one +declaration by this function. So, if point is within a top-level +declaration then move it to the start of that declaration. If point +is already at the start of a top-level declaration, then move it to +the start of the preceding declaration. Returns point if point is +left at the start of a declaration, and nil otherwise, because +point is at the beginning of the buffer and no declaration starts +there." + (interactive) + (haskell-ds-move-to-decl nil (haskell-ds-bird-p) nil)) + +(defun haskell-ds-comment-p + (&optional + pt) + "Test if the cursor is on whitespace or a comment. + +`PT' defaults to `(point)'" + ;; ensure result is `t' or `nil' instead of just truthy + (if (or + ;; is cursor on whitespace + (haskell-ds-whitespace-p (following-char)) + ;; http://emacs.stackexchange.com/questions/14269/how-to-detect-if-the-point-is-within-a-comment-area + ;; is cursor at begging, inside, or end of comment + (let ((fontfaces (get-text-property (or pt + (point)) 'face))) + (when (not (listp fontfaces)) + (setf fontfaces (list fontfaces))) + (delq nil (mapcar + #'(lambda (f) + (member f '(font-lock-comment-face + font-lock-doc-face + font-lock-comment-delimiter-face))) + fontfaces)))) + t + nil)) + +(defun haskell-ds-line-commented-p () + "Tests if all characters from `point' to `end-of-line' pass +`haskell-ds-comment-p'" + (let ((r t)) + (while (and r (not (eolp))) + (if (not (haskell-ds-comment-p)) + (setq r nil)) + (forward-char)) + r)) + +(defun haskell-ds-forward-decl () + "Move forward to the first character that starts a top-level +declaration. As `haskell-ds-backward-decl' but forward." + (interactive) + (let ((p (point)) b e empty was-at-bob) + ;; Go back to beginning of defun, then go to beginning of next + (haskell-ds-move-to-decl nil (haskell-ds-bird-p) nil) + (setq b (point)) + (haskell-ds-move-to-decl t (haskell-ds-bird-p) nil) + (setq e (point)) + ;; tests if line is empty + (setq empty (and (<= (point) p) + (not (eolp)))) + (setq was-at-bob (and (= (point-min) b) + (= b p) + (< p e))) + ;; this conditional allows for when empty lines at end, first + ;; `C-M-e' will go to end of defun, next will go to end of file. + (when (or was-at-bob + empty) + (if (or (and was-at-bob + (= ?\n + (save-excursion + (goto-char (point-min)) + (following-char)))) + empty) + (haskell-ds-move-to-decl t (haskell-ds-bird-p) nil)) + ;; Then go back to end of current + (forward-line -1) + (while (and (haskell-ds-line-commented-p) + ;; prevent infinite loop + (not (bobp))) + (forward-line -1)) + (forward-line 1))) + (point)) + +(defun haskell-ds-generic-find-next-decl (bird-literate) + "Find the name, position and type of the declaration at or after point. +Return ((NAME . (START-POSITION . NAME-POSITION)) . TYPE) +if one exists and nil otherwise. The start-position is at the start +of the declaration, and the name-position is at the start of the name +of the declaration. The name is a string, the positions are buffer +positions and the type is one of the symbols \"variable\", \"datatype\", +\"class\", \"import\" and \"instance\"." + (let ( ;; The name, type and name-position of the declaration to + ;; return. + name + type + name-pos + ;; Buffer positions marking the start and end of the space + ;; containing a declaration. + start + end) + ;; Change to declaration scanning syntax. + (with-syntax-table haskell-ds-syntax-table + ;; Stop when we are at the end of the buffer or when a valid + ;; declaration is grabbed. + (while (not (or (eobp) name)) + ;; Move forward to next declaration at or after point. + (haskell-ds-move-to-decl t bird-literate t) + ;; Start and end of search space is currently just the starting + ;; line of the declaration. + (setq start (point) + end (line-end-position)) + (cond + ;; If the start of the top-level declaration does not begin + ;; with a starting keyword, then (if legal) must be a type + ;; signature or value binding, and the variable concerned is + ;; grabbed. + ((not (looking-at haskell-ds-start-keywords-re)) + (setq name (haskell-ds-get-variable "")) + (if name + (progn + (setq type 'variable) + (re-search-forward (regexp-quote name) end t) + (setq name-pos (match-beginning 0))))) + ;; User-defined datatype declaration. + ((re-search-forward "\\=\\(data\\|newtype\\|type\\)\\>" end t) + (re-search-forward "=>" end t) + (if (looking-at "[ \t]*\\(\\sw+\\)") + (progn + (setq name (match-string-no-properties 1)) + (setq name-pos (match-beginning 1)) + (setq type 'datatype)))) + ;; Class declaration. + ((re-search-forward "\\=class\\>" end t) + (re-search-forward "=>" end t) + (if (looking-at "[ \t]*\\(\\sw+\\)") + (progn + (setq name (match-string-no-properties 1)) + (setq name-pos (match-beginning 1)) + (setq type 'class)))) + ;; Import declaration. + ((looking-at "import[ \t]+\\(?:safe[\t ]+\\)?\\(?:qualified[ \t]+\\)?\\(?:\"[^\"]*\"[\t ]+\\)?\\(\\(?:\\sw\\|.\\)+\\)") + (setq name (match-string-no-properties 1)) + (setq name-pos (match-beginning 1)) + (setq type 'import)) + ;; Instance declaration. + ((re-search-forward "\\=instance[ \t]+" end t) + (re-search-forward "=>[ \t]+" end t) + ;; The instance "title" starts just after the `instance' (and + ;; any context) and finishes just before the _first_ `where' + ;; if one exists. This solution is ugly, but I can't find a + ;; nicer one---a simple regexp will pick up the last `where', + ;; which may be rare but nevertheless... + (setq name-pos (point)) + (setq name (buffer-substring-no-properties + (point) + (progn + ;; Look for a `where'. + (if (re-search-forward "\\<where\\>" end t) + ;; Move back to just before the `where'. + (progn + (re-search-backward "\\s-where") + (point)) + ;; No `where' so move to last non-whitespace + ;; before `end'. + (progn + (goto-char end) + (skip-chars-backward " \t") + (point)))))) + ;; If we did not manage to extract a name, cancel this + ;; declaration (eg. when line ends in "=> "). + (if (string-match "^[ \t]*$" name) (setq name nil)) + (setq type 'instance))) + ;; Move past start of current declaration. + (goto-char end)) + ;; If we have a valid declaration then return it, otherwise return + ;; nil. + (if name + (cons (cons name (cons (copy-marker start t) (copy-marker name-pos t))) + type) + nil)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Declaration scanning via `imenu'. + +;;;###autoload +(defun haskell-ds-create-imenu-index () + "Function for finding `imenu' declarations in Haskell mode. +Finds all declarations (classes, variables, imports, instances and +datatypes) in a Haskell file for the `imenu' package." + ;; Each list has elements of the form `(INDEX-NAME . INDEX-POSITION)'. + ;; These lists are nested using `(INDEX-TITLE . INDEX-ALIST)'. + (let* ((bird-literate (haskell-ds-bird-p)) + (index-alist '()) + (index-class-alist '()) ;; Classes + (index-var-alist '()) ;; Variables + (index-imp-alist '()) ;; Imports + (index-inst-alist '()) ;; Instances + (index-type-alist '()) ;; Datatypes + ;; Variables for showing progress. + (bufname (buffer-name)) + (divisor-of-progress (max 1 (/ (buffer-size) 100))) + ;; The result we wish to return. + result) + (goto-char (point-min)) + ;; Loop forwards from the beginning of the buffer through the + ;; starts of the top-level declarations. + (while (< (point) (point-max)) + (message "Scanning declarations in %s... (%3d%%)" bufname + (/ (- (point) (point-min)) divisor-of-progress)) + ;; Grab the next declaration. + (setq result (haskell-ds-generic-find-next-decl bird-literate)) + (if result + ;; If valid, extract the components of the result. + (let* ((name-posns (car result)) + (name (car name-posns)) + (posns (cdr name-posns)) + (start-pos (car posns)) + (type (cdr result))) + ;; Place `(name . start-pos)' in the correct alist. + (cl-case type + (variable + (setq index-var-alist + (cl-acons name start-pos index-var-alist))) + (datatype + (setq index-type-alist + (cl-acons name start-pos index-type-alist))) + (class + (setq index-class-alist + (cl-acons name start-pos index-class-alist))) + (import + (setq index-imp-alist + (cl-acons name start-pos index-imp-alist))) + (instance + (setq index-inst-alist + (cl-acons name start-pos index-inst-alist))))))) + ;; Now sort all the lists, label them, and place them in one list. + (message "Sorting declarations in %s..." bufname) + (when index-type-alist + (push (cons "Datatypes" + (sort index-type-alist 'haskell-ds-imenu-label-cmp)) + index-alist)) + (when index-inst-alist + (push (cons "Instances" + (sort index-inst-alist 'haskell-ds-imenu-label-cmp)) + index-alist)) + (when index-imp-alist + (push (cons "Imports" + (sort index-imp-alist 'haskell-ds-imenu-label-cmp)) + index-alist)) + (when index-class-alist + (push (cons "Classes" + (sort index-class-alist 'haskell-ds-imenu-label-cmp)) + index-alist)) + (when index-var-alist + (if haskell-decl-scan-bindings-as-variables + (push (cons "Variables" + (sort index-var-alist 'haskell-ds-imenu-label-cmp)) + index-alist) + (setq index-alist (append index-alist + (sort index-var-alist 'haskell-ds-imenu-label-cmp))))) + (message "Sorting declarations in %s...done" bufname) + ;; Return the alist. + index-alist)) + +(defun haskell-ds-imenu-label-cmp (el1 el2) + "Predicate to compare labels in lists from `haskell-ds-create-imenu-index'." + (string< (car el1) (car el2))) + +(defun haskell-ds-imenu () + "Install `imenu' for Haskell scripts." + (setq imenu-create-index-function 'haskell-ds-create-imenu-index) + (when haskell-decl-scan-add-to-menubar + (imenu-add-to-menubar "Declarations"))) + +;; The main functions to turn on declaration scanning. +;;;###autoload +(defun turn-on-haskell-decl-scan () + "Unconditionally activate `haskell-decl-scan-mode'." + (interactive) + (haskell-decl-scan-mode)) +(make-obsolete 'turn-on-haskell-decl-scan + 'haskell-decl-scan-mode + "2015-07-23") + +;;;###autoload +(define-minor-mode haskell-decl-scan-mode + "Toggle Haskell declaration scanning minor mode on or off. +With a prefix argument ARG, enable minor mode if ARG is +positive, and disable it otherwise. If called from Lisp, enable +the mode if ARG is omitted or nil, and toggle it if ARG is `toggle'. + +See also info node `(haskell-mode)haskell-decl-scan-mode' for +more details about this minor mode. + +Top-level declarations are scanned and listed in the menu item +\"Declarations\" (if enabled via option +`haskell-decl-scan-add-to-menubar'). Selecting an item from this +menu will take point to the start of the declaration. + +\\[beginning-of-defun] and \\[end-of-defun] move forward and backward to the start of a declaration. + +This may link with `haskell-doc-mode'. + +For non-literate and LaTeX-style literate scripts, we assume the +common convention that top-level declarations start at the first +column. For Bird-style literate scripts, we assume the common +convention that top-level declarations start at the third column, +ie. after \"> \". + +Anything in `font-lock-comment-face' is not considered for a +declaration. Therefore, using Haskell font locking with comments +coloured in `font-lock-comment-face' improves declaration scanning. + +Literate Haskell scripts are supported: If the value of +`haskell-literate' (set automatically by `literate-haskell-mode') +is `bird', a Bird-style literate script is assumed. If it is nil +or `tex', a non-literate or LaTeX-style literate script is +assumed, respectively. + +Invokes `haskell-decl-scan-mode-hook' on activation." + :group 'haskell-decl-scan + + (kill-local-variable 'beginning-of-defun-function) + (kill-local-variable 'end-of-defun-function) + (kill-local-variable 'imenu-create-index-function) + (unless haskell-decl-scan-mode + ;; How can we cleanly remove the "Declarations" menu? + (when haskell-decl-scan-add-to-menubar + (local-set-key [menu-bar index] nil))) + + (when haskell-decl-scan-mode + (setq-local beginning-of-defun-function 'haskell-ds-backward-decl) + (setq-local end-of-defun-function 'haskell-ds-forward-decl) + (haskell-ds-imenu))) + + +;; Provide ourselves: + +(provide 'haskell-decl-scan) + +;;; haskell-decl-scan.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-decl-scan.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-decl-scan.elc new file mode 100644 index 000000000000..f00f8d1ebaa6 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-decl-scan.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-doc.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-doc.el new file mode 100644 index 000000000000..5ac49b8f87aa --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-doc.el @@ -0,0 +1,1861 @@ +;;; haskell-doc.el --- show function types in echo area -*- coding: utf-8; lexical-binding: t -*- + +;; Copyright © 2004, 2005, 2006, 2007, 2009, 2016 Free Software Foundation, Inc. +;; Copyright © 1997 Hans-Wolfgang Loidl +;; 2016 Arthur Fayzrakhmanov + +;; Author: Hans-Wolfgang Loidl <hwloidl@dcs.glasgow.ac.uk> +;; Temporary Maintainer and Hacker: Graeme E Moss <gem@cs.york.ac.uk> +;; Keywords: extensions, minor mode, language mode, Haskell +;; Created: 1997-06-17 +;; URL: http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/CONTRIB/haskell-modes/emacs/haskell-doc.el?rev=HEAD + +;; This file is not part of GNU Emacs. + +;; This program 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 program 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This program shows the type of the Haskell function under the cursor in the +;; minibuffer. It acts as a kind of "Emacs background process", by regularly +;; checking the word under the cursor and matching it against a list of +;; prelude, library, local and global functions. + +;; This program was inspired by the `eldoc.el' package by Noah Friedman. + +;; Installation: + +;; Depending on the major mode you use for your Haskell programs add +;; one of the following to your .emacs: +;; +;; (add-hook 'haskell-mode-hook 'haskell-doc-mode) + +;; Customisation: + +;; You can control what exactly is shown by setting the following variables to +;; either t or nil: +;; `haskell-doc-show-global-types' (default: nil) +;; `haskell-doc-show-reserved' (default: t) +;; `haskell-doc-show-prelude' (default: t) +;; `haskell-doc-show-strategy' (default: t) +;; `haskell-doc-show-user-defined' (default: t) + +;; If you want to define your own strings for some identifiers define an +;; alist of (ID . STRING) and set `haskell-doc-show-user-defined' to t. +;; E.g: +;; +;; (setq haskell-doc-show-user-defined t) +;; (setq haskell-doc-user-defined-ids +;; (list +;; '("main" . "just another pathetic main function") +;; '("foo" . "a very dummy name") +;; '("bar" . "another dummy name"))) + +;; The following two variables are useful to make the type fit on one line: +;; If `haskell-doc-chop-off-context' is non-nil the context part of the type +;; of a local fct will be eliminated (default: t). +;; If `haskell-doc-chop-off-fctname' is non-nil the function name is not +;; shown together with the type (default: nil). + +;; Internals: + +;; `haskell-doc-mode' is implemented as a minor-mode. So, you can combine it +;; with any other mode. To enable it just type +;; M-x haskell-doc-mode + +;; These are the names of the functions that can be called directly by the +;; user (with keybindings in `haskell-mode'): +;; `haskell-doc-mode' ... toggle haskell-doc-mode; with prefix turn it on +;; unconditionally if the prefix is greater 0 otherwise +;; turn it off +;; Key: CTRL-c CTRL-o (CTRL-u CTRL-c CTRL-o) +;; `haskell-doc-ask-mouse-for-type' ... show the type of the id under the mouse +;; Key: C-S-M-mouse-3 +;; `haskell-doc-show-reserved' ... toggle echoing of reserved id's types +;; `haskell-doc-show-prelude' ... toggle echoing of prelude id's types +;; `haskell-doc-show-strategy' ... toggle echoing of strategy id's types +;; `haskell-doc-show-user-defined' ... toggle echoing of user def id's types +;; `haskell-doc-check-active' ... check whether haskell-doc is active; +;; Key: CTRL-c ESC-/ + +;; ToDo: + +;; - Fix byte-compile problems in `haskell-doc-prelude-types' for getArgs etc +;; - Write a parser for .hi files. Read library interfaces via this parser. +;; - Indicate kind of object with colours +;; - Handle multi-line types +;; - Encode i-am-fct info in the alist of ids and types. + +;; Bugs: + +;; - Some prelude fcts aren't displayed properly. This might be due to a +;; name clash of Haskell and Elisp functions (e.g. length) which +;; confuses Emacs when reading `haskell-doc-prelude-types' + +;;; Changelog: + +;; $Log: haskell-doc.el,v $ +;; Revision 1.31 2015/07/23 10:34:20 ankhers +;; (turn-on-haskell-doc-mode): marked obsolete +;; (turn-on-haskell-doc): marked obsolete +;; other packages have been moving away from (turn-on-haskell-*) +;; +;; Revision 1.30 2009/02/02 21:00:33 monnier +;; (haskell-doc-imported-list): Don't add current buffer +;; to the imported file list if it is not (yet?) visiting a file. +;; +;; Revision 1.29 2007-12-12 04:04:19 monnier +;; (haskell-doc-in-code-p): New function. +;; (haskell-doc-show-type): Use it. +;; +;; Revision 1.28 2007/08/30 03:10:08 monnier +;; Comment/docs fixes. +;; +;; Revision 1.27 2007/07/30 17:36:50 monnier +;; (displayed-month): Remove declaration since it's not used here. +;; +;; Revision 1.26 2007/02/10 06:28:55 monnier +;; (haskell-doc-get-current-word): Remove. +;; Change all refs to it, to use haskell-ident-at-point instead. +;; +;; Revision 1.25 2007/02/09 21:53:42 monnier +;; (haskell-doc-get-current-word): Correctly distinguish +;; variable identifiers and infix identifiers. +;; (haskell-doc-rescan-files): Avoid switch-to-buffer. +;; (haskell-doc-imported-list): Operate on current buffer. +;; (haskell-doc-make-global-fct-index): Adjust call. +;; +;; Revision 1.24 2006/11/20 20:18:24 monnier +;; (haskell-doc-mode-print-current-symbol-info): Fix thinko. +;; +;; Revision 1.23 2006/10/20 03:12:31 monnier +;; Drop post-command-idle-hook in favor of run-with-idle-timer. +;; (haskell-doc-timer, haskell-doc-buffers): New vars. +;; (haskell-doc-mode): Use them. +;; (haskell-doc-check-active): Update the check. +;; (haskell-doc-mode-print-current-symbol-info): Remove the interactive spec. +;; Don't sit-for unless it's really needed. +;; +;; Revision 1.22 2006/09/20 18:42:35 monnier +;; Doc fix. +;; +;; Revision 1.21 2005/11/21 21:48:52 monnier +;; * haskell-doc.el (haskell-doc-extract-types): Get labelled data working. +;; (haskell-doc-prelude-types): Update via auto-generation. +;; +;; * haskell-doc.el (haskell-doc-extract-types): Get it partly working. +;; (haskell-doc-fetch-lib-urls): Don't use a literal if we apply +;; `nreverse' on it later on. +;; (haskell-doc-prelude-types): Update some parts by auto-generation. +;; (haskell-doc-grab, haskell-doc-string-nub-ws): Simplify. +;; +;; * haskell-doc.el (haskell-doc-maintainer, haskell-doc-varlist) +;; (haskell-doc-submit-bug-report, haskell-doc-ftp-site) +;; (haskell-doc-visit-home): Remove. +;; (haskell-doc-reserved-ids, haskell-doc-fetch-lib-urls) +;; (haskell-doc-extract-and-insert-types): New funs. +;; (haskell-doc-reserved-ids): Fix type of `map'. +;; +;; Revision 1.20 2005/11/21 21:27:57 monnier +;; (haskell-doc-extract-types): Get labelled data working. +;; (haskell-doc-prelude-types): Update via auto-generation. +;; +;; Revision 1.19 2005/11/21 20:44:13 monnier +;; (haskell-doc-extract-types): Get it partly working. +;; (haskell-doc-fetch-lib-urls): Don't use a literal if we apply +;; `nreverse' on it later on. +;; (haskell-doc-prelude-types): Update some parts by auto-generation. +;; (haskell-doc-grab, haskell-doc-string-nub-ws): Simplify. +;; +;; Revision 1.18 2005/11/21 18:02:15 monnier +;; (haskell-doc-maintainer, haskell-doc-varlist) +;; (haskell-doc-submit-bug-report, haskell-doc-ftp-site) +;; (haskell-doc-visit-home): Remove. +;; (haskell-doc-reserved-ids, haskell-doc-fetch-lib-urls) +;; (haskell-doc-extract-and-insert-types): New funs. +;; (haskell-doc-reserved-ids): Fix type of `map'. +;; +;; Revision 1.17 2005/11/20 23:55:09 monnier +;; Add coding cookie. +;; +;; Revision 1.16 2005/11/07 01:28:16 monnier +;; (haskell-doc-xemacs-p, haskell-doc-emacs-p) +;; (haskell-doc-message): Remove. +;; (haskell-doc-is-id-char-at): Remove. +;; (haskell-doc-get-current-word): Rewrite. +;; +;; Revision 1.15 2005/11/04 17:11:12 monnier +;; Add arch-tag. +;; +;; Revision 1.14 2005/08/24 11:36:32 monnier +;; (haskell-doc-message): Paren typo. +;; +;; Revision 1.13 2005/08/23 19:23:27 monnier +;; (haskell-doc-show-type): Assume that the availability +;; of display-message won't change at runtime. +;; +;; Revision 1.12 2005/07/18 21:04:14 monnier +;; (haskell-doc-message): Remove. +;; (haskell-doc-show-type): inline it. Do nothing for if there's no doc to show. +;; +;; Revision 1.11 2004/12/10 17:33:18 monnier +;; (haskell-doc-minor-mode-string): Make it dynamic. +;; (haskell-doc-install-keymap): Remove conflicting C-c C-o binding. +;; (haskell-doc-mode): Make a nil arg turn the mode ON. +;; (turn-on-haskell-doc-mode): Make it an alias for haskell-doc-mode. +;; (haskell-doc-mode): Don't touch haskell-doc-minor-mode-string. +;; (haskell-doc-show-global-types): Don't touch +;; haskell-doc-minor-mode-string. Call haskell-doc-make-global-fct-index. +;; (haskell-doc-check-active): Fix message. +;; (define-key-after): Don't define. +;; (haskell-doc-install-keymap): Check existence of define-key-after. +;; +;; Revision 1.10 2004/11/25 23:03:23 monnier +;; (haskell-doc-sym-doc): Make even the last char bold. +;; +;; Revision 1.9 2004/11/24 22:14:36 monnier +;; (haskell-doc-install-keymap): Don't blindly assume there's a Hugs menu. +;; +;; Revision 1.8 2004/11/22 10:45:35 simonmar +;; Fix type of getLine +;; +;; Revision 1.7 2004/10/14 22:27:47 monnier +;; (turn-off-haskell-doc-mode, haskell-doc-current-info): Don't autoload. +;; +;; Revision 1.6 2004/10/13 22:45:22 monnier +;; (haskell-doc): New group. +;; (haskell-doc-show-reserved, haskell-doc-show-prelude) +;; (haskell-doc-show-strategy, haskell-doc-show-user-defined) +;; (haskell-doc-chop-off-context, haskell-doc-chop-off-fctname): +;; Make them custom vars. +;; (haskell-doc-keymap): Declare and fill it right there. +;; (haskell-doc-mode): Simplify. +;; (haskell-doc-toggle-var): Make it into what it was supposed to be. +;; (haskell-doc-mode-print-current-symbol-info): Simplify. +;; (haskell-doc-current-info): New autoloaded function. +;; (haskell-doc-sym-doc): New fun extracted from haskell-doc-show-type. +;; (haskell-doc-show-type): Use it. +;; (haskell-doc-wrapped-type-p): Remove unused var `lim'. +;; (haskell-doc-forward-sexp-safe, haskell-doc-current-symbol): Remove. Unused. +;; (haskell-doc-visit-home): Don't require ange-ftp, it's autoloaded. +;; (haskell-doc-install-keymap): Simplify. +;; +;; Revision 1.5 2003/01/09 11:56:26 simonmar +;; Patches from Ville Skyttä <scop@xemacs.org>, the XEmacs maintainer of +;; the haskell-mode: +;; +;; - Make the auto-mode-alist modifications autoload-only. +;; +;; Revision 1.4 2002/10/14 09:55:03 simonmar +;; Patch to update the Prelude/libraries function names and to remove +;; support for older versions of Haskell. +;; +;; Submitted by: Anders Lau Olsen <alauo@mip.sdu.dk> +;; +;; Revision 1.3 2002/04/30 09:34:37 rrt +;; Remove supporting Haskell 1.4 and 1.2 from the ToDo list. It's Far Too Late. +;; +;; Add (require 'imenu). Thanks to N. Y. Kwok. +;; +;; Revision 1.2 2002/04/23 14:45:10 simonmar +;; Tweaks to the doc strings and support for customization, from +;; Ville Skyttä <scop@xemacs.org>. +;; +;; Revision 1.1 2001/07/19 16:17:36 rrt +;; Add the current version of the Moss/Thorn/Marlow Emacs mode, along with its +;; web pages and sample files. This is now the preferred mode, and the +;; haskell.org pages are being changed to reflect that. Also includes the new +;; GHCi mode from Chris Webb. +;; +;; Revision 1.6 1998/12/10 16:27:25 hwloidl +;; Minor changes ("Doc" as modeline string, mouse-3 moved to C-S-M-mouse-3) +;; +;; Revision 1.5 1998/09/24 14:25:46 gem +;; Fixed minor compatibility bugs with Haskell mode of Moss&Thorn. +;; Disabled M-/ binding. +;; +;; Revision 1.4 1997/11/12 23:51:19 hwloidl +;; Fixed start-up problem under emacs-19.34. +;; Added support for wrapped (multi-line) types and 2 vars to control the +;; behaviour with long fct types +;; +;; Revision 1.3 1997/11/03 00:48:03 hwloidl +;; Major revision for first release. +;; Added alists for showing prelude fcts, haskell syntax, and strategies +;; Added mouse interface to show type under mouse +;; Fixed bug which causes demon to fall over +;; Works now with hugs-mode and haskell-mode under emacs 19.34,20 and xemacs 19.15 +;; + +;;; Code: + +(require 'haskell-mode) +(require 'haskell-process) +(require 'haskell) +(require 'haskell-utils) +(require 'inf-haskell) +(require 'imenu) +(require 'eldoc) + +;;;###autoload +(defgroup haskell-doc nil + "Show Haskell function types in echo area." + :group 'haskell + :prefix "haskell-doc-") + + +(defvar-local haskell-doc-mode nil + "*If non-nil, show the type of the function near point or a related comment. + +If the identifier near point is a Haskell keyword and the variable +`haskell-doc-show-reserved' is non-nil show a one line summary +of the syntax. + +If the identifier near point is a Prelude or one of the standard library +functions and `haskell-doc-show-prelude' is non-nil show its type. + +If the identifier near point is local \(i.e. defined in this module\) check +the `imenu' list of functions for the type. This obviously requires that +your language mode uses `imenu'. + +If the identifier near point is global \(i.e. defined in an imported module\) +and the variable `haskell-doc-show-global-types' is non-nil show the type of its +function. + +If the identifier near point is a standard strategy or a function, type related +related to strategies and `haskell-doc-show-strategy' is non-nil show the type +of the function. Strategies are special to the parallel execution of Haskell. +If you're not interested in that just turn it off. + +If the identifier near point is a user defined function that occurs as key +in the alist `haskell-doc-user-defined-ids' and the variable +`haskell-doc-show-user-defined' is non-nil show the type of the function. + +This variable is buffer-local.") + +(defvar haskell-doc-mode-hook nil + "Hook invoked when entering `haskell-doc-mode'.") + +(defvar-local haskell-doc-index nil + "Variable holding an alist matching file names to fct-type alists. +The function `haskell-doc-make-global-fct-index' rebuilds this variables +\(similar to an `imenu' rescan\). +This variable is buffer-local.") + +(defcustom haskell-doc-show-global-types nil + "If non-nil, search for the types of global functions by loading the files. +This variable is buffer-local." + :group 'haskell-doc + :type 'boolean) +(make-variable-buffer-local 'haskell-doc-show-global-types) + +(defcustom haskell-doc-show-reserved t + "If non-nil, show a documentation string for reserved ids. +This variable is buffer-local." + :group 'haskell-doc + :type 'boolean) +(make-variable-buffer-local 'haskell-doc-show-reserved) + +(defcustom haskell-doc-show-prelude t + "If non-nil, show a documentation string for prelude functions. +This variable is buffer-local." + :group 'haskell-doc + :type 'boolean) +(make-variable-buffer-local 'haskell-doc-show-prelude) + +(defcustom haskell-doc-show-strategy t + "If non-nil, show a documentation string for strategies. +This variable is buffer-local." + :group 'haskell-doc + :type 'boolean) +(make-variable-buffer-local 'haskell-doc-show-strategy) + +(defcustom haskell-doc-show-user-defined t + "If non-nil, show a documentation string for user defined ids. +This variable is buffer-local." + :group 'haskell-doc + :type 'boolean) +(make-variable-buffer-local 'haskell-doc-show-user-defined) + +(defcustom haskell-doc-chop-off-context t + "If non-nil eliminate the context part in a Haskell type." + :group 'haskell-doc + :type 'boolean) + +(defcustom haskell-doc-chop-off-fctname nil + "If non-nil omit the function name and show only the type." + :group 'haskell-doc + :type 'boolean) + +(defcustom haskell-doc-use-inf-haskell nil + "If non-nil use inf-haskell.el to get type and kind information." + :group 'haskell-doc + :type 'boolean) + +(defvar haskell-doc-search-distance 40 ; distance in characters + "*How far to search when looking for the type declaration of fct under cursor.") + + +(defvar haskell-doc-idle-delay 0.50 + "*Number of seconds of idle time to wait before printing. +If user input arrives before this interval of time has elapsed after the +last input, no documentation will be printed. + +If this variable is set to 0, no idle time is required.") + +(defvar haskell-doc-argument-case 'identity ; 'upcase + "Case in which to display argument names of functions, as a symbol. +This has two preferred values: `upcase' or `downcase'. +Actually, any name of a function which takes a string as an argument and +returns another string is acceptable.") + +(defvar haskell-doc-mode-message-commands nil + "*Obarray of command names where it is appropriate to print in the echo area. + +This is not done for all commands since some print their own +messages in the echo area, and these functions would instantly overwrite +them. But `self-insert-command' as well as most motion commands are good +candidates. + +It is probably best to manipulate this data structure with the commands +`haskell-doc-add-command' and `haskell-doc-remove-command'.") + +;;(cond ((null haskell-doc-mode-message-commands) +;; ;; If you increase the number of buckets, keep it a prime number. +;; (setq haskell-doc-mode-message-commands (make-vector 31 0)) +;; (let ((list '("self-insert-command" +;; "next-" "previous-" +;; "forward-" "backward-" +;; "beginning-of-" "end-of-" +;; "goto-" +;; "recenter" +;; "scroll-")) +;; (syms nil)) +;; (while list +;; (setq syms (all-completions (car list) obarray 'fboundp)) +;; (setq list (cdr list)) +;; (while syms +;; (set (intern (car syms) haskell-doc-mode-message-commands) t) +;; (setq syms (cdr syms))))))) + +;; Bookkeeping; the car contains the last symbol read from the buffer. +;; The cdr contains the string last displayed in the echo area, so it can +;; be printed again if necessary without reconsing. +(defvar haskell-doc-last-data '(nil . nil)) + +(defvar haskell-doc-minor-mode-string + '(haskell-doc-show-global-types " DOC" " Doc") + "*String to display in mode line when Haskell-Doc Mode is enabled.") + + +(defvar haskell-doc-reserved-ids + '(("case" . "case exp of { alts [;] }") + ("class" . "class [context =>] simpleclass [where { cbody [;] }]") + ("data" . "data [context =>] simpletype = constrs [deriving]") + ("default" . "default (type1 , ... , typen)") + ("deriving" . "deriving (dclass | (dclass1, ... , dclassn))") ; used with data or newtype + ("do" . "do { stmts [;] } stmts -> exp [; stmts] | pat <- exp ; stmts | let decllist ; stmts") + ("else" . "if exp then exp else exp") + ("if" . "if exp then exp else exp") + ("import" . "import [qualified] modid [as modid] [impspec]") + ("in" . "let decllist in exp") + ("infix" . "infix [digit] ops") + ("infixl" . "infixl [digit] ops") + ("infixr" . "infixr [digit] ops") + ("instance" . "instance [context =>] qtycls inst [where { valdefs [;] }]") + ("let" . "let { decl; ...; decl [;] } in exp") + ("module" . "module modid [exports] where body") + ("newtype" . "newtype [context =>] simpletype = con atype [deriving]") + ("of" . "case exp of { alts [;] }") + ("then" . "if exp then exp else exp") + ("type" . "type simpletype = type") + ("where" . "exp where { decl; ...; decl [;] }") ; check that ; see also class, instance, module + ("as" . "import [qualified] modid [as modid] [impspec]") + ("qualified" . "import [qualified] modid [as modid] [impspec]") + ("hiding" . "hiding ( import1 , ... , importn [ , ] )") + ("family" . "(type family type [kind] [= type_fam_equations]) | (data family type [kind])")) + "An alist of reserved identifiers. +Each element is of the form (ID . DOC) where both ID and DOC are strings. +DOC should be a concise single-line string describing the construct in which +the keyword is used.") + + +(defun haskell-doc-extract-types (url) + (with-temp-buffer + (insert-file-contents url) + (goto-char (point-min)) + (while (search-forward " " nil t) (replace-match " " t t)) + + ;; First, focus on the actual code, removing the surrounding HTML text. + (goto-char (point-min)) + (let ((last (point-min)) + (modules nil)) + (while (re-search-forward "^module +\\([[:alnum:]]+\\)" nil t) + (let ((module (match-string 1))) + (if (member module modules) + ;; The library nodes of the HTML doc contain modules twice: + ;; once at the top, with only type declarations, and once at + ;; the bottom with an actual sample implementation which may + ;; include declaration of non-exported values. + ;; We're now at this second occurrence is the implementation + ;; which should thus be ignored. + nil + (push module modules) + (delete-region last (point)) + (search-forward "</tt>") + ;; Some of the blocks of code are split. + (while (looking-at "\\(<[^<>]+>[ \t\n]*\\)*<tt>") + (goto-char (match-end 0)) + (search-forward "</tt>")) + (setq last (point))))) + (delete-region last (point-max)) + + ;; Then process the HTML encoding to get back to pure ASCII. + (goto-char (point-min)) + (while (search-forward "<br>" nil t) (replace-match "\n" t t)) + ;; (goto-char (point-min)) + ;; (while (re-search-forward "<[^<>]+>" nil t) (replace-match "" t t)) + (goto-char (point-min)) + (while (search-forward ">" nil t) (replace-match ">" t t)) + (goto-char (point-min)) + (while (search-forward "<" nil t) (replace-match "<" t t)) + (goto-char (point-min)) + (while (search-forward "&" nil t) (replace-match "&" t t)) + (goto-char (point-min)) + (if (re-search-forward "&[a-z]+;" nil t) + (error "Unexpected charref %s" (match-string 0))) + ;; Remove TABS. + (goto-char (point-min)) + (while (search-forward "\t" nil t) (replace-match " " t t)) + + ;; Finally, extract the actual data. + (goto-char (point-min)) + (let* ((elems nil) + (space-re "[ \t\n]*\\(?:--.*\n[ \t\n]*\\)*") + (comma-re (concat " *," space-re)) + ;; A list of identifiers. We have to be careful to weed out + ;; entries like "ratPrec = 7 :: Int". Also ignore entries + ;; which start with a < since they're actually in the HTML text + ;; part. And the list may be spread over several lines, cut + ;; after a comma. + (idlist-re + (concat "\\([^< \t\n][^ \t\n]*" + "\\(?:" comma-re "[^ \t\n]+\\)*\\)")) + ;; A type. A few types are spread over 2 lines, + ;; cut after the "=>", so we have to handle these as well. + (type-re "\\(.*[^\n>]\\(?:>[ \t\n]+.*[^\n>]\\)*\\) *$") + ;; A decl of a list of values, possibly indented. + (val-decl-re + (concat "^\\( +\\)?" idlist-re "[ \t\n]*::[ \t\n]*" type-re)) + (re (concat + ;; 3 possibilities: a class decl, a data decl, or val decl. + ;; First, let's match a class decl. + "^class \\(?:.*=>\\)? *\\(.*[^ \t\n]\\)[ \t\n]*where" + + ;; Or a value decl: + "\\|" val-decl-re + + "\\|" ;; Or a data decl. We only handle single-arm + ;; datatypes with labels. + "^data +\\([[:alnum:]][[:alnum:] ]*[[:alnum:]]\\)" + " *=.*{\\([^}]+\\)}" + )) + (re-class (concat "^[^ \t\n]\\|" re)) + curclass) + (while (re-search-forward (if curclass re-class re) nil t) + (cond + ;; A class decl. + ((match-end 1) (setq curclass (match-string 1))) + ;; A value decl. + ((match-end 4) + (let ((type (match-string 4)) + (vars (match-string 3)) + (indented (match-end 2))) + (if (string-match "[ \t\n][ \t\n]+" type) + (setq type (replace-match " " t t type))) + (if (string-match " *\\(--.*\\)?\\'" type) + (setq type (substring type 0 (match-beginning 0)))) + (if indented + (if curclass + (if (string-match "\\`\\(.*[^ \t\n]\\) *=> *" type) + (let ((classes (match-string 1 type))) + (setq type (substring type (match-end 0))) + (if (string-match "\\`(.*)\\'" classes) + (setq classes (substring classes 1 -1))) + (setq type (concat "(" curclass ", " classes + ") => " type))) + (setq type (concat curclass " => " type))) + ;; It's actually not an error: just a type annotation on + ;; some local variable. + ;; (error "Indentation outside a class in %s: %s" + ;; module vars) + nil) + (setq curclass nil)) + (dolist (var (split-string vars comma-re t)) + (if (string-match "(.*)" var) (setq var (substring var 1 -1))) + (push (cons var type) elems)))) + ;; A datatype decl. + ((match-end 5) + (setq curclass nil) + (let ((name (match-string 5))) + (save-excursion + (save-restriction + (narrow-to-region (match-beginning 6) (match-end 6)) + (goto-char (point-min)) + (while (re-search-forward val-decl-re nil t) + (let ((vars (match-string 2)) + (type (match-string 3))) + (if (string-match "[ \t\n][ \t\n]+" type) + (setq type (replace-match " " t t type))) + (if (string-match " *\\(--.*\\)?\\'" type) + (setq type (substring type 0 (match-beginning 0)))) + (if (string-match ",\\'" type) + (setq type (substring type 0 -1))) + (setq type (concat name " -> " type)) + (dolist (var (split-string vars comma-re t)) + (if (string-match "(.*)" var) + (setq var (substring var 1 -1))) + (push (cons var type) elems)))))))) + + ;; The end of a class declaration. + (t (setq curclass nil) (beginning-of-line)))) + (cons (car (last modules)) elems))))) + +(defun haskell-doc-fetch-lib-urls (base-url) + (with-temp-buffer + (insert-file-contents base-url) + (goto-char (point-min)) + (search-forward "Part II: Libraries") + (delete-region (point-min) (point)) + (search-forward "</table>") + (delete-region (point) (point-max)) + (goto-char (point-min)) + (let ((libs (list "standard-prelude.html"))) + (while (re-search-forward "<a href=\"\\([^\"]+\\)\">" nil t) + (push (match-string 1) libs)) + (mapcar (lambda (s) (expand-file-name s (file-name-directory base-url))) + (nreverse libs))))) + +(defun haskell-doc-extract-and-insert-types (url) + "Fetch the types from the online doc and insert them at point. +URL is the URL of the online doc." + (interactive (if current-prefix-arg + (read-file-name "URL: ") + (list "http://www.haskell.org/onlinereport/"))) + (let ((urls (haskell-doc-fetch-lib-urls url))) + (dolist (url urls) + (let ((data (haskell-doc-extract-types url))) + (insert ";; " (pop data)) (indent-according-to-mode) (newline) + (dolist (elem (sort data (lambda (x y) (string-lessp (car x) (car y))))) + (prin1 elem (current-buffer)) + (indent-according-to-mode) (newline)))))) + +(defvar haskell-doc-prelude-types + ;; This list was auto generated by `haskell-doc-extract-and-insert-types'. + '( + ;; Prelude + ("!!" . "[a] -> Int -> a") + ("$" . "(a -> b) -> a -> b") + ("$!" . "(a -> b) -> a -> b") + ("&&" . "Bool -> Bool -> Bool") + ("*" . "Num a => a -> a -> a") + ("**" . "Floating a => a -> a -> a") + ("+" . "Num a => a -> a -> a") + ("++" . "[a] -> [a] -> [a]") + ("-" . "Num a => a -> a -> a") + ("." . "(b -> c) -> (a -> b) -> a -> c") + ("/" . "Fractional a => a -> a -> a") + ("/=" . "Eq a => a -> a -> Bool") + ("<" . "Ord a => a -> a -> Bool") + ("<=" . "Ord a => a -> a -> Bool") + ("=<<" . "Monad m => (a -> m b) -> m a -> m b") + ("==" . "Eq a => a -> a -> Bool") + (">" . "Ord a => a -> a -> Bool") + (">=" . "Ord a => a -> a -> Bool") + (">>" . "Monad m => m a -> m b -> m b") + (">>=" . "Monad m => m a -> (a -> m b) -> m b") + ("^" . "(Num a, Integral b) => a -> b -> a") + ("^^" . "(Fractional a, Integral b) => a -> b -> a") + ("abs" . "Num a => a -> a") + ("acos" . "Floating a => a -> a") + ("acosh" . "Floating a => a -> a") + ("all" . "(a -> Bool) -> [a] -> Bool") + ("and" . "[Bool] -> Bool") + ("any" . "(a -> Bool) -> [a] -> Bool") + ("appendFile" . "FilePath -> String -> IO ()") + ("asTypeOf" . "a -> a -> a") + ("asin" . "Floating a => a -> a") + ("asinh" . "Floating a => a -> a") + ("atan" . "Floating a => a -> a") + ("atan2" . "RealFloat a => a -> a -> a") + ("atanh" . "Floating a => a -> a") + ("break" . "(a -> Bool) -> [a] -> ([a],[a])") + ("catch" . "IO a -> (IOError -> IO a) -> IO a") + ("ceiling" . "(RealFrac a, Integral b) => a -> b") + ("compare" . "Ord a => a -> a -> Ordering") + ("concat" . "[[a]] -> [a]") + ("concatMap" . "(a -> [b]) -> [a] -> [b]") + ("const" . "a -> b -> a") + ("cos" . "Floating a => a -> a") + ("cosh" . "Floating a => a -> a") + ("curry" . "((a, b) -> c) -> a -> b -> c") + ("cycle" . "[a] -> [a]") + ("decodeFloat" . "RealFloat a => a -> (Integer,Int)") + ("div" . "Integral a => a -> a -> a") + ("divMod" . "Integral a => a -> a -> (a,a)") + ("drop" . "Int -> [a] -> [a]") + ("dropWhile" . "(a -> Bool) -> [a] -> [a]") + ("either" . "(a -> c) -> (b -> c) -> Either a b -> c") + ("elem" . "(Eq a) => a -> [a] -> Bool") + ("encodeFloat" . "RealFloat a => Integer -> Int -> a") + ("enumFrom" . "Enum a => a -> [a]") + ("enumFromThen" . "Enum a => a -> a -> [a]") + ("enumFromThenTo" . "Enum a => a -> a -> a -> [a]") + ("enumFromTo" . "Enum a => a -> a -> [a]") + ("error" . "String -> a") + ("even" . "(Integral a) => a -> Bool") + ("exp" . "Floating a => a -> a") + ("exponent" . "RealFloat a => a -> Int") + ("fail" . "Monad m => String -> m a") + ("filter" . "(a -> Bool) -> [a] -> [a]") + ("flip" . "(a -> b -> c) -> b -> a -> c") + ("floatDigits" . "RealFloat a => a -> Int") + ("floatRadix" . "RealFloat a => a -> Integer") + ("floatRange" . "RealFloat a => a -> (Int,Int)") + ("floor" . "(RealFrac a, Integral b) => a -> b") + ("fmap" . "Functor f => (a -> b) -> f a -> f b") + ("foldl" . "(a -> b -> a) -> a -> [b] -> a") + ("foldl1" . "(a -> a -> a) -> [a] -> a") + ("foldr" . "(a -> b -> b) -> b -> [a] -> b") + ("foldr1" . "(a -> a -> a) -> [a] -> a") + ("fromEnum" . "Enum a => a -> Int") + ("fromInteger" . "Num a => Integer -> a") + ("fromIntegral" . "(Integral a, Num b) => a -> b") + ("fromRational" . "Fractional a => Rational -> a") + ("fst" . "(a,b) -> a") + ("gcd" . "(Integral a) => a -> a -> a") + ("getChar" . "IO Char") + ("getContents" . "IO String") + ("getLine" . "IO String") + ("head" . "[a] -> a") + ("id" . "a -> a") + ("init" . "[a] -> [a]") + ("interact" . "(String -> String) -> IO ()") + ("ioError" . "IOError -> IO a") + ("isDenormalized" . "RealFloat a => a -> Bool") + ("isIEEE" . "RealFloat a => a -> Bool") + ("isInfinite" . "RealFloat a => a -> Bool") + ("isNaN" . "RealFloat a => a -> Bool") + ("isNegativeZero" . "RealFloat a => a -> Bool") + ("iterate" . "(a -> a) -> a -> [a]") + ("last" . "[a] -> a") + ("lcm" . "(Integral a) => a -> a -> a") + ("length" . "[a] -> Int") + ("lex" . "ReadS String") + ("lines" . "String -> [String]") + ("log" . "Floating a => a -> a") + ("logBase" . "Floating a => a -> a -> a") + ("lookup" . "(Eq a) => a -> [(a,b)] -> Maybe b") + ("map" . "(a -> b) -> [a] -> [b]") + ("mapM" . "Monad m => (a -> m b) -> [a] -> m [b]") + ("mapM_" . "Monad m => (a -> m b) -> [a] -> m ()") + ("max" . "Ord a => a -> a -> a") + ("maxBound" . "Bounded a => a") + ("maximum" . "(Ord a) => [a] -> a") + ("maybe" . "b -> (a -> b) -> Maybe a -> b") + ("min" . "Ord a => a -> a -> a") + ("minBound" . "Bounded a => a") + ("minimum" . "(Ord a) => [a] -> a") + ("mod" . "Integral a => a -> a -> a") + ("negate" . "Num a => a -> a") + ("not" . "Bool -> Bool") + ("notElem" . "(Eq a) => a -> [a] -> Bool") + ("null" . "[a] -> Bool") + ("numericEnumFrom" . "(Fractional a) => a -> [a]") + ("numericEnumFromThen" . "(Fractional a) => a -> a -> [a]") + ("numericEnumFromThenTo" . "(Fractional a, Ord a) => a -> a -> a -> [a]") + ("numericEnumFromTo" . "(Fractional a, Ord a) => a -> a -> [a]") + ("odd" . "(Integral a) => a -> Bool") + ("or" . "[Bool] -> Bool") + ("otherwise" . "Bool") + ("pi" . "Floating a => a") + ("pred" . "Enum a => a -> a") + ("print" . "Show a => a -> IO ()") + ("product" . "(Num a) => [a] -> a") + ("properFraction" . "(RealFrac a, Integral b) => a -> (b,a)") + ("putChar" . "Char -> IO ()") + ("putStr" . "String -> IO ()") + ("putStrLn" . "String -> IO ()") + ("quot" . "Integral a => a -> a -> a") + ("quotRem" . "Integral a => a -> a -> (a,a)") + ("read" . "(Read a) => String -> a") + ("readFile" . "FilePath -> IO String") + ("readIO" . "Read a => String -> IO a") + ("readList" . "Read a => ReadS [a]") + ("readLn" . "Read a => IO a") + ("readParen" . "Bool -> ReadS a -> ReadS a") + ("reads" . "(Read a) => ReadS a") + ("readsPrec" . "Read a => Int -> ReadS a") + ("realToFrac" . "(Real a, Fractional b) => a -> b") + ("recip" . "Fractional a => a -> a") + ("rem" . "Integral a => a -> a -> a") + ("repeat" . "a -> [a]") + ("replicate" . "Int -> a -> [a]") + ("return" . "Monad m => a -> m a") + ("reverse" . "[a] -> [a]") + ("round" . "(RealFrac a, Integral b) => a -> b") + ("scaleFloat" . "RealFloat a => Int -> a -> a") + ("scanl" . "(a -> b -> a) -> a -> [b] -> [a]") + ("scanl1" . "(a -> a -> a) -> [a] -> [a]") + ("scanr" . "(a -> b -> b) -> b -> [a] -> [b]") + ("scanr1" . "(a -> a -> a) -> [a] -> [a]") + ("seq" . "a -> b -> b") + ("sequence" . "Monad m => [m a] -> m [a]") + ("sequence_" . "Monad m => [m a] -> m ()") + ("show" . "Show a => a -> String") + ("showChar" . "Char -> ShowS") + ("showList" . "Show a => [a] -> ShowS") + ("showParen" . "Bool -> ShowS -> ShowS") + ("showString" . "String -> ShowS") + ("shows" . "(Show a) => a -> ShowS") + ("showsPrec" . "Show a => Int -> a -> ShowS") + ("significand" . "RealFloat a => a -> a") + ("signum" . "Num a => a -> a") + ("sin" . "Floating a => a -> a") + ("sinh" . "Floating a => a -> a") + ("snd" . "(a,b) -> b") + ("span" . "(a -> Bool) -> [a] -> ([a],[a])") + ("splitAt" . "Int -> [a] -> ([a],[a])") + ("sqrt" . "Floating a => a -> a") + ("subtract" . "(Num a) => a -> a -> a") + ("succ" . "Enum a => a -> a") + ("sum" . "(Num a) => [a] -> a") + ("tail" . "[a] -> [a]") + ("take" . "Int -> [a] -> [a]") + ("takeWhile" . "(a -> Bool) -> [a] -> [a]") + ("tan" . "Floating a => a -> a") + ("tanh" . "Floating a => a -> a") + ("toEnum" . "Enum a => Int -> a") + ("toInteger" . "Integral a => a -> Integer") + ("toRational" . "Real a => a -> Rational") + ("truncate" . "(RealFrac a, Integral b) => a -> b") + ("uncurry" . "(a -> b -> c) -> ((a, b) -> c)") + ("undefined" . "a") + ("unlines" . "[String] -> String") + ("until" . "(a -> Bool) -> (a -> a) -> a -> a") + ("unwords" . "[String] -> String") + ("unzip" . "[(a,b)] -> ([a],[b])") + ("unzip3" . "[(a,b,c)] -> ([a],[b],[c])") + ("userError" . "String -> IOError") + ("words" . "String -> [String]") + ("writeFile" . "FilePath -> String -> IO ()") + ("zip" . "[a] -> [b] -> [(a,b)]") + ("zip3" . "[a] -> [b] -> [c] -> [(a,b,c)]") + ("zipWith" . "(a->b->c) -> [a]->[b]->[c]") + ("zipWith3" . "(a->b->c->d) -> [a]->[b]->[c]->[d]") + ("||" . "Bool -> Bool -> Bool") + ;; Ratio + ("%" . "(Integral a) => a -> a -> Ratio a") + ("approxRational" . "(RealFrac a) => a -> a -> Rational") + ("denominator" . "(Integral a) => Ratio a -> a") + ("numerator" . "(Integral a) => Ratio a -> a") + ;; Complex + ("cis" . "(RealFloat a) => a -> Complex a") + ("conjugate" . "(RealFloat a) => Complex a -> Complex a") + ("imagPart" . "(RealFloat a) => Complex a -> a") + ("magnitude" . "(RealFloat a) => Complex a -> a") + ("mkPolar" . "(RealFloat a) => a -> a -> Complex a") + ("phase" . "(RealFloat a) => Complex a -> a") + ("polar" . "(RealFloat a) => Complex a -> (a,a)") + ("realPart" . "(RealFloat a) => Complex a -> a") + ;; Numeric + ("floatToDigits" . "(RealFloat a) => Integer -> a -> ([Int], Int)") + ("fromRat" . "(RealFloat a) => Rational -> a") + ("lexDigits" . "ReadS String") + ("readDec" . "(Integral a) => ReadS a") + ("readFloat" . "(RealFrac a) => ReadS a") + ("readHex" . "(Integral a) => ReadS a") + ("readInt" . "(Integral a) => a -> (Char -> Bool) -> (Char -> Int) -> ReadS a") + ("readOct" . "(Integral a) => ReadS a") + ("readSigned" . "(Real a) => ReadS a -> ReadS a") + ("showEFloat" . "(RealFloat a) => Maybe Int -> a -> ShowS") + ("showFFloat" . "(RealFloat a) => Maybe Int -> a -> ShowS") + ("showFloat" . "(RealFloat a) => a -> ShowS") + ("showGFloat" . "(RealFloat a) => Maybe Int -> a -> ShowS") + ("showHex" . "Integral a => a -> ShowS") + ("showInt" . "Integral a => a -> ShowS") + ("showIntAtBase" . "Integral a => a -> (Int -> Char) -> a -> ShowS") + ("showOct" . "Integral a => a -> ShowS") + ("showSigned" . "(Real a) => (a -> ShowS) -> Int -> a -> ShowS") + ;; Ix + ("inRange" . "Ix a => (a,a) -> a -> Bool") + ("index" . "Ix a => (a,a) -> a -> Int") + ("range" . "Ix a => (a,a) -> [a]") + ("rangeSize" . "Ix a => (a,a) -> Int") + ;; Array + ("!" . "(Ix a) => Array a b -> a -> b") + ("//" . "(Ix a) => Array a b -> [(a,b)] -> Array a b") + ("accum" . "(Ix a) => (b -> c -> b) -> Array a b -> [(a,c)]") + ("accumArray" . "(Ix a) => (b -> c -> b) -> b -> (a,a) -> [(a,c)]") + ("array" . "(Ix a) => (a,a) -> [(a,b)] -> Array a b") + ("assocs" . "(Ix a) => Array a b -> [(a,b)]") + ("bounds" . "(Ix a) => Array a b -> (a,a)") + ("elems" . "(Ix a) => Array a b -> [b]") + ("indices" . "(Ix a) => Array a b -> [a]") + ("ixmap" . "(Ix a, Ix b) => (a,a) -> (a -> b) -> Array b c") + ("listArray" . "(Ix a) => (a,a) -> [b] -> Array a b") + ;; List + ("\\\\" . "Eq a => [a] -> [a] -> [a]") + ("delete" . "Eq a => a -> [a] -> [a]") + ("deleteBy" . "(a -> a -> Bool) -> a -> [a] -> [a]") + ("deleteFirstsBy" . "(a -> a -> Bool) -> [a] -> [a] -> [a]") + ("elemIndex" . "Eq a => a -> [a] -> Maybe Int") + ("elemIndices" . "Eq a => a -> [a] -> [Int]") + ("find" . "(a -> Bool) -> [a] -> Maybe a") + ("findIndex" . "(a -> Bool) -> [a] -> Maybe Int") + ("findIndices" . "(a -> Bool) -> [a] -> [Int]") + ("genericDrop" . "Integral a => a -> [b] -> [b]") + ("genericIndex" . "Integral a => [b] -> a -> b") + ("genericLength" . "Integral a => [b] -> a") + ("genericReplicate" . "Integral a => a -> b -> [b]") + ("genericSplitAt" . "Integral a => a -> [b] -> ([b],[b])") + ("genericTake" . "Integral a => a -> [b] -> [b]") + ("group" . "Eq a => [a] -> [[a]]") + ("groupBy" . "(a -> a -> Bool) -> [a] -> [[a]]") + ("inits" . "[a] -> [[a]]") + ("insert" . "Ord a => a -> [a] -> [a]") + ("insertBy" . "(a -> a -> Ordering) -> a -> [a] -> [a]") + ("intersect" . "Eq a => [a] -> [a] -> [a]") + ("intersectBy" . "(a -> a -> Bool) -> [a] -> [a] -> [a]") + ("intersperse" . "a -> [a] -> [a]") + ("isPrefixOf" . "Eq a => [a] -> [a] -> Bool") + ("isSuffixOf" . "Eq a => [a] -> [a] -> Bool") + ("mapAccumL" . "(a -> b -> (a, c)) -> a -> [b] -> (a, [c])") + ("mapAccumR" . "(a -> b -> (a, c)) -> a -> [b] -> (a, [c])") + ("maximumBy" . "(a -> a -> Ordering) -> [a] -> a") + ("minimumBy" . "(a -> a -> Ordering) -> [a] -> a") + ("nub" . "Eq a => [a] -> [a]") + ("nubBy" . "(a -> a -> Bool) -> [a] -> [a]") + ("partition" . "(a -> Bool) -> [a] -> ([a],[a])") + ("sort" . "Ord a => [a] -> [a]") + ("sortBy" . "(a -> a -> Ordering) -> [a] -> [a]") + ("tails" . "[a] -> [[a]]") + ("transpose" . "[[a]] -> [[a]]") + ("unfoldr" . "(b -> Maybe (a,b)) -> b -> [a]") + ("union" . "Eq a => [a] -> [a] -> [a]") + ("unionBy" . "(a -> a -> Bool) -> [a] -> [a] -> [a]") + ("unzip4" . "[(a,b,c,d)] -> ([a],[b],[c],[d])") + ("unzip5" . "[(a,b,c,d,e)] -> ([a],[b],[c],[d],[e])") + ("unzip6" . "[(a,b,c,d,e,f)] -> ([a],[b],[c],[d],[e],[f])") + ("unzip7" . "[(a,b,c,d,e,f,g)] -> ([a],[b],[c],[d],[e],[f],[g])") + ("zip4" . "[a] -> [b] -> [c] -> [d] -> [(a,b,c,d)]") + ("zip5" . "[a] -> [b] -> [c] -> [d] -> [e] -> [(a,b,c,d,e)]") + ("zip6" . "[a] -> [b] -> [c] -> [d] -> [e] -> [f]") + ("zip7" . "[a] -> [b] -> [c] -> [d] -> [e] -> [f] -> [g]") + ("zipWith4" . "(a->b->c->d->e) -> [a]->[b]->[c]->[d]->[e]") + ("zipWith5" . "(a->b->c->d->e->f) ->") + ("zipWith6" . "(a->b->c->d->e->f->g) -> [a]->[b]->[c]->[d]->[e]->[f]->[g]") + ("zipWith7" . "(a->b->c->d->e->f->g->h) -> [a]->[b]->[c]->[d]->[e]->[f]->[g]->[h]") + ;; Maybe + ("catMaybes" . "[Maybe a] -> [a]") + ("fromJust" . "Maybe a -> a") + ("fromMaybe" . "a -> Maybe a -> a") + ("isJust" . "Maybe a -> Bool") + ("isNothing" . "Maybe a -> Bool") + ("listToMaybe" . "[a] -> Maybe a") + ("mapMaybe" . "(a -> Maybe b) -> [a] -> [b]") + ("maybeToList" . "Maybe a -> [a]") + ;; Char + ("chr" . "Int -> Char") + ("digitToInt" . "Char -> Int") + ("intToDigit" . "Int -> Char") + ("isAlpha" . "Char -> Bool") + ("isAlphaNum" . "Char -> Bool") + ("isAscii" . "Char -> Bool") + ("isControl" . "Char -> Bool") + ("isDigit" . "Char -> Bool") + ("isHexDigit" . "Char -> Bool") + ("isLatin1" . "Char -> Bool") + ("isLower" . "Char -> Bool") + ("isOctDigit" . "Char -> Bool") + ("isPrint" . "Char -> Bool") + ("isSpace" . "Char -> Bool") + ("isUpper" . "Char -> Bool") + ("lexLitChar" . "ReadS String") + ("ord" . "Char -> Int") + ("readLitChar" . "ReadS Char") + ("showLitChar" . "Char -> ShowS") + ("toLower" . "Char -> Char") + ("toUpper" . "Char -> Char") + ;; Monad + ("ap" . "Monad m => m (a -> b) -> m a -> m b") + ("filterM" . "Monad m => (a -> m Bool) -> [a] -> m [a]") + ("foldM" . "Monad m => (a -> b -> m a) -> a -> [b] -> m a") + ("guard" . "MonadPlus m => Bool -> m ()") + ("join" . "Monad m => m (m a) -> m a") + ("liftM" . "Monad m => (a -> b) -> (m a -> m b)") + ("liftM2" . "Monad m => (a -> b -> c) -> (m a -> m b -> m c)") + ("liftM3" . "Monad m => (a -> b -> c -> d) -> (m a -> m b -> m c -> m d)") + ("liftM4" . "Monad m => (a -> b -> c -> d -> e) -> (m a -> m b -> m c -> m d -> m e)") + ("liftM5" . "Monad m => (a -> b -> c -> d -> e -> f) -> (m a -> m b -> m c -> m d -> m e -> m f)") + ("mapAndUnzipM" . "Monad m => (a -> m (b,c)) -> [a] -> m ([b], [c])") + ("mplus" . "MonadPlus m => m a -> m a -> m a") + ("msum" . "MonadPlus m => [m a] -> m a") + ("mzero" . "MonadPlus m => m a") + ("unless" . "Monad m => Bool -> m () -> m ()") + ("when" . "Monad m => Bool -> m () -> m ()") + ("zipWithM" . "Monad m => (a -> b -> m c) -> [a] -> [b] -> m [c]") + ("zipWithM_" . "Monad m => (a -> b -> m c) -> [a] -> [b] -> m ()") + ;; IO + ("bracket" . "IO a -> (a -> IO b) -> (a -> IO c) -> IO c") + ("bracket_" . "IO a -> (a -> IO b) -> IO c -> IO c") + ("hClose" . "Handle -> IO ()") + ("hFileSize" . "Handle -> IO Integer") + ("hFlush" . "Handle -> IO ()") + ("hGetBuffering" . "Handle -> IO BufferMode") + ("hGetChar" . "Handle -> IO Char") + ("hGetContents" . "Handle -> IO String") + ("hGetLine" . "Handle -> IO String") + ("hGetPosn" . "Handle -> IO HandlePosn") + ("hIsClosed" . "Handle -> IO Bool") + ("hIsEOF" . "Handle -> IO Bool") + ("hIsOpen" . "Handle -> IO Bool") + ("hIsReadable" . "Handle -> IO Bool") + ("hIsSeekable" . "Handle -> IO Bool") + ("hIsWritable" . "Handle -> IO Bool") + ("hLookAhead" . "Handle -> IO Char") + ("hPrint" . "Show a => Handle -> a -> IO ()") + ("hPutChar" . "Handle -> Char -> IO ()") + ("hPutStr" . "Handle -> String -> IO ()") + ("hPutStrLn" . "Handle -> String -> IO ()") + ("hReady" . "Handle -> IO Bool") + ("hSeek" . "Handle -> SeekMode -> Integer -> IO ()") + ("hSetBuffering" . "Handle -> BufferMode -> IO ()") + ("hSetPosn" . "HandlePosn -> IO ()") + ("hWaitForInput" . "Handle -> Int -> IO Bool") + ("ioeGetErrorString" . "IOError -> String") + ("ioeGetFileName" . "IOError -> Maybe FilePath") + ("ioeGetHandle" . "IOError -> Maybe Handle") + ("isAlreadyExistsError" . "IOError -> Bool") + ("isAlreadyInUseError" . "IOError -> Bool") + ("isDoesNotExistError" . "IOError -> Bool") + ("isEOF" . "IO Bool") + ("isEOFError" . "IOError -> Bool") + ("isFullError" . "IOError -> Bool") + ("isIllegalOperation" . "IOError -> Bool") + ("isPermissionError" . "IOError -> Bool") + ("isUserError" . "IOError -> Bool") + ("openFile" . "FilePath -> IOMode -> IO Handle") + ("stderr" . "Handle") + ("stdin" . "Handle") + ("stdout" . "Handle") + ("try" . "IO a -> IO (Either IOError a)") + ;; Directory + ("createDirectory" . "FilePath -> IO ()") + ("doesDirectoryExist" . "FilePath -> IO Bool") + ("doesFileExist" . "FilePath -> IO Bool") + ("executable" . "Permissions -> Bool") + ("getCurrentDirectory" . "IO FilePath") + ("getDirectoryContents" . "FilePath -> IO [FilePath]") + ("getModificationTime" . "FilePath -> IO ClockTime") + ("getPermissions" . "FilePath -> IO Permissions") + ("readable" . "Permissions -> Bool") + ("removeDirectory" . "FilePath -> IO ()") + ("removeFile" . "FilePath -> IO ()") + ("renameDirectory" . "FilePath -> FilePath -> IO ()") + ("renameFile" . "FilePath -> FilePath -> IO ()") + ("searchable" . "Permissions -> Bool") + ("setCurrentDirectory" . "FilePath -> IO ()") + ("setPermissions" . "FilePath -> Permissions -> IO ()") + ("writable" . "Permissions -> Bool") + ;; System + ("exitFailure" . "IO a") + ("exitWith" . "ExitCode -> IO a") + ("getArgs" . "IO [String]") + ("getEnv" . "String -> IO String") + ("getProgName" . "IO String") + ("system" . "String -> IO ExitCode") + ;; Time + ("addToClockTime" . "TimeDiff -> ClockTime -> ClockTime") + ("calendarTimeToString" . "CalendarTime -> String") + ("ctDay" . "CalendarTime -> Int") + ("ctHour" . "CalendarTime -> Int") + ("ctIsDST" . "CalendarTime -> Bool") + ("ctMin" . "CalendarTime -> Int") + ("ctMonth" . "CalendarTime -> Month") + ("ctPicosec" . "CalendarTime -> Integer") + ("ctSec" . "CalendarTime -> Int") + ("ctTZ" . "CalendarTime -> Int") + ("ctTZName" . "CalendarTime -> String") + ("ctWDay" . "CalendarTime -> Day") + ("ctYDay" . "CalendarTime -> Int") + ("ctYear" . "CalendarTime -> Int") + ("diffClockTimes" . "ClockTime -> ClockTime -> TimeDiff") + ("formatCalendarTime" . "TimeLocale -> String -> CalendarTime -> String") + ("getClockTime" . "IO ClockTime") + ("tdDay" . "TimeDiff -> Int") + ("tdHour" . "TimeDiff -> Int") + ("tdMin" . "TimeDiff -> Int") + ("tdMonth" . "TimeDiff -> Int") + ("tdPicosec" . "TimeDiff -> Integer") + ("tdSec" . "TimeDiff -> Int") + ("tdYear" . "TimeDiff -> Int") + ("toCalendarTime" . "ClockTime -> IO CalendarTime") + ("toClockTime" . "CalendarTime -> ClockTime") + ("toUTCTime" . "ClockTime -> CalendarTime") + ;; Locale + ("amPm" . "TimeLocale -> (String, String)") + ("dateFmt" . "TimeLocale -> String") + ("dateTimeFmt" . "TimeLocale -> String") + ("defaultTimeLocale" . "TimeLocale") + ("months" . "TimeLocale -> [(String, String)]") + ("time12Fmt" . "TimeLocale -> String") + ("timeFmt" . "TimeLocale -> String") + ("wDays" . "TimeLocale -> [(String, String)]") + ;; CPUTime + ("cpuTimePrecision" . "Integer") + ("getCPUTime" . "IO Integer") + ;; Random + ("genRange" . "RandomGen g => g -> (Int, Int)") + ("getStdGen" . "IO StdGen") + ("getStdRandom" . "(StdGen -> (a, StdGen)) -> IO a") + ("mkStdGen" . "Int -> StdGen") + ("newStdGen" . "IO StdGen") + ("next" . "RandomGen g => g -> (Int, g)") + ("random" . "(Random a, RandomGen g) => g -> (a, g)") + ("randomIO" . "Random a => IO a") + ("randomR" . "(Random a, RandomGen g) => (a, a) -> g -> (a, g)") + ("randomRIO" . "Random a => (a,a) -> IO a") + ("randomRs" . "(Random a, RandomGen g) => (a, a) -> g -> [a]") + ("randoms" . "(Random a, RandomGen g) => g -> [a]") + ("setStdGen" . "StdGen -> IO ()") + ("split" . "RandomGen g => g -> (g, g)") + ) + "Alist of prelude functions and their types.") + + +(defvar haskell-doc-strategy-ids + (list + '("par" . "Done -> Done -> Done ; [infixr 0]") + '("seq" . "Done -> Done -> Done ; [infixr 1]") + + '("using" . "a -> Strategy a -> a ; [infixl 0]") + '("demanding" . "a -> Done -> a ; [infixl 0]") + '("sparking" . "a -> Done -> a ; [infixl 0]") + + '(">||" . "Done -> Done -> Done ; [infixr 2]") + '(">|" . "Done -> Done -> Done ; [infixr 3]") + '("$||" . "(a -> b) -> Strategy a -> a -> b ; [infixl 6]") + '("$|" . "(a -> b) -> Strategy a -> a -> b ; [infixl 6]") + '(".|" . "(b -> c) -> Strategy b -> (a -> b) -> (a -> c) ; [infixl 9]") + '(".||" . "(b -> c) -> Strategy b -> (a -> b) -> (a -> c) ; [infixl 9]") + '("-|" . "(a -> b) -> Strategy b -> (b -> c) -> (a -> c) ; [infixl 9]") + '("-||" . "(a -> b) -> Strategy b -> (b -> c) -> (a -> c) ; [infixl 9]") + + '("Done" . "type Done = ()") + '("Strategy" . "type Strategy a = a -> Done") + + '("r0" . "Strategy a") + '("rwhnf" . "Eval a => Strategy a") + '("rnf" . "Strategy a") + '("NFData" . "class Eval a => NFData a where rnf :: Strategy a") + '("NFDataIntegral" ."class (NFData a, Integral a) => NFDataIntegral a") + '("NFDataOrd" . "class (NFData a, Ord a) => NFDataOrd a") + + '("markStrat" . "Int -> Strategy a -> Strategy a") + + '("seqPair" . "Strategy a -> Strategy b -> Strategy (a,b)") + '("parPair" . "Strategy a -> Strategy b -> Strategy (a,b)") + '("seqTriple" . "Strategy a -> Strategy b -> Strategy c -> Strategy (a,b,c)") + '("parTriple" . "Strategy a -> Strategy b -> Strategy c -> Strategy (a,b,c)") + + '("parList" . "Strategy a -> Strategy [a]") + '("parListN" . "(Integral b) => b -> Strategy a -> Strategy [a]") + '("parListNth" . "Int -> Strategy a -> Strategy [a]") + '("parListChunk" . "Int -> Strategy a -> Strategy [a]") + '("parMap" . "Strategy b -> (a -> b) -> [a] -> [b]") + '("parFlatMap" . "Strategy [b] -> (a -> [b]) -> [a] -> [b]") + '("parZipWith" . "Strategy c -> (a -> b -> c) -> [a] -> [b] -> [c]") + '("seqList" . "Strategy a -> Strategy [a]") + '("seqListN" . "(Integral a) => a -> Strategy b -> Strategy [b]") + '("seqListNth" . "Int -> Strategy b -> Strategy [b]") + + '("parBuffer" . "Int -> Strategy a -> [a] -> [a]") + + '("seqArr" . "(Ix b) => Strategy a -> Strategy (Array b a)") + '("parArr" . "(Ix b) => Strategy a -> Strategy (Array b a)") + + '("fstPairFstList" . "(NFData a) => Strategy [(a,b)]") + '("force" . "(NFData a) => a -> a ") + '("sforce" . "(NFData a) => a -> b -> b") + ) + "Alist of strategy functions and their types as defined in Strategies.lhs.") + +(defvar haskell-doc-user-defined-ids nil + "Alist of functions and strings defined by the user.") + + +(defsubst haskell-doc-is-of (fn types) + "Check whether FN is one of the functions in the alist TYPES and return the type." + (assoc fn types) ) + + +;; Put this minor mode on the global minor-mode-alist. +(or (assq 'haskell-doc-mode (default-value 'minor-mode-alist)) + (setq-default minor-mode-alist + (append (default-value 'minor-mode-alist) + '((haskell-doc-mode haskell-doc-minor-mode-string))))) + + +(defvar haskell-doc-keymap + (let ((map (make-sparse-keymap))) + (define-key map [visit] + '("Visit FTP home site" . haskell-doc-visit-home)) + (define-key map [submit] + '("Submit bug report" . haskell-doc-submit-bug-report)) + (define-key map [dummy] '("---" . nil)) + (define-key map [make-index] + '("Make global fct index" . haskell-doc-make-global-fct-index)) + (define-key map [global-types-on] + '("Toggle display of global types" . haskell-doc-show-global-types)) + (define-key map [strategy-on] + '("Toggle display of strategy ids" . haskell-doc-show-strategy)) + (define-key map [user-defined-on] + '("Toggle display of user defined ids" . haskell-doc-show-user-defined)) + (define-key map [prelude-on] + '("Toggle display of prelude functions" . haskell-doc-show-prelude)) + (define-key map [reserved-ids-on] + '("Toggle display of reserved ids" . haskell-doc-show-reserved)) + (define-key map [haskell-doc-on] + '("Toggle haskell-doc mode" . haskell-doc-mode)) + map)) + +(defun haskell-doc-install-keymap () + "Install a menu for `haskell-doc-mode' as a submenu of \"Hugs\"." + (interactive) + ;; Add the menu to the hugs menu as last entry. + (let ((hugsmap (lookup-key (current-local-map) [menu-bar Hugs]))) + (if (not (or (featurep 'xemacs) ; XEmacs has problems here + (not (keymapp hugsmap)) + (lookup-key hugsmap [haskell-doc]))) + (if (functionp 'define-key-after) + (define-key-after hugsmap [haskell-doc] + (cons "Haskell-doc" haskell-doc-keymap) + [Haskell-doc mode])))) + ;; Add shortcuts for these commands. + (local-set-key "\C-c\e/" 'haskell-doc-check-active) + ;; Conflicts with the binding of haskell-insert-otherwise. + ;; (local-set-key "\C-c\C-o" 'haskell-doc-mode) + (local-set-key [(control shift meta mouse-3)] + 'haskell-doc-ask-mouse-for-type)) + + +(defvar haskell-doc-timer nil) +(defvar haskell-doc-buffers nil) + +;;;###autoload +(defun haskell-doc-mode (&optional arg) + "Enter `haskell-doc-mode' for showing fct types in the echo area. +See variable docstring." + (interactive (list (or current-prefix-arg 'toggle))) + + (setq haskell-doc-mode + (cond + ((eq arg 'toggle) (not haskell-doc-mode)) + (arg (> (prefix-numeric-value arg) 0)) + (t))) + + ;; First, unconditionally turn the mode OFF. + + (setq haskell-doc-buffers (delq (current-buffer) haskell-doc-buffers)) + ;; Refresh the buffers list. + (dolist (buf haskell-doc-buffers) + (unless (and (buffer-live-p buf) + (with-current-buffer buf haskell-doc-mode)) + (setq haskell-doc-buffers (delq buf haskell-doc-buffers)))) + ;; Turn off the idle timer (or idle post-command-hook). + (when (and haskell-doc-timer (null haskell-doc-buffers)) + (cancel-timer haskell-doc-timer) + (setq haskell-doc-timer nil)) + (remove-hook 'post-command-hook + 'haskell-doc-mode-print-current-symbol-info 'local) + + (when haskell-doc-mode + ;; Turning the mode ON. + (push (current-buffer) haskell-doc-buffers) + + (if (fboundp 'run-with-idle-timer) + (unless haskell-doc-timer + (setq haskell-doc-timer + (run-with-idle-timer + haskell-doc-idle-delay t + 'haskell-doc-mode-print-current-symbol-info))) + (add-hook 'post-command-hook + 'haskell-doc-mode-print-current-symbol-info nil 'local)) + (and haskell-doc-show-global-types + (haskell-doc-make-global-fct-index)) ; build type index for global fcts + + (haskell-doc-install-keymap) + + (run-hooks 'haskell-doc-mode-hook)) + + (and (called-interactively-p 'any) + (message "haskell-doc-mode is %s" + (if haskell-doc-mode "enabled" "disabled"))) + haskell-doc-mode) + +(defmacro haskell-doc-toggle-var (id prefix) + ;; toggle variable or set it based on prefix value + `(setq ,id + (if ,prefix + (>= (prefix-numeric-value ,prefix) 0) + (not ,id))) ) + +(defun haskell-doc-show-global-types (&optional prefix) + "Turn on global types information in `haskell-doc-mode'." + (interactive "P") + (haskell-doc-toggle-var haskell-doc-show-global-types prefix) + (if haskell-doc-show-global-types + (haskell-doc-make-global-fct-index))) + +(defun haskell-doc-show-reserved (&optional prefix) + "Toggle the automatic display of a doc string for reserved ids." + (interactive "P") + (haskell-doc-toggle-var haskell-doc-show-reserved prefix)) + +(defun haskell-doc-show-prelude (&optional prefix) + "Toggle the automatic display of a doc string for reserved ids." + (interactive "P") + (haskell-doc-toggle-var haskell-doc-show-prelude prefix)) + +(defun haskell-doc-show-strategy (&optional prefix) + "Toggle the automatic display of a doc string for strategy ids." + (interactive "P") + (haskell-doc-toggle-var haskell-doc-show-strategy prefix)) + +(defun haskell-doc-show-user-defined (&optional prefix) + "Toggle the automatic display of a doc string for user defined ids." + (interactive "P") + (haskell-doc-toggle-var haskell-doc-show-user-defined prefix)) + + +;;;###autoload +(defalias 'turn-on-haskell-doc-mode 'haskell-doc-mode) +(make-obsolete 'turn-on-haskell-doc-mode + 'haskell-doc-mode + "2015-07-23") + +;;;###autoload +(defalias 'turn-on-haskell-doc 'haskell-doc-mode) +(make-obsolete 'turn-on-haskell-doc + 'haskell-doc-mode + "2015-07-23") + +(defalias 'turn-off-haskell-doc-mode 'turn-off-haskell-doc) + +(defun turn-off-haskell-doc () + "Unequivocally turn off `haskell-doc-mode' (which see)." + (haskell-doc-mode 0)) + +(defun haskell-doc-check-active () + "Check whether the print function is hooked in. +Should be the same as the value of `haskell-doc-mode' but alas currently it +is not." + (interactive) + (message "%s" + (if (or (and haskell-doc-mode haskell-doc-timer) + (memq 'haskell-doc-mode-print-current-symbol-info + post-command-hook)) + "haskell-doc is ACTIVE" + (substitute-command-keys + "haskell-doc is not ACTIVE \(Use \\[haskell-doc-mode] to turn it on\)")))) + + +;; This is the function hooked into the elisp command engine +(defun haskell-doc-mode-print-current-symbol-info () + "Print the type of the symbol under the cursor. + +This function is run by an idle timer to print the type + automatically if `haskell-doc-mode' is turned on." + (and haskell-doc-mode + (haskell-doc-in-code-p) + (not haskell-mode-interactive-prompt-state) + (not (eobp)) + (not executing-kbd-macro) + ;; Having this mode operate in the minibuffer makes it impossible to + ;; see what you're doing. + (not (eq (selected-window) (minibuffer-window))) + ;; not in string or comment + ;; take a nap, if run straight from post-command-hook. + (if (fboundp 'run-with-idle-timer) t + (sit-for haskell-doc-idle-delay)) + ;; good morning! read the word under the cursor for breakfast + (haskell-doc-show-type))) +;; ;; ToDo: find surrounding fct +;; (cond ((eq current-symbol current-fnsym) +;; (haskell-doc-show-type current-fnsym)) +;; (t +;; (or nil ; (haskell-doc-print-var-docstring current-symbol) +;; (haskell-doc-show-type current-fnsym))))))) + +;;;###autoload +(defun haskell-doc-current-info () + "Return the info about symbol at point. +Meant for `eldoc-documentation-function'." + ;; There are a number of possible documentation functions. + ;; Some of them are asynchronous. + (when (haskell-doc-in-code-p) + (let ((msg (or + (haskell-doc-current-info--interaction) + (haskell-doc-sym-doc (haskell-ident-at-point))))) + (unless (symbolp msg) msg)))) + +(defun haskell-doc-ask-mouse-for-type (event) + "Read the identifier under the mouse and echo its type. +This uses the same underlying function `haskell-doc-show-type' as the hooked +function. Only the user interface is different." + (interactive "e") + (save-excursion + (select-window (posn-window (event-end event))) + (goto-char (posn-point (event-end event))) + (haskell-doc-show-type))) + +(defun haskell-doc-in-code-p () + "A predicate indicating suitable case to show docs." + (not (or (and (eq haskell-literate 'bird) + ;; Copied from haskell-indent-bolp. + (<= (current-column) 2) + (eq (char-after (line-beginning-position)) ?\>)) + (nth 8 (syntax-ppss))))) + +;;;###autoload +(defun haskell-doc-show-type (&optional sym) + "Show the type of the function near point or given symbol SYM. +For the function under point, show the type in the echo area. +This information is extracted from the `haskell-doc-prelude-types' alist +of prelude functions and their types, or from the local functions in the +current buffer." + (interactive) + (unless sym (setq sym (haskell-ident-at-point))) + ;; if printed before do not print it again + (unless (string= sym (car haskell-doc-last-data)) + (let ((doc (or (haskell-doc-current-info--interaction t) + (haskell-doc-sym-doc sym)))) + (when (and doc (haskell-doc-in-code-p)) + ;; In Emacs 19.29 and later, and XEmacs 19.13 and later, all + ;; messages are recorded in a log. Do not put haskell-doc messages + ;; in that log since they are legion. + (let ((message-log-max nil)) + (message "%s" doc)))))) + +(defvar haskell-doc-current-info--interaction-last nil + "Async message stack. +If non-nil, a previous eldoc message from an async call, that +hasn't been displayed yet.") + +(defun haskell-doc-current-info--interaction (&optional sync) + "Asynchronous call to `haskell-process-get-type'. +Suitable for use in the eldoc function `haskell-doc-current-info'. + +If SYNC is non-nil, the call will be synchronous instead, and +instead of calling `eldoc-print-current-symbol-info', the result +will be returned directly." + ;; Return nil if nothing is available, or 'async if something might + ;; be available, but asynchronously later. This will call + ;; `eldoc-print-current-symbol-info' later. + (when (haskell-doc-in-code-p) + ;; do nothing when inside string or comment + (let (sym prev-message) + (cond + ((setq prev-message haskell-doc-current-info--interaction-last) + (setq haskell-doc-current-info--interaction-last nil) + (cdr prev-message)) + ((setq sym + (if (use-region-p) + (buffer-substring-no-properties + (region-beginning) (region-end)) + (haskell-ident-at-point))) + (if sync + (haskell-process-get-type sym #'identity t) + (haskell-process-get-type + sym (lambda (response) + (setq haskell-doc-current-info--interaction-last + (cons 'async response)) + (eldoc-print-current-symbol-info))))))))) + +(defun haskell-process-get-type (expr-string &optional callback sync) + "Asynchronously get the type of a given string. + +EXPR-STRING should be an expression passed to :type in ghci. + +CALLBACK will be called with a formatted type string. + +If SYNC is non-nil, make the call synchronously instead." + (unless callback (setq callback (lambda (response) (message "%s" response)))) + (let ((process (and (haskell-session-maybe) + (haskell-session-process (haskell-session-maybe)))) + ;; Avoid passing bad strings to ghci + (expr-okay + (and (not (string-match-p "\\`[[:space:]]*\\'" expr-string)) + (not (string-match-p "\n" expr-string)))) + (ghci-command (concat ":type " expr-string)) + (process-response + (lambda (response) + ;; Responses with empty first line are likely errors + (if (string-match-p (rx string-start line-end) response) + (setq response nil) + ;; Remove a newline at the end + (setq response (replace-regexp-in-string "\n\\'" "" response)) + ;; Propertize for eldoc + (save-match-data + (when (string-match " :: " response) + ;; Highlight type + (let ((name (substring response 0 (match-end 0))) + (type (propertize + (substring response (match-end 0)) + 'face 'eldoc-highlight-function-argument))) + (setq response (concat name type))))) + (when haskell-doc-prettify-types + (dolist (re '(("::" . "∷") ("=>" . "⇒") ("->" . "→"))) + (setq response + (replace-regexp-in-string (car re) (cdr re) response)))) + response)))) + (when (and process expr-okay) + (if sync + (let ((response (haskell-process-queue-sync-request process ghci-command))) + (funcall callback (funcall process-response response))) + (haskell-process-queue-command + process + (make-haskell-command + :go (lambda (_) (haskell-process-send-string process ghci-command)) + :complete + (lambda (_ response) + (funcall callback (funcall process-response response))))) + 'async)))) + +(defun haskell-doc-sym-doc (sym) + "Show the type of given symbol SYM. +For the function under point, show the type in the echo area. +This information is extracted from the `haskell-doc-prelude-types' alist +of prelude functions and their types, or from the local functions in the +current buffer. +If `haskell-doc-use-inf-haskell' is non-nil, this function will consult +the inferior Haskell process for type/kind information, rather than using +the haskell-doc database." + (if haskell-doc-use-inf-haskell + (unless (or (null sym) (string= "" sym)) + (let* ((message-log-max nil) + (result (ignore-errors + (unwind-protect + (inferior-haskell-type sym) + (message ""))))) + (if (and result (string-match " :: " result)) + result + (setq result (unwind-protect + (inferior-haskell-kind sym) + (message ""))) + (and result (string-match " :: " result) result)))) + (let ((i-am-prelude nil) + (i-am-fct nil) + (type nil) + (is-reserved (haskell-doc-is-of sym haskell-doc-reserved-ids)) + (is-prelude (haskell-doc-is-of sym haskell-doc-prelude-types)) + (is-strategy (haskell-doc-is-of sym haskell-doc-strategy-ids)) + (is-user-defined (haskell-doc-is-of sym haskell-doc-user-defined-ids))) + (cond + ;; if reserved id (i.e. Haskell keyword + ((and haskell-doc-show-reserved + is-reserved) + (setq type (cdr is-reserved)) + (setcdr haskell-doc-last-data type)) + ;; if built-in function get type from docstring + ((and (not (null haskell-doc-show-prelude)) + is-prelude) + (setq type (cdr is-prelude)) ; (cdr (assoc sym haskell-doc-prelude-types))) + (if (= 2 (length type)) ; horrible hack to remove bad formatting + (setq type (car (cdr type)))) + (setq i-am-prelude t) + (setq i-am-fct t) + (setcdr haskell-doc-last-data type)) + ((and haskell-doc-show-strategy + is-strategy) + (setq i-am-fct t) + (setq type (cdr is-strategy)) + (setcdr haskell-doc-last-data type)) + ((and haskell-doc-show-user-defined + is-user-defined) + ;; (setq i-am-fct t) + (setq type (cdr is-user-defined)) + (setcdr haskell-doc-last-data type)) + (t + (let ( (x (haskell-doc-get-and-format-fct-type sym)) ) + (if (null x) + (setcdr haskell-doc-last-data nil) ; if not found reset last data + (setq type (car x)) + (setq i-am-fct (string= "Variables" (cdr x))) + (if (and haskell-doc-show-global-types (null type)) + (setq type (haskell-doc-get-global-fct-type sym))) + (setcdr haskell-doc-last-data type)))) ) + ;; ToDo: encode i-am-fct info into alist of types + (and type + ;; drop `::' if it's not a fct + (let ( (str (cond ((and i-am-fct (not haskell-doc-chop-off-fctname)) + (format "%s :: %s" sym type)) + (t + (format "%s" type)))) ) + (if i-am-prelude + (add-text-properties 0 (length str) '(face bold) str)) + str))))) + + +;; ToDo: define your own notion of `near' to find surrounding fct +;;(defun haskell-doc-fnsym-in-current-sexp () +;; (let* ((p (point)) +;; (sym (progn +;; (forward-word -1) +;; (while (and (forward-word -1) ; (haskell-doc-forward-sexp-safe -1) +;; (> (point) (point-min)))) +;; (cond ((or (= (point) (point-min)) +;; (memq (or (char-after (point)) 0) +;; '(?\( ?\")) +;; ;; If we hit a quotation mark before a paren, we +;; ;; are inside a specific string, not a list of +;; ;; symbols. +;; (eq (or (char-after (1- (point))) 0) ?\")) +;; nil) +;; (t (condition-case nil +;; (read (current-buffer)) +;; (error nil))))))) +;; (goto-char p) +;; (if sym +;; (format "%s" sym) +;; sym))) + +;; (and (symbolp sym) +;; sym))) + + +;; ToDo: handle open brackets to decide if it's a wrapped type + +(defun haskell-doc-grab-line (fct-and-pos) + "Get the type of an \(FCT POSITION\) pair from the current buffer." + ;; (if (null fct-and-pos) + ;; "" ; fn is not a local fct + (let ( (str "")) + (goto-char (cdr fct-and-pos)) + (beginning-of-line) + ;; search for start of type (phsp give better bound?) + (if (null (search-forward "::" (+ (point) haskell-doc-search-distance) t)) + "" + (setq str (haskell-doc-grab)) ; leaves point at end of line + (while (haskell-doc-wrapped-type-p) ; while in a multi-line type expr + (forward-line 1) + (beginning-of-line) + (skip-chars-forward " \t") + (setq str (concat str (haskell-doc-grab)))) + (haskell-doc-string-nub-ws ; squeeze string + (if haskell-doc-chop-off-context ; no context + (haskell-doc-chop-off-context str) + str))))) +;; (concat (car fct-and-pos) "::" (haskell-doc-string-nub-ws str)))) + +(defun haskell-doc-wrapped-type-p () + "Check whether the type under the cursor is wrapped over several lines. +The cursor must be at the end of a line, which contains the type. +Currently, only the following is checked: +If this line ends with a `->' or the next starts with an `->' it is a +multi-line type \(same for `=>'\). +`--' comments are ignored. +ToDo: Check for matching parenthesis!." + (save-excursion + (let ( (here (point)) + (lim (progn (beginning-of-line) (point))) + ;; (foo "") + (res nil) + ) + (goto-char here) + (search-backward "--" lim t) ; skip over `--' comment + (skip-chars-backward " \t") + (if (bolp) ; skip empty lines + (progn + (forward-line 1) + (end-of-line) + (setq res (haskell-doc-wrapped-type-p))) + (forward-char -1) + ;; (setq foo (concat foo (char-to-string (preceding-char)) (char-to-string (following-char)))) + (if (or (and (or (char-equal (preceding-char) ?-) (char-equal (preceding-char) ?=)) + (char-equal (following-char) ?>)) ; (or -!> =!> + (char-equal (following-char) ?,)) ; !,) + (setq res t) + (forward-line) + (let ((here (point))) + (goto-char here) + (skip-chars-forward " \t") + (if (looking-at "--") ; it is a comment line + (progn + (forward-line 1) + (end-of-line) + (setq res (haskell-doc-wrapped-type-p))) + (forward-char 1) + ;; (setq foo (concat foo (char-to-string (preceding-char)) (char-to-string (following-char)))) + ;; (message "|%s|" foo) + (if (and (or (char-equal (preceding-char) ?-) (char-equal (preceding-char) ?=)) + (char-equal (following-char) ?>)) ; -!> or =!> + (setq res t)))))) + res))) + +(defun haskell-doc-grab () + "Return the text from point to the end of the line, chopping off comments. +Leaves point at end of line." + (let ((str (buffer-substring-no-properties + (point) (progn (end-of-line) (point))))) + (if (string-match "--" str) + (substring str 0 (match-beginning 0)) + str))) + +(defun haskell-doc-string-nub-ws (str) + "Replace all sequences of whitespace in STR by just one space. +ToDo: Also eliminate leading and trailing whitespace." + (let ((i -1)) + (while (setq i (string-match " [ \t\n]+\\|[\t\n]+" str (1+ i))) + (setq str (replace-match " " t t str))) + str)) + +(defun haskell-doc-chop-off-context (str) + "Eliminate the context in a type represented by the string STR." + (let ((i (string-match "=>" str)) ) + (if (null i) + str + (substring str (+ i 2))))) + +(defun haskell-doc-get-imenu-info (obj kind) + "Return a string describing OBJ of KIND \(Variables, Types, Data\)." + (cond + ((eq major-mode 'haskell-mode) + (let* ((imenu-info-alist (cdr (assoc kind imenu--index-alist))) + ;; (names (mapcar 'car imenu-info-alist)) + (x (assoc obj imenu-info-alist))) + (when x (haskell-doc-grab-line x)))) + + (t ;; (error "Cannot get local functions in %s mode, sorry" major-mode))) + nil))) + +;; ToDo: +;; - modular way of defining a mapping of module name to file +;; - use a path to search for file (not just current directory) + + +(defun haskell-doc-imported-list () + "Return a list of the imported modules in current buffer." + (interactive "fName of outer `include' file: ") ; (buffer-file-name)) + ;; Don't add current buffer to the imported file list if it is not (yet?) + ;; visiting a file since it leads to errors further down. + (let ((imported-file-list (and buffer-file-name (list buffer-file-name)))) + (widen) + (goto-char (point-min)) + (while (re-search-forward "^\\s-*import\\s-+\\([^ \t\n]+\\)" nil t) + (let ((basename (match-string 1))) + (dolist (ext '(".hs" ".lhs")) + (let ((file (concat basename ext))) + (if (file-exists-p file) + (push file imported-file-list)))))) + (nreverse imported-file-list) + ;;(message imported-file-list) + )) + +;; ToDo: generalise this to "Types" etc (not just "Variables") + +(defun haskell-doc-rescan-files (filelist) + "Do an `imenu' rescan on every file in FILELIST and return the fct-list. +This function switches to and potentially loads many buffers." + (save-current-buffer + (mapcar (lambda (f) + (set-buffer (find-file-noselect f)) + (imenu--make-index-alist t) + (cons f + (mapcar (lambda (x) + `(,(car x) . ,(haskell-doc-grab-line x))) + (cdr (assoc "Variables" imenu--index-alist))))) + filelist))) + +(defun haskell-doc-make-global-fct-index () + "Scan imported files for types of global fcts and update `haskell-doc-index'." + (interactive) + (setq haskell-doc-index + (haskell-doc-rescan-files (haskell-doc-imported-list)))) + +;; ToDo: use a separate munge-type function to format type concisely + +(defun haskell-doc-get-global-fct-type (&optional sym) + "Get type for function symbol SYM by examining `haskell-doc-index'." + (interactive) ; "fName of outer `include' file: \nsFct:") + (save-excursion + ;; (switch-to-buffer "*scratch*") + ;; (goto-char (point-max)) + ;; ;; Produces a list of fct-type alists + ;; (if (null sym) + ;; (setq sym (progn (forward-word -1) (read (current-buffer))))) + (or sym + (current-word)) + (let* ( (fn sym) ; (format "%s" sym)) + (fal haskell-doc-index) + (res "") ) + (while (not (null fal)) + (let* ( (l (car fal)) + (f (car l)) + (x (assoc fn (cdr l))) ) + (if (not (null x)) + (let* ( (ty (cdr x)) ; the type as string + (idx (string-match "::" ty)) + (str (if (null idx) + ty + (substring ty (+ idx 2)))) ) + (setq res (format "[%s] %s" f str)))) + (setq fal (cdr fal)))) + res))) ; (message res)) ) + +(defun haskell-doc-get-and-format-fct-type (fn) + "Get the type and kind of FN by checking local and global functions." + (save-excursion + (save-match-data + (let ((docstring "") + (doc nil) + ) + ;; is it a local function? + (setq docstring (haskell-doc-get-imenu-info fn "Variables")) + (if (not (null docstring)) + ;; (string-match (format "^%s\\s-+::\\s-+\\(.*\\)$" fn) docstring)) + (setq doc `(,docstring . "Variables"))) ; `(,(match-string 1 docstring) . "Variables") )) + ;; is it a type declaration? + (setq docstring (haskell-doc-get-imenu-info fn "Types")) + (if (not (null docstring)) + ;; (string-match (format "^\\s-*type\\s-+%s.*$" fn) docstring)) + (setq doc `(,docstring . "Types"))) ; `(,(match-string 0 docstring) . "Types")) ) + (if (not (null docstring)) + ;; (string-match (format "^\\s-*data.*%s.*$" fn) docstring)) + (setq doc `(,docstring . "Data"))) ; (setq doc `(,(match-string 0 docstring) . "Data")) ) + ;; 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 diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-doc.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-doc.elc new file mode 100644 index 000000000000..b7629b4ccc3f --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-doc.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-font-lock.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-font-lock.el new file mode 100644 index 000000000000..8360c7dd06e3 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-font-lock.el @@ -0,0 +1,711 @@ +;;; haskell-font-lock.el --- Font locking module for Haskell Mode -*- lexical-binding: t -*- + +;; Copyright 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +;; Copyright 1997-1998 Graeme E Moss, and Tommy Thorn + +;; Author: 1997-1998 Graeme E Moss <gem@cs.york.ac.uk> +;; 1997-1998 Tommy Thorn <thorn@irisa.fr> +;; 2003 Dave Love <fx@gnu.org> +;; Keywords: faces files Haskell + +;; This file is not part of GNU Emacs. + +;; 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 <http://www.gnu.org/licenses/>. + + +;;; Code: + +(require 'cl-lib) +(require 'haskell-compat) +(require 'haskell-lexeme) +(require 'font-lock) + +;;;###autoload +(defgroup haskell-appearance nil + "Haskell Appearance." + :group 'haskell) + + +(defcustom haskell-font-lock-symbols nil + "Display \\ and -> and such using symbols in fonts. + +This may sound like a neat trick, but be extra careful: it changes the +alignment and can thus lead to nasty surprises with regards to layout." + :group 'haskell-appearance + :type 'boolean) + +(defcustom haskell-font-lock-symbols-alist + '(("\\" . "λ") + ("not" . "¬") + ("->" . "→") + ("<-" . "←") + ("=>" . "⇒") + ("()" . "∅") + ("==" . "≡") + ("/=" . "≢") + (">=" . "≥") + ("<=" . "≤") + ("!!" . "‼") + ("&&" . "∧") + ("||" . "∨") + ("sqrt" . "√") + ("undefined" . "⊥") + ("pi" . "π") + ("~>" . "⇝") ;; Omega language + ;; ("~>" "↝") ;; less desirable + ("-<" . "↢") ;; Paterson's arrow syntax + ;; ("-<" "⤙") ;; nicer but uncommon + ("::" . "∷") + ("." "∘" ; "○" + ;; Need a predicate here to distinguish the . used by + ;; forall <foo> . <bar>. + haskell-font-lock-dot-is-not-composition) + ("forall" . "∀")) + "Alist mapping Haskell symbols to chars. + +Each element has the form (STRING . COMPONENTS) or (STRING +COMPONENTS PREDICATE). + +STRING is the Haskell symbol. +COMPONENTS is a representation specification suitable as an argument to +`compose-region'. +PREDICATE if present is a function of one argument (the start position +of the symbol) which should return non-nil if this mapping should +be disabled at that position." + :type '(alist string string) + :group 'haskell-appearance) + +(defcustom haskell-font-lock-keywords + ;; `as', `hiding', and `qualified' are part of the import + ;; spec syntax, but they are not reserved. + ;; `_' can go in here since it has temporary word syntax. + '("case" "class" "data" "default" "deriving" "do" + "else" "if" "import" "in" "infix" "infixl" + "infixr" "instance" "let" "module" "mdo" "newtype" "of" + "rec" "pattern" "proc" "signature" "then" "type" "where" "_") + "Identifiers treated as reserved keywords in Haskell." + :group 'haskell-appearance + :type '(repeat string)) + + +(defun haskell-font-lock-dot-is-not-composition (start) + "Return non-nil if the \".\" at START is not a composition operator. +This is the case if the \".\" is part of a \"forall <tvar> . <type>\"." + (save-excursion + (goto-char start) + (or (re-search-backward "\\<forall\\>[^.\"]*\\=" + (line-beginning-position) t) + (not (or + (string= " " (string (char-after start))) + (null (char-before start)) + (string= " " (string (char-before start)))))))) + +(defvar haskell-yesod-parse-routes-mode-keywords + '(("^\\([^ \t\n]+\\)\\(?:[ \t]+\\([^ \t\n]+\\)\\)?" + (1 'font-lock-string-face) + (2 'haskell-constructor-face nil lax)))) + +(define-derived-mode haskell-yesod-parse-routes-mode text-mode "Yesod parseRoutes mode" + "Mode for parseRoutes from Yesod." + (setq-local font-lock-defaults '(haskell-yesod-parse-routes-mode-keywords t t nil nil))) + +(defcustom haskell-font-lock-quasi-quote-modes + `(("hsx" . xml-mode) + ("hamlet" . shakespeare-hamlet-mode) + ("shamlet" . shakespeare-hamlet-mode) + ("whamlet" . shakespeare-hamlet-mode) + ("xmlQQ" . xml-mode) + ("xml" . xml-mode) + ("cmd" . shell-mode) + ("sh_" . shell-mode) + ("jmacro" . javascript-mode) + ("jmacroE" . javascript-mode) + ("r" . ess-mode) + ("rChan" . ess-mode) + ("sql" . sql-mode) + ("json" . json-mode) + ("aesonQQ" . json-mode) + ("parseRoutes" . haskell-yesod-parse-routes-mode)) + "Mapping from quasi quoter token to fontification mode. + +If a quasi quote is seen in Haskell code its contents will have +font faces assigned as if respective mode was enabled." + :group 'haskell-appearance + :type '(repeat (cons string symbol))) + +;;;###autoload +(defface haskell-keyword-face + '((t :inherit font-lock-keyword-face)) + "Face used to highlight Haskell keywords." + :group 'haskell-appearance) + +;;;###autoload +(defface haskell-type-face + '((t :inherit font-lock-type-face)) + "Face used to highlight Haskell types" + :group 'haskell-appearance) + +;;;###autoload +(defface haskell-constructor-face + '((t :inherit font-lock-type-face)) + "Face used to highlight Haskell constructors." + :group 'haskell-appearance) + +;; This used to be `font-lock-variable-name-face' but it doesn't result in +;; a highlighting that's consistent with other modes (it's mostly used +;; for function defintions). +(defface haskell-definition-face + '((t :inherit font-lock-function-name-face)) + "Face used to highlight Haskell definitions." + :group 'haskell-appearance) + +;; This is probably just wrong, but it used to use +;; `font-lock-function-name-face' with a result that was not consistent with +;; other major modes, so I just exchanged with `haskell-definition-face'. +;;;###autoload +(defface haskell-operator-face + '((t :inherit font-lock-variable-name-face)) + "Face used to highlight Haskell operators." + :group 'haskell-appearance) + +;;;###autoload +(defface haskell-pragma-face + '((t :inherit font-lock-preprocessor-face)) + "Face used to highlight Haskell pragmas ({-# ... #-})." + :group 'haskell-appearance) + +;;;###autoload +(defface haskell-liquid-haskell-annotation-face + '((t :inherit haskell-pragma-face)) + "Face used to highlight LiquidHaskell annotations ({-@ ... @-})." + :group 'haskell-appearance) + +;;;###autoload +(defface haskell-literate-comment-face + '((t :inherit font-lock-doc-face)) + "Face with which to fontify literate comments. +Inherit from `default' to avoid fontification of them." + :group 'haskell-appearance) + +(defface haskell-quasi-quote-face + '((t :inherit font-lock-string-face)) + "Generic face for quasiquotes. + +Some quote types are fontified according to other mode defined in +`haskell-font-lock-quasi-quote-modes'." + :group 'haskell-appearance) + +(defun haskell-font-lock-compose-symbol (alist) + "Compose a sequence of ascii chars into a symbol. +Regexp match data 0 points to the chars." + ;; Check that the chars should really be composed into a symbol. + (let* ((start (match-beginning 0)) + (end (match-end 0)) + (syntaxes (cond + ((eq (char-syntax (char-after start)) ?w) '(?w)) + ((eq (char-syntax (char-after start)) ?.) '(?.)) + ;; Special case for the . used for qualified names. + ((and (eq (char-after start) ?\.) (= end (1+ start))) + '(?_ ?\\ ?w)) + (t '(?_ ?\\)))) + sym-data) + (if (or (memq (char-syntax (or (char-before start) ?\ )) syntaxes) + (memq (char-syntax (or (char-after end) ?\ )) syntaxes) + (or (elt (syntax-ppss) 3) (elt (syntax-ppss) 4)) + (and (consp (setq sym-data (cdr (assoc (match-string 0) alist)))) + (let ((pred (cadr sym-data))) + (setq sym-data (car sym-data)) + (funcall pred start)))) + ;; No composition for you. Let's actually remove any composition + ;; we may have added earlier and which is now incorrect. + (remove-text-properties start end '(composition)) + ;; That's a symbol alright, so add the composition. + (compose-region start end sym-data))) + ;; Return nil because we're not adding any face property. + nil) + +(defun haskell-font-lock-symbols-keywords () + (when (and haskell-font-lock-symbols + haskell-font-lock-symbols-alist) + `((,(regexp-opt (mapcar 'car haskell-font-lock-symbols-alist) t) + (0 (haskell-font-lock-compose-symbol ',haskell-font-lock-symbols-alist) + ;; In Emacs-21, if the `override' field is nil, the face + ;; expressions is only evaluated if the text has currently + ;; no face. So force evaluation by using `keep'. + keep))))) + +(defun haskell-font-lock--forward-type (&optional ignore) + "Find where does this type declaration end. + +Moves the point to the end of type declaration. It should be +invoked with point just after one of type introducing keywords +like ::, class, instance, data, newtype, type." + (interactive) + (let ((cont t) + (end (point)) + (token nil) + ;; we are starting right after :: + (last-token-was-operator t) + (last-token-was-newline nil) + (open-parens 0)) + (while cont + (setq token (haskell-lexeme-looking-at-token 'newline)) + + (cond + ((null token) + (setq cont nil)) + ((member token '(newline)) + (setq last-token-was-newline (not last-token-was-operator)) + (setq end (match-end 0)) + (goto-char (match-end 0))) + ((member (match-string-no-properties 0) + '(")" "]" "}")) + (setq open-parens (1- open-parens)) + (if (< open-parens 0) + ;; unmatched closing parenthesis closes type declaration + (setq cont nil) + (setq end (match-end 0)) + (goto-char end)) + (setq last-token-was-newline nil)) + ((and (member (match-string-no-properties 0) + '("," ";" "|")) + (not (member (match-string-no-properties 0) ignore))) + (if (equal 0 open-parens) + (setq cont nil) + (setq last-token-was-operator t) + (setq end (match-end 0)) + (goto-char end)) + (setq last-token-was-newline nil)) + ((and (or (member (match-string-no-properties 0) + '("<-" "=" "←")) + (member (match-string-no-properties 0) haskell-font-lock-keywords)) + (not (member (match-string-no-properties 0) ignore))) + (setq cont nil) + (setq last-token-was-newline nil)) + ((member (match-string-no-properties 0) + '("(" "[" "{")) + (if last-token-was-newline + (setq cont nil) + (setq open-parens (1+ open-parens)) + (setq end (match-end 0)) + (goto-char end) + (setq last-token-was-newline nil))) + ((member token '(qsymid char string number template-haskell-quote template-haskell-quasi-quote)) + (setq last-token-was-operator (member (haskell-lexeme-classify-by-first-char (char-after (match-beginning 1))) + '(varsym consym))) + (if (and (not last-token-was-operator) last-token-was-newline) + (setq cont nil) + + (goto-char (match-end 0)) + (setq end (point))) + (setq last-token-was-newline nil)) + ((member token '(comment nested-comment literate-comment)) + (goto-char (match-end 0)) + (setq end (point))) + (t + (goto-char (match-end 0)) + (setq end (point)) + (setq last-token-was-newline nil)))) + (goto-char end))) + + +(defun haskell-font-lock--select-face-on-type-or-constructor () + "Private function used to select either type or constructor face +on an uppercase identifier." + (cl-case (haskell-lexeme-classify-by-first-char (char-after (match-beginning 1))) + (varid (let ((word (match-string-no-properties 0))) + (cond + ((member word haskell-font-lock-keywords) + ;; Note: keywords parse as keywords only when not qualified. + ;; GHC parses Control.let as a single but illegal lexeme. + (when (member word '("class" "instance" "type" "data" "newtype")) + (save-excursion + (goto-char (match-end 0)) + (save-match-data + (haskell-font-lock--forward-type + (cond + ((member word '("class" "instance")) + '("|")) + ((member word '("type")) + ;; Need to support 'type instance' + '("=" "instance"))))) + (add-text-properties (match-end 0) (point) '(font-lock-multiline t haskell-type t)))) + 'haskell-keyword-face) + ((member word '("forall")) + (when (get-text-property (match-beginning 0) 'haskell-type) + 'haskell-keyword-face))))) + (conid (if (get-text-property (match-beginning 0) 'haskell-type) + 'haskell-type-face + 'haskell-constructor-face)) + (varsym (unless (and (member (match-string 0) '("-" "+" ".")) + (equal (string-to-syntax "w") (syntax-after (match-beginning 0)))) + ;; We need to protect against the case of + ;; plus, minus or dot inside a floating + ;; point number. + 'haskell-operator-face)) + (consym (if (not (member (match-string 1) '("::" "∷"))) + (if (get-text-property (match-beginning 0) 'haskell-type) + 'haskell-type-face + 'haskell-constructor-face) + (save-excursion + (goto-char (match-end 0)) + (save-match-data + (haskell-font-lock--forward-type)) + (add-text-properties (match-end 0) (point) '(font-lock-multiline t haskell-type t))) + 'haskell-operator-face)))) + +(defun haskell-font-lock--put-face-on-type-or-constructor () + "Private function used to put either type or constructor face +on an uppercase identifier." + (let ((face (haskell-font-lock--select-face-on-type-or-constructor))) + (when (and face + (not (text-property-not-all (match-beginning 0) (match-end 0) 'face nil))) + (put-text-property (match-beginning 0) (match-end 0) 'face face)))) + + +(defun haskell-font-lock-keywords () + ;; this has to be a function because it depends on global value of + ;; `haskell-font-lock-symbols' + "Generate font lock eywords." + (let* (;; Bird-style literate scripts start a line of code with + ;; "^>", otherwise a line of code starts with "^". + (line-prefix "^\\(?:> ?\\)?") + + (varid "[[:lower:]_][[:alnum:]'_]*") + ;; We allow ' preceding conids because of DataKinds/PolyKinds + (conid "'?[[:upper:]][[:alnum:]'_]*") + (sym "\\s.+") + + ;; Top-level declarations + (topdecl-var + (concat line-prefix "\\(" varid "\\(?:\\s-*,\\s-*" varid "\\)*" "\\)" + ;; optionally allow for a single newline after identifier + "\\(\\s-+\\|\\s-*[\n]\\s-+\\)" + ;; A toplevel declaration can be followed by a definition + ;; (=), a type (::) or (∷), a guard, or a pattern which can + ;; either be a variable, a constructor, a parenthesized + ;; thingy, or an integer or a string. + "\\(" varid "\\|" conid "\\|::\\|∷\\|=\\||\\|\\s(\\|[0-9\"']\\)")) + (topdecl-var2 + (concat line-prefix "\\(" varid "\\|" conid "\\)\\s-*`\\(" varid "\\)`")) + (topdecl-bangpat + (concat line-prefix "\\(" varid "\\)\\s-*!")) + (topdecl-sym + (concat line-prefix "\\(" varid "\\|" conid "\\)\\s-*\\(" sym "\\)")) + (topdecl-sym2 (concat line-prefix "(\\(" sym "\\))")) + + keywords) + + (setq keywords + `(;; NOTICE the ordering below is significant + ;; + ("^#\\(?:[^\\\n]\\|\\\\\\(?:.\\|\n\\|\\'\\)\\)*\\(?:\n\\|\\'\\)" 0 'font-lock-preprocessor-face t) + + ,@(haskell-font-lock-symbols-keywords) + + ;; Special case for `as', `hiding', `safe' and `qualified', which are + ;; keywords in import statements but are not otherwise reserved. + ("\\<import[ \t]+\\(?:\\(safe\\>\\)[ \t]*\\)?\\(?:\\(qualified\\>\\)[ \t]*\\)?\\(?:\"[^\"]*\"[\t ]*\\)?[^ \t\n()]+[ \t]*\\(?:\\(\\<as\\>\\)[ \t]*[^ \t\n()]+[ \t]*\\)?\\(\\<hiding\\>\\)?" + (1 'haskell-keyword-face nil lax) + (2 'haskell-keyword-face nil lax) + (3 'haskell-keyword-face nil lax) + (4 'haskell-keyword-face nil lax)) + + ;; Special case for `foreign import' + ;; keywords in foreign import statements but are not otherwise reserved. + ("\\<\\(foreign\\)[ \t]+\\(import\\)[ \t]+\\(?:\\(ccall\\|stdcall\\|cplusplus\\|jvm\\|dotnet\\)[ \t]+\\)?\\(?:\\(safe\\|unsafe\\|interruptible\\)[ \t]+\\)?" + (1 'haskell-keyword-face nil lax) + (2 'haskell-keyword-face nil lax) + (3 'haskell-keyword-face nil lax) + (4 'haskell-keyword-face nil lax)) + + ;; Special case for `foreign export' + ;; keywords in foreign export statements but are not otherwise reserved. + ("\\<\\(foreign\\)[ \t]+\\(export\\)[ \t]+\\(?:\\(ccall\\|stdcall\\|cplusplus\\|jvm\\|dotnet\\)[ \t]+\\)?" + (1 'haskell-keyword-face nil lax) + (2 'haskell-keyword-face nil lax) + (3 'haskell-keyword-face nil lax)) + + ;; Special case for `type family' and `data family'. + ;; `family' is only reserved in these contexts. + ("\\<\\(type\\|data\\)[ \t]+\\(family\\>\\)" + (1 'haskell-keyword-face nil lax) + (2 'haskell-keyword-face nil lax)) + + ;; Special case for `type role' + ;; `role' is only reserved in this context. + ("\\<\\(type\\)[ \t]+\\(role\\>\\)" + (1 'haskell-keyword-face nil lax) + (2 'haskell-keyword-face nil lax)) + + ;; Toplevel Declarations. + ;; Place them *before* generic id-and-op highlighting. + (,topdecl-var (1 (unless (member (match-string 1) haskell-font-lock-keywords) + 'haskell-definition-face))) + (,topdecl-var2 (2 (unless (member (match-string 2) haskell-font-lock-keywords) + 'haskell-definition-face))) + (,topdecl-bangpat (1 (unless (member (match-string 1) haskell-font-lock-keywords) + 'haskell-definition-face))) + (,topdecl-sym (2 (unless (member (match-string 2) '("\\" "=" "->" "→" "<-" "←" "::" "∷" "," ";" "`")) + 'haskell-definition-face))) + (,topdecl-sym2 (1 (unless (member (match-string 1) '("\\" "=" "->" "→" "<-" "←" "::" "∷" "," ";" "`")) + 'haskell-definition-face))) + + ;; These four are debatable... + ("(\\(,*\\|->\\))" 0 'haskell-constructor-face) + ("\\[\\]" 0 'haskell-constructor-face) + + ("`" + (0 (if (or (elt (syntax-ppss) 3) (elt (syntax-ppss) 4)) + (parse-partial-sexp (point) (point-max) nil nil (syntax-ppss) + 'syntax-table) + (when (save-excursion + (goto-char (match-beginning 0)) + (haskell-lexeme-looking-at-backtick)) + (goto-char (match-end 0)) + (unless (text-property-not-all (match-beginning 1) (match-end 1) 'face nil) + (put-text-property (match-beginning 1) (match-end 1) 'face 'haskell-operator-face)) + (unless (text-property-not-all (match-beginning 2) (match-end 2) 'face nil) + (put-text-property (match-beginning 2) (match-end 2) 'face 'haskell-operator-face)) + (unless (text-property-not-all (match-beginning 4) (match-end 4) 'face nil) + (put-text-property (match-beginning 4) (match-end 4) 'face 'haskell-operator-face)) + (add-text-properties + (match-beginning 0) (match-end 0) + '(font-lock-fontified t fontified t font-lock-multiline t)))))) + + (,haskell-lexeme-idsym-first-char + (0 (if (or (elt (syntax-ppss) 3) (elt (syntax-ppss) 4)) + (parse-partial-sexp (point) (point-max) nil nil (syntax-ppss) + 'syntax-table) + (when (save-excursion + (goto-char (match-beginning 0)) + (haskell-lexeme-looking-at-qidsym)) + (goto-char (match-end 0)) + ;; note that we have to put face ourselves here because font-lock + ;; will use match data from the original matcher + (haskell-font-lock--put-face-on-type-or-constructor))))))) + keywords)) + + +(defun haskell-font-lock-fontify-block (lang-mode start end) + "Fontify a block as LANG-MODE." + (let ((string (buffer-substring-no-properties start end)) + (modified (buffer-modified-p)) + (org-buffer (current-buffer)) pos next) + (remove-text-properties start end '(face nil)) + (with-current-buffer + (get-buffer-create + (concat " haskell-font-lock-fontify-block:" (symbol-name lang-mode))) + (delete-region (point-min) (point-max)) + (insert string " ") ;; so there's a final property change + (cl-letf (((symbol-function 'message) + (lambda (_fmt &rest _args)))) + ;; silence messages + (unless (eq major-mode lang-mode) (funcall lang-mode)) + (font-lock-ensure)) + (setq pos (point-min)) + (while (setq next (next-single-property-change pos 'face)) + (put-text-property + (+ start (1- pos)) (1- (+ start next)) 'face + (or (get-text-property pos 'face) 'default) org-buffer) + (setq pos next)) + (unless (equal pos (point-max)) + (put-text-property + (+ start (1- pos)) (1- (+ start (point-max))) 'face + 'default org-buffer))) + (add-text-properties + start end + '(font-lock-fontified t fontified t font-lock-multiline t)) + (set-buffer-modified-p modified))) + +(defun haskell-syntactic-face-function (state) + "`font-lock-syntactic-face-function' for Haskell." + (cond + ((nth 3 state) + (if (equal ?| (nth 3 state)) + ;; find out what kind of QuasiQuote is this + (let* ((qqname (save-excursion + (goto-char (nth 8 state)) + (skip-syntax-backward "w._") + (buffer-substring-no-properties (point) (nth 8 state)))) + (lang-mode (cdr (assoc qqname haskell-font-lock-quasi-quote-modes)))) + + (if (and lang-mode + (fboundp lang-mode)) + (save-excursion + ;; find the end of the QuasiQuote + (parse-partial-sexp (point) (point-max) nil nil state + 'syntax-table) + (haskell-font-lock-fontify-block lang-mode (1+ (nth 8 state)) (1- (point))) + ;; must return nil here so that it is not fontified again as string + nil) + ;; fontify normally as string because lang-mode is not present + 'haskell-quasi-quote-face)) + (save-excursion + (let + ((state2 + (parse-partial-sexp (point) (point-max) nil nil state + 'syntax-table)) + (end-of-string (point))) + + (put-text-property (nth 8 state) (point) + 'face 'font-lock-string-face) + + + (if (or (equal t (nth 3 state)) (nth 3 state2)) + ;; This is an unterminated string constant, use warning + ;; face for the opening quote. + (put-text-property (nth 8 state) (1+ (nth 8 state)) + 'face 'font-lock-warning-face)) + + (goto-char (1+ (nth 8 state))) + (while (re-search-forward "\\\\" end-of-string t) + + (goto-char (1- (point))) + + (if (looking-at haskell-lexeme-string-literal-inside-item) + (goto-char (match-end 0)) + + ;; We are looking at an unacceptable escape + ;; sequence. Use warning face to highlight that. + (put-text-property (point) (1+ (point)) + 'face 'font-lock-warning-face) + (goto-char (1+ (point))))))) + ;; must return nil here so that it is not fontified again as string + nil)) + ;; Detect literate comment lines starting with syntax class '<' + ((save-excursion + (goto-char (nth 8 state)) + (equal (string-to-syntax "<") (syntax-after (point)))) + 'haskell-literate-comment-face) + ;; Detect pragmas. A pragma is enclosed in special comment + ;; delimiters {-# .. #-}. + ((save-excursion + (goto-char (nth 8 state)) + (and (looking-at-p "{-#") + (forward-comment 1) + (goto-char (- (point) 3)) + (looking-at-p "#-}"))) + 'haskell-pragma-face) + ;; Detect Liquid Haskell annotations enclosed in special comment + ;; delimiters {-@ .. @-}. + ((save-excursion + (goto-char (nth 8 state)) + (and (looking-at-p "{-@") + (forward-comment 1) + (goto-char (- (point) 3)) + (looking-at-p "@-}"))) + 'haskell-liquid-haskell-annotation-face) + ;; Haddock comment start with either "-- [|^*$]" or "{- ?[|^*$]" + ;; (note space optional for nested comments and mandatory for + ;; double dash comments). + ;; + ;; Haddock comment will also continue on next line, provided: + ;; - current line is a double dash haddock comment + ;; - next line is also double dash comment + ;; - there is only whitespace between + ;; + ;; We recognize double dash haddock comments by property + ;; 'font-lock-doc-face attached to newline. In case of {- -} + ;; comments newline is outside of comment. + ((save-excursion + (goto-char (nth 8 state)) + (or (looking-at-p "\\(?:{- ?\\|-- \\)[|^*$]") + (and (looking-at-p "--") ; are we at double dash comment + (forward-line -1) ; this is nil on first line + (eq (get-text-property (line-end-position) 'face) + 'font-lock-doc-face) ; is a doc face + (forward-line) + (skip-syntax-forward "-") ; see if there is only whitespace + (eq (point) (nth 8 state))))) ; we are back in position + ;; Here we look inside the comment to see if there are substrings + ;; worth marking inside we try to emulate as much of haddock as + ;; possible. First we add comment face all over the comment, then + ;; we add special features. + (let ((beg (nth 8 state)) + (end (save-excursion + (parse-partial-sexp (point) (point-max) nil nil state + 'syntax-table) + (point))) + (emphasis-open-point nil) + (strong-open-point nil)) + (put-text-property beg end 'face 'font-lock-doc-face) + + (when (fboundp 'add-face-text-property) + ;; `add-face-text-property' is not defined in Emacs 23 + + ;; iterate over chars, take escaped chars unconditionally + ;; mark when a construct is opened, close and face it when + ;; it is closed + + (save-excursion + (while (< (point) end) + (if (looking-at "__\\|\\\\.\\|\\\n\\|[/]") + (progn + (cond + ((equal (match-string 0) "/") + (if emphasis-open-point + (progn + (add-face-text-property emphasis-open-point (match-end 0) + '(:slant italic)) + (setq emphasis-open-point nil)) + (setq emphasis-open-point (point)))) + ((equal (match-string 0) "__") + (if strong-open-point + (progn + (add-face-text-property strong-open-point (match-end 0) + '(:weight bold)) + (setq strong-open-point nil)) + (setq strong-open-point (point)))) + (t + ;; this is a backslash escape sequence, skip over it + )) + (goto-char (match-end 0))) + ;; skip chars that are not interesting + (goto-char (1+ (point))) + (skip-chars-forward "^_\\\\/" end)))))) + nil) + (t 'font-lock-comment-face))) + +(defun haskell-font-lock-defaults-create () + "Locally set `font-lock-defaults' for Haskell." + (setq-local font-lock-defaults + '((haskell-font-lock-keywords) + nil nil nil nil + (font-lock-syntactic-face-function + . haskell-syntactic-face-function) + ;; Get help from font-lock-syntactic-keywords. + (parse-sexp-lookup-properties . t) + (font-lock-extra-managed-props . (composition))))) + +(defun haskell-fontify-as-mode (text mode) + "Fontify TEXT as MODE, returning the fontified text." + (with-temp-buffer + (funcall mode) + (insert text) + (if (fboundp 'font-lock-ensure) + (font-lock-ensure) + (with-no-warnings (font-lock-fontify-buffer))) + (buffer-substring (point-min) (point-max)))) + +;; Provide ourselves: + +(provide 'haskell-font-lock) + +;; Local Variables: +;; coding: utf-8-unix +;; tab-width: 8 +;; End: + +;;; haskell-font-lock.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-font-lock.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-font-lock.elc new file mode 100644 index 000000000000..c7eaff60900b --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-font-lock.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-ghc-support.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-ghc-support.el new file mode 100644 index 000000000000..93690170c6da --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-ghc-support.el @@ -0,0 +1,1344 @@ +;;; haskell-ghc-support.el --- GHC specific code -*- coding: utf-8; lexical-binding: t -*- + +;; Copyright © 2016 Haskell Mode +;; Author: 2016 Gracjan Polak + +;; This file is not part of GNU Emacs. + +;; 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This file containt GHC specific constants and information. + +;;; Code: + +(defvar haskell-ghc-supported-extensions + '( + ;;; BEGIN haskell-ghc-supported-extensions + "AllowAmbiguousTypes" + "AlternativeLayoutRule" + "AlternativeLayoutRuleTransitional" + "ApplicativeDo" + "Arrows" + "AutoDeriveTypeable" + "BangPatterns" + "BinaryLiterals" + "CApiFFI" + "CPP" + "ConstrainedClassMethods" + "ConstraintKinds" + "DataKinds" + "DatatypeContexts" + "DefaultSignatures" + "DeriveAnyClass" + "DeriveDataTypeable" + "DeriveFoldable" + "DeriveFunctor" + "DeriveGeneric" + "DeriveLift" + "DeriveTraversable" + "DisambiguateRecordFields" + "DoAndIfThenElse" + "DoRec" + "DuplicateRecordFields" + "EmptyCase" + "EmptyDataDecls" + "ExistentialQuantification" + "ExplicitForAll" + "ExplicitNamespaces" + "ExtendedDefaultRules" + "FlexibleContexts" + "FlexibleInstances" + "ForeignFunctionInterface" + "FunctionalDependencies" + "GADTSyntax" + "GADTs" + "GHCForeignImportPrim" + "GeneralizedNewtypeDeriving" + "Haskell2010" + "Haskell98" + "ImplicitParams" + "ImplicitPrelude" + "ImpredicativeTypes" + "IncoherentInstances" + "InstanceSigs" + "InterruptibleFFI" + "JavaScriptFFI" + "KindSignatures" + "LambdaCase" + "LiberalTypeSynonyms" + "MagicHash" + "MonadComprehensions" + "MonadFailDesugaring" + "MonoLocalBinds" + "MonoPatBinds" + "MonomorphismRestriction" + "MultiParamTypeClasses" + "MultiWayIf" + "NPlusKPatterns" + "NamedFieldPuns" + "NamedWildCards" + "NegativeLiterals" + "NoAllowAmbiguousTypes" + "NoAlternativeLayoutRule" + "NoAlternativeLayoutRuleTransitional" + "NoApplicativeDo" + "NoArrows" + "NoAutoDeriveTypeable" + "NoBangPatterns" + "NoBinaryLiterals" + "NoCApiFFI" + "NoCPP" + "NoConstrainedClassMethods" + "NoConstraintKinds" + "NoDataKinds" + "NoDatatypeContexts" + "NoDefaultSignatures" + "NoDeriveAnyClass" + "NoDeriveDataTypeable" + "NoDeriveFoldable" + "NoDeriveFunctor" + "NoDeriveGeneric" + "NoDeriveLift" + "NoDeriveTraversable" + "NoDisambiguateRecordFields" + "NoDoAndIfThenElse" + "NoDoRec" + "NoDuplicateRecordFields" + "NoEmptyCase" + "NoEmptyDataDecls" + "NoExistentialQuantification" + "NoExplicitForAll" + "NoExplicitNamespaces" + "NoExtendedDefaultRules" + "NoFlexibleContexts" + "NoFlexibleInstances" + "NoForeignFunctionInterface" + "NoFunctionalDependencies" + "NoGADTSyntax" + "NoGADTs" + "NoGHCForeignImportPrim" + "NoGeneralizedNewtypeDeriving" + "NoImplicitParams" + "NoImplicitPrelude" + "NoImpredicativeTypes" + "NoIncoherentInstances" + "NoInstanceSigs" + "NoInterruptibleFFI" + "NoJavaScriptFFI" + "NoKindSignatures" + "NoLambdaCase" + "NoLiberalTypeSynonyms" + "NoMagicHash" + "NoMonadComprehensions" + "NoMonadFailDesugaring" + "NoMonoLocalBinds" + "NoMonoPatBinds" + "NoMonomorphismRestriction" + "NoMultiParamTypeClasses" + "NoMultiWayIf" + "NoNPlusKPatterns" + "NoNamedFieldPuns" + "NoNamedWildCards" + "NoNegativeLiterals" + "NoNondecreasingIndentation" + "NoNullaryTypeClasses" + "NoNumDecimals" + "NoOverlappingInstances" + "NoOverloadedLabels" + "NoOverloadedLists" + "NoOverloadedStrings" + "NoPackageImports" + "NoParallelArrays" + "NoParallelListComp" + "NoPartialTypeSignatures" + "NoPatternGuards" + "NoPatternSignatures" + "NoPatternSynonyms" + "NoPolyKinds" + "NoPolymorphicComponents" + "NoPostfixOperators" + "NoQuasiQuotes" + "NoRank2Types" + "NoRankNTypes" + "NoRebindableSyntax" + "NoRecordPuns" + "NoRecordWildCards" + "NoRecursiveDo" + "NoRelaxedLayout" + "NoRelaxedPolyRec" + "NoRoleAnnotations" + "NoScopedTypeVariables" + "NoStandaloneDeriving" + "NoStaticPointers" + "NoStrict" + "NoStrictData" + "NoTemplateHaskell" + "NoTemplateHaskellQuotes" + "NoTraditionalRecordSyntax" + "NoTransformListComp" + "NoTupleSections" + "NoTypeApplications" + "NoTypeFamilies" + "NoTypeFamilyDependencies" + "NoTypeInType" + "NoTypeOperators" + "NoTypeSynonymInstances" + "NoUnboxedTuples" + "NoUndecidableInstances" + "NoUndecidableSuperClasses" + "NoUnicodeSyntax" + "NoUnliftedFFITypes" + "NoViewPatterns" + "NondecreasingIndentation" + "NullaryTypeClasses" + "NumDecimals" + "OverlappingInstances" + "OverloadedLabels" + "OverloadedLists" + "OverloadedStrings" + "PackageImports" + "ParallelArrays" + "ParallelListComp" + "PartialTypeSignatures" + "PatternGuards" + "PatternSignatures" + "PatternSynonyms" + "PolyKinds" + "PolymorphicComponents" + "PostfixOperators" + "QuasiQuotes" + "Rank2Types" + "RankNTypes" + "RebindableSyntax" + "RecordPuns" + "RecordWildCards" + "RecursiveDo" + "RelaxedLayout" + "RelaxedPolyRec" + "RoleAnnotations" + "Safe" + "ScopedTypeVariables" + "StandaloneDeriving" + "StaticPointers" + "Strict" + "StrictData" + "TemplateHaskell" + "TemplateHaskellQuotes" + "TraditionalRecordSyntax" + "TransformListComp" + "Trustworthy" + "TupleSections" + "TypeApplications" + "TypeFamilies" + "TypeFamilyDependencies" + "TypeInType" + "TypeOperators" + "TypeSynonymInstances" + "UnboxedTuples" + "UndecidableInstances" + "UndecidableSuperClasses" + "UnicodeSyntax" + "UnliftedFFITypes" + "Unsafe" + "ViewPatterns" + ;;; END haskell-ghc-supported-extensions + ) + "List of language extensions supported by any known version of GHC. + +This list should be updated by running `haskell-update-ghc-support'.") + +(defvar haskell-ghc-supported-options + '( + ;;; BEGIN haskell-ghc-supported-options + "-#include" + "--abi-hash" + "--frontend" + "--help" + "--info" + "--interactive" + "--make" + "--numeric-version" + "--print-booter-version" + "--print-build-platform" + "--print-c-compiler-flags" + "--print-c-compiler-link-flags" + "--print-debug-on" + "--print-gcc-linker-flags" + "--print-global-package-db" + "--print-have-interpreter" + "--print-have-native-code-generator" + "--print-host-platform" + "--print-ld-flags" + "--print-ld-linker-flags" + "--print-leading-underscore" + "--print-libdir" + "--print-object-splitting-supported" + "--print-project-git-commit-id" + "--print-project-version" + "--print-rts-ways" + "--print-stage" + "--print-support-smp" + "--print-tables-next-to-code" + "--print-target-platform" + "--print-unregisterised" + "--show-iface" + "--show-options" + "--show-packages" + "--supported-extensions" + "--supported-languages" + "--version" + "-?" + "-C" + "-D" + "-E" + "-F" + "-H" + "-I" + "-L" + "-M" + "-O" + "-Odph" + "-Onot" + "-Rghc-timing" + "-S" + "-U" + "-V" + "-W" + "-Wall" + "-Wall-missed-specialisations" + "-Walternative-layout-rule-transitional" + "-Wamp" + "-Wauto-orphans" + "-Wcompat" + "-Wcontext-quantification" + "-Wdefault" + "-Wdeferred-type-errors" + "-Wdeprecated-flags" + "-Wdeprecations" + "-Wderiving-typeable" + "-Wdodgy-exports" + "-Wdodgy-foreign-imports" + "-Wdodgy-imports" + "-Wduplicate-constraints" + "-Wduplicate-exports" + "-Wempty-enumerations" + "-Werror" + "-Weverything" + "-Wextra" + "-Whi-shadowing" + "-Widentities" + "-Wimplicit-prelude" + "-Wincomplete-patterns" + "-Wincomplete-record-updates" + "-Wincomplete-uni-patterns" + "-Winline-rule-shadowing" + "-Wmissed-specialisations" + "-Wmissing-exported-signatures" + "-Wmissing-exported-sigs" + "-Wmissing-fields" + "-Wmissing-import-lists" + "-Wmissing-local-signatures" + "-Wmissing-local-sigs" + "-Wmissing-methods" + "-Wmissing-monadfail-instances" + "-Wmissing-pattern-synonym-signatures" + "-Wmissing-signatures" + "-Wmonomorphism-restriction" + "-Wname-shadowing" + "-Wno-all" + "-Wno-all-missed-specialisations" + "-Wno-alternative-layout-rule-transitional" + "-Wno-amp" + "-Wno-auto-orphans" + "-Wno-compat" + "-Wno-context-quantification" + "-Wno-default" + "-Wno-deferred-type-errors" + "-Wno-deprecated-flags" + "-Wno-deprecations" + "-Wno-deriving-typeable" + "-Wno-dodgy-exports" + "-Wno-dodgy-foreign-imports" + "-Wno-dodgy-imports" + "-Wno-duplicate-constraints" + "-Wno-duplicate-exports" + "-Wno-empty-enumerations" + "-Wno-everything" + "-Wno-extra" + "-Wno-hi-shadowing" + "-Wno-identities" + "-Wno-implicit-prelude" + "-Wno-incomplete-patterns" + "-Wno-incomplete-record-updates" + "-Wno-incomplete-uni-patterns" + "-Wno-inline-rule-shadowing" + "-Wno-missed-specialisations" + "-Wno-missing-exported-signatures" + "-Wno-missing-exported-sigs" + "-Wno-missing-fields" + "-Wno-missing-import-lists" + "-Wno-missing-local-signatures" + "-Wno-missing-local-sigs" + "-Wno-missing-methods" + "-Wno-missing-monadfail-instances" + "-Wno-missing-pattern-synonym-signatures" + "-Wno-missing-signatures" + "-Wno-monomorphism-restriction" + "-Wno-name-shadowing" + "-Wno-noncanonical-monad-instances" + "-Wno-noncanonical-monadfail-instances" + "-Wno-noncanonical-monoid-instances" + "-Wno-orphans" + "-Wno-overflowed-literals" + "-Wno-overlapping-patterns" + "-Wno-partial-type-signatures" + "-Wno-redundant-constraints" + "-Wno-safe" + "-Wno-semigroup" + "-Wno-tabs" + "-Wno-trustworthy-safe" + "-Wno-type-defaults" + "-Wno-typed-holes" + "-Wno-unrecognised-pragmas" + "-Wno-unrecognised-warning-flags" + "-Wno-unsafe" + "-Wno-unsupported-calling-conventions" + "-Wno-unsupported-llvm-version" + "-Wno-unticked-promoted-constructors" + "-Wno-unused-binds" + "-Wno-unused-do-bind" + "-Wno-unused-foralls" + "-Wno-unused-imports" + "-Wno-unused-local-binds" + "-Wno-unused-matches" + "-Wno-unused-pattern-binds" + "-Wno-unused-top-binds" + "-Wno-unused-type-patterns" + "-Wno-warnings-deprecations" + "-Wno-wrong-do-bind" + "-Wnoncanonical-monad-instances" + "-Wnoncanonical-monadfail-instances" + "-Wnoncanonical-monoid-instances" + "-Wnot" + "-Worphans" + "-Woverflowed-literals" + "-Woverlapping-patterns" + "-Wpartial-type-signatures" + "-Wredundant-constraints" + "-Wsafe" + "-Wsemigroup" + "-Wtabs" + "-Wtrustworthy-safe" + "-Wtype-defaults" + "-Wtyped-holes" + "-Wunrecognised-pragmas" + "-Wunrecognised-warning-flags" + "-Wunsafe" + "-Wunsupported-calling-conventions" + "-Wunsupported-llvm-version" + "-Wunticked-promoted-constructors" + "-Wunused-binds" + "-Wunused-do-bind" + "-Wunused-foralls" + "-Wunused-imports" + "-Wunused-local-binds" + "-Wunused-matches" + "-Wunused-pattern-binds" + "-Wunused-top-binds" + "-Wunused-type-patterns" + "-Wwarn" + "-Wwarnings-deprecations" + "-Wwrong-do-bind" + "-XAllowAmbiguousTypes" + "-XAlternativeLayoutRule" + "-XAlternativeLayoutRuleTransitional" + "-XApplicativeDo" + "-XArrows" + "-XAutoDeriveTypeable" + "-XBangPatterns" + "-XBinaryLiterals" + "-XCApiFFI" + "-XCPP" + "-XConstrainedClassMethods" + "-XConstraintKinds" + "-XDataKinds" + "-XDatatypeContexts" + "-XDefaultSignatures" + "-XDeriveAnyClass" + "-XDeriveDataTypeable" + "-XDeriveFoldable" + "-XDeriveFunctor" + "-XDeriveGeneric" + "-XDeriveLift" + "-XDeriveTraversable" + "-XDisambiguateRecordFields" + "-XDoAndIfThenElse" + "-XDoRec" + "-XDuplicateRecordFields" + "-XEmptyCase" + "-XEmptyDataDecls" + "-XExistentialQuantification" + "-XExplicitForAll" + "-XExplicitNamespaces" + "-XExtendedDefaultRules" + "-XFlexibleContexts" + "-XFlexibleInstances" + "-XForeignFunctionInterface" + "-XFunctionalDependencies" + "-XGADTSyntax" + "-XGADTs" + "-XGHCForeignImportPrim" + "-XGeneralizedNewtypeDeriving" + "-XGenerics" + "-XHaskell2010" + "-XHaskell98" + "-XImplicitParams" + "-XImplicitPrelude" + "-XImpredicativeTypes" + "-XIncoherentInstances" + "-XInstanceSigs" + "-XInterruptibleFFI" + "-XJavaScriptFFI" + "-XKindSignatures" + "-XLambdaCase" + "-XLiberalTypeSynonyms" + "-XMagicHash" + "-XMonadComprehensions" + "-XMonadFailDesugaring" + "-XMonoLocalBinds" + "-XMonoPatBinds" + "-XMonomorphismRestriction" + "-XMultiParamTypeClasses" + "-XMultiWayIf" + "-XNPlusKPatterns" + "-XNamedFieldPuns" + "-XNamedWildCards" + "-XNegativeLiterals" + "-XNoAllowAmbiguousTypes" + "-XNoAlternativeLayoutRule" + "-XNoAlternativeLayoutRuleTransitional" + "-XNoApplicativeDo" + "-XNoArrows" + "-XNoAutoDeriveTypeable" + "-XNoBangPatterns" + "-XNoBinaryLiterals" + "-XNoCApiFFI" + "-XNoCPP" + "-XNoConstrainedClassMethods" + "-XNoConstraintKinds" + "-XNoDataKinds" + "-XNoDatatypeContexts" + "-XNoDefaultSignatures" + "-XNoDeriveAnyClass" + "-XNoDeriveDataTypeable" + "-XNoDeriveFoldable" + "-XNoDeriveFunctor" + "-XNoDeriveGeneric" + "-XNoDeriveLift" + "-XNoDeriveTraversable" + "-XNoDisambiguateRecordFields" + "-XNoDoAndIfThenElse" + "-XNoDoRec" + "-XNoDuplicateRecordFields" + "-XNoEmptyCase" + "-XNoEmptyDataDecls" + "-XNoExistentialQuantification" + "-XNoExplicitForAll" + "-XNoExplicitNamespaces" + "-XNoExtendedDefaultRules" + "-XNoFlexibleContexts" + "-XNoFlexibleInstances" + "-XNoForeignFunctionInterface" + "-XNoFunctionalDependencies" + "-XNoGADTSyntax" + "-XNoGADTs" + "-XNoGHCForeignImportPrim" + "-XNoGeneralizedNewtypeDeriving" + "-XNoGenerics" + "-XNoImplicitParams" + "-XNoImplicitPrelude" + "-XNoImpredicativeTypes" + "-XNoIncoherentInstances" + "-XNoInstanceSigs" + "-XNoInterruptibleFFI" + "-XNoJavaScriptFFI" + "-XNoKindSignatures" + "-XNoLambdaCase" + "-XNoLiberalTypeSynonyms" + "-XNoMagicHash" + "-XNoMonadComprehensions" + "-XNoMonadFailDesugaring" + "-XNoMonoLocalBinds" + "-XNoMonoPatBinds" + "-XNoMonomorphismRestriction" + "-XNoMultiParamTypeClasses" + "-XNoMultiWayIf" + "-XNoNPlusKPatterns" + "-XNoNamedFieldPuns" + "-XNoNamedWildCards" + "-XNoNegativeLiterals" + "-XNoNondecreasingIndentation" + "-XNoNullaryTypeClasses" + "-XNoNumDecimals" + "-XNoOverlappingInstances" + "-XNoOverloadedLabels" + "-XNoOverloadedLists" + "-XNoOverloadedStrings" + "-XNoPackageImports" + "-XNoParallelArrays" + "-XNoParallelListComp" + "-XNoPartialTypeSignatures" + "-XNoPatternGuards" + "-XNoPatternSignatures" + "-XNoPatternSynonyms" + "-XNoPolyKinds" + "-XNoPolymorphicComponents" + "-XNoPostfixOperators" + "-XNoQuasiQuotes" + "-XNoRank2Types" + "-XNoRankNTypes" + "-XNoRebindableSyntax" + "-XNoRecordPuns" + "-XNoRecordWildCards" + "-XNoRecursiveDo" + "-XNoRelaxedLayout" + "-XNoRelaxedPolyRec" + "-XNoRoleAnnotations" + "-XNoScopedTypeVariables" + "-XNoStandaloneDeriving" + "-XNoStaticPointers" + "-XNoStrict" + "-XNoStrictData" + "-XNoTemplateHaskell" + "-XNoTemplateHaskellQuotes" + "-XNoTraditionalRecordSyntax" + "-XNoTransformListComp" + "-XNoTupleSections" + "-XNoTypeApplications" + "-XNoTypeFamilies" + "-XNoTypeFamilyDependencies" + "-XNoTypeInType" + "-XNoTypeOperators" + "-XNoTypeSynonymInstances" + "-XNoUnboxedTuples" + "-XNoUndecidableInstances" + "-XNoUndecidableSuperClasses" + "-XNoUnicodeSyntax" + "-XNoUnliftedFFITypes" + "-XNoViewPatterns" + "-XNondecreasingIndentation" + "-XNullaryTypeClasses" + "-XNumDecimals" + "-XOverlappingInstances" + "-XOverloadedLabels" + "-XOverloadedLists" + "-XOverloadedStrings" + "-XPackageImports" + "-XParallelArrays" + "-XParallelListComp" + "-XPartialTypeSignatures" + "-XPatternGuards" + "-XPatternSignatures" + "-XPatternSynonyms" + "-XPolyKinds" + "-XPolymorphicComponents" + "-XPostfixOperators" + "-XQuasiQuotes" + "-XRank2Types" + "-XRankNTypes" + "-XRebindableSyntax" + "-XRecordPuns" + "-XRecordWildCards" + "-XRecursiveDo" + "-XRelaxedLayout" + "-XRelaxedPolyRec" + "-XRoleAnnotations" + "-XSafe" + "-XScopedTypeVariables" + "-XStandaloneDeriving" + "-XStaticPointers" + "-XStrict" + "-XStrictData" + "-XTemplateHaskell" + "-XTemplateHaskellQuotes" + "-XTraditionalRecordSyntax" + "-XTransformListComp" + "-XTrustworthy" + "-XTupleSections" + "-XTypeApplications" + "-XTypeFamilies" + "-XTypeFamilyDependencies" + "-XTypeInType" + "-XTypeOperators" + "-XTypeSynonymInstances" + "-XUnboxedTuples" + "-XUndecidableInstances" + "-XUndecidableSuperClasses" + "-XUnicodeSyntax" + "-XUnliftedFFITypes" + "-XUnsafe" + "-XViewPatterns" + "-auto" + "-auto-all" + "-c" + "-caf-all" + "-clear-package-db" + "-cpp" + "-dannot-lint" + "-dasm-lint" + "-dcmm-lint" + "-dcore-lint" + "-ddump-asm" + "-ddump-asm-conflicts" + "-ddump-asm-expanded" + "-ddump-asm-liveness" + "-ddump-asm-native" + "-ddump-asm-regalloc" + "-ddump-asm-regalloc-stages" + "-ddump-asm-stats" + "-ddump-bcos" + "-ddump-call-arity" + "-ddump-cmm" + "-ddump-cmm-cbe" + "-ddump-cmm-cfg" + "-ddump-cmm-cps" + "-ddump-cmm-info" + "-ddump-cmm-proc" + "-ddump-cmm-procmap" + "-ddump-cmm-raw" + "-ddump-cmm-sink" + "-ddump-cmm-sp" + "-ddump-cmm-split" + "-ddump-cmm-switch" + "-ddump-core-stats" + "-ddump-cs-trace" + "-ddump-cse" + "-ddump-debug" + "-ddump-deriv" + "-ddump-ds" + "-ddump-file-prefix" + "-ddump-foreign" + "-ddump-hi" + "-ddump-hi-diffs" + "-ddump-hpc" + "-ddump-if-trace" + "-ddump-inlinings" + "-ddump-llvm" + "-ddump-minimal-imports" + "-ddump-mod-cycles" + "-ddump-mod-map" + "-ddump-occur-anal" + "-ddump-opt-cmm" + "-ddump-parsed" + "-ddump-prep" + "-ddump-rn" + "-ddump-rn-stats" + "-ddump-rn-trace" + "-ddump-rtti" + "-ddump-rule-firings" + "-ddump-rule-rewrites" + "-ddump-rules" + "-ddump-simpl" + "-ddump-simpl-iterations" + "-ddump-simpl-stats" + "-ddump-simpl-trace" + "-ddump-spec" + "-ddump-splices" + "-ddump-stg" + "-ddump-str-signatures" + "-ddump-stranal" + "-ddump-strsigs" + "-ddump-tc" + "-ddump-tc-trace" + "-ddump-ticked" + "-ddump-to-file" + "-ddump-types" + "-ddump-vect" + "-ddump-view-pattern-commoning" + "-ddump-vt-trace" + "-ddump-worker-wrapper" + "-debug" + "-dep-makefile" + "-dep-suffix" + "-dfaststring-stats" + "-dinitial-unique" + "-distrust" + "-distrust-all-packages" + "-dno-debug-output" + "-dno-llvm-mangler" + "-dno-ppr-case-as-let" + "-dno-ppr-ticks" + "-dno-suppress-coercions" + "-dno-suppress-idinfo" + "-dno-suppress-module-prefixes" + "-dno-suppress-type-applications" + "-dno-suppress-type-signatures" + "-dno-suppress-unfoldings" + "-dno-suppress-uniques" + "-dno-suppress-var-kinds" + "-dppr-case-as-let" + "-dppr-cols" + "-dppr-debug" + "-dppr-ticks" + "-dppr-user-length" + "-dshow-passes" + "-dsource-stats" + "-dstg-lint" + "-dstg-stats" + "-dsuppress-all" + "-dsuppress-coercions" + "-dsuppress-idinfo" + "-dsuppress-module-prefixes" + "-dsuppress-type-applications" + "-dsuppress-type-signatures" + "-dsuppress-unfoldings" + "-dsuppress-uniques" + "-dsuppress-var-kinds" + "-dth-dec-file" + "-dtrace-level" + "-dumpdir" + "-dunique-increment" + "-dverbose-core2core" + "-dverbose-stg2stg" + "-dylib-install-name" + "-dynamic" + "-dynamic-too" + "-dynhisuf" + "-dynload" + "-dyno" + "-dynosuf" + "-e" + "-eventlog" + "-exclude-module" + "-fPArr" + "-fPIC" + "-fallow-incoherent-instances" + "-fallow-overlapping-instances" + "-fallow-undecidable-instances" + "-farrows" + "-fasm" + "-fbang-patterns" + "-fbuilding-cabal-package" + "-fbyte-code" + "-fcall-arity" + "-fcase-merge" + "-fcmm-elim-common-blocks" + "-fcmm-sink" + "-fconstraint-solver-iterations" + "-fcontext-stack" + "-fcpr-anal" + "-fcpr-off" + "-fcross-module-specialise" + "-fcse" + "-fdefer-type-errors" + "-fdefer-typed-holes" + "-fdicts-cheap" + "-fdicts-strict" + "-fdmd-tx-dict-sel" + "-fdo-eta-reduction" + "-fdo-lambda-eta-expansion" + "-feager-blackholing" + "-fembed-manifest" + "-fenable-rewrite-rules" + "-ferror-spans" + "-fexcess-precision" + "-fexpose-all-unfoldings" + "-fext-core" + "-fextended-default-rules" + "-fexternal-interpreter" + "-fffi" + "-ffi" + "-fflat-cache" + "-ffloat-all-lams" + "-ffloat-in" + "-ffloat-lam-args" + "-fforce-recomp" + "-ffrontend-opt" + "-ffull-laziness" + "-ffun-to-thunk" + "-fgen-manifest" + "-fghci-history" + "-fghci-sandbox" + "-fglasgow-exts" + "-fhelpful-errors" + "-fhistory-size" + "-fhpc" + "-fhpc-no-auto" + "-fignore-asserts" + "-fignore-interface-pragmas" + "-fimplicit-params" + "-fimplicit-prelude" + "-firrefutable-tuples" + "-fkill-absence" + "-fkill-one-shot" + "-flate-dmd-anal" + "-fliberate-case" + "-fliberate-case-threshold" + "-fllvm" + "-floopification" + "-fmax-inline-alloc-size" + "-fmax-inline-memcpy-insns" + "-fmax-inline-memset-insns" + "-fmax-pmcheck-iterations" + "-fmax-relevant-binds" + "-fmax-simplifier-iterations" + "-fmax-worker-args" + "-fmono-pat-binds" + "-fmonomorphism-restriction" + "-fno-PArr" + "-fno-PIC" + "-fno-allow-incoherent-instances" + "-fno-allow-overlapping-instances" + "-fno-allow-undecidable-instances" + "-fno-arrows" + "-fno-bang-patterns" + "-fno-building-cabal-package" + "-fno-call-arity" + "-fno-case-merge" + "-fno-cmm-elim-common-blocks" + "-fno-cmm-sink" + "-fno-code" + "-fno-cpr-anal" + "-fno-cross-module-specialise" + "-fno-cse" + "-fno-defer-type-errors" + "-fno-defer-typed-holes" + "-fno-dicts-cheap" + "-fno-dicts-strict" + "-fno-dmd-tx-dict-sel" + "-fno-do-eta-reduction" + "-fno-do-lambda-eta-expansion" + "-fno-eager-blackholing" + "-fno-embed-manifest" + "-fno-enable-rewrite-rules" + "-fno-error-spans" + "-fno-excess-precision" + "-fno-expose-all-unfoldings" + "-fno-ext-core" + "-fno-extended-default-rules" + "-fno-external-interpreter" + "-fno-ffi" + "-fno-fi" + "-fno-flat-cache" + "-fno-float-in" + "-fno-force-recomp" + "-fno-full-laziness" + "-fno-fun-to-thunk" + "-fno-gen-manifest" + "-fno-ghci-history" + "-fno-ghci-sandbox" + "-fno-glasgow-exts" + "-fno-helpful-errors" + "-fno-hpc" + "-fno-hpc-no-auto" + "-fno-ignore-asserts" + "-fno-ignore-interface-pragmas" + "-fno-implicit-params" + "-fno-implicit-prelude" + "-fno-irrefutable-tuples" + "-fno-kill-absence" + "-fno-kill-one-shot" + "-fno-late-dmd-anal" + "-fno-liberate-case" + "-fno-liberate-case-threshold" + "-fno-loopification" + "-fno-max-relevant-binds" + "-fno-mono-pat-binds" + "-fno-monomorphism-restriction" + "-fno-omit-interface-pragmas" + "-fno-omit-yields" + "-fno-opt-coercion" + "-fno-parr" + "-fno-pedantic-bottoms" + "-fno-pre-inlining" + "-fno-print-equality-relations" + "-fno-print-expanded-synonyms" + "-fno-print-explicit-coercions" + "-fno-print-explicit-foralls" + "-fno-print-explicit-kinds" + "-fno-print-explicit-runtime-reps" + "-fno-print-potential-instances" + "-fno-print-typechecker-elaboration" + "-fno-print-unicode-syntax" + "-fno-prof-auto" + "-fno-prof-cafs" + "-fno-prof-count-entries" + "-fno-regs-graph" + "-fno-regs-iterative" + "-fno-reverse-errors" + "-fno-rewrite-rules" + "-fno-safe-infer" + "-fno-scoped-type-variables" + "-fno-shared-implib" + "-fno-show-warning-groups" + "-fno-simple-list-literals" + "-fno-spec-constr" + "-fno-spec-constr-count" + "-fno-spec-constr-threshold" + "-fno-specialise" + "-fno-specialise-aggressively" + "-fno-state-hack" + "-fno-static-argument-transformation" + "-fno-strictness" + "-fno-th" + "-fno-unbox-small-strict-fields" + "-fno-unbox-strict-fields" + "-fno-use-rpaths" + "-fno-vectorisation-avoidance" + "-fno-vectorise" + "-fno-version-macros" + "-fno-warn-" + "-fno-warn-alternative-layout-rule-transitional" + "-fno-warn-amp" + "-fno-warn-auto-orphans" + "-fno-warn-context-quantification" + "-fno-warn-deprecated-flags" + "-fno-warn-deprecations" + "-fno-warn-deriving-typeable" + "-fno-warn-dodgy-exports" + "-fno-warn-dodgy-foreign-imports" + "-fno-warn-dodgy-imports" + "-fno-warn-duplicate-constraints" + "-fno-warn-duplicate-exports" + "-fno-warn-empty-enumerations" + "-fno-warn-hi-shadowing" + "-fno-warn-identities" + "-fno-warn-implicit-prelude" + "-fno-warn-incomplete-patterns" + "-fno-warn-incomplete-record-updates" + "-fno-warn-incomplete-uni-patterns" + "-fno-warn-inline-rule-shadowing" + "-fno-warn-missing-exported-sigs" + "-fno-warn-missing-fields" + "-fno-warn-missing-import-lists" + "-fno-warn-missing-local-sigs" + "-fno-warn-missing-methods" + "-fno-warn-missing-signatures" + "-fno-warn-monomorphism-restriction" + "-fno-warn-name-shadowing" + "-fno-warn-orphans" + "-fno-warn-overflowed-literals" + "-fno-warn-overlapping-patterns" + "-fno-warn-partial-type-signatures" + "-fno-warn-pointless-pragmas" + "-fno-warn-safe" + "-fno-warn-tabs" + "-fno-warn-trustworthy-safe" + "-fno-warn-type-defaults" + "-fno-warn-typed-holes" + "-fno-warn-unrecognised-pragmas" + "-fno-warn-unsafe" + "-fno-warn-unsupported-calling-conventions" + "-fno-warn-unsupported-llvm-version" + "-fno-warn-unticked-promoted-constructors" + "-fno-warn-unused-binds" + "-fno-warn-unused-do-bind" + "-fno-warn-unused-imports" + "-fno-warn-unused-matches" + "-fno-warn-warnings-deprecations" + "-fno-warn-wrong-do-bind" + "-fno-worker-wrapper" + "-fno-write-interface" + "-fobject-code" + "-fomit-interface-pragmas" + "-fomit-yields" + "-fpackage-trust" + "-fparr" + "-fpedantic-bottoms" + "-fplugin" + "-fplugin-opt" + "-fpre-inlining" + "-fprint-equality-relations" + "-fprint-expanded-synonyms" + "-fprint-explicit-coercions" + "-fprint-explicit-foralls" + "-fprint-explicit-kinds" + "-fprint-explicit-runtime-reps" + "-fprint-potential-instances" + "-fprint-typechecker-elaboration" + "-fprint-unicode-syntax" + "-fprof-auto" + "-fprof-auto-calls" + "-fprof-auto-exported" + "-fprof-auto-top" + "-fprof-cafs" + "-fprof-count-entries" + "-framework" + "-framework-path" + "-freduction-depth" + "-fregs-graph" + "-fregs-iterative" + "-freverse-errors" + "-frewrite-rules" + "-frule-check" + "-fscoped-type-variables" + "-fshared-implib" + "-fshow-warning-groups" + "-fsimpl-tick-factor" + "-fsimple-list-literals" + "-fsimplifier-phases" + "-fspec-constr" + "-fspec-constr-count" + "-fspec-constr-recursive" + "-fspec-constr-threshold" + "-fspecialise" + "-fspecialise-aggressively" + "-fstatic-argument-transformation" + "-fstrictness" + "-fstrictness-before" + "-fth" + "-ftype-function-depth" + "-funbox-small-strict-fields" + "-funbox-strict-fields" + "-funfolding-creation-threshold" + "-funfolding-dict-discount" + "-funfolding-fun-discount" + "-funfolding-keeness-factor" + "-funfolding-use-threshold" + "-fuse-rpaths" + "-fvectorisation-avoidance" + "-fvectorise" + "-fversion-macros" + "-fvia-C" + "-fvia-c" + "-fwarn-" + "-fwarn-alternative-layout-rule-transitional" + "-fwarn-amp" + "-fwarn-auto-orphans" + "-fwarn-context-quantification" + "-fwarn-deprecated-flags" + "-fwarn-deprecations" + "-fwarn-deriving-typeable" + "-fwarn-dodgy-exports" + "-fwarn-dodgy-foreign-imports" + "-fwarn-dodgy-imports" + "-fwarn-duplicate-constraints" + "-fwarn-duplicate-exports" + "-fwarn-empty-enumerations" + "-fwarn-hi-shadowing" + "-fwarn-identities" + "-fwarn-implicit-prelude" + "-fwarn-incomplete-patterns" + "-fwarn-incomplete-record-updates" + "-fwarn-incomplete-uni-patterns" + "-fwarn-inline-rule-shadowing" + "-fwarn-missing-exported-sigs" + "-fwarn-missing-fields" + "-fwarn-missing-import-lists" + "-fwarn-missing-local-sigs" + "-fwarn-missing-methods" + "-fwarn-missing-signatures" + "-fwarn-monomorphism-restriction" + "-fwarn-name-shadowing" + "-fwarn-orphans" + "-fwarn-overflowed-literals" + "-fwarn-overlapping-patterns" + "-fwarn-partial-type-signatures" + "-fwarn-pointless-pragmas" + "-fwarn-safe" + "-fwarn-tabs" + "-fwarn-trustworthy-safe" + "-fwarn-type-defaults" + "-fwarn-typed-holes" + "-fwarn-unrecognised-pragmas" + "-fwarn-unsafe" + "-fwarn-unsupported-calling-conventions" + "-fwarn-unsupported-llvm-version" + "-fwarn-unticked-promoted-constructors" + "-fwarn-unused-binds" + "-fwarn-unused-do-bind" + "-fwarn-unused-imports" + "-fwarn-unused-matches" + "-fwarn-warnings-deprecations" + "-fwarn-wrong-do-bind" + "-fworker-wrapper" + "-fwrite-interface" + "-g" + "-global-package-db" + "-gransim" + "-haddock" + "-haddock-opts" + "-hcsuf" + "-hide-all-packages" + "-hide-all-plugin-packages" + "-hide-package" + "-hidir" + "-hisuf" + "-hpcdir" + "-i" + "-ignore-package" + "-include-pkg-deps" + "-j" + "-keep-hc-file" + "-keep-hc-files" + "-keep-llvm-file" + "-keep-llvm-files" + "-keep-s-file" + "-keep-s-files" + "-keep-tmp-files" + "-l" + "-main-is" + "-mavx" + "-mavx2" + "-mavx512cd" + "-mavx512er" + "-mavx512f" + "-mavx512pf" + "-msse" + "-msse2" + "-msse3" + "-msse4" + "-msse4.2" + "-n" + "-ndp" + "-no-auto" + "-no-auto-all" + "-no-auto-link-packages" + "-no-caf-all" + "-no-global-package-db" + "-no-hs-main" + "-no-link" + "-no-recomp" + "-no-rtsopts" + "-no-rtsopts-suggestions" + "-no-user-package-conf" + "-no-user-package-db" + "-o" + "-odir" + "-ohi" + "-optF" + "-optL" + "-optP" + "-opta" + "-optc" + "-opti" + "-optl" + "-optlc" + "-optlo" + "-optwindres" + "-osuf" + "-outputdir" + "-package" + "-package-conf" + "-package-db" + "-package-env" + "-package-id" + "-package-key" + "-package-name" + "-parallel" + "-pgmF" + "-pgmL" + "-pgmP" + "-pgma" + "-pgmc" + "-pgmdll" + "-pgmi" + "-pgml" + "-pgmlc" + "-pgmlibtool" + "-pgmlo" + "-pgms" + "-pgmwindres" + "-plugin-package" + "-plugin-package-id" + "-prof" + "-rdynamic" + "-recomp" + "-relative-dynlib-paths" + "-rtsopts" + "-rtsopts=all" + "-rtsopts=none" + "-rtsopts=some" + "-shared" + "-sig-of" + "-smp" + "-split-objs" + "-split-sections" + "-static" + "-staticlib" + "-stubdir" + "-syslib" + "-this-package-key" + "-this-unit-id" + "-threaded" + "-ticky" + "-ticky-LNE" + "-ticky-allocd" + "-ticky-dyn-thunk" + "-tmpdir" + "-trust" + "-user-package-db" + "-v" + "-w" + "-with-rtsopts" + ;;; END haskell-ghc-supported-options + ) + "List of options supported by any known version of GHC. + +This list should be updated by running `haskell-update-ghc-support'.") + + +(defun haskell-update-ghc-support (ghc-path) + "Update `haskell-ghc-supported-options' and `haskell-ghc-supported-extensions'. + +This command should be run once a GHC is released. It will use +--show-options and --supported-extensions to source the +information from GHC-PATH. Then it will update source code to +include newly found options. Old options are never removed and +are retained to support old versions of the compiler. + +Options and extension are kept in ascending order." + (interactive + (list + (read-shell-command "GHC command: " nil nil + (let ((filename + (cond + (buffer-file-name) + ((eq major-mode 'dired-mode) + (when (fboundp 'dired-get-filename) + ;; silence the checker + (dired-get-filename nil t)))))) + (and filename (file-relative-name filename)))))) + + + (let ((extentions (split-string (shell-command-to-string (concat ghc-path " --supported-extensions")))) + (options (split-string (shell-command-to-string (concat ghc-path " --show-options"))))) + (with-current-buffer + (find-file-noselect (replace-regexp-in-string "\\.elc$" ".el" (symbol-file 'haskell-ghc-supported-options))) + (save-excursion + (goto-char (point-min)) + (re-search-forward "BEGIN haskell-ghc-supported-extensions") + (forward-line 1) + (let ((point (point))) + (re-search-forward "END haskell-ghc-supported-extensions") + (goto-char (line-beginning-position)) + (delete-region point (point))) + (setq haskell-ghc-supported-extensions + (delete-dups (sort (append extentions haskell-ghc-supported-extensions) #'string<))) + (dolist (item haskell-ghc-supported-extensions) + (insert " \"" item "\"\n")) + (re-search-forward "BEGIN haskell-ghc-supported-options") + (forward-line 1) + (let ((point (point))) + (re-search-forward "END haskell-ghc-supported-options") + (goto-char (line-beginning-position)) + (delete-region point (point))) + (setq haskell-ghc-supported-options + (delete-dups (sort (append options haskell-ghc-supported-options) #'string<))) + (dolist (item haskell-ghc-supported-options) + (insert " \"" item "\"\n")))))) + +(provide 'haskell-ghc-support) diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-ghc-support.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-ghc-support.elc new file mode 100644 index 000000000000..1fde197f6453 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-ghc-support.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-hoogle.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-hoogle.el new file mode 100644 index 000000000000..62aaaaad7a3a --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-hoogle.el @@ -0,0 +1,151 @@ +;;; haskell-hoogle.el --- Look up Haskell documentation via hoogle or hayoo -*- lexical-binding: t; -*- + +;; Copyright © 2015 Steve Purcell +;; 2016 Arthur Fayzrakhmanov + +;; Author: Steve Purcell <steve@sanityinc.com> +;; Keywords: docs + +;; This program 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 of the License, or +;; (at your option) any later version. + +;; This program 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Functions for looking up documentation with hayoo or hoogle, via +;; either local or remote servers. + +;;; Code: + +(require 'ansi-color) +(require 'haskell-mode) +(require 'haskell-utils) + + +(defcustom haskell-hoogle-command + (if (executable-find "hoogle") "hoogle") + "Name of the command to use to query Hoogle. +If nil, use the Hoogle web-site." + :group 'haskell + :type '(choice (const :tag "Use Web-site" nil) + string)) + +(defcustom haskell-hoogle-url "http://haskell.org/hoogle/?q=%s" + "Default value for hoogle web site." + :group 'haskell + :type '(choice + (const :tag "haskell-org" "http://haskell.org/hoogle/?q=%s") + (const :tag "fp-complete" "https://www.stackage.org/lts/hoogle?q=%s") + (const :tag "hayoo" "http://hayoo.fh-wedel.de/?query=%s") + string)) + +;;;###autoload +(defun haskell-hoogle (query &optional info) + "Do a Hoogle search for QUERY. +When `haskell-hoogle-command' is non-nil, this command runs +that. Otherwise, it opens a hoogle search result in the browser. + +If prefix argument INFO is given, then `haskell-hoogle-command' +is asked to show extra info for the items matching QUERY.." + (interactive + (let ((def (haskell-ident-at-point))) + (if (and def (symbolp def)) (setq def (symbol-name def))) + (list (read-string (if def + (format "Hoogle query (default %s): " def) + "Hoogle query: ") + nil nil def) + current-prefix-arg))) + (if (null haskell-hoogle-command) + (browse-url (format haskell-hoogle-url (url-hexify-string query))) + (let ((command (concat haskell-hoogle-command + (if info " -i " "") + " --color " (shell-quote-argument query)))) + (with-help-window "*hoogle*" + (with-current-buffer standard-output + (insert (shell-command-to-string command)) + (ansi-color-apply-on-region (point-min) (point-max))))))) + +;;;###autoload +(defalias 'hoogle 'haskell-hoogle) + +(defvar haskell-hoogle-server-process-name "emacs-local-hoogle") +(defvar haskell-hoogle-server-buffer-name (format "*%s*" haskell-hoogle-server-process-name)) +(defvar haskell-hoogle-port-number 49513 "Port number.") +(defvar haskell-hoogle-server-process nil "The process handle of the local hoogle server.") + +(defun haskell-hoogle-start-server () + "Start hoogle local server." + (interactive) + (if (executable-find "hoogle") + (unless (haskell-hoogle-server-live-p) + (set 'haskell-hoogle-server-process + (start-process + haskell-hoogle-server-process-name + (get-buffer-create haskell-hoogle-server-buffer-name) + "hoogle" "server" "-p" (number-to-string haskell-hoogle-port-number)))) + (error "\"hoogle\" executable not found"))) + +(defun haskell-hoogle-server-live-p () + "Whether the hoogle server process is live." + (condition-case _err + (process-live-p haskell-hoogle-server-process) + (error nil))) + +(defun haskell-hoogle-kill-server () + "Kill the hoogle server if it is live." + (interactive) + (when (haskell-hoogle-server-live-p) + (kill-process (get-buffer-create haskell-hoogle-server-buffer-name)) + (set 'haskell-hoogle-server-process nil))) + +;;;###autoload +(defun haskell-hoogle-lookup-from-local () + "Lookup by local hoogle." + (interactive) + (if (haskell-hoogle-server-live-p) + (browse-url (format "http://localhost:%i/?hoogle=%s" + haskell-hoogle-port-number + (read-string "hoogle: " (haskell-ident-at-point)))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (when (y-or-n-p "Hoogle server not running, start hoogle server? ") + (haskell-hoogle-start-server)) + (haskell-mode-toggle-interactive-prompt-state t)))) + + +(defcustom haskell-hayoo-url "http://hayoo.fh-wedel.de/?query=%s" + "Default value for hayoo web site." + :group 'haskell + :type '(choice + (const :tag "fh-wedel.de" "http://hayoo.fh-wedel.de/?query=%s") + string)) + +;;;###autoload +(defun haskell-hayoo (query) + "Do a Hayoo search for QUERY." + (interactive + (let ((def (haskell-ident-at-point))) + (if (and def (symbolp def)) (setq def (symbol-name def))) + (list (read-string (if def + (format "Hayoo query (default %s): " def) + "Hayoo query: ") + nil nil def)))) + (browse-url (format haskell-hayoo-url (url-hexify-string query)))) + +;;;###autoload +(defalias 'hayoo 'haskell-hayoo) + + + + +(provide 'haskell-hoogle) +;;; haskell-hoogle.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-hoogle.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-hoogle.elc new file mode 100644 index 000000000000..93ab3fc36cd9 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-hoogle.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-indent.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-indent.el new file mode 100644 index 000000000000..afa558503b7c --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-indent.el @@ -0,0 +1,1596 @@ +;;; haskell-indent.el --- "semi-intelligent" indentation module for Haskell Mode -*- lexical-binding: t -*- + +;; Copyright 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. +;; Copyright 1997-1998 Guy Lapalme + +;; Author: 1997-1998 Guy Lapalme <lapalme@iro.umontreal.ca> + +;; Keywords: indentation Haskell layout-rule +;; URL: http://www.iro.umontreal.ca/~lapalme/layout/index.html + +;; This file is not part of GNU Emacs. + +;; 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Purpose: +;; +;; To support automatic indentation of Haskell programs using +;; the layout rule described in section 1.5 and appendix B.3 of the +;; the Haskell report. The rationale and the implementation principles +;; are described in an article to appear in Journal of Functional Programming. +;; "Dynamic tabbing for automatic indentation with the layout rule" +;; +;; It supports literate scripts. +;; Haskell indentation is performed +;; within \begin{code}...\end{code} sections of a literate script +;; and in lines beginning with > with Bird style literate script +;; TAB aligns to the left column outside of these sections. +;; +;; Installation: +;; +;; To turn indentation on for all Haskell buffers under the Haskell +;; mode of Moss&Thorn <http://www.haskell.org/haskell-mode/> +;; add this to .emacs: +;; +;; (add-hook 'haskell-mode-hook 'turn-on-haskell-indent) +;; +;; Otherwise, call `turn-on-haskell-indent'. +;; +;; +;; Customisation: +;; The "standard" offset for statements is 4 spaces. +;; It can be changed by setting the variable "haskell-indent-offset" to +;; another value +;; +;; The default number of blanks after > in a Bird style literate script +;; is 1; it can be changed by setting the variable +;; "haskell-indent-literate-Bird-default-offset" +;; +;; `haskell-indent-hook' is invoked if not nil. +;; +;; All functions/variables start with +;; `(turn-(on/off)-)haskell-indent' or `haskell-indent-'. + +;; This file can also be used as a hook for the Hugs Mode developed by +;; Chris Van Humbeeck <chris.vanhumbeeck@cs.kuleuven.ac.be> +;; It can be obtained at: +;; http://www-i2.informatik.rwth-aachen.de/Forschung/FP/Haskell/hugs-mode.el +;; +;; For the Hugs mode put the following in your .emacs +;; +;;(setq auto-mode-alist (append auto-mode-alist '(("\\.hs\\'" . hugs-mode)))) +;;(autoload 'hugs-mode "hugs-mode" "Go into hugs mode" t) +;; +;; If only the indentation mode is used then replace the two +;; preceding lines with +;;(setq auto-mode-alist (append auto-mode-alist +;; '(("\\.hs\\'" . turn-on-haskell-indent)))) +;;(autoload 'turn-on-haskell-indent "hindent" "Indentation mode for Haskell" t) +;; +;; For indentation in both cases then add the following to your .emacs +;;(add-hook 'hugs-mode-hook 'turn-on-haskell-indent) +;;(autoload 'haskell-indent-cycle "hindent" "Indentation cycle for Haskell" t) +;; + +;;; Code: + +(require 'cl-lib) +(require 'haskell-string) + +(defvar haskell-literate) + +;;;###autoload +(defgroup haskell-indent nil + "Haskell indentation." + :group 'haskell + :link '(custom-manual "(haskell-mode)Indentation") + :prefix "haskell-indent-") + +(defcustom haskell-indent-offset 4 + "Indentation of Haskell statements with respect to containing block." + :type 'integer + :safe #'natnump + :group 'haskell-indent) + +(defcustom haskell-indent-literate-Bird-default-offset 1 + "Default number of blanks after > in a Bird style literate script." + :type 'integer + :safe #'natnump + :group 'haskell-indent) + +(defcustom haskell-indent-rhs-align-column 0 + "Column on which to align right-hand sides (use 0 for ad-hoc alignment)." + :type 'integer + :safe #'natnump + :group 'haskell-indent) + +(defun haskell-indent-point-to-col (apoint) + "Return the column number of APOINT." + (save-excursion + (goto-char apoint) + (current-column))) + +(defconst haskell-indent-start-keywords-re + (concat "\\<" + (regexp-opt '("class" "data" "import" "infix" "infixl" "infixr" + "instance" "module" "newtype" "primitive" "signature" "type") t) + "\\>") + "Regexp for keywords to complete when standing at the first word of a line.") + + +;; Customizations for different kinds of environments +;; in which dealing with low-level events are different. +(defun haskell-indent-mark-active () + (if (featurep 'xemacs) + (if zmacs-regions + zmacs-region-active-p + t) + mark-active)) + +;; for pushing indentation information + +(defvar haskell-indent-info) ;Used with dynamic scoping. + +(defun haskell-indent-push-col (col &optional name) + "Push indentation information for the column COL. +The info is followed by NAME (if present). +Makes sure that the same indentation info is not pushed twice. +Uses free var `haskell-indent-info'." + (let ((tmp (cons col name))) + (if (member tmp haskell-indent-info) + haskell-indent-info + (push tmp haskell-indent-info)))) + +(defun haskell-indent-push-pos (pos &optional name) + "Push indentation information for POS followed by NAME (if present)." + (haskell-indent-push-col (haskell-indent-point-to-col pos) name)) + +;; (defvar haskell-indent-tab-align nil +;; "Align all indentations on TAB stops.") + +(defun haskell-indent-column+offset (column offset) + (unless offset (setq offset haskell-indent-offset)) + (setq column (+ column offset)) + ;; (if (and haskell-indent-tab-align (> offset 0)) + ;; (* 8 (/ (+ column 7) 8)) + column) ;; ) + +(defun haskell-indent-push-pos-offset (pos &optional offset) + "Pushes indentation information for the column corresponding to POS +followed by an OFFSET (if present use its value otherwise use +`haskell-indent-offset')." + (haskell-indent-push-col (haskell-indent-column+offset + (haskell-indent-point-to-col pos) + offset))) + +;; redefinition of some Emacs function for dealing with +;; Bird Style literate scripts + +(defun haskell-indent-bolp () + "`bolp' but dealing with Bird-style literate scripts." + (or (bolp) + (and (eq haskell-literate 'bird) + (<= (current-column) (1+ haskell-indent-literate-Bird-default-offset)) + (eq (char-after (line-beginning-position)) ?\>)))) + +(defun haskell-indent-empty-line-p () + "Checks if the current line is empty; deals with Bird style scripts." + (save-excursion + (beginning-of-line) + (if (and (eq haskell-literate 'bird) + (eq (following-char) ?\>)) + (forward-char 1)) + (looking-at "[ \t]*$"))) + +(defun haskell-indent-back-to-indentation () + "`back-to-indentation' function but dealing with Bird-style literate scripts." + (if (and (eq haskell-literate 'bird) + (progn (beginning-of-line) (eq (following-char) ?\>))) + (progn + (forward-char 1) + (skip-chars-forward " \t")) + (back-to-indentation))) + +(defun haskell-indent-current-indentation () + "`current-indentation' function dealing with Bird-style literate scripts." + (if (eq haskell-literate 'bird) + (save-excursion + (haskell-indent-back-to-indentation) + (current-column)) + (current-indentation))) + +(defun haskell-indent-backward-to-indentation (n) + "`backward-to-indentation' function dealing with Bird-style literate scripts." + (if (eq haskell-literate 'bird) + (progn + (forward-line (- n)) + (haskell-indent-back-to-indentation)) + (backward-to-indentation n))) + +(defun haskell-indent-forward-line (&optional n) + "`forward-line' function but dealing with Bird-style literate scripts." + (prog1 + (forward-line n) + (if (and (eq haskell-literate 'bird) (eq (following-char) ?\>)) + (progn (forward-char 1) ; skip > and initial blanks... + (skip-chars-forward " \t"))))) + +(defun haskell-indent-line-to (n) + "`indent-line-to' function but dealing with Bird-style literate scripts." + (if (eq haskell-literate 'bird) + (progn + (beginning-of-line) + (if (eq (following-char) ?\>) + (delete-char 1)) + (delete-horizontal-space) ; remove any starting TABs so + (indent-line-to n) ; that indent-line only adds spaces + (save-excursion + (beginning-of-line) + (if (> n 0) (delete-char 1)) ; delete the first space before + (insert ?\>))) ; inserting a > + (indent-line-to n))) + +(defun haskell-indent-skip-blanks-and-newlines-forward (end) + "Skip forward blanks, tabs and newlines until END. +Take account of Bird-style literate scripts." + (skip-chars-forward " \t\n" end) + (if (eq haskell-literate 'bird) + (while (and (bolp) (eq (following-char) ?\>)) + (forward-char 1) ; skip > + (skip-chars-forward " \t\n" end)))) + +(defun haskell-indent-skip-blanks-and-newlines-backward (start) + "Skip backward blanks, tabs and newlines up to START. +Take account of Bird-style literate scripts." + (skip-chars-backward " \t\n" start) + (if (eq haskell-literate 'bird) + (while (and (eq (current-column) 1) + (eq (preceding-char) ?\>)) + (forward-char -1) ; skip back > + (skip-chars-backward " \t\n" start)))) + +;; specific functions for literate code + +(defun haskell-indent-within-literate-code () + "Check if point is within a part of literate Haskell code. +If so, return its start; otherwise return nil: +If it is Bird-style, then return the position of the >; +otherwise return the ending position of \\begin{code}." + (save-excursion + (cl-case haskell-literate + (bird + (beginning-of-line) + (if (or (eq (following-char) ?\>) + (and (bolp) (forward-line -1) (eq (following-char) ?\>))) + (progn + (while (and (zerop (forward-line -1)) + (eq (following-char) ?\>))) + (if (not (eq (following-char) ?\>)) + (forward-line)) + (point)))) + ;; Look for a \begin{code} or \end{code} line. + ((latex tex) + (if (re-search-backward + "^\\(\\\\begin{code}$\\)\\|\\(\\\\end{code}$\\)" nil t) + ;; within a literate code part if it was a \\begin{code}. + (match-end 1))) + (t (error "haskell-indent-within-literate-code: should not happen!"))))) + +(defun haskell-indent-put-region-in-literate (beg end &optional arg) + "Put lines of the region as a piece of literate code. +With prefix arg, remove indication that the region is literate code. +It deals with both Bird style and non Bird-style scripts." + (interactive "r\nP") + (unless haskell-literate + (error "Cannot put a region in literate in a non literate script")) + (if (eq haskell-literate 'bird) + (let ((comment-start "> ") ; Change dynamic bindings for + (comment-start-skip "^> ?") ; comment-region. + (comment-end "") + (comment-end-skip "\n") + (comment-style 'plain)) + (comment-region beg end arg)) + ;; Not Bird style. + (if arg ; Remove the literate indication. + (save-excursion + (goto-char end) ; Remove end. + (if (re-search-backward "^\\\\end{code}[ \t\n]*\\=" + (line-beginning-position -2) t) + (delete-region (point) (line-beginning-position 2))) + (goto-char beg) ; Remove end. + (beginning-of-line) + (if (looking-at "\\\\begin{code}") + (kill-line 1))) + (save-excursion ; Add the literate indication. + (goto-char end) + (unless (bolp) (newline)) + (insert "\\end{code}\n") + (goto-char beg) + (unless (bolp) (newline)) + (insert "\\begin{code}\n"))))) + +;;; Start of indentation code +(defcustom haskell-indent-look-past-empty-line t + "If nil, indentation engine will not look past an empty line for layout points." + :group 'haskell-indent + :safe #'booleanp + :type 'boolean) + +(defun haskell-indent-start-of-def () + "Return the position of the start of a definition. +The start of a def is expected to be recognizable by starting in column 0, +unless `haskell-indent-look-past-empty-line' is nil, in which case we +take a coarser approximation and stop at the first empty line." + (save-excursion + (let ((start-code (and haskell-literate + (haskell-indent-within-literate-code))) + (top-col (if (eq haskell-literate 'bird) 2 0)) + (save-point (point))) + ;; determine the starting point of the current piece of code + (setq start-code (if start-code (1+ start-code) (point-min))) + ;; go backward until the first preceding empty line + (haskell-indent-forward-line -1) + (while (and (if haskell-indent-look-past-empty-line + (or (> (haskell-indent-current-indentation) top-col) + (haskell-indent-empty-line-p)) + (and (> (haskell-indent-current-indentation) top-col) + (not (haskell-indent-empty-line-p)))) + (> (point) start-code) + (= 0 (haskell-indent-forward-line -1)))) + ;; go forward after the empty line + (if (haskell-indent-empty-line-p) + (haskell-indent-forward-line 1)) + (setq start-code (point)) + ;; find the first line of code which is not a comment + (forward-comment (point-max)) + (if (> (point) save-point) + start-code + (point))))) + +(defun haskell-indent-open-structure (start end) + "If any structure (list or tuple) is not closed, between START and END, +returns the location of the opening symbol, nil otherwise." + (save-excursion + (nth 1 (parse-partial-sexp start end)))) + +(defun haskell-indent-in-string (start end) + "If a string is not closed , between START and END, returns the +location of the opening symbol, nil otherwise." + (save-excursion + (let ((pps (parse-partial-sexp start end))) + (if (nth 3 pps) (nth 8 pps))))) + +(defun haskell-indent-in-comment (start end) + "Check, starting from START, if END is at or within a comment. +Returns the location of the start of the comment, nil otherwise." + (let (pps) + (cl-assert (<= start end)) + (cond ((= start end) nil) + ((nth 4 (save-excursion (setq pps (parse-partial-sexp start end)))) + (nth 8 pps)) + ;; We also want to say that we are *at* the beginning of a comment. + ((and (not (nth 8 pps)) + (>= (point-max) (+ end 2)) + (nth 4 (save-excursion + (setq pps (parse-partial-sexp end (+ end 2)))))) + (nth 8 pps))))) + +(defvar haskell-indent-off-side-keywords-re + "\\<\\(do\\|let\\|of\\|where\\|mdo\\|rec\\)\\>[ \t]*") + +(defun haskell-indent-type-at-point () + "Return the type of the line (also puts information in `match-data')." + (cond + ((haskell-indent-empty-line-p) 'empty) + ((haskell-indent-in-comment (point-min) (point)) 'comment) + ((looking-at "\\(\\([[:alpha:]]\\(\\sw\\|'\\)*\\)\\|_\\)[ \t\n]*") + 'ident) + ((looking-at "\\(|[^|]\\)[ \t\n]*") 'guard) + ((looking-at "\\(=[^>=]\\|::\\|∷\\|→\\|←\\|->\\|<-\\)[ \t\n]*") 'rhs) + (t 'other))) + +(defvar haskell-indent-current-line-first-ident "" + "Global variable that keeps track of the first ident of the line to indent.") + + +(defun haskell-indent-contour-line (start end) + "Generate contour information between START and END points." + (if (< start end) + (save-excursion + (goto-char end) + (haskell-indent-skip-blanks-and-newlines-backward start) + (let ((cur-col (current-column)) ; maximum column number + (fl 0) ; number of lines that forward-line could not advance + contour) + (while (and (> cur-col 0) (= fl 0) (>= (point) start)) + (haskell-indent-back-to-indentation) + (if (< (point) start) (goto-char start)) + (and (not (member (haskell-indent-type-at-point) + '(empty comment))) ; skip empty and comment lines + (< (current-column) cur-col) ; less indented column found + (push (point) contour) ; new contour point found + (setq cur-col (current-column))) + (setq fl (haskell-indent-forward-line -1))) + contour)))) + +(defun haskell-indent-next-symbol (end) + "Move point to the next symbol." + (skip-syntax-forward ")" end) + (if (< (point) end) + (progn + (forward-sexp 1) + (haskell-indent-skip-blanks-and-newlines-forward end)))) + +(defun haskell-indent-next-symbol-safe (end) + "Puts point to the next following symbol, or to end if there are no more symbols in the sexp." + (condition-case _errlist (haskell-indent-next-symbol end) + (error (goto-char end)))) + +(defun haskell-indent-separate-valdef (start end) + "Return a list of positions for important parts of a valdef." + (save-excursion + (let (valname valname-string aft-valname + guard aft-guard + rhs-sign aft-rhs-sign + type) + ;; "parse" a valdef separating important parts + (goto-char start) + (setq type (haskell-indent-type-at-point)) + (if (or (memq type '(ident other))) ; possible start of a value def + (progn + (if (eq type 'ident) + (progn + (setq valname (match-beginning 0)) + (setq valname-string (match-string 0)) + (goto-char (match-end 0))) + (skip-chars-forward " \t" end) + (setq valname (point)) ; type = other + (haskell-indent-next-symbol-safe end)) + (while (and (< (point) end) + (setq type (haskell-indent-type-at-point)) + (or (memq type '(ident other)))) + (if (null aft-valname) + (setq aft-valname (point))) + (haskell-indent-next-symbol-safe end)))) + (if (and (< (point) end) (eq type 'guard)) ; start of a guard + (progn + (setq guard (match-beginning 0)) + (goto-char (match-end 0)) + (while (and (< (point) end) + (setq type (haskell-indent-type-at-point)) + (not (eq type 'rhs))) + (if (null aft-guard) + (setq aft-guard (point))) + (haskell-indent-next-symbol-safe end)))) + (if (and (< (point) end) (eq type 'rhs)) ; start of a rhs + (progn + (setq rhs-sign (match-beginning 0)) + (goto-char (match-end 0)) + (if (< (point) end) + (setq aft-rhs-sign (point))))) + (list valname valname-string aft-valname + guard aft-guard rhs-sign aft-rhs-sign)))) + +(defsubst haskell-indent-no-otherwise (guard) + "Check if there is no otherwise at GUARD." + (save-excursion + (goto-char guard) + (not (looking-at "|[ \t]*otherwise\\>")))) + + +(defun haskell-indent-guard (start end end-visible indent-info) + "Find indentation information for a line starting with a guard." + (save-excursion + (let* ((haskell-indent-info indent-info) + (sep (haskell-indent-separate-valdef start end)) + (valname (nth 0 sep)) + (guard (nth 3 sep)) + (rhs-sign (nth 5 sep))) + ;; push information indentation for the visible part + (if (and guard (< guard end-visible) (haskell-indent-no-otherwise guard)) + (haskell-indent-push-pos guard) + (if rhs-sign + (haskell-indent-push-pos rhs-sign) ; probably within a data definition... + (if valname + (haskell-indent-push-pos-offset valname)))) + haskell-indent-info))) + +(defun haskell-indent-rhs (start end end-visible indent-info) + "Find indentation information for a line starting with a rhs." + (save-excursion + (let* ((haskell-indent-info indent-info) + (sep (haskell-indent-separate-valdef start end)) + (valname (nth 0 sep)) + (guard (nth 3 sep)) + (rhs-sign (nth 5 sep))) + ;; push information indentation for the visible part + (if (and rhs-sign (< rhs-sign end-visible)) + (haskell-indent-push-pos rhs-sign) + (if (and guard (< guard end-visible)) + (haskell-indent-push-pos-offset guard) + (if valname ; always visible !! + (haskell-indent-push-pos-offset valname)))) + haskell-indent-info))) + +(defconst haskell-indent-decision-table + (let ((or "\\)\\|\\(")) + (concat "\\(" + "1.1.11" or ; 1= vn gd rh arh + "1.1.10" or ; 2= vn gd rh + "1.1100" or ; 3= vn gd agd + "1.1000" or ; 4= vn gd + "1.0011" or ; 5= vn rh arh + "1.0010" or ; 6= vn rh + "110000" or ; 7= vn avn + "100000" or ; 8= vn + "001.11" or ; 9= gd rh arh + "001.10" or ;10= gd rh + "001100" or ;11= gd agd + "001000" or ;12= gd + "000011" or ;13= rh arh + "000010" or ;14= rh + "000000" ;15= + "\\)"))) + +(defun haskell-indent-find-case (test) + "Find the index that matches TEST in the decision table." + (if (string-match haskell-indent-decision-table test) + ;; use the fact that the resulting match-data is a list of the form + ;; (0 6 [2*(n-1) nil] 0 6) where n is the number of the matching regexp + ;; so n= ((length match-data)/2)-1 + (- (/ (length (match-data 'integers)) 2) 1) + (error "haskell-indent-find-case: impossible case: %s" test))) + +(defun haskell-indent-empty (start end end-visible indent-info) + "Find indentation points for an empty line." + (save-excursion + (let* ((haskell-indent-info indent-info) + (sep (haskell-indent-separate-valdef start end)) + (valname (pop sep)) + (valname-string (pop sep)) + (aft-valname (pop sep)) + (guard (pop sep)) + (aft-guard (pop sep)) + (rhs-sign (pop sep)) + (aft-rhs-sign (pop sep)) + (last-line (= end end-visible)) + (test (string + (if valname ?1 ?0) + (if (and aft-valname (< aft-valname end-visible)) ?1 ?0) + (if (and guard (< guard end-visible)) ?1 ?0) + (if (and aft-guard (< aft-guard end-visible)) ?1 ?0) + (if (and rhs-sign (< rhs-sign end-visible)) ?1 ?0) + (if (and aft-rhs-sign (< aft-rhs-sign end-visible)) ?1 ?0)))) + (if (and valname-string ; special case for start keywords + (string-match haskell-indent-start-keywords-re valname-string)) + (progn + (haskell-indent-push-pos valname) + ;; very special for data keyword + (if (string-match "\\<data\\>" valname-string) + (if rhs-sign (haskell-indent-push-pos rhs-sign) + (haskell-indent-push-pos-offset valname)) + (haskell-indent-push-pos-offset valname))) + (cl-case ; general case + (haskell-indent-find-case test) + ;; "1.1.11" 1= vn gd rh arh + (1 (haskell-indent-push-pos valname) + (haskell-indent-push-pos valname valname-string) + (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| ")) + (haskell-indent-push-pos aft-rhs-sign)) + ;; "1.1.10" 2= vn gd rh + (2 (haskell-indent-push-pos valname) + (haskell-indent-push-pos valname valname-string) + (if last-line + (haskell-indent-push-pos-offset guard) + (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| ")))) + ;; "1.1100" 3= vn gd agd + (3 (haskell-indent-push-pos valname) + (haskell-indent-push-pos aft-guard) + (if last-line (haskell-indent-push-pos-offset valname))) + ;; "1.1000" 4= vn gd + (4 (haskell-indent-push-pos valname) + (if last-line (haskell-indent-push-pos-offset guard 2))) + ;; "1.0011" 5= vn rh arh + (5 (haskell-indent-push-pos valname) + (if (or (and aft-valname (= (char-after rhs-sign) ?\=)) + (= (char-after rhs-sign) ?\:)) + (haskell-indent-push-pos valname valname-string)) + (haskell-indent-push-pos aft-rhs-sign)) + ;; "1.0010" 6= vn rh + (6 (haskell-indent-push-pos valname) + (haskell-indent-push-pos valname valname-string) + (if last-line (haskell-indent-push-pos-offset valname))) + ;; "110000" 7= vn avn + (7 (haskell-indent-push-pos valname) + (if last-line + (haskell-indent-push-pos aft-valname) + (haskell-indent-push-pos valname valname-string))) + ;; "100000" 8= vn + (8 (haskell-indent-push-pos valname)) + ;; "001.11" 9= gd rh arh + (9 (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| ")) + (haskell-indent-push-pos aft-rhs-sign)) + ;; "001.10" 10= gd rh + (10 (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| ")) + (if last-line (haskell-indent-push-pos-offset guard))) + ;; "001100" 11= gd agd + (11 (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| ")) + (haskell-indent-push-pos aft-guard)) + ;; "001000" 12= gd + (12 (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| ")) + (if last-line (haskell-indent-push-pos-offset guard 2))) + ;; "000011" 13= rh arh + (13 (haskell-indent-push-pos aft-rhs-sign)) + ;; "000010" 14= rh + (14 (if last-line (haskell-indent-push-pos-offset rhs-sign 2 ))) + ;; "000000" 15= + (t (error "haskell-indent-empty: %s impossible case" test )))) + haskell-indent-info))) + +(defun haskell-indent-ident (start end end-visible indent-info) + "Find indentation points for a line starting with an identifier." + (save-excursion + (let* + ((haskell-indent-info indent-info) + (sep (haskell-indent-separate-valdef start end)) + (valname (pop sep)) + (valname-string (pop sep)) + (aft-valname (pop sep)) + (guard (pop sep)) + (aft-guard (pop sep)) + (rhs-sign (pop sep)) + (aft-rhs-sign (pop sep)) + (last-line (= end end-visible)) + (is-where + (string-match "where[ \t]*" haskell-indent-current-line-first-ident)) + (diff-first ; not a function def with the same name + (or (null valname-string) + (not (string= (haskell-string-trim valname-string) + (haskell-string-trim haskell-indent-current-line-first-ident))))) + + ;; (is-type-def + ;; (and rhs-sign (eq (char-after rhs-sign) ?\:))) + (test (string + (if valname ?1 ?0) + (if (and aft-valname (< aft-valname end-visible)) ?1 ?0) + (if (and guard (< guard end-visible)) ?1 ?0) + (if (and aft-guard (< aft-guard end-visible)) ?1 ?0) + (if (and rhs-sign (< rhs-sign end-visible)) ?1 ?0) + (if (and aft-rhs-sign (< aft-rhs-sign end-visible)) ?1 ?0)))) + (if (and valname-string ; special case for start keywords + (string-match haskell-indent-start-keywords-re valname-string)) + (progn + (haskell-indent-push-pos valname) + (if (string-match "\\<data\\>" valname-string) + ;; very special for data keyword + (if aft-rhs-sign (haskell-indent-push-pos aft-rhs-sign) + (haskell-indent-push-pos-offset valname)) + (if (not (string-match + haskell-indent-start-keywords-re + haskell-indent-current-line-first-ident)) + (haskell-indent-push-pos-offset valname)))) + (if (string= haskell-indent-current-line-first-ident "::") + (if valname (haskell-indent-push-pos valname)) + (cl-case ; general case + (haskell-indent-find-case test) + ;; "1.1.11" 1= vn gd rh arh + (1 (if is-where + (haskell-indent-push-pos guard) + (haskell-indent-push-pos valname) + (if diff-first (haskell-indent-push-pos aft-rhs-sign)))) + ;; "1.1.10" 2= vn gd rh + (2 (if is-where + (haskell-indent-push-pos guard) + (haskell-indent-push-pos valname) + (if last-line + (haskell-indent-push-pos-offset guard)))) + ;; "1.1100" 3= vn gd agd + (3 (if is-where + (haskell-indent-push-pos-offset guard) + (haskell-indent-push-pos valname) + (if diff-first + (haskell-indent-push-pos aft-guard)))) + ;; "1.1000" 4= vn gd + (4 (if is-where + (haskell-indent-push-pos guard) + (haskell-indent-push-pos valname) + (if last-line + (haskell-indent-push-pos-offset guard 2)))) + ;; "1.0011" 5= vn rh arh + (5 (if is-where + (haskell-indent-push-pos-offset valname) + (haskell-indent-push-pos valname) + (if diff-first + (haskell-indent-push-pos aft-rhs-sign)))) + ;; "1.0010" 6= vn rh + (6 (if is-where + (haskell-indent-push-pos-offset valname) + (haskell-indent-push-pos valname) + (if last-line + (haskell-indent-push-pos-offset valname)))) + ;; "110000" 7= vn avn + (7 (if is-where + (haskell-indent-push-pos-offset valname) + (haskell-indent-push-pos valname) + (if last-line + (haskell-indent-push-pos aft-valname)))) + ;; "100000" 8= vn + (8 (if is-where + (haskell-indent-push-pos-offset valname) + (haskell-indent-push-pos valname))) + ;; "001.11" 9= gd rh arh + (9 (if is-where + (haskell-indent-push-pos guard) + (haskell-indent-push-pos aft-rhs-sign))) + ;; "001.10" 10= gd rh + (10 (if is-where + (haskell-indent-push-pos guard) + (if last-line + (haskell-indent-push-pos-offset guard)))) + ;; "001100" 11= gd agd + (11 (if is-where + (haskell-indent-push-pos guard) + (if (haskell-indent-no-otherwise guard) + (haskell-indent-push-pos aft-guard)))) + ;; "001000" 12= gd + (12 (if last-line (haskell-indent-push-pos-offset guard 2))) + ;; "000011" 13= rh arh + (13 (haskell-indent-push-pos aft-rhs-sign)) + ;; "000010" 14= rh + (14 (if last-line (haskell-indent-push-pos-offset rhs-sign 2))) + ;; "000000" 15= + (t (error "haskell-indent-ident: %s impossible case" test ))))) + haskell-indent-info))) + +(defun haskell-indent-other (start end end-visible indent-info) + "Find indentation points for a non-empty line starting with something other +than an identifier, a guard or rhs." + (save-excursion + (let* ((haskell-indent-info indent-info) + (sep (haskell-indent-separate-valdef start end)) + (valname (pop sep)) + (valname-string (pop sep)) + (aft-valname (pop sep)) + (guard (pop sep)) + (aft-guard (pop sep)) + (rhs-sign (pop sep)) + (aft-rhs-sign (pop sep)) + (last-line (= end end-visible)) + (test (string + (if valname ?1 ?0) + (if (and aft-valname (< aft-valname end-visible)) ?1 ?0) + (if (and guard (< guard end-visible)) ?1 ?0) + (if (and aft-guard (< aft-guard end-visible)) ?1 ?0) + (if (and rhs-sign (< rhs-sign end-visible)) ?1 ?0) + (if (and aft-rhs-sign (< aft-rhs-sign end-visible)) ?1 ?0)))) + (if (and valname-string ; special case for start keywords + (string-match haskell-indent-start-keywords-re valname-string)) + (haskell-indent-push-pos-offset valname) + (cl-case ; general case + (haskell-indent-find-case test) + ;; "1.1.11" 1= vn gd rh arh + (1 (haskell-indent-push-pos aft-rhs-sign)) + ;; "1.1.10" 2= vn gd rh + (2 (if last-line + (haskell-indent-push-pos-offset guard) + (haskell-indent-push-pos-offset rhs-sign 2))) + ;; "1.1100" 3= vn gd agd + (3 (haskell-indent-push-pos aft-guard)) + ;; "1.1000" 4= vn gd + (4 (haskell-indent-push-pos-offset guard 2)) + ;; "1.0011" 5= vn rh arh + (5 (haskell-indent-push-pos valname) + (haskell-indent-push-pos aft-rhs-sign)) + ;; "1.0010" 6= vn rh + (6 (if last-line + (haskell-indent-push-pos-offset valname) + (haskell-indent-push-pos-offset rhs-sign 2))) + ;; "110000" 7= vn avn + (7 (haskell-indent-push-pos-offset aft-valname)) + ;; "100000" 8= vn + (8 (haskell-indent-push-pos valname)) + ;; "001.11" 9= gd rh arh + (9 (haskell-indent-push-pos aft-rhs-sign)) + ;; "001.10" 10= gd rh + (10 (if last-line + (haskell-indent-push-pos-offset guard) + (haskell-indent-push-pos-offset rhs-sign 2))) + ;; "001100" 11= gd agd + (11 (if (haskell-indent-no-otherwise guard) + (haskell-indent-push-pos aft-guard))) + ;; "001000" 12= gd + (12 (if last-line (haskell-indent-push-pos-offset guard 2))) + ;; "000011" 13= rh arh + (13 (haskell-indent-push-pos aft-rhs-sign)) + ;; "000010" 14= rh + (14 (if last-line (haskell-indent-push-pos-offset rhs-sign 2))) + ;; "000000" 15= + (t (error "haskell-indent-other: %s impossible case" test )))) + haskell-indent-info))) + +(defun haskell-indent-valdef-indentation (start end end-visible curr-line-type + indent-info) + "Find indentation information for a value definition." + (let ((haskell-indent-info indent-info)) + (if (< start end-visible) + (cl-case curr-line-type + (empty (haskell-indent-empty start end end-visible indent-info)) + (ident (haskell-indent-ident start end end-visible indent-info)) + (guard (haskell-indent-guard start end end-visible indent-info)) + (rhs (haskell-indent-rhs start end end-visible indent-info)) + (comment (error "Comment indent should never happen")) + (other (haskell-indent-other start end end-visible indent-info))) + haskell-indent-info))) + +(defun haskell-indent-line-indentation (line-start line-end end-visible + curr-line-type indent-info) + "Compute indentation info between LINE-START and END-VISIBLE. +Separate a line of program into valdefs between offside keywords +and find indentation info for each part." + (save-excursion + ;; point is (already) at line-start + (cl-assert (eq (point) line-start)) + (let ((haskell-indent-info indent-info) + (start (or (haskell-indent-in-comment line-start line-end) + (haskell-indent-in-string line-start line-end)))) + (if start ; if comment at the end + (setq line-end start)) ; end line before it + ;; loop on all parts separated by off-side-keywords + (while (and (re-search-forward haskell-indent-off-side-keywords-re + line-end t) + (not (or (haskell-indent-in-comment line-start (point)) + (haskell-indent-in-string line-start (point))))) + (let ((beg-match (match-beginning 0)) ; save beginning of match + (end-match (match-end 0))) ; save end of match + ;; Do not try to find indentation points if off-side-keyword at + ;; the start... + (if (or (< line-start beg-match) + ;; Actually, if we're looking at a "let" inside a "do", we + ;; should add the corresponding indentation point. + (eq (char-after beg-match) ?l)) + (setq haskell-indent-info + (haskell-indent-valdef-indentation line-start beg-match + end-visible + curr-line-type + haskell-indent-info))) + ;; ...but keep the start of the line if keyword alone on the line + (if (= line-end end-match) + (haskell-indent-push-pos beg-match)) + (setq line-start end-match) + (goto-char line-start))) + (haskell-indent-valdef-indentation line-start line-end end-visible + curr-line-type haskell-indent-info)))) + + +(defun haskell-indent-layout-indent-info (start contour-line) + (let ((haskell-indent-info nil) + (curr-line-type (haskell-indent-type-at-point)) + line-start line-end end-visible) + (save-excursion + (if (eq curr-line-type 'ident) + (let ; guess the type of line + ((sep + (haskell-indent-separate-valdef + (point) (line-end-position)))) + ;; if the first ident is where or the start of a def + ;; keep it in a global variable + (setq haskell-indent-current-line-first-ident + (if (string-match "where[ \t]*" (nth 1 sep)) + (nth 1 sep) + (if (nth 5 sep) ; is there a rhs-sign + (if (= (char-after (nth 5 sep)) ?\:) ;is it a typdef + "::" (nth 1 sep)) + ""))))) + (while contour-line ; explore the contour points + (setq line-start (pop contour-line)) + (goto-char line-start) + (setq line-end (line-end-position)) + (setq end-visible ; visible until the column of the + (if contour-line ; next contour point + (save-excursion + (move-to-column + (haskell-indent-point-to-col (car contour-line))) + (point)) + line-end)) + (unless (or (haskell-indent-open-structure start line-start) + (haskell-indent-in-comment start line-start)) + (setq haskell-indent-info + (haskell-indent-line-indentation line-start line-end + end-visible curr-line-type + haskell-indent-info))))) + haskell-indent-info)) + +(defun haskell-indent-find-matching-start (regexp limit &optional pred start) + (let ((open (haskell-indent-open-structure limit (point)))) + (if open (setq limit (1+ open)))) + (unless start (setq start (point))) + (when (re-search-backward regexp limit t) + (let ((nestedcase (match-end 1)) + (outer (or (haskell-indent-in-string limit (point)) + (haskell-indent-in-comment limit (point)) + (haskell-indent-open-structure limit (point)) + (if (and pred (funcall pred start)) (point))))) + (cond + (outer + (goto-char outer) + (haskell-indent-find-matching-start regexp limit pred start)) + (nestedcase + ;; Nested case. + (and (haskell-indent-find-matching-start regexp limit pred) + (haskell-indent-find-matching-start regexp limit pred start))) + (t (point)))))) + +(defun haskell-indent-filter-let-no-in (start) + "Return non-nil if point is in front of a `let' that has no `in'. +START is the position of the presumed `in'." + ;; We're looking at either `in' or `let'. + (when (looking-at "let") + (ignore-errors + (save-excursion + (forward-word 1) + (forward-comment (point-max)) + (if (looking-at "{") + (progn + (forward-sexp 1) + (forward-comment (point-max)) + (< (point) start)) + ;; Use the layout rule to see whether this let is already closed + ;; without an `in'. + (let ((col (current-column))) + (while (progn (forward-line 1) (haskell-indent-back-to-indentation) + (< (point) start)) + (when (< (current-column) col) + (setq col nil) + (goto-char start))) + (null col))))))) + +(defun haskell-indent-comment (open start) + "Compute indent info for comments and text inside comments. +OPEN is the start position of the comment in which point is." + ;; Ideally we'd want to guess whether it's commented out code or + ;; whether it's text. Instead, we'll assume it's text. + (save-excursion + (if (= open (point)) + ;; We're actually just in front of a comment: align with following + ;; code or with comment on previous line. + (let ((prev-line-info + (cond + ((eq (char-after) ?\{) nil) ;Align as if it were code. + ((and (forward-comment -1) + (> (line-beginning-position 3) open)) + ;; We're after another comment and there's no empty line + ;; between us. + (list (list (haskell-indent-point-to-col (point))))) + (t nil)))) ;Else align as if it were code + ;; Align with following code. + (forward-comment (point-max)) + ;; There are several possible indentation points for this code-line, + ;; but the only valid indentation point for the comment is the one + ;; that the user will select for the code-line. Obviously we can't + ;; know that, so we just assume that the code-line is already at its + ;; proper place. + ;; Strictly speaking "assume it's at its proper place" would mean + ;; we'd just use (current-column), but since this is using info from + ;; lines further down and it's common to reindent line-by-line, + ;; we'll align not with the current indentation, but with the + ;; one that auto-indentation "will" select. + (append + prev-line-info + (let ((indent-info (save-excursion + (haskell-indent-indentation-info start))) + (col (current-column))) + ;; Sort the indent-info so that the current indentation comes + ;; out first. + (setq indent-info + (sort indent-info + (lambda (x y) + (<= (abs (- col (car x))) (abs (- col (car y))))))) + indent-info))) + + ;; We really are inside a comment. + (if (looking-at "-}") + (progn + (forward-char 2) + (forward-comment -1) + (list (list (1+ (haskell-indent-point-to-col (point)))))) + (let ((offset (if (looking-at "--?") + (- (match-beginning 0) (match-end 0))))) + (forward-line -1) ;Go to previous line. + (haskell-indent-back-to-indentation) + (if (< (point) start) (goto-char start)) + + (list (list (if (looking-at comment-start-skip) + (if offset + (+ 2 offset (haskell-indent-point-to-col (point))) + (haskell-indent-point-to-col (match-end 0))) + (haskell-indent-point-to-col (point)))))))))) + +(defcustom haskell-indent-thenelse 0 + "If non-nil, \"then\" and \"else\" are indented. +This is necessary in the \"do\" layout under Haskell-98. +See http://hackage.haskell.org/trac/haskell-prime/wiki/DoAndIfThenElse" + :group 'haskell-indent + :safe #'booleanp + :type 'integer) + +(defun haskell-indent-closing-keyword (start) + (let ((open (save-excursion + (haskell-indent-find-matching-start + (cl-case (char-after) + (?i "\\<\\(?:\\(in\\)\\|let\\)\\>") + (?o "\\<\\(?:\\(of\\)\\|case\\)\\>") + (?t "\\<\\(?:\\(then\\)\\|if\\)\\>") + (?e "\\<\\(?:\\(else\\)\\|if\\)\\>")) + start + (if (eq (char-after) ?i) + ;; Filter out the `let's that have no `in'. + 'haskell-indent-filter-let-no-in))))) + ;; For a "hanging let/case/if at EOL" we should use a different + ;; indentation scheme. + (save-excursion + (goto-char open) + (if (haskell-indent-hanging-p) + (setq open (haskell-indent-virtual-indentation start)))) + ;; FIXME: we should try and figure out if the `if' is in a `do' layout + ;; before using haskell-indent-thenelse. + (list (list (+ (if (memq (char-after) '(?t ?e)) haskell-indent-thenelse 0) + (haskell-indent-point-to-col open)))))) + +(defcustom haskell-indent-after-keywords + '(("where" 2 0) + ("of" 2) + ("do" 2) + ("mdo" 2) + ("rec" 2) + ("in" 2 0) + ("{" 2) + "if" + "then" + "else" + "let") + "Keywords after which indentation should be indented by some offset. +Each keyword info can have the following forms: + + KEYWORD | (KEYWORD OFFSET [OFFSET-HANGING]) + +If absent OFFSET-HANGING defaults to OFFSET. +If absent OFFSET defaults to `haskell-indent-offset'. + +OFFSET-HANGING is the offset to use in the case where the keyword +is at the end of an otherwise-non-empty line." + :group 'haskell-indent + :type '(repeat (choice string + (cons :tag "" (string :tag "keyword:") + (cons :tag "" (integer :tag "offset") + (choice (const nil) + (list :tag "" + (integer :tag "offset-pending")))))))) + +(defun haskell-indent-skip-lexeme-forward () + (and (zerop (skip-syntax-forward "w")) + (skip-syntax-forward "_") + (skip-syntax-forward "(") + (skip-syntax-forward ")"))) + +(defvar haskell-indent-inhibit-after-offset nil) + +(defun haskell-indent-offset-after-info () + "Return the info from `haskell-indent-after-keywords' for keyword at point." + (let ((id (buffer-substring + (point) + (save-excursion + (haskell-indent-skip-lexeme-forward) + (point))))) + (or (assoc id haskell-indent-after-keywords) + (car (member id haskell-indent-after-keywords))))) + +(defcustom haskell-indent-dont-hang '("(") + "Lexemes that should never be considered as hanging." + :group 'haskell-indent + :type '(repeat string)) + +(defun haskell-indent-hanging-p () + ;; A Hanging keyword is one that's at the end of a line except it's not at + ;; the beginning of a line. + (not (or (= (current-column) (haskell-indent-current-indentation)) + (save-excursion + (let ((lexeme + (buffer-substring + (point) + (progn (haskell-indent-skip-lexeme-forward) (point))))) + (or (member lexeme haskell-indent-dont-hang) + (> (line-end-position) + (progn (forward-comment (point-max)) (point))))))))) + +(defun haskell-indent-after-keyword-column (offset-info start &optional default) + (unless offset-info + (setq offset-info (haskell-indent-offset-after-info))) + (unless default (setq default haskell-indent-offset)) + (setq offset-info + (if haskell-indent-inhibit-after-offset '(0) (cdr-safe offset-info))) + (if (not (haskell-indent-hanging-p)) + (haskell-indent-column+offset (current-column) + (or (car offset-info) default)) + ;; The keyword is hanging at the end of the line. + (haskell-indent-column+offset + (haskell-indent-virtual-indentation start) + (or (cadr offset-info) (car offset-info) default)))) + +(defun haskell-indent-inside-paren (open) + ;; there is an open structure to complete + (if (looking-at "\\s)\\|[;,]") + ;; A close-paren or a , or ; can only correspond syntactically to + ;; the open-paren at `open'. So there is no ambiguity. + (progn + (if (or (and (eq (char-after) ?\;) (eq (char-after open) ?\()) + (and (eq (char-after) ?\,) (eq (char-after open) ?\{))) + (message "Mismatched punctuation: `%c' in %c...%c" + (char-after) (char-after open) + (if (eq (char-after open) ?\() ?\) ?\}))) + (save-excursion + (goto-char open) + (list (list + (if (haskell-indent-hanging-p) + (haskell-indent-virtual-indentation nil) + (haskell-indent-point-to-col open)))))) + ;; There might still be layout within the open structure. + (let* ((end (point)) + (basic-indent-info + ;; Anything else than a ) is subject to layout. + (if (looking-at "\\s.\\|\\$ ") + (haskell-indent-point-to-col open) ; align a punct with ( + (let ((follow (save-excursion + (goto-char (1+ open)) + (haskell-indent-skip-blanks-and-newlines-forward end) + (point)))) + (if (= follow end) + (save-excursion + (goto-char open) + (haskell-indent-after-keyword-column nil nil 1)) + (haskell-indent-point-to-col follow))))) + (open-column (haskell-indent-point-to-col open)) + (contour-line (haskell-indent-contour-line (1+ open) end))) + (if (null contour-line) + (list (list basic-indent-info)) + (let ((indent-info + (haskell-indent-layout-indent-info + (1+ open) contour-line))) + ;; Fix up indent info. + (let ((base-elem (assoc open-column indent-info))) + (if base-elem + (progn (setcar base-elem basic-indent-info) + (setcdr base-elem nil)) + (setq indent-info + (append indent-info (list (list basic-indent-info))))) + indent-info)))))) + +(defun haskell-indent-virtual-indentation (start) + "Compute the \"virtual indentation\" of text at point. +The \"virtual indentation\" is the indentation that text at point would have +had, if it had been placed on its own line." + (let ((col (current-column)) + (haskell-indent-inhibit-after-offset (haskell-indent-hanging-p))) + (if (save-excursion (skip-chars-backward " \t") (bolp)) + ;; If the text is indeed on its own line, than the virtual indent is + ;; the current indentation. + col + ;; Else, compute the indentation that it would have had. + (let ((info (haskell-indent-indentation-info start)) + (max -1)) + ;; `info' is a list of possible indent points. Each indent point is + ;; assumed to correspond to a different parse. So we need to find + ;; the parse that corresponds to the case at hand (where there's no + ;; line break), which is assumed to always be the + ;; deepest indentation. + (dolist (x info) + (setq x (car x)) + ;; Sometimes `info' includes the current indentation (or yet + ;; deeper) by mistake, because haskell-indent-indentation-info + ;; wasn't designed to be called on a piece of text that is not at + ;; BOL. So ignore points past `col'. + (if (and (> x max) (not (>= x col))) + (setq max x))) + ;; In case all the indent points are past `col', just use `col'. + (if (>= max 0) max col))))) + +(defun haskell-indent-indentation-info (&optional start) + "Return a list of possible indentations for the current line. +These are then used by `haskell-indent-cycle'. +START if non-nil is a presumed start pos of the current definition." + (unless start (setq start (haskell-indent-start-of-def))) + (let (open contour-line) + (cond + ;; in string? + ((setq open (haskell-indent-in-string start (point))) + (list (list (+ (haskell-indent-point-to-col open) + (if (looking-at "\\\\") 0 1))))) + + ;; in comment ? + ((setq open (haskell-indent-in-comment start (point))) + (haskell-indent-comment open start)) + + ;; Closing the declaration part of a `let' or the test exp part of a case. + ((looking-at "\\(?:in\\|of\\|then\\|else\\)\\>") + (haskell-indent-closing-keyword start)) + + ;; Right after a special keyword. + ((save-excursion + (forward-comment (- (point-max))) + (when (and (not (zerop (skip-syntax-backward "w"))) + (setq open (haskell-indent-offset-after-info))) + (list (list (haskell-indent-after-keyword-column open start)))))) + + ;; open structure? ie ( { [ + ((setq open (haskell-indent-open-structure start (point))) + (haskell-indent-inside-paren open)) + + ;; full indentation + ((setq contour-line (haskell-indent-contour-line start (point))) + (haskell-indent-layout-indent-info start contour-line)) + + (t + ;; simple contour just one indentation at start + (list (list (if (and (eq haskell-literate 'bird) + (eq (haskell-indent-point-to-col start) 1)) + ;; for a Bird style literate script put default offset + ;; in the case of no indentation + (1+ haskell-indent-literate-Bird-default-offset) + (haskell-indent-point-to-col start)))))))) + +(defvar haskell-indent-last-info nil) + + +(defun haskell-indent-cycle () + "Indentation cycle. +We stay in the cycle as long as the TAB key is pressed." + (interactive "*") + (if (and haskell-literate + (not (haskell-indent-within-literate-code))) + ;; use the ordinary tab for text... + (funcall (default-value 'indent-line-function)) + (let ((marker (if (> (current-column) (haskell-indent-current-indentation)) + (point-marker))) + (bol (progn (beginning-of-line) (point)))) + (haskell-indent-back-to-indentation) + (unless (and (eq last-command this-command) + (eq bol (car haskell-indent-last-info))) + (save-excursion + (setq haskell-indent-last-info + (list bol (haskell-indent-indentation-info) 0 0)))) + + (let* ((il (nth 1 haskell-indent-last-info)) + (index (nth 2 haskell-indent-last-info)) + (last-insert-length (nth 3 haskell-indent-last-info)) + (indent-info (nth index il))) + + (haskell-indent-line-to (car indent-info)) ; insert indentation + (delete-char last-insert-length) + (setq last-insert-length 0) + (let ((text (cdr indent-info))) + (if text + (progn + (insert text) + (setq last-insert-length (length text))))) + + (setq haskell-indent-last-info + (list bol il (% (1+ index) (length il)) last-insert-length)) + + (if (= (length il) 1) + (message "Sole indentation") + (message "Indent cycle (%d)..." (length il))) + + (if marker + (goto-char (marker-position marker))))))) + +(defun haskell-indent-region (_start _end) + (error "Auto-reindentation of a region is not supported")) + +;;; alignment functions + +(defun haskell-indent-shift-columns (dest-column region-stack) + "Shift columns in REGION-STACK to go to DEST-COLUMN. +Elements of the stack are pairs of points giving the start and end +of the regions to move." + (let (reg col diffcol reg-end) + (while (setq reg (pop region-stack)) + (setq reg-end (copy-marker (cdr reg))) + (goto-char (car reg)) + (setq col (current-column)) + (setq diffcol (- dest-column col)) + (if (not (zerop diffcol)) + (catch 'end-of-buffer + (while (<= (point) (marker-position reg-end)) + (if (< diffcol 0) + (backward-delete-char-untabify (- diffcol) nil) + (insert-char ?\ diffcol)) + (end-of-line 2) ; should be (forward-line 1) + (if (eobp) ; but it adds line at the end... + (throw 'end-of-buffer nil)) + (move-to-column col))))))) + +(defun haskell-indent-align-def (p-arg type) + "Align guards or rhs within the current definition before point. +If P-ARG is t align all defs up to the mark. +TYPE is either 'guard or 'rhs." + (save-excursion + (let (start-block end-block + (maxcol (if (eq type 'rhs) haskell-indent-rhs-align-column 0)) + contour sep defname defnamepos + defcol pos lastpos + regstack eqns-start start-found) + ;; find the starting and ending boundary points for alignment + (if p-arg + (if (mark) ; aligning everything in the region + (progn + (when (> (mark) (point)) (exchange-point-and-mark)) + (setq start-block + (save-excursion + (goto-char (mark)) + (line-beginning-position))) + (setq end-block + (progn (if (haskell-indent-bolp) + (haskell-indent-forward-line -1)) + (line-end-position)))) + (error "The mark is not set for aligning definitions")) + ;; aligning the current definition + (setq start-block (haskell-indent-start-of-def)) + (setq end-block (line-end-position))) + ;; find the start of the current valdef using the contour line + ;; in reverse order because we need the nearest one from the end + (setq contour + (reverse (haskell-indent-contour-line start-block end-block))) + (setq pos (car contour)) ; keep the start of the first contour + ;; find the nearest start of a definition + (while (and (not defname) contour) + (goto-char (pop contour)) + (if (haskell-indent-open-structure start-block (point)) + nil + (setq sep (haskell-indent-separate-valdef (point) end-block)) + (if (nth 5 sep) ; is there a rhs? + (progn (setq defnamepos (nth 0 sep)) + (setq defname (nth 1 sep)))))) + ;; start building the region stack + (if defnamepos + (progn ; there is a valdef + ;; find the start of each equation or guard + (if p-arg ; when indenting a region + ;; accept any start of id or pattern as def name + (setq defname "\\<\\|(")) + (setq defcol (haskell-indent-point-to-col defnamepos)) + (goto-char pos) + (setq end-block (line-end-position)) + (catch 'top-of-buffer + (while (and (not start-found) + (>= (point) start-block)) + (if (<= (haskell-indent-current-indentation) defcol) + (progn + (move-to-column defcol) + (if (and (looking-at defname) ; start of equation + (not (haskell-indent-open-structure start-block (point)))) + (push (cons (point) 'eqn) eqns-start) + ;; found a less indented point not starting an equation + (setq start-found t))) + ;; more indented line + (haskell-indent-back-to-indentation) + (if (and (eq (haskell-indent-type-at-point) 'guard) ; start of a guard + (not (haskell-indent-open-structure start-block (point)))) + (push (cons (point) 'gd) eqns-start))) + (if (bobp) + (throw 'top-of-buffer nil) + (haskell-indent-backward-to-indentation 1)))) + ;; remove the spurious guards before the first equation + (while (and eqns-start (eq (cdar eqns-start) 'gd)) + (pop eqns-start)) + ;; go through each equation to find the region to indent + (while eqns-start + (let ((eqn (caar eqns-start))) + (setq lastpos (if (cdr eqns-start) + (save-excursion + (goto-char (cl-caadr eqns-start)) + (haskell-indent-forward-line -1) + (line-end-position)) + end-block)) + (setq sep (haskell-indent-separate-valdef eqn lastpos))) + (if (eq type 'guard) + (setq pos (nth 3 sep)) + ;; check if what follows a rhs sign is more indented or not + (let ((rhs (nth 5 sep)) + (aft-rhs (nth 6 sep))) + (if (and rhs aft-rhs + (> (haskell-indent-point-to-col rhs) + (haskell-indent-point-to-col aft-rhs))) + (setq pos aft-rhs) + (setq pos rhs)))) + (if pos + (progn ; update region stack + (push (cons pos (or lastpos pos)) regstack) + (setq maxcol ; find the highest column number + (max maxcol + (progn ;find the previous non-empty column + (goto-char pos) + (skip-chars-backward + " \t" + (line-beginning-position)) + (if (haskell-indent-bolp) + ;;if on an empty prefix + (haskell-indent-point-to-col pos) ;keep original indent + (1+ (haskell-indent-point-to-col (point))))))))) + (pop eqns-start)) + ;; now shift according to the region stack + (if regstack + (haskell-indent-shift-columns maxcol regstack))))))) + +(defun haskell-indent-align-guards-and-rhs (_start _end) + "Align the guards and rhs of functions in the region, which must be active." + ;; The `start' and `end' args are dummys right now: they're just there so + ;; we can use the "r" interactive spec which properly signals an error. + (interactive "*r") + (haskell-indent-align-def t 'guard) + (haskell-indent-align-def t 'rhs)) + +;;; insertion functions + +(defun haskell-indent-insert-equal () + "Insert an = sign and align the previous rhs of the current function." + (interactive "*") + (if (or (haskell-indent-bolp) + (/= (preceding-char) ?\ )) + (insert ?\ )) + (insert "= ") + (haskell-indent-align-def (haskell-indent-mark-active) 'rhs)) + +(defun haskell-indent-insert-guard (&optional text) + "Insert and align a guard sign (|) followed by optional TEXT. +Alignment works only if all guards are to the south-east of their |." + (interactive "*") + (let ((pc (if (haskell-indent-bolp) ?\012 + (preceding-char))) + (pc1 (or (char-after (- (point) 2)) 0))) + ;; check what guard to insert depending on the previous context + (if (= pc ?\ ) ; x = any char other than blank or | + (if (/= pc1 ?\|) + (insert "| ") ; after " x" + ()) ; after " |" + (if (= pc ?\|) + (if (= pc1 ?\|) + (insert " | ") ; after "||" + (insert " ")) ; after "x|" + (insert " | "))) ; general case + (if text (insert text)) + (haskell-indent-align-def (haskell-indent-mark-active) 'guard))) + +(defun haskell-indent-insert-otherwise () + "Insert a guard sign (|) followed by `otherwise'. +Also align the previous guards of the current function." + (interactive "*") + (haskell-indent-insert-guard "otherwise") + (haskell-indent-insert-equal)) + +(defun haskell-indent-insert-where () + "Insert a where keyword at point and indent resulting line. +One indentation cycle is used." + (interactive "*") + (insert "where ") + (haskell-indent-cycle)) + + +;;; haskell-indent-mode + +(defvar-local haskell-indent-mode nil + "Non-nil if the semi-intelligent Haskell indentation mode is in effect.") + +(defvar haskell-indent-map + (let ((map (make-sparse-keymap))) + ;; Removed: remapping DEL seems a bit naughty --SDM + ;; (define-key map "\177" 'backward-delete-char-untabify) + ;; The binding to TAB is already handled by indent-line-function. --Stef + ;; (define-key map "\t" 'haskell-indent-cycle) + (define-key map (kbd "C-c C-=") 'haskell-indent-insert-equal) + (define-key map (kbd "C-c C-|") 'haskell-indent-insert-guard) + ;; Alternate binding, in case C-c C-| is too inconvenient to type. + ;; Duh, C-g is a special key, let's not use it here. + ;; (define-key map (kbd "C-c C-g") 'haskell-indent-insert-guard) + (define-key map (kbd "C-c C-o") 'haskell-indent-insert-otherwise) + (define-key map (kbd "C-c C-w") 'haskell-indent-insert-where) + (define-key map (kbd "C-c C-.") 'haskell-indent-align-guards-and-rhs) + (define-key map (kbd "C-c C->") 'haskell-indent-put-region-in-literate) + map)) + +;;;###autoload +(defun turn-on-haskell-indent () + "Turn on ``intelligent'' Haskell indentation mode." + (when (and (bound-and-true-p haskell-indentation-mode) + (fboundp 'haskell-indentation-mode)) + (haskell-indentation-mode 0)) + + (setq-local indent-line-function 'haskell-indent-cycle) + (setq-local indent-region-function 'haskell-indent-region) + (setq haskell-indent-mode t) + ;; Activate our keymap. + (let ((map (current-local-map))) + (while (and map (not (eq map haskell-indent-map))) + (setq map (keymap-parent map))) + ;; if haskell-indent-map is already active: there's nothing to do. + (unless map + ;; Put our keymap on top of the others. We could also put it in + ;; second place, or in a minor-mode. The minor-mode approach would be + ;; easier, but it's harder for the user to override it. This approach + ;; is the closest in behavior compared to the previous code that just + ;; used a bunch of local-set-key. + (set-keymap-parent haskell-indent-map (current-local-map)) + ;; Protect our keymap. + (setq map (make-sparse-keymap)) + (set-keymap-parent map haskell-indent-map) + (use-local-map map))) + (run-hooks 'haskell-indent-hook)) + +(defun turn-off-haskell-indent () + "Turn off ``intelligent'' Haskell indentation mode." + (kill-local-variable 'indent-line-function) + (kill-local-variable 'indent-region-function) + ;; Remove haskell-indent-map from the local map. + (let ((map (current-local-map))) + (while map + (let ((parent (keymap-parent map))) + (if (eq haskell-indent-map parent) + (set-keymap-parent map (keymap-parent parent)) + (setq map parent))))) + (setq haskell-indent-mode nil)) + +;; Put this minor mode on the global minor-mode-alist. +(or (assq 'haskell-indent-mode (default-value 'minor-mode-alist)) + (setq-default minor-mode-alist + (append (default-value 'minor-mode-alist) + '((haskell-indent-mode " Ind"))))) + +;;;###autoload +(defun haskell-indent-mode (&optional arg) + "``Intelligent'' Haskell indentation mode. +This deals with the layout rule of Haskell. +\\[haskell-indent-cycle] starts the cycle which proposes new +possibilities as long as the TAB key is pressed. Any other key +or mouse click terminates the cycle and is interpreted except for +RET which merely exits the cycle. +Other special keys are: + \\[haskell-indent-insert-equal] + inserts an = + \\[haskell-indent-insert-guard] + inserts an | + \\[haskell-indent-insert-otherwise] + inserts an | otherwise = +these functions also align the guards and rhs of the current definition + \\[haskell-indent-insert-where] + inserts a where keyword + \\[haskell-indent-align-guards-and-rhs] + aligns the guards and rhs of the region + \\[haskell-indent-put-region-in-literate] + makes the region a piece of literate code in a literate script + +If `ARG' is falsey, toggle `haskell-indent-mode'. Else sets +`haskell-indent-mode' to whether `ARG' is greater than 0. + +Invokes `haskell-indent-hook' if not nil." + (interactive "P") + (setq haskell-indent-mode + (if (null arg) (not haskell-indent-mode) + (> (prefix-numeric-value arg) 0))) + (if haskell-indent-mode + (turn-on-haskell-indent) + (turn-off-haskell-indent))) + +(provide 'haskell-indent) + +;;; haskell-indent.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-indent.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-indent.elc new file mode 100644 index 000000000000..a22b1be2641d --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-indent.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-indentation.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-indentation.el new file mode 100644 index 000000000000..0ab735ff2ad3 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-indentation.el @@ -0,0 +1,1255 @@ +;;; haskell-indentation.el --- indentation module for Haskell Mode -*- lexical-binding: t -*- + +;; Copyright (C) 2013 Kristof Bastiaensen, Gergely Risko + +;; Author: Kristof Bastiaensen <kristof.bastiaensen@vleeuwen.org> +;; Author: Gergely Risko <errge@nilcons.com> +;; Keywords: indentation haskell +;; URL: https://github.com/haskell/haskell-mode + +;; This file is not part of GNU Emacs. + +;; 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Installation: +;; +;; To turn indentation on for all Haskell buffers under Haskell mode add +;; this to your configuration file: +;; +;; (add-hook haskell-mode-hook 'haskell-indentation-mode) +;; +;; Otherwise, call `haskell-indentation-mode'. + +;;; Code: + +;; TODO eliminate magic number 2 where possible, use a variable + +;; TODO `haskell-indentation-find-indentation' — fix it, get rid of "safe" +;; version + +(require 'cl-lib) +(require 'haskell-lexeme) + +;;;###autoload +(defgroup haskell-indentation nil + "Haskell indentation." + :link '(custom-manual "(haskell-mode)Indentation") + :group 'haskell + :prefix "haskell-indentation-") + +(defcustom haskell-indentation-layout-offset 2 + "Extra indentation to add before expressions in a Haskell layout list." + :type 'integer + :group 'haskell-indentation) + +(defcustom haskell-indentation-starter-offset 2 + "Extra indentation after an opening keyword (e.g. \"let\")." + :type 'integer + :group 'haskell-indentation) + +(defcustom haskell-indentation-left-offset 2 + "Extra indentation after an indentation to the left (e.g. after \"do\")." + :type 'integer + :group 'haskell-indentation) + +(defcustom haskell-indentation-where-pre-offset 2 + "Extra indentation before the keyword \"where\"." + :type 'integer + :group 'haskell-indentation) + +(defcustom haskell-indentation-where-post-offset 2 + "Extra indentation after the keyword \"where\"." + :type 'integer + :group 'haskell-indentation) + +(defcustom haskell-indentation-electric-flag nil + "Non-nil means insertion of some characters may auto reindent the line. +If the variable `electric-indent-mode' is non-nil then this variable is +overridden." + :type 'symbol + :group 'haskell-indentation) +(make-variable-buffer-local 'haskell-indentation-electric-flag) + +(defvar haskell-indentation-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "RET") #'haskell-indentation-newline-and-indent) + (define-key map (kbd "<backtab>") #'haskell-indentation-indent-backwards) + (define-key map (kbd ",") #'haskell-indentation-common-electric-command) + (define-key map (kbd ";") #'haskell-indentation-common-electric-command) + (define-key map (kbd ")") #'haskell-indentation-common-electric-command) + (define-key map (kbd "}") #'haskell-indentation-common-electric-command) + (define-key map (kbd "]") #'haskell-indentation-common-electric-command) + map) + "Keymap for `haskell-indentation-mode'.") + +;;;###autoload +(define-minor-mode haskell-indentation-mode + "Haskell indentation mode that deals with the layout rule. +It rebinds RET, DEL and BACKSPACE, so that indentations can be +set and deleted as if they were real tabs." + :keymap haskell-indentation-mode-map + (kill-local-variable 'indent-line-function) + (kill-local-variable 'indent-region-function) + + (when haskell-indentation-mode + (when (and (bound-and-true-p haskell-indent-mode) + (fboundp 'turn-off-haskell-indent)) + (turn-off-haskell-indent)) + (setq-local indent-line-function #'haskell-indentation-indent-line) + (setq-local indent-region-function #'haskell-indentation-indent-region))) + +;;;###autoload +(defun turn-on-haskell-indentation () + "Turn on the haskell-indentation minor mode." + (interactive) + (haskell-indentation-mode t)) + +(make-obsolete 'turn-on-haskell-indentation + 'haskell-indentation-mode + "2015-05-25") + +(defvar haskell-literate) ; defined in haskell-mode.el + +(defun haskell-indentation-bird-p () + "Return t if this is a literate Haskell buffer in bird style, NIL otherwise." + (eq haskell-literate 'bird)) + +;;---------------------------------------------------------------------------- +;; UI starts here + +(defun haskell-indentation-reindent-to (col &optional move) + "Reindent current line to COL, move the point there if MOVE is non-NIL." + (let* ((ci (haskell-indentation-current-indentation))) + (save-excursion + (move-to-column ci) + (if (<= ci col) + (insert-before-markers (make-string (- col ci) ? )) + (delete-char (- col ci)))) + (when move + (move-to-column col)))) + +(defun haskell-indentation-indent-rigidly (start end arg) + "Indent all lines starting in the region sideways by ARG columns. +Called from a program, takes three arguments, START, END and ARG. +You can remove all indentation from a region by giving a large +negative ARG. Handles bird style literate Haskell too." + (interactive "*r\np") + (save-excursion + (goto-char end) + (let ((end-marker (point-marker))) + (goto-char start) + (or (bolp) (forward-line 0)) + (while (< (point) end-marker) + (let ((ci (haskell-indentation-current-indentation))) + (when (and t + (eq (char-after) ?>)) + (forward-char 1)) + (skip-syntax-forward "-") + (unless (eolp) + (haskell-indentation-reindent-to (max 0 (+ ci arg)))) + (forward-line 1))) + (move-marker end-marker nil)))) + +(defun haskell-indentation-current-indentation () + "Column position of first non-whitespace character in current line." + (save-excursion + (beginning-of-line) + (when (haskell-indentation-bird-p) + (forward-char)) + (skip-syntax-forward "-") + (current-column))) + +(defun haskell-indentation-bird-outside-code-p () + "Non-NIL if we are in bird literate mode, but outside of code." + (and (haskell-indentation-bird-p) + (or (< (current-column) 2) + (save-excursion + (beginning-of-line) + (not (eq (char-after) ?>)))))) + +(defun haskell-indentation-newline-and-indent () + "Insert newline and indent." + (interactive "*") + ;; On RET (or C-j), we: + ;; - just jump to the next line if literate haskell, but outside code + (if (haskell-indentation-bird-outside-code-p) + (progn + (delete-horizontal-space) + (newline)) + ;; - save the current column + (let ((ci (haskell-indentation-current-indentation))) + ;; - jump to the next line and reindent to at the least same level + (delete-horizontal-space) + (newline) + ;; calculate indentation after newline is inserted because if we + ;; break an identifier we might create a keyword, for example + ;; "dowhere" => "do where" + (let ((indentations (or (haskell-indentation-find-indentations) + '(0)))) + (when (haskell-indentation-bird-p) + (insert "> ")) + (haskell-indentation-reindent-to + (haskell-indentation-next-indentation (- ci 1) indentations 'nofail) + 'move))))) + +(defun haskell-indentation-next-indentation (col indentations &optional nofail) + "Find the leftmost indentation which is greater than COL. +Indentations are taken from INDENTATIONS, which should be a +list. Return the last indentation if there are no bigger ones and +NOFAIL is non-NIL." + (when (null indentations) + (error "haskell-indentation-next-indentation called with empty list")) + (or (cl-find-if (lambda (i) (> i col)) indentations) + (when nofail + (car (last indentations))))) + +(defun haskell-indentation-previous-indentation (col indentations &optional nofail) + "Find the rightmost indentation less than COL from INDENTATIONS. +When no indentations are less than COL, return the rightmost indentation +if NOFAIL is non-nil, or nil otherwise." + (when (null indentations) + (error "haskell-indentation-previous-indentation called with empty list")) + (let ((rev (reverse indentations))) + (or (cl-find-if (lambda (i) (< i col)) rev) + (when nofail + (car rev))))) + +(defvar haskell-indentation-dyn-last-direction nil + "") ; FIXME +(defvar haskell-indentation-dyn-last-indentations nil + "") ; FIXME + +(defun haskell-indentation-indent-line () + "Indent current line, cycle though indentation positions. +Do nothing inside multiline comments and multiline strings. +Start enumerating the indentation points to the right. The user +can continue by repeatedly pressing TAB. When there is no more +indentation points to the right, we switch going to the left." + (interactive "*") + ;; try to repeat + (when (not (haskell-indentation-indent-line-repeat)) + (setq haskell-indentation-dyn-last-direction nil) + ;; parse error is intentionally not cought here, it may come from + ;; `haskell-indentation-find-indentations', but escapes the scope + ;; and aborts the opertaion before any moving happens + (let* ((cc (current-column)) + (ci (haskell-indentation-current-indentation)) + (inds (save-excursion + (move-to-column ci) + (or (haskell-indentation-find-indentations) + '(0)))) + (valid (memq ci inds)) + (cursor-in-whitespace (< cc ci))) + + (if (and valid cursor-in-whitespace) + (move-to-column ci) + (haskell-indentation-reindent-to + (haskell-indentation-next-indentation ci inds 'nofail) + cursor-in-whitespace)) + (setq haskell-indentation-dyn-last-direction 'right + haskell-indentation-dyn-last-indentations inds)))) + +(defun haskell-indentation-indent-line-repeat () + "Cycle though indentation positions." + (cond + ((and (memq last-command + '(indent-for-tab-command + haskell-indentation-indent-backwards)) + (eq haskell-indentation-dyn-last-direction 'region)) + (let ((mark-even-if-inactive t)) + (haskell-indentation-indent-rigidly + (region-beginning) + (region-end) + 1)) + t) + ((and (eq last-command 'indent-for-tab-command) + (memq haskell-indentation-dyn-last-direction '(left right)) + haskell-indentation-dyn-last-indentations) + (let ((ci (haskell-indentation-current-indentation))) + (if (eq haskell-indentation-dyn-last-direction 'left) + (haskell-indentation-reindent-to + (haskell-indentation-previous-indentation + ci haskell-indentation-dyn-last-indentations 'nofail)) + ;; right + (if (haskell-indentation-next-indentation + ci haskell-indentation-dyn-last-indentations) + (haskell-indentation-reindent-to + (haskell-indentation-next-indentation + ci haskell-indentation-dyn-last-indentations 'nofail)) + ;; but failed, switch to left + (setq haskell-indentation-dyn-last-direction 'left) + (haskell-indentation-indent-line-repeat))) + t)) + (t nil))) + +(defun haskell-indentation-indent-region (_start _end) + "This function does nothing. + +It is better to do nothing to indent region in Haskell than to +break the semantics of indentation. This function is used for +`indent-region-function' because the default is to call +`indent-line-function' on every line from START to END and that +also produces catastrophic results. + +Someday we will have indent region that preserves semantics and +fixes up only indentation." + nil) + +(defun haskell-indentation-indent-backwards () + "Indent the current line to the previous indentation point." + (interactive "*") + (cond + ((and (memq last-command + '(indent-for-tab-command haskell-indentation-indent-backwards)) + (eq haskell-indentation-dyn-last-direction 'region)) + (let ((mark-even-if-inactive t)) + (haskell-indentation-indent-rigidly (region-beginning) (region-end) -1))) + ((use-region-p) + (setq haskell-indentation-dyn-last-direction 'region) + (haskell-indentation-indent-rigidly (region-beginning) (region-end) -1) + (message "Press TAB or S-TAB again to indent the region more")) + (t + (setq haskell-indentation-dyn-last-direction nil) + (let* ((cc (current-column)) + (ci (haskell-indentation-current-indentation)) + (inds (save-excursion + (move-to-column ci) + (or (haskell-indentation-find-indentations) + '(0)))) + (cursor-in-whitespace (< cc ci)) + (pi (haskell-indentation-previous-indentation ci inds))) + (if (null pi) + ;; if there are no more indentations to the left, just go to column 0 + (haskell-indentation-reindent-to + (car (haskell-indentation-first-indentation)) cursor-in-whitespace) + (haskell-indentation-reindent-to pi cursor-in-whitespace)))))) + +(defun haskell-indentation-common-electric-command (arg) + "Call `self-insert-command' to insert the character typed ARG times +and indent when all of the following are true: +1) The character is the first non-whitespace character on the line. +2) There is only one possible indentation position. +3) The variable `electric-indent-mode' or `haskell-indentation-electric-flag' + is non-nil. +4) The point is not in a comment, string, or quasiquote." + (interactive "*p") + (let ((col (current-column)) + ind) + (self-insert-command arg) + (when (and (or haskell-indentation-electric-flag + electric-indent-mode) + (= (haskell-indentation-current-indentation) + col) + (> arg 0) + (not (nth 8 (syntax-ppss))) + (= 1 (save-excursion + (move-to-column col) + (length (setq ind (haskell-indentation-find-indentations)))))) + (haskell-indentation-reindent-to (car ind))))) + + +;;---------------------------------------------------------------------------- +;; Parser Starts Here + +;; The parser is implemented as a recursive descent parser. Each parser +;; advances the point to after the expression it parses, and sets the +;; dynamic scoped variables containing the information about the +;; indentations. The dynamic scoping allows transparent backtracking to +;; previous states of these variables. A new state can be set using `let'. +;; When the scope of this function ends, the variable is automatically +;; reverted to its old value. + +;; This is basicly a performance hack. It would have been possible to +;; thread this state using a association-list through the parsers, but it +;; would be probably more complicated and slower due to the lack of real +;; closures in Emacs Lisp. +;; +;; When finished parsing, the tokenizer returns 'end-token, and +;; following-token is set to the token after point. The parser adds its +;; indentations to possible-indentations and returns to it's parent, or +;; exits non-locally by throwing parse-end, so that the parent will not add +;; new indentations to it. + +;; the parse state: +(defvar following-token) ;; the next token after parsing finished +;; the token at the current parser point or a pseudo-token (see +;; `haskell-indentation-read-next-token') +(defvar current-token) +(defvar previous-token) +(defvar left-indent) ;; most left possible indentation +(defvar starter-indent) ;; column at a keyword +(defvar current-indent) ;; the most right indentation +(defvar layout-indent) ;; the column of the layout list +(defvar possible-indentations) ;; the return value of the indentations +(defvar indentation-point) ;; where to stop parsing +(defvar implicit-layout-active) ;; is "off-side" rule active? + +(defun haskell-indentation-goto-least-indentation () + "" ; FIXME + (beginning-of-line) + (if (haskell-indentation-bird-p) + (catch 'return + (while t + (when (not (eq (char-after) ?>)) + (forward-line) + (forward-char 2) + (throw 'return nil)) + (let ((ps (nth 8 (syntax-ppss)))) + (when ps ;; inside comment or string + (goto-char ps) + (beginning-of-line))) + (when (and (>= 2 (haskell-indentation-current-indentation)) + (not (looking-at ">\\s-*$"))) + (forward-char 2) + (throw 'return nil)) + (when (bobp) + (forward-char 2) + (throw 'return nil)) + (forward-line -1))) + ;; not bird style + (catch 'return + (while (not (bobp)) + (let ((point (point))) + ;; (forward-comment -1) gets lost if there are unterminated + ;; string constants and does not move point anywhere. We fix + ;; that case with (forward-line -1) + (forward-comment (- (buffer-size))) + (if (equal (point) point) + (forward-line -1) + (beginning-of-line))) + (let* ((ps (syntax-ppss)) + (start-of-comment-or-string (nth 8 ps)) + (start-of-list-expression (nth 1 ps))) + (cond + (start-of-comment-or-string + ;; inside comment or string + (goto-char start-of-comment-or-string)) + (start-of-list-expression + ;; inside a parenthesized expression + (goto-char start-of-list-expression)) + ((= 0 (haskell-indentation-current-indentation)) + (throw 'return nil)))))) + (beginning-of-line) + (when (bobp) + (forward-comment (buffer-size))))) + +(defun haskell-indentation-parse-to-indentations () + "" ; FIXME + (save-excursion + (skip-syntax-forward "-") + (let ((indentation-point (point)) + (layout-indent 0) + (current-indent haskell-indentation-layout-offset) + (starter-indent haskell-indentation-layout-offset) + (left-indent haskell-indentation-layout-offset) + (case-fold-search nil) + current-token + previous-token + following-token + possible-indentations + implicit-layout-active) + (haskell-indentation-goto-least-indentation) + (if (<= indentation-point (point)) + (haskell-indentation-first-indentation) + (setq current-token (haskell-indentation-peek-token)) + (catch 'parse-end + (haskell-indentation-toplevel)) + possible-indentations)))) + +(defun haskell-indentation-first-indentation () + "Return column of first indentation." + (list (if (haskell-indentation-bird-p) 2 0))) + +(defun haskell-indentation-find-indentations () + "Return list of indentation positions corresponding to actual cursor position." + (let ((ppss (syntax-ppss))) + (cond + ((nth 3 ppss) + (if (save-excursion + (and (forward-line -1) + (< (nth 8 ppss) (point)))) + ;; if this string goes over more than one line we want to + ;; sync with the last line, not the first one + (list (save-excursion + (forward-line -1) + (current-indentation))) + + (append + (haskell-indentation-first-indentation) + (list (save-excursion + (goto-char (nth 8 ppss)) + (current-column)))))) + ((nth 4 ppss) + (if (save-excursion + (and (skip-syntax-forward "-") + (eolp) + (not (> (forward-line 1) 0)) + (not (nth 4 (syntax-ppss))))) + (haskell-indentation-parse-to-indentations) + (haskell-indentation-first-indentation))) + (t + (haskell-indentation-parse-to-indentations))))) + +(defconst haskell-indentation-unicode-tokens + '(("→" . "->") ;; #x2192 RIGHTWARDS ARROW + ("∷" . "::") ;; #x2237 PROPORTION + ("←" . "<-") ;; #x2190 LEFTWARDS ARROW + ("⇒" . "=>") ;; #x21D2 RIGHTWARDS DOUBLE ARROW + ("∀" . "forall") ;; #x2200 FOR ALL + ("⤙" . "-<") ;; #x2919 LEFTWARDS ARROW-TAIL + ("⤚" . ">-") ;; #x291A RIGHTWARDS ARROW-TAIL + ("⤛" . "-<<") ;; #x291B LEFTWARDS DOUBLE ARROW-TAIL + ("⤜" . ">>-") ;; #x291C RIGHTWARDS DOUBLE ARROW-TAIL + ("★" . "*")) ;; #x2605 BLACK STAR + "Translation from UnicodeSyntax tokens to their ASCII representation.") + +(defconst haskell-indentation-toplevel-list + `(("module" . haskell-indentation-module) + ("signature" . haskell-indentation-module) + ("data" . haskell-indentation-data) + ("type" . haskell-indentation-data) + ("newtype" . haskell-indentation-data) + ("import" . haskell-indentation-import) + ("foreign" . haskell-indentation-foreign) + ("where" . haskell-indentation-toplevel-where) + ("class" . haskell-indentation-class-declaration) + ("instance" . haskell-indentation-class-declaration) + ("deriving" . haskell-indentation-deriving)) + "Alist of toplevel keywords with associated parsers.") + +(defconst haskell-indentation-type-list + `(("::" . + ,(apply-partially 'haskell-indentation-with-starter + (apply-partially 'haskell-indentation-separated + 'haskell-indentation-type '("->" "=>")))) + ("(" . + ,(apply-partially 'haskell-indentation-list + 'haskell-indentation-type ")" ",")) + ("[" . + ,(apply-partially 'haskell-indentation-list + 'haskell-indentation-type "]" ",")) + ("{" . + ,(apply-partially 'haskell-indentation-list + 'haskell-indentation-type "}" ","))) + "Alist of tokens in type declarations with associated parsers.") + +(defconst haskell-indentation-expression-list + `(("data" . haskell-indentation-data) + ("type" . haskell-indentation-data) + ("newtype" . haskell-indentation-data) + ("if" . haskell-indentation-if) + ("let" . + ,(apply-partially 'haskell-indentation-phrase + '(haskell-indentation-declaration-layout + "in" haskell-indentation-expression))) + ("do" . + ,(apply-partially 'haskell-indentation-with-starter + 'haskell-indentation-expression-layout)) + ("mdo" . + ,(apply-partially 'haskell-indentation-with-starter + 'haskell-indentation-expression-layout)) + ("rec" . + ,(apply-partially 'haskell-indentation-with-starter + 'haskell-indentation-expression-layout)) + ("case" . + ,(apply-partially 'haskell-indentation-phrase + '(haskell-indentation-expression + "of" haskell-indentation-case-layout))) + ("\\" . + ,(apply-partially 'haskell-indentation-with-starter + 'haskell-indentation-lambda-maybe-lambdacase)) + ("proc" . + ,(apply-partially 'haskell-indentation-phrase + '(haskell-indentation-expression + "->" haskell-indentation-expression))) + ("where" . + ,(apply-partially 'haskell-indentation-with-starter + 'haskell-indentation-declaration-layout nil t)) + ("::" . haskell-indentation-scoped-type) + ("=" . + ,(apply-partially 'haskell-indentation-statement-right + 'haskell-indentation-expression)) + ("<-" . + ,(apply-partially 'haskell-indentation-statement-right + 'haskell-indentation-expression)) + ("(" . + ,(apply-partially 'haskell-indentation-list + 'haskell-indentation-expression + ")" + '(list "," "->"))) + ("[" . + ,(apply-partially 'haskell-indentation-list + 'haskell-indentation-expression "]" "," "|")) + ("{" . + ,(apply-partially 'haskell-indentation-list + 'haskell-indentation-expression "}" ","))) + "Alist of keywords in expressions with associated parsers.") + +(defun haskell-indentation-expression-layout () + "Parse layout list with expressions, such as after \"do\"." + (haskell-indentation-layout #'haskell-indentation-expression)) + +(defun haskell-indentation-declaration-layout () + "Parse layout list with declarations, such as after \"where\"." + (haskell-indentation-layout #'haskell-indentation-declaration)) + +(defun haskell-indentation-case-layout () + "Parse layout list with case expressions." + (haskell-indentation-layout #'haskell-indentation-case)) + +(defun haskell-indentation-lambda-maybe-lambdacase () + "Parse lambda or lambda-case expression. +After a lambda (backslash) there are two possible cases: + +- the new lambdacase expression, that can be recognized by the + next token being \"case\"; + +- or simply an anonymous function definition in the form of + \"expression -> expression\"." + (if (string= current-token "case") + (haskell-indentation-with-starter + #'haskell-indentation-case-layout) + (haskell-indentation-phrase-rest + '(haskell-indentation-expression "->" haskell-indentation-expression)))) + +(defun haskell-indentation-fundep () + "Parse functional dependency." + (haskell-indentation-with-starter + (apply-partially #'haskell-indentation-separated + #'haskell-indentation-fundep1 ","))) + +(defun haskell-indentation-fundep1 () + "Parse an item in functional dependency declaration." + (let ((current-indent (current-column))) + (while (member current-token '(value "->")) + (haskell-indentation-read-next-token)) + (when (and (eq current-token 'end-tokens) + (member following-token '(value "->"))) + (haskell-indentation-add-indentation current-indent)))) + +(defun haskell-indentation-toplevel () + "Parse toplevel statements." + (haskell-indentation-layout + (lambda () + (let ((parser (assoc current-token haskell-indentation-toplevel-list))) + (if parser + (funcall (cdr parser)) + (haskell-indentation-declaration)))))) + +(defun haskell-indentation-type () + "Parse type declaration." + (let ((current-indent (current-column))) + (catch 'return + (while t + (cond + ((member current-token '(value operator "->" "=>")) + (haskell-indentation-read-next-token)) + + ((eq current-token 'end-tokens) + (when (member following-token + '(value operator no-following-token + "(" "[" "{" "::")) + (if (equal following-token "=>") + (haskell-indentation-add-indentation starter-indent) + (haskell-indentation-add-indentation current-indent)) + (haskell-indentation-add-indentation left-indent)) + (throw 'return nil)) + (t (let ((parser (assoc current-token haskell-indentation-type-list))) + (if (not parser) + (throw 'return nil) + (funcall (cdr parser)))))))))) + +(defun haskell-indentation-type-1 () + "Parse a single type declaration." + (let ((current-indent (current-column))) + (catch 'return + (cond + ((member current-token '(value operator "->" "=>")) + (haskell-indentation-read-next-token)) + + ((eq current-token 'end-tokens) + (when (member following-token + '(value operator no-following-token + "->" "=>" "(" "[" "{" "::")) + (haskell-indentation-add-indentation current-indent)) + (throw 'return nil)) + (t (let ((parser (assoc current-token haskell-indentation-type-list))) + (if (not parser) + (throw 'return nil) + (funcall (cdr parser))))))))) + +(defun haskell-indentation-scoped-type () + "Parse scoped type declaration. + +For example + let x :: Int = 12 + do x :: Int <- return 12" + (haskell-indentation-with-starter + (apply-partially #'haskell-indentation-separated #'haskell-indentation-type '("->" "=>"))) + (when (member current-token '("<-" "=")) + (haskell-indentation-statement-right #'haskell-indentation-expression))) + +(defun haskell-indentation-data () + "Parse data or type declaration." + (haskell-indentation-read-next-token) + (when (string= current-token "instance") + (haskell-indentation-read-next-token)) + (haskell-indentation-type) + (cond ((eq current-token 'end-tokens) + (when (member following-token '("=" "where")) + (haskell-indentation-add-indentation current-indent) + (throw 'parse-end nil))) + ((string= current-token "=") + (let ((starter-indent-inside (current-column))) + (haskell-indentation-with-starter + (lambda () + (haskell-indentation-separated + #'haskell-indentation-expression "|"))) + (cond + ((equal current-token 'end-tokens) + (when (string= following-token "deriving") + (haskell-indentation-push-indentation starter-indent-inside) + (haskell-indentation-add-left-indent))) + ((equal current-token "deriving") + (haskell-indentation-with-starter + #'haskell-indentation-type-1))))) + ((string= current-token "where") + (haskell-indentation-with-starter + #'haskell-indentation-expression-layout nil) + (cond + ((equal current-token 'end-tokens) + (when (string= following-token "deriving") + (haskell-indentation-add-left-indent))) + ((equal current-token "deriving") + (haskell-indentation-with-starter + #'haskell-indentation-type-1)))))) + +(defun haskell-indentation-import () + "Parse import declaration." + (haskell-indentation-with-starter #'haskell-indentation-expression)) + +(defun haskell-indentation-foreign () + "Parse foreign import declaration." + (haskell-indentation-with-starter (apply-partially #'haskell-indentation-expression '(value operator "import")))) + +(defun haskell-indentation-class-declaration () + "Parse class declaration." + (haskell-indentation-with-starter + (lambda () + (haskell-indentation-type) + (when (string= current-token "|") + (haskell-indentation-fundep)) + (when (string= current-token "where") + (haskell-indentation-with-starter + #'haskell-indentation-declaration-layout nil))))) + +(defun haskell-indentation-deriving () + "Parse standalone declaration." + (haskell-indentation-with-starter + (lambda () + (when (string= "instance" current-token) + (haskell-indentation-read-next-token)) + (when (equal current-token 'end-tokens) + (haskell-indentation-add-left-indent) + (throw 'parse-end nil)) + (haskell-indentation-type) + (when (string= current-token "|") + (haskell-indentation-fundep))))) + +(defun haskell-indentation-module () + "Parse module declaration." + (haskell-indentation-with-starter + (lambda () + (haskell-indentation-read-next-token) + (when (equal current-token 'layout-item) + (haskell-indentation-read-next-token)) + (when (string= current-token "(") + (haskell-indentation-list + #'haskell-indentation-module-export + ")" ",")) + (if (string= current-token "where") + (haskell-indentation-read-next-token) + + (when (eq current-token 'end-tokens) + (when (member following-token '(value no-following-token "(")) + (haskell-indentation-add-indentation + (+ starter-indent haskell-indentation-starter-offset)) + (haskell-indentation-add-indentation + (+ left-indent haskell-indentation-starter-offset)) + (throw 'parse-end nil)) + (haskell-indentation-add-layout-indent) + (throw 'parse-end nil)))))) + +(defun haskell-indentation-toplevel-where () + "Parse 'where' that we may hit as a standalone in module declaration." + (haskell-indentation-read-next-token) + + (when (eq current-token 'end-tokens) + (haskell-indentation-add-layout-indent) + (throw 'parse-end nil))) + +(defun haskell-indentation-module-export () + "Parse export list." + (cond ((string= current-token "module") + (let ((current-indent (current-column))) + (haskell-indentation-read-next-token) + (cond ((eq current-token 'end-tokens) + (haskell-indentation-add-indentation current-indent)) + ((eq current-token 'value) + (haskell-indentation-read-next-token))))) + (t (haskell-indentation-type)))) + +(defun haskell-indentation-list (parser end sep &optional stmt-sep) + "Parse a list, pair or other expression containing multiple +items parsed by PARSER, separated by SEP or STMT-SEP, and ending +with END." + ;; note that we use macro expansion here to preserver Emacs 23 + ;; compatibility and its lack of lexical binding + (haskell-indentation-with-starter + `(lambda () + (let ((implicit-layout-active nil)) + (haskell-indentation-separated + #',parser ,sep ,stmt-sep))) + end)) + +(defun haskell-indentation-with-starter (parser &optional end where-expr?) + "Parse an expression starting with a keyword or parenthesis. +Skip the keyword or parenthesis." ; FIXME: better description needed + (let ((starter-column (current-column)) + (current-indent current-indent) + (left-indent + (if (= (current-column) (haskell-indentation-current-indentation)) + (current-column) + left-indent))) + (haskell-indentation-read-next-token) + (when (eq current-token 'end-tokens) + (cond ((equal following-token end) + ;; indent before keyword or parenthesis + (haskell-indentation-add-indentation starter-column)) + (where-expr? + ;; left indent + where post indent + (haskell-indentation-add-where-post-indent left-indent)) + (t + (haskell-indentation-add-left-indent))) + (throw 'parse-end nil)) + (let* ((current-indent (current-column)) + (starter-indent (min starter-column current-indent)) + (left-indent + (if end + (+ starter-indent haskell-indentation-starter-offset) + left-indent))) + (funcall parser) + (cond ((eq current-token 'end-tokens) + (when (equal following-token end) + ;; indent before keyword or parenthesis + (haskell-indentation-add-indentation starter-indent)) + ;; add no more indentations if we expect a closing keyword + (when end + (throw 'parse-end nil))) + ((equal current-token end) + (haskell-indentation-read-next-token)))))) + +(defun haskell-indentation-case-alternative () + "" ; FIXME + (setq left-indent (current-column)) + (haskell-indentation-separated #'haskell-indentation-expression "," nil) + (cond ((eq current-token 'end-tokens) + (haskell-indentation-add-indentation current-indent)) + ((string= current-token "->") + (haskell-indentation-statement-right #'haskell-indentation-expression)) + ;; otherwise fallthrough + )) + +(defun haskell-indentation-case () + "" ; FIXME + (haskell-indentation-expression) + (cond ((eq current-token 'end-tokens) + (haskell-indentation-add-indentation current-indent)) + ((string= current-token "|") + (haskell-indentation-with-starter + (apply-partially #'haskell-indentation-separated + #'haskell-indentation-case-alternative "|" nil) + nil)) + ((string= current-token "->") + (haskell-indentation-statement-right #'haskell-indentation-expression)) + ;; otherwise fallthrough + )) + +(defun haskell-indentation-statement-right (parser) + "Process right side of a statement. +Set `current-indent' to the current column and calls the given +parser. If parsing ends here, set indentation to left-indent." + (haskell-indentation-read-next-token) + (when (eq current-token 'end-tokens) + (haskell-indentation-add-left-indent) + (haskell-indentation-add-indentation current-indent) + (throw 'parse-end nil)) + (funcall parser) + (when (equal current-token "where") + (haskell-indentation-with-starter + #'haskell-indentation-expression-layout nil))) + +(defun haskell-indentation-guard () + "Parse \"guard\" statement." + (setq left-indent (current-column)) + (haskell-indentation-separated + #'haskell-indentation-expression "," nil)) + +(defun haskell-indentation-declaration () + "Parse function or type declaration." + (haskell-indentation-separated #'haskell-indentation-expression "," nil) + (when (string= current-token "|") + (haskell-indentation-with-starter + (apply-partially #'haskell-indentation-separated + #'haskell-indentation-guard "|" nil) + nil)) + (when (eq current-token 'end-tokens) + (when (member following-token '("|" "=" "::" ",")) + (haskell-indentation-add-indentation current-indent) + (throw 'parse-end nil)))) + +(defun haskell-indentation-layout (parser) + "Parse layout list, where each layout item is parsed by parser." + (if (string= current-token "{") + (haskell-indentation-list parser "}" ";") ; explicit layout + (haskell-indentation-implicit-layout-list parser))) + +(defun haskell-indentation-expression-token-p (token) + "Return non-NIL value if TOKEN is an expression token." + (member token + '("if" "let" "do" "case" "\\" "(" "{" "[" "::" + value operator no-following-token))) + +(defun haskell-indentation-expression (&optional accepted-tokens) + "Parse an expression until an unknown token is encountered." + (catch 'return + (let ((current-indent (current-column))) + (unless accepted-tokens + (setq accepted-tokens '(value operator))) + (while t + (cond + ((memq current-token accepted-tokens) + (haskell-indentation-read-next-token)) + ((eq current-token 'end-tokens) + (cond ((string= following-token "where") + (haskell-indentation-add-where-pre-indent)) ; before a where + ((haskell-indentation-expression-token-p following-token) + ;; a normal expression can be either continued or have + ;; left indent + (haskell-indentation-add-indentation + current-indent) + (haskell-indentation-add-indentation + left-indent))) + (throw 'return nil)) + (t (let ((parser (assoc current-token + haskell-indentation-expression-list))) + (when (null parser) + (throw 'return nil)) ; not expression token, so exit + (funcall (cdr parser)) ; run parser + + ;; after an 'open' expression such as 'if', exit + (unless (member (car parser) '("(" "[" "{" "case")) + (throw 'return nil))))))))) + +(defun haskell-indentation-separated (parser separator &optional stmt-separator) + "Evaluate PARSER separated by SEPARATOR and STMT-SEPARATOR. +If STMT-SEPARATOR is not NIL, it will be used to set a new starter-indent. + +For example: + + [ i | i <- [1..10] + ," + (catch 'return + (unless (listp separator) + (setq separator (list separator))) + (unless (listp stmt-separator) + (setq stmt-separator (list stmt-separator))) + (while t + (funcall parser) + (cond ((member current-token separator) + (haskell-indentation-at-separator)) + + ((member current-token stmt-separator) + (setq starter-indent (current-column)) + (haskell-indentation-at-separator)) + + ((eq current-token 'end-tokens) + (when (or (member following-token separator) + (member following-token stmt-separator)) + ;; Set an indentation before a separator, for example: + ;; [ 1 or [ 1 | a + ;; , 2 , 20 + (haskell-indentation-add-indentation starter-indent) + (when (< left-indent starter-indent) + (haskell-indentation-add-indentation left-indent)) + (throw 'parse-end nil)) + (when (equal following-token 'no-following-token) + ;; Set an indentation before a separator, for example: + ;; [ 1 or [ 1 | a + ;; , 2 , 20 + (haskell-indentation-add-indentation starter-indent) + (haskell-indentation-add-indentation left-indent)) + (throw 'return nil)) + (t (throw 'return nil)))))) + +(defun haskell-indentation-at-separator () + "At a separator. + +If at a new line, set starter-indent at the separator +and current-indent after the separator, for example: + +l = [ 1 + , 2 + , -- start now here." + (let ((separator-column + (and (= (current-column) (haskell-indentation-current-indentation)) + (current-column)))) + (haskell-indentation-read-next-token) + (cond ((eq current-token 'end-tokens) + (haskell-indentation-add-indentation current-indent) + (haskell-indentation-add-indentation left-indent) + (throw 'return nil)) + (separator-column ; on the beginning of the line + (setq current-indent (current-column)) + (setq starter-indent separator-column) + (setq left-indent + (+ starter-indent haskell-indentation-starter-offset)))))) + +(defun haskell-indentation-implicit-layout-list (parser) + "An implicit layout list, elements are parsed with PARSER. +This sets the `layout-indent' variable to the column where the +layout starts." + (let* ((layout-indent (current-column)) + (current-indent (current-column)) + (left-indent (current-column)) + (implicit-layout-active t)) + (catch 'return + (while t + (let ((left-indent left-indent)) + (funcall parser)) + (cond ((member current-token '(layout-item ";")) + (haskell-indentation-read-next-token)) + ((eq current-token 'end-tokens) + (when (or (and + (not (member following-token '("{" operator))) + (not (member previous-token '(operator))) + (haskell-indentation-expression-token-p following-token)) + (string= following-token ";") + (and (equal layout-indent 0) + (member following-token (mapcar #'car haskell-indentation-toplevel-list)) + (not (string= following-token "where")))) + (haskell-indentation-add-layout-indent)) + (throw 'return nil)) + (t (throw 'return nil)))))) + ;; put `haskell-indentation-read-next-token' outside the current-indent + ;; definition so it will not return 'layout-end again + (when (eq current-token 'layout-end) + (let ((implicit-layout-active t)) + ;; leave layout at 'layout-end or illegal token + (haskell-indentation-read-next-token)))) + +(defun haskell-indentation-if () + "" ; FIXME + (haskell-indentation-with-starter + (lambda () + (if (string= current-token "|") + (haskell-indentation-with-starter + (lambda () + (haskell-indentation-separated + #'haskell-indentation-case-alternative "|" nil)) + nil) + (haskell-indentation-phrase-rest + '(haskell-indentation-expression + "then" haskell-indentation-expression + "else" haskell-indentation-expression)))) + nil)) + +(defun haskell-indentation-phrase (phrase) + "" ; FIXME + (haskell-indentation-with-starter + (apply-partially #'haskell-indentation-phrase-rest phrase) + nil)) + +(defun haskell-indentation-phrase-rest (phrase1) + "" ; FIXME + (while phrase1 + (let ((phrase phrase1)) + (setq phrase1 nil) + (let ((current-indent (current-column)) + (left-indent left-indent) + (layout-indent layout-indent)) + (funcall (car phrase))) + (cond + ((eq current-token 'end-tokens) + (cond ((null (cdr phrase))) ;; fallthrough + ((equal following-token (cadr phrase)) + (haskell-indentation-add-indentation starter-indent) + (unless (member following-token '("," ";")) + ;; we want to keep comma and semicolon aligned always + (haskell-indentation-add-indentation left-indent)) + (throw 'parse-end nil)) + ((string= (cadr phrase) "in") + (when (= left-indent layout-indent) + (haskell-indentation-add-layout-indent) + (throw 'parse-end nil))) + (t (throw 'parse-end nil)))) + ((null (cdr phrase))) + ((equal (cadr phrase) current-token) + (haskell-indentation-read-next-token) + (when (eq current-token 'end-tokens) + (haskell-indentation-add-indentation + (+ starter-indent haskell-indentation-starter-offset)) + (haskell-indentation-add-indentation + (+ left-indent haskell-indentation-starter-offset)) + (throw 'parse-end nil)) + (setq phrase1 (cddr phrase))) + ((string= (cadr phrase) "in")))))) + +(defun haskell-indentation-add-indentation (indent) + "" ; FIXME + (haskell-indentation-push-indentation + (if (<= indent layout-indent) + (+ layout-indent haskell-indentation-layout-offset) + indent))) + +(defun haskell-indentation-add-layout-indent () + "" ; FIXME + (haskell-indentation-push-indentation layout-indent)) + +(defun haskell-indentation-add-where-pre-indent () + "" ; FIXME + (haskell-indentation-push-indentation + (+ layout-indent haskell-indentation-where-pre-offset)) + (if (= layout-indent haskell-indentation-layout-offset) + (haskell-indentation-push-indentation + haskell-indentation-where-pre-offset))) + +(defun haskell-indentation-add-where-post-indent (indent) + "" ; FIXME + (haskell-indentation-push-indentation + (+ indent haskell-indentation-where-post-offset))) + +(defun haskell-indentation-add-left-indent () + "" ; FIXME + (haskell-indentation-add-indentation + (+ left-indent haskell-indentation-left-offset))) + +(defun haskell-indentation-push-indentation (indent) + "Add INDENT to list of possible indentations. + +Add INDENT to `possible-indentations' if it is not there +yet. Keep the list in ascending order." + (unless (member indent possible-indentations) + (setq possible-indentations + (sort (cons indent possible-indentations) #'<)))) + +(defun haskell-indentation-read-next-token () + "Go to the next token and set current-token to the next token. + +The following symbols are used as pseudo tokens: + +'layout-item: A new item in a layout list. The next token + will be the first token from the item. + +'layout-end: the end of a layout list. Next token will be + the first token after the layout list. + +'end-tokens: back at point where we started, following-token + will be set to the next token. + +Pseudo tokens are used only when implicit-layout-active is +t. That is the case only after keywords \"do\", \"where\", +\"let\" and \"of\". + +If we are at a new line, parse-line is increased, and +current-indent and left-indent are set to the indentation of the +line." + (cond ((and implicit-layout-active + (eq current-token 'end-tokens)) + 'end-tokens) + ((and implicit-layout-active + (eq current-token 'layout-end)) + (cond ((> layout-indent (current-column)) + 'layout-end) + ((= layout-indent (current-column)) + (setq current-token 'layout-item)) + ((< layout-indent (current-column)) + (setq current-token (haskell-indentation-peek-token))))) + ((and implicit-layout-active + (eq current-token 'layout-item)) + (setq current-token (haskell-indentation-peek-token))) + ((and implicit-layout-active + (> layout-indent (current-column))) + (setq current-token 'layout-end)) + (t + (setq previous-token (haskell-indentation-peek-token)) + (haskell-indentation-skip-token) + (if (>= (point) indentation-point) + (progn + (setq following-token + (if (and (not (eobp)) + (= (point) indentation-point)) + (haskell-indentation-peek-token) + 'no-following-token)) + (setq current-token 'end-tokens)) + (when (= (current-column) (haskell-indentation-current-indentation)) + ;; on a new line + (setq current-indent (current-column))) + (cond ((and implicit-layout-active + (> layout-indent (current-column))) + (setq current-token 'layout-end)) + ((and implicit-layout-active + (= layout-indent (current-column))) + (setq current-token 'layout-item)) + (t (setq current-token (haskell-indentation-peek-token)))))))) + +(defun haskell-indentation-peek-token () + "Return token starting at point." + (cond ((looking-at "\\(if\\|then\\|else\\|let\\|in\\|mdo\\|rec\\|do\\|proc\\|case\\|of\\|where\\|module\\|signature\\|deriving\\|import\\|data\\|type\\|newtype\\|class\\|instance\\)\\([^[:alnum:]'_]\\|$\\)") + (match-string-no-properties 1)) + ((looking-at "[][(){}[,;]") + (match-string-no-properties 0)) + ((looking-at "\\(\\\\\\|->\\|<-\\|::\\|=\\||\\|=>\\)\\([^-:!#$%&*+./<=>?@\\\\^|~]\\|$\\)") + (match-string-no-properties 1)) + ((looking-at "\\(→\\|←\\|∷\\|⇒\\)\\([^-:!#$%&*+./<=>?@\\\\^|~]\\|$\\)") + (let ((tok (match-string-no-properties 1))) + (or (cdr (assoc tok haskell-indentation-unicode-tokens)) tok))) + ((looking-at"[-:!#$%&*+./<=>?@\\\\^|~`]" ) + 'operator) + (t 'value))) + +(defun haskell-indentation-skip-token () + "Skip to the next token." + (if (haskell-lexeme-looking-at-token) + (goto-char (match-end 0)) + ;; otherwise skip until space found + (skip-syntax-forward "^-")) + ;; we have to skip unterminated string fence at the end of line + (skip-chars-forward "\n") + (forward-comment (buffer-size)) + (while (and (haskell-indentation-bird-p) + (bolp) + (eq (char-after) ?>)) + (forward-char) + (forward-comment (buffer-size)))) + +(provide 'haskell-indentation) + +;; Local Variables: +;; tab-width: 8 +;; End: + +;;; haskell-indentation.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-indentation.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-indentation.elc new file mode 100644 index 000000000000..4d5b998fe250 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-indentation.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-interactive-mode.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-interactive-mode.el new file mode 100644 index 000000000000..c218c6c3facb --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-interactive-mode.el @@ -0,0 +1,1129 @@ +;;; haskell-interactive-mode.el --- The interactive Haskell mode -*- lexical-binding: t -*- + +;; Copyright © 2011-2012 Chris Done +;; 2016 Arthur Fayzrakhmanov + +;; Author: Chris Done <chrisdone@gmail.com> + +;; This file is not part of GNU Emacs. + +;; 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 GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;;; Todo: + +;;; Code: + +(require 'haskell-mode) +(require 'haskell-compile) +(require 'haskell-process) +(require 'haskell-session) +(require 'haskell-font-lock) +(require 'haskell-presentation-mode) +(require 'haskell-utils) +(require 'haskell-string) +(require 'ansi-color) +(require 'cl-lib) +(require 'etags) + +(defvar-local haskell-interactive-mode-history-index 0) + +(defvar-local haskell-interactive-mode-history (list)) + +(defvar-local haskell-interactive-mode-old-prompt-start nil + "Mark used for the old beginning of the prompt.") + +(defun haskell-interactive-prompt-regex () + "Generate a regex for searching for any occurence of the prompt\ +at the beginning of the line. This should prevent any +interference with prompts that look like haskell expressions." + (concat "^" (regexp-quote haskell-interactive-prompt))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Globals used internally + +(declare-function haskell-interactive-kill "haskell") + +(defvar haskell-interactive-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "RET") 'haskell-interactive-mode-return) + (define-key map (kbd "SPC") 'haskell-interactive-mode-space) + (define-key map (kbd "C-j") 'haskell-interactive-mode-newline-indent) + (define-key map (kbd "C-a") 'haskell-interactive-mode-beginning) + (define-key map (kbd "<home>") 'haskell-interactive-mode-beginning) + (define-key map (kbd "C-c C-k") 'haskell-interactive-mode-clear) + (define-key map (kbd "C-c C-c") 'haskell-process-interrupt) + (define-key map (kbd "C-c C-f") 'next-error-follow-minor-mode) + (define-key map (kbd "C-c C-z") 'haskell-interactive-switch-back) + (define-key map (kbd "M-p") 'haskell-interactive-mode-history-previous) + (define-key map (kbd "M-n") 'haskell-interactive-mode-history-next) + (define-key map (kbd "C-c C-p") 'haskell-interactive-mode-prompt-previous) + (define-key map (kbd "C-c C-n") 'haskell-interactive-mode-prompt-next) + (define-key map (kbd "C-<up>") 'haskell-interactive-mode-history-previous) + (define-key map (kbd "C-<down>") 'haskell-interactive-mode-history-next) + (define-key map (kbd "TAB") 'haskell-interactive-mode-tab) + (define-key map (kbd "<C-S-backspace>") 'haskell-interactive-mode-kill-whole-line) + map) + "Keymap used in `haskell-interactive-mode'.") + +(define-derived-mode haskell-interactive-mode fundamental-mode "Interactive-Haskell" + "Interactive mode for Haskell. + +Key bindings: +\\{haskell-interactive-mode-map}" + :group 'haskell-interactive + :syntax-table haskell-mode-syntax-table + + (setq haskell-interactive-mode-history (list)) + (setq haskell-interactive-mode-history-index 0) + + (setq next-error-function #'haskell-interactive-next-error-function) + (add-hook 'completion-at-point-functions + #'haskell-interactive-mode-completion-at-point-function nil t) + (add-hook 'kill-buffer-hook #'haskell-interactive-kill nil t) + (haskell-interactive-mode-prompt)) + +(defvar haskell-interactive-mode-prompt-start + nil + "Mark used for the beginning of the prompt.") + +(defvar haskell-interactive-mode-result-end + nil + "Mark used to figure out where the end of the current result output is. +Used to distinguish betwen user input.") + +(defvar-local haskell-interactive-previous-buffer nil + "Records the buffer to which `haskell-interactive-switch-back' should jump. +This is set by `haskell-interactive-switch', and should otherwise +be nil.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Hooks + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Mode + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Faces + +;;;###autoload +(defface haskell-interactive-face-prompt + '((t :inherit font-lock-function-name-face)) + "Face for the prompt." + :group 'haskell-interactive) + +;;;###autoload +(defface haskell-interactive-face-prompt2 + '((t :inherit font-lock-keyword-face)) + "Face for the prompt2 in multi-line mode." + :group 'haskell-interactive) + +;;;###autoload +(defface haskell-interactive-face-compile-error + '((t :inherit compilation-error)) + "Face for compile errors." + :group 'haskell-interactive) + +;;;###autoload +(defface haskell-interactive-face-compile-warning + '((t :inherit compilation-warning)) + "Face for compiler warnings." + :group 'haskell-interactive) + +;;;###autoload +(defface haskell-interactive-face-result + '((t :inherit font-lock-string-face)) + "Face for the result." + :group 'haskell-interactive) + +;;;###autoload +(defface haskell-interactive-face-garbage + '((t :inherit font-lock-string-face)) + "Face for trailing garbage after a command has completed." + :group 'haskell-interactive) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Actions + +(defun haskell-interactive-mode-newline-indent () + "Make newline and indent." + (interactive) + (newline) + (indent-to (length haskell-interactive-prompt)) + (indent-relative)) + +(defun haskell-interactive-mode-kill-whole-line () + "Kill the whole REPL line." + (interactive) + (kill-region haskell-interactive-mode-prompt-start + (line-end-position))) + +(defun haskell-interactive-switch-back () + "Switch back to the buffer from which this interactive buffer was reached." + (interactive) + (if haskell-interactive-previous-buffer + (switch-to-buffer-other-window haskell-interactive-previous-buffer) + (message "No previous buffer."))) + +(defun haskell-interactive-copy-to-prompt () + "Copy the current line to the prompt, overwriting the current prompt." + (interactive) + (let ((l (buffer-substring-no-properties (line-beginning-position) + (line-end-position)))) + ;; If it looks like the prompt is at the start of the line, chop + ;; it off. + (when (and (>= (length l) (length haskell-interactive-prompt)) + (string= (substring l 0 (length haskell-interactive-prompt)) + haskell-interactive-prompt)) + (setq l (substring l (length haskell-interactive-prompt)))) + + (haskell-interactive-mode-set-prompt l))) + +(defun haskell-interactive-mode-space (n) + "Handle the space key." + (interactive "p") + (if (and (bound-and-true-p god-local-mode) + (fboundp 'god-mode-self-insert)) + (call-interactively 'god-mode-self-insert) + (if (haskell-interactive-at-compile-message) + (next-error-no-select 0) + (self-insert-command n)))) + +(defun haskell-interactive-at-prompt (&optional end-line) + "If at prompt, return start position of user-input, otherwise return nil. +If END-LINE is non-nil, then return non-nil when the end of line +is at the prompt." + (if (>= (if end-line (line-end-position) (point)) + haskell-interactive-mode-prompt-start) + haskell-interactive-mode-prompt-start + nil)) + +(define-derived-mode haskell-error-mode + special-mode "Error" + "Major mode for viewing Haskell compile errors.") + +;; (define-key haskell-error-mode-map (kbd "q") 'quit-window) + +(defun haskell-interactive-mode-handle-h () + "Handle ^H in output." + (let ((bound (point-min)) + (inhibit-read-only t)) + (save-excursion + (while (search-backward "\b" bound t 1) + (save-excursion + (forward-char) + (let ((end (point))) + (if (search-backward-regexp "[^\b]" bound t 1) + (forward-char) + (goto-char (point-min))) + (let ((start (point))) + (delete-region (max (- (point) (- end start)) + (point-min)) + end)))))))) + +(defun haskell-interactive-mode-multi-line (expr) + "If a multi-line expression EXPR has been entered, then reformat it to be: + +:{ +do the + multi-liner + expr +:}" + (if (not (string-match-p "\n" expr)) + expr + (let ((pre (format "^%s" (regexp-quote haskell-interactive-prompt))) + (lines (split-string expr "\n"))) + (cl-loop for elt on (cdr lines) do + (setcar elt (replace-regexp-in-string pre "" (car elt)))) + ;; Temporarily set prompt2 to be empty to avoid unwanted output + (concat ":set prompt2 \"\"\n" + ":{\n" + (mapconcat #'identity lines "\n") + "\n:}\n" + (format ":set prompt2 \"%s\"" haskell-interactive-prompt2))))) + +(defun haskell-interactive-mode-line-is-query (line) + "Is LINE actually a :t/:k/:i?" + (and (string-match "^:[itk] " line) + t)) + +(defun haskell-interactive-mode-beginning () + "Go to the start of the line." + (interactive) + (if (haskell-interactive-at-prompt) + (goto-char haskell-interactive-mode-prompt-start) + (move-beginning-of-line nil))) + +(defun haskell-interactive-mode-input-partial () + "Get the interactive mode input up to point." + (let ((input-start (haskell-interactive-at-prompt))) + (unless input-start + (error "not at prompt")) + (buffer-substring-no-properties input-start (point)))) + +(defun haskell-interactive-mode-input () + "Get the interactive mode input." + (buffer-substring-no-properties + haskell-interactive-mode-prompt-start + (point-max))) + +(defun haskell-interactive-mode-prompt (&optional session) + "Show a prompt at the end of the REPL buffer. +If SESSION is non-nil, use the REPL buffer associated with +SESSION, otherwise operate on the current buffer." + (with-current-buffer (if session + (haskell-session-interactive-buffer session) + (current-buffer)) + (save-excursion + (goto-char (point-max)) + (let ((prompt (propertize haskell-interactive-prompt + 'font-lock-face 'haskell-interactive-face-prompt + 'prompt t + 'read-only haskell-interactive-prompt-read-only + 'rear-nonsticky t))) + ;; At the time of writing, front-stickying the first char gives an error + ;; Has unfortunate side-effect of being able to insert before the prompt + (insert (substring prompt 0 1) + (propertize (substring prompt 1) + 'front-sticky t))) + (let ((marker (setq-local haskell-interactive-mode-prompt-start (make-marker)))) + (set-marker marker (point)))) + (when (haskell-interactive-at-prompt t) + (haskell-interactive-mode-scroll-to-bottom)))) + +(defun haskell-interactive-mode-eval-result (session text) + "Insert the result of an eval as plain text." + (with-current-buffer (haskell-session-interactive-buffer session) + (let ((at-end (eobp)) + (prop-text (propertize text + 'font-lock-face 'haskell-interactive-face-result + 'front-sticky t + 'prompt t + 'read-only haskell-interactive-mode-read-only + 'rear-nonsticky t + 'result t))) + (save-excursion + (goto-char (point-max)) + (when (string= text haskell-interactive-prompt2) + (setq prop-text + (propertize prop-text + 'font-lock-face 'haskell-interactive-face-prompt2 + 'read-only haskell-interactive-prompt-read-only))) + (insert (ansi-color-apply prop-text)) + (haskell-interactive-mode-handle-h) + (let ((marker (setq-local haskell-interactive-mode-result-end (make-marker)))) + (set-marker marker (point)))) + (when at-end + (haskell-interactive-mode-scroll-to-bottom))))) + +(defun haskell-interactive-mode-scroll-to-bottom () + "Scroll to bottom." + (let ((w (get-buffer-window (current-buffer)))) + (when w + (goto-char (point-max)) + (set-window-point w (point))))) + +(defun haskell-interactive-mode-compile-error (session message) + "Echo an error." + (haskell-interactive-mode-compile-message + session message 'haskell-interactive-face-compile-error)) + +(defun haskell-interactive-mode-compile-warning (session message) + "Warning message." + (haskell-interactive-mode-compile-message + session message 'haskell-interactive-face-compile-warning)) + +(defun haskell-interactive-mode-compile-message (session message type) + "Echo a compiler warning." + (with-current-buffer (haskell-session-interactive-buffer session) + (setq next-error-last-buffer (current-buffer)) + (save-excursion + (haskell-interactive-mode-goto-end-point) + (let ((lines (string-match "^\\(.*\\)\n\\([[:unibyte:][:nonascii:]]+\\)" message))) + (if lines + (progn + (insert (propertize (concat (match-string 1 message) " …\n") + 'expandable t + 'font-lock-face type + 'front-sticky t + 'read-only haskell-interactive-mode-read-only + 'rear-nonsticky t)) + (insert (propertize (concat (match-string 2 message) "\n") + 'collapsible t + 'font-lock-face type + 'front-sticky t + 'invisible haskell-interactive-mode-hide-multi-line-errors + 'message-length (length (match-string 2 message)) + 'read-only haskell-interactive-mode-read-only + 'rear-nonsticky t))) + (insert (propertize (concat message "\n") + 'font-lock-face type + 'front-sticky t + 'read-only haskell-interactive-mode-read-only + 'rear-nonsticky t))))))) + +(defun haskell-interactive-mode-insert (session message) + "Echo a read only piece of text before the prompt." + (with-current-buffer (haskell-session-interactive-buffer session) + (save-excursion + (haskell-interactive-mode-goto-end-point) + (insert (propertize message + 'front-sticky t + 'read-only t + 'rear-nonsticky t))))) + +(defun haskell-interactive-mode-goto-end-point () + "Go to the 'end' of the buffer (before the prompt)." + (goto-char haskell-interactive-mode-prompt-start) + (goto-char (line-beginning-position))) + +(defun haskell-interactive-mode-history-add (input) + "Add INPUT to the history." + (setq haskell-interactive-mode-history + (cons "" + (cons input + (cl-remove-if (lambda (i) (or (string= i input) (string= i ""))) + haskell-interactive-mode-history)))) + (setq haskell-interactive-mode-history-index + 0)) + +(defun haskell-interactive-mode-tab () + "Do completion if at prompt or else try collapse/expand." + (interactive) + (cond + ((haskell-interactive-at-prompt) + (completion-at-point)) + ((get-text-property (point) 'collapsible) + (let ((column (current-column))) + (search-backward-regexp "^[^ ]") + (haskell-interactive-mode-tab-expand) + (goto-char (+ column (line-beginning-position))))) + (t (haskell-interactive-mode-tab-expand)))) + +(defun haskell-interactive-mode-tab-expand () + "Expand the rest of the message." + (cond ((get-text-property (point) 'expandable) + (let* ((pos (1+ (line-end-position))) + (visibility (get-text-property pos 'invisible)) + (length (1+ (get-text-property pos 'message-length)))) + (let ((inhibit-read-only t)) + (put-text-property pos + (+ pos length) + 'invisible + (not visibility))))))) + +(defconst haskell-interactive-mode-error-regexp + "^\\(\\(?:[A-Z]:\\)?[^ \r\n:][^\r\n:]*\\):\\([0-9()-:]+\\):?") + +(defun haskell-interactive-at-compile-message () + "Am I on a compile message?" + (and (not (haskell-interactive-at-prompt)) + (save-excursion + (goto-char (line-beginning-position)) + (looking-at haskell-interactive-mode-error-regexp)))) + +(defun haskell-interactive-mode-error-backward (&optional count) + "Go backward to the previous error." + (interactive) + (search-backward-regexp haskell-interactive-mode-error-regexp nil t count)) + +(defun haskell-interactive-mode-error-forward (&optional count) + "Go forward to the next error, or return to the REPL." + (interactive) + (goto-char (line-end-position)) + (if (search-forward-regexp haskell-interactive-mode-error-regexp nil t count) + (progn (goto-char (line-beginning-position)) + t) + (progn (goto-char (point-max)) + nil))) + +(defun haskell-interactive-mode-delete-compile-messages (session &optional file-name) + "Delete compile messages in REPL buffer. +If FILE-NAME is non-nil, restrict to removing messages concerning +FILE-NAME only." + (with-current-buffer (haskell-session-interactive-buffer session) + (save-excursion + (goto-char (point-min)) + (when (search-forward-regexp "^Compilation failed.$" nil t 1) + (let ((inhibit-read-only t)) + (delete-region (line-beginning-position) + (1+ (line-end-position)))) + (goto-char (point-min))) + (while (when (re-search-forward haskell-interactive-mode-error-regexp nil t) + (let ((msg-file-name (match-string-no-properties 1)) + (msg-startpos (line-beginning-position))) + ;; skip over hanging continuation message lines + (while (progn (forward-line) (looking-at "^[ ]+"))) + + (when (or (not file-name) (string= file-name msg-file-name)) + (let ((inhibit-read-only t)) + (set-text-properties msg-startpos (point) nil)) + (delete-region msg-startpos (point)) + )) + t))))) + +;;;###autoload +(defun haskell-interactive-mode-reset-error (session) + "Reset the error cursor position." + (interactive) + (with-current-buffer (haskell-session-interactive-buffer session) + (haskell-interactive-mode-goto-end-point) + (let ((mrk (point-marker))) + (haskell-session-set session 'next-error-locus nil) + (haskell-session-set session 'next-error-region (cons mrk (copy-marker mrk t)))) + (goto-char (point-max)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Misc + +(declare-function haskell-interactive-switch "haskell") +(declare-function haskell-session "haskell") + +(defun haskell-session-interactive-buffer (s) + "Get the session interactive buffer." + (let ((buffer (haskell-session-get s 'interactive-buffer))) + (if (and buffer (buffer-live-p buffer)) + buffer + (let ((buffer-name (format "*%s*" (haskell-session-name s))) + (index 0)) + (while (get-buffer buffer-name) + (setq buffer-name (format "*%s <%d>*" (haskell-session-name s) index)) + (setq index (1+ index))) + (let ((buffer (get-buffer-create buffer-name))) + (haskell-session-set-interactive-buffer s buffer) + (with-current-buffer buffer + (haskell-interactive-mode) + (haskell-session-assign s)) + (haskell-interactive-switch) + buffer))))) + +(defun haskell-interactive-buffer () + "Get the interactive buffer of the session." + (haskell-session-interactive-buffer (haskell-session))) + +(defun haskell-process-cabal-live (state buffer) + "Do live updates for Cabal processes." + (haskell-interactive-mode-insert + (haskell-process-session (cadr state)) + (replace-regexp-in-string + haskell-process-prompt-regex + "" + (substring buffer (cl-cadddr state)))) + (setf (cl-cdddr state) (list (length buffer))) + nil) + +(defun haskell-process-parse-error (string) + "Parse the line number from the error string STRING." + (let ((span nil)) + (cl-loop for regex + in haskell-compilation-error-regexp-alist + do (when (string-match (car regex) string) + (setq span + (list :file (match-string 1 string) + :line (string-to-number (match-string 2 string)) + :col (string-to-number (match-string 4 string)) + :line2 (when (match-string 3 string) + (string-to-number (match-string 3 string))) + :col2 (when (match-string 5 string) + (string-to-number (match-string 5 string))))))) + span)) + +(defun haskell-process-suggest-add-package (session msg) + "Add the (matched) module to your cabal file. +Cabal file is selected using SESSION's name, module matching is done in MSG." + (let* ((suggested-package (match-string 1 msg)) + (package-name (replace-regexp-in-string "-[^-]+$" "" suggested-package)) + (version (progn (string-match "\\([^-]+\\)$" suggested-package) + (match-string 1 suggested-package))) + (cabal-file (concat (haskell-session-name session) + ".cabal"))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (when (y-or-n-p + (format "Add `%s' to %s?" + package-name + cabal-file)) + (haskell-cabal-add-dependency package-name version nil t) + (when (y-or-n-p (format "Enable -package %s in the GHCi session?" package-name)) + (haskell-process-queue-without-filters + (haskell-session-process session) + (format ":set -package %s" package-name)))) + (haskell-mode-toggle-interactive-prompt-state t)))) + +(defun haskell-process-suggest-remove-import (session file import line) + "Suggest removing or commenting out import statement. +Asks user to handle redundant import statement using interactive +SESSION in specified FILE to remove IMPORT on given LINE." + (let ((first t)) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (cl-case (read-event + (propertize (format "%sThe import line `%s' is redundant. Remove? (y, n, c: comment out) " + (if (not first) + "Please answer n, y or c: " + "") + import) + 'face + 'minibuffer-prompt)) + (?y + (haskell-process-find-file session file) + (save-excursion + (goto-char (point-min)) + (forward-line (1- line)) + (goto-char (line-beginning-position)) + (delete-region (line-beginning-position) + (line-end-position)))) + (?n + (message "Ignoring redundant import %s" import)) + (?c + (haskell-process-find-file session file) + (save-excursion + (goto-char (point-min)) + (forward-line (1- line)) + (goto-char (line-beginning-position)) + (insert "-- ")))) + ;; unwind + (haskell-mode-toggle-interactive-prompt-state t)))) + +(defun haskell-process-find-file (session file) + "Find the given file in the project." + (find-file (cond ((file-exists-p (concat (haskell-session-current-dir session) "/" file)) + (concat (haskell-session-current-dir session) "/" file)) + ((file-exists-p (concat (haskell-session-cabal-dir session) "/" file)) + (concat (haskell-session-cabal-dir session) "/" file)) + (t file)))) + +(defun haskell-process-suggest-pragma (session pragma extension file) + "Suggest to add something to the top of the file. +SESSION is used to search given file. Adds PRAGMA and EXTENSION +wrapped in compiler directive at the top of FILE." + (let ((string (format "{-# %s %s #-}" pragma extension))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (when (y-or-n-p (format "Add %s to the top of the file? " string)) + (haskell-process-find-file session file) + (save-excursion + (goto-char (point-min)) + (insert (concat string "\n")))) + (haskell-mode-toggle-interactive-prompt-state t)))) + +(defun haskell-interactive-mode-insert-error (response) + "Insert an error message." + (insert "\n" + (haskell-fontify-as-mode + response + 'haskell-mode)) + (haskell-interactive-mode-prompt)) + +(defun haskell-interactive-popup-error (response) + "Popup an error." + (if haskell-interactive-popup-errors + (let ((buf (get-buffer-create "*HS-Error*"))) + (pop-to-buffer buf nil t) + (with-current-buffer buf + + (haskell-error-mode) + (let ((inhibit-read-only t)) + (erase-buffer) + (insert (propertize response + 'font-lock-face + 'haskell-interactive-face-compile-error)) + (goto-char (point-min)) + (delete-blank-lines) + (insert (propertize "-- Hit `q' to close this window.\n\n" + 'font-lock-face 'font-lock-comment-face)) + (save-excursion + (goto-char (point-max)) + (insert (propertize "\n-- To disable popups, customize `haskell-interactive-popup-errors'.\n\n" + 'font-lock-face 'font-lock-comment-face)))))) + (haskell-interactive-mode-insert-error response))) + +(defun haskell-interactive-next-error-function (&optional n reset) + "See `next-error-function' for more information." + + (let* ((session (haskell-interactive-session)) + (next-error-region (haskell-session-get session 'next-error-region)) + (next-error-locus (haskell-session-get session 'next-error-locus)) + (reset-locus nil)) + + (when (and next-error-region (or reset (and (/= n 0) (not next-error-locus)))) + (goto-char (car next-error-region)) + (unless (looking-at haskell-interactive-mode-error-regexp) + (haskell-interactive-mode-error-forward)) + + (setq reset-locus t) + (unless (looking-at haskell-interactive-mode-error-regexp) + (error "no errors found"))) + + ;; move point if needed + (cond + (reset-locus nil) + ((> n 0) (unless (haskell-interactive-mode-error-forward n) + (error "no more errors"))) + + ((< n 0) (unless (haskell-interactive-mode-error-backward (- n)) + (error "no more errors")))) + + (let ((orig-line (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) + + (when (string-match haskell-interactive-mode-error-regexp orig-line) + (let* ((msgmrk (set-marker (make-marker) (line-beginning-position))) + (location (haskell-process-parse-error orig-line)) + (file (plist-get location :file)) + (line (plist-get location :line)) + (col1 (plist-get location :col)) + (col2 (plist-get location :col2)) + + (cabal-relative-file (expand-file-name file (haskell-session-cabal-dir session))) + (src-relative-file (expand-file-name file (haskell-session-current-dir session))) + + (real-file (cond ((file-exists-p cabal-relative-file) cabal-relative-file) + ((file-exists-p src-relative-file) src-relative-file)))) + + (haskell-session-set session 'next-error-locus msgmrk) + + (if real-file + (let ((m1 (make-marker)) + (m2 (make-marker))) + (with-current-buffer (find-file-noselect real-file) + (save-excursion + (goto-char (point-min)) + (forward-line (1- line)) + (set-marker m1 (+ col1 (point) -1)) + + (when col2 + (set-marker m2 (- (point) col2))))) + ;; ...finally select&hilight error locus + (compilation-goto-locus msgmrk m1 (and (marker-position m2) m2))) + (error "don't know where to find %S" file))))))) + +(defun haskell-interactive-session () + "Get the `haskell-session', throw an error if it's not available." + (or (haskell-session-maybe) + (haskell-session-assign + (or (haskell-session-from-buffer) + (haskell-session-choose) + (error "No session associated with this buffer. Try M-x haskell-session-change or report this as a bug."))))) + +(defun haskell-interactive-process () + "Get the Haskell session." + (or (haskell-session-process (haskell-interactive-session)) + (error "No Haskell session/process associated with this + buffer. Maybe run M-x haskell-process-restart?"))) + +(defun haskell-interactive-mode-do-presentation (expr) + "Present the given expression EXPR. +Requires the `present' package to be installed. +Will automatically import it qualified as Present." + (let ((p (haskell-interactive-process))) + ;; If Present.code isn't available, we probably need to run the + ;; setup. + (unless (string-match "^Present" (haskell-process-queue-sync-request p ":t Present.encode")) + (haskell-interactive-mode-setup-presentation p)) + ;; Happily, let statements don't affect the `it' binding in any + ;; way, so we can fake it, no pun intended. + (let ((error (haskell-process-queue-sync-request + p (concat "let it = Present.asData (" expr ")")))) + (if (not (string= "" error)) + (haskell-interactive-mode-eval-result (haskell-interactive-session) (concat error "\n")) + (let ((hash (haskell-interactive-mode-presentation-hash))) + (haskell-process-queue-sync-request + p (format "let %s = Present.asData (%s)" hash expr)) + (let* ((presentation (haskell-interactive-mode-present-id + hash + (list 0)))) + (insert "\n") + (haskell-interactive-mode-insert-presentation hash presentation) + (haskell-interactive-mode-eval-result (haskell-interactive-session) "\n")))) + (haskell-interactive-mode-prompt (haskell-interactive-session))))) + +(defun haskell-interactive-mode-present-id (hash id) + "Generate a presentation for the current expression at ID." + ;; See below for commentary of this statement. + (let ((p (haskell-interactive-process))) + (haskell-process-queue-without-filters + p "let _it = it") + (let* ((text (haskell-process-queue-sync-request + p + (format "Present.putStr (Present.encode (Present.fromJust (Present.present (Present.fromJust (Present.fromList [%s])) %s)))" + (mapconcat 'identity (mapcar 'number-to-string id) ",") + hash))) + (reply + (if (string-match "^*** " text) + '((rep nil)) + (read text)))) + ;; Not necessary, but nice to restore it to the expression that + ;; the user actually typed in. + (haskell-process-queue-without-filters + p "let it = _it") + reply))) + +(defun haskell-presentation-present-slot (btn) + "The callback to evaluate the slot and present it in place of the button BTN." + (let ((id (button-get btn 'presentation-id)) + (hash (button-get btn 'hash)) + (parent-rep (button-get btn 'parent-rep)) + (continuation (button-get btn 'continuation))) + (let ((point (point))) + (button-put btn 'invisible t) + (delete-region (button-start btn) (button-end btn)) + (haskell-interactive-mode-insert-presentation + hash + (haskell-interactive-mode-present-id hash id) + parent-rep + continuation) + (when (> (point) point) + (goto-char (1+ point)))))) + +(defun haskell-interactive-mode-presentation-slot (hash slot parent-rep &optional continuation) + "Make a slot at point, pointing to ID." + (let ((type (car slot)) + (id (cadr slot))) + (if (member (intern type) '(Integer Char Int Float Double)) + (haskell-interactive-mode-insert-presentation + hash + (haskell-interactive-mode-present-id hash id) + parent-rep + continuation) + (haskell-interactive-mode-presentation-slot-button slot parent-rep continuation hash)))) + +(defun haskell-interactive-mode-presentation-slot-button (slot parent-rep continuation hash) + (let ((start (point)) + (type (car slot)) + (id (cadr slot))) + (insert (propertize type 'font-lock-face '(:height 0.8 :underline t :inherit font-lock-comment-face))) + (let ((button (make-text-button start (point) + :type 'haskell-presentation-slot-button))) + (button-put button 'hide-on-click t) + (button-put button 'presentation-id id) + (button-put button 'parent-rep parent-rep) + (button-put button 'continuation continuation) + (button-put button 'hash hash)))) + +(defun haskell-interactive-mode-insert-presentation (hash presentation &optional parent-rep continuation) + "Insert the presentation, hooking up buttons for each slot." + (let* ((rep (cadr (assoc 'rep presentation))) + (text (cadr (assoc 'text presentation))) + (slots (cadr (assoc 'slots presentation))) + (nullary (null slots))) + (cond + ((string= "integer" rep) + (insert (propertize text 'font-lock-face 'font-lock-constant))) + ((string= "floating" rep) + (insert (propertize text 'font-lock-face 'font-lock-constant))) + ((string= "char" rep) + (insert (propertize + (if (string= "string" parent-rep) + (replace-regexp-in-string "^'\\(.+\\)'$" "\\1" text) + text) + 'font-lock-face 'font-lock-string-face))) + ((string= "tuple" rep) + (insert "(") + (let ((first t)) + (cl-loop for slot in slots + do (unless first (insert ",")) + do (haskell-interactive-mode-presentation-slot hash slot rep) + do (setq first nil))) + (insert ")")) + ((string= "list" rep) + (if (null slots) + (if continuation + (progn (delete-char -1) + (delete-indentation)) + (insert "[]")) + (let ((i 0)) + (unless continuation + (insert "[")) + (let ((start-column (current-column))) + (cl-loop for slot in slots + do (haskell-interactive-mode-presentation-slot + hash + slot + rep + (= i (1- (length slots)))) + do (when (not (= i (1- (length slots)))) + (insert "\n") + (indent-to (1- start-column)) + (insert ",")) + do (setq i (1+ i)))) + (unless continuation + (insert "]"))))) + ((string= "string" rep) + (unless (string= "string" parent-rep) + (insert (propertize "\"" 'font-lock-face 'font-lock-string-face))) + (cl-loop for slot in slots + do (haskell-interactive-mode-presentation-slot hash slot rep)) + (unless (string= "string" parent-rep) + (insert (propertize "\"" 'font-lock-face 'font-lock-string-face)))) + ((string= "alg" rep) + (when (and parent-rep + (not nullary) + (not (string= "list" parent-rep))) + (insert "(")) + (let ((start-column (current-column))) + (insert (propertize text 'font-lock-face 'font-lock-type-face)) + (cl-loop for slot in slots + do (insert "\n") + do (indent-to (+ 2 start-column)) + do (haskell-interactive-mode-presentation-slot hash slot rep))) + (when (and parent-rep + (not nullary) + (not (string= "list" parent-rep))) + (insert ")"))) + ((string= "record" rep) + (let ((start-column (current-column))) + (insert (propertize text 'font-lock-face 'font-lock-type-face) + " { ") + (cl-loop for field in slots + do (insert "\n") + do (indent-to (+ 2 start-column)) + do (let ((name (nth 0 field)) + (slot (nth 1 field))) + (insert name " = ") + (haskell-interactive-mode-presentation-slot hash slot rep))) + (insert "\n") + (indent-to start-column) + (insert "}"))) + ((eq rep nil) + (insert (propertize "?" 'font-lock-face 'font-lock-warning))) + (t + (let ((err "Unable to present! This very likely means Emacs +is out of sync with the `present' package. You should make sure +they're both up to date, or report a bug.")) + (insert err) + (error err)))))) + +(defun haskell-interactive-mode-setup-presentation (p) + "Setup the GHCi REPL for using presentations. + +Using asynchronous queued commands as opposed to sync at this +stage, as sync would freeze up the UI a bit, and we actually +don't care when the thing completes as long as it's soonish." + ;; Import dependencies under Present.* namespace + (haskell-process-queue-without-filters p "import qualified Data.Maybe as Present") + (haskell-process-queue-without-filters p "import qualified Data.ByteString.Lazy as Present") + (haskell-process-queue-without-filters p "import qualified Data.AttoLisp as Present") + (haskell-process-queue-without-filters p "import qualified Present.ID as Present") + (haskell-process-queue-without-filters p "import qualified Present as Present") + ;; Make a dummy expression to avoid "Loading package" nonsense + (haskell-process-queue-without-filters + p "Present.present (Present.fromJust (Present.fromList [0])) ()")) + +(defvar haskell-interactive-mode-presentation-hash 0 + "Counter for the hash.") + +(defun haskell-interactive-mode-presentation-hash () + "Generate a presentation hash." + (format "_present_%s" + (setq haskell-interactive-mode-presentation-hash + (1+ haskell-interactive-mode-presentation-hash)))) + +(define-button-type 'haskell-presentation-slot-button + 'action 'haskell-presentation-present-slot + 'follow-link t + 'help-echo "Click to expand…") + +(defun haskell-interactive-mode-history-toggle (n) + "Toggle the history N items up or down." + (unless (null haskell-interactive-mode-history) + (setq haskell-interactive-mode-history-index + (mod (+ haskell-interactive-mode-history-index n) + (length haskell-interactive-mode-history))) + (unless (zerop haskell-interactive-mode-history-index) + (message "History item: %d" haskell-interactive-mode-history-index)) + (haskell-interactive-mode-set-prompt + (nth haskell-interactive-mode-history-index + haskell-interactive-mode-history)))) + +(defun haskell-interactive-mode-set-prompt (p) + "Set (and overwrite) the current prompt." + (with-current-buffer (haskell-session-interactive-buffer (haskell-interactive-session)) + (goto-char haskell-interactive-mode-prompt-start) + (delete-region (point) (point-max)) + (insert p))) + +(defun haskell-interactive-mode-history-previous (arg) + "Cycle backwards through input history." + (interactive "*p") + (when (haskell-interactive-at-prompt) + (if (not (zerop arg)) + (haskell-interactive-mode-history-toggle arg) + (setq haskell-interactive-mode-history-index 0) + (haskell-interactive-mode-history-toggle 1)))) + +(defun haskell-interactive-mode-history-next (arg) + "Cycle forward through input history." + (interactive "*p") + (when (haskell-interactive-at-prompt) + (if (not (zerop arg)) + (haskell-interactive-mode-history-toggle (- arg)) + (setq haskell-interactive-mode-history-index 0) + (haskell-interactive-mode-history-toggle -1)))) + +(defun haskell-interactive-mode-prompt-previous () + "Jump to the previous prompt." + (interactive) + (let ((prev-prompt-pos + (save-excursion + (beginning-of-line) ;; otherwise prompt at current line matches + (and (search-backward-regexp (haskell-interactive-prompt-regex) nil t) + (match-end 0))))) + (when prev-prompt-pos (goto-char prev-prompt-pos)))) + +(defun haskell-interactive-mode-prompt-next () + "Jump to the next prompt." + (interactive) + (search-forward-regexp (haskell-interactive-prompt-regex) nil t)) + +(defun haskell-interactive-mode-clear () + "Clear the screen and put any current input into the history." + (interactive) + (let ((session (haskell-interactive-session))) + (with-current-buffer (haskell-session-interactive-buffer session) + (let ((inhibit-read-only t)) + (set-text-properties (point-min) (point-max) nil)) + (delete-region (point-min) (point-max)) + (remove-overlays) + (haskell-interactive-mode-prompt session) + (haskell-session-set session 'next-error-region nil) + (haskell-session-set session 'next-error-locus nil)) + (with-current-buffer (get-buffer-create "*haskell-process-log*") + (let ((inhibit-read-only t)) + (delete-region (point-min) (point-max))) + (remove-overlays)))) + +(defun haskell-interactive-mode-completion-at-point-function () + "Offer completions for partial expression between prompt and point. +This completion function is used in interactive REPL buffer itself." + (when (haskell-interactive-at-prompt) + (let* ((process (haskell-interactive-process)) + (inp (haskell-interactive-mode-input-partial)) + (resp2 (haskell-process-get-repl-completions process inp)) + (rlen (- (length inp) (length (car resp2)))) + (coll (append (if (string-prefix-p inp "import") '("import")) + (if (string-prefix-p inp "let") '("let")) + (cdr resp2)))) + (list (- (point) rlen) (point) coll)))) + +(defun haskell-interactive-mode-trigger-compile-error (state response) + "Look for an <interactive> compile error. +If there is one, pop that up in a buffer, similar to `debug-on-error'." + (when (and haskell-interactive-types-for-show-ambiguous + (string-match "^\n<interactive>:[-0-9]+:[-0-9]+:" response) + (not (string-match "^\n<interactive>:[-0-9]+:[-0-9]+:[\n ]+[Ww]arning:" response))) + (let ((inhibit-read-only t)) + (delete-region haskell-interactive-mode-prompt-start (point)) + (set-marker haskell-interactive-mode-prompt-start + haskell-interactive-mode-old-prompt-start) + (goto-char (point-max))) + (cond + ((and (not (haskell-interactive-mode-line-is-query (elt state 2))) + (or (string-match "No instance for (?Show[ \n]" response) + (string-match "Ambiguous type variable " response))) + (haskell-process-reset (haskell-interactive-process)) + (let ((resp (haskell-process-queue-sync-request + (haskell-interactive-process) + (concat ":t " + (buffer-substring-no-properties + haskell-interactive-mode-prompt-start + (point-max)))))) + (cond + ((not (string-match "<interactive>:" resp)) + (haskell-interactive-mode-insert-error resp)) + (t (haskell-interactive-popup-error response))))) + (t (haskell-interactive-popup-error response) + t)) + t)) + +;;;###autoload +(defun haskell-interactive-mode-echo (session message &optional mode) + "Echo a read only piece of text before the prompt." + (with-current-buffer (haskell-session-interactive-buffer session) + (save-excursion + (haskell-interactive-mode-goto-end-point) + (insert (if mode + (haskell-fontify-as-mode + (concat message "\n") + mode) + (propertize (concat message "\n") + 'front-sticky t + 'read-only t + 'rear-nonsticky t)))))) + +(defun haskell-interactive-mode-splices-buffer (session) + "Get the splices buffer for the current SESSION." + (get-buffer-create (haskell-interactive-mode-splices-buffer-name session))) + +(defun haskell-interactive-mode-splices-buffer-name (session) + (format "*%s:splices*" (haskell-session-name session))) + +(defun haskell-interactive-mode-compile-splice (session message) + "Echo a compiler splice." + (with-current-buffer (haskell-interactive-mode-splices-buffer session) + (unless (eq major-mode 'haskell-mode) + (haskell-mode)) + (let* ((parts (split-string message "\n ======>\n")) + (file-and-decl-lines (split-string (nth 0 parts) "\n")) + (file (nth 0 file-and-decl-lines)) + (decl (mapconcat #'identity (cdr file-and-decl-lines) "\n")) + (output (nth 1 parts))) + (insert "-- " file "\n") + (let ((start (point))) + (insert decl "\n") + (indent-rigidly start (point) -4)) + (insert "-- =>\n") + (let ((start (point))) + (insert output "\n") + (indent-rigidly start (point) -4))))) + +(defun haskell-interactive-mode-insert-garbage (session message) + "Echo a read only piece of text before the prompt." + (with-current-buffer (haskell-session-interactive-buffer session) + (save-excursion + (haskell-interactive-mode-goto-end-point) + (insert (propertize message + 'front-sticky t + 'font-lock-face 'haskell-interactive-face-garbage + 'read-only t + 'rear-nonsticky t))))) + +;;;###autoload +(defun haskell-process-show-repl-response (line) + "Send LINE to the GHCi process and echo the result in some fashion. +Result will be printed in the minibuffer or presented using +function `haskell-presentation-present', depending on variable +`haskell-process-use-presentation-mode'." + (let ((process (haskell-interactive-process))) + (haskell-process-queue-command + process + (make-haskell-command + :state (cons process line) + :go (lambda (state) + (haskell-process-send-string (car state) (cdr state))) + :complete (lambda (state response) + (if haskell-process-use-presentation-mode + (haskell-presentation-present + (haskell-process-session (car state)) + response) + (haskell-mode-message-line response))))))) + +(provide 'haskell-interactive-mode) + +;;; haskell-interactive-mode.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-interactive-mode.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-interactive-mode.elc new file mode 100644 index 000000000000..2d82cfc43db5 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-interactive-mode.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-lexeme.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-lexeme.el new file mode 100644 index 000000000000..877774e7756b --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-lexeme.el @@ -0,0 +1,513 @@ +;;; haskell-lexeme.el --- haskell lexical tokens -*- coding: utf-8; lexical-binding: t -*- + +;; Copyright (C) 2015 Gracjan Polak + +;; 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;;; Code: + +(require 'rx) + +(unless (category-docstring ?P) + (define-category ?P "Haskell symbol constituent characters") + (map-char-table + #'(lambda (key val) + (if (or + (and (consp key) (> (car key) 128)) + (and (numberp key) (> key 128))) + (if (member val '(Pc Pd Po Sm Sc Sk So)) + (modify-category-entry key ?P)))) + unicode-category-table) + + (dolist (key (string-to-list "!#$%&*+./<=>?@^|~\\-:")) + (modify-category-entry key ?P))) + +(defconst haskell-lexeme-modid + "[[:upper:]][[:alnum:]'_]*" + "Regexp matching a valid Haskell module identifier. + +Note that GHC accepts Unicode category UppercaseLetter as a first +character. Following letters are from Unicode categories +UppercaseLetter, LowercaseLetter, OtherLetter, TitlecaseLetter, +ModifierLetter, DecimalNumber, OtherNumber, backslash or +underscore.") + +(defconst haskell-lexeme-id + "[[:alpha:]_][[:alnum:]'_]*" + "Regexp matching a valid Haskell identifier. + +GHC accepts a string starting with any alphabetic character or +underscore followed by any alphanumeric character or underscore +or apostrophe.") + +(defconst haskell-lexeme-sym + "\\cP+" + "Regexp matching a valid Haskell variable or constructor symbol. + +GHC accepts a string of chars from the set +[:!#$%&*+./<=>?@^|~\\-] or Unicode category Symbol for chars with +codes larger than 128 only.") + +(defconst haskell-lexeme-idsym-first-char + "\\(?:[[:alpha:]_]\\|\\cP\\)" + "Regexp matching first character of a qualified or unqualified +identifier or symbol. + +Useful for `re-search-forward'.") + +(defconst haskell-lexeme-modid-opt-prefix + (concat "\\(?:" haskell-lexeme-modid "\\.\\)*") + "Regexp matching a valid Haskell module prefix, potentially empty. + +Module path prefix is separated by dots and finishes with a +dot. For path component syntax see `haskell-lexeme-modid'.") + +(defconst haskell-lexeme-qid-or-qsym + (rx-to-string `(: (regexp ,haskell-lexeme-modid-opt-prefix) + (group (| (regexp ,haskell-lexeme-id) (regexp ,haskell-lexeme-sym) + )))) + "Regexp matching a valid qualified identifier or symbol. + +Note that (match-string 1) returns the unqualified part.") + +(defun haskell-lexeme-looking-at-qidsym () + "Non-nil when point is just in front of an optionally qualified +identifier or symbol. + +Using this function is more efficient than matching against the +regexp `haskell-lexeme-qid-or-qsym'. + +Returns: + 'qid - if matched a qualified id: 'Data.Map' or 'Map' + 'qsym - if matched a qualified id: 'Monad.>>=' or '>>=' + 'qprefix - if matched only modid prefix: 'Data.' + +After successful 'qid or 'qsym match (match-string 1) will return +the unqualified part (if any)." + (let ((begin (point)) + (match-data-old (match-data))) + (save-excursion + (while (looking-at (concat haskell-lexeme-modid "\\.")) + (goto-char (match-end 0))) + (cond + ((looking-at haskell-lexeme-id) + (let ((beg (match-beginning 0)) + (end (match-end 0))) + + ;; check is MagicHash is present at the end of the token + (goto-char end) + (when (looking-at "#+") + (setq end (match-end 0))) + + (set-match-data + (list begin end + beg end))) + 'qid) + ((looking-at haskell-lexeme-sym) + (set-match-data + (list begin (match-end 0) + (match-beginning 0) (match-end 0))) + 'qsym) + ((equal begin (point)) + (set-match-data match-data-old) + nil) + (t + (set-match-data + (list begin (point) + nil nil)) + 'qprefix))))) + +(defun haskell-lexeme-looking-at-backtick () + "Non-nil when point is just in front of an identifier quoted with backticks. + +When match is successful, match-data will contain: + (match-text 1) - opening backtick + (match-text 2) - whole qualified identifier + (match-text 3) - unqualified part of identifier + (match-text 4) - closing backtick" + (let ((match-data-old (match-data)) + first-backtick-start + last-backtick-start + qid-start + id-start + id-end + result) + (save-excursion + (when (looking-at "`") + (setq first-backtick-start (match-beginning 0)) + (goto-char (match-end 0)) + (forward-comment (buffer-size)) + (when (haskell-lexeme-looking-at-qidsym) + (setq qid-start (match-beginning 0)) + (setq id-start (match-beginning 1)) + (setq id-end (match-end 1)) + (goto-char (match-end 0)) + (forward-comment (buffer-size)) + (when (looking-at "`") + (setq last-backtick-start (match-beginning 0)) + (set-match-data + (mapcar + (lambda (p) + (set-marker (make-marker) p)) + (list + first-backtick-start (1+ last-backtick-start) + first-backtick-start (1+ first-backtick-start) + qid-start id-end + id-start id-end + last-backtick-start (1+ last-backtick-start)))) + (setq result t))))) + (unless result + (set-match-data match-data-old)) + result)) + +(defconst haskell-lexeme-qid + (rx-to-string `(: (regexp "'*") + (regexp ,haskell-lexeme-modid-opt-prefix) + (group (regexp ,haskell-lexeme-id)))) + "Regexp matching a valid qualified identifier. + +Note that (match-string 1) returns the unqualified part.") + +(defconst haskell-lexeme-qsym + (rx-to-string `(: (regexp "'*") + (regexp ,haskell-lexeme-modid-opt-prefix) + (group (regexp ,haskell-lexeme-id)))) + "Regexp matching a valid qualified symbol. + +Note that (match-string 1) returns the unqualified part.") + +(defconst haskell-lexeme-number + (rx (| (: (regexp "[0-9]+\\.[0-9]+") (opt (regexp "[eE][-+]?[0-9]+"))) + (regexp "[0-9]+[eE][-+]?[0-9]+") + (regexp "0[xX][0-9a-fA-F]+") + (regexp "0[oO][0-7]+") + (regexp "[0-9]+"))) + "Regexp matching a floating point, decimal, octal or hexadecimal number. + +Note that negative sign char is not part of a number.") + +(defconst haskell-lexeme-char-literal-inside + (rx (| (not (any "\n'\\")) + (: "\\" + (| "a" "b" "f" "n" "r" "t" "v" "\\" "\"" "'" + "NUL" "SOH" "STX" "ETX" "EOT" "ENQ" "ACK" + "BEL" "BS" "HT" "LF" "VT" "FF" "CR" "SO" "SI" "DLE" + "DC1" "DC2" "DC3" "DC4" "NAK" "SYN" "ETB" "CAN" + "EM" "SUB" "ESC" "FS" "GS" "RS" "US" "SP" "DEL" + (regexp "[0-9]+") + (: "x" (regexp "[0-9a-fA-F]+")) + (: "o" (regexp "[0-7]+")) + (: "^" (regexp "[]A-Z@^_\\[]")))))) + "Regexp matching an inside of a character literal. + +Note that `haskell-lexeme-char-literal-inside' matches strictly +only escape sequences defined in Haskell Report.") + +(defconst haskell-lexeme--char-literal-rx + (rx-to-string `(: (group "'") + (| (: (group (regexp "[[:alpha:]_([]")) (group "'")) ; exactly one char + (: (group (| (regexp "\\\\[^\n][^'\n]*") ; allow quote just after first backslash + (regexp "[^[:alpha:]_:(['\n][^'\n]*"))) + (| (group "'") "\n" (regexp "\\'")))))) + "Regexp matching a character literal lookalike. + +Note that `haskell-lexeme--char-literal-rx' matches more than +Haskell Report specifies because we want to support also code +under edit. + +Character literals end with a quote or a newline or end of +buffer. + +Regexp has subgroup expressions: + (match-text 1) matches the opening quote. + (match-text 2) matches the inside of the character literal. + (match-text 3) matches the closing quote or an empty string + at the end of line or the end buffer.") + +(defun haskell-lexeme-looking-at-char-literal () + "Non-nil when point is at a char literal lookalike. + +Note that this function matches more than Haskell Report +specifies because we want to support also code under edit. + +Char literals end with a quote or an unescaped newline or end +of buffer. + +After successful match: + (match-text 1) matches the opening quote. + (match-text 2) matches the inside of the char literla. + (match-text 3) matches the closing quote, or a closing + newline or is nil when at the end of the buffer." + (when (looking-at haskell-lexeme--char-literal-rx) + (set-match-data + (list (match-beginning 0) (match-end 0) + (match-beginning 1) (match-end 1) + (or (match-beginning 2) (match-beginning 4)) (or (match-end 2) (match-end 4)) + (or (match-beginning 3) (match-beginning 5)) (or (match-end 3) (match-end 5)))) + t)) + +(defconst haskell-lexeme-string-literal-inside-item + (rx (| (not (any "\n\"\\")) + (: "\\" + (| "a" "b" "f" "n" "r" "t" "v" "\\" "\"" "'" "&" + "NUL" "SOH" "STX" "ETX" "EOT" "ENQ" "ACK" + "BEL" "BS" "HT" "LF" "VT" "FF" "CR" "SO" "SI" "DLE" + "DC1" "DC2" "DC3" "DC4" "NAK" "SYN" "ETB" "CAN" + "EM" "SUB" "ESC" "FS" "GS" "RS" "US" "SP" "DEL" + (regexp "[0-9]+") + (: "x" (regexp "[0-9a-fA-F]+")) + (: "o" (regexp "[0-7]+")) + (: "^" (regexp "[]A-Z@^_\\[]")) + (regexp "[ \t\n\r\v\f]*\\\\"))))) + "Regexp matching an item that is a single character or a single +escape sequence inside of a string literal. + +Note that `haskell-lexeme-string-literal-inside-item' matches +strictly only escape sequences defined in Haskell Report.") + +(defconst haskell-lexeme-string-literal + (rx (: (group "\"") + (group (* (| (regexp "\\\\[ \t\n\r\v\f]*\\\\") + (regexp "\\\\[ \t\n\r\v\f]+") + (regexp "\\\\[^ \t\n\r\v\f]") + (* (regexp "[^\"\n\\]"))))) + (group (| "\"" (regexp "$") (regexp "\\\\?\\'") + )))) + "Regexp matching a string literal lookalike. + +Note that `haskell-lexeme-string-literal' matches more than +Haskell Report specifies because we want to support also code +under edit. + +String literals end with double quote or unescaped newline or end +of buffer. + +Regexp has subgroup expressions: + (match-text 1) matches the opening double quote. + (match-text 2) matches the inside of the string. + (match-text 3) matches the closing double quote or an empty string + at the end of line or the end buffer.") + +(defun haskell-lexeme-looking-at-string-literal () + "Non-nil when point is at a string literal lookalike. + +Note that this function matches more than Haskell Report +specifies because we want to support also code under edit. + +String literals end with double quote or unescaped newline or end +of buffer. + +After successful match: + (match-text 1) matches the opening doublequote. + (match-text 2) matches the inside of the string. + (match-text 3) matches the closing quote, or a closing + newline or is nil when at the end of the buffer." + (when (looking-at "\"") + (save-excursion + (let ((begin (point))) + (goto-char (match-end 0)) + (let (finish) + (while (and (not finish) + (re-search-forward "[\"\n\\]" nil 'goto-eob)) + (cond + ((equal (match-string 0) "\\") + (if (looking-at "[ \t\n\r\v\f]+\\\\?") + (goto-char (match-end 0)) + (goto-char (1+ (point))))) + + ((equal (match-string 0) "\"") + (set-match-data + (list begin (match-end 0) + begin (1+ begin) + (1+ begin) (match-beginning 0) + (match-beginning 0) (match-end 0))) + (setq finish t)) + + ((equal (match-string 0) "\n") + (set-match-data + (list begin (match-beginning 0) + begin (1+ begin) + (1+ begin) (match-beginning 0) + nil nil)) + (setq finish t)))) + (unless finish + ;; string closed by end of buffer + (set-match-data + (list begin (point) + begin (1+ begin) + (1+ begin) (point) + nil nil)))))) + ;; there was a match + t)) + +(defun haskell-lexeme-looking-at-quasi-quote-literal () + "Non-nil when point is just in front of Template Haskell +quaisquote literal. + +Quasi quotes start with '[xxx|' or '[$xxx|' sequence and end with + '|]'. The 'xxx' is a quoter name. There is no escaping mechanism +provided for the ending sequence. + +Regexp has subgroup expressions: + (match-text 1) matches the quoter name (without $ sign if present). + (match-text 2) matches the opening vertical bar. + (match-text 3) matches the inside of the quoted string. + (match-text 4) matches the closing vertical bar + or nil if at the end of the buffer. + +Note that this function excludes 'e', 't', 'd', 'p' as quoter +names according to Template Haskell specification." + (let ((match-data-old (match-data))) + (if (and + (looking-at (rx-to-string `(: "[" (optional "$") + (group (regexp ,haskell-lexeme-id)) + (group "|")))) + (equal (haskell-lexeme-classify-by-first-char (char-after (match-beginning 1))) + 'varid) + (not (member (match-string 1) '("e" "t" "d" "p")))) + (save-excursion + ;; note that quasi quote syntax does not have any escaping + ;; mechanism and if not closed it will span til lthe end of buffer + (goto-char (match-end 0)) + (let ((match-data (match-data)) + (match-data-2 (and (re-search-forward "|]" nil t) + (match-data)))) + (if match-data-2 + (set-match-data + (list + (nth 0 match-data) (nth 1 match-data-2) ;; whole match + (nth 2 match-data) (nth 3 match-data) ;; quoter name + (nth 4 match-data) (nth 5 match-data) ;; opening bar + (nth 5 match-data) (nth 0 match-data-2) ;; inner string + (nth 0 match-data-2) (1+ (nth 0 match-data-2)))) ;; closing bar + + (set-match-data + (list + (nth 0 match-data) (point-max) ;; whole match + (nth 2 match-data) (nth 3 match-data) ;; quoter name + (nth 4 match-data) (nth 5 match-data) ;; opening bar + (nth 5 match-data) (point-max) ;; inner string + nil nil)) ;; closing bar + )) + t) + ;; restore old match data if not matched + (set-match-data match-data-old) + nil))) + +(defun haskell-lexeme-classify-by-first-char (char) + "Classify token by CHAR. + +CHAR is a chararacter that is assumed to be the first character +of a token." + (let ((category (get-char-code-property (or char ?\ ) 'general-category))) + + (cond + ((or (member char '(?! ?# ?$ ?% ?& ?* ?+ ?. ?/ ?< ?= ?> ?? ?@ ?^ ?| ?~ ?\\ ?-)) + (and (> char 127) + (member category '(Pc Pd Po Sm Sc Sk So)))) + 'varsym) + ((equal char ?:) + 'consym) + ((equal char ?\') + 'char) + ((equal char ?\") + 'string) + ((member category '(Lu Lt)) + 'conid) + ((or (equal char ?_) + (member category '(Ll Lo))) + 'varid) + ((and (>= char ?0) (<= char ?9)) + 'number) + ((member char '(?\] ?\[ ?\( ?\) ?\{ ?\} ?\` ?\, ?\;)) + 'special)))) + +(defun haskell-lexeme-looking-at-token (&rest flags) + "Like `looking-at' but understands Haskell lexemes. + +Moves point forward over whitespace. Returns a symbol describing +type of Haskell token recognized. Use `match-string', +`match-beginning' and `match-end' with argument 0 to query match +result. + +Possible results are: +- 'special: for chars [](){}`,; +- 'comment: for single line comments +- 'nested-comment: for multiline comments +- 'qsymid: for qualified identifiers or symbols +- 'string: for strings literals +- 'char: for char literals +- 'number: for decimal, float, hexadecimal and octal number literals +- 'template-haskell-quote: for a string of apostrophes for template haskell +- 'template-haskell-quasi-quote: for a string of apostrophes for template haskell + +Note that for qualified symbols (match-string 1) returns the +unqualified identifier or symbol. Further qualification for +symbol or identifier can be done with: + + (haskell-lexeme-classify-by-first-char (char-after (match-beginning 1))) + +See `haskell-lexeme-classify-by-first-char' for details." + (while + ;; Due to how unterminated strings terminate at newline, some + ;; newlines have syntax set to generic string delimeter. We want + ;; those to be treated as whitespace anyway + (or + (> (skip-syntax-forward "-") 0) + (and (not (member 'newline flags)) + (> (skip-chars-forward "\n") 0)))) + (let + ((case-fold-search nil) + (point (point-marker))) + (or + (and + (equal (string-to-syntax "<") + (get-char-property (point) 'syntax-table)) + (progn + (set-match-data (list point (set-marker (make-marker) (line-end-position)))) + 'literate-comment)) + (and (looking-at "\n") + 'newline) + (and (looking-at "{-") + (save-excursion + (forward-comment 1) + (set-match-data (list point (point-marker))) + 'nested-comment)) + (and (haskell-lexeme-looking-at-char-literal) + 'char) + (and (haskell-lexeme-looking-at-string-literal) + 'string) + (and (looking-at "[][(){}`,;]") + (if (haskell-lexeme-looking-at-quasi-quote-literal) + 'template-haskell-quasi-quote + 'special)) + (and (haskell-lexeme-looking-at-qidsym) + (if (save-match-data + (string-match "\\`---*\\'" (match-string-no-properties 0))) + (progn + (set-match-data (list point (set-marker (make-marker) (line-end-position)))) + 'comment) + 'qsymid)) + (and (looking-at haskell-lexeme-number) + 'number) + (and (looking-at "'+") + 'template-haskell-quote) + (and (looking-at ".") + 'illegal)))) + +(provide 'haskell-lexeme) + +;;; haskell-lexeme.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-lexeme.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-lexeme.elc new file mode 100644 index 000000000000..1ea9b604e92e --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-lexeme.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-load.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-load.el new file mode 100644 index 000000000000..fb8bd98f3aff --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-load.el @@ -0,0 +1,632 @@ +;;; haskell-load.el --- Compiling and loading modules in the GHCi process -*- lexical-binding: t -*- + +;; Copyright © 2014 Chris Done. All rights reserved. +;; 2016 Arthur Fayzrakhmanov + +;; 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) +(require 'haskell-mode) +(require 'haskell-process) +(require 'haskell-interactive-mode) +(require 'haskell-modules) +(require 'haskell-commands) +(require 'haskell-session) +(require 'haskell-string) + +(defun haskell-process-look-config-changes (session) + "Check whether a cabal configuration file has changed. +Restarts the SESSION's process if that is the case." + (let ((current-checksum (haskell-session-get session 'cabal-checksum)) + (new-checksum (haskell-cabal-compute-checksum + (haskell-session-get session 'cabal-dir)))) + (when (not (string= current-checksum new-checksum)) + (haskell-interactive-mode-echo + session + (format "Cabal file changed: %s" new-checksum)) + (haskell-session-set-cabal-checksum + session + (haskell-session-get session 'cabal-dir)) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (unless + (and haskell-process-prompt-restart-on-cabal-change + (not + (y-or-n-p "Cabal file changed. Restart GHCi process? "))) + (haskell-process-start (haskell-interactive-session))) + (haskell-mode-toggle-interactive-prompt-state t))))) + +(defun haskell-process-live-build (process buffer echo-in-repl) + "Show live updates for loading files." + (cond + ((haskell-process-consume + process + (concat "\\[[ ]*\\([0-9]+\\) of \\([0-9]+\\)\\]" + " Compiling \\([^ ]+\\)[ ]+" + "( \\([^ ]+\\), \\([^ ]+\\) )[^\r\n]*[\r\n]+")) + (haskell-process-echo-load-message process buffer echo-in-repl nil) + t) + ((haskell-process-consume + process + (concat "\\[[ ]*\\([0-9]+\\) of \\([0-9]+\\)\\]" + " Compiling \\[TH\\] \\([^ ]+\\)[ ]+" + "( \\([^ ]+\\), \\([^ ]+\\) )[^\r\n]*[\r\n]+")) + (haskell-process-echo-load-message process buffer echo-in-repl t) + t) + ((haskell-process-consume + process + "Loading package \\([^ ]+\\) ... linking ... done.\n") + (haskell-mode-message-line + (format "Loading: %s" + (match-string 1 buffer))) + t) + ((haskell-process-consume + process + "^Preprocessing executables for \\(.+?\\)\\.\\.\\.") + (let ((msg (format "Preprocessing: %s" (match-string 1 buffer)))) + (haskell-interactive-mode-echo (haskell-process-session process) msg) + (haskell-mode-message-line msg))) + ((haskell-process-consume process "Linking \\(.+?\\) \\.\\.\\.") + (let ((msg (format "Linking: %s" (match-string 1 buffer)))) + (haskell-interactive-mode-echo (haskell-process-session process) msg) + (haskell-mode-message-line msg))) + ((haskell-process-consume process "\nBuilding \\(.+?\\)\\.\\.\\.") + (let ((msg (format "Building: %s" (match-string 1 buffer)))) + (haskell-interactive-mode-echo (haskell-process-session process) msg) + (haskell-mode-message-line msg))) + ((string-match "Collecting type info for [[:digit:]]+ module(s) \\.\\.\\." + (haskell-process-response process) + (haskell-process-response-cursor process)) + (haskell-mode-message-line (match-string 0 buffer)) + ;; Do not consume "Ok, modules loaded" that goes before + ;; "Collecting type info...", just exit. + nil))) + +(defun haskell-process-load-complete (session process buffer reload module-buffer &optional cont) + "Handle the complete loading response. BUFFER is the string of +text being sent over the process pipe. MODULE-BUFFER is the +actual Emacs buffer of the module being loaded." + (when (get-buffer (format "*%s:splices*" (haskell-session-name session))) + (with-current-buffer (haskell-interactive-mode-splices-buffer session) + (erase-buffer))) + (let* ((ok (cond + ((haskell-process-consume + process + "Ok, \\(?:[0-9]+\\) modules? loaded\\.$") + t) + ((haskell-process-consume + process + "Failed, \\(?:[0-9]+\\) modules? loaded\\.$") + nil) + ((haskell-process-consume + process + "Ok, modules loaded: \\(.+\\)\\.$") + t) + ((haskell-process-consume + process + "Failed, modules loaded: \\(.+\\)\\.$") + nil) + (t + (error (message "Unexpected response from haskell process."))))) + (modules (haskell-process-extract-modules buffer)) + (cursor (haskell-process-response-cursor process)) + (warning-count 0)) + (haskell-process-set-response-cursor process 0) + (haskell-check-remove-overlays module-buffer) + (while + (haskell-process-errors-warnings module-buffer session process buffer) + (setq warning-count (1+ warning-count))) + (haskell-process-set-response-cursor process cursor) + (if (and (not reload) + haskell-process-reload-with-fbytecode) + (haskell-process-reload-with-fbytecode process module-buffer) + (haskell-process-import-modules process (car modules))) + (if ok + (haskell-mode-message-line (if reload "Reloaded OK." "OK.")) + (haskell-interactive-mode-compile-error session "Compilation failed.")) + (when cont + (condition-case-unless-debug e + (funcall cont ok) + (error (message "%S" e)) + (quit nil))))) + +(defun haskell-process-suggest-imports (session file modules ident) + "Suggest add missed imports to file. +Asks user to add to SESSION's FILE missed import. MODULES is a +list of modules where missed IDENT was found." + (cl-assert session) + (cl-assert file) + (cl-assert ident) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (let* ((process (haskell-session-process session)) + (suggested-already (haskell-process-suggested-imports process)) + (module + (cond + ((> (length modules) 1) + (when (y-or-n-p + (format + "Identifier `%s' not in scope, choose module to import?" + ident)) + (haskell-complete-module-read "Module: " modules))) + ((= (length modules) 1) + (let ((module (car modules))) + (unless (member module suggested-already) + (haskell-process-set-suggested-imports + process + (cons module suggested-already)) + (when (y-or-n-p + (format "Identifier `%s' not in scope, import `%s'?" + ident + module)) + module))))))) + (when module + (haskell-process-find-file session file) + (haskell-add-import module))) + (haskell-mode-toggle-interactive-prompt-state t))) + +(defun haskell-process-trigger-suggestions (session msg file line) + "Trigger prompting to add any extension suggestions." + (cond ((let ((case-fold-search nil)) + (or + (and (string-match " -X\\([A-Z][A-Za-z]+\\)" msg) + (not (string-match "\\([A-Z][A-Za-z]+\\) is deprecated" msg))) + (string-match "Use \\([A-Z][A-Za-z]+\\) to permit this" msg) + (string-match "Use \\([A-Z][A-Za-z]+\\) to allow" msg) + (string-match "Use \\([A-Z][A-Za-z]+\\) to enable" msg) + (string-match + "Use \\([A-Z][A-Za-z]+\\) if you want to disable this" + msg) + (string-match "use \\([A-Z][A-Za-z]+\\)" msg) + (string-match "You need \\([A-Z][A-Za-z]+\\)" msg))) + (when haskell-process-suggest-language-pragmas + (haskell-process-suggest-pragma + session + "LANGUAGE" + (match-string 1 msg) + file))) + ((string-match + " The \\(qualified \\)?import of[ ][‘`‛]\\([^ ]+\\)['’] is redundant" + msg) + (when haskell-process-suggest-remove-import-lines + (haskell-process-suggest-remove-import + session + file + (match-string 2 msg) + line))) + ((string-match "[Ww]arning: orphan instance: " msg) + (when haskell-process-suggest-no-warn-orphans + (haskell-process-suggest-pragma + session + "OPTIONS" "-fno-warn-orphans" + file))) + ((or (string-match "against inferred type [‘`‛]\\[Char\\]['’]" msg) + (string-match "with actual type [‘`‛]\\[Char\\]['’]" msg)) + (when haskell-process-suggest-overloaded-strings + (haskell-process-suggest-pragma + session + "LANGUAGE" "OverloadedStrings" + file))) + ((string-match "^Not in scope: .*[‘`‛]\\(.+\\)['’]$" msg) + (let* ((match1 (match-string 1 msg)) + (ident (if (string-match "^[A-Za-z0-9_'.]+\\.\\(.+\\)$" match1) + ;; Skip qualification. + (match-string 1 match1) + match1))) + (when haskell-process-suggest-hoogle-imports + (let ((modules (haskell-process-hoogle-ident ident))) + (haskell-process-suggest-imports session file modules ident))) + (when haskell-process-suggest-haskell-docs-imports + (let ((modules (haskell-process-haskell-docs-ident ident))) + (haskell-process-suggest-imports session file modules ident))) + (when haskell-process-suggest-hayoo-imports + (let ((modules (haskell-process-hayoo-ident ident))) + (haskell-process-suggest-imports session file modules ident))))) + ((string-match "^[ ]+It is a member of the hidden package [‘`‛]\\([^@\r\n]+\\).*['’].$" msg) + (when haskell-process-suggest-add-package + (haskell-process-suggest-add-package session msg))))) + +(defun haskell-process-do-cabal (command) + "Run a Cabal command." + (let ((process (ignore-errors + (haskell-interactive-process)))) + (cond + ((or (eq process nil) + (let ((child (haskell-process-process process))) + (not (equal 'run (process-status child))))) + (message "Process is not running, so running directly.") + (shell-command (concat "cabal " command) + (get-buffer-create "*haskell-process-log*") + (get-buffer-create "*haskell-process-log*")) + (switch-to-buffer-other-window (get-buffer "*haskell-process-log*"))) + (t (haskell-process-queue-command + process + (make-haskell-command + :state (list (haskell-interactive-session) process command 0) + :go + (lambda (state) + (haskell-process-send-string + (cadr state) + (format haskell-process-do-cabal-format-string + (haskell-session-cabal-dir (car state)) + (format "%s %s" + (cl-ecase (haskell-process-type) + ('ghci haskell-process-path-cabal) + ('cabal-repl haskell-process-path-cabal) + ('cabal-new-repl haskell-process-path-cabal) + ('cabal-ghci haskell-process-path-cabal) + ('stack-ghci haskell-process-path-stack)) + (cl-caddr state))))) + :live + (lambda (state buffer) + (let ((cmd (replace-regexp-in-string "^\\([a-z]+\\).*" + "\\1" + (cl-caddr state)))) + (cond ((or (string= cmd "build") + (string= cmd "install")) + (haskell-process-live-build (cadr state) buffer t)) + (t + (haskell-process-cabal-live state buffer))))) + :complete + (lambda (state response) + (let* ((process (cadr state)) + (session (haskell-process-session process)) + (message-count 0) + (cursor (haskell-process-response-cursor process))) + ;; XXX: what the hell about the rampant code duplication? + (haskell-process-set-response-cursor process 0) + (while (haskell-process-errors-warnings nil session process response) + (setq message-count (1+ message-count))) + (haskell-process-set-response-cursor process cursor) + (let ((msg (format "Complete: cabal %s (%s compiler messages)" + (cl-caddr state) + message-count))) + (haskell-interactive-mode-echo session msg) + (when (= message-count 0) + (haskell-interactive-mode-echo + session + "No compiler messages, dumping complete output:") + (haskell-interactive-mode-echo session response)) + (haskell-mode-message-line msg) + (when (and haskell-notify-p + (fboundp 'notifications-notify)) + (notifications-notify + :title (format "*%s*" (haskell-session-name (car state))) + :body msg + :app-name (cl-ecase (haskell-process-type) + ('ghci haskell-process-path-cabal) + ('cabal-repl haskell-process-path-cabal) + ('cabal-new-repl haskell-process-path-cabal) + ('cabal-ghci haskell-process-path-cabal) + ('stack-ghci haskell-process-path-stack)) + :app-icon haskell-process-logo))))))))))) + +(defun haskell-process-echo-load-message (process buffer echo-in-repl th) + "Echo a load message." + (let ((session (haskell-process-session process)) + (module-name (match-string 3 buffer)) + (file-name (match-string 4 buffer))) + (haskell-interactive-show-load-message + session + 'compiling + module-name + (haskell-session-strip-dir session file-name) + echo-in-repl + th))) + +(defun haskell-process-extract-modules (buffer) + "Extract the modules from the process buffer." + (let* ((modules-string (match-string 1 buffer)) + (modules (and modules-string (split-string modules-string ", ")))) + (cons modules modules-string))) + +;;;###autoload +(defface haskell-error-face + '((((supports :underline (:style wave))) + :underline (:style wave :color "#dc322f")) + (t + :inherit error)) + "Face used for marking error lines." + :group 'haskell-mode) + +;;;###autoload +(defface haskell-warning-face + '((((supports :underline (:style wave))) + :underline (:style wave :color "#b58900")) + (t + :inherit warning)) + "Face used for marking warning lines." + :group 'haskell-mode) + +;;;###autoload +(defface haskell-hole-face + '((((supports :underline (:style wave))) + :underline (:style wave :color "#6c71c4")) + (t + :inherit warning)) + "Face used for marking hole lines." + :group 'haskell-mode) + +(defvar haskell-check-error-fringe (propertize "!" 'display '(left-fringe exclamation-mark))) +(defvar haskell-check-warning-fringe (propertize "?" 'display '(left-fringe question-mark))) +(defvar haskell-check-hole-fringe (propertize "_" 'display '(left-fringe horizontal-bar))) + +(defun haskell-check-overlay-p (ovl) + (overlay-get ovl 'haskell-check)) + +(defun haskell-check-filter-overlays (xs) + (cl-remove-if-not 'haskell-check-overlay-p xs)) + +(defun haskell-check-remove-overlays (buffer) + (with-current-buffer buffer + (remove-overlays (point-min) (point-max) 'haskell-check t))) + +(defmacro haskell-with-overlay-properties (proplist ovl &rest body) + "Evaluate BODY with names in PROPLIST bound to the values of +correspondingly-named overlay properties of OVL." + (let ((ovlvar (cl-gensym "OVL-"))) + `(let* ((,ovlvar ,ovl) + ,@(mapcar (lambda (p) `(,p (overlay-get ,ovlvar ',p))) proplist)) + ,@body))) + +(defun haskell-overlay-start> (o1 o2) + (> (overlay-start o1) (overlay-start o2))) +(defun haskell-overlay-start< (o1 o2) + (< (overlay-start o1) (overlay-start o2))) + +(defun haskell-first-overlay-in-if (test beg end) + (let ((ovls (cl-remove-if-not test (overlays-in beg end)))) + (cl-first (sort (cl-copy-list ovls) 'haskell-overlay-start<)))) + +(defun haskell-last-overlay-in-if (test beg end) + (let ((ovls (cl-remove-if-not test (overlays-in beg end)))) + (cl-first (sort (cl-copy-list ovls) 'haskell-overlay-start>)))) + +(defun haskell-error-overlay-briefly (ovl) + (haskell-with-overlay-properties + (haskell-msg haskell-msg-type) ovl + (cond + ((not (eq haskell-msg-type 'warning)) + haskell-msg) + ((string-prefix-p "[Ww]arning:\n " haskell-msg) + (cl-subseq haskell-msg 13)) + (t + (error + "Invariant failed: a warning message from GHC has unexpected form: %s." + haskell-msg))))) + +(defun haskell-goto-error-overlay (ovl) + (cond (ovl + (goto-char (overlay-start ovl)) + (haskell-mode-message-line (haskell-error-overlay-briefly ovl))) + (t + (message "No further notes from Haskell compiler.")))) + +(defun haskell-goto-first-error () + (interactive) + (haskell-goto-error-overlay + (haskell-first-overlay-in-if 'haskell-check-overlay-p + (buffer-end 0) (buffer-end 1)))) + +(defun haskell-goto-prev-error () + (interactive) + (haskell-goto-error-overlay + (let ((ovl-at + (cl-first (haskell-check-filter-overlays (overlays-at (point)))))) + (or (haskell-last-overlay-in-if 'haskell-check-overlay-p + (point-min) + (if ovl-at (overlay-start ovl-at) (point))) + ovl-at)))) + +(defun haskell-goto-next-error () + (interactive) + (haskell-goto-error-overlay + (let ((ovl-at + (cl-first (haskell-check-filter-overlays (overlays-at (point)))))) + (or (haskell-first-overlay-in-if + 'haskell-check-overlay-p + (if ovl-at (overlay-end ovl-at) (point)) (point-max)) + ovl-at)))) + +(defun haskell-check-paint-overlay + (buffer error-from-this-file-p line msg file type hole coln) + (with-current-buffer buffer + (let (beg end) + (goto-char (point-min)) + ;; XXX: we can avoid excess buffer walking by relying on the maybe-fact + ;; that GHC sorts error messages by line number, maybe. + (cond + (error-from-this-file-p + (forward-line (1- line)) + (forward-char (1- coln)) + (setq beg (point)) + (if (eq type 'hole) + (forward-char (length hole)) + (skip-chars-forward "^[:space:]" (line-end-position))) + (setq end (point))) + (t + (setq beg (point)) + (forward-line) + (setq end (point)))) + (let ((ovl (make-overlay beg end))) + (overlay-put ovl 'haskell-check t) + (overlay-put ovl 'haskell-file file) + (overlay-put ovl 'haskell-msg msg) + (overlay-put ovl 'haskell-msg-type type) + (overlay-put ovl 'help-echo msg) + (overlay-put ovl 'haskell-hole hole) + (cl-destructuring-bind + (face fringe) + (cl-case type + (warning + (list 'haskell-warning-face haskell-check-warning-fringe)) + (hole + (list 'haskell-hole-face haskell-check-hole-fringe)) + (error + (list 'haskell-error-face haskell-check-error-fringe))) + (overlay-put ovl 'before-string fringe) + (overlay-put ovl 'face face)))))) + +(defun haskell-process-errors-warnings + (module-buffer session process buffer &optional return-only) + "Trigger handling type errors or warnings. +Either prints the messages in the interactive buffer or if CONT +is specified, passes the error onto that. + +When MODULE-BUFFER is non-NIL, paint error overlays." + (save-excursion + (cond + ((haskell-process-consume + process + "\\(Module imports form a cycle:[ \n]+module [^ ]+ ([^)]+)[[:unibyte:][:nonascii:]]+?\\)\nFailed") + (let ((err (match-string 1 buffer))) + (if (string-match "module [`'‘‛]\\([^ ]+\\)['’`] (\\([^)]+\\))" err) + (let* ((default-directory (haskell-session-current-dir session)) + (module (match-string 1 err)) + (file (match-string 2 err)) + (relative-file-name (file-relative-name file))) + (unless return-only + (haskell-interactive-show-load-message + session + 'import-cycle + module + relative-file-name + nil + nil) + (haskell-interactive-mode-compile-error + session + (format "%s:1:0: %s" + relative-file-name + err))) + (list :file file :line 1 :col 0 :msg err :type 'error)) + t))) + ((haskell-process-consume + process + (concat "[\r\n]\\([A-Z]?:?[^ \r\n:][^:\n\r]+\\):\\([0-9()-:]+\\):" + "[ \n\r]+\\([[:unibyte:][:nonascii:]]+?\\)\n[^ ]")) + (haskell-process-set-response-cursor + process + (- (haskell-process-response-cursor process) 1)) + (let* ((buffer (haskell-process-response process)) + (file (match-string 1 buffer)) + (location-raw (match-string 2 buffer)) + (error-msg (match-string 3 buffer)) + (type (cond ((string-match "^[Ww]arning:" error-msg) 'warning) + ((string-match "^Splicing " error-msg) 'splice) + (t 'error))) + (critical (not (eq type 'warning))) + ;; XXX: extract hole information, pass down to + ;; `haskell-check-paint-overlay' + (final-msg (format "%s:%s: %s" + (haskell-session-strip-dir session file) + location-raw + error-msg)) + (location (haskell-process-parse-error + (concat file ":" location-raw ": x"))) + (line (plist-get location :line)) + (col1 (plist-get location :col))) + (when (and module-buffer haskell-process-show-overlays) + (haskell-check-paint-overlay + module-buffer + (string= (file-truename (buffer-file-name module-buffer)) + (file-truename file)) + line error-msg file type nil col1)) + (if return-only + (list :file file :line line :col col1 :msg error-msg :type type) + (progn (funcall (cl-case type + (warning 'haskell-interactive-mode-compile-warning) + (splice 'haskell-interactive-mode-compile-splice) + (error 'haskell-interactive-mode-compile-error)) + session final-msg) + (when critical + (haskell-mode-message-line final-msg)) + (haskell-process-trigger-suggestions + session + error-msg + file + line) + t))))))) + +(defun haskell-interactive-show-load-message (session type module-name file-name echo th) + "Show the '(Compiling|Loading) X' message." + (let ((msg (concat + (cl-ecase type + ('compiling + (if haskell-interactive-mode-include-file-name + (format "Compiling: %s (%s)" module-name file-name) + (format "Compiling: %s" module-name))) + ('loading (format "Loading: %s" module-name)) + ('import-cycle + (format "Module has an import cycle: %s" module-name))) + (if th " [TH]" "")))) + (haskell-mode-message-line msg) + (when haskell-interactive-mode-delete-superseded-errors + (haskell-interactive-mode-delete-compile-messages session file-name)) + (when echo + (haskell-interactive-mode-echo session msg)))) + +;;;###autoload +(defun haskell-process-reload-devel-main () + "Reload the module `DevelMain' and then run `DevelMain.update'. + +This is for doing live update of the code of servers or GUI +applications. Put your development version of the program in +`DevelMain', and define `update' to auto-start the program on a +new thread, and use the `foreign-store' package to access the +running context across :load/:reloads in GHCi." + (interactive) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (with-current-buffer + (or (get-buffer "DevelMain.hs") + (if (y-or-n-p + "You need to open a buffer named DevelMain.hs. Find now?") + (ido-find-file) + (error "No DevelMain.hs buffer."))) + (let ((session (haskell-interactive-session))) + (let ((process (haskell-interactive-process))) + (haskell-process-queue-command + process + (make-haskell-command + :state (list :session session + :process process + :buffer (current-buffer)) + :go (lambda (state) + (haskell-process-send-string (plist-get state ':process) + ":l DevelMain")) + :live (lambda (state buffer) + (haskell-process-live-build (plist-get state ':process) + buffer + nil)) + :complete (lambda (state response) + (haskell-process-load-complete + (plist-get state ':session) + (plist-get state ':process) + response + nil + (plist-get state ':buffer) + (lambda (ok) + (when ok + (haskell-process-queue-without-filters + (haskell-interactive-process) + "DevelMain.update") + (message "DevelMain updated.")))))))))) + (haskell-mode-toggle-interactive-prompt-state t))) + +(provide 'haskell-load) +;;; haskell-load.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-load.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-load.elc new file mode 100644 index 000000000000..e03be46bc695 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-load.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-menu.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-menu.el new file mode 100644 index 000000000000..7e1f1b0b7b4d --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-menu.el @@ -0,0 +1,162 @@ +;;; haskell-menu.el --- A Haskell sessions menu -*- lexical-binding: t -*- + +;; Copyright (C) 2013 Chris Done + +;; Author: Chris Done <chrisdone@gmail.com> + +;; This file is not part of GNU Emacs. + +;; 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 GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;;; Todo: + +;;; Code: + +(require 'cl-lib) +(require 'haskell-compat) +(require 'haskell-session) +(require 'haskell-process) +(require 'haskell-interactive-mode) + +(defcustom haskell-menu-buffer-name "*haskell-menu*" + "The name of the Haskell session menu buffer" + :group 'haskell-interactive + :type 'string) + +;;;###autoload +(defun haskell-menu () + "Launch the Haskell sessions menu." + (interactive) + (or (get-buffer haskell-menu-buffer-name) + (with-current-buffer (get-buffer-create haskell-menu-buffer-name) + (haskell-menu-mode))) + (switch-to-buffer-other-window (get-buffer haskell-menu-buffer-name)) + (haskell-menu-revert-function nil nil)) + +(defvar haskell-menu-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "n") 'next-line) + (define-key map (kbd "p") 'previous-line) + (define-key map (kbd "RET") 'haskell-menu-mode-ret) + map) + "Keymap for `haskell-menu-mode'.") + +(define-derived-mode haskell-menu-mode special-mode "Haskell Session Menu" + "Major mode for managing Haskell sessions. +Each line describes one session. +Letters do not insert themselves; instead, they are commands." + (setq buffer-read-only t) + (setq-local revert-buffer-function 'haskell-menu-revert-function) + (setq truncate-lines t) + (haskell-menu-revert-function nil t)) + +(suppress-keymap haskell-menu-mode-map t) + +(defun haskell-menu-revert-function (_arg1 _arg2) + "Function to refresh the display." + (let ((buffer-read-only nil) + (orig-line (line-number-at-pos)) + (orig-col (current-column))) + (or (eq buffer-undo-list t) + (setq buffer-undo-list nil)) + (erase-buffer) + (haskell-menu-insert-menu) + (goto-char (point-min)) + (forward-line (1- orig-line)) + (forward-char orig-col))) + +(defun haskell-menu-insert-menu () + "Insert the Haskell sessions menu to the current buffer." + (if (null haskell-sessions) + (insert "No Haskell sessions.") + (haskell-menu-tabulate + (list "Name" "PID" "Time" "RSS" "Cabal directory" "Working directory" "Command") + (mapcar (lambda (session) + (let ((process (haskell-process-process (haskell-session-process session)))) + (cond + (process + (let ((id (process-id process))) + (list (propertize (haskell-session-name session) 'face 'buffer-menu-buffer) + (if (process-live-p process) (number-to-string id) "-") + (if (process-live-p process) + (format-time-string "%H:%M:%S" + (encode-time (cl-caddr (assoc 'etime (process-attributes id))) + 0 0 0 0 0)) + "-") + (if (process-live-p process) + (concat (number-to-string (/ (cdr (assoc 'rss (process-attributes id))) + 1024)) + "MB") + "-") + (haskell-session-cabal-dir session) + (haskell-session-current-dir session) + (mapconcat 'identity (process-command process) " ")))) + (t (list (propertize (haskell-session-name session) 'face 'buffer-menu-buffer) + "—" + "—" + "—" + (haskell-session-cabal-dir session) + (haskell-session-current-dir session)))))) + haskell-sessions)))) + +(defun haskell-menu-tabulate (headings rows) + "Prints a list of lists as a formatted table to the current buffer." + (let* ((columns (length headings)) + (widths (make-list columns 0))) + ;; Calculate column widths. This is kind of hideous. + (dolist (row rows) + (setq widths + (let ((list (list))) + (dotimes (i columns) + (setq list (cons (max (nth i widths) + (1+ (length (nth i row))) + (1+ (length (nth i headings)))) + list))) + (reverse list)))) + ;; Print headings. + (let ((heading (propertize " " 'display '(space :align-to 0)))) + (dotimes (i columns) + (setq heading (concat heading + (format (concat "%-" (number-to-string (nth i widths)) "s") + (nth i headings))))) + (setq header-line-format heading)) + ;; Print tabulated rows. + (dolist (row rows) + (dotimes (i columns) + (insert (format (concat "%-" (number-to-string (nth i widths)) "s") + (nth i row)))) + (insert "\n")))) + +(defun haskell-menu-mode-ret () + "Handle RET key." + (interactive) + (let* ((name (save-excursion + (goto-char (line-beginning-position)) + (buffer-substring-no-properties (point) + (progn (search-forward " ") + (forward-char -1) + (point))))) + (session (car (cl-remove-if-not (lambda (session) + (string= (haskell-session-name session) + name)) + haskell-sessions)))) + (switch-to-buffer (haskell-session-interactive-buffer session)))) + +(provide 'haskell-menu) + +;;; haskell-menu.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-menu.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-menu.elc new file mode 100644 index 000000000000..c1a3de07d0cb --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-menu.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-mode-autoloads.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-mode-autoloads.el new file mode 100644 index 000000000000..8e49f2f0b474 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-mode-autoloads.el @@ -0,0 +1,1011 @@ +;;; haskell-mode-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) + +;;;### (autoloads nil "ghc-core" "ghc-core.el" (23377 61614 464227 +;;;;;; 981000)) +;;; Generated autoloads from ghc-core.el + +(let ((loads (get 'ghc-core 'custom-loads))) (if (member '"ghc-core" loads) nil (put 'ghc-core 'custom-loads (cons '"ghc-core" loads)))) + +(autoload 'ghc-core-create-core "ghc-core" "\ +Compile and load the current buffer as tidy core. + +\(fn)" t nil) + +(add-to-list 'auto-mode-alist '("\\.hcr\\'" . ghc-core-mode)) + +(add-to-list 'auto-mode-alist '("\\.dump-simpl\\'" . ghc-core-mode)) + +(autoload 'ghc-core-mode "ghc-core" "\ +Major mode for GHC Core files. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "ghci-script-mode" "ghci-script-mode.el" (23377 +;;;;;; 61614 444618 708000)) +;;; Generated autoloads from ghci-script-mode.el + +(autoload 'ghci-script-mode "ghci-script-mode" "\ +Major mode for working with .ghci files. + +\(fn)" t nil) + +(add-to-list 'auto-mode-alist '("\\.ghci\\'" . ghci-script-mode)) + +;;;*** + +;;;### (autoloads nil "haskell" "haskell.el" (23377 61614 468670 +;;;;;; 911000)) +;;; Generated autoloads from haskell.el + +(autoload 'interactive-haskell-mode "haskell" "\ +Minor mode for enabling haskell-process interaction. + +\(fn &optional ARG)" t nil) + +(autoload 'haskell-interactive-mode-return "haskell" "\ +Handle the return key. + +\(fn)" t nil) + +(autoload 'haskell-session-kill "haskell" "\ +Kill the session process and buffer, delete the session. +0. Prompt to kill all associated buffers. +1. Kill the process. +2. Kill the interactive buffer unless LEAVE-INTERACTIVE-BUFFER is not given. +3. Walk through all the related buffers and set their haskell-session to nil. +4. Remove the session from the sessions list. + +\(fn &optional LEAVE-INTERACTIVE-BUFFER)" t nil) + +(autoload 'haskell-interactive-kill "haskell" "\ +Kill the buffer and (maybe) the session. + +\(fn)" t nil) + +(autoload 'haskell-session "haskell" "\ +Get the Haskell session, prompt if there isn't one or fail. + +\(fn)" nil nil) + +(autoload 'haskell-interactive-switch "haskell" "\ +Switch to the interactive mode for this session. + +\(fn)" t nil) + +(autoload 'haskell-session-change "haskell" "\ +Change the session for the current buffer. + +\(fn)" t nil) + +(autoload 'haskell-kill-session-process "haskell" "\ +Kill the process. + +\(fn &optional SESSION)" t nil) + +(autoload 'haskell-interactive-mode-visit-error "haskell" "\ +Visit the buffer of the current (or last) error message. + +\(fn)" t nil) + +(autoload 'haskell-mode-jump-to-tag "haskell" "\ +Jump to the tag of the given identifier. + +Give optional NEXT-P parameter to override value of +`xref-prompt-for-identifier' during definition search. + +\(fn &optional NEXT-P)" t nil) + +(autoload 'haskell-mode-after-save-handler "haskell" "\ +Function that will be called after buffer's saving. + +\(fn)" nil nil) + +(autoload 'haskell-mode-tag-find "haskell" "\ +The tag find function, specific for the particular session. + +\(fn &optional NEXT-P)" t nil) + +(autoload 'haskell-interactive-bring "haskell" "\ +Bring up the interactive mode for this session. + +\(fn)" t nil) + +(autoload 'haskell-process-load-file "haskell" "\ +Load the current buffer file. + +\(fn)" t nil) + +(autoload 'haskell-process-reload "haskell" "\ +Re-load the current buffer file. + +\(fn)" t nil) + +(autoload 'haskell-process-reload-file "haskell" "\ + + +\(fn)" nil nil) + +(autoload 'haskell-process-load-or-reload "haskell" "\ +Load or reload. Universal argument toggles which. + +\(fn &optional TOGGLE)" t nil) + +(autoload 'haskell-process-cabal-build "haskell" "\ +Build the Cabal project. + +\(fn)" t nil) + +(autoload 'haskell-process-cabal "haskell" "\ +Prompts for a Cabal command to run. + +\(fn P)" t nil) + +(autoload 'haskell-process-minimal-imports "haskell" "\ +Dump minimal imports. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-align-imports" "haskell-align-imports.el" +;;;;;; (23377 61614 510222 266000)) +;;; Generated autoloads from haskell-align-imports.el + +(autoload 'haskell-align-imports "haskell-align-imports" "\ +Align all the imports in the buffer. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-c2hs" "haskell-c2hs.el" (23377 61614 +;;;;;; 473135 401000)) +;;; Generated autoloads from haskell-c2hs.el + +(add-to-list 'auto-mode-alist '("\\.chs\\'" . haskell-c2hs-mode)) + +(autoload 'haskell-c2hs-mode "haskell-c2hs" "\ +Mode for editing *.chs files of the c2hs haskell tool. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-cabal" "haskell-cabal.el" (23377 61614 +;;;;;; 491779 380000)) +;;; Generated autoloads from haskell-cabal.el + +(add-to-list 'auto-mode-alist '("\\.cabal\\'" . haskell-cabal-mode)) + +(autoload 'haskell-cabal-mode "haskell-cabal" "\ +Major mode for Cabal package description files. + +\(fn)" t nil) + +(autoload 'haskell-cabal-get-field "haskell-cabal" "\ +Read the value of field with NAME from project's cabal file. +If there is no valid .cabal file to get the setting from (or +there is no corresponding setting with that name in the .cabal +file), then this function returns nil. + +\(fn NAME)" t nil) + +(autoload 'haskell-cabal-get-dir "haskell-cabal" "\ +Get the Cabal dir for a new project. Various ways of figuring this out, + and indeed just prompting the user. Do them all. + +\(fn &optional USE-DEFAULTS)" nil nil) + +(autoload 'haskell-cabal-visit-file "haskell-cabal" "\ +Locate and visit package description file for file visited by current buffer. +This uses `haskell-cabal-find-file' to locate the closest +\".cabal\" file and open it. This command assumes a common Cabal +project structure where the \".cabal\" file is in the top-folder +of the project, and all files related to the project are in or +below the top-folder. If called with non-nil prefix argument +OTHER-WINDOW use `find-file-other-window'. + +\(fn OTHER-WINDOW)" t nil) + +(let ((loads (get 'haskell-cabal 'custom-loads))) (if (member '"haskell-cabal" loads) nil (put 'haskell-cabal 'custom-loads (cons '"haskell-cabal" loads)))) + +;;;*** + +;;;### (autoloads nil "haskell-collapse" "haskell-collapse.el" (23377 +;;;;;; 61614 449081 791000)) +;;; Generated autoloads from haskell-collapse.el + +(autoload 'haskell-collapse-mode "haskell-collapse" "\ +Minor mode to collapse and expand haskell expressions + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-commands" "haskell-commands.el" (23377 +;;;;;; 61614 507848 25000)) +;;; Generated autoloads from haskell-commands.el + +(autoload 'haskell-process-restart "haskell-commands" "\ +Restart the inferior Haskell process. + +\(fn)" t nil) + +(autoload 'haskell-process-clear "haskell-commands" "\ +Clear the current process. + +\(fn)" t nil) + +(autoload 'haskell-process-interrupt "haskell-commands" "\ +Interrupt the process (SIGINT). + +\(fn)" t nil) + +(autoload 'haskell-describe "haskell-commands" "\ +Describe the given identifier IDENT. + +\(fn IDENT)" t nil) + +(autoload 'haskell-rgrep "haskell-commands" "\ +Grep the effective project for the symbol at point. +Very useful for codebase navigation. + +Prompts for an arbitrary regexp given a prefix arg PROMPT. + +\(fn &optional PROMPT)" t nil) + +(autoload 'haskell-process-do-info "haskell-commands" "\ +Print info on the identifier at point. +If PROMPT-VALUE is non-nil, request identifier via mini-buffer. + +\(fn &optional PROMPT-VALUE)" t nil) + +(autoload 'haskell-process-do-type "haskell-commands" "\ +Print the type of the given expression. + +Given INSERT-VALUE prefix indicates that result type signature +should be inserted. + +\(fn &optional INSERT-VALUE)" t nil) + +(autoload 'haskell-mode-jump-to-def-or-tag "haskell-commands" "\ +Jump to the definition. +Jump to definition of identifier at point by consulting GHCi, or +tag table as fallback. + +Remember: If GHCi is busy doing something, this will delay, but +it will always be accurate, in contrast to tags, which always +work but are not always accurate. +If the definition or tag is found, the location from which you jumped +will be pushed onto `xref--marker-ring', so you can return to that +position with `xref-pop-marker-stack'. + +\(fn &optional NEXT-P)" t nil) + +(autoload 'haskell-mode-goto-loc "haskell-commands" "\ +Go to the location of the thing at point. +Requires the :loc-at command from GHCi. + +\(fn)" t nil) + +(autoload 'haskell-mode-jump-to-def "haskell-commands" "\ +Jump to definition of identifier IDENT at point. + +\(fn IDENT)" t nil) + +(autoload 'haskell-process-cd "haskell-commands" "\ +Change directory. + +\(fn &optional NOT-INTERACTIVE)" t nil) + +(autoload 'haskell-process-cabal-macros "haskell-commands" "\ +Send the cabal macros string. + +\(fn)" t nil) + +(autoload 'haskell-mode-show-type-at "haskell-commands" "\ +Show type of the thing at point or within active region asynchronously. +This function requires GHCi 8+ or GHCi-ng. + +\\<haskell-interactive-mode-map> +To make this function works sometimes you need to load the file in REPL +first using command `haskell-process-load-file' bound to +\\[haskell-process-load-file]. + +Optional argument INSERT-VALUE indicates that +recieved type signature should be inserted (but only if nothing +happened since function invocation). + +\(fn &optional INSERT-VALUE)" t nil) + +(autoload 'haskell-process-unignore "haskell-commands" "\ +Unignore any ignored files. +Do not ignore files that were specified as being ignored by the +inferior GHCi process. + +\(fn)" t nil) + +(autoload 'haskell-session-change-target "haskell-commands" "\ +Set the build TARGET for cabal REPL. + +\(fn TARGET)" t nil) + +(autoload 'haskell-mode-stylish-buffer "haskell-commands" "\ +Apply stylish-haskell to the current buffer. + +Use `haskell-mode-stylish-haskell-path' to know where to find +stylish-haskell executable. This function tries to preserve +cursor position and markers by using +`haskell-mode-buffer-apply-command'. + +\(fn)" t nil) + +(autoload 'haskell-mode-find-uses "haskell-commands" "\ +Find use cases of the identifier at point and highlight them all. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-compile" "haskell-compile.el" (23377 +;;;;;; 61614 495238 977000)) +;;; Generated autoloads from haskell-compile.el + +(let ((loads (get 'haskell-compile 'custom-loads))) (if (member '"haskell-compile" loads) nil (put 'haskell-compile 'custom-loads (cons '"haskell-compile" loads)))) + +(autoload 'haskell-compile "haskell-compile" "\ +Compile the Haskell program including the current buffer. +Tries to locate the next cabal description in current or parent +folders via `haskell-cabal-find-dir' and if found, invoke +`haskell-compile-cabal-build-command' from the cabal package root +folder. If no cabal package could be detected, +`haskell-compile-command' is used instead. + +If prefix argument EDIT-COMMAND is non-nil (and not a negative +prefix `-'), `haskell-compile' prompts for custom compile +command. + +If EDIT-COMMAND contains the negative prefix argument `-', +`haskell-compile' calls the alternative command defined in +`haskell-compile-cabal-build-alt-command' if a cabal package was +detected. + +`haskell-compile' uses `haskell-compilation-mode' which is +derived from `compilation-mode'. See Info +node `(haskell-mode)compilation' for more details. + +\(fn &optional EDIT-COMMAND)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-completions" "haskell-completions.el" +;;;;;; (23377 61614 502566 919000)) +;;; Generated autoloads from haskell-completions.el + +(let ((loads (get 'haskell-completions 'custom-loads))) (if (member '"haskell-completions" loads) nil (put 'haskell-completions 'custom-loads (cons '"haskell-completions" loads)))) + +(autoload 'haskell-completions-completion-at-point "haskell-completions" "\ +Provide completion list for thing at point. +This function is used in non-interactive `haskell-mode'. It +provides completions for haskell keywords, language pragmas, +GHC's options, and language extensions, but not identifiers. + +\(fn)" nil nil) + +;;;*** + +;;;### (autoloads nil "haskell-customize" "haskell-customize.el" +;;;;;; (23377 61614 493162 389000)) +;;; Generated autoloads from haskell-customize.el + +(let ((loads (get 'haskell 'custom-loads))) (if (member '"haskell-customize" loads) nil (put 'haskell 'custom-loads (cons '"haskell-customize" loads)))) + +(let ((loads (get 'haskell-interactive 'custom-loads))) (if (member '"haskell-customize" loads) nil (put 'haskell-interactive 'custom-loads (cons '"haskell-customize" loads)))) + +;;;*** + +;;;### (autoloads nil "haskell-debug" "haskell-debug.el" (23377 61614 +;;;;;; 443095 895000)) +;;; Generated autoloads from haskell-debug.el + +(let ((loads (get 'haskell-debug 'custom-loads))) (if (member '"haskell-debug" loads) nil (put 'haskell-debug 'custom-loads (cons '"haskell-debug" loads)))) + +(defface haskell-debug-warning-face '((t :inherit 'compilation-warning)) "\ +Face for warnings." :group (quote haskell-debug)) + +(defface haskell-debug-trace-number-face '((t :weight bold :background "#f5f5f5")) "\ +Face for numbers in backtrace." :group (quote haskell-debug)) + +(defface haskell-debug-newline-face '((t :weight bold :background "#f0f0f0")) "\ +Face for newlines in trace steps." :group (quote haskell-debug)) + +(defface haskell-debug-keybinding-face '((t :inherit 'font-lock-type-face :weight bold)) "\ +Face for keybindings." :group (quote haskell-debug)) + +(defface haskell-debug-heading-face '((t :inherit 'font-lock-keyword-face)) "\ +Face for headings." :group (quote haskell-debug)) + +(defface haskell-debug-muted-face '((t :foreground "#999")) "\ +Face for muteds." :group (quote haskell-debug)) + +;;;*** + +;;;### (autoloads nil "haskell-decl-scan" "haskell-decl-scan.el" +;;;;;; (23377 61614 526149 653000)) +;;; Generated autoloads from haskell-decl-scan.el + +(let ((loads (get 'haskell-decl-scan 'custom-loads))) (if (member '"haskell-decl-scan" loads) nil (put 'haskell-decl-scan 'custom-loads (cons '"haskell-decl-scan" loads)))) + +(autoload 'haskell-ds-create-imenu-index "haskell-decl-scan" "\ +Function for finding `imenu' declarations in Haskell mode. +Finds all declarations (classes, variables, imports, instances and +datatypes) in a Haskell file for the `imenu' package. + +\(fn)" nil nil) + +(autoload 'turn-on-haskell-decl-scan "haskell-decl-scan" "\ +Unconditionally activate `haskell-decl-scan-mode'. + +\(fn)" t nil) + +(autoload 'haskell-decl-scan-mode "haskell-decl-scan" "\ +Toggle Haskell declaration scanning minor mode on or off. +With a prefix argument ARG, enable minor mode if ARG is +positive, and disable it otherwise. If called from Lisp, enable +the mode if ARG is omitted or nil, and toggle it if ARG is `toggle'. + +See also info node `(haskell-mode)haskell-decl-scan-mode' for +more details about this minor mode. + +Top-level declarations are scanned and listed in the menu item +\"Declarations\" (if enabled via option +`haskell-decl-scan-add-to-menubar'). Selecting an item from this +menu will take point to the start of the declaration. + +\\[beginning-of-defun] and \\[end-of-defun] move forward and backward to the start of a declaration. + +This may link with `haskell-doc-mode'. + +For non-literate and LaTeX-style literate scripts, we assume the +common convention that top-level declarations start at the first +column. For Bird-style literate scripts, we assume the common +convention that top-level declarations start at the third column, +ie. after \"> \". + +Anything in `font-lock-comment-face' is not considered for a +declaration. Therefore, using Haskell font locking with comments +coloured in `font-lock-comment-face' improves declaration scanning. + +Literate Haskell scripts are supported: If the value of +`haskell-literate' (set automatically by `literate-haskell-mode') +is `bird', a Bird-style literate script is assumed. If it is nil +or `tex', a non-literate or LaTeX-style literate script is +assumed, respectively. + +Invokes `haskell-decl-scan-mode-hook' on activation. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-doc" "haskell-doc.el" (23377 61614 +;;;;;; 465805 530000)) +;;; Generated autoloads from haskell-doc.el + +(let ((loads (get 'haskell-doc 'custom-loads))) (if (member '"haskell-doc" loads) nil (put 'haskell-doc 'custom-loads (cons '"haskell-doc" loads)))) + +(autoload 'haskell-doc-mode "haskell-doc" "\ +Enter `haskell-doc-mode' for showing fct types in the echo area. +See variable docstring. + +\(fn &optional ARG)" t nil) + +(defalias 'turn-on-haskell-doc-mode 'haskell-doc-mode) + +(defalias 'turn-on-haskell-doc 'haskell-doc-mode) + +(autoload 'haskell-doc-current-info "haskell-doc" "\ +Return the info about symbol at point. +Meant for `eldoc-documentation-function'. + +\(fn)" nil nil) + +(autoload 'haskell-doc-show-type "haskell-doc" "\ +Show the type of the function near point or given symbol SYM. +For the function under point, show the type in the echo area. +This information is extracted from the `haskell-doc-prelude-types' alist +of prelude functions and their types, or from the local functions in the +current buffer. + +\(fn &optional SYM)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-font-lock" "haskell-font-lock.el" +;;;;;; (23377 61614 481501 453000)) +;;; Generated autoloads from haskell-font-lock.el + +(let ((loads (get 'haskell-appearance 'custom-loads))) (if (member '"haskell-font-lock" loads) nil (put 'haskell-appearance 'custom-loads (cons '"haskell-font-lock" loads)))) + +(defface haskell-keyword-face '((t :inherit font-lock-keyword-face)) "\ +Face used to highlight Haskell keywords." :group (quote haskell-appearance)) + +(defface haskell-type-face '((t :inherit font-lock-type-face)) "\ +Face used to highlight Haskell types" :group (quote haskell-appearance)) + +(defface haskell-constructor-face '((t :inherit font-lock-type-face)) "\ +Face used to highlight Haskell constructors." :group (quote haskell-appearance)) + +(defface haskell-operator-face '((t :inherit font-lock-variable-name-face)) "\ +Face used to highlight Haskell operators." :group (quote haskell-appearance)) + +(defface haskell-pragma-face '((t :inherit font-lock-preprocessor-face)) "\ +Face used to highlight Haskell pragmas ({-# ... #-})." :group (quote haskell-appearance)) + +(defface haskell-liquid-haskell-annotation-face '((t :inherit haskell-pragma-face)) "\ +Face used to highlight LiquidHaskell annotations ({-@ ... @-})." :group (quote haskell-appearance)) + +(defface haskell-literate-comment-face '((t :inherit font-lock-doc-face)) "\ +Face with which to fontify literate comments. +Inherit from `default' to avoid fontification of them." :group (quote haskell-appearance)) + +;;;*** + +;;;### (autoloads nil "haskell-hoogle" "haskell-hoogle.el" (23377 +;;;;;; 61614 467321 953000)) +;;; Generated autoloads from haskell-hoogle.el + +(autoload 'haskell-hoogle "haskell-hoogle" "\ +Do a Hoogle search for QUERY. +When `haskell-hoogle-command' is non-nil, this command runs +that. Otherwise, it opens a hoogle search result in the browser. + +If prefix argument INFO is given, then `haskell-hoogle-command' +is asked to show extra info for the items matching QUERY.. + +\(fn QUERY &optional INFO)" t nil) + +(defalias 'hoogle 'haskell-hoogle) + +(autoload 'haskell-hoogle-lookup-from-local "haskell-hoogle" "\ +Lookup by local hoogle. + +\(fn)" t nil) + +(autoload 'haskell-hayoo "haskell-hoogle" "\ +Do a Hayoo search for QUERY. + +\(fn QUERY)" t nil) + +(defalias 'hayoo 'haskell-hayoo) + +;;;*** + +;;;### (autoloads nil "haskell-indent" "haskell-indent.el" (23377 +;;;;;; 61614 517159 450000)) +;;; Generated autoloads from haskell-indent.el + +(let ((loads (get 'haskell-indent 'custom-loads))) (if (member '"haskell-indent" loads) nil (put 'haskell-indent 'custom-loads (cons '"haskell-indent" loads)))) + +(autoload 'turn-on-haskell-indent "haskell-indent" "\ +Turn on ``intelligent'' Haskell indentation mode. + +\(fn)" nil nil) + +(autoload 'haskell-indent-mode "haskell-indent" "\ +``Intelligent'' Haskell indentation mode. +This deals with the layout rule of Haskell. +\\[haskell-indent-cycle] starts the cycle which proposes new +possibilities as long as the TAB key is pressed. Any other key +or mouse click terminates the cycle and is interpreted except for +RET which merely exits the cycle. +Other special keys are: + \\[haskell-indent-insert-equal] + inserts an = + \\[haskell-indent-insert-guard] + inserts an | + \\[haskell-indent-insert-otherwise] + inserts an | otherwise = +these functions also align the guards and rhs of the current definition + \\[haskell-indent-insert-where] + inserts a where keyword + \\[haskell-indent-align-guards-and-rhs] + aligns the guards and rhs of the region + \\[haskell-indent-put-region-in-literate] + makes the region a piece of literate code in a literate script + +If `ARG' is falsey, toggle `haskell-indent-mode'. Else sets +`haskell-indent-mode' to whether `ARG' is greater than 0. + +Invokes `haskell-indent-hook' if not nil. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-indentation" "haskell-indentation.el" +;;;;;; (23377 61614 474683 85000)) +;;; Generated autoloads from haskell-indentation.el + +(let ((loads (get 'haskell-indentation 'custom-loads))) (if (member '"haskell-indentation" loads) nil (put 'haskell-indentation 'custom-loads (cons '"haskell-indentation" loads)))) + +(autoload 'haskell-indentation-mode "haskell-indentation" "\ +Haskell indentation mode that deals with the layout rule. +It rebinds RET, DEL and BACKSPACE, so that indentations can be +set and deleted as if they were real tabs. + +\(fn &optional ARG)" t nil) + +(autoload 'turn-on-haskell-indentation "haskell-indentation" "\ +Turn on the haskell-indentation minor mode. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-interactive-mode" "haskell-interactive-mode.el" +;;;;;; (23377 61614 446289 590000)) +;;; Generated autoloads from haskell-interactive-mode.el + +(defface haskell-interactive-face-prompt '((t :inherit font-lock-function-name-face)) "\ +Face for the prompt." :group (quote haskell-interactive)) + +(defface haskell-interactive-face-prompt2 '((t :inherit font-lock-keyword-face)) "\ +Face for the prompt2 in multi-line mode." :group (quote haskell-interactive)) + +(defface haskell-interactive-face-compile-error '((t :inherit compilation-error)) "\ +Face for compile errors." :group (quote haskell-interactive)) + +(defface haskell-interactive-face-compile-warning '((t :inherit compilation-warning)) "\ +Face for compiler warnings." :group (quote haskell-interactive)) + +(defface haskell-interactive-face-result '((t :inherit font-lock-string-face)) "\ +Face for the result." :group (quote haskell-interactive)) + +(defface haskell-interactive-face-garbage '((t :inherit font-lock-string-face)) "\ +Face for trailing garbage after a command has completed." :group (quote haskell-interactive)) + +(autoload 'haskell-interactive-mode-reset-error "haskell-interactive-mode" "\ +Reset the error cursor position. + +\(fn SESSION)" t nil) + +(autoload 'haskell-interactive-mode-echo "haskell-interactive-mode" "\ +Echo a read only piece of text before the prompt. + +\(fn SESSION MESSAGE &optional MODE)" nil nil) + +(autoload 'haskell-process-show-repl-response "haskell-interactive-mode" "\ +Send LINE to the GHCi process and echo the result in some fashion. +Result will be printed in the minibuffer or presented using +function `haskell-presentation-present', depending on variable +`haskell-process-use-presentation-mode'. + +\(fn LINE)" nil nil) + +;;;*** + +;;;### (autoloads nil "haskell-load" "haskell-load.el" (23377 61614 +;;;;;; 434479 297000)) +;;; Generated autoloads from haskell-load.el + +(defface haskell-error-face '((((supports :underline (:style wave))) :underline (:style wave :color "#dc322f")) (t :inherit error)) "\ +Face used for marking error lines." :group (quote haskell-mode)) + +(defface haskell-warning-face '((((supports :underline (:style wave))) :underline (:style wave :color "#b58900")) (t :inherit warning)) "\ +Face used for marking warning lines." :group (quote haskell-mode)) + +(defface haskell-hole-face '((((supports :underline (:style wave))) :underline (:style wave :color "#6c71c4")) (t :inherit warning)) "\ +Face used for marking hole lines." :group (quote haskell-mode)) + +(autoload 'haskell-process-reload-devel-main "haskell-load" "\ +Reload the module `DevelMain' and then run `DevelMain.update'. + +This is for doing live update of the code of servers or GUI +applications. Put your development version of the program in +`DevelMain', and define `update' to auto-start the program on a +new thread, and use the `foreign-store' package to access the +running context across :load/:reloads in GHCi. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-menu" "haskell-menu.el" (23377 61614 +;;;;;; 486880 305000)) +;;; Generated autoloads from haskell-menu.el + +(autoload 'haskell-menu "haskell-menu" "\ +Launch the Haskell sessions menu. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-mode" "haskell-mode.el" (23377 61614 +;;;;;; 513037 533000)) +;;; Generated autoloads from haskell-mode.el + +(autoload 'haskell-version "haskell-mode" "\ +Show the `haskell-mode` version in the echo area. +With prefix argument HERE, insert it at point. + +\(fn &optional HERE)" t nil) + +(autoload 'haskell-mode-view-news "haskell-mode" "\ +Display information on recent changes to haskell-mode. + +\(fn)" t nil) + +(autoload 'haskell-mode "haskell-mode" "\ +Major mode for editing Haskell programs. + +\\<haskell-mode-map> + +Literate Haskell scripts are supported via `literate-haskell-mode'. +The variable `haskell-literate' indicates the style of the script in the +current buffer. See the documentation on this variable for more details. + +Use `haskell-version' to find out what version of Haskell mode you are +currently using. + +Additional Haskell mode modules can be hooked in via `haskell-mode-hook'. + +Indentation modes: + + `haskell-indentation-mode', Kristof Bastiaensen, Gergely Risko + Intelligent semi-automatic indentation Mk2 + + `haskell-indent-mode', Guy Lapalme + Intelligent semi-automatic indentation. + +Interaction modes: + + `interactive-haskell-mode' + Interact with per-project GHCi processes through a REPL and + directory-aware sessions. + +Other modes: + + `haskell-decl-scan-mode', Graeme E Moss + Scans top-level declarations, and places them in a menu. + + `haskell-doc-mode', Hans-Wolfgang Loidl + Echoes types of functions or syntax of keywords when the cursor is idle. + +To activate a minor-mode, simply run the interactive command. For +example, `M-x haskell-doc-mode'. Run it again to disable it. + +To enable a mode for every haskell-mode buffer, add a hook in +your Emacs configuration. To do that you can customize +`haskell-mode-hook' or add lines to your .emacs file. For +example, to enable `interactive-haskell-mode', use the following: + + (add-hook 'haskell-mode-hook 'interactive-haskell-mode) + +Minor modes that work well with `haskell-mode': + +- `smerge-mode': show and work with diff3 conflict markers used + by git, svn and other version control systems. + +\(fn)" t nil) + +(autoload 'haskell-forward-sexp "haskell-mode" "\ +Haskell specific version of `forward-sexp'. + +Move forward across one balanced expression (sexp). With ARG, do +it that many times. Negative arg -N means move backward across N +balanced expressions. This command assumes point is not in a +string or comment. + +If unable to move over a sexp, signal `scan-error' with three +arguments: a message, the start of the obstacle (a parenthesis or +list marker of some kind), and end of the obstacle. + +\(fn &optional ARG)" t nil) + +(autoload 'literate-haskell-mode "haskell-mode" "\ +As `haskell-mode' but for literate scripts. + +\(fn)" t nil) + +(add-to-list 'auto-mode-alist '("\\.[gh]s\\'" . haskell-mode)) + +(add-to-list 'auto-mode-alist '("\\.hsig\\'" . haskell-mode)) + +(add-to-list 'auto-mode-alist '("\\.l[gh]s\\'" . literate-haskell-mode)) + +(add-to-list 'auto-mode-alist '("\\.hsc\\'" . haskell-mode)) + +(add-to-list 'interpreter-mode-alist '("runghc" . haskell-mode)) + +(add-to-list 'interpreter-mode-alist '("runhaskell" . haskell-mode)) + +(add-to-list 'completion-ignored-extensions ".hi") + +(autoload 'haskell-mode-generate-tags "haskell-mode" "\ +Generate tags using Hasktags. This is synchronous function. + +If optional AND-THEN-FIND-THIS-TAG argument is present it is used +with function `xref-find-definitions' after new table was +generated. + +\(fn &optional AND-THEN-FIND-THIS-TAG)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-modules" "haskell-modules.el" (23377 +;;;;;; 61614 520638 53000)) +;;; Generated autoloads from haskell-modules.el + +(autoload 'haskell-session-installed-modules "haskell-modules" "\ +Get the modules installed in the current package set. + +\(fn SESSION &optional DONTCREATE)" nil nil) + +(autoload 'haskell-session-all-modules "haskell-modules" "\ +Get all modules -- installed or in the current project. +If DONTCREATE is non-nil don't create a new session. + +\(fn SESSION &optional DONTCREATE)" nil nil) + +(autoload 'haskell-session-project-modules "haskell-modules" "\ +Get the modules of the current project. +If DONTCREATE is non-nil don't create a new session. + +\(fn SESSION &optional DONTCREATE)" nil nil) + +;;;*** + +;;;### (autoloads nil "haskell-move-nested" "haskell-move-nested.el" +;;;;;; (23377 61614 514693 505000)) +;;; Generated autoloads from haskell-move-nested.el + +(autoload 'haskell-move-nested "haskell-move-nested" "\ +Shift the nested off-side-rule block adjacent to point by COLS columns to the right. + +In Transient Mark mode, if the mark is active, operate on the contents +of the region instead. + +\(fn COLS)" nil nil) + +(autoload 'haskell-move-nested-right "haskell-move-nested" "\ +Increase indentation of the following off-side-rule block adjacent to point. + +Use a numeric prefix argument to indicate amount of indentation to apply. + +In Transient Mark mode, if the mark is active, operate on the contents +of the region instead. + +\(fn COLS)" t nil) + +(autoload 'haskell-move-nested-left "haskell-move-nested" "\ +Decrease indentation of the following off-side-rule block adjacent to point. + +Use a numeric prefix argument to indicate amount of indentation to apply. + +In Transient Mark mode, if the mark is active, operate on the contents +of the region instead. + +\(fn COLS)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-navigate-imports" "haskell-navigate-imports.el" +;;;;;; (23377 61614 522273 319000)) +;;; Generated autoloads from haskell-navigate-imports.el + +(autoload 'haskell-navigate-imports "haskell-navigate-imports" "\ +Cycle the Haskell import lines or return to point (with prefix arg). + +\(fn &optional RETURN)" t nil) + +(autoload 'haskell-navigate-imports-go "haskell-navigate-imports" "\ +Go to the first line of a list of consecutive import lines. Cycles. + +\(fn)" t nil) + +(autoload 'haskell-navigate-imports-return "haskell-navigate-imports" "\ +Return to the non-import point we were at before going to the module list. + If we were originally at an import list, we can just cycle through easily. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-session" "haskell-session.el" (23377 +;;;;;; 61614 476646 160000)) +;;; Generated autoloads from haskell-session.el + +(autoload 'haskell-session-maybe "haskell-session" "\ +Maybe get the Haskell session, return nil if there isn't one. + +\(fn)" nil nil) + +(autoload 'haskell-session-process "haskell-session" "\ +Get the session process. + +\(fn S)" nil nil) + +;;;*** + +;;;### (autoloads nil "haskell-sort-imports" "haskell-sort-imports.el" +;;;;;; (23377 61614 489920 40000)) +;;; Generated autoloads from haskell-sort-imports.el + +(autoload 'haskell-sort-imports "haskell-sort-imports" "\ +Sort the import list at point. It sorts the current group +i.e. an import list separated by blank lines on either side. + +If the region is active, it will restrict the imports to sort +within that region. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "haskell-unicode-input-method" "haskell-unicode-input-method.el" +;;;;;; (23377 61614 457460 312000)) +;;; Generated autoloads from haskell-unicode-input-method.el + +(autoload 'turn-on-haskell-unicode-input-method "haskell-unicode-input-method" "\ +Set input method `haskell-unicode'. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "highlight-uses-mode" "highlight-uses-mode.el" +;;;;;; (23377 61614 499589 351000)) +;;; Generated autoloads from highlight-uses-mode.el + +(autoload 'highlight-uses-mode "highlight-uses-mode" "\ +Minor mode for highlighting and jumping between uses. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads nil "inf-haskell" "inf-haskell.el" (23377 61614 +;;;;;; 441568 997000)) +;;; Generated autoloads from inf-haskell.el + +(let ((loads (get 'inferior-haskell 'custom-loads))) (if (member '"inf-haskell" loads) nil (put 'inferior-haskell 'custom-loads (cons '"inf-haskell" loads)))) + +(defalias 'run-haskell 'switch-to-haskell) + +(autoload 'switch-to-haskell "inf-haskell" "\ +Show the inferior-haskell buffer. Start the process if needed. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil "w3m-haddock" "w3m-haddock.el" (23377 61614 +;;;;;; 505606 375000)) +;;; Generated autoloads from w3m-haddock.el + +(defface w3m-haddock-heading-face '((((class color)) :inherit highlight)) "\ +Face for quarantines." :group (quote haskell)) + +;;;*** + +;;;### (autoloads nil nil ("haskell-compat.el" "haskell-complete-module.el" +;;;;;; "haskell-ghc-support.el" "haskell-lexeme.el" "haskell-mode-pkg.el" +;;;;;; "haskell-presentation-mode.el" "haskell-process.el" "haskell-repl.el" +;;;;;; "haskell-sandbox.el" "haskell-string.el" "haskell-utils.el") +;;;;;; (23377 61614 524498 941000)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; haskell-mode-autoloads.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-mode-pkg.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-mode-pkg.el new file mode 100644 index 000000000000..5b37f9cac52b --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-mode-pkg.el @@ -0,0 +1,8 @@ +(define-package "haskell-mode" "20180601.143" "A Haskell editing mode" + '((emacs "24.3")) + :keywords + '("haskell" "cabal" "ghc" "repl") + :url "https://github.com/haskell/haskell-mode") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-mode.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-mode.el new file mode 100644 index 000000000000..7823e13ddc0d --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-mode.el @@ -0,0 +1,1195 @@ +;;; haskell-mode.el --- A Haskell editing mode -*- coding: utf-8; lexical-binding: t -*- + +;; Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2016 +;; Free Software Foundation, Inc + +;; Copyright © 1992, 1997-1998 Simon Marlow, Graeme E Moss, and Tommy Thorn + +;; Author: 1992 Simon Marlow +;; 1997-1998 Graeme E Moss <gem@cs.york.ac.uk> and +;; Tommy Thorn <thorn@irisa.fr>, +;; 2001-2002 Reuben Thomas (>=v1.4) +;; 2003 Dave Love <fx@gnu.org> +;; 2016 Arthur Fayzrakhmanov +;; Keywords: faces files Haskell +;; Version: 16.2-git +;; URL: https://github.com/haskell/haskell-mode + +;; This file is not part of GNU Emacs. + +;; 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; A major mode for editing Haskell (the functional programming +;; language, see URL `http://www.haskell.org') in Emacs. +;; +;; Some of its major features include: +;; +;; - syntax highlighting (font lock), +;; +;; - automatic indentation, +;; +;; - on-the-fly documentation, +;; +;; - interaction with inferior GHCi/Hugs instance, +;; +;; - scans declarations and places them in a menu. +;; +;; See URL `https://github.com/haskell/haskell-mode' and/or +;; Info node `(haskell-mode)Introduction' for more information. +;; +;; Use `M-x haskell-mode-view-news` (after Haskell Mode is installed) +;; to show information on recent changes in Haskell Mode. + +;;; Change Log: + +;; This mode is based on an editing mode by Simon Marlow 11/1/92 +;; and heavily modified by Graeme E Moss and Tommy Thorn 7/11/98. +;; +;; Version 1.5: +;; Added autoload for haskell-indentation +;; +;; Version 1.43: +;; Various tweaks to doc strings and customization support from +;; Ville Skyttä <scop@xemacs.org>. +;; +;; Version 1.42: +;; Added autoload for GHCi inferior mode (thanks to Scott +;; Williams for the bug report and fix). +;; +;; Version 1.41: +;; Improved packaging, and made a couple more variables +;; interactively settable. +;; +;; Version 1.4: +;; Added GHCi mode from Chris Webb, and tidied up a little. +;; +;; Version 1.3: +;; The literate or non-literate style of a buffer is now indicated +;; by just the variable haskell-literate: nil, `bird', or `tex'. +;; For literate buffers with ambiguous style, the value of +;; haskell-literate-default is used. +;; +;; Version 1.2: +;; Separated off font locking, declaration scanning and simple +;; indentation, and made them separate modules. Modules can be +;; added easily now. Support for modules haskell-doc, +;; haskell-indent, and haskell-hugs. Literate and non-literate +;; modes integrated into one mode, and literate buffer indicated by +;; value of haskell-literate(-bird-style). +;; +;; Version 1.1: +;; Added support for declaration scanning under XEmacs via +;; func-menu. Moved operators to level two fontification. +;; +;; Version 1.0: +;; Added a nice indention support from Heribert Schuetz +;; <Heribert.Schuetz@informatik.uni-muenchen.de>: +;; +;; I have just hacked an Emacs Lisp function which you might prefer +;; to `indent-relative' in haskell-mode.el. See below. It is not +;; really Haskell-specific because it does not take into account +;; keywords like `do', `of', and `let' (where the layout rule +;; applies), but I already find it useful. +;; +;; Cleaned up the imenu support. Added support for literate scripts. +;; +;; Version 0.103 [HWL]: +;; From Hans Wolfgang Loidl <hwloidl@dcs.gla.ac.uk>: +;; +;; I (HWL) added imenu support by copying the appropriate functions +;; from hugs-mode. A menu-bar item "Declarations" is now added in +;; haskell mode. The new code, however, needs some clean-up. +;; +;; Version 0.102: +;; +;; Moved C-c C-c key binding to comment-region. Leave M-g M-g to do +;; the work. comment-start-skip is changed to comply with comment-start. +;; +;; Version 0.101: +;; +;; Altered indent-line-function to indent-relative. +;; +;; Version 0.100: +;; +;; First official release. + +;;; Code: + +(require 'haskell-customize) +(require 'ansi-color) +(require 'dabbrev) +(require 'compile) +(require 'etags) +(require 'flymake) +(require 'outline) +(require 'cl-lib) +(require 'haskell-ghc-support) +(require 'haskell-complete-module) +(require 'haskell-compat) +(require 'haskell-align-imports) +(require 'haskell-lexeme) +(require 'haskell-sort-imports) +(require 'haskell-string) +(require 'haskell-indentation) +(require 'haskell-font-lock) +(require 'haskell-cabal) + +;; All functions/variables start with `(literate-)haskell-'. + +;; Version of mode. +(defconst haskell-version "16.2-git" + "The release version of `haskell-mode'.") + +;;;###autoload +(defun haskell-version (&optional here) + "Show the `haskell-mode` version in the echo area. +With prefix argument HERE, insert it at point." + (interactive "P") + (let* ((haskell-mode-dir (ignore-errors + (file-name-directory (or (locate-library "haskell-mode") "")))) + (version (format "haskell-mode version %s (%s)" + haskell-version + haskell-mode-dir))) + (if here + (insert version) + (message "%s" version)))) + +;;;###autoload +(defun haskell-mode-view-news () + "Display information on recent changes to haskell-mode." + (interactive) + (with-current-buffer (find-file-read-only (expand-file-name "NEWS" haskell-mode-pkg-base-dir)) + (goto-char (point-min)) + (outline-hide-sublevels 1) + (outline-next-visible-heading 1) + (outline-show-subtree))) + +;; Are we looking at a literate script? +(defvar-local haskell-literate nil + "If not nil, the current buffer contains a literate Haskell script. +Possible values are: `bird' and `tex', for Bird-style and LaTeX-style +literate scripts respectively. Set by `haskell-mode' and +`literate-haskell-mode'. For an ambiguous literate buffer -- i.e. does +not contain either \"\\begin{code}\" or \"\\end{code}\" on a line on +its own, nor does it contain \">\" at the start of a line -- the value +of `haskell-literate-default' is used.") +(put 'haskell-literate 'safe-local-variable 'symbolp) + +;; Default literate style for ambiguous literate buffers. +(defcustom haskell-literate-default 'bird + "Default value for `haskell-literate'. +Used if the style of a literate buffer is ambiguous. This variable should +be set to the preferred literate style." + :group 'haskell + :type '(choice (const bird) (const tex) (const nil))) + +(defvar haskell-mode-map + (let ((map (make-sparse-keymap))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Editing-specific commands + (define-key map (kbd "C-c C-,") 'haskell-mode-format-imports) + (define-key map [remap delete-indentation] 'haskell-delete-indentation) + (define-key map (kbd "C-c C-l") 'haskell-mode-enable-process-minor-mode) + (define-key map (kbd "C-c C-b") 'haskell-mode-enable-process-minor-mode) + (define-key map (kbd "C-c C-v") 'haskell-mode-enable-process-minor-mode) + (define-key map (kbd "C-c C-t") 'haskell-mode-enable-process-minor-mode) + (define-key map (kbd "C-c C-i") 'haskell-mode-enable-process-minor-mode) + (define-key map (kbd "C-c C-s") 'haskell-mode-toggle-scc-at-point) + map) + "Keymap used in `haskell-mode'.") + +(defun haskell-mode-enable-process-minor-mode () + "Tell the user to choose a minor mode for process interaction." + (interactive) + (error "Run `C-h f haskell-mode` for instruction how to setup a Haskell interaction mode.")) + +(easy-menu-define haskell-mode-menu haskell-mode-map + "Menu for the Haskell major mode." + ;; Suggestions from Pupeno <pupeno@pupeno.com>: + ;; - choose the underlying interpreter + ;; - look up docs + `("Haskell" + ["Indent line" indent-according-to-mode] + ["(Un)Comment region" comment-region mark-active] + "---" + ["Start interpreter" haskell-interactive-switch] + ["Load file" haskell-process-load-file] + "---" + ["Load tidy core" ghc-core-create-core] + "---" + ,(if (default-boundp 'eldoc-documentation-function) + ["Doc mode" eldoc-mode + :style toggle :selected (bound-and-true-p eldoc-mode)] + ["Doc mode" haskell-doc-mode + :style toggle :selected (and (boundp 'haskell-doc-mode) haskell-doc-mode)]) + ["Customize" (customize-group 'haskell)] + )) + +;; Procedurally generated (see Lexeme.hs in ghc). +;; This is a bit unsightly: it's generated by making a list of all +;; unicode characters whose Unicode general category ghc would +;; recognize as valid symbol (or identifier, below) constituent. +(defvar haskell--char-syntax-symbols + '((161 . 169) 172 (174 . 177) 180 (182 . 184) 191 215 247 + (706 . 709) (722 . 735) (741 . 747) 749 (751 . 767) 885 + 894 (900 . 901) 903 1014 1154 (1370 . 1375) (1417 . 1418) + (1421 . 1423) 1470 1472 1475 1478 (1523 . 1524) (1542 . 1551) + 1563 (1566 . 1567) (1642 . 1645) 1748 1758 1769 (1789 . 1790) + (1792 . 1805) (2038 . 2041) (2096 . 2110) 2142 (2404 . 2405) + 2416 (2546 . 2547) (2554 . 2555) (2800 . 2801) 2928 + (3059 . 3066) 3199 3449 3572 3647 3663 (3674 . 3675) + (3841 . 3863) (3866 . 3871) 3892 3894 3896 3973 (4030 . 4037) + (4039 . 4044) (4046 . 4058) (4170 . 4175) (4254 . 4255) + 4347 (4960 . 4968) (5008 . 5017) 5120 (5741 . 5742) + (5867 . 5869) (5941 . 5942) (6100 . 6102) (6104 . 6107) + (6144 . 6154) 6464 (6468 . 6469) (6622 . 6623) (6624 . 6655) + (6686 . 6687) (6816 . 6822) (6824 . 6829) (7002 . 7018) + (7028 . 7036) (7164 . 7167) (7227 . 7231) (7294 . 7295) + (7360 . 7367) 7379 8125 (8127 . 8129) (8141 . 8143) + (8157 . 8159) (8173 . 8175) (8189 . 8190) (8208 . 8215) + (8224 . 8231) (8240 . 8248) (8251 . 8260) (8263 . 8286) + (8314 . 8316) (8330 . 8332) (8352 . 8381) (8448 . 8449) + (8451 . 8454) (8456 . 8457) 8468 (8470 . 8472) (8478 . 8483) + 8485 8487 8489 8494 (8506 . 8507) (8512 . 8516) (8522 . 8525) + 8527 (8592 . 8703) (8704 . 8959) (8960 . 8967) (8972 . 9000) + (9003 . 9210) (9216 . 9254) (9280 . 9290) (9372 . 9449) + (9472 . 9599) (9600 . 9631) (9632 . 9727) (9728 . 9983) + (9984 . 10087) (10132 . 10175) (10176 . 10180) (10183 . 10213) + (10224 . 10239) (10240 . 10495) (10496 . 10623) (10624 . 10626) + (10649 . 10711) (10716 . 10747) (10750 . 10751) (10752 . 11007) + (11008 . 11123) (11126 . 11157) (11160 . 11193) (11197 . 11208) + (11210 . 11217) (11493 . 11498) (11513 . 11516) (11518 . 11519) + 11632 (11776 . 11777) (11782 . 11784) 11787 (11790 . 11803) + (11806 . 11807) (11818 . 11822) (11824 . 11841) (11904 . 11929) + (11931 . 12019) (12032 . 12245) (12272 . 12283) (12289 . 12292) + (12306 . 12307) 12316 12320 12336 (12342 . 12343) + (12349 . 12351) (12443 . 12444) 12448 12539 (12688 . 12689) + (12694 . 12703) (12736 . 12771) (12800 . 12830) (12842 . 12871) + 12880 (12896 . 12927) (12938 . 12976) (12992 . 13054) + (13056 . 13311) (19904 . 19967) (42128 . 42182) (42238 . 42239) + (42509 . 42511) 42611 42622 (42738 . 42743) (42752 . 42774) + (42784 . 42785) (42889 . 42890) (43048 . 43051) (43062 . 43065) + (43124 . 43127) (43214 . 43215) (43256 . 43258) (43310 . 43311) + 43359 (43457 . 43469) (43486 . 43487) (43612 . 43615) + (43639 . 43641) (43742 . 43743) (43760 . 43761) 43867 + 44011 64297 (64434 . 64449) (65020 . 65021) (65040 . 65046) + 65049 (65072 . 65076) (65093 . 65094) (65097 . 65103) + (65104 . 65106) (65108 . 65112) (65119 . 65126) (65128 . 65131) + (65281 . 65287) (65290 . 65295) (65306 . 65312) 65340 + (65342 . 65344) 65372 65374 65377 (65380 . 65381) + (65504 . 65510) (65512 . 65518) (65532 . 65533) (65792 . 65794) + (65847 . 65855) (65913 . 65929) 65932 (65936 . 65947) + 65952 (66000 . 66044) 66463 66512 66927 67671 (67703 . 67704) + 67871 67903 (68176 . 68184) 68223 68296 (68336 . 68342) + (68409 . 68415) (68505 . 68508) (69703 . 69709) (69819 . 69820) + (69822 . 69825) (69952 . 69955) (70004 . 70005) (70085 . 70088) + 70093 (70200 . 70205) 70854 (71105 . 71113) (71233 . 71235) + (74864 . 74868) (92782 . 92783) 92917 (92983 . 92991) + (92996 . 92997) 113820 113823 (118784 . 119029) (119040 . 119078) + (119081 . 119140) (119146 . 119148) (119171 . 119172) + (119180 . 119209) (119214 . 119261) (119296 . 119361) + 119365 (119552 . 119638) 120513 120539 120571 120597 + 120629 120655 120687 120713 120745 120771 (126704 . 126705) + (126976 . 127019) (127024 . 127123) (127136 . 127150) + (127153 . 127167) (127169 . 127183) (127185 . 127221) + (127248 . 127278) (127280 . 127339) (127344 . 127386) + (127462 . 127487) (127488 . 127490) (127504 . 127546) + (127552 . 127560) (127568 . 127569) (127744 . 127788) + (127792 . 127869) (127872 . 127950) (127956 . 127991) + (128000 . 128254) (128256 . 128330) (128336 . 128377) + (128379 . 128419) (128421 . 128511) (128512 . 128578) + (128581 . 128591) (128592 . 128639) (128640 . 128719) + (128736 . 128748) (128752 . 128755) (128768 . 128883) + (128896 . 128980) (129024 . 129035) (129040 . 129095) + (129104 . 129113) (129120 . 129159) (129168 . 129197))) + +(defvar haskell--char-syntax-identifiers + '(170 + (178 . 179) 181 (185 . 186) (188 . 190) (192 . 214) (216 . 246) + (248 . 255) (256 . 383) (384 . 591) (592 . 687) (880 . 883) + (886 . 887) (891 . 893) 895 902 (904 . 906) 908 (910 . 929) (931 . 1013) + (1015 . 1023) (1024 . 1153) (1162 . 1279) (1280 . 1327) + (1329 . 1366) (1377 . 1415) (1488 . 1514) (1520 . 1522) (1568 . 1599) + (1601 . 1610) (1632 . 1641) (1646 . 1647) (1649 . 1747) 1749 + (1774 . 1788) 1791 1808 (1810 . 1839) (1869 . 1871) (1872 . 1919) + (1920 . 1957) 1969 (1984 . 2026) (2048 . 2069) (2112 . 2136) (2208 . 2226) + (2308 . 2361) 2365 2384 (2392 . 2401) (2406 . 2415) (2418 . 2431) + 2432 (2437 . 2444) (2447 . 2448) (2451 . 2472) (2474 . 2480) + 2482 (2486 . 2489) 2493 2510 (2524 . 2525) (2527 . 2529) (2534 . 2545) + (2548 . 2553) (2565 . 2570) (2575 . 2576) (2579 . 2600) + (2602 . 2608) (2610 . 2611) (2613 . 2614) (2616 . 2617) (2649 . 2652) + 2654 (2662 . 2671) (2674 . 2676) (2693 . 2701) (2703 . 2705) + (2707 . 2728) (2730 . 2736) (2738 . 2739) (2741 . 2745) 2749 2768 + (2784 . 2785) (2790 . 2799) (2821 . 2828) (2831 . 2832) (2835 . 2856) + (2858 . 2864) (2866 . 2867) (2869 . 2873) 2877 (2908 . 2909) + (2911 . 2913) (2918 . 2927) (2929 . 2935) 2947 (2949 . 2954) (2958 . 2960) + (2962 . 2965) (2969 . 2970) 2972 (2974 . 2975) (2979 . 2980) + (2984 . 2986) (2990 . 3001) 3024 (3046 . 3058) (3077 . 3084) (3086 . 3088) + (3090 . 3112) (3114 . 3129) 3133 (3160 . 3161) (3168 . 3169) + (3174 . 3183) (3192 . 3198) (3205 . 3212) (3214 . 3216) (3218 . 3240) + (3242 . 3251) (3253 . 3257) 3261 3294 (3296 . 3297) (3302 . 3311) + (3313 . 3314) (3333 . 3340) (3342 . 3344) (3346 . 3386) 3389 + 3406 (3424 . 3425) (3430 . 3445) (3450 . 3455) (3461 . 3478) (3482 . 3505) + (3507 . 3515) 3517 (3520 . 3526) (3558 . 3567) (3585 . 3632) + (3634 . 3635) (3648 . 3653) (3664 . 3673) (3713 . 3714) 3716 (3719 . 3720) + 3722 3725 (3732 . 3735) (3737 . 3743) (3745 . 3747) 3749 + 3751 (3754 . 3755) (3757 . 3760) (3762 . 3763) 3773 (3776 . 3780) + (3792 . 3801) (3804 . 3807) 3840 (3872 . 3891) (3904 . 3911) (3913 . 3948) + (3976 . 3980) (4096 . 4138) (4159 . 4169) (4176 . 4181) + (4186 . 4189) 4193 (4197 . 4198) (4206 . 4208) (4213 . 4225) 4238 + (4240 . 4249) (4256 . 4293) 4295 4301 (4304 . 4346) (4349 . 4351) + (4352 . 4607) (4608 . 4680) (4682 . 4685) (4688 . 4694) 4696 (4698 . 4701) + (4704 . 4744) (4746 . 4749) (4752 . 4784) (4786 . 4789) + (4792 . 4798) 4800 (4802 . 4805) (4808 . 4822) (4824 . 4880) (4882 . 4885) + (4888 . 4954) (4969 . 4988) (4992 . 5007) (5024 . 5108) + (5121 . 5740) (5743 . 5759) (5761 . 5786) (5792 . 5866) (5873 . 5880) + (5888 . 5900) (5902 . 5905) (5920 . 5937) (5952 . 5969) + (5984 . 5996) (5998 . 6000) (6016 . 6067) 6108 (6112 . 6121) (6128 . 6137) + (6160 . 6169) (6176 . 6210) (6212 . 6263) (6272 . 6312) 6314 + (6320 . 6389) (6400 . 6430) (6470 . 6479) (6480 . 6509) (6512 . 6516) + (6528 . 6571) (6593 . 6599) (6608 . 6618) (6656 . 6678) + (6688 . 6740) (6784 . 6793) (6800 . 6809) (6917 . 6963) (6981 . 6987) + (6992 . 7001) (7043 . 7072) (7086 . 7103) (7104 . 7141) + (7168 . 7203) (7232 . 7241) (7245 . 7247) (7248 . 7287) (7401 . 7404) + (7406 . 7409) (7413 . 7414) (7424 . 7467) (7531 . 7543) + (7545 . 7551) (7552 . 7578) (7680 . 7935) (7936 . 7957) (7960 . 7965) + (7968 . 8005) (8008 . 8013) (8016 . 8023) 8025 8027 8029 + (8031 . 8061) (8064 . 8116) (8118 . 8124) 8126 (8130 . 8132) (8134 . 8140) + (8144 . 8147) (8150 . 8155) (8160 . 8172) (8178 . 8180) + (8182 . 8188) 8304 (8308 . 8313) (8320 . 8329) 8450 8455 (8458 . 8467) + 8469 (8473 . 8477) 8484 8486 8488 (8490 . 8493) (8495 . 8505) + (8508 . 8511) (8517 . 8521) 8526 (8528 . 8543) (8579 . 8580) + 8585 (9312 . 9371) (9450 . 9471) (10102 . 10131) (11264 . 11310) + (11312 . 11358) (11360 . 11387) (11390 . 11391) (11392 . 11492) + (11499 . 11502) (11506 . 11507) 11517 (11520 . 11557) 11559 11565 + (11568 . 11623) (11648 . 11670) (11680 . 11686) (11688 . 11694) + (11696 . 11702) (11704 . 11710) (11712 . 11718) (11720 . 11726) + (11728 . 11734) (11736 . 11742) 12294 12348 (12353 . 12438) 12447 + (12449 . 12538) 12543 (12549 . 12589) (12593 . 12686) (12690 . 12693) + (12704 . 12730) (12784 . 12799) (12832 . 12841) (12872 . 12879) + (12881 . 12895) (12928 . 12937) (12977 . 12991) (13312 . 19893) + (19968 . 40908) (40960 . 40980) (40982 . 42124) (42192 . 42231) + (42240 . 42507) (42512 . 42539) (42560 . 42606) (42624 . 42651) + (42656 . 42725) (42786 . 42863) (42865 . 42887) (42891 . 42894) + (42896 . 42925) (42928 . 42929) 42999 (43002 . 43007) + (43008 . 43009) (43011 . 43013) (43015 . 43018) (43020 . 43042) + (43056 . 43061) (43072 . 43123) (43138 . 43187) (43216 . 43225) + (43250 . 43255) 43259 (43264 . 43301) (43312 . 43334) (43360 . 43388) + (43396 . 43442) (43472 . 43481) (43488 . 43492) (43495 . 43518) + (43520 . 43560) (43584 . 43586) (43588 . 43595) (43600 . 43609) + (43616 . 43631) (43633 . 43638) 43642 (43646 . 43647) + (43648 . 43695) 43697 (43701 . 43702) (43705 . 43709) 43712 43714 + (43739 . 43740) (43744 . 43754) 43762 (43777 . 43782) (43785 . 43790) + (43793 . 43798) (43808 . 43814) (43816 . 43822) (43824 . 43866) + (43876 . 43877) (43968 . 44002) (44016 . 44025) (44032 . 55203) + (55216 . 55238) (55243 . 55291) (63744 . 64109) (64112 . 64217) + (64256 . 64262) (64275 . 64279) 64285 (64287 . 64296) + (64298 . 64310) (64312 . 64316) 64318 (64320 . 64321) (64323 . 64324) + (64326 . 64335) (64336 . 64433) (64467 . 64829) (64848 . 64911) + (64914 . 64967) (65008 . 65019) (65136 . 65140) (65142 . 65276) + (65296 . 65305) (65313 . 65338) (65345 . 65370) (65382 . 65391) + (65393 . 65437) (65440 . 65470) (65474 . 65479) (65482 . 65487) + (65490 . 65495) (65498 . 65500) (65536 . 65547) (65549 . 65574) + (65576 . 65594) (65596 . 65597) (65599 . 65613) (65616 . 65629) + (65664 . 65786) (65799 . 65843) (65909 . 65912) (65930 . 65931) + (66176 . 66204) (66208 . 66256) (66273 . 66299) (66304 . 66339) + (66352 . 66368) (66370 . 66377) (66384 . 66421) (66432 . 66461) + (66464 . 66499) (66504 . 66511) (66560 . 66639) (66640 . 66687) + (66688 . 66717) (66720 . 66729) (66816 . 66855) (66864 . 66915) + (67072 . 67382) (67392 . 67413) (67424 . 67431) (67584 . 67589) + 67592 (67594 . 67637) (67639 . 67640) 67644 67647 (67648 . 67669) + (67672 . 67679) (67680 . 67702) (67705 . 67711) (67712 . 67742) + (67751 . 67759) (67840 . 67867) (67872 . 67897) (67968 . 67999) + (68000 . 68023) (68030 . 68031) 68096 (68112 . 68115) + (68117 . 68119) (68121 . 68147) (68160 . 68167) (68192 . 68222) + (68224 . 68255) (68288 . 68295) (68297 . 68324) (68331 . 68335) + (68352 . 68405) (68416 . 68437) (68440 . 68447) (68448 . 68466) + (68472 . 68479) (68480 . 68497) (68521 . 68527) (68608 . 68680) + (69216 . 69246) (69635 . 69687) (69714 . 69743) (69763 . 69807) + (69840 . 69864) (69872 . 69881) (69891 . 69926) (69942 . 69951) + (69968 . 70002) 70006 (70019 . 70066) (70081 . 70084) (70096 . 70106) + (70113 . 70132) (70144 . 70161) (70163 . 70187) (70320 . 70366) + (70384 . 70393) (70405 . 70412) (70415 . 70416) (70419 . 70440) + (70442 . 70448) (70450 . 70451) (70453 . 70457) 70461 + (70493 . 70497) (70784 . 70831) (70852 . 70853) 70855 (70864 . 70873) + (71040 . 71086) (71168 . 71215) 71236 (71248 . 71257) + (71296 . 71338) (71360 . 71369) (71840 . 71922) 71935 (72384 . 72440) + (73728 . 74648) (77824 . 78894) (92160 . 92728) (92736 . 92766) + (92768 . 92777) (92880 . 92909) (92928 . 92975) (93008 . 93017) + (93019 . 93025) (93027 . 93047) (93053 . 93071) (93952 . 94020) + 94032 (110592 . 110593) (113664 . 113770) (113776 . 113788) + (113792 . 113800) (113808 . 113817) (119648 . 119665) (119808 . 119892) + (119894 . 119964) (119966 . 119967) 119970 (119973 . 119974) + (119977 . 119980) (119982 . 119993) 119995 (119997 . 120003) + (120005 . 120069) (120071 . 120074) (120077 . 120084) + (120086 . 120092) (120094 . 120121) (120123 . 120126) (120128 . 120132) + 120134 (120138 . 120144) (120146 . 120485) (120488 . 120512) + (120514 . 120538) (120540 . 120570) (120572 . 120596) + (120598 . 120628) (120630 . 120654) (120656 . 120686) (120688 . 120712) + (120714 . 120744) (120746 . 120770) (120772 . 120779) + (120782 . 120831) (124928 . 125124) (125127 . 125135) (126464 . 126467) + (126469 . 126495) (126497 . 126498) 126500 126503 (126505 . 126514) + (126516 . 126519) 126521 126523 126530 126535 126537 + 126539 (126541 . 126543) (126545 . 126546) 126548 126551 126553 + 126555 126557 126559 (126561 . 126562) 126564 (126567 . 126570) + (126572 . 126578) (126580 . 126583) (126585 . 126588) 126590 (126592 . 126601) + (126603 . 126619) (126625 . 126627) (126629 . 126633) + (126635 . 126651) (127232 . 127244) (131072 . 173782) (173824 . 177972) + (177984 . 178205) (194560 . 195101))) + + +;; Syntax table. +(defvar haskell-mode-syntax-table + (let ((table (make-syntax-table))) + (modify-syntax-entry ?\ " " table) + (modify-syntax-entry ?\t " " table) + (modify-syntax-entry ?\" "\"" table) + (modify-syntax-entry ?\' "_" table) + (modify-syntax-entry ?_ "_" table) + (modify-syntax-entry ?\( "()" table) + (modify-syntax-entry ?\) ")(" table) + (modify-syntax-entry ?\[ "(]" table) + (modify-syntax-entry ?\] ")[" table) + + (modify-syntax-entry ?\{ "(}1nb" table) + (modify-syntax-entry ?\} "){4nb" table) + (modify-syntax-entry ?- ". 123" table) + (modify-syntax-entry ?\n ">" table) + + (modify-syntax-entry ?\` "$`" table) + + (mapc (lambda (x) + (modify-syntax-entry x "." table)) + "!#$%&*+./:<=>?@^|~,;\\") + + ;; Haskell symbol characters are treated as punctuation because + ;; they are not able to form identifiers with word constituent 'w' + ;; class characters. + (dolist (charcodes haskell--char-syntax-symbols) + (modify-syntax-entry charcodes "." table)) + ;; ... and for identifier characters + (dolist (charcodes haskell--char-syntax-identifiers) + (modify-syntax-entry charcodes "w" table)) + + table) + "Syntax table used in Haskell mode.") + +(defun haskell-syntax-propertize (begin end) + (save-excursion + (when haskell-literate + (goto-char begin) + ;; Algorithm (first matching rule wins): + ;; - current line is latex code if previous non-empty line was + ;; latex code or was \begin{code} and current line is not + ;; \end{code} + ;; - current line is bird code if it starts with > + ;; - else literate comment + (let ((previous-line-latex-code + (catch 'return + (save-excursion + (when (= (forward-line -1) 0) + (while (looking-at-p "^[\t ]*$") + (unless (= (forward-line -1) 0) + (throw 'return nil))) + (or + (and + (not (equal (string-to-syntax "<") (syntax-after (point)))) + (not (looking-at-p "^>"))) + (looking-at-p "^\\\\begin{code}[\t ]*$"))))))) + (while (< (point) end) + (unless (looking-at-p "^[\t ]*$") + (if previous-line-latex-code + (if (looking-at-p "^\\\\end{code}[\t ]*$") + (progn + (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax "<")) + (setq previous-line-latex-code nil)) + ;; continue latex-code + ) + (if (looking-at-p "^>") + ;; this is a whitespace + (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax "-")) + ;; this is a literate comment + (progn + (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax "<")) + (when (looking-at-p "^\\\\begin{code}[\t ]*$") + (setq previous-line-latex-code t)))))) + (forward-line 1)))) + + (goto-char begin) + (let ((ppss (syntax-ppss))) + (when (nth 4 ppss) + ;; go to the end of a comment, there is nothing to see inside + ;; a comment so we might as well just skip over it + ;; immediatelly + (setq ppss (parse-partial-sexp (point) (point-max) nil nil ppss + 'syntax-table))) + (when (nth 8 ppss) + ;; go to the beginning of a comment or string + (goto-char (nth 8 ppss)) + (when (equal ?| (nth 3 ppss)) + ;; if this is a quasi quote we need to backtrack even more + ;; to the opening bracket + (skip-chars-backward "^[") + (goto-char (1- (point))))) + + (while (< (point) end) + (let + ((token-kind (haskell-lexeme-looking-at-token))) + + (cond + ((equal token-kind 'qsymid) + (when (member + (haskell-lexeme-classify-by-first-char (char-after (match-beginning 1))) + '(varsym consym)) + ;; we have to neutralize potential comments here + (put-text-property (match-beginning 1) (match-end 1) 'syntax-table (string-to-syntax ".")))) + ((equal token-kind 'number) + (put-text-property (match-beginning 0) (match-end 0) 'syntax-table (string-to-syntax "w"))) + ((equal token-kind 'char) + (save-excursion + (goto-char (match-beginning 2)) + (let ((limit (match-end 2))) + (save-match-data + (while (re-search-forward "\"" limit t) + (put-text-property (match-beginning 0) (match-end 0) 'syntax-table (string-to-syntax "."))))) + ;; Place a generic string delimeter only when an open + ;; quote is closed by end-of-line Emacs acts strangely + ;; when a generic delimiter is not closed so in case + ;; string ends at the end of the buffer we will use + ;; plain string + (if (and (not (match-beginning 3)) + (not (equal (match-end 2) (point-max)))) + (progn + (put-text-property (match-beginning 1) (match-end 1) 'syntax-table (string-to-syntax "|")) + (put-text-property (match-end 2 ) (1+ (match-end 2)) 'syntax-table (string-to-syntax "|"))) + (put-text-property (match-beginning 1) (match-end 1) 'syntax-table (string-to-syntax "\"")) + (when (not (equal (match-end 2) (point-max))) + (put-text-property (match-end 2 ) (1+ (match-end 2)) 'syntax-table (string-to-syntax "\"")))))) + ((equal token-kind 'string) + (save-excursion + (goto-char (match-beginning 2)) + (let ((limit (match-end 2))) + (save-match-data + (while (re-search-forward "\"" limit t) + (put-text-property (match-beginning 0) (match-end 0) 'syntax-table (string-to-syntax "."))))) + ;; Place a generic string delimeter only when an open + ;; quote is closed by end-of-line Emacs acts strangely + ;; when a generic delimiter is not closed so in case + ;; string ends at the end of the buffer we will use + ;; plain string + (when (and (not (match-beginning 3)) + (not (equal (match-end 2) (point-max)))) + (put-text-property (match-beginning 1) (match-end 1) 'syntax-table (string-to-syntax "|")) + (put-text-property (match-end 2 ) (1+ (match-end 2)) 'syntax-table (string-to-syntax "|"))))) + ((equal token-kind 'template-haskell-quasi-quote) + (put-text-property (match-beginning 2) (match-end 2) 'syntax-table (string-to-syntax "\"")) + (when (match-beginning 4) + (put-text-property (match-beginning 4) (match-end 4) 'syntax-table (string-to-syntax "\""))) + (save-excursion + (goto-char (match-beginning 3)) + (let ((limit (match-end 3))) + (save-match-data + (while (re-search-forward "\"" limit t) + (put-text-property (match-beginning 0) (match-end 0) 'syntax-table (string-to-syntax ".")))))))) + (if token-kind + (goto-char (match-end 0)) + (goto-char end))))))) + +(defun haskell-ident-at-point () + "Return the identifier near point going backward or nil if none found. +May return a qualified name." + (let ((reg (haskell-ident-pos-at-point))) + (when reg + (buffer-substring-no-properties (car reg) (cdr reg))))) + +(defun haskell-spanable-pos-at-point () + "Like `haskell-ident-pos-at-point', but includes any surrounding backticks." + (save-excursion + (let ((pos (haskell-ident-pos-at-point))) + (when pos + (cl-destructuring-bind (start . end) pos + (if (and (eq ?` (char-before start)) + (eq ?` (char-after end))) + (cons (- start 1) (+ end 1)) + (cons start end))))))) + +(defun haskell-ident-pos-at-point () + "Return the span of the identifier near point going backward. +Returns nil if no identifier found or point is inside string or +comment. May return a qualified name." + (when (not (nth 8 (syntax-ppss))) + ;; Do not handle comments and strings + (let (start end) + ;; Initial point position is non-deterministic, it may occur anywhere + ;; inside identifier span, so the approach is: + ;; - first try go left and find left boundary + ;; - then try go right and find right boundary + ;; + ;; In both cases assume the longest path, e.g. when going left take into + ;; account than point may occur at the end of identifier, when going right + ;; take into account that point may occur at the beginning of identifier. + ;; + ;; We should handle `.` character very careful because it is heavily + ;; overloaded. Examples of possible cases: + ;; Control.Monad.>>= -- delimiter + ;; Control.Monad.when -- delimiter + ;; Data.Aeson..: -- delimiter and operator symbol + ;; concat.map -- composition function + ;; .? -- operator symbol + (save-excursion + ;; First, skip whitespace if we're on it, moving point to last + ;; identifier char. That way, if we're at "map ", we'll see the word + ;; "map". + (when (and (eolp) + (not (bolp))) + (backward-char)) + (when (and (not (eobp)) + (eq (char-syntax (char-after)) ? )) + (skip-chars-backward " \t") + (backward-char)) + ;; Now let's try to go left. + (save-excursion + (if (not (haskell-mode--looking-at-varsym)) + ;; Looking at non-operator char, this is quite simple + (progn + (skip-syntax-backward "w_") + ;; Remember position + (setq start (point))) + ;; Looking at operator char. + (while (and (not (bobp)) + (haskell-mode--looking-at-varsym)) + ;; skip all operator chars backward + (setq start (point)) + (backward-char)) + ;; Extra check for case when reached beginning of the buffer. + (when (haskell-mode--looking-at-varsym) + (setq start (point)))) + ;; Slurp qualification part if present. If identifier is qualified in + ;; case of non-operator point will stop before `.` dot, but in case of + ;; operator it will stand at `.` delimiting dot. So if we're looking + ;; at `.` let's step one char forward and try to get qualification + ;; part. + (goto-char start) + (when (looking-at-p (rx ".")) + (forward-char)) + (let ((pos (haskell-mode--skip-qualification-backward))) + (when pos + (setq start pos)))) + ;; Finally, let's try to go right. + (save-excursion + ;; Try to slurp qualification part first. + (skip-syntax-forward "w_") + (setq end (point)) + (while (and (looking-at (rx "." upper)) + (not (zerop (progn (forward-char) + (skip-syntax-forward "w_"))))) + (setq end (point))) + ;; If point was at non-operator we already done, otherwise we need an + ;; extra check. + (while (haskell-mode--looking-at-varsym) + (forward-char) + (setq end (point)))) + (when (not (= start end)) + (cons start end)))))) + +(defun haskell-mode--looking-at-varsym () + "Return t when point stands at operator symbol." + (when (not (eobp)) + (let ((lex (haskell-lexeme-classify-by-first-char (char-after)))) + (or (eq lex 'varsym) + (eq lex 'consym))))) + +(defun haskell-mode--skip-qualification-backward () + "Skip qualified part of identifier backward. +Expects point stands *after* delimiting dot. +Returns beginning position of qualified part or nil if no qualified part found." + (when (not (and (bobp) + (looking-at (rx bol)))) + (let ((case-fold-search nil) + pos) + (while (and (eq (char-before) ?.) + (progn (backward-char) + (not (zerop (skip-syntax-backward "w'")))) + (skip-syntax-forward "'") + (looking-at "[[:upper:]]")) + (setq pos (point))) + pos))) + +(defun haskell-delete-indentation (&optional arg) + "Like `delete-indentation' but ignoring Bird-style \">\"." + (interactive "*P") + (let ((fill-prefix (or fill-prefix (if (eq haskell-literate 'bird) ">")))) + (delete-indentation arg))) + +(defvar eldoc-print-current-symbol-info-function) + +;; The main mode functions +;;;###autoload +(define-derived-mode haskell-mode prog-mode "Haskell" + "Major mode for editing Haskell programs. + +\\<haskell-mode-map> + +Literate Haskell scripts are supported via `literate-haskell-mode'. +The variable `haskell-literate' indicates the style of the script in the +current buffer. See the documentation on this variable for more details. + +Use `haskell-version' to find out what version of Haskell mode you are +currently using. + +Additional Haskell mode modules can be hooked in via `haskell-mode-hook'. + +Indentation modes: + + `haskell-indentation-mode', Kristof Bastiaensen, Gergely Risko + Intelligent semi-automatic indentation Mk2 + + `haskell-indent-mode', Guy Lapalme + Intelligent semi-automatic indentation. + +Interaction modes: + + `interactive-haskell-mode' + Interact with per-project GHCi processes through a REPL and + directory-aware sessions. + +Other modes: + + `haskell-decl-scan-mode', Graeme E Moss + Scans top-level declarations, and places them in a menu. + + `haskell-doc-mode', Hans-Wolfgang Loidl + Echoes types of functions or syntax of keywords when the cursor is idle. + +To activate a minor-mode, simply run the interactive command. For +example, `M-x haskell-doc-mode'. Run it again to disable it. + +To enable a mode for every haskell-mode buffer, add a hook in +your Emacs configuration. To do that you can customize +`haskell-mode-hook' or add lines to your .emacs file. For +example, to enable `interactive-haskell-mode', use the following: + + (add-hook 'haskell-mode-hook 'interactive-haskell-mode) + +Minor modes that work well with `haskell-mode': + +- `smerge-mode': show and work with diff3 conflict markers used + by git, svn and other version control systems." + :group 'haskell + (when (version< emacs-version "24.3") + (error "haskell-mode requires at least Emacs 24.3")) + + ;; paragraph-{start,separate} should treat comments as paragraphs as well. + (setq-local paragraph-start (concat " *{-\\| *-- |\\|" page-delimiter)) + (setq-local paragraph-separate (concat " *$\\| *\\({-\\|-}\\) *$\\|" page-delimiter)) + (setq-local fill-paragraph-function 'haskell-fill-paragraph) + ;; (setq-local adaptive-fill-function 'haskell-adaptive-fill) + (setq-local comment-start "-- ") + (setq-local comment-padding 0) + (setq-local comment-start-skip "[-{]-[ \t]*") + (setq-local comment-end "") + (setq-local comment-end-skip "[ \t]*\\(-}\\|\\s>\\)") + (setq-local forward-sexp-function #'haskell-forward-sexp) + (setq-local parse-sexp-ignore-comments nil) + (setq-local syntax-propertize-function #'haskell-syntax-propertize) + + ;; Set things up for eldoc-mode. + (setq-local eldoc-documentation-function 'haskell-doc-current-info) + ;; Set things up for imenu. + (setq-local imenu-create-index-function 'haskell-ds-create-imenu-index) + ;; Set things up for font-lock. + (setq-local font-lock-defaults + '((haskell-font-lock-keywords) + nil nil nil nil + (font-lock-syntactic-face-function + . haskell-syntactic-face-function) + ;; Get help from font-lock-syntactic-keywords. + (parse-sexp-lookup-properties . t) + (font-lock-extra-managed-props . (composition haskell-type)))) + ;; Preprocessor definitions can have backslash continuations + (setq-local font-lock-multiline t) + ;; Haskell's layout rules mean that TABs have to be handled with extra care. + ;; The safer option is to avoid TABs. The second best is to make sure + ;; TABs stops are 8 chars apart, as mandated by the Haskell Report. --Stef + (setq-local indent-tabs-mode nil) + (setq-local tab-width 8) + (setq-local comment-auto-fill-only-comments t) + ;; Haskell is not generally suitable for electric indentation, since + ;; there is no unambiguously correct indent level for any given line. + (when (boundp 'electric-indent-inhibit) + (setq electric-indent-inhibit t)) + + ;; dynamic abbrev support: recognize Haskell identifiers + ;; Haskell is case-sensitive language + (setq-local dabbrev-case-fold-search nil) + (setq-local dabbrev-case-distinction nil) + (setq-local dabbrev-case-replace nil) + (setq-local dabbrev-abbrev-char-regexp "\\sw\\|[.]") + (setq haskell-literate nil) + (add-hook 'before-save-hook 'haskell-mode-before-save-handler nil t) + (add-hook 'after-save-hook 'haskell-mode-after-save-handler nil t) + ;; provide non-interactive completion function + (add-hook 'completion-at-point-functions + 'haskell-completions-completion-at-point + nil + t) + (haskell-indentation-mode)) + +(defcustom haskell-mode-hook '(haskell-indentation-mode interactive-haskell-mode) + "List of functions to run after `haskell-mode' is enabled. + +Use to enable minor modes coming with `haskell-mode' or run an +arbitrary function. + +Note that `haskell-indentation-mode' and `haskell-indent-mode' should not be +run at the same time." + :group 'haskell + :type 'hook + :options '(capitalized-words-mode + flyspell-prog-mode + haskell-decl-scan-mode + haskell-indent-mode + haskell-indentation-mode + highlight-uses-mode + imenu-add-menubar-index + interactive-haskell-mode + turn-on-haskell-unicode-input-method)) + +(defun haskell-fill-paragraph (justify) + (save-excursion + ;; Fill paragraph should only work in comments. + ;; The -- comments are handled properly by default + ;; The {- -} comments need some extra love. + (let* ((syntax-values (syntax-ppss)) + (comment-num (nth 4 syntax-values))) + (cond + ((eq t comment-num) + ;; standard fill works wonders inside a non-nested comment + (fill-comment-paragraph justify)) + + ((integerp comment-num) + ;; we are in a nested comment. lets narrow to comment content + ;; and use plain paragraph fill for that + (let* ((comment-start-point (nth 8 syntax-values)) + (comment-end-point + (save-excursion + (goto-char comment-start-point) + (forward-sexp) + ;; Find end of any comment even if forward-sexp + ;; fails to find the right braces. + (backward-char 3) + (re-search-forward "[ \t]?-}" nil t) + (match-beginning 0))) + (fill-start (+ 2 comment-start-point)) + (fill-end comment-end-point) + (fill-paragraph-handle-comment nil)) + (save-restriction + (narrow-to-region fill-start fill-end) + (fill-paragraph justify) + ;; If no filling happens, whatever called us should not + ;; continue with standard text filling, so return t + t))) + ((eolp) + ;; do nothing outside of a comment + t) + (t + ;; go to end of line and try again + (end-of-line) + (haskell-fill-paragraph justify)))))) + + +;; (defun haskell-adaptive-fill () +;; ;; We want to use "-- " as the prefix of "-- |", etc. +;; (let* ((line-end (save-excursion (end-of-line) (point))) +;; (line-start (point))) +;; (save-excursion +;; (unless (in-comment) +;; ;; Try to find the start of a comment. We only fill comments. +;; (search-forward-regexp comment-start-skip line-end t)) +;; (when (in-comment) +;; (let ();(prefix-start (point))) +;; (skip-syntax-forward "^w") +;; (make-string (- (point) line-start) ?\s)))))) + +;;;###autoload +(defun haskell-forward-sexp (&optional arg) + "Haskell specific version of `forward-sexp'. + +Move forward across one balanced expression (sexp). With ARG, do +it that many times. Negative arg -N means move backward across N +balanced expressions. This command assumes point is not in a +string or comment. + +If unable to move over a sexp, signal `scan-error' with three +arguments: a message, the start of the obstacle (a parenthesis or +list marker of some kind), and end of the obstacle." + (interactive "^p") + (or arg (setq arg 1)) + (if (< arg 0) + (while (< arg 0) + (skip-syntax-backward "->") + ;; Navigate backwards using plain `backward-sexp', assume that it + ;; skipped over at least one Haskell expression, and jump forward until + ;; last possible point before the starting position. If applicable, + ;; `scan-error' is signalled by `backward-sexp'. + (let ((end (point)) + (forward-sexp-function nil)) + (backward-sexp) + (let ((cur (point))) + (while (< (point) end) + (setf cur (point)) + (haskell-forward-sexp) + (skip-syntax-forward "->")) + (goto-char cur))) + (setf arg (1+ arg))) + (save-match-data + (while (> arg 0) + (when (haskell-lexeme-looking-at-token) + (cond ((member (match-string 0) (list "(" "[" "{")) + (goto-char (or (scan-sexps (point) 1) (buffer-end 1)))) + ((member (match-string 0) (list ")" "]" "}")) + (signal 'scan-error (list "Containing expression ends prematurely." + (match-beginning 0) + (match-end 0)))) + (t (goto-char (match-end 0))))) + (setf arg (1- arg)))))) + + + +;;;###autoload +(define-derived-mode literate-haskell-mode haskell-mode "LitHaskell" + "As `haskell-mode' but for literate scripts." + (setq haskell-literate + (save-excursion + (goto-char (point-min)) + (cond + ((re-search-forward "^\\\\\\(begin\\|end\\){code}$" nil t) 'tex) + ((re-search-forward "^>" nil t) 'bird) + (t haskell-literate-default)))) + (if (eq haskell-literate 'bird) + ;; fill-comment-paragraph isn't much use there, and even gets confused + ;; by the syntax-table text-properties we add to mark the first char + ;; of each line as a comment-starter. + (setq-local fill-paragraph-handle-comment nil)) + (setq-local mode-line-process '("/" (:eval (symbol-name haskell-literate))))) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.[gh]s\\'" . haskell-mode)) +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.hsig\\'" . haskell-mode)) +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.l[gh]s\\'" . literate-haskell-mode)) +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.hsc\\'" . haskell-mode)) +;;;###autoload +(add-to-list 'interpreter-mode-alist '("runghc" . haskell-mode)) +;;;###autoload +(add-to-list 'interpreter-mode-alist '("runhaskell" . haskell-mode)) +;;;###autoload +(add-to-list 'completion-ignored-extensions ".hi") + + +(defcustom haskell-check-command "hlint" + "*Command used to check a Haskell file." + :group 'haskell + :type '(choice (const "hlint") + (const "ghc -fno-code") + (string :tag "Other command"))) + +(defcustom haskell-tags-on-save nil + "Generate tags via hasktags after saving." + :group 'haskell + :type 'boolean) + +(defvar haskell-saved-check-command nil + "Internal use.") + +;; Like Python. Should be abstracted, sigh. +(defun haskell-check (command) + "Check a Haskell file (default current buffer's file). +Runs COMMAND, a shell command, as if by `compile'. +See `haskell-check-command' for the default." + (interactive + (list (read-string "Checker command: " + (or haskell-saved-check-command + (concat haskell-check-command " " + (let ((name (buffer-file-name))) + (if name + (file-name-nondirectory name)))))))) + (setq haskell-saved-check-command command) + (save-some-buffers (not compilation-ask-about-save) nil) + (compilation-start command)) + +(defun haskell-flymake-init () + "Flymake init function for Haskell. +To be added to `flymake-init-create-temp-buffer-copy'." + (let ((checker-elts (and haskell-saved-check-command + (split-string haskell-saved-check-command)))) + (list (car checker-elts) + (append (cdr checker-elts) + (list (flymake-init-create-temp-buffer-copy + 'flymake-create-temp-inplace)))))) + +(add-to-list 'flymake-allowed-file-name-masks '("\\.l?hs\\'" haskell-flymake-init)) + +(defun haskell-mode-format-imports () + "Format the imports by aligning and sorting them." + (interactive) + (let ((col (current-column))) + (haskell-sort-imports) + (haskell-align-imports) + (goto-char (+ (line-beginning-position) + col)))) + +(declare-function haskell-mode-stylish-buffer "haskell-commands") + +(defun haskell-mode-before-save-handler () + "Function that will be called before buffer's saving." + (when haskell-stylish-on-save + (ignore-errors (haskell-mode-stylish-buffer)))) + +;; From Bryan O'Sullivan's blog: +;; http://www.serpentine.com/blog/2007/10/09/using-emacs-to-insert-scc-annotations-in-haskell-code/ +(defun haskell-mode-try-insert-scc-at-point () + "Try to insert an SCC annotation at point. Return true if +successful, nil otherwise." + (if (or (looking-at "\\b\\|[ \t]\\|$") + ;; Allow SCC if point is on a non-letter with whitespace to the left + (and (not (bolp)) + (save-excursion + (forward-char -1) + (looking-at "[ \t]")))) + (let ((space-at-point (looking-at "[ \t]"))) + (unless (and (not (bolp)) (save-excursion + (forward-char -1) + (looking-at "[ \t]"))) + (insert " ")) + (insert "{-# SCC \"\" #-}") + (unless space-at-point + (insert " ")) + (forward-char (if space-at-point -5 -6)) + t ))) + +(defun haskell-mode-insert-scc-at-point () + "Insert an SCC annotation at point." + (interactive) + (if (not (haskell-mode-try-insert-scc-at-point)) + (error "Not over an area of whitespace"))) + +(make-obsolete + 'haskell-mode-insert-scc-at-point + 'haskell-mode-toggle-scc-at-point + "2015-11-11") + +(defun haskell-mode-try-kill-scc-at-point () + "Try to kill an SCC annotation at point. Return true if +successful, nil otherwise." + (save-excursion + (let ((old-point (point)) + (scc "\\({-#[ \t]*SCC \"[^\"]*\"[ \t]*#-}\\)[ \t]*")) + (while (not (or (looking-at scc) (bolp))) + (forward-char -1)) + (if (and (looking-at scc) + (<= (match-beginning 1) old-point) + (> (match-end 1) old-point)) + (progn (kill-region (match-beginning 0) (match-end 0)) + t))))) + +;; Also Bryan O'Sullivan's. +(defun haskell-mode-kill-scc-at-point () + "Kill the SCC annotation at point." + (interactive) + (if (not (haskell-mode-try-kill-scc-at-point)) + (error "No SCC at point"))) + +(make-obsolete + 'haskell-mode-kill-scc-at-point + 'haskell-mode-toggle-scc-at-point + "2015-11-11") + +(defun haskell-mode-toggle-scc-at-point () + "If point is in an SCC annotation, kill the annotation. Otherwise, try to insert a new annotation." + (interactive) + (if (not (haskell-mode-try-kill-scc-at-point)) + (if (not (haskell-mode-try-insert-scc-at-point)) + (error "Could not insert or remove SCC")))) + +(defun haskell-guess-module-name-from-file-name (file-name) + "Guess the module name from FILE-NAME. + +Based on given FILE-NAME this function tries to find path +components that look like module identifiers and composes full +module path using this information. For example: + + /Abc/Def/Xyz.lhs => Abc.Def.Xyz + /Ab-c/Def/Xyz.lhs => Def.Xyz + src/Abc/Def/Xyz.hs => Abc.Def.Xyz + c:\\src\\Abc\\Def\\Xyz.hs => Abc.Def.Xyz + nonmodule.txt => nil + +This function usually will be used with `buffer-file-name': + + (haskell-guess-module-name-from-file-name (buffer-file-name))" + + (let* ((file-name-sans-ext (file-name-sans-extension file-name)) + (components (cl-loop for part + in (reverse (split-string file-name-sans-ext "/")) + while (let ((case-fold-search nil)) + (string-match (concat "^" haskell-lexeme-modid "$") part)) + collect part))) + (when components + (mapconcat 'identity (reverse components) ".")))) + +(defun haskell-guess-module-name () + "Guess the current module name of the buffer. +Uses `haskell-guess-module-name-from-file-name'." + (haskell-guess-module-name-from-file-name (buffer-file-name))) + +(defvar haskell-auto-insert-module-format-string + "-- | \n\nmodule %s where\n\n" + "Template string that will be inserted in new haskell buffers via `haskell-auto-insert-module-template'.") + +(defun haskell-auto-insert-module-template () + "Insert a module template for the newly created buffer." + (interactive) + (when (and (= (point-min) + (point-max)) + (buffer-file-name)) + (insert (format haskell-auto-insert-module-format-string (haskell-guess-module-name-from-file-name (buffer-file-name)))) + (goto-char (point-min)) + (end-of-line))) + +;;;###autoload +(defun haskell-mode-generate-tags (&optional and-then-find-this-tag) + "Generate tags using Hasktags. This is synchronous function. + +If optional AND-THEN-FIND-THIS-TAG argument is present it is used +with function `xref-find-definitions' after new table was +generated." + (interactive) + (let* ((dir (haskell-cabal--find-tags-dir)) + (command (haskell-cabal--compose-hasktags-command dir))) + (if (not command) + (error "Unable to compose hasktags command") + (shell-command command) + (haskell-mode-message-line "Tags generated.") + (when and-then-find-this-tag + (let ((tags-file-name dir)) + (xref-find-definitions and-then-find-this-tag)))))) + +;; Provide ourselves: +(provide 'haskell-mode) +;;; haskell-mode.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-mode.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-mode.elc new file mode 100644 index 000000000000..b72cd8ee647f --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-mode.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-mode.info b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-mode.info new file mode 100644 index 000000000000..69dcfd97abe5 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-mode.info @@ -0,0 +1,2425 @@ +This is haskell-mode.info, produced by makeinfo version 6.1 from +haskell-mode.texi. + +This manual is for Haskell mode, version 16.1-git + + Copyright © 2013-2017 Haskell Mode contributors. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License + (http://www.gnu.org/licenses/fdl.html), Version 1.3 or any later + version published by the Free Software Foundation; with no + Invariant Sections, no Front-Cover Texts and no Back-Cover Texts. +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* Haskell Mode: (haskell-mode). Haskell Development Environment for Emacs(en) +END-INFO-DIR-ENTRY + + +File: haskell-mode.info, Node: Top, Next: Introduction, Up: (dir) + +Haskell Mode +************ + +Haskell Mode is an Haskell development Environment for GNU Emacs version +24.3 or later. It provides syntax-based indentation, font locking, +editing cabal files, and supports running an inferior Haskell +interpreter (e.g. GHCi). + +* Menu: + +* Introduction:: An introduction to Haskell Mode +* Installation:: How to get started +* Editing Haskell Code:: How to edit code +* Syntax highlighting:: Haskell Mode has colors +* Completion support:: Autocomplete +* Unicode support:: How to use Unicode +* Indentation:: Notes about indentation +* External indentation:: Other ways to indent code +* Autoformating:: Using external formatters +* Module templates:: Module templates +* Declaration scanning:: How to navigate in a source file +* Compilation:: How to compile +* Interactive Haskell:: How to interact with GHCi +* Editing Cabal files:: Cabal support +* Browsing Haddocks:: Using ‘w3m’ to browse documentation +* Spell checking strings and comments:: Using ‘flyspell-prog-mode’ +* Aligning code:: Aligning code using ‘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 +* Function index:: Index of commands +* Variable index:: Index of options and types + + +File: haskell-mode.info, Node: Introduction, Next: Installation, Prev: Top, Up: Top + +1 Introduction +************** + +“Haskell Mode” is a major mode providing a convenient environment for +editing Haskell (http://www.haskell.org) programs. + + Some of its major features are: + + • Syntax highlighting (font lock), + • automatic semi-intelligent indentation, + • on-the-fly documentation, + • interaction with inferior GHCi/Hugs instance, + • project building with cabal and stack + • scanning declarations and placing them in a menu. + + The name Haskell Mode refers to the whole collection of modules in +this package. There is specifically a file ‘haskell-mode.el’ which +defines a major mode called ‘haskell-mode’. Generally, in this +documentation they will be distinguished by normal font and title case +(Haskell Mode) and code font (‘haskell-mode’). + +1.1 History +=========== + +‘haskell-mode’ has a long history. It goes all the way back to 1992. +Since then, it has received many contributions in many forms. Some +design choices that remain in haskell-mode today are historical. Some +modules are outdated or no longer used, or are used by a few people. + + Historically there hasn’t been a single individual or set of +individuals directing the package’s architecture for a long period of +time, rather, patches and new modules were accepted in liberally and we +are left with a box full of interesting toys that may or may not work. + + As of 2016 Haskell Mode is coordinated using Github at +<https://github.com/haskell/haskell-mode>. + + +File: haskell-mode.info, Node: Installation, Next: Editing Haskell Code, Prev: Introduction, Up: Top + +2 Installation +************** + +Haskell Mode is distributed as a package in MELPA repository +(https://melpa.org). To use MELPA as Emacs package archive do the +following: + + 1. Customize ‘package-archives’ using + M-x customize-option RET package-archives + 2. Use ‘INS’ to add new archive, use: + Archive name: melpa-stable + URL or directory name: http://stable.melpa.org/packages/ + 3. Fetch new packages using: + M-x package-refresh-contents + 4. Install Haskell Mode using: + M-x package-install RET haskell-mode RET + + Voila! ‘haskell-mode’ is installed! You should be able to edit +Haskell source code in color now. + + The above steps should result in the following snippet in your +‘.emacs’: + + (require 'package) + (custom-set-variables + ;; custom-set-variables was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + '(package-archives + (quote + (("gnu" . "http://elpa.gnu.org/packages/") + ("melpa-stable" . "http://stable.melpa.org/packages/"))))) + + Haskell Mode supports GNU Emacs versions 24.3+, including 25 +(snapshot). + + Haskell Mode is available from melpa-stable (releases) +(http://stable.melpa.org) and melpa (git snapshots) (http://melpa.org). + + Other means of obtaining ‘haskell-mode’ include el-get +(https://github.com/dimitri/el-get), Emacs Prelude +(https://github.com/bbatsov/prelude) and Debian package +(https://packages.debian.org/search?keywords=haskell-mode). + + Last version of ‘haskell-mode’ that supported Emacs 23, 24.1, and +24.2 is ‘haskell-mode’ 13.16 available at +<https://github.com/haskell/haskell-mode/releases/tag/v13.16>. + +2.1 Customizing +=============== + +Most of Haskell Mode’s settings are configurable via customizable +variables (*note (emacs)Easy Customization::, for details). You can use +‘M-x customize-group <RET> haskell’ to browse the ‘haskell’ +customization sub-tree. + + One of the important setting you should customize is the +‘haskell-mode-hook’ variable (*note (emacs)Hooks::) which gets run right +after the ‘haskell-mode’ major mode is initialized for a buffer. You +can customize ‘haskell-mode-hook’ by + + M-x customize-variable RET haskell-mode-hook + + There you can enable or disable a couple of predefined options or add +any function to the list. + + +File: haskell-mode.info, Node: Editing Haskell Code, Next: Syntax highlighting, Prev: Installation, Up: Top + +3 Editing Haskell Code +********************** + +Haskell Mode as one of its components provides a major mode for editing +Haskell source code called ‘haskell-mode’, which gave the name to the +whole project. There is a derived mode provided called +‘literate-haskell-mode’ that support Literate Haskell source code both +in Bird and in Latex forms. + + Haskell Mode supports files with the following extensions: + +‘.hs’ + official file extension for Haskell files. Haskell Mode out of the + box supports most of GHC extensions. +‘.lhs’ + official file extension for Literate Haskell files. Both Bird and + Latex styles are supported. +‘.hsc’ + Haskell interfaces to C code used by hsc2hs + (http://www.haskell.org/ghc/docs/latest/html/users_guide/hsc2hs.html) + pre-processor. +‘.cpphs’ + Haskell source with CPP pragmas used with cpphs + (http://projects.haskell.org/cpphs) pre-processor. +‘.c2hs’ + Haskell FFI bindings to C libraries used with c2hs + (https://github.com/haskell/c2hs) pre-processor. + + Haskell Mode offers many productivity tools described in following +chapters in this manual. + +3.1 Managing imports +==================== + +There are a few functions for managing imports. + +3.1.1 Jump to imports +--------------------- + +To jump to your import list, run + + ‘M-x’ ‘haskell-navigate-imports’ + + It’s nicer to have a keybinding to do this, for example: + + (define-key haskell-mode-map (kbd "<f8>") 'haskell-navigate-imports) + + You can hit it repeatedly to jump between groups of imports. It will +cycle. + +3.1.2 Format imports +-------------------- + +To generally format (sort, align) your imports, you can run + + ‘M-x’ ‘haskell-mode-format-imports’ + + Or ‘C-c C-,’. + +3.1.3 Sort imports +------------------ + +To just sort imports, jump to an import section and run + + ‘M-x’ ‘haskell-sort-imports’ + +3.1.4 Align imports +------------------- + +To just align imports, jump to an import section and run + + ‘M-x’ ‘haskell-align-imports’ + +3.1.5 stylish-haskell +--------------------- + +As an alternative to the elisp functions described above, haskell-mode +can use the program stylish-haskell +(http://hackage.haskell.org/package/stylish-haskell) to format imports. +You can set this behavior by typing: ‘M-x’ ‘customize-variable’ ‘RET’ +‘haskell-stylish-on-save’. You can install ‘stylish-haskell’ by running +‘stack install stylish-haskell’, or if you have not installed ‘stack’, +‘cabal install stylish-haskell’. + +3.2 Haskell Tags +================ + +‘haskell-mode’ can generate tags when saving source files. To generate +tags ‘haskell-mode’ uses external program — Hasktags +(https://github.com/MarcWeber/hasktags) (wiki-article +(https://wiki.haskell.org/Tags)). To turn on tags generatation +customize or set to ‘t’ ‘haskell-tags-on-save’ variable. Also, you may +find useful to revert tags tables automatically, this can be done by +customizing ‘tags-revert-without-query’ variable (either globally or for +Haskell buffers only). + +3.3 Profiling and Debugging support +=================================== + +When profiling code with GHC, it is often useful to add cost centres +(https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/profiling.html#cost-centres) +by hand. These allow finer-grained information about program behavior. +‘haskell-mode’ provides the function ‘haskell-mode-toggle-scc-at-point’ +to make this more convenient. It will remove an SCC annotation at point +if one is present, or add one if point is over whitespace. By default +it is bound to ‘C-c C-s’. + + +File: haskell-mode.info, Node: Syntax highlighting, Next: Completion support, Prev: Editing Haskell Code, Up: Top + +4 Syntax highlighting +********************* + +‘haskell-mode’ supports “syntax highlighting” via Emacs’ Font Lock minor +mode which should be enabled by default in current Emacsen. *Note +(emacs)Font Lock::, for more information on how to control +‘font-lock-mode’. + + Syntax highlighting facilities parse strings and string escape +sequences and are able to highlight unrecognized constructs. + + Haskell Mode shows keywords, identifiers, operators, constructors and +types in different colors. + + There is also support to use mode-specific syntax highlighing for +quasiquotes. + + At this point quasi quotes for HTML, XML, shell scripts, Hamlet +templates and SQL are supported out of the box. Customize +‘haskell-font-lock-quasi-quote-modes’ to make sure your quoters are +supported. + + The following customization variables are responsible for faces +applied: + + ‘’ ‘haskell-keyword-face’: for keywords + ‘’ ‘haskell-type-face’: for type names and type class names + ‘’ ‘haskell-constructor-face’: for constructors + ‘’ ‘haskell-definition-face’: function and operator name at the + definition place + ‘’ ‘haskell-operator-face’: operators + ‘’ ‘haskell-pragma-face’: GHC pragmas + ‘’ ‘haskell-literate-comment-face’: literate comments + ‘’ ‘haskell-quasi-quote-face’: quasi quotes unless using mode + specific highlighting + ‘’ ‘haskell-c2hs-hook-pair-face’: c2hs hooks + ‘’ ‘haskell-c2hs-hook-name-face’: c2hs hook names + + All the above are available for customization. + + GHC quasi quote syntax is ambiguous with list comprehension therefore +syntax highlighting might get confused with situations like these: + + result = [html| html <- htmlList] + result = [html| <html><body>...</body></html> |] + + Please use spaces around a list comprehension variable to make this +unambiguous. Any of the following will work: + + result = [ html| html <- htmlList] + result = [html | html <- htmlList] + + GHC’s ambiguity is an accident of the past but it is unlikely to be +fixed due to backward compatibility baggage. + + +File: haskell-mode.info, Node: Completion support, Next: Unicode support, Prev: Syntax highlighting, Up: Top + +5 Completion support +******************** + +‘haskell-mode’ can complete symbols, pragma directives, language +extensions, and language keywords out-of-box. ‘haskell-mode’ completes +identifiers (symbols) using tags (see “Tags”), however you can get more +precise completions with ‘haskell-interactive-mode’. In interactive +mode completion candidates are produced by querying GHCi REPL. + + If ‘haskell-interactive-mode’ is enabled and working Haskell mode +provides completions for import statements taking into account currently +loaded and available packages. Also it completes symbols querying REPL +with ‘:complete’ command, hence completion candidate list also includes +symbols from imported modules. + + Unfortunatelly, it is not possible to provide candidates for +identifiers defined locally in ‘let’ and ‘where’ blocks even in +interactive mode. But if you’re using company-mode +(http://company-mode.github.io/) you can override ‘company-backends’ +variable for Haskell buffers to combine completion candidates from +completion-at-point function (‘company-capf’ backend) and dynamic +abbrevs. ‘company-mode’ provides special backend for dabbrev code +completions, namely ‘company-dabbrev-code’. To combine completions from +diffrent backends you can create grouped backends, it is very easy — a +grouped backend is just a list of backends, for example: + + (add-hook 'haskell-mode-hook + (lambda () + (set (make-local-variable 'company-backends) + (append '((company-capf company-dabbrev-code)) + company-backends)))) + + If you use a GHCi version prior to 8.0.1 you might want to set +‘haskell-completions-complete-operators’ to ‘nil’, if you experience +major slowdown while trying to complete after an Haskell operator (See +GHC-Bug 10576 (https://ghc.haskell.org/trac/ghc/ticket/10576)). + + +File: haskell-mode.info, Node: Unicode support, Next: Indentation, Prev: Completion support, Up: Top + +6 Unicode support +***************** + +See the Haskell Wiki’s entry on Unicode Symbols +(http://www.haskell.org/haskellwiki/Unicode-symbols) for general +information about Unicode support in Haskell. + + As Emacs supports editing files containing Unicode out of the box, so +does Haskell Mode. As an add-on, Haskell Mode includes the +‘haskell-unicode’ input method which allows you to easily type a number +of Unicode symbols that are useful when writing Haskell code; *Note +(emacs)Input Methods::, for more details. + + To automatically enable the ‘haskell-unicode’ input method in +haskell-mode buffers use ‘M-x customize-variable <RET> +haskell-mode-hook’ or put the following code in your ‘.emacs’ file: + + (add-hook 'haskell-mode-hook 'turn-on-haskell-unicode-input-method) + +To temporarily enable this input method for a single buffer you can use +‘M-x turn-on-haskell-unicode-input-method’. + + When the ‘haskell-unicode’ input method is active, you can simply +type ‘->’ and it is immediately replaced with ‘→’. Use ‘C-\’ to toggle +the input method. To see a table of all key sequences use ‘M-x +describe-input-method <RET> haskell-unicode’. A sequence like ‘<=’ is +ambiguous and can mean either ‘⇐’ or ‘≤’. Typing it presents you with a +choice. Type ‘1’ or ‘2’ to select an option or keep typing to use the +default option. + + Currently defined sequences are listed in the following table: + +SequenceUnicode SequenceUnicode SequenceUnicode SequenceUnicode +---------------------------------------------------------------------------- +alpha α Alpha Α beta β Beta Β +gamma γ Gamma Γ delta δ Delta Δ +epsilonε EpsilonΕ zeta ζ Zeta Ζ +eta η Eta Η theta θ Theta Θ +iota ι Iota Ι kappa κ Kappa Κ +lambda λ Lambda Λ lamda λ Lamda Λ +mu μ Mu Μ nu ν Nu Ν +xi ξ Xi Ξ omicronο OmicronΟ +pi π Pi Π rho ρ Rho Ρ +sigma σ Sigma Σ tau τ Tau Τ +upsilonυ UpsilonΥ phi φ Phi Φ +chi χ Chi Χ psi ψ Psi Ψ +omega ω Omega Ω digammaϝ DigammaϜ +san ϻ San Ϻ qoppa ϙ Qoppa Ϙ +sampi ϡ Sampi Ϡ stigma ϛ Stigma Ϛ +heta ͱ Heta Ͱ sho ϸ Sho Ϸ +|A| 𝔸 |B| 𝔹 |C| ℂ |D| 𝔻 +|E| 𝔼 |F| 𝔽 |G| 𝔾 |H| ℍ +|I| 𝕀 |J| 𝕁 |K| 𝕂 |L| 𝕃 +|M| 𝕄 |N| ℕ |O| 𝕆 |P| ℙ +|Q| ℚ |R| ℝ |S| 𝕊 |T| 𝕋 +|U| 𝕌 |V| 𝕍 |W| 𝕎 |X| 𝕏 +|Y| 𝕐 |Z| ℤ |gamma|ℽ |Gamma|ℾ +|pi| ℼ |Pi| ℿ :: ∷ forall ∀ +exists ∃ -> → <- ← => ⇒ +~> ⇝ <~ ⇜ && ∧ || ∨ +== ≡ /= ≢, ≠ <= ≤ >= ≥ +/< ≮ /> ≯ * ⋅ elem ∈ +notElem∉ member ∈ notMember∉ union ∪ +intersection∩ isSubsetOf⊆ isProperSubsetOf⊂ <<< ⋘ +>>> ⋙ <| ⊲ |> ⊳ >< ⋈ +mappend⊕ . ∘ undefined⊥ := ≔ +=: ≕ =def ≝ =? ≟ ... … +_0 ₀ _1 ₁ _2 ₂ _3 ₃ +_4 ₄ _5 ₅ _6 ₆ _7 ₇ +_8 ₈ _9 ₉ ^0 ⁰ ^1 ¹ +^2 ² ^3 ³ ^4 ⁴ ^5 ⁵ +^6 ⁶ ^7 ⁷ ^8 ⁸ ^9 ⁹ + + If you don’t like the highlighting of partially matching tokens you +can turn it off by setting ‘input-method-highlight-flag’ to ‘nil’ via +‘M-x customize-variable’. + + +File: haskell-mode.info, Node: Indentation, Next: External indentation, Prev: Unicode support, Up: Top + +7 Indentation +************* + +In Haskell, code indentation has semantic meaning as it defines the +block structure. Haskell also supports braces and semicolons notation +for conveying the block structure. However, most Haskell programs +written by humans use indentation for block structuring. + + Haskell Mode ships with two indentation modes: + + • ‘haskell-indentation-mode’ (default). + + This is a semi-intelligent indentation mode doing a decent job at + recognizing Haskell syntactical constructs. It is based on a + recursive descent Haskell parser. ‘TAB’ selects the next potential + indentation position, ‘S-TAB’ selects the previous one. If a block + is selected you can use ‘TAB’ to indent the block more and ‘S-TAB’ + to indent the block less. + + When ‘electric-indent-mode’ is enabled or the variable + ‘haskell-indentation-electric-flag’ is non-nil, the insertion of + some characters (by default ‘,’ ‘;’ ‘)’ ‘}’ ‘]’) may trigger auto + reindentation under appropriate conditions. See the documentation + of ‘haskell-indentation-common-electric-command’ for more details. + + • ‘haskell-indent-mode’ (optional). + + This is a semi-intelligent indentation mode doing a decent job at + recognizing Haskell syntactical constructs. It is based on a + decision table. Sadly it is no longer developed and does not + recognize newer Haskell syntax. ‘TAB’ cycles through all available + indentation positions. + + To use ‘haskell-indent-mode’, add this to your ‘~/.emacs’ file: + + (add-hook 'haskell-mode-hook 'turn-on-haskell-indent) + + Note that ‘turn-on-haskell-indent’ will disable + ‘haskell-indentation-mode’. + + For general information about indentation support in GNU Emacs, *note +(emacs)Indentation::. + +7.1 Rectangle Commands +====================== + +GNU Emacs provides so-called “rectangle commands” which operate on +rectangular areas of text, which are particularly useful for languages +with a layout rule such as Haskell. *Note (emacs)Rectangles::, to learn +more about rectangle commands. + + Moreover, CUA mode (*note (emacs)CUA Bindings::) provides enhanced +rectangle support with visible rectangle highlighting. When CUA mode is +active, you can initiate a rectangle selection by ‘C-RET’ and extend it +simply by movement commands. You don’t have to enable full CUA mode to +benefit from these enhanced rectangle commands; you can activate CUA +selection mode (without redefining ‘C-x’,‘C-c’,‘C-v’, and ‘C-z’) by +calling ‘M-x cua-selection-mode’ (or adding ‘(cua-selection-mode nil)’ +to your ‘haskell-mode-hook’). + +7.2 Region indent is a no-op +============================ + +There is a ‘indent-region’ function that supposedly could be used to +indent code region without changing its semantics. Sadly it does not +work that way because usual use case for ‘indent-region’ is: + + 1. Alter first line of code in region. + 2. Call ‘indent-region’ to fix indentation for remaining lines. + + Note that between 1 and 2 program is already semantically broken and +knowing how to indent it preserving semantic from before step 1 would +require time travel. + + To stay on the safe side ‘indent-region-function’ is bound to a no-op +in ‘haskell-mode’. + + +File: haskell-mode.info, Node: External indentation, Next: Autoformating, Prev: Indentation, Up: Top + +8 Other ways to indent code +*************************** + +8.1 Indentation with tabs, not spaces +===================================== + +Some projects require indenting code with tabs and forbid indenting it +with spaces. For hacking on such projects, check out +haskell-tab-indent-mode +(https://spwhitton.name/tech/code/haskell-tab-indent). + +8.2 Structured indentation +========================== + +Another alternative is to install structured-haskell-mode +(https://github.com/chrisdone/structured-haskell-mode). which indents +code by parsing the code with a full Haskell parser and deciding where +to indent based on that. + + +File: haskell-mode.info, Node: Autoformating, Next: Module templates, Prev: External indentation, Up: Top + +9 Using external formatters +*************************** + +You can enable stylish-haskell +(https://github.com/jaspervdj/stylish-haskell) by installing it: + + $ cabal install stylish-haskell + + And by enabling it with a customization + + (custom-set-variables + '(haskell-stylish-on-save t)) + + Now when you run ‘save-buffer’ (or ‘C-x C-s’) the module will be +automatically formatted. + + Alternatively, you can run the function directly on demand with ‘M-x’ +‘haskell-mode-stylish-buffer’. + + +File: haskell-mode.info, Node: Module templates, Next: Declaration scanning, Prev: Autoformating, Up: Top + +10 Module templates +******************* + +To enable auto-insertion of module templates, enable: + + (add-hook 'haskell-mode-hook 'haskell-auto-insert-module-template) + + When you open a file called ‘Foo.hs’, it will auto-insert + + -- | + + module Foo where + + And put your cursor in the comment section. + + +File: haskell-mode.info, Node: Declaration scanning, Next: Compilation, Prev: Module templates, Up: Top + +11 Declaration scannning +************************ + +‘haskell-decl-scan-mode’ is a minor mode which performs declaration +scanning and provides ‘M-x imenu’ support (*note (emacs)Imenu:: for more +information). + + For non-literate and TeX-style literate scripts, the common +convention that top-level declarations start at the first column is +assumed. For Bird-style literate scripts, the common convention that +top-level declarations start at the third column, ie. after ‘> ’, is +assumed. + + When ‘haskell-decl-scan-mode’ is active, the standard Emacs top-level +definition movement commands (*note (emacs)Moving by Defuns::) are +enabled to operate on Haskell declarations: + +‘C-M-a’ + Move to beginning of current or preceding declaration + (‘beginning-of-defun’). + +‘C-M-e’ + Move to end of current or following declaration (‘end-of-defun’). + +‘C-M-h’ + Select whole current or following declaration (‘mark-defun’). + + Moreover, if enabled via the option +‘haskell-decl-scan-add-to-menubar’, a menu item “Declarations” is added +to the menu bar listing the scanned declarations and allowing to jump to +declarations in the source buffer. + + It’s recommended to have font lock mode enabled (*note (emacs)Font +Lock::) as ‘haskell-decl-scan-mode’ ignores text highlighted with +‘font-lock-comment-face’. + + As usual, in order to activate ‘haskell-decl-scan-mode’ automatically +for Haskell buffers, add ‘haskell-decl-scan-mode’ to +‘haskell-mode-hook’: + + (add-hook 'haskell-mode-hook 'haskell-decl-scan-mode) + + ‘haskell-decl-scan-mode’ enables the use of features that build upon +‘imenu’ support such as Speedbar Frames (*note (emacs)Speedbar::) or the +global “Which Function” minor mode (*note (emacs)Which Function::). + + In order to enable ‘which-function-mode’ for Haskell buffers you need +to add the following to your Emacs initialization: + + (eval-after-load "which-func" + '(add-to-list 'which-func-modes 'haskell-mode)) + +11.1 Speedbar +============= + +Haskell-mode comes with declaration scanning support. This means that +if you enable Haskell support for speedbar: + + (speedbar-add-supported-extension ".hs") + + And open speedbar with + + ‘M-x speedbar’ + + It gives a listing of each module and under each module: + + Imports + Instances + Data types + Classes + Bindings + + You will get a bar that looks like this: + +~/Projects/ace/src/ACE/ +0:<+> Types +0:[+] Combinators.hs +0:[-] Datalog.hs +1: {-} Classes +2: > ToTerm +1: {-} Imports +2: > ACE.Types.Syntax +2: > Database.Datalog +1: {-} Instances +2: {+} ToTerm A +2: {+} ToTerm Co to ToTerm Gen +2: {+} ToTerm Intransitive to ToTerm N +2: {+} ToTerm P +2: {+} ToTerm Quotation to ToTerm Un +2: {+} ToTerm V +0:[-] Html.hs +1: {+} Imports +1: {+} Instances +1: > mtoMarkup +1: > toMarkupm +1: > wrap +0:[-] Parsers.hs +1: {+} Imports +1: {-} Datatypes +2: > ACEParser +0:[+] Pretty.hs +0:[+] Tokenizer.hs + + The hierarchy is expandable/collapsible and each entry will jump to +the line in the right file when clicked/selected. + + +File: haskell-mode.info, Node: Compilation, Next: Interactive Haskell, Prev: Declaration scanning, Up: Top + +12 Compilation +************** + +Haskell mode comes equipped with a specialized “Compilation mode” +tailored to GHC’s compiler messages with optional support for Cabal +projects. *Note (emacs)Compilation Mode::, for more information about +the basic commands provided by the Compilation mode which are available +in the Haskell compilation sub-mode as well. The additional features +provided compared to Emacs’ basic Compilation mode are: + + • DWIM-style auto-detection of compile command (including support for + CABAL projects) + • Support for GHC’s compile messages and recognizing error, warning + and info source locations (including ‘-ferror-spans’ syntax) + • Support for filtering out GHC’s uninteresting ‘Loading package...’ + linker messages + + In order to use it, invoke the ‘haskell-compile’ command instead of +‘compile’ as you would for the ordinary Compilation mode. It’s +recommended to bind ‘haskell-compile’ to a convenient key binding. For +instance, you can add the following to your Emacs initialization to bind +‘haskell-compile’ to ‘C-c C-c’. + + (eval-after-load "haskell-mode" + '(define-key haskell-mode-map (kbd "C-c C-c") 'haskell-compile)) + + (eval-after-load "haskell-cabal" + '(define-key haskell-cabal-mode-map (kbd "C-c C-c") 'haskell-compile)) + +The following description assumes that ‘haskell-compile’ has been bound +to ‘C-c C-c’. + + When invoked, ‘haskell-compile’ tries to guess how to compile the +Haskell program your currently visited buffer belongs to, by searching +for a ‘.cabal’ file in the current of enclosing parent folders. If a +‘.cabal’ file was found, the command defined in the +‘haskell-compile-cabal-build-command’ option is used. Note that to +compile a ‘stack’ based project you will need to set this variable to +‘stack build’. As usual you can do it using ‘M-x customize-variable’ or +with: + + (setq haskell-compile-cabal-build-command "stack build") + + Moreover, when requesting to compile a ‘.cabal’-file is detected and +a negative prefix argument (e.g. ‘C-- C-c C-c’) was given, the +alternative ‘haskell-compile-cabal-build-command-alt’ is invoked. By +default, ‘haskell-compile-cabal-build-command-alt’ contains a ‘cabal +clean -s’ command in order to force a full rebuild. + + Otherwise if no ‘.cabal’ could be found, a single-module compilation +is assumed and ‘haskell-compile-command’ is used (_if_ the currently +visited buffer contains Haskell source code). + + You can also inspect and modify the compile command to be invoked +temporarily by invoking ‘haskell-compile’ with a prefix argument (e.g. +‘C-u C-c C-c’). If later-on you want to recompile using the same +customized compile command, invoke ‘recompile’ (bound to ‘g’) inside the +‘*haskell-compilation*’ buffer. + +12.1 Keybindings +================ + +Key Function +binding +------------ +TAB compilation-next-error + +RET compile-goto-error + +C-o compilation-display-error + +SPC scroll-up-command + +- negative-argument + +0 digit-argument +.. +9 +< beginning-of-buffer + +> end-of-buffer + +? describe-mode + +g recompile + +h describe-mode + +q quit-window + +DEL scroll-down-command + +S-SPC scroll-down-command + +<backtab>compilation-previous-error + +<follow-link>mouse-face + +<mouse-2>compile-goto-error + +<remap>Prefix + Command + +M-n compilation-next-error + +M-p compilation-previous-error + +M-{ compilation-previous-file + +M-} compilation-next-file + +C-c compile-goto-error +C-c +C-c next-error-follow-minor-mode +C-f +C-c kill-compilation +C-k + + +File: haskell-mode.info, Node: Interactive Haskell, Next: Editing Cabal files, Prev: Compilation, Up: Top + +13 Interactive Haskell +********************** + +REPL (read–eval–print loop) is provided both via Comint +(‘inferior-haskell-mode’) and an adhoc way called +‘haskell-interactive-mode’. The Comint based ‘inferior-haskell-mode’ is +just the REPL, it comes with the standard key bindings(like ‘ielm’ or +‘eshell’). + + ‘haskell-interactive-mode’ comes with a different set of features: + + • Separate sessions per Cabal project ‘haskell-session.el’. + • A new inferior Haskell process handling code ‘haskell-process.el’. + • New REPL implementation similiar to SLIME/IELM + • Navigatable error overlays ‘haskell-interactive-mode.el’. + + With ‘haskell-interactive-mode’, each Haskell source buffer is +associated with at most one GHCi session, so when you call +‘haskell-process-load-file’ for a Haskell source buffer which has no +session associated yet, you’re asked which GHCi session to create or +associate with. + +13.1 Goto Error +=============== + +In a Haskell source buffer associated with a GHCi session, errors that +prevent the file from loading are highlighted with ‘haskell-error-face’. +You can move between these error lines with + +‘M-n’ + is bound to ‘haskell-goto-next-error’ +‘M-p’ + is bound to ‘haskell-goto-prev-error’ +‘C-c M-p’ + is bound to ‘haskell-goto-first-error’ + +13.2 Using GHCi 8+ or GHCi-ng +============================= + +If you use either of the above, then you can use these functions: + + (define-key interactive-haskell-mode-map (kbd "M-.") 'haskell-mode-goto-loc) + (define-key interactive-haskell-mode-map (kbd "C-c C-t") 'haskell-mode-show-type-at) + + You have to load the module before it works, after that it will +remember for the current GHCi session. + +13.3 Customizing +================ + +What kind of Haskell REPL ‘haskell-interactive-mode’ will start up +depends on the value of ‘haskell-process-type’. This can be one of the +symbols ‘auto’, ‘ghci’, ‘cabal-repl’, ‘cabal-new-repl’, or ‘stack-ghci’. +If it’s ‘auto’, the directory contents and available programs will be +used to make a best guess at the process type. The actual process type +will then determine which variables ‘haskell-interactive-mode’ will +access to determine the program to start and its arguments: + + • If it’s ‘ghci’, ‘haskell-process-path-ghci’ and + ‘haskell-process-args-ghci’ will be used. + • If it’s ‘cabal-repl’, ‘haskell-process-path-cabal’ and + ‘haskell-process-args-cabal-repl’. + • If it’s ‘cabal-new-repl’, ‘haskell-process-path-cabal’ and + ‘haskell-process-args-cabal-new-repl’. + • If it’s ‘stack-ghci’, ‘haskell-process-path-stack’ and + ‘haskell-process-args-stack-ghci’ will be used. + + With each of these pairs, the the ‘haskell-process-path-...’ variable +needs to be a string specifying the program path, or a list of strings +where the first element is the program path and the rest are initial +arguments. The ‘haskell-process-args-...’ is a list of strings +specifying (further) command-line arguments. + +13.4 Haskell Interactive Mode Setup +=================================== + +The most straight-forward way to get setup with Interactive Mode is to +bind the right keybindings and set some customizations. This page +contains a good base setup. + + To enable the minor mode which activates keybindings associated with +interactive mode, use: + + (require 'haskell-interactive-mode) + (require 'haskell-process) + (add-hook 'haskell-mode-hook 'interactive-haskell-mode) + +13.4.1 Customizations +--------------------- + +This enables some handy and benign features. + + (custom-set-variables + '(haskell-process-suggest-remove-import-lines t) + '(haskell-process-auto-import-loaded-modules t) + '(haskell-process-log t)) + +13.4.2 Haskell-mode bindings +---------------------------- + +This gives the basic ways to start a session. In a Haskell buffer: + + • Run ‘C-`’ to make a REPL open, this will create a session, start + GHCi, and open the REPL. + • Or: run ‘C-c C-l’ to load the file. This will first try to start a + session as the previous command does. + • Or: run any command which requires a running session. It will + always prompt to create one if there isn’t one already for the + current project. + + (define-key haskell-mode-map (kbd "C-c C-l") 'haskell-process-load-or-reload) + (define-key haskell-mode-map (kbd "C-`") 'haskell-interactive-bring) + (define-key haskell-mode-map (kbd "C-c C-t") 'haskell-process-do-type) + (define-key haskell-mode-map (kbd "C-c C-i") 'haskell-process-do-info) + (define-key haskell-mode-map (kbd "C-c C-c") 'haskell-process-cabal-build) + (define-key haskell-mode-map (kbd "C-c C-k") 'haskell-interactive-mode-clear) + (define-key haskell-mode-map (kbd "C-c c") 'haskell-process-cabal) + +13.4.3 Cabal-mode bindings +-------------------------- + +The below commands pretty much match the ones above, but are handy to +have in cabal-mode, too: + + (define-key haskell-cabal-mode-map (kbd "C-`") 'haskell-interactive-bring) + (define-key haskell-cabal-mode-map (kbd "C-c C-k") 'haskell-interactive-mode-clear) + (define-key haskell-cabal-mode-map (kbd "C-c C-c") 'haskell-process-cabal-build) + (define-key haskell-cabal-mode-map (kbd "C-c c") 'haskell-process-cabal) + +13.4.4 GHCi process type +------------------------ + +By default ‘haskell-process-type’ is set to ‘auto’. It is smart enough +to pick the right type based on your project structure and installed +tools, but in case something goes funky or you want to explicitly set +the process type and ignore the inferred type, you can customize this +setting by running ‘M-x’ ‘customize-variable’ ‘RET’ +‘haskell-process-type’ ‘RET’, or by setting the code: + + (custom-set-variables + '(haskell-process-type 'cabal-repl)) + + Here is a list of available process types: + + • ghci + • cabal-repl + • cabal-new-repl + • cabal-dev + • cabal-ghci + • stack-ghci + + Please, check the documentation for ‘haskell-process-type’ to see how +the real type is guessed, when it’s set to ‘auto’. + +13.4.5 Troubleshooting +---------------------- + +Launching your GHCi process can fail when you’re first getting setup, +depending on the type you choose. If it does fail to launch, switch to +the buffer ‘*haskell-process-log*’ and see what’s up. The buffer +contains a log of incoming/outgoing messages to the GHCi process. + +13.5 Haskell Interactive Mode Tags Using GHCi +============================================= + +You can bind the following to use GHCi to find definitions of things: + + (define-key haskell-mode-map (kbd "M-.") 'haskell-mode-jump-to-def) + + The one problem with this approach is that if your code doesn’t +compile, GHCi doesn’t give any location info. So you need to make sure +your code compiles and the modules you want to jump to are loaded +byte-compiled. + + Note: I think that when you restart GHCi you lose location +information, even if you have the ‘.o’ and ‘.hi’ files lying around. +I’m not sure. But sometimes ‘:i foo’ will give ‘foo is defined in Bar’ +rather than ‘foo is defined in /foo/Bar.hs:123:23’. + + Alternatively, you can use tags generation, which doesn’t require a +valid compile. + +13.5.1 Tags Setup +----------------- + +Make sure to install ‘hasktags’. + + $ cabal install hasktags + + Then add the customization variable to enable tags generation on +save: + + (custom-set-variables + '(haskell-tags-on-save t)) + + And make sure ‘hasktags’ is in your ‘$PATH’ which Emacs can see. + +13.5.2 Generating tags +---------------------- + +Now, every time you run ‘save-buffer’ (‘C-x C-s’), there is a hook that +will run and generate Emacs *Note (emacs)Tags:: for the whole project +directory. The resulting file will be called ‘TAGS’. + + WARNING: You should be careful that your project root isn’t your home +directory or something, otherwise it will traverse all the way down and +take an impossibly long time. + +13.5.3 Jumping to tags +---------------------- + +Bind the following keybinding: + + (define-key haskell-mode-map (kbd "M-.") 'haskell-mode-tag-find) + + To jump to the location of the top-level identifier at point, run +‘M-x’ ‘haskell-mode-tag-find’ or ‘M-.’. + +13.5.4 Hybrid: GHCi and fallback to tags +---------------------------------------- + +To use GHCi first and then if that fails to fallback to tags for +jumping, use: + + (define-key haskell-mode-map (kbd "M-.") 'haskell-mode-jump-to-def-or-tag) + +13.5.5 Troubleshooting tags +--------------------------- + +Sometimes a ‘TAGS’ file is deleted (by you or some other process). +Emacs will complain that it doesn’t exist anymore. To resolve this +simply do ‘M-x’ ‘tags-reset-tags-tables’. + +13.6 Sessions +============= + +All commands in Haskell Interactive Mode work within a session. +Consider it like a “project” or a “solution” in popular IDEs. It tracks +the root of your project and an associated process and REPL. + +13.6.1 Start a session +---------------------- + +To start a session run the following steps: + + • Open some Cabal or Haskell file. + • Run ‘C-`’ to make a REPL open, this will create a session, start + GHCi, and open the REPL. + • Or: run ‘C-c C-l’ to load the file. This will first try to start a + session as the previous command does. + • Or: run any command which requires a running session. It will + always prompt to create one if there isn’t one already for the + current project. + + It will prompt for a Cabal directory and a current directory. It +figures out where the cabal directory is and defaults for the current +directory, so you should be able to just hit RET twice. + +13.6.2 Switch a session +----------------------- + +Sometimes a particular file is used in two different sessions/projects. +You can run + + M-x haskell-session-change + + If it prompts you to make a new session, tell it no (that’s a bug). +It will ask you to choose from a list of sessions. + +13.6.3 Killing a session +------------------------ + +To kill a session you can run + + M-x haskell-session-kill + + Which will prompt to kill all associated buffers, too. Hit ‘n‘ to +retain them. + + Alternatively, you can switch to the REPL and just kill the buffer +normally with ‘C-x k RET’. It will prompt + + Kill the whole session (y or n)? + + You can choose ‘y’ to kill the session itself, or ‘n’ to just kill +the REPL buffer. You can bring it back with ‘M-x’ +‘haskell-interactive-bring’. + +13.6.4 Menu +----------- + +To see a list of all sessions you have open with some simple statistics +about memory usage, etc. run + + M-x haskell-menu + + For example: + + foo 14648 08:21:42 214MB /path/to/fpco/foo/ /path/to/fpco/foo/ ghci + bar 29119 00:22:03 130MB /path/to/bar/ /path/to/bar/ ghci + mu 22575 08:48:20 73MB /path/to/fpco/mu/ /path/to/fpco/mu/ ghci + +13.7 Compiling +============== + +There are a bunch of ways to compile Haskell modules. This page covers +a few of them. + +13.7.1 Load into GHCi +--------------------- + +To compile and load a Haskell module into GHCi, run the following + + M-x haskell-process-load + + Or ‘C-c C-l’. You’ll see any compile errors in the REPL window. + +13.7.2 Build the Cabal project +------------------------------ + +To compile the whole Cabal project, run the following + + M-x haskell-process-cabal-build + + Or ‘C-c C-c’. You’ll see any compile errors in the REPL window. + +13.7.3 Reloading modules +------------------------ + +To reload the current module, even when you’re in other modules, you can +run ‘C-u M-x’ ‘haskell-process-load-or-reload’ or ‘C-u C-c C-l’. It +will now reload that module whenever you run ‘C-c C-l’ in the future +from whatever module you’re in. To disable this mode, just run ‘C-u C-c +C-l’ again. + +13.7.4 Jumping to compile errors +-------------------------------- + +You can use the standard compile error navigation function ‘C-x `’ — +jump to the next error. + + Or you can move your cursor to an error in the REPL and hit ‘RET’ to +jump to it. + +13.7.5 Auto-removing imports +---------------------------- + +If the customization variable +‘haskell-process-suggest-remove-import-lines’ is enabled. + + (custom-set-variables + '(haskell-process-suggest-remove-import-lines t)) + + Building and loading modules which output warnings like, + + Warning: The import of `Control.Monad' is redundant + except perhaps to import instances from `Control.Monad' + To import instances alone, use: import Control.Monad() + + will prompt the user with + + > The import line `Control.Monad' is redundant. Remove? (y, n, c: comment out) + + If you answer + + • ‘y’: it will delete the import, but leave the empty line remaining + (this avoids messing with line positions in subsequent error + messages). + • ‘n’: it will leave the import. + • ‘c’: it will comment out the import (this is handy for when you + just want to temporarily hide an import). + +13.7.6 Auto-adding of modules to import +--------------------------------------- + +Enable the customization variable +‘haskell-process-suggest-hoogle-imports’. + + (custom-set-variables + '(haskell-process-suggest-hoogle-imports t)) + + Whenever GHC says something is not in scope, it will hoogle that +symbol. If there are results, it will prompt to add one of the modules +from Hoogle’s results. + + You need to make sure you’ve generated your Hoogle database properly. + +13.7.7 Auto-adding of extensions +-------------------------------- + +It you use an extension which is not enabled, GHC will often inform you. +For example, if you write: + + newtype X a = X (IO a) + deriving (Monad) + + Then you’ll see a message like: + + x.hs:13:13: Can't make a derived instance of `Monad X': … + `Monad' is not a derivable class + Try -XGeneralizedNewtypeDeriving for GHC's newtype-deriving extension + In the newtype declaration for `X' + + This ‘-XFoo’ pattern will be picked up and you will be prompted: + + > Add `{-# LANGUAGE GeneralizedNewtypeDeriving #-}` to the top of the + > file? (y or n) + + If you answer ‘y‘, it will temporarily jump to the buffer and it to +the top of the file. + +13.7.8 Orphan instances +----------------------- + +If GHC complains about orphan instances, you usually are doing it +intentionally, so it prompts to add ‘-fno-warn-orphans’ to the top of +the file with an ‘OPTIONS’ pragma. + +13.7.9 Auto-adding of dependencies +---------------------------------- + +When doing a build, you will sometimes get a message from GHC like: + + src/ACE/Tokenizer.hs:11:18: Could not find module `Data.Attoparsec.Text' … + It is a member of the hidden package `attoparsec-0.11.1.0'. + + This message contains all the necessary information to add this to +your .cabal file, so you will be prompted to add it to your .cabal file: + + Add `attoparsec' to ace.cabal? (y or n) y + + If you hit ‘y’, it will prompt with this: + + attoparsec >= 0.11.1.0 + + Which you can edit (e.g. do some PVP decision or remove constraints +entirely), and then it will open up your ‘.cabal’ file and go through +each section: + + Add to library? (y or n) y + + This will add it to the top of the ‘build-depends’ field in your +library section. If you have any executables, it will go through each +of those, prompting, too. + + Now you can rebuild with ‘C-c C-c’ again. + +13.8 Haskell Interactive Mode REPL +================================== + +When GHCi has been launched, it works on a read-eval-print basis. So +you will be presented with the prompt: + + The lambdas must flow. + Changed directory: /path/to/your/project/ + λ> + +13.8.1 Changing REPL target +--------------------------- + +With ‘haskell-session-change-target’ you can change the target for REPL +session. + + After REPL session started, in ‘haskell-interactive-mode’ buffer +invoke the ‘haskell-session-change-target’ and select from available +targets for + + - Testing + + - Benchmark + + - Executable + + - Library + + Answer “yes” to restart the session and run your tests, benchmarks, +executables. + + TODO/WRITEME + +13.8.2 Bringing the REPL +------------------------ + +If you don’t know where the REPL buffer is, you can always bring it +with: + + M-x haskell-interactive-bring + + Or ‘C-`’. + +13.8.3 Evaluating expressions +----------------------------- + +To evaluate expressions, simply type one out and hit ‘RET‘. + + λ> 123 + 123 + +13.8.4 Evaluating multiline expressions +--------------------------------------- + +GHCi features two ways to evaluate multiline expressions. You can use +‘:set +m’ to enable multiline input +(https://www.haskell.org/ghc/docs/latest/html/users_guide/ghci.html#multiline-input) +for all expressions, or you can wrap your expression in ‘:{’ and ‘:}’ +(they have to be on their own lines). + + The prompt will change to indicate that you’re inputting a multiline +expression: + + λ> :{ + λ| let a = 10 + λ| b = 20 + λ| c = 30 + λ| :} + + You can also simulate multiline mode by having your input contain +newline characters. You can input a literal newline character with ‘C-q +C-j’, or you can use: + + M-x haskell-interactive-mode-newline-indent + + which is bound to ‘C-j’. This command indents after the newline. +You can simulate the above example like so: + + λ> let a = 10 + b = 20 + c = 30 + +13.8.5 Type of expressions +-------------------------- + +You can use normal ‘:type’ which is part of GHCi to get the type of +something: + + λ> :t id + id :: a -> a + + But you can also just write out the value directly, + + λ> id + id :: a -> a + + and because there’s no ‘Show’ instance for ‘(a -> a)’. This would +normally yield a compile error: + + No instance for (Show (a0 -> a0)) + arising from a use of `print' + Possible fix: add an instance declaration for (Show (a0 -> a0)) + In a stmt of an interactive GHCi command: print it + + It will run ‘:type id’ in the background and print out the result. +The same is true for ambiguous things: + + λ> :t read "a" + read "a" :: Read a => a + + Because this would normally be an ambiguous constraint: + + Ambiguous type variable `a0' in the constraint: + (Read a0) arising from a use of `read' + Probable fix: add a type signature that fixes these type variable(s) + In the expression: read \"a\" + In an equation for `it': it = read \"a\" + + Which is less useful than just printing the type out. + + You can disable this behaviour by disabling the customization option: + + (custom-set-variables + '(haskell-interactive-types-for-show-ambiguous nil)) + +13.8.6 Printing mode +-------------------- + +You can choose between printing modes used for the results of evaluating +expressions. To do that, configure the variable +‘haskell-interactive-mode-eval-mode’. Example: + + (setq haskell-interactive-mode-eval-mode 'haskell-mode) + + A handy function you can use is: + + (defun haskell-interactive-toggle-print-mode () + (interactive) + (setq haskell-interactive-mode-eval-mode + (intern + (ido-completing-read "Eval result mode: " + '("fundamental-mode" + "haskell-mode" + "espresso-mode" + "ghc-core-mode" + "org-mode"))))) + + (Add whichever modes you want to use.) + + And then run + + M-x haskell-interactive-toggle-print-mode + + Or ‘C-c C-v’: + + (define-key haskell-interactive-mode-map (kbd "C-c C-v") + 'haskell-interactive-toggle-print-mode) + + There you can choose ‘haskell-mode‘, for example, to pretty print the +output as Haskell. + +13.8.7 Presentations +-------------------- + +If you have the ‘present’ package installed, you can use the following +syntax to print anything which is an instance of ‘Data’: + + λ> :present 123 + 123 + + It will print data structures lazily: + + λ> :present [1..] + [1 + ,[Integer]] + + It shows types when there is an unevaluated field in a constructor. +You can click the ‘[Integer]’ or press ‘RET’ on it to expand further: + + λ> :present [1..] + [1 + ,2 + ,[Integer]] + + Etc. Remember: this only works for instances of ‘Data.Data.Data’. + +13.8.8 History +-------------- + +A history is maintained for the duration of the REPL buffer. To go up +and down in the history, run ‘M-p’ for previous and ‘M-n’ for next. + +13.8.9 Cancelling commands +-------------------------- + +To cancel a running REPL command, run ‘C-c C-c’. + +13.8.10 Clear the REPL +---------------------- + +Run ‘C-c C-k’ to clear the REPL. + +13.8.11 Trick: Put Interactive REPL in Separate Frame +----------------------------------------------------- + +The following ‘create-haskell-interactive-frame’ is a quick hack to move +the repl to a separate frame, for those that want a more predictable +layout of windows in Emacs. + + (defun create-unfocused-frame () + (let* + ((prv (window-frame)) + (created (make-frame))) + (select-frame-set-input-focus prv) created)) + + (defun create-haskell-interactive-frame () + (interactive) + (haskell-interactive-bring) + (create-unfocused-frame) + (delete-window)) + + +13.8.12 Troubleshooting +----------------------- + +If the REPL ever goes funny, you can clear the command queue via: + + M-x haskell-process-clear + + Alternatively, you can just restart the process: + + M-x haskell-process-restart + + You can also switch to the buffer ‘*haskell-process-log*’, which can +be enabled and disabled with the customization variable +‘haskell-process-log‘, to see what the cause of your troubles are. + + If the process fails and nothing unusual is in the process log, the +following command can dump the ‘haskell-process’ state: + + M-: (haskell-process) + + The output can be copied from the ‘*Messages*’ buffer. + +13.9 Haskell Interactive Mode Querying +====================================== + +There a few ways GHCi lets you query information about your code. + +13.9.1 Get identifer type +------------------------- + +To print the type of the top-level identifier at point in the REPL and +in the message buffer, run the following command: + + M-x haskell-process-do-type + + or ‘C-c C-t’. + +13.9.2 Insert identifier’s type as type signature +------------------------------------------------- + +To print the type of the top-level identifier at point, run the +following command: + + C-u M-x haskell-process-do-type + + or ‘C-u C-c C-t’. + +13.9.3 Get identifier info +-------------------------- + +To print the info of the identifier at point, run the following command: + + M-x haskell-process-do-info + + or ‘C-c C-i’. + +13.9.4 Presentation mode +------------------------ + +When using ‘C-c C-i’ or ‘C-c C-t’ it will open a buffer in +haskell-presentation-mode. You can hit ‘q’ to close the buffer. + + But you can also continue to use ‘C-c C-i’ inside the buffer to drill +further down data types and classes. + + E.g. if you go to ‘Ord’ in your code buffer and ‘C-c C-i’, it will +popup a buffer containing + + class Eq a => Ord a where + compare :: a -> a -> Ordering + (<) :: a -> a -> Bool + (>=) :: a -> a -> Bool + (>) :: a -> a -> Bool + (<=) :: a -> a -> Bool + max :: a -> a -> a + min :: a -> a -> a + -- Defined in `GHC.Classes' + + And all the instances of that class. But then you can also move your +cursor to ‘Ordering’ and hit ‘C-c C-i’ again to get another popup: + + data Ordering = LT | EQ | GT -- Defined in `GHC.Types' + instance Bounded Ordering -- Defined in `GHC.Enum' + instance Enum Ordering -- Defined in `GHC.Enum' + instance Eq Ordering -- Defined in `GHC.Classes' + instance Ord Ordering -- Defined in `GHC.Classes' + instance Read Ordering -- Defined in `GHC.Read' + instance Show Ordering -- Defined in `GHC.Show' + + And so on. It’s a very good way of exploring a new codebase. + +13.9.5 Browse import’s module +----------------------------- + +To print all exported identifiers of the module imported by the import +line at point, run the following command: + + M-x haskell-process-do-info + + or ‘C-c C-i’. It will print all exports by running ‘:browse +The.Module’ in the GHCi process. + +13.10 Haskell Interactive Mode Cabal integration +================================================ + +There’s some integration with Cabal in Haskell Interactive Mode. Once +you’ve started a session, the features below are available. + +13.10.1 Cabal building +---------------------- + +The most common Cabal action is building, so that has a specific +command: + + M-x haskell-process-cabal-build + + Or ‘C-c C-c’. When building, it will hide unneccessary output. + + For example, to build the ‘ace‘ package, the output is simply: + + Compiling: ACE.Types.Tokens + Compiling: ACE.Combinators + Compiling: ACE.Tokenizer + Compiling: ACE.Parsers + Compiling: ACE.Pretty + Compiling: ACE + Complete: cabal build (0 compiler messages) + + Whereas the complete output is normally: + + Building ace-0.5... + Preprocessing library ace-0.5... + [4 of 9] Compiling ACE.Types.Tokens ( src/ACE/Types/Tokens.hs, dist/build/ACE/Types/Tokens.o ) + [5 of 9] Compiling ACE.Combinators ( src/ACE/Combinators.hs, dist/build/ACE/Combinators.o ) [ACE.Types.Tokens changed] + [6 of 9] Compiling ACE.Tokenizer ( src/ACE/Tokenizer.hs, dist/build/ACE/Tokenizer.o ) [ACE.Types.Tokens changed] + [7 of 9] Compiling ACE.Parsers ( src/ACE/Parsers.hs, dist/build/ACE/Parsers.o ) + [8 of 9] Compiling ACE.Pretty ( src/ACE/Pretty.hs, dist/build/ACE/Pretty.o ) + [9 of 9] Compiling ACE ( src/ACE.hs, dist/build/ACE.o ) [ACE.Tokenizer changed] + In-place registering ace-0.5... + + Which is considerably more verbose but rarely useful or interesting. + +13.10.2 Arbitrary cabal commands +-------------------------------- + +To run an arbitrary Cabal command: + + C-u M-x haskell-process-cabal + + Or run ‘C-u C-c c’. + + It will prompt for an input, so you can write ‘configure -fdev’, for +example. + +13.10.3 Completing cabal commands +--------------------------------- + +To run some common Cabal commands, just run: + + M-x haskell-process-cabal + + Or ‘C-c c’. This is commonly used to do ‘install’, ‘haddock’, +‘configure’, etc. + +13.11 Haskell Interactive Mode Debugger +======================================= + +There is limited support for debugging in GHCi. Haskell Interactive +Mode provides an interface for interacting with this. + +13.11.1 Opening the debug buffer +-------------------------------- + +To open the debug buffer run the following command from any buffer +associated with a session: + + M-x haskell-debug + + It will open a buffer that looks like this: + + Debugging haskell + + You have to load a module to start debugging. + + g - refresh + + Modules + + No loaded modules. + +13.11.2 Loading modules +----------------------- + +To debug anything you need to load something into GHCi. Switch to a +normal file, for example: + + main = do putStrLn "Hello!" + putStrLn "World" + + and load it into GHCi (‘C-c C-l’). Now when you hit ‘g’ (to refresh) +in the debugging buffer, you’ll see something like: + + + Debugging haskell + + b - breakpoint, g - refresh + + Context + + Not debugging right now. + + Breakpoints + + No active breakpoints. + + Modules + + Main - hello.hs + +13.11.3 Setting a breakpoint +---------------------------- + +To set a breakpoint hit ‘b’ in the debugger buffer. It will prompt for +a name. Enter ‘main’ and hit ‘RET’. + + Now the buffer will look like this: + + Debugging haskell + + s - step into an expression, b - breakpoint + d - delete breakpoint, g - refresh + + Context + + Not debugging right now. + + Breakpoints + + 0 - Main (1:8) + + Modules + + Main - hello.hs + +13.11.4 Start stepping +---------------------- + +Hit ‘s’ to step through an expression: it will prompt for an expression +to evaluate and step through. Enter ‘main’ and hit ‘RET’. Now the +buffer will look like this: + + Debugging haskell + + s - step into an expression, b - breakpoint + d - delete breakpoint, a - abandon context, c - continue + p - previous step, n - next step + g - refresh + + Context + + main - hello.hs (stopped) + + do putStrLn "Hello!" + putStrLn "World" + + _result :: IO () = _ + + 1 do putStrLn "Hello!" putStrLn "World" + + Breakpoints + + 0 - Main (1:8) + + Modules + + Main - hello.hs + + What we see here is the current expression being evaluated: + + do putStrLn "Hello!" + putStrLn "World" + + And we see the type of it: + + _result :: IO () = _ + + And we see a backtrace of steps so far: + + 1 do putStrLn "Hello!" putStrLn "World" + +13.11.5 Continue stepping +------------------------- + +To continue stepping, just hit ‘s’ again. Now the context will change +to: + + main - hello.hs (stopped) + + putStrLn "Hello!" + + _result :: IO () = _ + + 1 do putStrLn "Hello!" putStrLn "World" + + Hitting ‘s’ once more, we see the context change to: + + putStrLn "World" + + _result :: IO () = _ + + 2 putStrLn "Hello!" + 1 do putStrLn "Hello!" putStrLn "World" + + Finally hitting ‘s’ again will say "Computation finished". Hitting +‘s’ a final time will change the display back to: + + Debugging haskell + + s - step into an expression, b - breakpoint + d - delete breakpoint, g - refresh + + Context + + Finished debugging. + + 2 putStrLn "Hello!" + 1 do putStrLn "Hello!" putStrLn "World" + + Breakpoints + + 1 - Main (1:8) + + Modules + + Main - hello.hs + + And you’re done debugging. + + +File: haskell-mode.info, Node: Editing Cabal files, Next: Browsing Haddocks, Prev: Interactive Haskell, Up: Top + +14 Editing Cabal files +********************** + +‘haskell-cabal-mode’ is a major mode for editing Cabal package +description files +(http://www.haskell.org/cabal/users-guide/developing-packages.html) and +is automatically associated with files having a ‘.cabal’ extension. + + For quickly locating and jumping to the nearest ‘.cabal’ file from a +Haskell source buffer, you can use ‘M-x haskell-cabal-visit-file’; with +a prefix argument (i.e. ‘C-u’) ‘find-file-other-window’ is used to +visit the ‘.cabal’ file. ‘haskell-cabal-visit-file’ is bound to the key +sequence ‘C-c v c’. + + TODO/WRITEME + + +File: haskell-mode.info, Node: Browsing Haddocks, Next: Spell checking strings and comments, Prev: Editing Cabal files, Up: Top + +15 Browsing Haddocks using ‘w3m’ +******************************** + +An experimental feature is use of the w3m browser to browse Haddock docs +inside Emacs. + +15.1 Get w3m +============ + +Most Linux distributions will have a package for the binary: + + $ sudo apt-get install w3m + + Now grab ‘w3m.el’ from: + + • <http://emacs-w3m.namazu.org/> + • ‘M-x’ ‘package-install’ ‘RET’ ‘w3m’ ‘RET’ + + Confirm installation by trying ‘M-x’ ‘w3m-browse-url’ ‘RET’ +‘haskell.org’ ‘RET’. + + If this works, you’re good to go. + +15.2 Configure w3m +================== + +Now that you have w3m, you probably want to configure it to be more of a +passive viewer than a full-fledged browser. For example: + + (setq w3m-mode-map (make-sparse-keymap)) + + (define-key w3m-mode-map (kbd "RET") 'w3m-view-this-url) + (define-key w3m-mode-map (kbd "q") 'bury-buffer) + (define-key w3m-mode-map (kbd "<mouse-1>") 'w3m-maybe-url) + (define-key w3m-mode-map [f5] 'w3m-reload-this-page) + (define-key w3m-mode-map (kbd "C-c C-d") 'haskell-w3m-open-haddock) + (define-key w3m-mode-map (kbd "M-<left>") 'w3m-view-previous-page) + (define-key w3m-mode-map (kbd "M-<right>") 'w3m-view-next-page) + (define-key w3m-mode-map (kbd "M-.") 'w3m-haddock-find-tag) + + (defun w3m-maybe-url () + (interactive) + (if (or (equal '(w3m-anchor) (get-text-property (point) 'face)) + (equal '(w3m-arrived-anchor) (get-text-property (point) 'face))) + (w3m-view-this-url))) + +15.3 Import w3m-haddock +======================= + +It’s not enabled by default in haskell-mode at present, so you need to +import it manually: + + (require 'w3m-haddock) + +15.4 Add a hook for w3m +======================= + +In order to make haddock pages a little more palatable (and add syntax +highlighting to source view), you can add this hook: + + (add-hook 'w3m-display-hook 'w3m-haddock-display) + + It’s a little rough around the edges, but it’s a start. + +15.5 Configure your package locations +===================================== + +By default, the package locations is set to: + + (defcustom haskell-w3m-haddock-dirs + '("~/.cabal/share/doc/")) + + If you are using an hsenv or a custom package directory, you should +configure this variable with M-x customize-variable or by writing the +custom-set-variables code for it. + +15.6 Finally +============ + +You did all that! Now you’re ready to bind a useful key: + + (define-key haskell-mode-map (kbd "C-c C-d") 'haskell-w3m-open-haddock) + + Now when you press ‘C-c’ ‘C-d’ it will prompt for a package to browse +to. + + This feature will be improved gradually as time goes on. + + +File: haskell-mode.info, Node: Spell checking strings and comments, Next: Aligning code, Prev: Browsing Haddocks, Up: Top + +16 Using with ‘flyspell-prog-mode’ +********************************** + +Strings and comments can be checked for spelling mistakes. There is a +standard Emacs mode for this purpose, ‘flyspell-prog-mode’, that can be +enabled in Haskell buffers. Spelling errors are underlined using +squiggly red lines. + + Documentation for ‘flyspell-prog-mode’ can be found in *Note +(emacs)Spelling::. Here we point to a couple of useful keybindings: + + • ‘M-$’ - Check and correct spelling of the word at point + (‘ispell-word’). + + • ‘digit’ - Replace the word, just this time, with one of the + displayed near-misses. Each near-miss is listed with a digit; type + that digit to select it. + + • ‘SPC’ - Skip this word—continue to consider it incorrect, but don’t + change it here. + + To enable spell checking of strings and comments add this line to +your ‘~/.emacs’ file: + + ‘(add-hook 'haskell-mode-hook 'flyspell-prog-mode)’ + + +File: haskell-mode.info, Node: Aligning code, Next: Rectangular commands, Prev: Spell checking strings and comments, Up: Top + +17 Aligning code +**************** + +Select a region you want to align text within, ‘M-x’ ‘align-regexp’, and +type a regexp representing the alignment delimiter. + + For example, I often line up my Haddock comments: + + f :: a -- ^ does a + -> Foo b -- ^ and b + -> c -- ^ to c + + Select the region, and let the regexp be ‘--’: + + f :: a -- ^ does a + -> Foo b -- ^ and b + -> c -- ^ to c + + Of course, this works for just about anything. Personally, I’ve +globally bound it to ‘C-x a r’: + + (global-set-key (kbd "C-x a r") 'align-regexp) + + Note that you can also just use the rules below for telling the +aligner about Haskell. Once you evaluate this, you can just use ‘M-x’ +‘align’, which I like to bind to ‘M-[’. + + (add-to-list 'align-rules-list + '(haskell-types + (regexp . "\\(\\s-+\\)\\(::\\|∷\\)\\s-+") + (modes quote (haskell-mode literate-haskell-mode)))) + (add-to-list 'align-rules-list + '(haskell-assignment + (regexp . "\\(\\s-+\\)=\\s-+") + (modes quote (haskell-mode literate-haskell-mode)))) + (add-to-list 'align-rules-list + '(haskell-arrows + (regexp . "\\(\\s-+\\)\\(->\\|→\\)\\s-+") + (modes quote (haskell-mode literate-haskell-mode)))) + (add-to-list 'align-rules-list + '(haskell-left-arrows + (regexp . "\\(\\s-+\\)\\(<-\\|←\\)\\s-+") + (modes quote (haskell-mode literate-haskell-mode)))) + + +File: haskell-mode.info, Node: Rectangular commands, Next: REPL, Prev: Aligning code, Up: Top + +18 Using rectangular region commands +************************************ + +Emacs has a set of commands which operate on the region as if it were +rectangular. This turns out to be extremely useful when dealing with +whitespace sensitive languages. + + • ‘C-x r o’ is "Open Rectangle". + + It will shift any text within the rectangle to the right side. + Also see: + + • ‘C-x r t’ is "String Rectangle". + + It will replace any text within the rectangle with the given string + on all the lines in the region. If comment-region didn’t already + exist, you could use this instead, for example. + + • ‘C-x r d’ is "Delete Rectangle". + + It will delete the contents of the rectangle and move anything on + the right over. + + • ‘C-x r r’ is "Copy Rectangle to Register". + + It will prompt you for a register number so it can save it for + later. + + • ‘C-x r g’ is "Insert register". + + This will insert the contents of the given register, overwriting + whatever happens to be within the target rectangle. (So make room) + + • ‘C-x r k’ is "Kill rectangle". + + Delete rectangle and save contents for: + + • ‘C-x r y’ is "Yank rectangle". + + This will insert the contents of the last killed rectangle. + + As with all Emacs modifier combos, you can type ‘C-x r C-h’ to find +out what keys are bound beginning with the ‘C-x r’ prefix. + + +File: haskell-mode.info, Node: REPL, Next: Collapsing Haskell code, Prev: Rectangular commands, Up: Top + +19 Using GHCi REPL within Emacs +******************************* + +To start the REPL you can run one of the following: + + • ‘M-x run-haskell’ + • ‘M-x switch-to-haskell’ + + This repl works with Comint +(https://www.emacswiki.org/emacs/ComintMode). So you will feel at home +if you are already using ‘M-x Shell’ or ‘M-x ielm’. + + ‘Inf-Haskell’ is a Major mode for running GHCi, with comint. + + Important key bindings in ‘Inf-haskell’: + +‘RET’ + invokes ‘comint-send-input’. Sends the input to the GHCi process, + evaluates the line and returns the output. + +‘C-d or <delete>’ + deletes the forward character + +‘<C-up> or M-p’ + invokes ‘comint-previous-input’. Cycle backwards through input + history, saving input. + +‘<C-down> or M-n’ + invokes ‘comint-next-input’. Cycle forwards through input history. + +‘C-c C-c’ + invokes ‘comint-interrupt-subjob’. Sends KeyboardInterrupt signal. + +‘C-c C-\’ + invokes ‘comint-quit-subjob’. Sends KeyboardInterrupt signal. + +‘C-c C-z’ + invokes ‘comint-stop-subjob’. Kills the GHCi process. + +‘C-c M-r’ + invokes ‘comint-previous-matching-input-from-input’. If you are + familiar with ‘C-r’ in bash. This is the same as that. Searches + backwards through input history for match for current input. + +‘C-c M-s’ + invokes ‘comint-next-matching-input-from-input’. Searches forwards + through input history for match for current input. + +‘C-c C-l’ + invokes ‘comint-dynamic-list-input-ring’. Displays a list of + recent inputs entered into the current buffer. + +‘C-c M-o’ + invokes ‘comint-clear-buffer’. Clears the buffer (Only with Emacs + 25.X and above) + +‘C-c C-n’ + invokes ‘comint-next-prompt’. Goes to the start of the previous + REPL prompt. + +‘C-c C-p’ + invokes ‘comint-previous-prompt’. Goes to the start of the next + REPL prompt. + +‘C-c C-o’ + invokes ‘comint-delete-output’. Clears the output of the most + recently evaluated expression. + +‘C-c C-e’ + invokes ‘comint-show-maximum-output’. Moves the point to the end + of the buffer. + +‘C-c C-u’ + invokes ‘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.) + +‘C-c C-w’ + invokes ‘backward-kill-word’. Kills backward, the word at point + +‘C-c C-s’ + invokes ‘comint-write-output’. Write output from interpreter since + last input to FILENAME. Any prompt at the end of the output is not + written. + +19.1 Relevant defcustoms: +========================= + +Interpreter (defcustom) Default Possible Values + Value +--------------------------------------------------------------------------- +‘haskell-process-type’ ‘'auto’ ‘'stack-ghci, 'cabal-repl, + 'ghci, 'auto’ +‘inferior-haskell-hook’ ‘nil’ - +‘haskell-process-path-ghci’ ‘ghci’ - +‘haskell-process-args-ghci’ ‘-ferror-spans’- +‘haskell-process-path-cabal’ ‘cabal’ - +‘haskell-process-args-cabal-repl’‘--ghc-option=-ferror-spans’- +‘haskell-process-path-stack’ ‘stack’ - +‘haskell-process-args-stack-ghci’‘--ghci-options=-ferror-spans- + --no-build + --no-load’ + +19.2 More on ‘haskell-process-type’ +=================================== + +The Haskell interpreter used by ‘Inf-Haskell’ is auto-detected by +default, but is customizable with defcustom ‘haskell-process-type’. The +values recognized by it are (default is ’auto): + + • ‘'stack-ghci’ + • ‘'cabal-repl’ + • ‘'ghci’ + • ‘'auto’ + + if the ‘haskell-process-type’ is ‘'auto’, the directories are +searched for ‘cabal.sandbox.config’ or ‘stack.yaml’ or ‘*.cabal’ file. +If the file is present, then appropriate process is started. + + When ‘cabal.sandbox.config’ is found ‘haskell-process-type’ is +‘'cabal-repl’. Similarly, when ‘stack.yaml’ is found +‘haskell-process-type’ is ‘'stack-ghci’. Similarly, when ‘xyz.cabal’ is +found ‘haskell-process-type’ is ‘'cabal-repl’. When nothing is found +‘haskell-process-type’ is ‘'ghci’. When more than one file such as +‘cabal.sandbox.config’ and ‘stack.yaml’ are found the following +preference is followed. + + ‘cabal.sandbox.config’ > ‘stack.yaml’ > ‘*.cabal’ + + +File: haskell-mode.info, Node: Collapsing Haskell code, Next: Getting Help and Reporting Bugs, Prev: REPL, Up: Top + +20 Collapsing Haskell code +************************** + +This is ‘hs-minor-mode’ for ‘haskell-mode’. This module uses hideshow +module. + + To activate this minor mode (haskell-collapse-mode) + • ‘M-x haskell-collapse-mode’ is "To start haskell-collapse-mode". + This minor mode works with indentation. + + In a quick glance: + +‘C-c C-c’ + is bound to ‘haskell-hide-toggle’ +‘C-c C-M-c’ +‘C-c C-M-h’ +‘C-c C-M-s’ + are all bound to ‘haskell-hide-toggle-all’ + + How to use ‘M-x haskell-hide-toggle’? + + Place your point on the code block that you want to collapse and hit +the keybinding. Now the code collapses and you can see the first line +of the block and elipsis. + + Take this example code (example usage of ‘M-x haskell-hide-toggle’): +when you place the cursor here, like this (notice the thick block in the +first line): + + ‘ f█x | rem i 3 == 0 = if i == 0 && (k /= 0) then (c k) else (h j) | +otherwise = 0 where i = sum x j = g x (div i 3) 0 0 [] k = zeroes x 0 ’ + + or + + ‘ f x | rem i 3 == 0 = if i == 0 && (k /= 0) then (c k) else (h j) █ +| otherwise = 0 where i = sum x j = g x (div i 3) 0 0 [] k = zeroes x 0 +’ + + then when you collapse it becomes something like this: + + ‘ f█x... ’ + + It works in terms of (indentation) blocks. + + One more example: + + ‘ f x | rem i 3 == 0 = if i == 0 && (k /= 0) then (c k) else (h j) | +otherwise = 0 w█ere i = sum x j = g x (div i 3) 0 0 [] k = zeroes x 0 ’ + + or + + ‘ f x | rem i 3 == 0 = if i == 0 && (k /= 0) then (c k) else (h j) | +otherwise = 0 where i = sum x j = g x (div i 3) 0 0 [] █ k = zeroes x 0 +’ + + this, will result in something like: + + ‘ f x | rem i 3 == 0 = if i == 0 && (k /= 0) then (c k) else (h j) | +otherwise = 0 where i = sum █... ’ + + The other functionality ‘M-x haskell-hide-toggle-all’ also works only +for indentation and it collapses all toplevel functions. + + So a file that looks like this: + + main = interact $ show.f. map read .words + f (x:xs) = dp x xs + + dp money a | money < 0 || null a = [1..1000] + dp 0 a = [] + dp money a @ (coin:coins) + | (length i) <= length j = i + | otherwise = j + where i = (coin:(dp (money-coin) a)) + j = (dp money coins) + + will turn into this: + + main = interact $ show.f. map read .words + f (x:xs) = dp x xs + + dp money a | money < 0 || null a = [1..1000] + dp 0 a = [] + dp money a @ (coin:coins)... + + +File: haskell-mode.info, Node: Getting Help and Reporting Bugs, Next: Concept index, Prev: Collapsing Haskell code, Up: Top + +21 Getting Help and Reporting Bugs +********************************** + +Work on Haskell Mode is organized with Github ‘haskell-mode’ project. +To understand how the project is run please read the information in the +project wiki pages (https://github.com/haskell/haskell-mode/wiki). + + To report any issues please use the Github’s issue mechanism +available from Haskell Mode’s GitHub Home +(https://github.com/haskell/haskell-mode). + + For a quick question visit ‘#haskell-emacs’ channel on IRC +‘irc.freenode.net’. + + There is also a (now defunct) Haskellmode-emacs mailing list +(http://projects.haskell.org/cgi-bin/mailman/listinfo/haskellmode-emacs), +also available on Gmane (http://gmane.org/) via the +gmane.comp.lang.haskell.emacs +(http://dir.gmane.org/gmane.comp.lang.haskell.emacs) newsgroup. + + We welcome code and non-code contributions so that we can all enjoy +coding Haskell even more. + + +File: haskell-mode.info, Node: Concept index, Next: Function index, Prev: Getting Help and Reporting Bugs, Up: Top + +Concept index +************* + + +* Menu: + +* benchmarking: Interactive Haskell. (line 472) +* CUA mode: Indentation. (line 49) +* customizing: Installation. (line 55) +* customizing <1>: Interactive Haskell. (line 53) +* haskell-mode: Editing Haskell Code. + (line 6) +* indentation: Indentation. (line 6) +* layout rule: Indentation. (line 6) +* off-side rule: Indentation. (line 6) +* rectangle: Indentation. (line 49) +* testing: Interactive Haskell. (line 470) +* Unicode: Unicode support. (line 6) + + +File: haskell-mode.info, Node: Function index, Next: Variable index, Prev: Concept index, Up: Top + +Function index +************** + + +* Menu: + +* haskell-cabal-mode: Editing Cabal files. (line 6) +* haskell-cabal-visit-file: Editing Cabal files. (line 11) +* haskell-compile: Compilation. (line 6) +* haskell-decl-scan-mode: Declaration scanning. + (line 6) +* haskell-mode: Editing Haskell Code. + (line 6) +* haskell-session-change-target: Interactive Haskell. (line 463) + + +File: haskell-mode.info, Node: Variable index, Prev: Function index, Up: Top + +Variable index +************** + + +* Menu: + +* haskell-c2hs-hook-name-face: Syntax highlighting. (line 39) +* haskell-c2hs-hook-pair-face: Syntax highlighting. (line 38) +* haskell-cabal-mode-hook: Editing Cabal files. (line 6) +* haskell-compile-cabal-build-command: Compilation. (line 35) +* haskell-compile-cabal-build-command-alt: Compilation. (line 35) +* haskell-compile-command: Compilation. (line 35) +* haskell-constructor-face: Syntax highlighting. (line 30) +* haskell-decl-scan-mode-hook: Declaration scanning. + (line 6) +* haskell-definition-face: Syntax highlighting. (line 31) +* haskell-interactive-mode-hook: Interactive Haskell. (line 463) +* haskell-keyword-face: Syntax highlighting. (line 28) +* haskell-literate-comment-face: Syntax highlighting. (line 35) +* haskell-mode-hook: Installation. (line 60) +* haskell-operator-face: Syntax highlighting. (line 33) +* haskell-pragma-face: Syntax highlighting. (line 34) +* haskell-process-args-cabal-new-repl: Interactive Haskell. (line 76) +* haskell-process-args-cabal-repl: Interactive Haskell. (line 76) +* haskell-process-args-ghci: Interactive Haskell. (line 76) +* haskell-process-args-stack-ghci: Interactive Haskell. (line 75) +* haskell-process-path-cabal: Interactive Haskell. (line 76) +* haskell-process-path-ghci: Interactive Haskell. (line 76) +* haskell-process-path-stack: Interactive Haskell. (line 76) +* haskell-process-type: Interactive Haskell. (line 76) +* haskell-quasi-quote-face: Syntax highlighting. (line 36) +* haskell-type-face: Syntax highlighting. (line 29) + + + +Tag Table: +Node: Top683 +Node: Introduction2588 +Node: Installation4173 +Node: Editing Haskell Code6796 +Node: Syntax highlighting10556 +Node: Completion support12816 +Node: Unicode support14860 +Node: Indentation19532 +Node: External indentation23008 +Node: Autoformating23736 +Node: Module templates24364 +Node: Declaration scanning24794 +Node: Compilation28082 +Node: Interactive Haskell31987 +Node: Editing Cabal files62914 +Node: Browsing Haddocks63661 +Node: Spell checking strings and comments66486 +Node: Aligning code67592 +Node: Rectangular commands69337 +Node: REPL70857 +Node: Collapsing Haskell code75635 +Node: Getting Help and Reporting Bugs78243 +Node: Concept index79287 +Node: Function index80326 +Node: Variable index81048 + +End Tag Table + + +Local Variables: +coding: utf-8 +End: diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-modules.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-modules.el new file mode 100644 index 000000000000..cb4e841d67e0 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-modules.el @@ -0,0 +1,117 @@ +;;; haskell-modules.el --- -*- 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 <http://www.gnu.org/licenses/>. + +;;; Code: + +(require 'haskell-sort-imports) +(require 'haskell-align-imports) +(require 'haskell-session) +(require 'haskell-navigate-imports) +(require 'haskell-complete-module) +(require 'haskell-sandbox) +(require 'haskell-customize) + +(defun haskell-add-import (&optional module) + "Add an import to the import list. Sorts and aligns imports, +unless `haskell-stylish-on-save' is set, in which case we defer +to stylish-haskell." + (interactive) + (save-excursion + (goto-char (point-max)) + (haskell-navigate-imports) + (insert (haskell-import-for-module + (or module + (haskell-complete-module-read + "Module: " + (haskell-session-all-modules (haskell-modules-session)))))) + (unless haskell-stylish-on-save (haskell-sort-imports) + (haskell-align-imports)))) + +(defun haskell-import-for-module (module) + "Get import statements for the given module." + (let ((mapping (assoc module haskell-import-mapping))) + (if mapping + (cdr mapping) + (concat (read-from-minibuffer "Import line: " + (format "import %s" module)) + "\n")))) + +;;;###autoload +(defun haskell-session-installed-modules (_session &optional _dontcreate) + "Get the modules installed in the current package set." + ;; TODO: Again, this makes HEAVY use of unix utilities. It'll work + ;; fine in Linux, probably okay on OS X, and probably not at all on + ;; Windows. Again, if someone wants to test on Windows and come up + ;; with alternatives that's OK. + ;; + ;; Ideally all these package queries can be provided by a Haskell + ;; program based on the Cabal API. Possibly as a nice service. Such + ;; a service could cache and do nice things like that. For now, this + ;; simple shell script takes us far. + ;; + ;; Probably also we can take the code from inferior-haskell-mode. + ;; + ;; Ugliness aside, if it saves us time to type it's a winner. + ;; + ;; FIXME/TODO: add support for (eq 'cabal-repl (haskell-process-type)) + (let ((session (haskell-session-maybe))) + (when session + (let ((modules (shell-command-to-string + (format "%s 2> /dev/null | %s | %s" + (cond + ((haskell-sandbox-exists-p session) + (concat "ghc-pkg dump -f " + (shell-quote-argument (haskell-sandbox-pkgdb session)))) + (t "ghc-pkg dump")) + "egrep '^(exposed-modules: | )[A-Z]'" + "cut -c18-")))) + (split-string modules))))) + +;;;###autoload +(defun haskell-session-all-modules (session &optional dontcreate) + "Get all modules -- installed or in the current project. +If DONTCREATE is non-nil don't create a new session." + (append (haskell-session-installed-modules session dontcreate) + (haskell-session-project-modules session dontcreate))) + +;;;###autoload +(defun haskell-session-project-modules (session &optional dontcreate) + "Get the modules of the current project. +If DONTCREATE is non-nil don't create a new session." + (if (or (not dontcreate) (haskell-session-maybe)) + (let* ((modules + (shell-command-to-string + (format "%s && %s" + (format "cd %s" (haskell-session-cabal-dir session)) + ;; TODO: Use a different, better source. Possibly hasktags or some such. + ;; TODO: At least make it cross-platform. Linux + ;; (and possibly OS X) have egrep, Windows + ;; doesn't -- or does it via Cygwin or MinGW? + ;; This also doesn't handle module\nName. But those gits can just cut it out! + "egrep '^module[\t\r ]+[^(\t\r ]+' . -r -I --include='*.*hs' --include='*.hsc' -s -o -h | sed 's/^module[\t\r ]*//' | sort | uniq")))) + (split-string modules)))) + +(defun haskell-modules-session () + "Get the `haskell-session', throw an error if it's not + available." + (or (haskell-session-maybe) + (haskell-session-assign + (or (haskell-session-from-buffer) + (haskell-session-choose) + (error "No session associated with this buffer. Try M-x haskell-session-change or report this as a bug."))))) + +(provide 'haskell-modules) diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-modules.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-modules.elc new file mode 100644 index 000000000000..9290a413e016 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-modules.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-move-nested.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-move-nested.el new file mode 100644 index 000000000000..1e4774de4fcc --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-move-nested.el @@ -0,0 +1,130 @@ +;;; haskell-move-nested.el --- Change the column of text nested below a line -*- lexical-binding: t -*- + +;; Copyright (C) 2010 Chris Done + +;; Author: Chris Done <chrisdone@gmail.com> + +;; This file is not part of GNU Emacs. + +;; This program 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 of +;; the License, or (at your option) any later version. + +;; This program 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 +;; <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This module is intended for Haskell mode users, but is +;; independent of Haskell mode. + +;; Example usage: + +;; (define-key haskell-mode-map (kbd "C-,") 'haskell-move-nested-left) +;; (define-key haskell-mode-map (kbd "C-.") 'haskell-move-nested-right) + +;;; Code: + +;;;###autoload +(defun haskell-move-nested (cols) + "Shift the nested off-side-rule block adjacent to point by COLS columns to the right. + +In Transient Mark mode, if the mark is active, operate on the contents +of the region instead. +" + (save-excursion + (if (and transient-mark-mode mark-active) + (progn + (indent-rigidly (region-beginning) (region-end) cols) + (setq deactivate-mark nil)) + (let ((region (haskell-move-nested-region))) + (when region + (indent-rigidly (car region) (cdr region) cols)))))) + +;;;###autoload +(defun haskell-move-nested-right (cols) + "Increase indentation of the following off-side-rule block adjacent to point. + +Use a numeric prefix argument to indicate amount of indentation to apply. + +In Transient Mark mode, if the mark is active, operate on the contents +of the region instead." + (interactive "p") + (haskell-move-nested cols) + ) + +;;;###autoload +(defun haskell-move-nested-left (cols) + "Decrease indentation of the following off-side-rule block adjacent to point. + +Use a numeric prefix argument to indicate amount of indentation to apply. + +In Transient Mark mode, if the mark is active, operate on the contents +of the region instead." + (interactive "p") + (haskell-move-nested (- cols)) + ) + +(defun haskell-move-nested-region () + "Infer region off-side-rule block adjacent to point. +Used by `haskell-move-nested'. +" + (save-excursion + (let ((starting-level (current-column))) + (forward-line) + (let ((current-level (haskell-move-nested-indent-level))) + (let ((start-point (line-beginning-position)) + (start-end-point (line-end-position)) + (end-point nil) + (last-line 0)) + (forward-line) + (while (and (not (= (line-beginning-position) last-line)) + (or (> (haskell-move-nested-indent-level) starting-level) + (and (> current-level starting-level) + (>= (haskell-move-nested-indent-level) current-level)))) + (setq last-line (line-beginning-position)) + (setq end-point (line-end-position)) + (forward-line)) + (cons start-point (or end-point + start-end-point))))))) + +(defun haskell-move-nested-indent-level () + (max + 0 + (1- (length + (buffer-substring-no-properties + (line-beginning-position) + (or (save-excursion (goto-char (line-beginning-position)) + (search-forward-regexp "[^ ]" (line-end-position) t 1)) + (line-beginning-position))))))) + +(defun haskell-kill-nested () + "Kill the nested region after point." + (interactive) + (let ((start (point)) + (reg (save-excursion + (search-backward-regexp "^[ ]+" (line-beginning-position) t 1) + (search-forward-regexp "[^ ]" (line-end-position) t 1) + (haskell-move-nested-region)))) + (kill-region start (cdr reg)))) + +(defun haskell-delete-nested () + "Kill the nested region after point." + (interactive) + (let ((start (point)) + (reg (save-excursion + (search-backward-regexp "^[ ]+" (line-beginning-position) t 1) + (search-forward-regexp "[^ ]" (line-end-position) t 1) + (haskell-move-nested-region)))) + (delete-region start (cdr reg)))) + +(provide 'haskell-move-nested) + +;;; haskell-move-nested.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-move-nested.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-move-nested.elc new file mode 100644 index 000000000000..f4a3b68471a9 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-move-nested.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-navigate-imports.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-navigate-imports.el new file mode 100644 index 000000000000..7600d2305695 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-navigate-imports.el @@ -0,0 +1,130 @@ +;;; haskell-navigate-imports.el --- A function for cycling through Haskell import lists -*- lexical-binding: t -*- + +;; Copyright (C) 2010 Chris Done + +;; Author: Chris Done <chrisdone@gmail.com> + +;; This file is not part of GNU Emacs. + +;; This program 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 of +;; the License, or (at your option) any later version. + +;; This program 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 +;; <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; The cycling step will stop once at the last import list so +;; that it is easy to add a new import list. + +;; This module works completely independently of any libraries +;; (including haskell-mode). + +;; Exports three interactive functions: +;; 1. haskell-navigate-imports +;; 2. haskell-navigate-imports-go +;; 3. haskell-navigate-imports-return + +;; Example usage: + +;; (require 'haskell-navigate-imports) +;; (define-key haskell-mode-map (kbd "<f8>") 'haskell-navigate-imports) + +;;; Code: + +(defvar haskell-navigate-imports-start-point nil) + +(defvar haskell-literate) ; defined in haskell-mode.el + +;;;###autoload +(defun haskell-navigate-imports (&optional return) + "Cycle the Haskell import lines or return to point (with prefix arg)." + (interactive "P") + (if return + (haskell-navigate-imports-return) + (haskell-navigate-imports-go))) + +;;;###autoload +(defun haskell-navigate-imports-go () + "Go to the first line of a list of consecutive import lines. Cycles." + (interactive) + (unless (or (haskell-navigate-imports-line) + (equal (line-beginning-position) (point-min)) + (save-excursion (forward-line -1) + (haskell-navigate-imports-line))) + (setq haskell-navigate-imports-start-point (point))) + (haskell-navigate-imports-go-internal)) + +;;;###autoload +(defun haskell-navigate-imports-return () + "Return to the non-import point we were at before going to the module list. + If we were originally at an import list, we can just cycle through easily." + (interactive) + (when haskell-navigate-imports-start-point + (goto-char haskell-navigate-imports-start-point))) + +(defun haskell-navigate-imports-go-internal () + "Go to the first line of a list of consecutive import lines. Cycle." + (if (haskell-navigate-imports-line) + (progn (haskell-navigate-imports-goto-end) + (when (haskell-navigate-imports-find-forward-line) + (haskell-navigate-imports-go-internal))) + (let ((point (haskell-navigate-imports-find-forward-line))) + (if point + (goto-char point) + (progn (goto-char (point-min)) + (if (haskell-navigate-imports-find-forward-line) + (haskell-navigate-imports-go-internal) + (let ((module (if (eq haskell-literate 'bird) + "^> ?module" + "^module"))) + (when (search-forward-regexp module nil t 1) + (search-forward "\n\n" nil t 1))))))))) + +(defun haskell-navigate-imports-goto-end () + "Skip a bunch of consecutive import lines." + (while (not (or (equal (point) + (point-max)) + (not (haskell-navigate-imports-line)))) + (forward-line))) + +(defun haskell-navigate-imports-find-forward-line () + "Return a point with at an import line, or nothing." + (save-excursion + (while (not (or (equal (point) (point-max)) + (haskell-navigate-imports-after-imports-p) ;; This one just speeds it up. + (haskell-navigate-imports-line))) + (forward-line)) + (if (haskell-navigate-imports-line) + (point) + nil))) + +(defun haskell-navigate-imports-line () + "Try to match the current line as a regexp." + (let ((line (buffer-substring-no-properties (line-beginning-position) + (line-end-position))) + (import (if (eq haskell-literate 'bird) + "^> ?import " + "^import "))) + (if (string-match import line) + line + nil))) + +(defun haskell-navigate-imports-after-imports-p () + "Are we after the imports list? Just for a speed boost." + (save-excursion + (goto-char (line-beginning-position)) + (not (not (search-forward-regexp "\\( = \\|\\<instance\\>\\| :: \\)" + (line-end-position) t 1))))) + +(provide 'haskell-navigate-imports) + +;;; haskell-navigate-imports.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-navigate-imports.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-navigate-imports.elc new file mode 100644 index 000000000000..afcbdd270f16 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-navigate-imports.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-presentation-mode.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-presentation-mode.el new file mode 100644 index 000000000000..c1d3fad72e61 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-presentation-mode.el @@ -0,0 +1,104 @@ +;;; haskell-presentation-mode.el --- Presenting Haskell things -*- lexical-binding: t -*- + +;; Copyright (C) 2013 Chris Done + +;; Author: Chris Done <chrisdone@gmail.com> + +;; This file is not part of GNU Emacs. + +;; 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 GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;;; Code: + +(require 'haskell-mode) +(require 'haskell-session) + +(defvar haskell-presentation-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "q") 'quit-window) + (define-key map (kbd "c") 'haskell-presentation-clear) + map) + "Keymap for `haskell-presentation-mode'.") + +(define-derived-mode haskell-presentation-mode + haskell-mode "Presentation" + "Major mode for viewing Haskell snippets. + \\{hypertext-mode-map}" + (setq case-fold-search nil)) + +(defconst haskell-presentation-buffer-name + "*Haskell Presentation*" + "Haskell Presentation buffer name.") + +(defconst haskell-presentation-hint-message + "-- Hit `q' to close this window; `c' to clear.\n\n" + "Hint message appered in Haskell Presentation buffer.") + +(defun haskell-presentation-buffer () + "Return Haskell Presentaion buffer. +Return current presenation buffer or create new one if absent. +Never returns nil." + ;; TODO Provide interactive calling options: when called interactively make + ;; the presentation buffer current. + (let ((may-buffer (get-buffer haskell-presentation-buffer-name))) + (if may-buffer + may-buffer + (let ((buffer (generate-new-buffer haskell-presentation-buffer-name))) + (with-current-buffer buffer + (insert haskell-presentation-hint-message) + (haskell-presentation-mode) + (setq buffer-read-only t)) + buffer)))) + +(defun haskell-presentation-clear () + "Clear Haskell Presentation buffer." + (interactive) + (let ((hp-buf (get-buffer haskell-presentation-buffer-name))) + (when hp-buf + (with-current-buffer hp-buf + (let ((buffer-read-only nil)) + (erase-buffer) + (insert haskell-presentation-hint-message)))))) + +(defun haskell-presentation-present (session code &optional clear) + "Present given code in a popup buffer. +Creates temporal Haskell Presentation buffer and assigns it to +given haskell SESSION; presented CODE will be fontified as +haskell code. Give an optional non-nil CLEAR arg to clear the +buffer before presenting message." + (let ((buffer (haskell-presentation-buffer))) + (with-current-buffer buffer + + (when (boundp 'shm-display-quarantine) + (setq-local shm-display-quarantine nil)) + + (when clear (haskell-presentation-clear)) + (haskell-session-assign session) + (goto-char (point-min)) + (forward-line 2) + (save-excursion + (let ((buffer-read-only nil)) + (insert code "\n\n")))) + + (if (eq major-mode 'haskell-presentation-mode) + (switch-to-buffer buffer) + (pop-to-buffer buffer)))) + +(provide 'haskell-presentation-mode) + +;;; haskell-presentation-mode.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-presentation-mode.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-presentation-mode.elc new file mode 100644 index 000000000000..7838ae6d3b1d --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-presentation-mode.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-process.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-process.el new file mode 100644 index 000000000000..6e922c61cda1 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-process.el @@ -0,0 +1,510 @@ +;;; haskell-process.el --- Communicating with the inferior Haskell process -*- lexical-binding: t -*- + +;; Copyright (C) 2011 Chris Done + +;; Author: Chris Done <chrisdone@gmail.com> + +;; This file is not part of GNU Emacs. + +;; 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 GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Code: + +(require 'cl-lib) +(require 'json) +(require 'url-util) +(require 'haskell-compat) +(require 'haskell-session) +(require 'haskell-customize) +(require 'haskell-string) + +(defconst haskell-process-prompt-regex "\4" + "Used for delimiting command replies. 4 is End of Transmission.") + +(defvar haskell-reload-p nil + "Used internally for `haskell-process-loadish'.") + +(defconst haskell-process-greetings + (list "Hello, Haskell!" + "The lambdas must flow." + "Hours of hacking await!" + "The next big Haskell project is about to start!" + "Your wish is my IO ().") + "Greetings for when the Haskell process starts up.") + +(defconst haskell-process-logo + (expand-file-name "logo.svg" haskell-mode-pkg-base-dir) + "Haskell logo for notifications.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Accessing commands -- using cl 'defstruct' + +(cl-defstruct haskell-command + "Data structure representing a command to be executed when with + a custom state and three callback." + ;; hold the custom command state + ;; state :: a + state + ;; called when to execute a command + ;; go :: a -> () + go + ;; called whenever output was collected from the haskell process + ;; live :: a -> Response -> Bool + live + ;; called when the output from the haskell process indicates that the command + ;; is complete + ;; complete :: a -> Response -> () + complete) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Building the process + +(defun haskell-process-compute-process-log-and-command (session hptype) + "Compute the log and process to start command for the SESSION from the HPTYPE. +Do not actually start any process. +HPTYPE is the result of calling `'haskell-process-type`' function." + (let ((session-name (haskell-session-name session))) + (cl-ecase hptype + ('ghci + (append (list (format "Starting inferior GHCi process %s ..." + haskell-process-path-ghci) + session-name + nil) + (apply haskell-process-wrapper-function + (list + (append (haskell-process-path-to-list haskell-process-path-ghci) + haskell-process-args-ghci))))) + ('cabal-new-repl + (append (list (format "Starting inferior `cabal new-repl' process using %s ..." + haskell-process-path-cabal) + session-name + nil) + (apply haskell-process-wrapper-function + (list + (append + (haskell-process-path-to-list haskell-process-path-cabal) + (list "new-repl") + haskell-process-args-cabal-new-repl + (let ((target (haskell-session-target session))) + (if target (list target) nil))))))) + ('cabal-repl + (append (list (format "Starting inferior `cabal repl' process using %s ..." + haskell-process-path-cabal) + session-name + nil) + (apply haskell-process-wrapper-function + (list + (append + (haskell-process-path-to-list haskell-process-path-cabal) + (list "repl") + haskell-process-args-cabal-repl + (let ((target (haskell-session-target session))) + (if target (list target) nil))))))) + ('stack-ghci + (append (list (format "Starting inferior stack GHCi process using %s" haskell-process-path-stack) + session-name + nil) + (apply haskell-process-wrapper-function + (list + (append + (haskell-process-path-to-list haskell-process-path-stack) + (list "ghci") + (let ((target (haskell-session-target session))) + (if target (list target) nil)) + haskell-process-args-stack-ghci)))))))) + +(defun haskell-process-path-to-list (path) + "Convert a path (which may be a string or a list) to a list." + (if (stringp path) + (list path) + path)) + +(defun haskell-process-make (name) + "Make an inferior Haskell process." + (list (cons 'name name))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Process communication + +(defun haskell-process-sentinel (proc event) + "The sentinel for the process pipe." + (let ((session (haskell-process-project-by-proc proc))) + (when session + (let* ((process (haskell-session-process session))) + (unless (haskell-process-restarting process) + (haskell-process-log + (propertize (format "Event: %S\n" event) + 'face '((:weight bold)))) + (haskell-process-log + (propertize "Process reset.\n" + 'face 'font-lock-comment-face)) + (run-hook-with-args 'haskell-process-ended-functions process)))))) + +(defun haskell-process-filter (proc response) + "The filter for the process pipe." + (let ((i 0)) + (cl-loop for line in (split-string response "\n") + do (haskell-process-log + (concat (if (= i 0) + (propertize "<- " 'face 'font-lock-comment-face) + " ") + (propertize line 'face 'haskell-interactive-face-compile-warning))) + do (setq i (1+ i)))) + (let ((session (haskell-process-project-by-proc proc))) + (when session + (if (haskell-process-cmd (haskell-session-process session)) + (haskell-process-collect session + response + (haskell-session-process session)))))) + +(defun haskell-process-log (msg) + "Effective append MSG to the process log (if enabled)." + (when haskell-process-log + (let* ((append-to (get-buffer-create "*haskell-process-log*"))) + (with-current-buffer append-to + ;; point should follow insertion so that it stays at the end + ;; of the buffer + (setq-local window-point-insertion-type t) + (let ((buffer-read-only nil)) + (insert msg "\n")))))) + +(defun haskell-process-project-by-proc (proc) + "Find project by process." + (cl-find-if (lambda (project) + (string= (haskell-session-name project) + (process-name proc))) + haskell-sessions)) + +(defun haskell-process-collect (_session response process) + "Collect input for the response until receives a prompt." + (haskell-process-set-response process + (concat (haskell-process-response process) response)) + (while (haskell-process-live-updates process)) + (when (string-match haskell-process-prompt-regex + (haskell-process-response process)) + (haskell-command-exec-complete + (haskell-process-cmd process) + (replace-regexp-in-string + haskell-process-prompt-regex + "" + (haskell-process-response process))) + (haskell-process-reset process) + (haskell-process-trigger-queue process))) + +(defun haskell-process-reset (process) + "Reset the process's state, ready for the next send/reply." + (progn (haskell-process-set-response-cursor process 0) + (haskell-process-set-response process "") + (haskell-process-set-cmd process nil))) + +(defun haskell-process-consume (process regex) + "Consume a regex from the response and move the cursor along if succeed." + (when (string-match regex + (haskell-process-response process) + (haskell-process-response-cursor process)) + (haskell-process-set-response-cursor process (match-end 0)) + t)) + +(defun haskell-process-send-string (process string) + "Try to send a string to the process's process. Ask to restart if it's not running." + (let ((child (haskell-process-process process))) + (if (equal 'run (process-status child)) + (let ((out (concat string "\n"))) + (let ((i 0)) + (cl-loop for line in (split-string out "\n") + do (unless (string-equal "" line) + (haskell-process-log + (concat (if (= i 0) + (propertize "-> " 'face 'font-lock-comment-face) + " ") + (propertize line 'face 'font-lock-string-face)))) + do (setq i (1+ i)))) + (process-send-string child out)) + (unless (haskell-process-restarting process) + (run-hook-with-args 'haskell-process-ended-functions process))))) + +(defun haskell-process-live-updates (process) + "Process live updates." + (haskell-command-exec-live (haskell-process-cmd process) + (haskell-process-response process))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Making commands + +(defun haskell-process-queue-without-filters (process line) + "Queue LINE to be sent to PROCESS without bothering to look at +the response." + (haskell-process-queue-command + process + (make-haskell-command + :state (cons process line) + :go (lambda (state) + (haskell-process-send-string (car state) + (cdr state)))))) + + +(defun haskell-process-queue-command (process command) + "Add a command to the process command queue." + (haskell-process-cmd-queue-add process command) + (haskell-process-trigger-queue process)) + +(defun haskell-process-trigger-queue (process) + "Trigger the next command in the queue to be ran if there is no current command." + (if (and (haskell-process-process process) + (process-live-p (haskell-process-process process))) + (unless (haskell-process-cmd process) + (let ((cmd (haskell-process-cmd-queue-pop process))) + (when cmd + (haskell-process-set-cmd process cmd) + (haskell-command-exec-go cmd)))) + (progn (haskell-process-reset process) + (haskell-process-set process 'command-queue nil) + (run-hook-with-args 'haskell-process-ended-functions process)))) + +(defun haskell-process-queue-flushed-p (process) + "Return t if command queue has been completely processed." + (not (or (haskell-process-cmd-queue process) + (haskell-process-cmd process)))) + +(defun haskell-process-queue-flush (process) + "Block till PROCESS' command queue has been completely processed. +This uses `accept-process-output' internally." + (while (not (haskell-process-queue-flushed-p process)) + (haskell-process-trigger-queue process) + (accept-process-output (haskell-process-process process) 1))) + +(defun haskell-process-queue-sync-request (process reqstr) + "Queue submitting REQSTR to PROCESS and return response blockingly." + (let ((cmd (make-haskell-command + :state (cons nil process) + :go `(lambda (s) (haskell-process-send-string (cdr s) ,reqstr)) + :complete 'setcar))) + (haskell-process-queue-command process cmd) + (haskell-process-queue-flush process) + (car-safe (haskell-command-state cmd)))) + +(defun haskell-process-get-repl-completions (process inputstr &optional limit) + "Query PROCESS with `:complete repl ...' for INPUTSTR. +Give optional LIMIT arg to limit completion candidates count, +zero, negative values, and nil means all possible completions. +Returns NIL when no completions found." + (let* ((mlimit (if (and limit (> limit 0)) + (concat " " (number-to-string limit) " ") + " ")) + (reqstr (concat ":complete repl" + mlimit + (haskell-string-literal-encode inputstr))) + (rawstr (haskell-process-queue-sync-request process reqstr)) + (response-status (haskell-utils-repl-response-error-status rawstr))) + (if (eq 'unknown-command response-status) + (error + "GHCi lacks `:complete' support (try installing GHC 7.8+ or ghci-ng)") + (when rawstr + ;; parse REPL response if any + (let* ((s1 (split-string rawstr "\r?\n" t)) + (cs (mapcar #'haskell-string-literal-decode (cdr s1))) + (h0 (car s1))) ;; "<limit count> <all count> <unused string>" + (unless (string-match + "\\`\\([0-9]+\\) \\([0-9]+\\) \\(\".*\"\\)\\'" + h0) + (error "Invalid `:complete' response")) + (let ((cnt1 (match-string 1 h0)) + (h1 (haskell-string-literal-decode (match-string 3 h0)))) + (unless (= (string-to-number cnt1) (length cs)) + (error "Lengths inconsistent in `:complete' reponse")) + (cons h1 cs))))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Accessing the process + +(defun haskell-process-get (process key) + "Get the PROCESS's KEY value. +Returns nil if KEY not set." + (cdr (assq key process))) + +(defun haskell-process-set (process key value) + "Set the PROCESS's KEY to VALUE. +Returns newly set VALUE." + (if process + (let ((cell (assq key process))) + (if cell + (setcdr cell value) ; modify cell in-place + (setcdr process (cons (cons key value) (cdr process))) ; new cell + value)) + (display-warning 'haskell-interactive + "`haskell-process-set' called with nil process"))) + +;; Wrappers using haskell-process-{get,set} + +(defun haskell-process-set-sent-stdin (p v) + "We've sent stdin, so let's not clear the output at the end." + (haskell-process-set p 'sent-stdin v)) + +(defun haskell-process-sent-stdin-p (p) + "Did we send any stdin to the process during evaluation?" + (haskell-process-get p 'sent-stdin)) + +(defun haskell-process-set-suggested-imports (p v) + "Remember what imports have been suggested, to avoid +re-asking about the same imports." + (haskell-process-set p 'suggested-imported v)) + +(defun haskell-process-suggested-imports (p) + "Get what modules have already been suggested and accepted." + (haskell-process-get p 'suggested-imported)) + +(defun haskell-process-set-evaluating (p v) + "Set status of evaluating to be on/off." + (haskell-process-set p 'evaluating v)) + +(defun haskell-process-evaluating-p (p) + "Get status of evaluating (on/off)." + (haskell-process-get p 'evaluating)) + +(defun haskell-process-set-process (p v) + "Set the process's inferior process." + (haskell-process-set p 'inferior-process v)) + +(defun haskell-process-process (p) + "Get the process child." + (haskell-process-get p 'inferior-process)) + +(defun haskell-process-name (p) + "Get the process name." + (haskell-process-get p 'name)) + +(defun haskell-process-cmd (p) + "Get the process's current command. +Return nil if no current command." + (haskell-process-get p 'current-command)) + +(defun haskell-process-set-cmd (p v) + "Set the process's current command." + (haskell-process-set-evaluating p nil) + (haskell-process-set-sent-stdin p nil) + (haskell-process-set-suggested-imports p nil) + (haskell-process-set p 'current-command v)) + +(defun haskell-process-response (p) + "Get the process's current response." + (haskell-process-get p 'current-response)) + +(defun haskell-process-session (p) + "Get the process's current session." + (haskell-process-get p 'session)) + +(defun haskell-process-set-response (p v) + "Set the process's current response." + (haskell-process-set p 'current-response v)) + +(defun haskell-process-set-session (p v) + "Set the process's current session." + (haskell-process-set p 'session v)) + +(defun haskell-process-response-cursor (p) + "Get the process's current response cursor." + (haskell-process-get p 'current-response-cursor)) + +(defun haskell-process-set-response-cursor (p v) + "Set the process's response cursor." + (haskell-process-set p 'current-response-cursor v)) + +;; low-level command queue operations + +(defun haskell-process-restarting (process) + "Is the PROCESS restarting?" + (haskell-process-get process 'is-restarting)) + +(defun haskell-process-cmd-queue (process) + "Get the PROCESS' command queue. +New entries get added to the end of the list. Use +`haskell-process-cmd-queue-add' and +`haskell-process-cmd-queue-pop' to modify the command queue." + (haskell-process-get process 'command-queue)) + +(defun haskell-process-cmd-queue-add (process cmd) + "Add CMD to end of PROCESS's command queue." + (cl-check-type cmd haskell-command) + (haskell-process-set process + 'command-queue + (append (haskell-process-cmd-queue process) + (list cmd)))) + +(defun haskell-process-cmd-queue-pop (process) + "Pop the PROCESS' next entry from command queue. +Returns nil if queue is empty." + (let ((queue (haskell-process-cmd-queue process))) + (when queue + (haskell-process-set process 'command-queue (cdr queue)) + (car queue)))) + + +(defun haskell-process-unignore-file (session file) + " + +Note to Windows Emacs hackers: + +chmod is how to change the mode of files in POSIX +systems. This will not work on your operating +system. + +There is a command a bit like chmod called \"Calcs\" +that you can try using here: + +http://technet.microsoft.com/en-us/library/bb490872.aspx + +If it works, you can submit a patch to this +function and remove this comment. +" + (shell-command (read-from-minibuffer "Permissions command: " + (concat "chmod 700 " + file))) + (haskell-session-modify + session + 'ignored-files + (lambda (files) + (cl-remove-if (lambda (path) + (string= path file)) + files)))) + +(defun haskell-command-exec-go (command) + "Call the command's go function." + (let ((go-func (haskell-command-go command))) + (when go-func + (funcall go-func (haskell-command-state command))))) + +(defun haskell-command-exec-complete (command response) + "Call the command's complete function." + (let ((comp-func (haskell-command-complete command))) + (when comp-func + (condition-case-unless-debug e + (funcall comp-func + (haskell-command-state command) + response) + (quit (message "Quit")) + (error (message "Haskell process command errored with: %S" e)))))) + +(defun haskell-command-exec-live (command response) + "Trigger the command's live updates callback." + (let ((live-func (haskell-command-live command))) + (when live-func + (funcall live-func + (haskell-command-state command) + response)))) + +(provide 'haskell-process) + +;;; haskell-process.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-process.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-process.elc new file mode 100644 index 000000000000..69bfb8a3774d --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-process.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-repl.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-repl.el new file mode 100644 index 000000000000..fe811ee1ddd7 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-repl.el @@ -0,0 +1,124 @@ +;;; haskell-repl.el --- REPL evaluation -*- 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 <http://www.gnu.org/licenses/>. + +;;; Code: + +(require 'cl-lib) +(require 'haskell-interactive-mode) +(require 'haskell-collapse) + +(defun haskell-interactive-handle-expr () + "Handle an inputted expression at the REPL." + (let ((expr (haskell-interactive-mode-input))) + (if (string= "" (replace-regexp-in-string " " "" expr)) + ;; Just make a new prompt on space-only input + (progn + (goto-char (point-max)) + (insert "\n") + (haskell-interactive-mode-prompt)) + (when (haskell-interactive-at-prompt) + (cond + ;; If already evaluating, then the user is trying to send + ;; input to the REPL during evaluation. Most likely in + ;; response to a getLine-like function. + ((and (haskell-process-evaluating-p (haskell-interactive-process)) + (= (line-end-position) (point-max))) + (goto-char (point-max)) + (let ((process (haskell-interactive-process)) + (string (buffer-substring-no-properties + haskell-interactive-mode-result-end + (point)))) + ;; here we need to go to end of line again as evil-mode + ;; might have managed to put us one char back + (goto-char (point-max)) + (insert "\n") + ;; Bring the marker forward + (setq haskell-interactive-mode-result-end + (point-max)) + (haskell-process-set-sent-stdin process t) + (haskell-process-send-string process string))) + ;; Otherwise we start a normal evaluation call. + (t (setq haskell-interactive-mode-old-prompt-start + (copy-marker haskell-interactive-mode-prompt-start)) + (set-marker haskell-interactive-mode-prompt-start (point-max)) + (haskell-interactive-mode-history-add expr) + (haskell-interactive-mode-do-expr expr))))))) + +(defun haskell-interactive-mode-do-expr (expr) + (cond + ((string-match "^:present " expr) + (haskell-interactive-mode-do-presentation (replace-regexp-in-string "^:present " "" expr))) + (t + (haskell-interactive-mode-run-expr expr)))) + +(defun haskell-interactive-mode-run-expr (expr) + "Run the given expression." + (let ((session (haskell-interactive-session)) + (process (haskell-interactive-process))) + (haskell-process-queue-command + process + (make-haskell-command + :state (list session process expr 0) + :go (lambda (state) + (goto-char (point-max)) + (insert "\n") + (setq haskell-interactive-mode-result-end + (point-max)) + (haskell-process-send-string (cadr state) + (haskell-interactive-mode-multi-line (cl-caddr state))) + (haskell-process-set-evaluating (cadr state) t)) + :live (lambda (state buffer) + (unless (and (string-prefix-p ":q" (cl-caddr state)) + (string-prefix-p (cl-caddr state) ":quit")) + (let* ((cursor (cl-cadddr state)) + (next (replace-regexp-in-string + haskell-process-prompt-regex + "" + (substring buffer cursor)))) + (haskell-interactive-mode-eval-result (car state) next) + (setf (cl-cdddr state) (list (length buffer))) + nil))) + :complete + (lambda (state response) + (haskell-process-set-evaluating (cadr state) nil) + (unless (haskell-interactive-mode-trigger-compile-error state response) + (haskell-interactive-mode-expr-result state response))))))) + +(defun haskell-interactive-mode-expr-result (state response) + "Print the result of evaluating the expression." + (let ((response + (with-temp-buffer + (insert response) + (haskell-interactive-mode-handle-h) + (buffer-string)))) + (when haskell-interactive-mode-eval-mode + (unless (haskell-process-sent-stdin-p (cadr state)) + (haskell-interactive-mode-eval-as-mode (car state) response)))) + (haskell-interactive-mode-prompt (car state))) + +(defun haskell-interactive-mode-eval-as-mode (session text) + "Insert TEXT font-locked according to `haskell-interactive-mode-eval-mode'." + (with-current-buffer (haskell-session-interactive-buffer session) + (let ((inhibit-read-only t)) + (delete-region (1+ haskell-interactive-mode-prompt-start) (point)) + (goto-char (point-max)) + (insert (haskell-fontify-as-mode text + haskell-interactive-mode-eval-mode)) + (when haskell-interactive-mode-collapse + (haskell-hide-toggle))))) + +(provide 'haskell-repl) diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-repl.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-repl.elc new file mode 100644 index 000000000000..c7d5f85c6549 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-repl.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-sandbox.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-sandbox.el new file mode 100644 index 000000000000..ba605fd66cc8 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-sandbox.el @@ -0,0 +1,41 @@ +;;; haskell-sandbox.el --- Support for sandboxes -*- 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 <http://www.gnu.org/licenses/>. + +;;; Code: + +(require 'cl-lib) +(require 'haskell-session) + +(defun haskell-sandbox-path (session) + "If there is a haskell-session, return the path to the usual sandbox location." + (concat (haskell-session-cabal-dir session) + "/.cabal-sandbox")) + +(defun haskell-sandbox-exists-p (session) + "Is there a cabal sandbox?" + (file-exists-p (haskell-sandbox-path session))) + +(defun haskell-sandbox-pkgdb (session) + "Get the package database of the sandbox." + (let* ((files (directory-files (haskell-sandbox-path session))) + (dir (car (cl-remove-if-not (lambda (file) + (string-match ".conf.d$" file)) + files)))) + (when dir + (concat (haskell-sandbox-path session) "/" dir)))) + +(provide 'haskell-sandbox) diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-sandbox.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-sandbox.elc new file mode 100644 index 000000000000..3fb5781eaf78 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-sandbox.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-session.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-session.el new file mode 100644 index 000000000000..2c5344d13f03 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-session.el @@ -0,0 +1,227 @@ +;;; haskell-session.el --- Haskell sessions -*- lexical-binding: t -*- + +;; Copyright (C) 2011-2012 Chris Done + +;; Author: Chris Done <chrisdone@gmail.com> + +;; This file is not part of GNU Emacs. + +;; 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 GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;;; Todo: + +;;; Code: + +(require 'cl-lib) +(require 'haskell-cabal) +(require 'haskell-customize) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Globals + +;; Used internally +(defvar-local haskell-session nil) + +(defvar haskell-sessions (list) + "All Haskell sessions in the Emacs session.") + +(defun haskell-session-tags-filename (session) + "Get the filename for the TAGS file." + (concat (haskell-session-cabal-dir session) "/TAGS")) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Finding/clearing the session + +;;;###autoload +(defun haskell-session-maybe () + "Maybe get the Haskell session, return nil if there isn't one." + (if (default-boundp 'haskell-session) + haskell-session + (setq haskell-session nil))) + +(defun haskell-session-from-buffer () + "Get the session based on the buffer." + (when (and (buffer-file-name) + (consp haskell-sessions)) + (cl-reduce (lambda (acc a) + (let ((dir (haskell-session-get a 'cabal-dir))) + (if dir + (if (string-prefix-p dir + (file-name-directory (buffer-file-name))) + (if acc + (if (and + (> (length (haskell-session-get a 'cabal-dir)) + (length (haskell-session-get acc 'cabal-dir)))) + a + acc) + a) + acc) + acc))) + haskell-sessions + :initial-value nil))) + +(defun haskell-session-default-name () + "Generate a default project name for the new project prompt." + (let ((file (haskell-cabal-find-file))) + (or (when file + (downcase (file-name-sans-extension + (file-name-nondirectory file)))) + "haskell"))) + +(defun haskell-session-assign (session) + "Assing current buffer to SESSION. + +This could be helpful for temporary or auxiliary buffers such as +presentation mode buffers (e.g. in case when session is killed +with all relevant buffers)." + (setq-local haskell-session session)) + +(defun haskell-session-choose () + "Find a session by choosing from a list of the current sessions." + (when haskell-sessions + (let* ((session-name (funcall haskell-completing-read-function + "Choose Haskell session: " + (cl-remove-if (lambda (name) + (and haskell-session + (string= (haskell-session-name haskell-session) + name))) + (mapcar 'haskell-session-name haskell-sessions)))) + (session (cl-find-if (lambda (session) + (string= (haskell-session-name session) + session-name)) + haskell-sessions))) + session))) + +(defun haskell-session-clear () + "Clear the buffer of any Haskell session choice." + (setq-local haskell-session nil)) + +(defun haskell-session-lookup (name) + "Get the session by name." + (cl-remove-if-not (lambda (s) + (string= name (haskell-session-name s))) + haskell-sessions)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Session modules + +(defun haskell-session-strip-dir (session file) + "Strip the load dir from the file path." + (let ((cur-dir (haskell-session-current-dir session))) + (if (> (length file) (length cur-dir)) + (if (string= (substring file 0 (length cur-dir)) + cur-dir) + (replace-regexp-in-string + "^[/\\]" "" + (substring file + (length cur-dir))) + file) + file))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Accessing the session + +(defun haskell-session-current-dir (s) + "Get the session current directory." + (let ((dir (haskell-session-get s 'current-dir))) + (or dir + (error "No current directory.")))) + +(defun haskell-session-name (s) + "Get the session name." + (haskell-session-get s 'name)) + +(defun haskell-session-target (s) + "Get the session build target. +If `haskell-process-load-or-reload-prompt' is nil, accept `default'." + (let* ((maybe-target (haskell-session-get s 'target)) + (target (if maybe-target maybe-target + (let ((new-target + (if haskell-process-load-or-reload-prompt + (read-string "build target (empty for default):") + ""))) + (haskell-session-set-target s new-target))))) + (if (not (string= target "")) target nil))) + +(defun haskell-session-set-target (s target) + "Set the session build target." + (haskell-session-set s 'target target)) + +(defun haskell-session-set-interactive-buffer (s v) + "Set the session interactive buffer." + (haskell-session-set s 'interactive-buffer v)) + +(defun haskell-session-set-process (s v) + "Set the session process." + (haskell-session-set s 'process v)) + +;;;###autoload +(defun haskell-session-process (s) + "Get the session process." + (haskell-session-get s 'process)) + +(defun haskell-session-set-cabal-dir (s v) + "Set the session cabal-dir." + (let ((true-path (file-truename v))) + (haskell-session-set s 'cabal-dir true-path) + (haskell-session-set-cabal-checksum s true-path))) + +(defun haskell-session-set-current-dir (s v) + "Set the session current directory." + (let ((true-path (file-truename v))) + (haskell-session-set s 'current-dir true-path))) + +(defun haskell-session-set-cabal-checksum (s cabal-dir) + "Set the session checksum of .cabal files" + (haskell-session-set s 'cabal-checksum + (haskell-cabal-compute-checksum cabal-dir))) + +(defun haskell-session-cabal-dir (s) + "Get the session cabal-dir." + (or (haskell-session-get s 'cabal-dir) + (let ((set-dir (haskell-cabal-get-dir (not haskell-process-load-or-reload-prompt)))) + (if set-dir + (progn (haskell-session-set-cabal-dir s set-dir) + set-dir) + (haskell-session-cabal-dir s))))) + +(defun haskell-session-modify (session key update) + "Update the value at KEY in SESSION with UPDATE." + (haskell-session-set + session + key + (funcall update + (haskell-session-get session key)))) + +(defun haskell-session-get (session key) + "Get the SESSION's KEY value. +Returns nil if KEY not set." + (cdr (assq key session))) + +(defun haskell-session-set (session key value) + "Set the SESSION's KEY to VALUE. +Returns newly set VALUE." + (let ((cell (assq key session))) + (if cell + (setcdr cell value) ; modify cell in-place + (setcdr session (cons (cons key value) (cdr session))) ; new cell + value))) + +(provide 'haskell-session) + +;;; haskell-session.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-session.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-session.elc new file mode 100644 index 000000000000..70767fe3cfaf --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-session.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-sort-imports.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-sort-imports.el new file mode 100644 index 000000000000..bd676dc73ed0 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-sort-imports.el @@ -0,0 +1,129 @@ +;;; haskell-sort-imports.el --- Sort the list of Haskell imports at the point alphabetically -*- lexical-binding: t -*- + +;; Copyright (C) 2010 Chris Done + +;; Author: Chris Done <chrisdone@gmail.com> + +;; This file is not part of GNU Emacs. + +;; This program 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 of +;; the License, or (at your option) any later version. + +;; This program 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 +;; <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; If the region is active it sorts the imports within the +;; region. + +;; This will align and sort the columns of the current import +;; list. It's more or less the coolest thing on the planet. + +;;; Code: + +(require 'cl-lib) + +(defvar haskell-sort-imports-regexp + (concat "^import[ ]+" + "\\(qualified \\)?" + "[ ]*\\(\"[^\"]*\" \\)?" + "[ ]*\\([A-Za-z0-9_.']*.*\\)")) + +;;;###autoload +(defun haskell-sort-imports () + "Sort the import list at point. It sorts the current group +i.e. an import list separated by blank lines on either side. + +If the region is active, it will restrict the imports to sort +within that region." + (interactive) + (when (haskell-sort-imports-at-import) + (let* ((points (haskell-sort-imports-decl-points)) + (current-string (buffer-substring-no-properties (car points) + (cdr points))) + (current-offset (- (point) (car points)))) + (if (region-active-p) + (progn (goto-char (region-beginning)) + (haskell-sort-imports-goto-import-start)) + (haskell-sort-imports-goto-group-start)) + (let* ((start (point)) + (imports (haskell-sort-imports-collect-imports)) + (sorted (sort (cl-copy-list imports) + (lambda (a b) + (string< (haskell-sort-imports-normalize a) + (haskell-sort-imports-normalize b)))))) + (when (not (equal imports sorted)) + (delete-region start (point)) + (mapc (lambda (import) (insert import "\n")) sorted)) + (goto-char start) + (when (search-forward current-string nil t 1) + (forward-char (- (length current-string))) + (forward-char current-offset)))))) + +(defun haskell-sort-imports-normalize (i) + "Normalize an import, if possible, so that it can be sorted." + (if (string-match haskell-sort-imports-regexp + i) + (match-string 3 i) + i)) + +(defun haskell-sort-imports-collect-imports () + (let ((imports (list))) + (while (looking-at "import") + (let* ((points (haskell-sort-imports-decl-points)) + (string (buffer-substring-no-properties (car points) + (cdr points)))) + (goto-char (min (1+ (cdr points)) + (point-max))) + (setq imports (cons string imports)))) + (reverse (delq nil (delete-dups imports))))) + +(defun haskell-sort-imports-goto-group-start () + "Go to the start of the import group." + (or (and (search-backward "\n\n" nil t 1) + (goto-char (+ 2 (line-end-position)))) + (when (search-backward-regexp "^module " nil t 1) + (goto-char (1+ (line-end-position)))) + (goto-char (point-min)))) + +(defun haskell-sort-imports-at-import () + "Are we at an import?" + (save-excursion + (haskell-sort-imports-goto-import-start) + (looking-at "import"))) + +(defun haskell-sort-imports-goto-import-start () + "Go to the start of the import." + (goto-char (car (haskell-sort-imports-decl-points)))) + +(defun haskell-sort-imports-decl-points () + "Get the points of the declaration." + (save-excursion + (let ((start (or (progn (goto-char (line-end-position)) + (search-backward-regexp "^[^ \n]" nil t 1) + (unless (or (looking-at "^-}$") + (looking-at "^{-$")) + (point))) + 0)) + (end (progn (goto-char (1+ (point))) + (or (when (search-forward-regexp "[\n]+[^ \n]" nil t 1) + (forward-char -1) + (search-backward-regexp "[^\n ]" nil t) + (line-end-position)) + (when (search-forward-regexp "\n" nil t 1) + (1- (point))) + (point-max))))) + (cons start end)))) + +(provide 'haskell-sort-imports) + +;;; haskell-sort-imports.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-sort-imports.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-sort-imports.elc new file mode 100644 index 000000000000..1b5fe2e25324 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-sort-imports.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-string.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-string.el new file mode 100644 index 000000000000..1427aa31991b --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-string.el @@ -0,0 +1,219 @@ +;;; haskell-string.el --- Haskell related string utilities -*- lexical-binding: t -*- + +;; Copyright (C) 2013 Herbert Valerio Riedel + +;; Author: Herbert Valerio Riedel <hvr@gnu.org> + +;; This file is not part of GNU Emacs. + +;; 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 of the License, 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;;; Todo: + +;; - write ERT tests + +;;; Code: + +(require 'cl-lib) + +(defun haskell-string-trim (string) + "Remove whitespace around STRING. + +A Whitespace character is defined in the Haskell Report as follows + + whitechar -> newline | vertab | space | tab | uniWhite + newline -> return linefeed | return | linefeed | formfeed + uniWhite -> any Unicode character defined as whitespace + +Note: The implementation currently only supports ASCII + white-space characters, i.e. the implemention doesn't + consider uniWhite." + + (let ((s1 (if (string-match "[\t\n\v\f\r ]+\\'" string) (replace-match "" t t string) string))) + (if (string-match "\\`[\t\n\v\f\r ]+" s1) (replace-match "" t t s1) s1))) + +(defun haskell-string-only-spaces-p (string) + "Return t if STRING contains only whitespace (or is empty)." + (string= "" (haskell-string-trim string))) + +(defun haskell-string-take (string n) + "Return (up to) N character length prefix of STRING." + (substring string 0 (min (length string) n))) + +(defconst haskell-string-literal-encode-ascii-array + [ "\\NUL" "\\SOH" "\\STX" "\\ETX" "\\EOT" "\\ENQ" "\\ACK" "\\a" "\\b" "\\t" "\\n" "\\v" "\\f" "\\r" "\\SO" "\\SI" "\\DLE" "\\DC1" "\\DC2" "\\DC3" "\\DC4" "\\NAK" "\\SYN" "\\ETB" "\\CAN" "\\EM" "\\SUB" "\\ESC" "\\FS" "\\GS" "\\RS" "\\US" " " "!" "\\\"" "#" "$" "%" "&" "'" "(" ")" "*" "+" "," "-" "." "/" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" ":" ";" "<" "=" ">" "?" "@" "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "[" "\\\\" "]" "^" "_" "`" "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z" "{" "|" "}" "~" "\\DEL" ] + "Array of encodings for 7-bit ASCII character points indexed by ASCII value.") + +(defun haskell-string-literal-encode (str &optional no-quotes) + "Encode STR according Haskell escape rules using 7-bit ASCII representation. + +The serialization has been implemented to closely match the +behaviour of GHC's Show instance for Strings. + +If NO-QUOTES is non-nil, omit wrapping result in quotes. + +This is the dual operation to `haskell-string-literal-decode'." + + (let ((lastc -1)) + (let ((encode (lambda (c) + (let ((lc lastc)) + (setq lastc c) + (if (>= c 128) ;; if non-ASCII code point + (format "\\%d" c) + ;; else, for ASCII code points + (if (or (and (= lc 14) (= c ?H)) ;; "\SO\&H" + (and (>= lc 128) (>= c ?0) (<= c ?9))) ;; "\123\&4" + (concat "\\&" (aref haskell-string-literal-encode-ascii-array c)) + (aref haskell-string-literal-encode-ascii-array c) + )))))) + + (if no-quotes + (mapconcat encode str "") + (concat "\"" (mapconcat encode str "") "\""))))) + +(defconst haskell-string-literal-escapes-regexp + (concat "[\\]\\(?:" + (regexp-opt (append + (mapcar (lambda (c) (format "%c" c)) + "abfnrtv\\\"'&") ;; "charesc" escape sequences + (mapcar (lambda (c) (format "^%c" c)) + "ABCDEFGHIJKLMNOPQRSTUVWXYZ@[\\]^_") ;; "cntrl" escape sequences + (mapcar (lambda (s) (format "%s" s)) + (split-string "NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR + SO SI DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC + FS GS RS US SP DEL")))) ;; "ascii" (w\o "cntrl") escape sequences + "\\|" "[\t\n\v\f\r ]+[\\]" ;; whitespace gaps + "\\|" "[0-9]+" ;; decimal escape sequence + "\\|" "o[0-7]+" ;; octal escape sequence + "\\|" "x[0-9a-f]+" ;; hex escape sequence + "\\)?") ;; everything else is an invalid escape sequence + "Regexp for matching escape codes in string literals. +See Haskell Report Sect 2.6, +URL `http://www.haskell.org/onlinereport/haskell2010/haskellch2.html#x7-200002.6', +for more details.") + +(defconst haskell-string-literal-decode1-table + (let ((h (make-hash-table :test 'equal))) + (mapc (lambda (c) (puthash (concat "\\" (car c)) (cdr c) h)) + '(;; ascii-escapes + ("NUL" . "\x00") ("SOH" . "\x01") ("STX" . "\x02") ("ETX" . "\x03") ("EOT" . "\x04") ("ENQ" . "\x05") + ("ACK" . "\x06") ("BEL" . "\x07") ("BS" . "\x08") ("HT" . "\x09") ("LF" . "\x0a") ("VT" . "\x0b") + ("FF" . "\x0c") ("CR" . "\x0d") ("SO" . "\x0e") ("SI" . "\x0f") ("DLE" . "\x10") ("DC1" . "\x11") + ("DC2" . "\x12") ("DC3" . "\x13") ("DC4" . "\x14") ("NAK" . "\x15") ("SYN" . "\x16") ("ETB" . "\x17") + ("CAN" . "\x18") ("EM" . "\x19") ("SUB" . "\x1a") ("ESC" . "\x1b") ("FS" . "\x1c") ("GS" . "\x1d") + ("RS" . "\x1e") ("US" . "\x1f") ("SP" . "\x20") ("DEL" . "\x7f" ) + ;; C-compatible single-char escape sequences + ("a" . "\x07") ("b" . "\x08") ("f" . "\x0c") ("n" . "\x0a") ("r" . "\x0d") ("t" . "\x09") ("v" . "\x0b") + ;; trivial escapes + ("\\" . "\\") ("\"" . "\"") ("'" . "'") + ;; "empty" escape + ("&" . ""))) + h) + "Hash table containing irregular escape sequences and their decoded strings. +Used by `haskell-string-literal-decode1'.") + +(defun haskell-string-literal-decode1 (l) + "Decode a single string literal escape sequence. +L must contain exactly one escape sequence. +This is an internal function used by `haskell-string-literal-decode'." + (let ((case-fold-search nil)) + (cond + ((gethash l haskell-string-literal-decode1-table)) + ((string-match "\\`[\\][0-9]+\\'" l) (char-to-string (string-to-number (substring l 1) 10))) + ((string-match "\\`[\\]x[[:xdigit:]]+\\'" l) (char-to-string (string-to-number (substring l 2) 16))) + ((string-match "\\`[\\]o[0-7]+\\'" l) (char-to-string (string-to-number (substring l 2) 8))) + ((string-match "\\`[\\]\\^[@-_]\\'" l) (char-to-string (- (aref l 2) ?@))) ;; "cntrl" escapes + ((string-match "\\`[\\][\t\n\v\f\r ]+[\\]\\'" l) "") ;; whitespace gap + (t (error "Invalid escape sequence"))))) + +(defun haskell-string-literal-decode (estr &optional no-quotes) + "Decode a Haskell string-literal. +If NO-QUOTES is nil, ESTR must be surrounded by quotes. + +This is the dual operation to `haskell-string-literal-encode'." + (if (and (not no-quotes) + (string-match-p "\\`\"[^\\\"[:cntrl:]]*\"\\'" estr)) + (substring estr 1 -1) ;; optimized fast-path for trivial strings + (let ((s (if no-quotes ;; else: do general decoding + estr + (if (string-match-p "\\`\".*\"\\'" estr) + (substring estr 1 -1) + (error "String literal must be delimited by quotes")))) + (case-fold-search nil)) + (replace-regexp-in-string haskell-string-literal-escapes-regexp #'haskell-string-literal-decode1 s t t)))) + +(defun haskell-string-ellipsize (string n) + "Return STRING truncated to (at most) N characters. +If truncation occured, last character in string is replaced by `…'. +See also `haskell-string-take'." + (cond + ((<= (length string) n) string) ;; no truncation needed + ((< n 1) "") + (t (concat (substring string 0 (1- n)) "…")))) + +(defun haskell-string-chomp (str) + "Chomp leading and tailing whitespace from STR." + (while (string-match "\\`\n+\\|^\\s-+\\|\\s-+$\\|\n+\\'" + str) + (setq str (replace-match "" t t str))) + str) + +(defun haskell-string-split-to-lines (str) + "Split STR to lines and return a list of strings with preceeding and +succeding space removed." + (when (stringp str) + (cl-mapcar #'haskell-string-chomp (split-string str "\n")))) + +(defun haskell-string-trim-prefix (prefix str) + "If PREFIX is prefix of STR, the string is trimmed." + (when (and (stringp prefix) + (stringp str)) + (if (string-prefix-p prefix str) + (substring str (length prefix))))) + +(defun haskell-string-trim-suffix (suffix str) + "If SUFFIX is suffix of STR, the string is trimmed." + (when (and (stringp suffix) + (stringp str)) + (if (string-suffix-p suffix str) + (substring str 0 (* -1 (length suffix)))))) + +(defun haskell-string-drop-qualifier (ident) + "Drop qualifier from given identifier IDENT. + +If the identifier is not qualified return it unchanged." + (or (and (string-match "^\\([^.]*\\.\\)*\\(?1:[^.]+\\)$" ident) + (match-string 1 ident)) + ident)) + +(defun haskell-mode-message-line (str) + "Echo STR in mini-buffer. +Given string is shrinken to single line, multiple lines just +disturbs the programmer." + (message "%s" (haskell-mode-one-line str (frame-width)))) + +(defun haskell-mode-one-line (str &optional width) + "Try to fit STR as much as possible on one line according to given WIDTH." + (unless width + (setq width (length str))) + (let* ((long-line (replace-regexp-in-string "\n" " " str)) + (condensed (replace-regexp-in-string + " +" " " (haskell-string-trim long-line)))) + (truncate-string-to-width condensed width nil nil "…"))) + +(provide 'haskell-string) + +;;; haskell-string.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-string.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-string.elc new file mode 100644 index 000000000000..b748e6b10146 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-string.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-unicode-input-method.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-unicode-input-method.el new file mode 100644 index 000000000000..de792b58e470 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-unicode-input-method.el @@ -0,0 +1,300 @@ +;;; haskell-unicode-input-method.el --- Haskell Unicode helper functions -*- coding: utf-8; lexical-binding: t -*- + +;; Copyright (C) 2010-2011 Roel van Dijk + +;; Author: Roel van Dijk <vandijk.roel@gmail.com> + +;; This file is not part of GNU Emacs. + +;; 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 of the License, 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;;; Code: + +(require 'quail) + +;;;###autoload +(defun turn-on-haskell-unicode-input-method () + "Set input method `haskell-unicode'." + (interactive) + (set-input-method "haskell-unicode")) + +(quail-define-package + "haskell-unicode" ;; name + "UTF-8" ;; language + "\\" ;; title + t ;; guidance + "Haskell Unicode input method. +Designed to be used with the Haskell UnicodeSyntax language +extension in combination with the x-unicode-symbols set of +packages (base-unicode-symbols and containers-unicode-symbols). +" ;; docstring + nil ;; translation-keys + nil ;; forget-last-selection + nil ;; deterministic + nil ;; kbd-translate + nil ;; show-layout + nil ;; create-decode-map + nil ;; maximum-shortest + nil ;; overlay-plist + nil ;; update-translation-function + nil ;; conversion-keys + t ;; simple + ) + +(quail-define-rules + ;; Greek letters + ("alpha " ["α"]) + ("Alpha " ["Α"]) + ("beta " ["β"]) + ("Beta " ["Β"]) + ("gamma " ["γ"]) + ("Gamma " ["Γ"]) + ("delta " ["δ"]) + ("Delta " ["Δ"]) + ("epsilon " ["ε"]) + ("Epsilon " ["Ε"]) + ("zeta " ["ζ"]) + ("Zeta " ["Ζ"]) + ("eta " ["η"]) + ("Eta " ["Η"]) + ("theta " ["θ"]) + ("Theta " ["Θ"]) + ("iota " ["ι"]) + ("Iota " ["Ι"]) + ("kappa " ["κ"]) + ("Kappa " ["Κ"]) + ("lambda " ["λ"]) + ("Lambda " ["Λ"]) + ("lamda " ["λ"]) + ("Lamda " ["Λ"]) + ("mu " ["μ"]) + ("Mu " ["Μ"]) + ("nu " ["ν"]) + ("Nu " ["Ν"]) + ("xi " ["ξ"]) + ("Xi " ["Ξ"]) + ("omicron " ["ο"]) + ("Omicron " ["Ο"]) + ("pi " ["π"]) + ("Pi " ["Π"]) + ("rho " ["ρ"]) + ("Rho " ["Ρ"]) + ("sigma " ["σ"]) + ("Sigma " ["Σ"]) + ("tau " ["τ"]) + ("Tau " ["Τ"]) + ("upsilon " ["υ"]) + ("Upsilon " ["Υ"]) + ("phi " ["φ"]) + ("Phi " ["Φ"]) + ("chi " ["χ"]) + ("Chi " ["Χ"]) + ("psi " ["ψ"]) + ("Psi " ["Ψ"]) + ("omega " ["ω"]) + ("Omega " ["Ω"]) + ("digamma " ["ϝ"]) + ("Digamma " ["Ϝ"]) + ("san " ["ϻ"]) + ("San " ["Ϻ"]) + ("qoppa " ["ϙ"]) + ("Qoppa " ["Ϙ"]) + ("sampi " ["ϡ"]) + ("Sampi " ["Ϡ"]) + ("stigma " ["ϛ"]) + ("Stigma " ["Ϛ"]) + ("heta " ["ͱ"]) + ("Heta " ["Ͱ"]) + ("sho " ["ϸ"]) + ("Sho " ["Ϸ"]) + + ;; Double-struck letters + ("|A|" ["𝔸"]) + ("|B|" ["𝔹"]) + ("|C|" ["ℂ"]) + ("|D|" ["𝔻"]) + ("|E|" ["𝔼"]) + ("|F|" ["𝔽"]) + ("|G|" ["𝔾"]) + ("|H|" ["ℍ"]) + ("|I|" ["𝕀"]) + ("|J|" ["𝕁"]) + ("|K|" ["𝕂"]) + ("|L|" ["𝕃"]) + ("|M|" ["𝕄"]) + ("|N|" ["ℕ"]) + ("|O|" ["𝕆"]) + ("|P|" ["ℙ"]) + ("|Q|" ["ℚ"]) + ("|R|" ["ℝ"]) + ("|S|" ["𝕊"]) + ("|T|" ["𝕋"]) + ("|U|" ["𝕌"]) + ("|V|" ["𝕍"]) + ("|W|" ["𝕎"]) + ("|X|" ["𝕏"]) + ("|Y|" ["𝕐"]) + ("|Z|" ["ℤ"]) + ("|gamma|" ["ℽ"]) + ("|Gamma|" ["ℾ"]) + ("|pi|" ["ℼ"]) + ("|Pi|" ["ℿ"]) + + ;; Types + ("::" ["∷"]) + + ;; Quantifiers + ("forall" ["∀"]) + ("exists" ["∃"]) + + ;; Arrows + ("->" ["→"]) + ;; ("-->" ["⟶"]) + ("<-" ["←"]) + ;; ("<--" ["⟵"]) + ;; ("<->" ["↔"]) + ;; ("<-->" ["⟷"]) + + ("=>" ["⇒"]) + ;; ("==>" ["⟹"]) + ;; ("<=" ["⇐"]) + ;; ("<==" ["⟸"]) + ;; ("<=>" ["⇔"]) + ;; ("<==>" ["⟺"]) + + ;; ("|->" ["↦"]) + ;; ("|-->" ["⟼"]) + ;; ("<-|" ["↤"]) + ;; ("<--|" ["⟻"]) + + ;; ("|=>" ["⤇"]) + ;; ("|==>" ["⟾"]) + ;; ("<=|" ["⤆"]) + ;; ("<==|" ["⟽"]) + + ("~>" ["⇝"]) + ;; ("~~>" ["⟿"]) + ("<~" ["⇜"]) + ;; ("<~~" ["⬳"]) + + ;; (">->" ["↣"]) + ;; ("<-<" ["↢"]) + ;; ("->>" ["↠"]) + ;; ("<<-" ["↞"]) + + ;; (">->>" ["⤖"]) + ;; ("<<-<" ["⬻"]) + + ;; ("<|-" ["⇽"]) + ;; ("-|>" ["⇾"]) + ;; ("<|-|>" ["⇿"]) + + ;; ("<-/-" ["↚"]) + ;; ("-/->" ["↛"]) + + ;; ("<-|-" ["⇷"]) + ;; ("-|->" ["⇸"]) + ;; ("<-|->" ["⇹"]) + + ;; ("<-||-" ["⇺"]) + ;; ("-||->" ["⇻"]) + ;; ("<-||->" ["⇼"]) + + ;; ("-o->" ["⇴"]) + ;; ("<-o-" ["⬰"]) + + ;; Boolean operators + ;; ("not" ["¬"]) + ("&&" ["∧"]) + ("||" ["∨"]) + + ;; Relational operators + ("==" ["≡"]) + ("/=" ["≢" "≠"]) + ("<=" ["≤"]) + (">=" ["≥"]) + ("/<" ["≮"]) + ("/>" ["≯"]) + + ;; Arithmetic + ;; (" / " [" ÷ "]) + (" * " [" ⋅ "]) + + ;; Containers / Collections + ;; ("++" ["⧺"]) + ;; ("+++" ["⧻"]) + ;; ("|||" ["⫴"]) + ;; ("empty" ["∅"]) + ("elem" ["∈"]) + ("notElem" ["∉"]) + ("member" ["∈"]) + ("notMember" ["∉"]) + ("union" ["∪"]) + ("intersection" ["∩"]) + ("isSubsetOf" ["⊆"]) + ("isProperSubsetOf" ["⊂"]) + + ;; Other + ;; ("<<" ["≪"]) + ;; (">>" ["≫"]) + ("<<<" ["⋘"]) + (">>>" ["⋙"]) + ("<|" ["⊲"]) + ("|>" ["⊳"]) + ("><" ["⋈"]) + ;; ("mempty" ["∅"]) + ("mappend" ["⊕"]) + ;; ("<*>" ["⊛"]) + (" . " [" ∘ "]) + ("undefined" ["⊥"]) + (":=" ["≔"]) + ("=:" ["≕"]) + ("=def" ["≝"]) + ("=?" ["≟"]) + ("..." ["…"]) + + ;; Braces + ;; ("[|" ["〚"]) + ;; ("|]" ["〛"]) + + ;; Numeric subscripts + ("_0 " ["₀"]) + ("_1 " ["₁"]) + ("_2 " ["₂"]) + ("_3 " ["₃"]) + ("_4 " ["₄"]) + ("_5 " ["₅"]) + ("_6 " ["₆"]) + ("_7 " ["₇"]) + ("_8 " ["₈"]) + ("_9 " ["₉"]) + + ;; Numeric superscripts + ("^0 " ["⁰"]) + ("^1 " ["¹"]) + ("^2 " ["²"]) + ("^3 " ["³"]) + ("^4 " ["⁴"]) + ("^5 " ["⁵"]) + ("^6 " ["⁶"]) + ("^7 " ["⁷"]) + ("^8 " ["⁸"]) + ("^9 " ["⁹"]) + ) + +(provide 'haskell-unicode-input-method) + +;;; haskell-unicode-input-method.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-unicode-input-method.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-unicode-input-method.elc new file mode 100644 index 000000000000..f5257af4e2b1 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-unicode-input-method.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-utils.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-utils.el new file mode 100644 index 000000000000..1126a2614d64 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-utils.el @@ -0,0 +1,193 @@ +;;; haskell-utils.el --- General utility functions used by haskell-mode modules -*- lexical-binding: t -*- + +;; Copyright © 2013 Herbert Valerio Riedel +;; 2016 Arthur Fayzrakhmanov + +;; Author: Herbert Valerio Riedel <hvr@gnu.org> + +;; This file is not part of GNU Emacs. + +;; 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 of the License, 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This module's purpose is to provide a place for helper functions +;; which are general enough to be usable by multiple modules and/or +;; to alleviate circular module dependency problems. +;; +;; When possible, functions in this module shall be accompanied by +;; ERT-based unit tests. +;; +;; See also `haskell-str.el' for string utility functions. +;; +;; All symbols in this module have a `haskell-utils-' prefix. + +;;; Code: + +;; ============================================================================= +;; NOTE: +;; THIS MODULE IS SUPPOSED TO BE A LEAF-MODULE AND SHALL NOT REQUIRE/DEPEND-ON +;; ANY OTHER HASKELL-MODE MODULES IN ORDER TO STAY AT THE BOTTOM OF THE MODULE +;; DEPENDENCY GRAPH. +;; ============================================================================= + +(eval-when-compile (require 'cl-lib)) + +(defvar-local haskell-utils-async-post-command-flag nil + "Non-nil means some commands were triggered during async function execution.") + +(defvar haskell-mode-interactive-prompt-state nil + "Special variable indicating a state of user input waiting.") + +(defun haskell-utils-read-directory-name (prompt default) + "Read directory name and normalize to true absolute path. +Refer to `read-directory-name' for the meaning of PROMPT and +DEFAULT. If `haskell-process-load-or-reload-prompt' is nil, +accept `default'." + (let ((filename (file-truename (read-directory-name prompt default default)))) + (concat (replace-regexp-in-string "/$" "" filename) "/"))) + +(defun haskell-utils-parse-import-statement-at-point () + "Return imported module name if on import statement or nil otherwise. +This currently assumes that the \"import\" keyword and the module +name are on the same line. + +This function supports the SafeHaskell and PackageImports syntax extensions. + +Note: doesn't detect if in {--}-style comment." + (save-excursion + (goto-char (line-beginning-position)) + (if (looking-at (concat "[\t ]*import[\t ]+" + "\\(?:safe[\t ]+\\)?" ;; SafeHaskell + "\\(?:qualified[\t ]+\\)?" + "\\(?:\"[^\"]*\"[\t ]+\\)?" ;; PackageImports + "\\([[:digit:][:upper:][:lower:]_.]+\\)")) + (match-string-no-properties 1)))) + +(defun haskell-utils-async-update-post-command-flag () + "A special hook which collects triggered commands during async execution. +This hook pushes value of variable `this-command' to flag variable +`haskell-utils-async-post-command-flag'." + (let* ((cmd this-command) + (updated-flag (cons cmd haskell-utils-async-post-command-flag))) + (setq haskell-utils-async-post-command-flag updated-flag))) + +(defun haskell-utils-async-watch-changes () + "Watch for triggered commands during async operation execution. +Resets flag variable +`haskell-utils-async-update-post-command-flag' to NIL. By changes it is +assumed that nothing happened, e.g. nothing was inserted in +buffer, point was not moved, etc. To collect data `post-command-hook' is used." + (setq haskell-utils-async-post-command-flag nil) + (add-hook + 'post-command-hook #'haskell-utils-async-update-post-command-flag nil t)) + +(defun haskell-utils-async-stop-watching-changes (buffer) + "Clean up after async operation finished. +This function takes care about cleaning up things made by +`haskell-utils-async-watch-changes'. The BUFFER argument is a buffer where +`post-command-hook' should be disabled. This is neccessary, because +it is possible that user will change buffer during async function +execusion." + (with-current-buffer buffer + (setq haskell-utils-async-post-command-flag nil) + (remove-hook + 'post-command-hook #'haskell-utils-async-update-post-command-flag t))) + +(defun haskell-utils-reduce-string (str) + "Remove newlines and extra whitespace from string STR. +If line starts with a sequence of whitespaces, substitutes this +sequence with a single whitespace. Removes all newline +characters." + (let ((s (replace-regexp-in-string "^\s+" " " str))) + (replace-regexp-in-string "\r?\n" "" s))) + +(defun haskell-utils-repl-response-error-status (response) + "Parse response REPL's RESPONSE for errors. +Returns one of the following symbols: + ++ unknown-command ++ option-missing ++ interactive-error ++ no-error + +*Warning*: this funciton covers only three kind of responses: + +* \"unknown command …\" + REPL missing requested command +* \"<interactive>:3:5: …\" + interactive REPL error +* \"Couldn't guess that module name. Does it exist?\" + (:type-at and maybe some other commands error) +* *all other reposnses* are treated as success reposneses and + 'no-error is returned." + (if response + (let ((first-line (car (split-string response "\n" t)))) + (cond + ((null first-line) 'no-error) + ((string-match-p "^unknown command" first-line) + 'unknown-command) + ((string-match-p + "^Couldn't guess that module name. Does it exist?" + first-line) + 'option-missing) + ((string-match-p "^<interactive>:" first-line) + 'interactive-error) + (t 'no-error))) + ;; in case of nil-ish reponse it's not clear is it error response or not + 'no-error)) + +(defun haskell-utils-compose-type-at-command (pos) + "Prepare :type-at command to be send to haskell process. +POS is a cons cell containing min and max positions, i.e. target +expression bounds." + (save-excursion + (let ((start-p (car pos)) + (end-p (cdr pos)) + start-l + start-c + end-l + end-c + value) + (goto-char start-p) + (setq start-l (line-number-at-pos)) + (setq start-c (1+ (current-column))) + (goto-char end-p) + (setq end-l (line-number-at-pos)) + (setq end-c (1+ (current-column))) + (setq value (buffer-substring-no-properties start-p end-p)) + ;; supress multiline expressions + (let ((lines (split-string value "\n" t))) + (when (and (cdr lines) + (stringp (car lines))) + (setq value (format "[ %s … ]" (car lines))))) + (replace-regexp-in-string + "\n$" + "" + (format ":type-at %s %d %d %d %d %s" + (buffer-file-name) + start-l + start-c + end-l + end-c + value))))) + + +(defun haskell-mode-toggle-interactive-prompt-state (&optional disabled) + "Set `haskell-mode-interactive-prompt-state' to t. +If given DISABLED argument sets variable value to nil, otherwise to t." + (setq haskell-mode-interactive-prompt-state (not disabled))) + +(provide 'haskell-utils) +;;; haskell-utils.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-utils.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-utils.elc new file mode 100644 index 000000000000..3c2ddd80e697 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-utils.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell.el new file mode 100644 index 000000000000..641fea35676c --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell.el @@ -0,0 +1,528 @@ +;;; haskell.el --- Top-level Haskell package -*- lexical-binding: t -*- + +;; Copyright © 2014 Chris Done. All rights reserved. +;; 2016 Arthur Fayzrakhmanov + +;; 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;;; Code: + +(require 'cl-lib) +(require 'haskell-mode) +(require 'haskell-hoogle) +(require 'haskell-process) +(require 'haskell-debug) +(require 'haskell-interactive-mode) +(require 'haskell-repl) +(require 'haskell-load) +(require 'haskell-commands) +(require 'haskell-modules) +(require 'haskell-string) +(require 'haskell-completions) +(require 'haskell-utils) +(require 'haskell-customize) + +(defvar interactive-haskell-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-c C-l") 'haskell-process-load-file) + (define-key map (kbd "C-c C-r") 'haskell-process-reload) + (define-key map (kbd "C-c C-t") 'haskell-process-do-type) + (define-key map (kbd "C-c C-i") 'haskell-process-do-info) + (define-key map (kbd "M-.") 'haskell-mode-jump-to-def-or-tag) + (define-key map (kbd "C-c C-k") 'haskell-interactive-mode-clear) + (define-key map (kbd "C-c C-c") 'haskell-process-cabal-build) + (define-key map (kbd "C-c C-v") 'haskell-cabal-visit-file) + (define-key map (kbd "C-c C-x") 'haskell-process-cabal) + (define-key map (kbd "C-c C-b") 'haskell-interactive-switch) + (define-key map (kbd "C-c C-z") 'haskell-interactive-switch) + map) + "Keymap for using `interactive-haskell-mode'.") + +;;;###autoload +(define-minor-mode interactive-haskell-mode + "Minor mode for enabling haskell-process interaction." + :lighter " Interactive" + :keymap interactive-haskell-mode-map + (add-hook 'completion-at-point-functions + #'haskell-completions-sync-repl-completion-at-point + nil + t)) + +(make-obsolete 'haskell-process-completions-at-point + 'haskell-completions-sync-repl-completion-at-point + "June 19, 2015") + +(defun haskell-process-completions-at-point () + "A `completion-at-point' function using the current haskell process." + (when (haskell-session-maybe) + (let ((process (haskell-process)) + symbol-bounds) + (cond + ;; ghci can complete module names, but it needs the "import " + ;; string at the beginning + ((looking-back (rx line-start + "import" (1+ space) + (? "qualified" (1+ space)) + (group (? (char upper) ; modid + (* (char alnum ?' ?.))))) + (line-beginning-position)) + (let ((text (match-string-no-properties 0)) + (start (match-beginning 1)) + (end (match-end 1))) + (list start end + (haskell-process-get-repl-completions process text)))) + ;; Complete OPTIONS, a completion list comes from variable + ;; `haskell-ghc-supported-options' + ((and (nth 4 (syntax-ppss)) + (save-excursion + (let ((p (point))) + (and (search-backward "{-#" nil t) + (search-forward-regexp "\\_<OPTIONS\\(?:_GHC\\)?\\_>" p t)))) + (looking-back + (rx symbol-start "-" (* (char alnum ?-))) + (line-beginning-position))) + (list (match-beginning 0) (match-end 0) haskell-ghc-supported-options)) + ;; Complete LANGUAGE, a list of completions comes from variable + ;; `haskell-ghc-supported-extensions' + ((and (nth 4 (syntax-ppss)) + (save-excursion + (let ((p (point))) + (and (search-backward "{-#" nil t) + (search-forward-regexp "\\_<LANGUAGE\\_>" p t)))) + (setq symbol-bounds (bounds-of-thing-at-point 'symbol))) + (list (car symbol-bounds) (cdr symbol-bounds) + haskell-ghc-supported-extensions)) + ((setq symbol-bounds (haskell-ident-pos-at-point)) + (cl-destructuring-bind (start . end) symbol-bounds + (list start end + (haskell-process-get-repl-completions + process (buffer-substring-no-properties start end))))))))) + +;;;###autoload +(defun haskell-interactive-mode-return () + "Handle the return key." + (interactive) + (cond + ;; At a compile message, jump to the location of the error in the + ;; source. + ((haskell-interactive-at-compile-message) + (next-error-internal)) + ;; At the input prompt, handle the expression in the usual way. + ((haskell-interactive-at-prompt) + (haskell-interactive-handle-expr)) + ;; At any other location in the buffer, copy the line to the + ;; current prompt. + (t + (haskell-interactive-copy-to-prompt)))) + +;;;###autoload +(defun haskell-session-kill (&optional leave-interactive-buffer) + "Kill the session process and buffer, delete the session. +0. Prompt to kill all associated buffers. +1. Kill the process. +2. Kill the interactive buffer unless LEAVE-INTERACTIVE-BUFFER is not given. +3. Walk through all the related buffers and set their haskell-session to nil. +4. Remove the session from the sessions list." + (interactive) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (let* ((session (haskell-session)) + (name (haskell-session-name session)) + (also-kill-buffers + (and haskell-ask-also-kill-buffers + (y-or-n-p + (format "Killing `%s'. Also kill all associated buffers?" + name))))) + (haskell-kill-session-process session) + (unless leave-interactive-buffer + (kill-buffer (haskell-session-interactive-buffer session))) + (cl-loop for buffer in (buffer-list) + do (with-current-buffer buffer + (when (and (boundp 'haskell-session) + (string= (haskell-session-name haskell-session) + name)) + (setq haskell-session nil) + (when also-kill-buffers + (kill-buffer))))) + (setq haskell-sessions + (cl-remove-if (lambda (session) + (string= (haskell-session-name session) + name)) + haskell-sessions))) + (haskell-mode-toggle-interactive-prompt-state t))) + +;;;###autoload +(defun haskell-interactive-kill () + "Kill the buffer and (maybe) the session." + (interactive) + (when (eq major-mode 'haskell-interactive-mode) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (when (and (boundp 'haskell-session) + haskell-session + (y-or-n-p "Kill the whole session?")) + (haskell-session-kill t))) + (haskell-mode-toggle-interactive-prompt-state t))) + +(defun haskell-session-make (name) + "Make a Haskell session." + (when (haskell-session-lookup name) + (error "Session of name %s already exists!" name)) + (let ((session (setq haskell-session + (list (cons 'name name))))) + (add-to-list 'haskell-sessions session) + (haskell-process-start session) + session)) + +(defun haskell-session-new-assume-from-cabal () + "Prompt to create a new project based on a guess from the nearest Cabal file. +If `haskell-process-load-or-reload-prompt' is nil, accept `default'." + (let ((name (haskell-session-default-name))) + (unless (haskell-session-lookup name) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (if (or (not haskell-process-load-or-reload-prompt) + (y-or-n-p (format "Start a new project named “%s”? " name))) + (haskell-session-make name)) + (haskell-mode-toggle-interactive-prompt-state t))))) + +;;;###autoload +(defun haskell-session () + "Get the Haskell session, prompt if there isn't one or fail." + (or (haskell-session-maybe) + (haskell-session-assign + (or (haskell-session-from-buffer) + (haskell-session-new-assume-from-cabal) + (haskell-session-choose) + (haskell-session-new))))) + +;;;###autoload +(defun haskell-interactive-switch () + "Switch to the interactive mode for this session." + (interactive) + (let ((initial-buffer (current-buffer)) + (buffer (haskell-session-interactive-buffer (haskell-session)))) + (with-current-buffer buffer + (setq haskell-interactive-previous-buffer initial-buffer)) + (unless (eq buffer (window-buffer)) + (switch-to-buffer-other-window buffer)))) + +(defun haskell-session-new () + "Make a new session." + (let ((name (read-from-minibuffer "Project name: " (haskell-session-default-name)))) + (when (not (string= name "")) + (let ((session (haskell-session-lookup name))) + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (if session + (when + (y-or-n-p + (format "Session %s already exists. Use it?" name)) + session) + (haskell-session-make name))) + (haskell-mode-toggle-interactive-prompt-state t))))) + +;;;###autoload +(defun haskell-session-change () + "Change the session for the current buffer." + (interactive) + (haskell-session-assign (or (haskell-session-new-assume-from-cabal) + (haskell-session-choose) + (haskell-session-new)))) + +(defun haskell-process-prompt-restart (process) + "Prompt to restart the died PROCESS." + (let ((process-name (haskell-process-name process)) + (cursor-in-echo-area t)) + (if haskell-process-suggest-restart + (progn + (haskell-mode-toggle-interactive-prompt-state) + (unwind-protect + (cond + ((string-match "You need to re-run the 'configure' command." + (haskell-process-response process)) + (cl-case (read-char-choice + (concat + "The Haskell process ended. Cabal wants you to run " + (propertize "cabal configure" + 'face + 'font-lock-keyword-face) + " because there is a version mismatch. Re-configure (y, n, l: view log)?" + "\n\n" + "Cabal said:\n\n" + (propertize (haskell-process-response process) + 'face + 'font-lock-comment-face)) + '(?l ?n ?y)) + (?y (let ((default-directory + (haskell-session-cabal-dir + (haskell-process-session process)))) + (message "%s" + (shell-command-to-string "cabal configure")))) + (?l (let* ((response (haskell-process-response process)) + (buffer (get-buffer "*haskell-process-log*"))) + (if buffer + (switch-to-buffer buffer) + (progn (switch-to-buffer + (get-buffer-create "*haskell-process-log*")) + (insert response))))) + (?n))) + (t + (cl-case (read-char-choice + (propertize + (format "The Haskell process `%s' has died. Restart? (y, n, l: show process log) " + process-name) + 'face + 'minibuffer-prompt) + '(?l ?n ?y)) + (?y (haskell-process-start (haskell-process-session process))) + (?l (let* ((response (haskell-process-response process)) + (buffer (get-buffer "*haskell-process-log*"))) + (if buffer + (switch-to-buffer buffer) + (progn (switch-to-buffer + (get-buffer-create "*haskell-process-log*")) + (insert response))))) + (?n)))) + ;; unwind + (haskell-mode-toggle-interactive-prompt-state t))) + (message "The Haskell process `%s' is dearly departed." process-name)))) + +(defun haskell-process () + "Get the current process from the current session." + (haskell-session-process (haskell-session))) + +;;;###autoload +(defun haskell-kill-session-process (&optional session) + "Kill the process." + (interactive) + (let* ((session (or session (haskell-session))) + (existing-process (get-process (haskell-session-name session)))) + (when (processp existing-process) + (haskell-interactive-mode-echo session "Killing process ...") + (haskell-process-set (haskell-session-process session) 'is-restarting t) + (delete-process existing-process)))) + +;;;###autoload +(defun haskell-interactive-mode-visit-error () + "Visit the buffer of the current (or last) error message." + (interactive) + (with-current-buffer (haskell-session-interactive-buffer (haskell-session)) + (if (progn (goto-char (line-beginning-position)) + (looking-at haskell-interactive-mode-error-regexp)) + (progn (forward-line -1) + (haskell-interactive-jump-to-error-line)) + (progn (goto-char (point-max)) + (haskell-interactive-mode-error-backward) + (haskell-interactive-jump-to-error-line))))) + +(defvar xref-prompt-for-identifier nil) + +;;;###autoload +(defun haskell-mode-jump-to-tag (&optional next-p) + "Jump to the tag of the given identifier. + +Give optional NEXT-P parameter to override value of +`xref-prompt-for-identifier' during definition search." + (interactive "P") + (let ((ident (haskell-string-drop-qualifier (haskell-ident-at-point))) + (tags-file-dir (haskell-cabal--find-tags-dir)) + (tags-revert-without-query t)) + (when (and ident + (not (string= "" (haskell-string-trim ident))) + tags-file-dir) + (let ((tags-file-name (concat tags-file-dir "TAGS"))) + (cond ((file-exists-p tags-file-name) + (let ((xref-prompt-for-identifier next-p)) + (xref-find-definitions ident))) + (t (haskell-mode-generate-tags ident))))))) + +;;;###autoload +(defun haskell-mode-after-save-handler () + "Function that will be called after buffer's saving." + (when haskell-tags-on-save + (ignore-errors (haskell-mode-generate-tags)))) + +;;;###autoload +(defun haskell-mode-tag-find (&optional _next-p) + "The tag find function, specific for the particular session." + (interactive "P") + (cond + ((elt (syntax-ppss) 3) ;; Inside a string + (haskell-mode-jump-to-filename-in-string)) + (t (call-interactively 'haskell-mode-jump-to-tag)))) + +(defun haskell-mode-jump-to-filename-in-string () + "Jump to the filename in the current string." + (let* ((string (save-excursion + (buffer-substring-no-properties + (1+ (search-backward-regexp "\"" (line-beginning-position) nil 1)) + (1- (progn (forward-char 1) + (search-forward-regexp "\"" (line-end-position) nil 1)))))) + (fp (expand-file-name string + (haskell-session-cabal-dir (haskell-session))))) + (find-file + (read-file-name + "" + fp + fp)))) + +;;;###autoload +(defun haskell-interactive-bring () + "Bring up the interactive mode for this session." + (interactive) + (let* ((session (haskell-session)) + (buffer (haskell-session-interactive-buffer session))) + (pop-to-buffer buffer))) + +;;;###autoload +(defun haskell-process-load-file () + "Load the current buffer file." + (interactive) + (save-buffer) + (haskell-interactive-mode-reset-error (haskell-session)) + (haskell-process-file-loadish (format "load \"%s\"" (replace-regexp-in-string + "\"" + "\\\\\"" + (buffer-file-name))) + nil + (current-buffer))) + +;;;###autoload +(defun haskell-process-reload () + "Re-load the current buffer file." + (interactive) + (save-buffer) + (haskell-interactive-mode-reset-error (haskell-session)) + (haskell-process-file-loadish "reload" t (current-buffer))) + +;;;###autoload +(defun haskell-process-reload-file () (haskell-process-reload)) + +(make-obsolete 'haskell-process-reload-file 'haskell-process-reload + "2015-11-14") + +;;;###autoload +(defun haskell-process-load-or-reload (&optional toggle) + "Load or reload. Universal argument toggles which." + (interactive "P") + (if toggle + (progn (setq haskell-reload-p (not haskell-reload-p)) + (message "%s (No action taken this time)" + (if haskell-reload-p + "Now running :reload." + "Now running :load <buffer-filename>."))) + (if haskell-reload-p (haskell-process-reload) (haskell-process-load-file)))) + +(make-obsolete 'haskell-process-load-or-reload 'haskell-process-load-file + "2015-11-14") + +;;;###autoload +(defun haskell-process-cabal-build () + "Build the Cabal project." + (interactive) + (haskell-process-do-cabal "build") + (haskell-process-add-cabal-autogen)) + +;;;###autoload +(defun haskell-process-cabal (p) + "Prompts for a Cabal command to run." + (interactive "P") + (if p + (haskell-process-do-cabal + (read-from-minibuffer "Cabal command (e.g. install): ")) + (haskell-process-do-cabal + (funcall haskell-completing-read-function "Cabal command: " + (append haskell-cabal-commands + (list "build --ghc-options=-fforce-recomp")))))) + +(defun haskell-process-file-loadish (command reload-p module-buffer) + "Run a loading-ish COMMAND that wants to pick up type errors\ +and things like that. RELOAD-P indicates whether the notification +should say 'reloaded' or 'loaded'. MODULE-BUFFER may be used +for various things, but is optional." + (let ((session (haskell-session))) + (haskell-session-current-dir session) + (when haskell-process-check-cabal-config-on-load + (haskell-process-look-config-changes session)) + (let ((process (haskell-process))) + (haskell-process-queue-command + process + (make-haskell-command + :state (list session process command reload-p module-buffer) + :go (lambda (state) + (haskell-process-send-string + (cadr state) (format ":%s" (cl-caddr state)))) + :live (lambda (state buffer) + (haskell-process-live-build + (cadr state) buffer nil)) + :complete (lambda (state response) + (haskell-process-load-complete + (car state) + (cadr state) + response + (cl-cadddr state) + (cl-cadddr (cdr state))))))))) + +;;;###autoload +(defun haskell-process-minimal-imports () + "Dump minimal imports." + (interactive) + (unless (> (save-excursion + (goto-char (point-min)) + (haskell-navigate-imports-go) + (point)) + (point)) + (goto-char (point-min)) + (haskell-navigate-imports-go)) + (haskell-process-queue-sync-request (haskell-process) + ":set -ddump-minimal-imports") + (haskell-process-load-file) + (insert-file-contents-literally + (concat (haskell-session-current-dir (haskell-session)) + "/" + (haskell-guess-module-name-from-file-name (buffer-file-name)) + ".imports"))) + +(defun haskell-interactive-jump-to-error-line () + "Jump to the error line." + (let ((orig-line (buffer-substring-no-properties (line-beginning-position) + (line-end-position)))) + (and (string-match "^\\([^:]+\\):\\([0-9]+\\):\\([0-9]+\\)\\(-[0-9]+\\)?:" orig-line) + (let* ((file (match-string 1 orig-line)) + (line (match-string 2 orig-line)) + (col (match-string 3 orig-line)) + (session (haskell-interactive-session)) + (cabal-path (haskell-session-cabal-dir session)) + (src-path (haskell-session-current-dir session)) + (cabal-relative-file (expand-file-name file cabal-path)) + (src-relative-file (expand-file-name file src-path))) + (let ((file (cond ((file-exists-p cabal-relative-file) + cabal-relative-file) + ((file-exists-p src-relative-file) + src-relative-file)))) + (when file + (other-window 1) + (find-file file) + (haskell-interactive-bring) + (goto-char (point-min)) + (forward-line (1- (string-to-number line))) + (goto-char (+ (point) (string-to-number col) -1)) + (haskell-mode-message-line orig-line) + t)))))) + +(provide 'haskell) +;;; haskell.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell.elc new file mode 100644 index 000000000000..bdc81f55d3ee --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/highlight-uses-mode.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/highlight-uses-mode.el new file mode 100644 index 000000000000..722c96414343 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/highlight-uses-mode.el @@ -0,0 +1,106 @@ +;;; highlight-uses-mode.el --- Mode for highlighting uses -*- 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 <http://www.gnu.org/licenses/>. + +;;; Code: + +(require 'cl-lib) + +(defvar highlight-uses-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "TAB") 'highlight-uses-mode-next) + (define-key map (kbd "S-TAB") 'highlight-uses-mode-prev) + (define-key map (kbd "<backtab>") 'highlight-uses-mode-prev) + (define-key map (kbd "RET") 'highlight-uses-mode-stop-here) + (define-key map (kbd "C-g") 'highlight-uses-mode) + map) + "Keymap for using `highlight-uses-mode'.") + +(defvar-local highlight-uses-mode-point nil) + +;;;###autoload +(define-minor-mode highlight-uses-mode + "Minor mode for highlighting and jumping between uses." + :lighter " Uses" + :keymap highlight-uses-mode-map + (if highlight-uses-mode + (setq highlight-uses-mode-point (point)) + (when highlight-uses-mode-point + (goto-char highlight-uses-mode-point))) + (remove-overlays (point-min) (point-max) 'highlight-uses-mode-highlight t)) + +(defun highlight-uses-mode-replace () + "Replace all highlighted instances in the buffer with something + else." + (interactive) + (save-excursion + (goto-char (point-min)) + (let ((o (highlight-uses-mode-next))) + (when o + (let ((replacement (read-from-minibuffer (format "Replace uses %s with: " + (buffer-substring + (overlay-start o) + (overlay-end o)))))) + + (while o + (goto-char (overlay-start o)) + (delete-region (overlay-start o) + (overlay-end o)) + (insert replacement) + (setq o (highlight-uses-mode-next)))))))) + +(defun highlight-uses-mode-stop-here () + "Stop at this point." + (interactive) + (setq highlight-uses-mode-point (point)) + (highlight-uses-mode -1)) + +(defun highlight-uses-mode-next () + "Jump to next result." + (interactive) + (let ((os (sort (cl-remove-if (lambda (o) + (or (<= (overlay-start o) (point)) + (not (overlay-get o 'highlight-uses-mode-highlight)))) + (overlays-in (point) (point-max))) + (lambda (a b) + (< (overlay-start a) + (overlay-start b)))))) + (when os + (goto-char (overlay-start (car os))) + (car os)))) + +(defun highlight-uses-mode-prev () + "Jump to previous result." + (interactive) + (let ((os (sort (cl-remove-if (lambda (o) + (or (>= (overlay-end o) (point)) + (not (overlay-get o 'highlight-uses-mode-highlight)))) + (overlays-in (point-min) (point))) + (lambda (a b) + (> (overlay-start a) + (overlay-start b)))))) + (when os + (goto-char (overlay-start (car os))) + (car os)))) + +(defun highlight-uses-mode-highlight (start end) + "Make a highlight overlay at the given span." + (let ((o (make-overlay start end))) + (overlay-put o 'priority 999) + (overlay-put o 'face 'isearch) + (overlay-put o 'highlight-uses-mode-highlight t))) + +(provide 'highlight-uses-mode) diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/highlight-uses-mode.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/highlight-uses-mode.elc new file mode 100644 index 000000000000..3b9bba06c085 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/highlight-uses-mode.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/inf-haskell.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/inf-haskell.el new file mode 100644 index 000000000000..a1ee32fe2fbc --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/inf-haskell.el @@ -0,0 +1,262 @@ +;;; inf-haskell.el --- Interaction with an inferior Haskell process -*- lexical-binding: t -*- + +;; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +;; Copyright (C) 2017 Vasantha Ganesh Kanniappan <vasanthaganesh.k@tuta.io> + +;; Author: Stefan Monnier <monnier@iro.umontreal.ca> +;; Keywords: Haskell + +;; 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; A major mode for the buffer that holds the inferior process + +;; Todo: + +;; - Check out Shim for ideas. +;; - i-h-load-buffer and i-h-send-region. + +;;; Code: + +(require 'comint) +(require 'shell) ; For directory tracking. +(require 'etags) +(require 'haskell-compat) +(require 'compile) +(require 'haskell-decl-scan) +(require 'haskell-cabal) +(require 'haskell-customize) +(require 'cl-lib) +(require 'haskell-string) + +;;;###autoload +(defgroup inferior-haskell nil + "Settings for REPL interaction via `inferior-haskell-mode'" + :link '(custom-manual "(haskell-mode)inferior-haskell-mode") + :prefix "inferior-haskell-" + :prefix "haskell-" + :group 'haskell) + +(defcustom inferior-haskell-hook nil + "The hook that is called after starting inf-haskell." + :type 'hook) + +(defun haskell-program-name-with-args () + "Return the command with the arguments to start the repl based on the +directory structure." + (cl-ecase (haskell-process-type) + ('ghci (cond ((eq system-type 'cygwin) (nconc "ghcii.sh" + haskell-process-args-ghci)) + (t (nconc `(,haskell-process-path-ghci) + haskell-process-args-ghci)))) + ('cabal-repl (nconc `(,haskell-process-path-cabal + "repl") + haskell-process-args-cabal-repl)) + ('stack-ghci (nconc `(,haskell-process-path-stack + "ghci") + haskell-process-args-stack-ghci)))) + +(defconst inferior-haskell-info-xref-re + "-- Defined at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\)\\(?:-\\([0-9]+\\)\\)?$") + +(defconst inferior-haskell-module-re + "-- Defined in \\(.+\\)$" + "Regular expression for matching module names in :info.") + +(defvar inferior-haskell-multiline-prompt-re + "^\\*?[[:upper:]][\\._[:alnum:]]*\\(?: \\*?[[:upper:]][\\._[:alnum:]]*\\)*| " + "Regular expression for matching multiline prompt (the one inside :{ ... :} blocks).") + +(defconst inferior-haskell-error-regexp-alist + `(;; Format of error messages used by GHCi. + ("^\\(.+?\\):\\([0-9]+\\):\\(\\([0-9]+\\):\\)?\\( \\|\n *\\)\\([Ww]arning\\)?" + 1 2 4 ,@(if (fboundp 'compilation-fake-loc) + '((6) nil (5 '(face nil font-lock-multiline t))))) + ;; Runtime exceptions, from ghci. + ("^\\*\\*\\* Exception: \\(.+?\\):(\\([0-9]+\\),\\([0-9]+\\))-(\\([0-9]+\\),\\([0-9]+\\)): .*" + 1 ,@(if (fboundp 'compilation-fake-loc) '((2 . 4) (3 . 5)) '(2 3))) + ;; GHCi uses two different forms for line/col ranges, depending on + ;; whether it's all on the same line or not :-( In Emacs-23, I could use + ;; explicitly numbered subgroups to merge the two patterns. + ("^\\*\\*\\* Exception: \\(.+?\\):\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\): .*" + 1 2 ,(if (fboundp 'compilation-fake-loc) '(3 . 4) 3)) + ;; Info messages. Not errors per se. + ,@(when (fboundp 'compilation-fake-loc) + `(;; Other GHCi patterns used in type errors. + ("^[ \t]+at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\)$" + 1 2 (3 . 4) 0) + ;; Foo.hs:318:80: + ;; Ambiguous occurrence `Bar' + ;; It could refer to either `Bar', defined at Zork.hs:311:5 + ;; or `Bar', imported from Bars at Frob.hs:32:0-16 + ;; (defined at Location.hs:97:5) + ("[ (]defined at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\))?$" 1 2 3 0) + ("imported from .* at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\)$" + 1 2 (3 . 4) 0) + ;; Info xrefs. + (,inferior-haskell-info-xref-re 1 2 (3 . 4) 0)))) + "Regexps for error messages generated by inferior Haskell processes. +The format should be the same as for `compilation-error-regexp-alist'.") + +(defconst haskell-prompt-regexp + ;; Why the backslash in [\\._[:alnum:]]? + "^\\*?[[:upper:]][\\._[:alnum:]]*\\(?: \\*?[[:upper:]][\\._[:alnum:]]*\\)*\\( λ\\)?> \\|^λ?> $") + +;;; TODO +;;; -> Make font lock work for strings, directories, hyperlinks +;;; -> Make font lock work for key words??? + +(defvar inf-haskell-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-c\C-d" 'comint-kill-subjob) + map)) + +(defvaralias 'inferior-haskell-mode-map 'inf-haskell-map) + +(define-derived-mode inferior-haskell-mode comint-mode "Inf-Haskell" + "Major mode for interacting with an inferior Haskell process." + :group 'inferior-haskell + (setq-local comint-prompt-regexp haskell-prompt-regexp) + + (setq-local paragraph-start haskell-prompt-regexp) + + (setq-local comint-input-autoexpand nil) + (setq-local comint-prompt-read-only t) + + ;; Setup directory tracking. + (setq-local shell-cd-regexp ":cd") + (condition-case nil + (shell-dirtrack-mode 1) + (error ;The minor mode function may not exist or not accept an arg. + (setq-local shell-dirtrackp t) + (add-hook 'comint-input-filter-functions 'shell-directory-tracker + nil 'local))) + + ;; Setup `compile' support so you can just use C-x ` and friends. + (setq-local compilation-error-regexp-alist inferior-haskell-error-regexp-alist) + (setq-local compilation-first-column 0) ;GHCI counts from 0. + (if (and (not (boundp 'minor-mode-overriding-map-alist)) + (fboundp 'compilation-shell-minor-mode)) + ;; If we can't remove compilation-minor-mode bindings, at least try to + ;; use compilation-shell-minor-mode, so there are fewer + ;; annoying bindings. + (compilation-shell-minor-mode 1) + ;; Else just use compilation-minor-mode but without its bindings because + ;; things like mouse-2 are simply too annoying. + (compilation-minor-mode 1) + (let ((map (make-sparse-keymap))) + (dolist (keys '([menu-bar] [follow-link])) + ;; Preserve some of the bindings. + (define-key map keys (lookup-key compilation-minor-mode-map keys))) + (add-to-list 'minor-mode-overriding-map-alist + (cons 'compilation-minor-mode map)))) + (add-hook 'inferior-haskell-hook 'inferior-haskell-init)) + +(defvar inferior-haskell-buffer nil + "The buffer in which the inferior process is running.") + +(defun inferior-haskell-start-process () + "Start an inferior haskell process. +With universal prefix \\[universal-argument], prompts for a COMMAND, +otherwise uses `haskell-program-name-with-args'. +It runs the hook `inferior-haskell-hook' after starting the process and +setting up the inferior-haskell buffer." + (let ((command (haskell-program-name-with-args))) + (setq default-directory inferior-haskell-root-dir) + (setq inferior-haskell-buffer + (apply 'make-comint "haskell" (car command) nil (cdr command))) + (with-current-buffer inferior-haskell-buffer + (inferior-haskell-mode) + (run-hooks 'inferior-haskell-hook)))) + +(defun inferior-haskell-process () + "Restart if not present." + (cond ((and (buffer-live-p inferior-haskell-buffer) + (comint-check-proc inferior-haskell-buffer)) + (get-buffer-process inferior-haskell-buffer)) + (t (inferior-haskell-start-process) + (inferior-haskell-process)))) + +;;;###autoload +(defalias 'run-haskell 'switch-to-haskell) +;;;###autoload +(defun switch-to-haskell () + "Show the inferior-haskell buffer. Start the process if needed." + (interactive) + (let ((proc (inferior-haskell-process))) + (pop-to-buffer-same-window (process-buffer proc)))) + +(defvar inferior-haskell-result-history nil) + +(defvar haskell-next-input "" + "This is a temporary variable to store the intermediate results while +`accecpt-process-output' with `haskell-extract-exp'") + +(defun haskell-extract-exp (str) + (setq haskell-next-input (concat haskell-next-input str)) + (if (with-temp-buffer + (insert haskell-next-input) + (re-search-backward haskell-prompt-regexp nil t 1)) + (progn + (push (substring haskell-next-input + 0 + (1- (with-temp-buffer + (insert haskell-next-input) + (re-search-backward haskell-prompt-regexp nil t 1)))) + inferior-haskell-result-history) + (setq haskell-next-input "")) + "")) + +(defun inferior-haskell-no-result-return (strg) + (let ((proc (inferior-haskell-process))) + (with-local-quit + (progn + (add-to-list 'comint-preoutput-filter-functions + (lambda (output) + (haskell-extract-exp output))) + (process-send-string proc strg) + (accept-process-output proc) + (sit-for 0.1) + (setq comint-preoutput-filter-functions nil))))) + +(defun inferior-haskell-get-result (inf-expr) + "Submit the expression `inf-expr' to ghci and read the result." + (let* ((times 5)) + (inferior-haskell-no-result-return (concat inf-expr "\n")) + (while (and (> times 0) + (not (stringp (car inferior-haskell-result-history)))) + (setq times (1- times)) + (inferior-haskell-no-result-return (concat inf-expr "\n"))) + (haskell-string-chomp (car inferior-haskell-result-history)))) + +(defun inferior-haskell-init () + "The first thing run while initalizing inferior-haskell-buffer" + (with-local-quit + (with-current-buffer inferior-haskell-buffer + (process-send-string (inferior-haskell-process) "\n") + (accept-process-output (inferior-haskell-process)) + (sit-for 0.1)))) + +(defvar haskell-set+c-p nil + "t if `:set +c` else nil") + +(defun haskell-set+c () + "set `:set +c` is not already set" + (if (not haskell-set+c-p) + (inferior-haskell-get-result ":set +c"))) + +(provide 'inf-haskell) + +;;; inf-haskell.el ends here diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/inf-haskell.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/inf-haskell.elc new file mode 100644 index 000000000000..91bd9d4d03cb --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/inf-haskell.elc Binary files differdiff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/logo.svg b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/logo.svg new file mode 100644 index 000000000000..401e5990ec96 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/logo.svg @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="481.8897pt" height="340.1574pt" viewBox="0 0 481.8897 340.1574" version="1.1"> +<defs> +<clipPath id="clip1"> + <path d="M 0 340.15625 L 481.890625 340.15625 L 481.890625 0 L 0 0 L 0 340.15625 Z M 0 340.15625 "/> +</clipPath> +</defs> +<g id="surface0"> +<g clip-path="url(#clip1)" clip-rule="nonzero"> +<path style=" stroke:none;fill-rule: nonzero; fill: rgb(40%,40%,40%); fill-opacity: 1;" d="M 0 340.15625 L 113.386719 170.078125 L 0 0 L 85.039062 0 L 198.425781 170.078125 L 85.039062 340.15625 L 0 340.15625 Z M 0 340.15625 "/> +<path style=" stroke:none;fill-rule: nonzero; fill: rgb(60%,60%,60%); fill-opacity: 1;" d="M 113.386719 340.15625 L 226.773438 170.078125 L 113.386719 0 L 198.425781 0 L 425.195312 340.15625 L 340.15625 340.15625 L 269.292969 233.859375 L 198.425781 340.15625 L 113.386719 340.15625 Z M 113.386719 340.15625 "/> +<path style=" stroke:none;fill-rule: nonzero; fill: rgb(40%,40%,40%); fill-opacity: 1;" d="M 387.402344 240.945312 L 349.609375 184.253906 L 481.890625 184.25 L 481.890625 240.945312 L 387.402344 240.945312 Z M 387.402344 240.945312 "/> +<path style=" stroke:none;fill-rule: nonzero; fill: rgb(40%,40%,40%); fill-opacity: 1;" d="M 330.710938 155.90625 L 292.914062 99.214844 L 481.890625 99.210938 L 481.890625 155.90625 L 330.710938 155.90625 Z M 330.710938 155.90625 "/> +</g> +</g> +</svg> diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/w3m-haddock.el b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/w3m-haddock.el new file mode 100644 index 000000000000..ee6ce43722d2 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/w3m-haddock.el @@ -0,0 +1,190 @@ +;;; -*- lexical-binding: t -*- +;;; w3m-haddock.el --- Make browsing haddocks with w3m-mode better. + +;; Copyright (C) 2014 Chris Done + +;; Author: Chris Done <chrisdone@gmail.com> + +;; This file is not part of GNU Emacs. + +;; 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 GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +(require 'cl-lib) +(require 'haskell-mode) +(require 'haskell-font-lock) + +(declare-function w3m-buffer-title "ext:w3m") +(declare-function w3m-browse-url "ext:w3m") +(defvar w3m-current-url) + +(add-hook 'w3m-display-hook 'w3m-haddock-display) + +;;;###autoload +(defface w3m-haddock-heading-face + '((((class color)) :inherit highlight)) + "Face for quarantines." + :group 'haskell) + +(defcustom haskell-w3m-haddock-dirs + '("~/.cabal/share/doc/") + "The path to your cabal documentation dir. It should contain +directories of package-name-x.x. + +You can rebind this if you're using hsenv by adding it to your +.dir-locals.el in your project root. E.g. + + ((haskell-mode . ((haskell-w3m-haddock-dirs . (\"/home/chris/Projects/foobar/.hsenv/cabal/share/doc\"))))) + +" + :group 'haskell + :type 'list) + +(defvar w3m-haddock-entry-regex "^\\(\\(data\\|type\\) \\|[a-z].* :: \\)" + "Regex to match entry headings.") + +(defun haskell-w3m-open-haddock () + "Open a haddock page in w3m." + (interactive) + (let* ((entries (cl-remove-if (lambda (s) (string= s "")) + (apply 'append (mapcar (lambda (dir) + (split-string (shell-command-to-string (concat "ls -1 " dir)) + + "\n")) + haskell-w3m-haddock-dirs)))) + (package-dir (ido-completing-read + "Package: " + entries))) + (cond + ((member package-dir entries) + (unless (cl-loop for dir in haskell-w3m-haddock-dirs + when (w3m-haddock-find-index dir package-dir) + do (progn (w3m-browse-url (w3m-haddock-find-index dir package-dir) + t) + (cl-return t))) + (w3m-browse-url (concat "http://hackage.haskell.org/package/" + package-dir) + t))) + (t + (w3m-browse-url (concat "http://hackage.haskell.org/package/" + package-dir) + t))))) + +(defun w3m-haddock-find-index (dir package) + (let ((html-index (concat dir "/" package "/html/index.html")) + (index (concat dir "/" package "/index.html"))) + (cond + ((file-exists-p html-index) + html-index) + ((file-exists-p index) + index)))) + +(defun w3m-haddock-page-p () + "Haddock general page?" + (save-excursion + (goto-char (point-max)) + (forward-line -2) + (looking-at "[ ]*Produced by Haddock"))) + +(defun w3m-haddock-source-p () + "Haddock source page?" + (save-excursion + (goto-char (point-min)) + (or (looking-at "Location: https?://hackage.haskell.org/package/.*/docs/src/") + (looking-at "Location: file://.*cabal/share/doc/.*/html/src/") + (looking-at "Location: .*src/.*.html$")))) + +(defun w3m-haddock-p () + "Any haddock page?" + (or (w3m-haddock-page-p) + (w3m-haddock-source-p))) + +(defun w3m-haddock-find-tag () + "Find a tag by jumping to the \"All\" index and doing a + search-forward." + (interactive) + (when (w3m-haddock-p) + (let ((ident (haskell-ident-at-point))) + (when ident + (w3m-browse-url + (replace-regexp-in-string "docs/.*" "docs/doc-index-All.html" w3m-current-url)) + (search-forward ident))))) + +(defun w3m-haddock-display (_url) + "To be run by w3m's display hook. This takes a normal w3m + buffer containing hadddock documentation and reformats it to be + more usable and look like a dedicated documentation page." + (when (w3m-haddock-page-p) + (save-excursion + (goto-char (point-min)) + (let ((inhibit-read-only t)) + (delete-region (point) + (line-end-position)) + (w3m-haddock-next-heading) + ;; Start formatting entries + (while (looking-at w3m-haddock-entry-regex) + (when (w3m-haddock-valid-heading) + (w3m-haddock-format-heading)) + (w3m-haddock-next-heading)))) + (rename-buffer (concat "*haddock: " (w3m-buffer-title (current-buffer)) "*"))) + (when (w3m-haddock-source-p) + (font-lock-mode -1) + (let ((n (line-number-at-pos))) + (save-excursion + (goto-char (point-min)) + (forward-line 1) + (let ((text (buffer-substring (point) + (point-max))) + (inhibit-read-only t)) + (delete-region (point) + (point-max)) + (insert + (haskell-fontify-as-mode text + 'haskell-mode)))) + (goto-char (point-min)) + (forward-line (1- n))))) + +(defun w3m-haddock-format-heading () + "Format a haddock entry." + (let ((o (make-overlay (line-beginning-position) + (1- (save-excursion (w3m-haddock-header-end)))))) + (overlay-put o 'face 'w3m-haddock-heading-face)) + (let ((end (save-excursion + (w3m-haddock-next-heading) + (when (w3m-haddock-valid-heading) + (point))))) + (when end + (save-excursion + (w3m-haddock-header-end) + (indent-rigidly (point) + end + 4))))) + +(defun w3m-haddock-next-heading () + "Go to the next heading, or end of the buffer." + (forward-line 1) + (or (search-forward-regexp w3m-haddock-entry-regex nil t 1) + (goto-char (point-max))) + (goto-char (line-beginning-position))) + +(defun w3m-haddock-valid-heading () + "Is this a valid heading?" + (not (get-text-property (point) 'face))) + +(defun w3m-haddock-header-end () + "Go to the end of the header." + (search-forward-regexp "\n[ \n]")) + +(provide 'w3m-haddock) diff --git a/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/w3m-haddock.elc b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/w3m-haddock.elc new file mode 100644 index 000000000000..391a591249df --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/w3m-haddock.elc Binary files differ |