master 388717429c9: New variable comment-start-line-regexp (bug#80837)

Sean Whitton <[email protected]>
Newsgroups gmane.emacs.diffs
Message-ID <[email protected]>
branch: master
commit 388717429c9c9a5eb2900953c07891f6fcb2046f
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 7a788d8c7da..9ddf8d41028 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -305,6 +305,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 8f7a37feeee..dce24949b5f 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)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.