branch: elpa/haskell-tng-mode commit c2a5b641b95268542a77e2771c4b49659565b08b Author: Tseen She <ts33n....@gmail.com> Commit: Tseen She <ts33n....@gmail.com>
cleaner import fontification --- README.md | 10 ++++------ haskell-tng-font-lock.el | 43 ++++++++++++++++++++++++++----------------- haskell-tng-mode.el | 7 +++++-- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index ad3fc08..b9e636e 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,12 @@ # Haskell Mode: The Next Generation -This is an exploratory alternative to [`haskell-mode`](https://github.com/haskell/haskell-mode/) that answers the question - -> How would we support Haskell in GNU Emacs if we started today? +This is an exploratory alternative to [`haskell-mode`](https://github.com/haskell/haskell-mode/) that answers the question *how would we support Haskell in GNU Emacs if we started today?* ## Why? -`haskell-mode` is almost 30 years old and has accumulated more than 25,000 lines of code. Nobody wants to maintain that. +`haskell-mode` is almost 30 years old and has accumulated more than 25,000 lines of code. It's too much to handle. -The GNU Emacs ecosystem has evolved to provide many features that `haskell-mode` independently implemented, such as [`projectile`](https://github.com/bbatsov/projectile), [`comint-mode`](https://masteringemacs.org/article/comint-writing-command-interpreter), [`highlight-symbol`](https://melpa.org/##/highlight-symbol), [`company-mode`](http://company-mode.github.io), [`yasnippet`](http://joaotavora.github.io/yasnippet/), [`polymode`](https://github.com/polymode/polymode), [`smartparens`]( [...] +Meanwhile, the GNU Emacs ecosystem has evolved to provide many features that `haskell-mode` independently implemented, such as [`projectile`](https://github.com/bbatsov/projectile), [`comint-mode`](https://masteringemacs.org/article/comint-writing-command-interpreter), [`highlight-symbol`](https://melpa.org/##/highlight-symbol), [`pretty-symbols`](https://github.com/drothlis/pretty-symbols), [`company-mode`](http://company-mode.github.io), [`yasnippet`](http://joaotavora.github.io/yasnip [...] ## Approach @@ -54,7 +52,7 @@ This is the status of core features: - [ ] `yasnippet` templates - [ ] `smartparens` compatibility (or something from stdlib) - [ ] `LANGUAGE` management - - [ ] `import` management + - [ ] `import` management (via hoogle and [`hsimport`](https://hackage.haskell.org/package/hsimport)) - Compiling: - [ ] `haskell-compile` for build tool agnostic interaction with `ghc` - [ ] `comint-mode` based `ghc` repl diff --git a/haskell-tng-font-lock.el b/haskell-tng-font-lock.el index a357192..7be03a2 100644 --- a/haskell-tng-font-lock.el +++ b/haskell-tng-font-lock.el @@ -14,6 +14,12 @@ ;; parsing, but until that day, we do it the idiomatic Emacs way (with hacks ;; and more hacks). ;; +;; We try very hard to use only single line fontifications, since multiline +;; introduces both a performance and maintenance penalty. For this reason, some +;; very unusual styles of Haskell, although valid, may not be supported. For +;; example, comments in unusual positions and line breaks after contextual +;; markers (e.g. multiline imports may pick up incorrect colours). +;; ;; https://www.gnu.org/software/emacs/manual/html_mono/elisp.html#Font-Lock-Mode ;; ;;; Code: @@ -47,17 +53,17 @@ ;; TODO: pragmas ;; ;; TODO: numeric / char primitives? - -;; FIXME: consider using rx instead of regexes... there are a lot of escapes -;; that obfuscate the meaning, plus we could use DRY. +;; +;; TODO: haddock (setq haskell-tng:keywords ;; These regexps use the `rx' library so we can reuse common subpatterns. It ;; also increases the readability of the code and, in many cases, allows us to ;; do more work in a single regexp instead of multiple passes. - (let ((conid '(: upper (* wordchar))) - (consym '(: ":" (+ (syntax symbol))))) + (let* ((conid '(: upper (* wordchar))) + (qual `(: (+ (: ,conid (char ?.))))) + (consym '(: ":" (+ (syntax symbol))))) `(;; reservedid / reservedop (,(rx-to-string '(| @@ -73,20 +79,23 @@ (: symbol-start (char ?\\)))) . 'haskell-tng:keyword) - ;; TODO: anchored matchers - ;; TODO: contextual / multiline support for the import region. - ;; qualified/hiding/as are keywords when used in imports - ("\\_<import\\_>[[:space:]]+\\_<\\(qualified\\)\\_>" 1 'haskell-tng:keyword) - ("\\_<import\\_>[^(]+?\\_<\\(hiding\\|as\\)\\_>" 1 'haskell-tng:keyword) - ("\\_<import\\_>\\(?:[[:space:]]\\|qualified\\)+\\_<\\([[:upper:]]\\(?:\\.\\|\\w\\)*\\)\\_>" - 1 'haskell-tng:module) - ("\\_<import\\_>[^(]+?\\_<as[[:space:]]+\\([[:upper:]]\\w+\\)" + ;; modules + (,(rx-to-string `(: symbol-start "module" symbol-end (+ space) + symbol-start (group (opt ,qual) ,conid) symbol-end)) 1 'haskell-tng:module) - ;; introducing modules - (,(rx-to-string '(: symbol-start "module" symbol-end (+ space) - symbol-start (group upper (* wordchar)) symbol-end)) - 1 'haskell-tng:module) + ;; imports + (,(rx-to-string '(: word-start "import" word-end)) ;; anchor matcher + (,(rx-to-string `(: point (+ space) (group word-start "qualified" word-end))) + nil nil (1 'haskell-tng:keyword)) + (,(rx-to-string `(: point + (opt (+ space) word-start "qualified" word-end) + (+ space) word-start (group (opt ,qual) ,conid) word-end)) + nil nil (1 'haskell-tng:module)) + (,(rx-to-string `(: point (+? (not (any ?\())) + word-start (group (| "hiding" "as")) word-end + (opt (+ space) word-start (group ,conid) word-end))) + nil nil (1 'haskell-tng:keyword) (2 'haskell-tng:module nil t))) ;; uses of F.Q.N.s (,(rx-to-string `(: symbol-start (+ (: ,conid ".")))) diff --git a/haskell-tng-mode.el b/haskell-tng-mode.el index 4cd0798..1887637 100644 --- a/haskell-tng-mode.el +++ b/haskell-tng-mode.el @@ -27,9 +27,12 @@ ;; TODO paragraph-start, paragraph-separate, fill-paragraph-function ;; ;; TODO comment-start, comment-padding, comment-start-skip, comment-end, - ;; comment-end-skip, comment-auto-fill-only-comments, parse-sexp-ignore-comments + ;; comment-end-skip, comment-auto-fill-only-comments, + ;; parse-sexp-ignore-comments (it is annoying that we must specify + ;; comments here AND in the syntax table) ;; - ;; (it is annoying that we specify comments here AND in the syntax table) + ;; TODO mark-defun + ;; TODO font-lock-mark-block-function (setq ;; TAB is evil