diff options
Diffstat (limited to 'configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-completions.el')
-rw-r--r-- | configs/shared/emacs/.emacs.d/elpa/haskell-mode-20180601.143/haskell-completions.el | 393 |
1 files changed, 393 insertions, 0 deletions
diff --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 |