master fb5cf238a9d: New variable comment-start-line-regexp (bug#80837)
Sean Whitton <[email protected]> Wed, 29 Jul 2026 07:21:11 -0400 (EDT)
| Newsgroups | gmane.emacs.diffs |
|---|---|
| Message-ID | <[email protected]> |
branch: master commit fb5cf238a9da9e2b182d27e94fbee63a184fc02f Author: Yuan Fu <[email protected]> Commit: Sean Whitton <[email protected]> New variable comment-start-line-regexp (bug#80837) * lisp/newcomment.el (comment-start-line-regexp): New variable (bug#80837). * lisp/progmodes/c-ts-common.el (c-ts-common-comment-setup): * lisp/progmodes/cmake-ts-mode.el (cmake-ts-mode): * lisp/progmodes/dockerfile-ts-mode.el (dockerfile-ts-mode): * lisp/progmodes/elixir-ts-mode.el (elixir-ts-mode): * lisp/progmodes/go-ts-mode.el (go-work-ts-mode): * lisp/progmodes/json-ts-mode.el (json-ts-mode): * lisp/progmodes/lua-ts-mode.el (lua-ts-mode): * lisp/progmodes/php-ts-mode.el (php-ts-mode--comment-setup): * lisp/progmodes/python.el (python-base-mode): * lisp/progmodes/ruby-mode.el (ruby-base-mode): * lisp/progmodes/sh-script.el (sh-base-mode): * lisp/textmodes/mhtml-ts-mode.el (mhtml-ts-mode--comment-setup): * lisp/textmodes/toml-ts-mode.el (toml-ts-mode): * lisp/textmodes/yaml-ts-mode.el (yaml-ts-mode): Set it. * doc/emacs/programs.texi (Options for Comments): * etc/NEWS: Document it. * lisp/progmodes/c-ts-common.el (c-ts-common-comment-start-line-regexp): New variable. * lisp/treesit.el (newcomment): Require. (treesit--likely-line-comment-p): New function. (treesit-forward-comment): Use it. Make COUNT parameter non-optional. --- doc/emacs/programs.texi | 6 ++++++ etc/NEWS | 6 ++++++ lisp/newcomment.el | 13 +++++++++++++ lisp/progmodes/c-ts-common.el | 7 +++++++ lisp/progmodes/cmake-ts-mode.el | 1 + lisp/progmodes/dockerfile-ts-mode.el | 1 + lisp/progmodes/elixir-ts-mode.el | 1 + lisp/progmodes/go-ts-mode.el | 1 + lisp/progmodes/json-ts-mode.el | 1 + lisp/progmodes/lua-ts-mode.el | 4 ++++ lisp/progmodes/php-ts-mode.el | 3 +++ lisp/progmodes/python.el | 1 + lisp/progmodes/ruby-mode.el | 1 + lisp/progmodes/sh-script.el | 1 + lisp/textmodes/mhtml-ts-mode.el | 2 ++ lisp/textmodes/toml-ts-mode.el | 1 + lisp/textmodes/yaml-ts-mode.el | 1 + lisp/treesit.el | 26 ++++++++++++++++++++++++-- 18 files changed, 75 insertions(+), 2 deletions(-) diff --git a/doc/emacs/programs.texi b/doc/emacs/programs.texi index 7cf7b2ff96f..d5738d684a2 100644 --- a/doc/emacs/programs.texi +++ b/doc/emacs/programs.texi @@ -1385,6 +1385,12 @@ comments also. (Note that @samp{\\} is needed in Lisp syntax to include a @samp{\} in the string, which is needed to deny the first star its special meaning in regexp syntax. @xref{Regexp Backslash}.) +@vindex comment-start-line-regexp + Modes that support both line and block comments should also set +@code{comment-start-line-regexp} to a regexp that matches only line +comment starters. This lets Emacs distinguish between the two kinds of +comments. + @vindex comment-start @vindex comment-end When a comment command makes a new comment, it inserts the value of diff --git a/etc/NEWS b/etc/NEWS index 92033851c74..6282d8cf9f6 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -265,6 +265,12 @@ buffer as if it were newly created. +++ ** The new function 'markers-in' returns the set of markers in a region. ++++ +** New buffer-local variable 'comment-start-line-regexp'. +Modes that support both line and block comments should set this +variable to a regexp that matches only the start of line comments, so +Emacs can distinguish between line and block comments. + --- ** New variable 'completion-frontend-properties'. This variable generalizes the 'completion-lazy-hilit' variable added in diff --git a/lisp/newcomment.el b/lisp/newcomment.el index 1f8a38b586e..8db8d2969a5 100644 --- a/lisp/newcomment.el +++ b/lisp/newcomment.el @@ -128,6 +128,19 @@ by the close of the first pair.") ;;;###autoload (put 'comment-start-skip 'safe-local-variable 'stringp) +;;;###autoload +(defvar comment-start-line-regexp nil + "Regexp matching the start of a line comment. + +Unlike `comment-start-skip', which matches the start of any comment, +this regexp matches only the start of line comments (as opposed to block +comments), so it can be used to distinguish between the two. + +Modes that support both line and block comments should set this +variable.") +;;;###autoload +(put 'comment-start-line-regexp 'safe-local-variable 'stringp) + ;;;###autoload (defvar comment-end-skip nil "Regexp to match the end of a comment plus everything back to its body.") diff --git a/lisp/progmodes/c-ts-common.el b/lisp/progmodes/c-ts-common.el index d5e6b012fe7..461b6852a26 100644 --- a/lisp/progmodes/c-ts-common.el +++ b/lisp/progmodes/c-ts-common.el @@ -60,6 +60,11 @@ (* (syntax whitespace))) "The `comment-start-skip' used by `c-ts-common-comment-setup'.") +(defvar c-ts-common-comment-start-line-regexp + (rx (seq "/" (+ "/")) + (* (syntax whitespace))) + "The `comment-start-line-regexp' used by `c-ts-common-comment-setup'.") + (defun c-ts-common-looking-at-star (_n _p bol &rest _) "A tree-sitter simple indent matcher. Matches if there is a \"*\" after BOL." @@ -287,6 +292,7 @@ Set up: - `comment-start' - `comment-end' - `comment-start-skip' + - `comment-start-line-regexp' - `comment-end-skip' - `adaptive-fill-mode' - `adaptive-fill-first-line-regexp' @@ -298,6 +304,7 @@ Set up: (setq-local comment-start "// ") (setq-local comment-end "") (setq-local comment-start-skip c-ts-common-comment-start-skip) + (setq-local comment-start-line-regexp c-ts-common-comment-start-line-regexp) (setq-local comment-end-skip (rx (* (syntax whitespace)) (group (or (syntax comment-end) diff --git a/lisp/progmodes/cmake-ts-mode.el b/lisp/progmodes/cmake-ts-mode.el index 6abd92b5e1a..678f3b09678 100644 --- a/lisp/progmodes/cmake-ts-mode.el +++ b/lisp/progmodes/cmake-ts-mode.el @@ -229,6 +229,7 @@ Return nil if there is no name or if NODE is not a defun node." (setq-local comment-start "# ") (setq-local comment-end "") (setq-local comment-start-skip (rx "#" (* (syntax whitespace)))) + (setq-local comment-start-line-regexp comment-start-skip) ;; Defuns. (setq-local treesit-defun-type-regexp (rx (or "function" "macro") diff --git a/lisp/progmodes/dockerfile-ts-mode.el b/lisp/progmodes/dockerfile-ts-mode.el index b97ec89b99a..551bd1bcaee 100644 --- a/lisp/progmodes/dockerfile-ts-mode.el +++ b/lisp/progmodes/dockerfile-ts-mode.el @@ -176,6 +176,7 @@ Return nil if there is no name or if NODE is not a stage node." (setq-local comment-start "# ") (setq-local comment-end "") (setq-local comment-start-skip (rx "#" (* (syntax whitespace)))) + (setq-local comment-start-line-regexp comment-start-skip) ;; Imenu. (setq-local treesit-simple-imenu-settings diff --git a/lisp/progmodes/elixir-ts-mode.el b/lisp/progmodes/elixir-ts-mode.el index 9bda7f0046f..b040113b3dc 100644 --- a/lisp/progmodes/elixir-ts-mode.el +++ b/lisp/progmodes/elixir-ts-mode.el @@ -724,6 +724,7 @@ Return nil if NODE is not a defun node or doesn't have a name." (setq-local comment-start "# ") (setq-local comment-start-skip (rx "#" (* (syntax whitespace)))) + (setq-local comment-start-line-regexp comment-start-skip) (setq-local comment-end "") (setq-local comment-end-skip diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el index 8de6d0e0700..d7563c3bbf6 100644 --- a/lisp/progmodes/go-ts-mode.el +++ b/lisp/progmodes/go-ts-mode.el @@ -725,6 +725,7 @@ what the parent of the node would be if it were a node." (setq-local comment-start "// ") (setq-local comment-end "") (setq-local comment-start-skip (rx "//" (* (syntax whitespace)))) + (setq-local comment-start-line-regexp comment-start-skip) ;; Indent. (setq-local indent-tabs-mode t diff --git a/lisp/progmodes/json-ts-mode.el b/lisp/progmodes/json-ts-mode.el index 9575eaf6cf0..b2ffccecd76 100644 --- a/lisp/progmodes/json-ts-mode.el +++ b/lisp/progmodes/json-ts-mode.el @@ -198,6 +198,7 @@ PATH is a list of keys (strings) and indices (numbers)." ;; Comments. (setq-local comment-start "// ") (setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *") + (setq-local comment-start-line-regexp "//+\\s *") (setq-local comment-end "") ;; Electric diff --git a/lisp/progmodes/lua-ts-mode.el b/lisp/progmodes/lua-ts-mode.el index 2963d5a96af..a9666c97788 100644 --- a/lisp/progmodes/lua-ts-mode.el +++ b/lisp/progmodes/lua-ts-mode.el @@ -683,6 +683,10 @@ Calls REPORT-FN directly." ;; Comments. (setq-local comment-start "--") (setq-local comment-start-skip "--\\s-*") + (setq-local comment-start-line-regexp + (rx (seq "--" (or (not (any "[")) + (seq "[" (zero-or-more "=") + (not (any "=["))))))) (setq-local comment-end "") ;; Pairs. diff --git a/lisp/progmodes/php-ts-mode.el b/lisp/progmodes/php-ts-mode.el index dee26915a31..452a0bffc2f 100644 --- a/lisp/progmodes/php-ts-mode.el +++ b/lisp/progmodes/php-ts-mode.el @@ -1405,6 +1405,9 @@ If FORCE is t setup comment for PHP. Depends on (seq "/" (+ "/")) (seq "/" (+ "*"))) (* (syntax whitespace))) + comment-start-line-regexp + (rx (or (seq "#" (or eol (not (any "[")))) + (seq "/" (+ "/")))) ;; reset the state of mhtml-ts-mode--comment-setup mhtml-ts-mode--comment-current-lang nil)) ;; otherwise set comment style for other languages. diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 962f9c5a031..093a8049fdd 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -7358,6 +7358,7 @@ implementations: `python-mode' and `python-ts-mode'." (setq-local comment-start "# ") (setq-local comment-start-skip "#+\\s-*") + (setq-local comment-start-line-regexp comment-start-skip) (setq-local parse-sexp-lookup-properties t) (setq-local parse-sexp-ignore-comments t) diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index f2e38e0af46..ff33f0554ba 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el @@ -2693,6 +2693,7 @@ Currently there are `ruby-mode' and `ruby-ts-mode'." (setq-local comment-end "") (setq-local comment-column ruby-comment-column) (setq-local comment-start-skip "#+ *") + (setq-local comment-start-line-regexp comment-start-skip) (setq-local parse-sexp-ignore-comments t) (setq-local parse-sexp-lookup-properties t) diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el index f9d4310f367..79180da8718 100644 --- a/lisp/progmodes/sh-script.el +++ b/lisp/progmodes/sh-script.el @@ -1475,6 +1475,7 @@ implementations. Currently there are two: `sh-mode' and (setq-local paragraph-separate (concat paragraph-start "\\|#!/")) (setq-local comment-start "# ") (setq-local comment-start-skip "#+[\t ]*") + (setq-local comment-start-line-regexp comment-start-skip) (setq-local local-abbrev-table sh-mode-abbrev-table) (setq-local comint-dynamic-complete-functions sh-dynamic-complete-functions) diff --git a/lisp/textmodes/mhtml-ts-mode.el b/lisp/textmodes/mhtml-ts-mode.el index d53d74e220a..f126fbcac0d 100644 --- a/lisp/textmodes/mhtml-ts-mode.el +++ b/lisp/textmodes/mhtml-ts-mode.el @@ -362,11 +362,13 @@ Return nil if there is no name or if NODE is not a defun node." ('html (setq-local comment-start "<!-- ") (setq-local comment-start-skip nil) + (setq-local comment-start-line-regexp nil) (setq-local comment-end " -->") (setq-local comment-end-skip nil)) ('css (setq-local comment-start "/*") (setq-local comment-start-skip "/\\*+[ \t]*") + (setq-local comment-start-line-regexp nil) (setq-local comment-end "*/") (setq-local comment-end-skip "[ \t]*\\*+/")) ('javascript diff --git a/lisp/textmodes/toml-ts-mode.el b/lisp/textmodes/toml-ts-mode.el index 63e3f60edd9..b121d8917d1 100644 --- a/lisp/textmodes/toml-ts-mode.el +++ b/lisp/textmodes/toml-ts-mode.el @@ -146,6 +146,7 @@ Return nil if there is no name or if NODE is not a defun node." ;; Comments (setq-local comment-start "# ") (setq-local comment-end "") + (setq-local comment-start-line-regexp "#+ *") ;; Indent. (setq-local treesit-simple-indent-rules toml-ts-mode--indent-rules) diff --git a/lisp/textmodes/yaml-ts-mode.el b/lisp/textmodes/yaml-ts-mode.el index 37925f69782..95fd4b6a78a 100644 --- a/lisp/textmodes/yaml-ts-mode.el +++ b/lisp/textmodes/yaml-ts-mode.el @@ -271,6 +271,7 @@ Calls REPORT-FN directly." (setq-local comment-start "# ") (setq-local comment-end "") (setq-local comment-start-skip "#+ *") + (setq-local comment-start-line-regexp comment-start-skip) ;; Indentation. (setq-local indent-tabs-mode nil) diff --git a/lisp/treesit.el b/lisp/treesit.el index 107b41abef6..8a1fb1ca86c 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -59,6 +59,7 @@ (require 'font-lock) (require 'seq) (require 'prog-mode) ; For `prog--text-at-point-or-region-p'. +(require 'newcomment) ; For `comment-start-line-regexp'. ;;; Function declarations @@ -3764,7 +3765,20 @@ by `text' and `sentence' in `treesit-thing-settings'." (max (point-min) (previous-single-char-property-change (point) 'treesit-parser))))))) -(defun treesit-forward-comment (&optional count) +(defun treesit--likely-line-comment-p (node) + "Return non-nil if NODE is likely a line comment." + (save-excursion + (goto-char (treesit-node-start node)) + (if comment-start-line-regexp + (looking-at-p comment-start-line-regexp) + ;; Without `comment-start-line-regexp', it's kind of best-effort. + (and comment-start + ;; If `comment-end' is non-empty, `comment-start' must be + ;; paired with it. + (string-empty-p (string-trim (or comment-end ""))) + (looking-at-p (regexp-quote (string-trim-right comment-start))))))) + +(defun treesit-forward-comment (count) "Tree-sitter `forward-comment-function' implementation. COUNT is the same as in `forward-comment'." @@ -3774,7 +3788,15 @@ COUNT is the same as in `forward-comment'." (setq thing (treesit-thing-at (point) 'comment)) (if (and thing (eq (point) (treesit-node-start thing))) (progn - (goto-char (min (1+ (treesit-node-end thing)) (point-max))) + (goto-char (treesit-node-end thing)) + ;; For line comments, go to the next line. This is + ;; important because a) for navigation convenience, and b) + ;; many functions expect `forward-comment' to behave this + ;; way (bug#80837). + (when (treesit--likely-line-comment-p thing) + (skip-chars-forward " \t") + (when (looking-at-p "\n") + (forward-char))) (setq count (1- count))) (setq count 0 res nil))) (while (< count 0)