diff --git a/CHANGELOG.md b/CHANGELOG.md index 59ed35b..7055075 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,8 @@ - [#170](https://github.com/clojure-emacs/clojure-ts-mode/pull/170): Add the `let*` semantic indentation rule from cljfmt. - [#171](https://github.com/clojure-emacs/clojure-ts-mode/pull/171): Highlight the names of methods (in `defrecord`, `reify` and the like) and of `letfn` functions as definitions at `treesit-font-lock-level` 4, where they were colored as function calls. - [#171](https://github.com/clojure-emacs/clojure-ts-mode/pull/171): Highlight Markdown in the docstrings of the forms in `clojure-ts-extra-def-forms`. +- [#172](https://github.com/clojure-emacs/clojure-ts-mode/pull/172): Fix `clojure-ts-outline-variant` and `clojure-ts-completion-enabled` being ignored in `.dir-locals.el`. +- [#172](https://github.com/clojure-emacs/clojure-ts-mode/pull/172): Stop marking `clojure-ts-ensure-grammars`, `clojure-ts-auto-remap` and the options that turn the embedded parsers on and off as safe in `.dir-locals.el`, where they have no effect. ## 0.6.0 (2025-12-02) diff --git a/clojure-ts-mode.el b/clojure-ts-mode.el index ca8f416..c3239c3 100644 --- a/clojure-ts-mode.el +++ b/clojure-ts-mode.el @@ -102,7 +102,6 @@ itself." (defcustom clojure-ts-ensure-grammars t "When non-nil, ensure required Tree-sitter grammars are installed." - :safe #'booleanp :type 'boolean :package-version '(clojure-ts-mode . "0.2.0")) @@ -130,30 +129,25 @@ double quotes on the third column." (defcustom clojure-ts-use-markdown-inline t "When non-nil, use Markdown inline grammar for docstrings." :type 'boolean - :safe #'booleanp :package-version '(clojure-ts-mode . "0.2.3")) (defcustom clojure-ts-use-regex-parser t "When non-nil, use separate grammar to highlight regex syntax." :type 'boolean - :safe #'booleanp :package-version '(clojure-ts-mode . "0.4")) (defcustom clojure-ts-clojurescript-use-js-parser t "When non-nil, use JS grammar to highlight syntax in js* forms." :type 'boolean - :safe #'booleanp :package-version '(clojure-ts-mode . "0.5")) (defcustom clojure-ts-jank-use-cpp-parser t "When non-nil, use C++ grammar to highlight syntax in cpp/raw forms." :type 'boolean - :safe #'booleanp :package-version '(clojure-ts-mode . "0.5")) (defcustom clojure-ts-auto-remap t "When non-nil, redirect all `clojure-mode' buffers to `clojure-ts-mode'." - :safe #'booleanp :type 'boolean :package-version '(clojure-ts-mode . "0.3")) @@ -163,7 +157,7 @@ double quotes on the third column." If set to the symbol `comments', then top-level comments starting with three or more semicolons will be treated as outline headings. If set to `imenu', then def-like forms are treated as outline headings." - :safe #'symbolp + :safe (lambda (value) (memq value '(comments imenu))) :type '(choice (const :tag "Use special comments" comments) (const :tag "Use imenu" imenu)) :package-version '(clojure-ts-mode . "0.4")) @@ -1785,12 +1779,6 @@ function literal." "Return non-nil if NODE is a function or a var definition." (clojure-ts--list-node-sym-match-p node clojure-ts--defun-symbols-regex)) -(defconst clojure-ts--markdown-inline-sexp-nodes - '("inline_link" "full_reference_link" "collapsed_reference_link" - "uri_autolink" "email_autolink" "shortcut_link" "image" - "code_span") - "Nodes representing s-expressions in the `markdown-inline' parser.") - (defun clojure-ts--default-sexp-node-p (node) "Return non-nil if point is after the # marker of set or function literal NODE." (and (eq (char-before) ?\#) @@ -1808,10 +1796,7 @@ function literal." ;; For `C-M-f' in "#|(a)" or "#|{1 2 3}" (,(rx (or "(" "{")) . ,#'clojure-ts--default-sexp-node-p)) (text ,(regexp-opt '("comment"))) - (defun ,#'clojure-ts--defun-node-p)) - (when clojure-ts-use-markdown-inline - (markdown-inline - (sexp ,(regexp-opt clojure-ts--markdown-inline-sexp-nodes)))))) + (defun ,#'clojure-ts--defun-node-p)))) ;;; Vertical alignment @@ -3440,6 +3425,23 @@ the same features enabled in MODE." ;; (plist-get configs :simple-indent))) )) +(defun clojure-ts--setup-outline () + "Set up `outline-minor-mode' for the variant in `clojure-ts-outline-variant'." + (if (eq clojure-ts-outline-variant 'comments) + (setq-local treesit-outline-predicate #'clojure-ts--outline-predicate + outline-level #'clojure-ts--outline-level) + (setq-local treesit-outline-predicate #'treesit-outline-predicate--from-imenu + outline-level #'treesit-outline-level)) + (setq-local outline-search-function #'treesit-outline-search)) + +(defun clojure-ts--setup-completion () + "Add or remove the completion function, following `clojure-ts-completion-enabled'." + (if clojure-ts-completion-enabled + (add-hook 'completion-at-point-functions + #'clojure-ts-completion-at-point-function nil 'local) + (remove-hook 'completion-at-point-functions + #'clojure-ts-completion-at-point-function 'local))) + (defun clojure-ts-mode-variables (&optional markdown-available regex-available) "Initialize buffer-local variables for `clojure-ts-mode'. @@ -3448,13 +3450,7 @@ REGEX-AVAILABLE." (setq-local indent-tabs-mode nil) (setq-local comment-add 1) (setq-local comment-start ";") - (when (equal clojure-ts-outline-variant 'comments) - ;; NOTE: If `imenu' option is selected for `clojure-ts-outline-variant', all - ;; necessary variables will be set automatically by - ;; `treesit-major-mode-setup'. - (setq-local treesit-outline-predicate #'clojure-ts--outline-predicate - outline-search-function #'treesit-outline-search - outline-level #'clojure-ts--outline-level)) + (clojure-ts--setup-outline) (setq-local clojure-ts-expected-ns-function #'clojure-ts-expected-ns) @@ -3489,15 +3485,17 @@ REGEX-AVAILABLE." (when (boundp 'treesit-thing-settings) ;; Emacs 30+ (setq-local treesit-thing-settings clojure-ts--thing-settings)) - (when clojure-ts-completion-enabled - (add-hook 'completion-at-point-functions - #'clojure-ts-completion-at-point-function nil 'local))) + (clojure-ts--setup-completion)) (defun clojure-ts--apply-local-variables () "Redo the parts of the setup that depend on file or directory-local variables. Those are set after the major mode." (when (local-variable-p 'clojure-ts-indent-style) - (setq-local treesit-simple-indent-rules (clojure-ts--configured-indent-rules)))) + (setq-local treesit-simple-indent-rules (clojure-ts--configured-indent-rules))) + (when (local-variable-p 'clojure-ts-outline-variant) + (clojure-ts--setup-outline)) + (when (local-variable-p 'clojure-ts-completion-enabled) + (clojure-ts--setup-completion))) (defun clojure-ts--major-mode-setup () "Run `treesit-major-mode-setup', then override some of its settings. diff --git a/test/clojure-ts-mode-config-test.el b/test/clojure-ts-mode-config-test.el index 43057e1..5feb918 100644 --- a/test/clojure-ts-mode-config-test.el +++ b/test/clojure-ts-mode-config-test.el @@ -174,7 +174,9 @@ y) (write-region "((clojure-ts-mode . ((clojure-ts-indent-style . fixed) (clojure-ts-align-forms-automatically . t) (clojure-ts-extra-def-forms . (\"defelem\")) - (clojure-ts-comment-macro-font-lock-body . t))))" + (clojure-ts-comment-macro-font-lock-body . t) + (clojure-ts-outline-variant . imenu) + (clojure-ts-completion-enabled . nil))))" nil (expand-file-name ".dir-locals.el" project-dir)) (dolist (dir (list project-dir other-dir)) (write-region clojure-ts-test--options-source nil @@ -193,7 +195,11 @@ y) ;; Fixed indentation and aligned map values. (expect (buffer-string) :to-match "(foo\n bar)") (expect (buffer-string) :to-match "(my-block x\n y)") - (expect (buffer-string) :to-match "{:a 1\n :bbb 2}")) + (expect (buffer-string) :to-match "{:a 1\n :bbb 2}") + (expect treesit-outline-predicate + :to-be #'treesit-outline-predicate--from-imenu) + (expect completion-at-point-functions + :not :to-contain #'clojure-ts-completion-at-point-function)) (with-current-buffer other-buffer (font-lock-ensure) (expect (clojure-ts-test--face-at "defelem") @@ -203,10 +209,29 @@ y) (indent-region (point-min) (point-max)) (expect (buffer-string) :to-match "(foo\n bar)") (expect (buffer-string) :to-match "(my-block x\n y)") - (expect (buffer-string) :to-match "{:a 1\n :bbb 2}"))) + (expect (buffer-string) :to-match "{:a 1\n :bbb 2}") + (expect treesit-outline-predicate + :to-be #'clojure-ts--outline-predicate) + (expect completion-at-point-functions + :to-contain #'clojure-ts-completion-at-point-function))) (kill-buffer project-buffer) (kill-buffer other-buffer))))))) +(describe "options read when the mode starts" + (it "should not be safe as directory-local variables, as they can't apply there" + (dolist (option '(clojure-ts-ensure-grammars + clojure-ts-use-markdown-inline + clojure-ts-use-regex-parser + clojure-ts-clojurescript-use-js-parser + clojure-ts-jank-use-cpp-parser + clojure-ts-auto-remap)) + (expect (safe-local-variable-p option nil) :not :to-be-truthy)))) + +(describe "clojure-ts-outline-variant" + (it "should only be safe as a directory-local variable with a valid value" + (expect (safe-local-variable-p 'clojure-ts-outline-variant 'imenu) :to-be-truthy) + (expect (safe-local-variable-p 'clojure-ts-outline-variant 'imenus) :not :to-be-truthy))) + (describe "options set with setopt" (it "should apply to the open buffers, even when set from another buffer" (with-clojure-ts-buffer clojure-ts-test--options-source