diff --git a/README.md b/README.md index 813b577..0942413 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ are standard Emacs keybindings, backed by the AST rather than heuristics: | `M-a` | `backward-sentence` | Move to the previous top-level declaration (Emacs 30+)| | `M-e` | `forward-sentence` | Move to the next top-level declaration (Emacs 30+) | + "Definitions" include function bindings, type signatures, data types, newtypes, type synonyms, classes, instances, and imports. "Statements" (sentences) cover the same set, enabling `M-a`/`M-e` to jump between top-level declarations. @@ -158,9 +159,63 @@ The font-lock features available at each level are: - `bracket` -- parentheses, brackets, braces - `delimiter` -- commas and semicolons - - - +#### Selecting features + +You don't have to use the level system. If you want fine-grained control over +what gets highlighted, cherry-pick individual features using +`treesit-font-lock-recompute-features`: + +```emacs-lisp +(defun my-curry-font-lock-setup () + (treesit-font-lock-recompute-features + ;; enable these features + '(comment definition keyword string number + type constructor module + operator variable function) + ;; disable these features + '(bracket delimiter))) + +(add-hook 'curry-base-mode-hook #'my-curry-font-lock-setup) +``` + +#### Customizing faces + +The faces used are standard `font-lock-*-face` faces, so any theme applies +automatically. For buffer-local customization (only affects Haskell buffers): + +```emacs-lisp +(add-hook 'curry-base-mode-hook + (lambda () + (face-remap-add-relative 'font-lock-type-face + :foreground "DarkSeaGreen4"))) +``` + +#### Adding custom font-lock rules + +For distinctions that curry-mode doesn't make by default, layer additional +tree-sitter font-lock rules via a hook: + +```emacs-lisp +(defface my-haskell-keyword-face + '((t :inherit font-lock-keyword-face :weight bold)) + "Face for certain Haskell keywords.") + +(defun my-curry-extra-keywords () + (setq treesit-font-lock-settings + (append treesit-font-lock-settings + (treesit-font-lock-rules + :language 'haskell + :override t + :feature 'keyword + '(["where" "let" "in" "do"] + @my-haskell-keyword-face)))) + (treesit-font-lock-recompute-features)) + +(add-hook 'curry-base-mode-hook #'my-curry-extra-keywords) +``` + +Use `M-x treesit-explore-mode` to inspect the syntax tree and find the right +node types to match. #### Prettify Symbols @@ -254,7 +309,16 @@ hook: (add-hook 'curry-base-mode-hook #'outline-minor-mode) ``` - +For tree-sitter-aware code folding (fold any node, not just top-level +definitions), [treesit-fold](https://github.com/emacs-tree-sitter/treesit-fold) +is supported out of the box. curry-mode automatically registers with +treesit-fold's Haskell fold definitions when the package is loaded: + +```emacs-lisp +(use-package treesit-fold + :ensure t + :hook (curry-base-mode . treesit-fold-mode)) +``` ### Structural Selection diff --git a/curry-mode.el b/curry-mode.el index 24fc0de..1189090 100644 --- a/curry-mode.el +++ b/curry-mode.el @@ -975,6 +975,16 @@ This mode is not intended to be used directly. Use `curry-mode'." :entryArgs [] :extraGhcArgs []))) +;; treesit-fold integration for code folding. +;; Registers curry-mode with the Haskell fold definitions when +;; treesit-fold is loaded. +(with-eval-after-load 'treesit-fold + (defvar treesit-fold-range-alist) + (declare-function treesit-fold-parsers-haskell "treesit-fold") + (unless (alist-get 'curry-mode treesit-fold-range-alist) + (push `(curry-mode . ,(treesit-fold-parsers-haskell)) + treesit-fold-range-alist))) + (provide 'curry-mode) ;;; curry-mode.el ends here