From e7ec97fc8a33e87f6762174683ad76a7c4e8a7f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arthur=20Fayzrakhmanov=20=28=D0=90=D1=80=D1=82=D1=83=D1=80?= =?UTF-8?q?=20=D0=A4=D0=B0=D0=B9=D0=B7=D1=80=D0=B0=D1=85=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=29?= Date: Sun, 21 Feb 2016 23:06:37 +0500 Subject: [PATCH 1/7] Define haskell keywords list --- haskell-completions.el | 51 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/haskell-completions.el b/haskell-completions.el index 5405f2ff4..14ac7fe4f 100644 --- a/haskell-completions.el +++ b/haskell-completions.el @@ -1,6 +1,6 @@ ;;; haskell-completions.el --- Haskell Completion package -*- lexical-binding: t -*- -;; Copyright © 2015 Athur Fayzrakhmanov. All rights reserved. +;; 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: @@ -63,8 +63,51 @@ "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'. -") +`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" + "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. @@ -206,7 +249,7 @@ identifier at point depending on result of function 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 +arbitrary identifier, etc. Returns nil in case it is impossible to grab prefix. If provided optional MINLEN parameter this function will return From 9d0459edc252d1377a951ca22d46ade7cc98cbf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arthur=20Fayzrakhmanov=20=28=D0=90=D1=80=D1=82=D1=83=D1=80?= =?UTF-8?q?=20=D0=A4=D0=B0=D0=B9=D0=B7=D1=80=D0=B0=D1=85=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=29?= Date: Sun, 21 Feb 2016 23:07:12 +0500 Subject: [PATCH 2/7] Rename haskell-completions-pragma-names Denote internal nature of this variable by double dash --- haskell-completions.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/haskell-completions.el b/haskell-completions.el index 14ac7fe4f..c53a7f1b4 100644 --- a/haskell-completions.el +++ b/haskell-completions.el @@ -40,7 +40,7 @@ (require 'haskell-process) (require 'haskell-interactive-mode) -(defvar haskell-completions-pragma-names +(defvar haskell-completions--pragma-names (list "DEPRECATED" "INCLUDE" "INCOHERENT" @@ -276,7 +276,7 @@ Returns nil if no completions available." (cl-case typ ;; non-interactive completions first ('haskell-completions-pragma-name-prefix - haskell-completions-pragma-names) + haskell-completions--pragma-names) ('haskell-completions-ghc-option-prefix haskell-ghc-supported-options) ('haskell-completions-language-extension-prefix From 8ca1af70378bbb06290c7e4613a83ee8e187f071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arthur=20Fayzrakhmanov=20=28=D0=90=D1=80=D1=82=D1=83=D1=80?= =?UTF-8?q?=20=D0=A4=D0=B0=D0=B9=D0=B7=D1=80=D0=B0=D1=85=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=29?= Date: Sun, 21 Feb 2016 23:08:41 +0500 Subject: [PATCH 3/7] Define non-interactive completion function --- haskell-completions.el | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/haskell-completions.el b/haskell-completions.el index c53a7f1b4..62c8c0908 100644 --- a/haskell-completions.el +++ b/haskell-completions.el @@ -263,6 +263,38 @@ result only if prefix length is not less than 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 + (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 + haskell-completions--keywords)))) + (list beg end candidates)))) + + +(defun haskell-completions-completion-at-point () + "Provide a list of completion candidates. +This function is supposed to be used in non-interactive context. +It provides completions for haskell keywords, language pragmas, +GHC's options, and language extensions, but not identifiers." + (let ((prefix (haskell-completions-grab-prefix))) + (haskell-completions--simple-completions prefix))) (defun haskell-completions-sync-completions-at-point () "A `completion-at-point' function using the current haskell process. From f2f90d40a2a652b5d2586def60b3eb9da028cffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arthur=20Fayzrakhmanov=20=28=D0=90=D1=80=D1=82=D1=83=D1=80?= =?UTF-8?q?=20=D0=A4=D0=B0=D0=B9=D0=B7=D1=80=D0=B0=D1=85=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=29?= Date: Sun, 21 Feb 2016 23:15:32 +0500 Subject: [PATCH 4/7] Add completions hook --- haskell-mode.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/haskell-mode.el b/haskell-mode.el index e19a37369..c76fb7ca1 100644 --- a/haskell-mode.el +++ b/haskell-mode.el @@ -783,6 +783,11 @@ Minor modes that work well with `haskell-mode': (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)) (defun haskell-fill-paragraph (justify) From 6dff9d0acc91db9fb39764f03fd1c5225c2cc362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arthur=20Fayzrakhmanov=20=28=D0=90=D1=80=D1=82=D1=83=D1=80?= =?UTF-8?q?=20=D0=A4=D0=B0=D0=B9=D0=B7=D1=80=D0=B0=D1=85=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=29?= Date: Mon, 22 Feb 2016 01:41:02 +0500 Subject: [PATCH 5/7] Improve docstring --- haskell-completions.el | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/haskell-completions.el b/haskell-completions.el index 62c8c0908..fb6f1fa77 100644 --- a/haskell-completions.el +++ b/haskell-completions.el @@ -252,6 +252,17 @@ 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) From e644b7abc9bea3bb7182f4dc143ae4938e504345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arthur=20Fayzrakhmanov=20=28=D0=90=D1=80=D1=82=D1=83=D1=80?= =?UTF-8?q?=20=D0=A4=D0=B0=D0=B9=D0=B7=D1=80=D0=B0=D1=85=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=29?= Date: Mon, 22 Feb 2016 01:41:59 +0500 Subject: [PATCH 6/7] Rename and rewrite REPL based completion funciton Make use of implemented simple completion funciton. Complete keywords. --- haskell-completions.el | 49 +++++++++++++++++++++--------------------- haskell.el | 4 ++-- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/haskell-completions.el b/haskell-completions.el index fb6f1fa77..b3b0c129f 100644 --- a/haskell-completions.el +++ b/haskell-completions.el @@ -307,35 +307,36 @@ GHC's options, and language extensions, but not identifiers." (let ((prefix (haskell-completions-grab-prefix))) (haskell-completions--simple-completions prefix))) -(defun haskell-completions-sync-completions-at-point () +(defun haskell-completions-sync-repl-completion-at-point () "A `completion-at-point' function using the current haskell process. 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 - (let ((imp (eql typ 'haskell-completions-module-name-prefix)) - lst) - (setq lst - (cl-case typ - ;; non-interactive completions first - ('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 - (when (and - (not (eql typ 'haskell-completions-general-prefix)) - (haskell-session-maybe) - (not - (haskell-process-cmd (haskell-interactive-process)))) - ;; 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 imp))))) - (when lst - (list beg end lst))))))) + (when (not (eql typ 'haskell-completions-general-prefix)) + ;; 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)))) + ;; 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. diff --git a/haskell.el b/haskell.el index 0ffaa9643..f977fd206 100644 --- a/haskell.el +++ b/haskell.el @@ -67,12 +67,12 @@ :lighter " Interactive" :keymap interactive-haskell-mode-map (add-hook 'completion-at-point-functions - #'haskell-completions-sync-completions-at-point + #'haskell-completions-sync-repl-completion-at-point nil t)) (make-obsolete 'haskell-process-completions-at-point - 'haskell-completions-sync-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." From c990a4f25f67ae48950abf5a86a909801fc96ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arthur=20Fayzrakhmanov=20=28=D0=90=D1=80=D1=82=D1=83=D1=80?= =?UTF-8?q?=20=D0=A4=D0=B0=D0=B9=D0=B7=D1=80=D0=B0=D1=85=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=29?= Date: Mon, 22 Feb 2016 20:52:45 +0500 Subject: [PATCH 7/7] Improve docstrings a bit --- haskell-completions.el | 16 ++++++++++++---- haskell-interactive-mode.el | 3 ++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/haskell-completions.el b/haskell-completions.el index b3b0c129f..54e8327cd 100644 --- a/haskell-completions.el +++ b/haskell-completions.el @@ -300,15 +300,23 @@ PREFIX should be a list such one returned by (defun haskell-completions-completion-at-point () - "Provide a list of completion candidates. -This function is supposed to be used in non-interactive context. -It provides completions for haskell keywords, language pragmas, + "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))) (haskell-completions--simple-completions prefix))) (defun haskell-completions-sync-repl-completion-at-point () - "A `completion-at-point' function using the current haskell process. + "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 diff --git a/haskell-interactive-mode.el b/haskell-interactive-mode.el index 20b667a1c..5135f9ea2 100644 --- a/haskell-interactive-mode.el +++ b/haskell-interactive-mode.el @@ -1016,7 +1016,8 @@ don't care when the thing completes as long as it's soonish." (remove-overlays)))) (defun haskell-interactive-mode-completion-at-point-function () - "Offer completions for partial expression between prompt and point" + "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))