Commit 9c8e8248 authored by Stefan Kangas's avatar Stefan Kangas
Browse files

Merge from origin/emacs-29

b3814b43 (ruby-ts--predefined-variables): Fix the $` and $' entries
db02cbdf * lisp/find-dired.el (find-dired-with-command): Quote fin...
2343a067 Generalize vc-pull-and-push to support more backends (bug...
846838db Add test suite for sgml-html-meta-auto-coding-function
0fb90f52 Fix decoding HTML files from archives
c854ef7a ; Fix last change (bug#60556).
8e83604d Avoid crashes in batch Emacs sub-processes on MS-Windows
808e101f Tweak BSD style indentation (bug#60984)
204519a2 Fix typo of exposed symbol name
9296e0c6 Fix typo after move to common lib (bug#61001)
e74ba72a ruby-ts-mode: Fix two additional cases with ruby-method-c...
ae7e28a4 ruby-mode.el: Expand some docstrings with examples
89cb3c3f Minor fixes for Haiku
6adc193a Move c-like common utils into own library (bug#60961)

# Conflicts:
#	lisp/progmodes/typescript-ts-mode.el
parents b767a641 b3814b43
Pipeline #22926 failed with stages
in 1 minute and 36 seconds
......@@ -209,7 +209,7 @@ it finishes, type \\[kill-find]."
" . \\( \\) "
(find-dired--escaped-ls-option))
(+ 1 (length find-program) (length " . \\( ")))
find-command-history)))
'find-command-history)))
(let ((dired-buffers dired-buffers))
;; Expand DIR ("" means default-directory), and make sure it has a
;; trailing slash.
......
......@@ -2189,7 +2189,7 @@ frame's display)."
This means that, for example, DISPLAY can differentiate between
the keybinding RET and [return]."
(let ((frame-type (framep-on-display display)))
(or (memq frame-type '(x w32 ns pc pgtk))
(or (memq frame-type '(x w32 ns pc pgtk haiku))
;; MS-DOS and MS-Windows terminals have built-in support for
;; function (symbol) keys
(memq system-type '(ms-dos windows-nt)))))
......
......@@ -2540,6 +2540,10 @@ This function is intended to be added to `auto-coding-functions'."
(bfcs-type
(coding-system-type buffer-file-coding-system)))
(if (and enable-multibyte-characters
;; 'charset' will signal an error in
;; coding-system-equal, since it isn't a
;; coding-system. So test that up front.
(not (equal sym-type 'charset))
(coding-system-equal 'utf-8 sym-type)
(coding-system-equal 'utf-8 bfcs-type))
buffer-file-coding-system
......
;;; c-ts-common.el --- Utilities for C like Languages -*- lexical-binding: t; -*-
;; Copyright (C) 2023 Free Software Foundation, Inc.
;; Author : 付禹安 (Yuan Fu) <casouri@gmail.com>
;; Keywords : c c++ java javascript rust languages tree-sitter
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;
;; For C-like language major modes:
;;
;; - Use `c-ts-common-comment-setup' to setup comment variables and
;; filling.
;;
;; - Use simple-indent matcher `c-ts-common-looking-at-star' and
;; anchor `c-ts-common-comment-start-after-first-star' for indenting
;; block comments. See `c-ts-mode--indent-styles' for example.
;;; Code:
(require 'treesit)
(eval-when-compile (require 'rx))
(declare-function treesit-node-start "treesit.c")
(declare-function treesit-node-end "treesit.c")
(declare-function treesit-node-type "treesit.c")
(defun c-ts-common-looking-at-star (_n _p bol &rest _)
"A tree-sitter simple indent matcher.
Matches if there is a \"*\" after BOL."
(eq (char-after bol) ?*))
(defun c-ts-common-comment-start-after-first-star (_n parent &rest _)
"A tree-sitter simple indent anchor.
Finds the \"/*\" and returns the point after the \"*\".
Assumes PARENT is a comment node."
(save-excursion
(goto-char (treesit-node-start parent))
(if (looking-at (rx "/*"))
(match-end 0)
(point))))
(defun c-ts-common-comment-2nd-line-matcher (_n parent &rest _)
"Matches if point is at the second line of a block comment.
PARENT should be a comment node."
(and (equal (treesit-node-type parent) "comment")
(save-excursion
(forward-line -1)
(back-to-indentation)
(eq (point) (treesit-node-start parent)))))
(defun c-ts-common-comment-2nd-line-anchor (_n _p bol &rest _)
"Return appropriate anchor for the second line of a comment.
If the first line is /* alone, return the position right after
the star; if the first line is /* followed by some text, return
the position right before the text minus 1.
Use an offset of 1 with this anchor. BOL is the beginning of
non-whitespace characters of the current line."
(save-excursion
(forward-line -1)
(back-to-indentation)
(when (looking-at comment-start-skip)
(goto-char (match-end 0))
(if (looking-at (rx (* (or " " "\t")) eol))
;; Only /* at the first line.
(progn (skip-chars-backward " \t")
(if (save-excursion
(goto-char bol)
(looking-at (rx "*")))
;; The common case. Checked by "Multiline Block
;; Comments 4".
(point)
;; The "Multiline Block Comments 2" test in
;; c-ts-common-resources/indent.erts checks this.
(1- (point))))
;; There is something after /* at the first line. The
;; "Multiline Block Comments 3" test checks this.
(1- (point))))))
(defvar c-ts-common--comment-regexp
;; These covers C/C++, Java, JavaScript, TypeScript, Rust, C#.
(rx (or "comment" "line_comment" "block_comment"))
"Regexp pattern that matches a comment in C-like languages.")
(defun c-ts-common--fill-paragraph (&optional arg)
"Fillling function for `c-ts-common'.
ARG is passed to `fill-paragraph'."
(interactive "*P")
(save-restriction
(widen)
(let ((node (treesit-node-at (point))))
(when (string-match-p c-ts-common--comment-regexp
(treesit-node-type node))
(if (save-excursion
(goto-char (treesit-node-start node))
(looking-at "//"))
(fill-comment-paragraph arg)
(c-ts-common--fill-block-comment arg)))
;; Return t so `fill-paragraph' doesn't attempt to fill by
;; itself.
t)))
(defun c-ts-common--fill-block-comment (&optional arg)
"Fillling function for block comments.
ARG is passed to `fill-paragraph'. Assume point is in a block
comment."
(let* ((node (treesit-node-at (point)))
(start (treesit-node-start node))
(end (treesit-node-end node))
;; Bind to nil to avoid infinite recursion.
(fill-paragraph-function nil)
(orig-point (point-marker))
(start-marker (point-marker))
(end-marker nil)
(end-len 0))
(move-marker start-marker start)
;; We mask "/*" and the space before "*/" like
;; `c-fill-paragraph' does.
(atomic-change-group
;; Mask "/*".
(goto-char start)
(when (looking-at (rx (* (syntax whitespace))
(group "/") "*"))
(goto-char (match-beginning 1))
(move-marker start-marker (point))
(replace-match " " nil nil nil 1))
;; Include whitespaces before /*.
(goto-char start)
(beginning-of-line)
(setq start (point))
;; Mask spaces before "*/" if it is attached at the end
;; of a sentence rather than on its own line.
(goto-char end)
(when (looking-back (rx (not (syntax whitespace))
(group (+ (syntax whitespace)))
"*/")
(line-beginning-position))
(goto-char (match-beginning 1))
(setq end-marker (point-marker))
(setq end-len (- (match-end 1) (match-beginning 1)))
(replace-match (make-string end-len ?x)
nil nil nil 1))
;; If "*/" is on its own line, don't included it in the
;; filling region.
(when (not end-marker)
(goto-char end)
(when (looking-back (rx "*/") 2)
(backward-char 2)
(skip-syntax-backward "-")
(setq end (point))))
;; Let `fill-paragraph' do its thing.
(goto-char orig-point)
(narrow-to-region start end)
;; We don't want to fill the region between START and
;; START-MARKER, otherwise the filling function might delete
;; some spaces there.
(fill-region start-marker end arg)
;; Unmask.
(when start-marker
(goto-char start-marker)
(delete-char 1)
(insert "/"))
(when end-marker
(goto-char end-marker)
(delete-region (point) (+ end-len (point)))
(insert (make-string end-len ?\s))))))
(defun c-ts-common-comment-setup ()
"Set up local variables for C-like comment.
Set up:
- `comment-start'
- `comment-end'
- `comment-start-skip'
- `comment-end-skip'
- `adaptive-fill-mode'
- `adaptive-fill-first-line-regexp'
- `paragraph-start'
- `paragraph-separate'
- `fill-paragraph-function'"
(setq-local comment-start "// ")
(setq-local comment-end "")
(setq-local comment-start-skip (rx (or (seq "/" (+ "/"))
(seq "/" (+ "*")))
(* (syntax whitespace))))
(setq-local comment-end-skip
(rx (* (syntax whitespace))
(group (or (syntax comment-end)
(seq (+ "*") "/")))))
(setq-local adaptive-fill-mode t)
;; This matches (1) empty spaces (the default), (2) "//", (3) "*",
;; but do not match "/*", because we don't want to use "/*" as
;; prefix when filling. (Actually, it doesn't matter, because
;; `comment-start-skip' matches "/*" which will cause
;; `fill-context-prefix' to use "/*" as a prefix for filling, that's
;; why we mask the "/*" in `c-ts-common--fill-paragraph'.)
(setq-local adaptive-fill-regexp
(concat (rx (* (syntax whitespace))
(group (or (seq "/" (+ "/")) (* "*"))))
adaptive-fill-regexp))
;; Note the missing * comparing to `adaptive-fill-regexp'. The
;; reason for its absence is a bit convoluted to explain. Suffice
;; to say that without it, filling a single line paragraph that
;; starts with /* doesn't insert * at the beginning of each
;; following line, and filling a multi-line paragraph whose first
;; two lines start with * does insert * at the beginning of each
;; following line. If you know how does adaptive filling works, you
;; know what I mean.
(setq-local adaptive-fill-first-line-regexp
(rx bos
(seq (* (syntax whitespace))
(group (seq "/" (+ "/")))
(* (syntax whitespace)))
eos))
;; Same as `adaptive-fill-regexp'.
(setq-local paragraph-start
(rx (or (seq (* (syntax whitespace))
(group (or (seq "/" (+ "/")) (* "*")))
(* (syntax whitespace))
;; Add this eol so that in
;; `fill-context-prefix', `paragraph-start'
;; doesn't match the prefix.
eol)
"\f")))
(setq-local paragraph-separate paragraph-start)
(setq-local fill-paragraph-function #'c-ts-common--fill-paragraph))
(provide 'c-ts-common)
;;; c-ts-common.el ends here
......@@ -64,26 +64,18 @@
;; files, provided that you have the corresponding parser grammar
;; libraries installed.
;;
;; For C-like language major modes:
;;
;; - Use `c-ts-mode-comment-setup' to setup comment variables and
;; filling.
;;
;; - Use simple-indent matcher `c-ts-mode--looking-at-star' and anchor
;; `c-ts-mode--comment-start-after-first-star' for indenting block
;; comments. See `c-ts-mode--indent-styles' for example.
;;
;; - Use variable `c-ts-mode-indent-block-type-regexp' with indent
;; offset c-ts-mode--statement-offset for indenting statements.
;; Again, see `c-ts-mode--indent-styles' for example.
;;
;;; Code:
(require 'treesit)
(require 'c-ts-common)
(eval-when-compile (require 'rx))
(declare-function treesit-parser-create "treesit.c")
(declare-function treesit-induce-sparse-tree "treesit.c")
(declare-function treesit-node-parent "treesit.c")
(declare-function treesit-node-start "treesit.c")
(declare-function treesit-node-end "treesit.c")
......@@ -173,12 +165,12 @@ MODE is either `c' or `cpp'."
((node-is "else") parent-bol 0)
((node-is "case") parent-bol 0)
((node-is "preproc_arg") no-indent)
;; `c-ts-mode--looking-at-star' has to come before
;; `c-ts-mode--comment-2nd-line-matcher'.
((and (parent-is "comment") c-ts-mode--looking-at-star)
c-ts-mode--comment-start-after-first-star -1)
(c-ts-mode--comment-2nd-line-matcher
c-ts-mode--comment-2nd-line-anchor
;; `c-ts-common-looking-at-star' has to come before
;; `c-ts-common-comment-2nd-line-matcher'.
((and (parent-is "comment") c-ts-common-looking-at-star)
c-ts-common-comment-start-after-first-star -1)
(c-ts-common-comment-2nd-line-matcher
c-ts-common-comment-2nd-line-anchor
1)
((parent-is "comment") prev-adaptive-prefix 0)
......@@ -245,6 +237,10 @@ MODE is either `c' or `cpp'."
((node-is "labeled_statement") point-min 0)
,@common)
(bsd
((node-is "}") parent-bol 0)
((node-is "labeled_statement") parent-bol c-ts-mode-indent-offset)
((parent-is "labeled_statement") parent-bol c-ts-mode-indent-offset)
((parent-is "compound_statement") parent-bol c-ts-mode-indent-offset)
((parent-is "if_statement") parent-bol 0)
((parent-is "for_statement") parent-bol 0)
((parent-is "while_statement") parent-bol 0)
......@@ -333,60 +329,6 @@ PARENT is NODE's parent."
(- (c-ts-mode--statement-offset node parent)
c-ts-mode-indent-offset))
(defun c-ts-mode--looking-at-star (_n _p bol &rest _)
"A tree-sitter simple indent matcher.
Matches if there is a \"*\" after BOL."
(eq (char-after bol) ?*))
(defun c-ts-mode--comment-start-after-first-star (_n parent &rest _)
"A tree-sitter simple indent anchor.
Finds the \"/*\" and returns the point after the \"*\".
Assumes PARENT is a comment node."
(save-excursion
(goto-char (treesit-node-start parent))
(if (looking-at (rx "/*"))
(match-end 0)
(point))))
(defun c-ts-mode--comment-2nd-line-matcher (_n parent &rest _)
"Matches if point is at the second line of a block comment.
PARENT should be a comment node."
(and (equal (treesit-node-type parent) "comment")
(save-excursion
(forward-line -1)
(back-to-indentation)
(eq (point) (treesit-node-start parent)))))
(defun c-ts-mode--comment-2nd-line-anchor (_n _p bol &rest _)
"Return appropriate anchor for the second line of a comment.
If the first line is /* alone, return the position right after
the star; if the first line is /* followed by some text, return
the position right before the text minus 1.
Use an offset of 1 with this anchor. BOL is the beginning of
non-whitespace characters of the current line."
(save-excursion
(forward-line -1)
(back-to-indentation)
(when (looking-at comment-start-skip)
(goto-char (match-end 0))
(if (looking-at (rx (* (or " " "\t")) eol))
;; Only /* at the first line.
(progn (skip-chars-backward " \t")
(if (save-excursion
(goto-char bol)
(looking-at (rx "*")))
;; The common case. Checked by "Multiline Block
;; Comments 4".
(point)
;; The "Multiline Block Comments 2" test in
;; c-ts-mode-resources/indent.erts checks this.
(1- (point))))
;; There is something after /* at the first line. The
;; "Multiline Block Comments 3" test checks this.
(1- (point))))))
;;; Font-lock
(defvar c-ts-mode--preproc-keywords
......@@ -782,156 +724,6 @@ the semicolon. This function skips the semicolon."
(treesit-node-end node))
(goto-char orig-point)))
;;; Filling
(defvar c-ts-mode--comment-regexp
;; These covers C/C++, Java, JavaScript, TypeScript, Rust, C#.
(rx (or "comment" "line_comment" "block_comment"))
"Regexp pattern that matches a comment in C-like languages.")
(defun c-ts-mode--fill-paragraph (&optional arg)
"Fillling function for `c-ts-mode'.
ARG is passed to `fill-paragraph'."
(interactive "*P")
(save-restriction
(widen)
(let ((node (treesit-node-at (point))))
(when (string-match-p c-ts-mode--comment-regexp
(treesit-node-type node))
(if (save-excursion
(goto-char (treesit-node-start node))
(looking-at "//"))
(fill-comment-paragraph arg)
(c-ts-mode--fill-block-comment arg)))
;; Return t so `fill-paragraph' doesn't attempt to fill by
;; itself.
t)))
(defun c-ts-mode--fill-block-comment (&optional arg)
"Fillling function for block comments.
ARG is passed to `fill-paragraph'. Assume point is in a block
comment."
(let* ((node (treesit-node-at (point)))
(start (treesit-node-start node))
(end (treesit-node-end node))
;; Bind to nil to avoid infinite recursion.
(fill-paragraph-function nil)
(orig-point (point-marker))
(start-marker (point-marker))
(end-marker nil)
(end-len 0))
(move-marker start-marker start)
;; We mask "/*" and the space before "*/" like
;; `c-fill-paragraph' does.
(atomic-change-group
;; Mask "/*".
(goto-char start)
(when (looking-at (rx (* (syntax whitespace))
(group "/") "*"))
(goto-char (match-beginning 1))
(move-marker start-marker (point))
(replace-match " " nil nil nil 1))
;; Include whitespaces before /*.
(goto-char start)
(beginning-of-line)
(setq start (point))
;; Mask spaces before "*/" if it is attached at the end
;; of a sentence rather than on its own line.
(goto-char end)
(when (looking-back (rx (not (syntax whitespace))
(group (+ (syntax whitespace)))
"*/")
(line-beginning-position))
(goto-char (match-beginning 1))
(setq end-marker (point-marker))
(setq end-len (- (match-end 1) (match-beginning 1)))
(replace-match (make-string end-len ?x)
nil nil nil 1))
;; If "*/" is on its own line, don't included it in the
;; filling region.
(when (not end-marker)
(goto-char end)
(when (looking-back (rx "*/") 2)
(backward-char 2)
(skip-syntax-backward "-")
(setq end (point))))
;; Let `fill-paragraph' do its thing.
(goto-char orig-point)
(narrow-to-region start end)
;; We don't want to fill the region between START and
;; START-MARKER, otherwise the filling function might delete
;; some spaces there.
(fill-region start-marker end arg)
;; Unmask.
(when start-marker
(goto-char start-marker)
(delete-char 1)
(insert "/"))
(when end-marker
(goto-char end-marker)
(delete-region (point) (+ end-len (point)))
(insert (make-string end-len ?\s))))))
(defun c-ts-mode-comment-setup ()
"Set up local variables for C-like comment.
Set up:
- `comment-start'
- `comment-end'
- `comment-start-skip'
- `comment-end-skip'
- `adaptive-fill-mode'
- `adaptive-fill-first-line-regexp'
- `paragraph-start'
- `paragraph-separate'
- `fill-paragraph-function'"
(setq-local comment-start "// ")
(setq-local comment-end "")
(setq-local comment-start-skip (rx (or (seq "/" (+ "/"))
(seq "/" (+ "*")))
(* (syntax whitespace))))
(setq-local comment-end-skip
(rx (* (syntax whitespace))
(group (or (syntax comment-end)
(seq (+ "*") "/")))))
(setq-local adaptive-fill-mode t)
;; This matches (1) empty spaces (the default), (2) "//", (3) "*",
;; but do not match "/*", because we don't want to use "/*" as
;; prefix when filling. (Actually, it doesn't matter, because
;; `comment-start-skip' matches "/*" which will cause
;; `fill-context-prefix' to use "/*" as a prefix for filling, that's
;; why we mask the "/*" in `c-ts-mode--fill-paragraph'.)
(setq-local adaptive-fill-regexp
(concat (rx (* (syntax whitespace))
(group (or (seq "/" (+ "/")) (* "*"))))
adaptive-fill-regexp))
;; Note the missing * comparing to `adaptive-fill-regexp'. The
;; reason for its absence is a bit convoluted to explain. Suffice
;; to say that without it, filling a single line paragraph that
;; starts with /* doesn't insert * at the beginning of each
;; following line, and filling a multi-line paragraph whose first
;; two lines start with * does insert * at the beginning of each
;; following line. If you know how does adaptive filling works, you
;; know what I mean.
(setq-local adaptive-fill-first-line-regexp
(rx bos
(seq (* (syntax whitespace))
(group (seq "/" (+ "/")))
(* (syntax whitespace)))
eos))
;; Same as `adaptive-fill-regexp'.
(setq-local paragraph-start
(rx (or (seq (* (syntax whitespace))
(group (or (seq "/" (+ "/")) (* "*")))
(* (syntax whitespace))
;; Add this eol so that in
;; `fill-context-prefix', `paragraph-start'
;; doesn't match the prefix.
eol)
"\f")))
(setq-local paragraph-separate paragraph-start)
(setq-local fill-paragraph-function #'c-ts-mode--fill-paragraph))
;;; Modes
(defvar-keymap c-ts-mode-map
......@@ -999,7 +791,7 @@ Set up:
(setq-local indent-tabs-mode t))
;; Comment
(c-ts-mode-comment-setup)
(c-ts-common-comment-setup)
;; Electric
(setq-local electric-indent-chars
......
......@@ -34,7 +34,7 @@
(require 'cc-mode)
(require 'cc-langs)
(require 'treesit)
(require 'c-ts-mode) ; For comment indenting and filling.
(require 'c-ts-common) ; For comment indenting and filling.
(eval-when-compile
(require 'cc-fonts)
......@@ -634,8 +634,8 @@ compilation and evaluation time conflicts."
((node-is "}") parent-bol 0)
((node-is ")") parent-bol 0)
((node-is "]") parent-bol 0)
((and (parent-is "comment") c-ts-mode--looking-at-star)
c-ts-mode--comment-start-after-first-star -1)
((and (parent-is "comment") c-ts-common-looking-at-star)
c-ts-common-comment-start-after-first-star -1)
((parent-is "comment") prev-adaptive-prefix 0)
((parent-is "namespace_declaration") parent-bol 0)
((parent-is "class_declaration") parent-bol 0)
......@@ -908,7 +908,7 @@ Key bindings:
(treesit-parser-create 'c-sharp)
;; Comments.
(c-ts-mode-comment-setup)
(c-ts-common-comment-setup)
(setq-local treesit-text-type-regexp
(regexp-opt '("comment"
......
......@@ -29,7 +29,7 @@
(require 'treesit)
(eval-when-compile (require 'rx))
(require 'c-ts-mode) ; For comment indent and filling.
(require 'c-ts-common) ; For comment indent and filling.
(declare-function treesit-parser-create "treesit.c")
(declare-function treesit-induce-sparse-tree "treesit.c")
......@@ -73,8 +73,8 @@
((node-is "}") (and parent parent-bol) 0)
((node-is ")") parent-bol 0)
((node-is "]") parent-bol 0)
((and (parent-is "comment") c-ts-mode--looking-at-star)
c-ts-mode--comment-start-after-first-star -1)
((and (parent-is "comment") c-ts-common-looking-at-star)
c-ts-common-comment-start-after-first-star -1)