mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2025-01-18 18:05:07 +00:00
Merge from origin/emacs-29
c36fe3df17
Fix c-ts-mode imenu defun name (bug#60296)a24e350170
Fix treesit--children-covering-range-recurse (bug#60301)fbb4eb919b
Support treesit-defun-name in tree-sitter major modes6253184afc
; * lisp/treesit.el (treesit-defun-at-point): Guard again...f8e219ebfa
Add treesit-defun-name and friends35c2ca2ca6
Make treesit-node-at/on guess language at point7f7def2ae6
; Add treesit-no-parser errorb6a2e1ddf6
* nt/INSTALL.W64: update instructions for setting up W64 ...265b91d891
Revert "; Bump minimum supported Windows version for MinG...75155e4586
; Bump minimum supported Windows version for MinGW64 to W...677f6c79eb
; Update minimum requirements of MinGW-w647723af5e4a
; * lisp/progmodes/c-ts-mode.el: quote literal string in ...38866510c7
; * src/xdisp.c (redisplay_internal): Reinstate the FRAME...a825aa0b13
Fix definition of CNS 11643-15 charseta42b20dd95
; * lisp/progmodes/c-ts-mode.el: Add outline section head...e4e3634539
Improve c-ts-mode block comment indent (bug#60270)e30621caa2
; Add treesit_recursion_limit6a43af5880
Fix block comment indent and filling for c-ts-mode (bug#5...e492c21e81
Fix treesit_cursor_helper (bug#60267)4437dbedf7
Fix restart-emacs alarms (Bug#60220)121a9ff9f6
Fix alternate stack test in configure84888080ee
Add more functions to "string" shortdocc90f97d4e5
Make the Contour terminal an alias of xterm-256colorc3fac9465f
; Fix punctuation in last change.756bb422a4
Correct wrong info in (info)Go to nodea8c3424d28
Fix typo in TUTORIAL.fr (bug#60261)24cd2f0daf
Add some diff-fixup-modifs testsd32091199a
Fix quoted argument in emacsclient-mail.desktop Exec key286c48137f
ert-x: Move window selection logic to its own macro823c49cea8
; ert-x: Simplify `ert-with-test-buffer-selected'38c6abe4d0
; ert-x: Add test for buffer read-only state0e39ad6fa5
Fix crash after X error
This commit is contained in:
commit
48db8b68a8
@ -5209,6 +5209,7 @@ AC_CACHE_CHECK([whether signals can be handled on alternate stack],
|
||||
[emacs_cv_alternate_stack],
|
||||
[AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([[#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
]],
|
||||
[[stack_t ss;
|
||||
struct sigaction sa;
|
||||
|
@ -5024,6 +5024,14 @@ comment-start token. Comment-start tokens are defined by regular
|
||||
expression @code{comment-start-skip}. This function assumes
|
||||
@var{parent} is the comment node.
|
||||
|
||||
@item prev-adaptive-prefix
|
||||
This anchor is a function that is called with 3 arguments: @var{node},
|
||||
@var{parent}, and @var{bol}. It tries to go to the beginning of the
|
||||
previous non-empty line, and matches @code{adaptive-fill-regexp}. If
|
||||
there is a match, this function returns the end of the match,
|
||||
otherwise it returns nil. This anchor is useful for a
|
||||
@code{indent-relative}-like indent behavior for block comments.
|
||||
|
||||
@end ftable
|
||||
@end defvar
|
||||
|
||||
|
@ -576,12 +576,12 @@ leaf node after @var{pos}.
|
||||
Finally, if there is no leaf node after @var{pos}, return the first
|
||||
leaf node before @var{pos}.
|
||||
|
||||
When @var{parser-or-lang} is @code{nil} or omitted, this function uses
|
||||
the first parser in @code{(treesit-parser-list)} of the current
|
||||
buffer. If @var{parser-or-lang} is a parser object, it uses that
|
||||
parser; if @var{parser-or-lang} is a language, it finds the first
|
||||
parser using that language in @code{(treesit-parser-list)}, and uses
|
||||
that.
|
||||
If @var{parser-or-lang} is a parser object, this function uses that
|
||||
parser; if @var{parser-or-lang} is a language, this function uses the
|
||||
first parser for that language in the current buffer, or creates one
|
||||
if none exists; if @var{parser-or-lang} is @code{nil}, this function
|
||||
tries to guess the language at @var{pos} by
|
||||
@code{treesit-language-at}.
|
||||
|
||||
If this function cannot find a suitable node to return, it returns
|
||||
@code{nil}.
|
||||
@ -610,13 +610,14 @@ is at or after @var{end}.
|
||||
inside any top-level construct (function definition, etc.) most
|
||||
probably will give you the root node, because the root node is the
|
||||
smallest node that covers that empty line. Most of the time, you want
|
||||
to use @code{treesit-node-at}, described above, instead.
|
||||
to use @code{treesit-node-at} instead.
|
||||
|
||||
When @var{parser-or-lang} is @code{nil}, this function uses the first
|
||||
parser in @code{(treesit-parser-list)} of the current buffer. If
|
||||
@var{parser-or-lang} is a parser object, it uses that parser; if
|
||||
@var{parser-or-lang} is a language, it finds the first parser using
|
||||
that language in @code{(treesit-parser-list)}, and uses that.
|
||||
If @var{parser-or-lang} is a parser object, this function uses that
|
||||
parser; if @var{parser-or-lang} is a language, this function uses the
|
||||
first parser for that language in the current buffer, or creates one
|
||||
if none exists; if @var{parser-or-lang} is @code{nil}, this function
|
||||
tries to guess the language at @var{beg} by
|
||||
@code{treesit-language-at}.
|
||||
|
||||
If @var{named} is non-@code{nil}, this function looks for a named node
|
||||
only (@pxref{tree-sitter named node, named node}).
|
||||
@ -628,9 +629,10 @@ This function returns the root node of the syntax tree generated by
|
||||
@end defun
|
||||
|
||||
@defun treesit-buffer-root-node &optional language
|
||||
This function finds the first parser that uses @var{language} in
|
||||
@code{(treesit-parser-list)} of the current buffer, and returns the
|
||||
root node generated by that parser. If it cannot find an appropriate
|
||||
This function finds the first parser for @var{language} in the current
|
||||
buffer, or creates one if none exists, and returns the root node
|
||||
generated by that parser. If @var{language} is omitted, it uses the
|
||||
first parser in the parser list. If it cannot find an appropriate
|
||||
parser, it returns @code{nil}.
|
||||
@end defun
|
||||
|
||||
@ -1725,6 +1727,9 @@ indentation.
|
||||
If @code{treesit-defun-type-regexp} is non-@code{nil}, it sets up
|
||||
navigation functions for @code{beginning-of-defun} and
|
||||
@code{end-of-defun}.
|
||||
@item
|
||||
If @code{treesit-defun-name-function} is non-@code{nil}, it sets up
|
||||
add-log functions used by @code{add-log-current-defun}.
|
||||
@end itemize
|
||||
@end defun
|
||||
|
||||
@ -1735,6 +1740,41 @@ For more information of these built-in tree-sitter features,
|
||||
For supporting mixing of multiple languages in a major mode,
|
||||
@pxref{Multiple Languages}.
|
||||
|
||||
Besides @code{beginning-of-defun} and @code{end-of-defun}, Emacs
|
||||
provides some additional functions for working with defuns:
|
||||
@code{treesit-defun-at-point} returns the defun node at point, and
|
||||
@code{treesit-defun-name} returns the name of a defun node.
|
||||
|
||||
@defun treesit-defun-at-point
|
||||
This function returns the defun node at point, or @code{nil} if none
|
||||
is found. It respects @code{treesit-defun-tactic}: it returns the
|
||||
top-level defun if the value is @code{top-level}, and returns the
|
||||
immediate enclosing defun if the value is @code{nested}.
|
||||
|
||||
This function requires @code{treesit-defun-type-regexp} to work. If
|
||||
it is @code{nil}, this function simply returns @code{nil}.
|
||||
@end defun
|
||||
|
||||
@defun treesit-defun-name node
|
||||
This function returns the defun name of @var{node}. It returns
|
||||
@code{nil} if there is no defun name for @var{node}, or if @var{node}
|
||||
is not a defun node, or if @var{node} is @code{nil}.
|
||||
|
||||
The defun name is names like function name, class name, struct name,
|
||||
etc.
|
||||
|
||||
If @code{treesit-defun-name-function} is @code{nil}, this function
|
||||
always returns @code{nil}.
|
||||
@end defun
|
||||
|
||||
@defvar treesit-defun-name-function
|
||||
If non-@code{nil}, this variable should store a function that is
|
||||
called with a node and returns the defun name of it. The function
|
||||
should have the same semantic as @code{treesit-defun-name}: if the
|
||||
node is not a defun node, or the node is a defun node but doesn't have
|
||||
a name, or the node is @code{nil}, return @code{nil}.
|
||||
@end defvar
|
||||
|
||||
@node Tree-sitter C API
|
||||
@section Tree-sitter C API Correspondence
|
||||
|
||||
|
@ -1098,9 +1098,8 @@ name, and @key{RET}. Thus, @kbd{gTop@key{RET}} would go to the node
|
||||
called @samp{Top} in this file. (This is equivalent to @kbd{t}, see
|
||||
@ref{Help-Int}.) @kbd{gGo to node@key{RET}} would come back here.
|
||||
|
||||
Unlike @kbd{m}, @kbd{g} does not allow the use of abbreviations.
|
||||
But it does allow completion, so you can type @key{TAB} to complete a
|
||||
partial node name.
|
||||
Like @kbd{m}, @kbd{g} allows the use of abbreviations. It also allows
|
||||
completion, so you can type @key{TAB} to complete a partial node name.
|
||||
|
||||
@cindex go to another Info file
|
||||
To go to a node in another file, you can include the file name in the
|
||||
|
12
etc/PROBLEMS
12
etc/PROBLEMS
@ -3499,6 +3499,18 @@ with development builds, since the .elc files are pre-compiled in releases.
|
||||
|
||||
** Dumping
|
||||
|
||||
*** temacs.exe fails to run when invoked by the build for dumping
|
||||
|
||||
The error message might be something like
|
||||
|
||||
make[2]: *** [Makefile:915: bootstrap-emacs.pdmp] Error 127
|
||||
|
||||
This happens if you try to build Emacs on versions of MS-Windows older
|
||||
than the minimum version supported by MinGW-w64. As of Dec 2022, the
|
||||
minimum supported Windows version is 8.1, and the computer hardware
|
||||
(CPU, memory, disk) should also match the minimum Windows 8.1
|
||||
requirements.
|
||||
|
||||
*** Segfault during 'make'
|
||||
|
||||
If Emacs segfaults when 'make' executes one of these commands:
|
||||
|
@ -1,7 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Categories=Network;Email;
|
||||
Comment=GNU Emacs is an extensible, customizable text editor - and more
|
||||
Exec=sh -c "exec emacsclient --alternate-editor= --display=\\"\\$DISPLAY\\" --eval \\\\(message-mailto\\\\ \\\\\\"%u\\\\\\"\\\\)"
|
||||
Exec=sh -c "exec emacsclient --alternate-editor= --display=\\"\\$DISPLAY\\" --eval \\"(message-mailto \\\\\\"\\$1\\\\\\")\\"" sh %u
|
||||
Icon=emacs
|
||||
Name=Emacs (Mail, Client)
|
||||
MimeType=x-scheme-handler/mailto;
|
||||
@ -13,7 +13,7 @@ Actions=new-window;new-instance;
|
||||
|
||||
[Desktop Action new-window]
|
||||
Name=New Window
|
||||
Exec=emacsclient --alternate-editor= --create-frame --eval "(message-mailto \\"%u\\")"
|
||||
Exec=sh -c "exec emacsclient --alternate-editor= --create-frame --eval \\"(message-mailto \\\\\\"\\$1\\\\\\")\\"" sh %u
|
||||
|
||||
[Desktop Action new-instance]
|
||||
Name=New Instance
|
||||
|
@ -3,7 +3,7 @@ Name=Emacs (Client)
|
||||
GenericName=Text Editor
|
||||
Comment=Edit text
|
||||
MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;
|
||||
Exec=sh -c "if [ -n \\"\\$*\\" ]; then exec emacsclient --alternate-editor= --display=\\"\\$DISPLAY\\" \\"\\$@\\"; else exec emacsclient --alternate-editor= --create-frame; fi" placeholder %F
|
||||
Exec=sh -c "if [ -n \\"\\$*\\" ]; then exec emacsclient --alternate-editor= --display=\\"\\$DISPLAY\\" \\"\\$@\\"; else exec emacsclient --alternate-editor= --create-frame; fi" sh %F
|
||||
Icon=emacs
|
||||
Type=Application
|
||||
Terminal=false
|
||||
|
@ -1219,7 +1219,7 @@ Les conditions de copie d'Emacs lui-même sont plus complexes, mais
|
||||
dans le même esprit. Lisez le fichier COPYING et donnez ensuite des
|
||||
copies de GNU Emacs à vos amis. Participez à l'éradication de
|
||||
l'obstructionnisme du logiciel (sa « propriétarisation ») en
|
||||
utilisant, écrivant et partagent des logiciels libres !
|
||||
utilisant, écrivant et partageant des logiciels libres !
|
||||
|
||||
Cette traduction française a été effectuée par Éric Jacoboni
|
||||
<jaco@teaser.fr> et complétée par Bastien Guerry <bzg@gnu.org>.
|
||||
|
@ -102,42 +102,35 @@ the name of the test and the result of NAME-FORM."
|
||||
(indent 1))
|
||||
`(ert--call-with-test-buffer ,name-form (lambda () ,@body)))
|
||||
|
||||
(cl-defmacro ert-with-test-buffer-selected ((&key name)
|
||||
&body body)
|
||||
"Create a test buffer, switch to it, and run BODY.
|
||||
(cl-defmacro ert-with-buffer-selected (buffer-or-name &body body)
|
||||
"Display a buffer in a temporary selected window and run BODY.
|
||||
|
||||
This extends `ert-with-test-buffer' by displaying the test
|
||||
buffer (whose name is derived from NAME) in a temporary window.
|
||||
The temporary window becomes the `selected-window' before BODY is
|
||||
evaluated. The modification hooks `before-change-functions' and
|
||||
If BUFFER-OR-NAME is nil, the current buffer is used.
|
||||
|
||||
The buffer is made the current buffer, and the temporary window
|
||||
becomes the `selected-window', before BODY is evaluated. The
|
||||
modification hooks `before-change-functions' and
|
||||
`after-change-functions' are not inhibited during the evaluation
|
||||
of BODY, which makes it easier to use `execute-kbd-macro' to
|
||||
simulate user interaction. The window configuration is restored
|
||||
before returning, even if BODY exits nonlocally. The return
|
||||
value is the last form in BODY."
|
||||
(declare (debug ((":name" form) def-body))
|
||||
(indent 1))
|
||||
(let ((ret (make-symbol "ert--with-test-buffer-selected-ret")))
|
||||
`(save-window-excursion
|
||||
(let (,ret)
|
||||
(ert-with-test-buffer (:name ,name)
|
||||
(with-current-buffer-window (current-buffer)
|
||||
`(display-buffer-below-selected
|
||||
(body-function
|
||||
. ,(lambda (window)
|
||||
(select-window window t)
|
||||
;; body-function is intended to initialize the
|
||||
;; contents of a temporary read-only buffer, so
|
||||
;; it is executed with some convenience
|
||||
;; changes. Undo those changes so that the
|
||||
;; test buffer behaves more like an ordinary
|
||||
;; buffer while the body executes.
|
||||
(let ((inhibit-modification-hooks nil)
|
||||
(inhibit-read-only nil)
|
||||
(buffer-read-only nil))
|
||||
(setq ,ret (progn ,@body))))))
|
||||
nil))
|
||||
,ret))))
|
||||
(declare (debug (form body)) (indent 1))
|
||||
`(save-window-excursion
|
||||
(with-current-buffer (or ,buffer-or-name (current-buffer))
|
||||
(with-selected-window (display-buffer (current-buffer))
|
||||
,@body))))
|
||||
|
||||
(cl-defmacro ert-with-test-buffer-selected ((&key name) &body body)
|
||||
"Create a test buffer, switch to it, and run BODY.
|
||||
|
||||
This combines `ert-with-test-buffer' and
|
||||
`ert-with-buffer-selected'. The return value is the last form in
|
||||
BODY."
|
||||
(declare (debug ((":name" form) body)) (indent 1))
|
||||
`(ert-with-test-buffer (:name ,name)
|
||||
(ert-with-buffer-selected (current-buffer)
|
||||
,@body)))
|
||||
|
||||
;;;###autoload
|
||||
(defun ert-kill-all-test-buffers ()
|
||||
|
@ -263,6 +263,12 @@ A FUNC form can have any number of `:no-eval' (or `:no-value'),
|
||||
:eval (stringp "a")
|
||||
:eval (stringp 'a)
|
||||
:eval "(stringp ?a)")
|
||||
(string-or-null-p
|
||||
:eval (string-or-null-p "a")
|
||||
:eval (string-or-null-p nil))
|
||||
(char-or-string-p
|
||||
:eval "(char-or-string-p ?a)"
|
||||
:eval (char-or-string-p "a"))
|
||||
(string-empty-p
|
||||
:no-manual t
|
||||
:eval (string-empty-p ""))
|
||||
@ -300,6 +306,9 @@ A FUNC form can have any number of `:no-eval' (or `:no-value'),
|
||||
:eval (string-to-number "2.5e+03"))
|
||||
(number-to-string
|
||||
:eval (number-to-string 42))
|
||||
(char-uppercase-p
|
||||
:eval "(char-uppercase-p ?A)"
|
||||
:eval "(char-uppercase-p ?a)")
|
||||
"Data About Strings"
|
||||
(length
|
||||
:eval (length "foo")
|
||||
|
@ -47,7 +47,8 @@ the terminal-initialization file to be loaded."
|
||||
("vt400" . "vt200")
|
||||
("vt420" . "vt200")
|
||||
("alacritty" . "xterm")
|
||||
("foot" . "xterm"))
|
||||
("foot" . "xterm")
|
||||
("contour" . "xterm"))
|
||||
"Alist of terminal type aliases.
|
||||
Entries are of the form (TYPE . ALIAS), where both elements are strings.
|
||||
This means to treat a terminal of type TYPE as if it were of type ALIAS."
|
||||
|
@ -184,7 +184,7 @@ with L, LRE, or LRO Unicode bidi character type.")
|
||||
|
||||
(dolist (c '(chinese-cns11643-1 chinese-cns11643-2 chinese-cns11643-3
|
||||
chinese-cns11643-4 chinese-cns11643-5 chinese-cns11643-6
|
||||
chinese-cns11643-7))
|
||||
chinese-cns11643-7 chinese-cns11643-15))
|
||||
(map-charset-chars #'modify-category-entry c ?c)
|
||||
(if (eq c 'chinese-cns11643-1)
|
||||
(map-charset-chars #'modify-category-entry c ?C #x4421 #x7E7E)
|
||||
|
@ -1268,7 +1268,7 @@
|
||||
:short-name "CNS11643-15"
|
||||
:long-name "CNS11643-15 (Chinese traditional)"
|
||||
:code-space [33 126 33 126]
|
||||
:code-offset #x27A000
|
||||
:code-offset #x28083A ; Right after 'big5-hkscs.
|
||||
:unify-map "CNS-F")
|
||||
|
||||
(unify-charset 'chinese-gb2312)
|
||||
|
@ -39,6 +39,8 @@
|
||||
(declare-function treesit-node-child-by-field-name "treesit.c")
|
||||
(declare-function treesit-node-type "treesit.c")
|
||||
|
||||
;;; Custom variables
|
||||
|
||||
(defcustom c-ts-mode-indent-offset 2
|
||||
"Number of spaces for each indentation step in `c-ts-mode'."
|
||||
:version "29.1"
|
||||
@ -91,6 +93,8 @@ follows the form of `treesit-simple-indent-rules'."
|
||||
table)
|
||||
"Syntax table for `c++-ts-mode'.")
|
||||
|
||||
;;; Indent
|
||||
|
||||
(defun c-ts-mode--indent-styles (mode)
|
||||
"Indent rules supported by `c-ts-mode'.
|
||||
MODE is either `c' or `cpp'."
|
||||
@ -102,7 +106,9 @@ MODE is either `c' or `cpp'."
|
||||
((node-is "else") parent-bol 0)
|
||||
((node-is "case") parent-bol 0)
|
||||
((node-is "preproc_arg") no-indent)
|
||||
((and (parent-is "comment") comment-end) comment-start -1)
|
||||
((and (parent-is "comment") c-ts-mode--looking-at-star)
|
||||
c-ts-mode--comment-start-after-first-star -1)
|
||||
((parent-is "comment") prev-adaptive-prefix 0)
|
||||
((node-is "labeled_statement") parent-bol 0)
|
||||
((parent-is "labeled_statement") parent-bol c-ts-mode-indent-offset)
|
||||
((match "preproc_ifdef" "compound_statement") point-min 0)
|
||||
@ -167,6 +173,24 @@ MODE is either `c' or `cpp'."
|
||||
('linux (alist-get 'linux (c-ts-mode--indent-styles mode)))))))
|
||||
`((,mode ,@style))))
|
||||
|
||||
(defun c-ts-mode--looking-at-star (&rest _)
|
||||
"A tree-sitter simple indent matcher.
|
||||
Matches if there is a \"*\" after point (ignoring whitespace in
|
||||
between)."
|
||||
(looking-at (rx (* (syntax whitespace)) "*")))
|
||||
|
||||
(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))))
|
||||
|
||||
;;; Font-lock
|
||||
|
||||
(defvar c-ts-mode--preproc-keywords
|
||||
'("#define" "#if" "#ifdef" "#ifndef"
|
||||
"#else" "#elif" "#endif" "#include")
|
||||
@ -361,28 +385,34 @@ MODE is either `c' or `cpp'."
|
||||
@c-ts-mode--fontify-defun)
|
||||
(:match "^DEFUN$" @fn)))))
|
||||
|
||||
;;; Font-lock helpers
|
||||
|
||||
(defun c-ts-mode--declarator-identifier (node)
|
||||
"Return the identifier of the declarator node NODE."
|
||||
(pcase (treesit-node-type node)
|
||||
;; Recurse.
|
||||
((or "attributed_declarator" "parenthesized_declarator")
|
||||
(c-ts-mode--declarator-identifier (treesit-node-child node 0 t)))
|
||||
("pointer_declarator"
|
||||
(c-ts-mode--declarator-identifier (treesit-node-child node -1)))
|
||||
((or "function_declarator" "array_declarator" "init_declarator")
|
||||
(c-ts-mode--declarator-identifier
|
||||
(treesit-node-child-by-field-name node "declarator")))
|
||||
;; Terminal case.
|
||||
((or "identifier" "field_identifier")
|
||||
node)))
|
||||
|
||||
(defun c-ts-mode--fontify-declarator (node override start end &rest args)
|
||||
"Fontify a declarator (whatever under the \"declarator\" field).
|
||||
For NODE, OVERRIDE, START, END, and ARGS, see
|
||||
`treesit-font-lock-rules'."
|
||||
(pcase (treesit-node-type node)
|
||||
((or "attributed_declarator" "parenthesized_declarator")
|
||||
(apply #'c-ts-mode--fontify-declarator
|
||||
(treesit-node-child node 0 t) override start end args))
|
||||
("pointer_declarator"
|
||||
(apply #'c-ts-mode--fontify-declarator
|
||||
(treesit-node-child node -1) override start end args))
|
||||
((or "function_declarator" "array_declarator" "init_declarator")
|
||||
(apply #'c-ts-mode--fontify-declarator
|
||||
(treesit-node-child-by-field-name node "declarator")
|
||||
override start end args))
|
||||
((or "identifier" "field_identifier")
|
||||
(treesit-fontify-with-override
|
||||
(treesit-node-start node) (treesit-node-end node)
|
||||
(pcase (treesit-node-type (treesit-node-parent node))
|
||||
("function_declarator" 'font-lock-function-name-face)
|
||||
(_ 'font-lock-variable-name-face))
|
||||
override start end))))
|
||||
(let* ((identifier (c-ts-mode--declarator-identifier node))
|
||||
(face (pcase (treesit-node-type (treesit-node-parent identifier))
|
||||
("function_declarator" 'font-lock-function-name-face)
|
||||
(_ 'font-lock-variable-name-face))))
|
||||
(treesit-fontify-with-override
|
||||
(treesit-node-start identifier) (treesit-node-end identifier)
|
||||
face override start end)))
|
||||
|
||||
(defun c-ts-mode--fontify-variable (node override start end &rest _)
|
||||
"Fontify an identifier node if it is a variable.
|
||||
@ -453,6 +483,21 @@ For NODE, OVERRIDE, START, and END, see
|
||||
(t 'font-lock-warning-face))
|
||||
override start end)))
|
||||
|
||||
;;; Imenu
|
||||
|
||||
(defun c-ts-mode--defun-name (node)
|
||||
"Return the name of the defun NODE.
|
||||
Return nil if NODE is not a defun node, return an empty string if
|
||||
NODE doesn't have a name."
|
||||
(treesit-node-text
|
||||
(pcase (treesit-node-type node)
|
||||
((or "function_definition" "declaration")
|
||||
(c-ts-mode--declarator-identifier
|
||||
(treesit-node-child-by-field-name node "declarator")))
|
||||
("struct_specifier"
|
||||
(treesit-node-child-by-field-name node "name")))
|
||||
t))
|
||||
|
||||
(defun c-ts-mode--imenu-1 (node)
|
||||
"Helper for `c-ts-mode--imenu'.
|
||||
Find string representation for NODE and set marker, then recurse
|
||||
@ -460,22 +505,7 @@ the subtrees."
|
||||
(let* ((ts-node (car node))
|
||||
(subtrees (mapcan #'c-ts-mode--imenu-1 (cdr node)))
|
||||
(name (when ts-node
|
||||
(treesit-node-text
|
||||
(pcase (treesit-node-type ts-node)
|
||||
("function_definition"
|
||||
(treesit-node-child-by-field-name
|
||||
(treesit-node-child-by-field-name
|
||||
ts-node "declarator")
|
||||
"declarator"))
|
||||
("declaration"
|
||||
(let ((child (treesit-node-child ts-node -1 t)))
|
||||
(pcase (treesit-node-type child)
|
||||
("identifier" child)
|
||||
(_ (treesit-node-child-by-field-name
|
||||
child "declarator")))))
|
||||
("struct_specifier"
|
||||
(treesit-node-child-by-field-name
|
||||
ts-node "name"))))))
|
||||
(treesit-defun-name ts-node)))
|
||||
(marker (when ts-node
|
||||
(set-marker (make-marker)
|
||||
(treesit-node-start ts-node)))))
|
||||
@ -517,6 +547,8 @@ the subtrees."
|
||||
(when var-index `(("Variable" . ,var-index)))
|
||||
(when func-index `(("Function" . ,func-index))))))
|
||||
|
||||
;;; Defun navigation
|
||||
|
||||
(defun c-ts-mode--end-of-defun ()
|
||||
"`end-of-defun-function' of `c-ts-mode'."
|
||||
;; A struct/enum/union_specifier node doesn't include the ; at the
|
||||
@ -562,6 +594,74 @@ the semicolon. This function skips the semicolon."
|
||||
(treesit-node-end node))
|
||||
(goto-char orig-point)))
|
||||
|
||||
;;; Filling
|
||||
|
||||
(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)))
|
||||
(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 nil)
|
||||
(end-marker nil)
|
||||
(end-len 0))
|
||||
(when (equal (treesit-node-type node) "comment")
|
||||
;; 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))
|
||||
(setq start-marker (point-marker))
|
||||
(replace-match " " nil nil nil 1))
|
||||
;; 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)
|
||||
(funcall #'fill-paragraph 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))))
|
||||
(goto-char orig-point))
|
||||
;; Return t so `fill-paragraph' doesn't attempt to fill by
|
||||
;; itself.
|
||||
t)))
|
||||
|
||||
;;; Modes
|
||||
|
||||
(defvar-keymap c-ts-mode-map
|
||||
:doc "Keymap for the C language with tree-sitter"
|
||||
:parent prog-mode-map
|
||||
@ -584,6 +684,7 @@ the semicolon. This function skips the semicolon."
|
||||
"class_specifier"))
|
||||
#'c-ts-mode--defun-valid-p))
|
||||
(setq-local treesit-defun-skipper #'c-ts-mode--defun-skipper)
|
||||
(setq-local treesit-defun-name-function #'c-ts-mode--defun-name)
|
||||
|
||||
;; Nodes like struct/enum/union_specifier can appear in
|
||||
;; function_definitions, so we need to find the top-level node.
|
||||
@ -593,6 +694,37 @@ the semicolon. This function skips the semicolon."
|
||||
(when (eq c-ts-mode-indent-style 'linux)
|
||||
(setq-local indent-tabs-mode t))
|
||||
|
||||
(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))
|
||||
;; Same as `adaptive-fill-regexp'.
|
||||
(setq-local adaptive-fill-first-line-regexp
|
||||
(rx bos
|
||||
(seq (* (syntax whitespace))
|
||||
(group (or (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)
|
||||
|
||||
;; Electric
|
||||
(setq-local electric-indent-chars
|
||||
(append "{}():;," electric-indent-chars))
|
||||
|
@ -837,6 +837,22 @@ compilation and evaluation time conflicts."
|
||||
;;;###autoload
|
||||
(add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-mode))
|
||||
|
||||
(defun csharp-ts-mode--defun-name (node)
|
||||
"Return the defun name of NODE.
|
||||
Return nil if there is no name or if NODE is not a defun node."
|
||||
(pcase (treesit-node-type node)
|
||||
((or "method_declaration"
|
||||
"record_declaration"
|
||||
"struct_declaration"
|
||||
"enum_declaration"
|
||||
"interface_declaration"
|
||||
"class_declaration"
|
||||
"class_declaration")
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name
|
||||
node "name")
|
||||
t))))
|
||||
|
||||
(defun csharp-ts-mode--imenu-1 (node)
|
||||
"Helper for `csharp-ts-mode--imenu'.
|
||||
Find string representation for NODE and set marker, then recurse
|
||||
@ -844,10 +860,7 @@ the subtrees."
|
||||
(let* ((ts-node (car node))
|
||||
(subtrees (mapcan #'csharp-ts-mode--imenu-1 (cdr node)))
|
||||
(name (when ts-node
|
||||
(or (treesit-node-text
|
||||
(or (treesit-node-child-by-field-name
|
||||
ts-node "name"))
|
||||
t)
|
||||
(or (treesit-defun-name ts-node)
|
||||
"Unnamed node")))
|
||||
(marker (when ts-node
|
||||
(set-marker (make-marker)
|
||||
@ -940,6 +953,7 @@ Key bindings:
|
||||
|
||||
;; Navigation.
|
||||
(setq-local treesit-defun-type-regexp "declaration")
|
||||
(setq-local treesit-defun-name-function #'csharp-ts-mode--defun-name)
|
||||
|
||||
;; Font-lock.
|
||||
(setq-local treesit-font-lock-settings csharp-ts-mode--font-lock-settings)
|
||||
|
@ -248,6 +248,22 @@
|
||||
'((["," ":" ";"]) @font-lock-delimiter-face))
|
||||
"Tree-sitter font-lock settings for `java-ts-mode'.")
|
||||
|
||||
(defun java-ts-mode--defun-name (node)
|
||||
"Return the defun name of NODE.
|
||||
Return nil if there is no name or if NODE is not a defun node."
|
||||
(pcase (treesit-node-type node)
|
||||
((or "method_declaration"
|
||||
"class_declaration"
|
||||
"record_declaration"
|
||||
"interface_declaration"
|
||||
"enum_declaration"
|
||||
"import_declaration"
|
||||
"package_declaration"
|
||||
"module_declaration")
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name node "name")
|
||||
t))))
|
||||
|
||||
(defun java-ts-mode--imenu-1 (node)
|
||||
"Helper for `java-ts-mode--imenu'.
|
||||
Find string representation for NODE and set marker, then recurse
|
||||
@ -255,10 +271,7 @@ the subtrees."
|
||||
(let* ((ts-node (car node))
|
||||
(subtrees (mapcan #'java-ts-mode--imenu-1 (cdr node)))
|
||||
(name (when ts-node
|
||||
(or (treesit-node-text
|
||||
(or (treesit-node-child-by-field-name
|
||||
ts-node "name"))
|
||||
t)
|
||||
(or (treesit-defun-name ts-node)
|
||||
"Unnamed node")))
|
||||
(marker (when ts-node
|
||||
(set-marker (make-marker)
|
||||
@ -339,6 +352,7 @@ the subtrees."
|
||||
"import_declaration"
|
||||
"package_declaration"
|
||||
"module_declaration")))
|
||||
(setq-local treesit-defun-name-function #'java-ts-mode--defun-name)
|
||||
|
||||
;; Font-lock.
|
||||
(setq-local treesit-font-lock-settings java-ts-mode--font-lock-settings)
|
||||
|
@ -3656,24 +3656,18 @@ OVERRIDE is the override flag described in
|
||||
(setq font-beg (treesit-node-end child)
|
||||
child (treesit-node-next-sibling child)))))
|
||||
|
||||
(defun js-treesit-current-defun ()
|
||||
"Return name of surrounding function.
|
||||
This function can be used as a value in `which-func-functions'"
|
||||
(let ((node (treesit-node-at (point)))
|
||||
(name-list ()))
|
||||
(cl-loop while node
|
||||
if (pcase (treesit-node-type node)
|
||||
("function_declaration" t)
|
||||
("method_definition" t)
|
||||
("class_declaration" t)
|
||||
("variable_declarator" t)
|
||||
(_ nil))
|
||||
do (push (treesit-node-text
|
||||
(treesit-node-child-by-field-name node "name")
|
||||
t)
|
||||
name-list)
|
||||
do (setq node (treesit-node-parent node))
|
||||
finally return (string-join name-list "."))))
|
||||
(defun js--treesit-defun-name (node)
|
||||
"Return the defun name of NODE.
|
||||
Return nil if there is no name or if NODE is not a defun node."
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name
|
||||
(pcase (treesit-node-type node)
|
||||
("lexical_declaration"
|
||||
(treesit-search-subtree node "variable_declarator" nil nil 1))
|
||||
((or "function_declaration" "method_definition" "class_declaration")
|
||||
node))
|
||||
"name")
|
||||
t))
|
||||
|
||||
(defun js--treesit-imenu-1 (node)
|
||||
"Given a sparse tree, create an imenu alist.
|
||||
@ -3702,15 +3696,8 @@ definition*\"."
|
||||
("function_declaration" 'function)))
|
||||
;; The root of the tree could have a nil ts-node.
|
||||
(name (when ts-node
|
||||
(let ((ts-node-1
|
||||
(if (eq type 'variable)
|
||||
(treesit-search-subtree
|
||||
ts-node "variable_declarator" nil nil 1)
|
||||
ts-node)))
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name
|
||||
ts-node-1 "name")
|
||||
t))))
|
||||
(or (treesit-defun-name ts-node)
|
||||
"Anonymous")))
|
||||
(marker (when ts-node
|
||||
(set-marker (make-marker)
|
||||
(treesit-node-start ts-node)))))
|
||||
@ -3890,6 +3877,7 @@ Currently there are `js-mode' and `js-ts-mode'."
|
||||
"method_definition"
|
||||
"function_declaration"
|
||||
"lexical_declaration")))
|
||||
(setq-local treesit-defun-name-function #'js--treesit-defun-name)
|
||||
;; Fontification.
|
||||
(setq-local treesit-font-lock-settings js--treesit-font-lock-settings)
|
||||
(setq-local treesit-font-lock-feature-list
|
||||
|
@ -107,6 +107,16 @@
|
||||
'((ERROR) @font-lock-warning-face))
|
||||
"Font-lock settings for JSON.")
|
||||
|
||||
(defun json-ts-mode--defun-name (node)
|
||||
"Return the defun name of NODE.
|
||||
Return nil if there is no name or if NODE is not a defun node."
|
||||
(pcase (treesit-node-type node)
|
||||
((or "pair" "object")
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name
|
||||
node "key")
|
||||
t))))
|
||||
|
||||
(defun json-ts-mode--imenu-1 (node)
|
||||
"Helper for `json-ts-mode--imenu'.
|
||||
Find string representation for NODE and set marker, then recurse
|
||||
@ -114,10 +124,8 @@ the subtrees."
|
||||
(let* ((ts-node (car node))
|
||||
(subtrees (mapcan #'json-ts-mode--imenu-1 (cdr node)))
|
||||
(name (when ts-node
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name
|
||||
ts-node "key")
|
||||
t)))
|
||||
(or (treesit-defun-name ts-node)
|
||||
"Anonymous")))
|
||||
(marker (when ts-node
|
||||
(set-marker (make-marker)
|
||||
(treesit-node-start ts-node)))))
|
||||
@ -161,6 +169,7 @@ the subtrees."
|
||||
;; Navigation.
|
||||
(setq-local treesit-defun-type-regexp
|
||||
(rx (or "pair" "object")))
|
||||
(setq-local treesit-defun-name-function #'json-ts-mode--defun-name)
|
||||
|
||||
;; Font-lock.
|
||||
(setq-local treesit-font-lock-settings json-ts-mode--font-lock-settings)
|
||||
|
@ -5448,6 +5448,16 @@ To this:
|
||||
|
||||
;;; Tree-sitter imenu
|
||||
|
||||
(defun python--treesit-defun-name (node)
|
||||
"Return the defun name of NODE.
|
||||
Return nil if there is no name or if NODE is not a defun node."
|
||||
(pcase (treesit-node-type node)
|
||||
((or "function_definition" "class_definition")
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name
|
||||
node "name")
|
||||
t))))
|
||||
|
||||
(defun python--imenu-treesit-create-index-1 (node)
|
||||
"Given a sparse tree, create an imenu alist.
|
||||
|
||||
@ -5473,9 +5483,8 @@ definition*\"."
|
||||
("class_definition" 'class)))
|
||||
;; The root of the tree could have a nil ts-node.
|
||||
(name (when ts-node
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name
|
||||
ts-node "name") t)))
|
||||
(or (treesit-defun-name ts-node)
|
||||
"Anonymous")))
|
||||
(marker (when ts-node
|
||||
(set-marker (make-marker)
|
||||
(treesit-node-start ts-node)))))
|
||||
@ -6643,6 +6652,8 @@ implementations: `python-mode' and `python-ts-mode'."
|
||||
#'python-imenu-treesit-create-index)
|
||||
(setq-local treesit-defun-type-regexp (rx (or "function" "class")
|
||||
"_definition"))
|
||||
(setq-local treesit-defun-name-function
|
||||
#'python--treesit-defun-name)
|
||||
(treesit-major-mode-setup)
|
||||
|
||||
(when python-indent-guess-indent-offset
|
||||
|
@ -273,6 +273,33 @@
|
||||
(when struct-index `(("Struct" . ,struct-index)))
|
||||
(when func-index `(("Fn" . ,func-index))))))
|
||||
|
||||
(defun rust-ts-mode--defun-name (node)
|
||||
"Return the defun name of NODE.
|
||||
Return nil if there is no name or if NODE is not a defun node."
|
||||
(pcase (treesit-node-type node)
|
||||
("enum_item"
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name node "name") t))
|
||||
("function_item"
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name node "name") t))
|
||||
("impl_item"
|
||||
(let ((trait-node (treesit-node-child-by-field-name node "trait")))
|
||||
(concat
|
||||
(treesit-node-text trait-node t)
|
||||
(when trait-node " for ")
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name node "type") t))))
|
||||
("mod_item"
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name node "name") t))
|
||||
("struct_item"
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name node "name") t))
|
||||
("type_item"
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name node "name") t))))
|
||||
|
||||
(defun rust-ts-mode--imenu-1 (node)
|
||||
"Helper for `rust-ts-mode--imenu'.
|
||||
Find string representation for NODE and set marker, then recurse
|
||||
@ -282,31 +309,8 @@ the subtrees."
|
||||
(subtrees (mapcan #'rust-ts-mode--imenu-1
|
||||
children))
|
||||
(name (when ts-node
|
||||
(pcase (treesit-node-type ts-node)
|
||||
("enum_item"
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name ts-node "name") t))
|
||||
("function_item"
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name ts-node "name") t))
|
||||
("impl_item"
|
||||
(let ((trait-node (treesit-node-child-by-field-name ts-node "trait")))
|
||||
(concat
|
||||
(treesit-node-text
|
||||
trait-node t)
|
||||
(when trait-node
|
||||
" for ")
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name ts-node "type") t))))
|
||||
("mod_item"
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name ts-node "name") t))
|
||||
("struct_item"
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name ts-node "name") t))
|
||||
("type_item"
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name ts-node "name") t)))))
|
||||
(or (treesit-defun-name ts-node)
|
||||
"Anonymous")))
|
||||
(marker (when ts-node
|
||||
(set-marker (make-marker)
|
||||
(treesit-node-start ts-node)))))
|
||||
@ -363,6 +367,7 @@ the subtrees."
|
||||
"function_item"
|
||||
"impl_item"
|
||||
"struct_item")))
|
||||
(setq-local treesit-defun-name-function #'rust-ts-mode--defun-name)
|
||||
|
||||
(treesit-major-mode-setup)))
|
||||
|
||||
|
@ -1412,6 +1412,19 @@ for determining whether point is within a selector."
|
||||
'((ERROR) @error))
|
||||
"Tree-sitter font-lock settings for `css-ts-mode'.")
|
||||
|
||||
(defun css--treesit-defun-name (node)
|
||||
"Return the defun name of NODE.
|
||||
Return nil if there is no name or if NODE is not a defun node."
|
||||
(pcase (treesit-node-type node)
|
||||
("rule_set" (treesit-node-text
|
||||
(treesit-node-child node 0) t))
|
||||
("media_statement"
|
||||
(let ((block (treesit-node-child node -1)))
|
||||
(string-trim
|
||||
(buffer-substring-no-properties
|
||||
(treesit-node-start node)
|
||||
(treesit-node-start block)))))))
|
||||
|
||||
(defun css--treesit-imenu-1 (node)
|
||||
"Helper for `css--treesit-imenu'.
|
||||
Find string representation for NODE and set marker, then recurse
|
||||
@ -1419,15 +1432,8 @@ the subtrees."
|
||||
(let* ((ts-node (car node))
|
||||
(subtrees (mapcan #'css--treesit-imenu-1 (cdr node)))
|
||||
(name (when ts-node
|
||||
(pcase (treesit-node-type ts-node)
|
||||
("rule_set" (treesit-node-text
|
||||
(treesit-node-child ts-node 0) t))
|
||||
("media_statement"
|
||||
(let ((block (treesit-node-child ts-node -1)))
|
||||
(string-trim
|
||||
(buffer-substring-no-properties
|
||||
(treesit-node-start ts-node)
|
||||
(treesit-node-start block))))))))
|
||||
(or (treesit-defun-name ts-node)
|
||||
"Anonymous")))
|
||||
(marker (when ts-node
|
||||
(set-marker (make-marker)
|
||||
(treesit-node-start ts-node)))))
|
||||
@ -1835,6 +1841,7 @@ can also be used to fill comments.
|
||||
(treesit-parser-create 'css)
|
||||
(setq-local treesit-simple-indent-rules css--treesit-indent-rules)
|
||||
(setq-local treesit-defun-type-regexp "rule_set")
|
||||
(setq-local treesit-defun-name-function #'css--treesit-defun-name)
|
||||
(setq-local treesit-font-lock-settings css--treesit-settings)
|
||||
(setq-local treesit-font-lock-feature-list
|
||||
'((selector comment query keyword)
|
||||
|
@ -107,12 +107,12 @@
|
||||
'((ERROR) @font-lock-warning-face))
|
||||
"Font-lock settings for TOML.")
|
||||
|
||||
(defun toml-ts-mode--get-table-name (node)
|
||||
"Obtains the header-name for the associated tree-sitter `NODE'."
|
||||
(if node
|
||||
(treesit-node-text
|
||||
(car (cdr (treesit-node-children node))))
|
||||
"Root table"))
|
||||
(defun toml-ts-mode--defun-name (node)
|
||||
"Return the defun name of NODE.
|
||||
Return nil if there is no name or if NODE is not a defun node."
|
||||
(pcase (treesit-node-type node)
|
||||
((or "table" "table_array_element")
|
||||
(car (cdr (treesit-node-children node))))))
|
||||
|
||||
(defun toml-ts-mode--imenu-1 (node)
|
||||
"Helper for `toml-ts-mode--imenu'.
|
||||
@ -120,7 +120,8 @@ Find string representation for NODE and set marker, then recurse
|
||||
the subtrees."
|
||||
(let* ((ts-node (car node))
|
||||
(subtrees (mapcan #'toml-ts-mode--imenu-1 (cdr node)))
|
||||
(name (toml-ts-mode--get-table-name ts-node))
|
||||
(name (or (treesit-defun-name ts-node)
|
||||
"Root table"))
|
||||
(marker (when ts-node
|
||||
(set-marker (make-marker)
|
||||
(treesit-node-start ts-node)))))
|
||||
@ -167,6 +168,7 @@ the subtrees."
|
||||
;; Navigation.
|
||||
(setq-local treesit-defun-type-regexp
|
||||
(rx (or "table" "table_array_element")))
|
||||
(setq-local treesit-defun-name-function #'toml-ts-mode--defun-name)
|
||||
|
||||
;; Font-lock.
|
||||
(setq-local treesit-font-lock-settings toml-ts-mode--font-lock-settings)
|
||||
|
156
lisp/treesit.el
156
lisp/treesit.el
@ -141,6 +141,9 @@ parser in `treesit-parser-list', or nil if there is no parser."
|
||||
|
||||
;;; Node API supplement
|
||||
|
||||
(define-error 'treesit-no-parser "No available parser for this buffer"
|
||||
'treesit-error)
|
||||
|
||||
(defun treesit-node-buffer (node)
|
||||
"Return the buffer in which NODE belongs."
|
||||
(treesit-parser-buffer
|
||||
@ -168,13 +171,15 @@ before POS.
|
||||
Return nil if no leaf node can be returned. If NAMED is non-nil,
|
||||
only look for named nodes.
|
||||
|
||||
If PARSER-OR-LANG is nil, use the first parser in
|
||||
`treesit-parser-list'; if PARSER-OR-LANG is a parser, use
|
||||
that parser; if PARSER-OR-LANG is a language, find a parser using
|
||||
that language in the current buffer, and use that."
|
||||
If PARSER-OR-LANG is a parser, use that parser; if PARSER-OR-LANG
|
||||
is a language, find the first parser for that language in the
|
||||
current buffer, or create one if none exists; If PARSER-OR-LANG
|
||||
is nil, try to guess the language at POS by
|
||||
`treesit-language-at'."
|
||||
(let* ((root (if (treesit-parser-p parser-or-lang)
|
||||
(treesit-parser-root-node parser-or-lang)
|
||||
(treesit-buffer-root-node parser-or-lang)))
|
||||
(treesit-buffer-root-node
|
||||
(or parser-or-lang (treesit-language-at pos)))))
|
||||
(node root)
|
||||
(node-before root)
|
||||
(pos-1 (max (1- pos) (point-min)))
|
||||
@ -216,13 +221,15 @@ to use `treesit-node-at' instead.
|
||||
Return nil if none was found. If NAMED is non-nil, only look for
|
||||
named node.
|
||||
|
||||
If PARSER-OR-LANG is nil, use the first parser in
|
||||
`treesit-parser-list'; if PARSER-OR-LANG is a parser, use
|
||||
that parser; if PARSER-OR-LANG is a language, find a parser using
|
||||
that language in the current buffer, and use that."
|
||||
If PARSER-OR-LANG is a parser, use that parser; if PARSER-OR-LANG
|
||||
is a language, find the first parser for that language in the
|
||||
current buffer, or create one if none exists; If PARSER-OR-LANG
|
||||
is nil, try to guess the language at BEG by
|
||||
`treesit-language-at'."
|
||||
(let ((root (if (treesit-parser-p parser-or-lang)
|
||||
(treesit-parser-root-node parser-or-lang)
|
||||
(treesit-buffer-root-node parser-or-lang))))
|
||||
(treesit-buffer-root-node
|
||||
(or parser-or-lang (treesit-language-at beg))))))
|
||||
(treesit-node-descendant-for-range root beg (or end beg) named)))
|
||||
|
||||
(defun treesit-node-top-level (node &optional type)
|
||||
@ -243,16 +250,15 @@ regexp, rather than using NODE's type."
|
||||
|
||||
(defun treesit-buffer-root-node (&optional language)
|
||||
"Return the root node of the current buffer.
|
||||
Use the first parser in `treesit-parser-list'.
|
||||
|
||||
If optional argument LANGUAGE is non-nil, use the first parser
|
||||
for LANGUAGE."
|
||||
Use the first parser in the parser list if LANGUAGE is omitted.
|
||||
If LANGUAGE is non-nil, use the first parser for LANGUAGE in the
|
||||
parser list, or create one if none exists."
|
||||
(if-let ((parser
|
||||
(or (if language
|
||||
(treesit-parser-create language)
|
||||
(or (car (treesit-parser-list))
|
||||
(signal 'treesit-error
|
||||
'("Buffer has no parser")))))))
|
||||
(if language
|
||||
(treesit-parser-create language)
|
||||
(or (car (treesit-parser-list))
|
||||
(signal 'treesit-no-parser (list (current-buffer)))))))
|
||||
(treesit-parser-root-node parser)))
|
||||
|
||||
(defun treesit-filter-child (node pred &optional named)
|
||||
@ -859,7 +865,7 @@ LIMIT is the recursion limit, which defaults to 100."
|
||||
(push child result))
|
||||
(setq child (treesit-node-next-sibling child)))
|
||||
;; If NODE has no child, keep NODE.
|
||||
(or result node)))
|
||||
(or result (list node))))
|
||||
|
||||
(defsubst treesit--node-length (node)
|
||||
"Return the length of the text of NODE."
|
||||
@ -1107,6 +1113,22 @@ See `treesit-simple-indent-presets'.")
|
||||
(re-search-forward comment-start-skip)
|
||||
(skip-syntax-backward "-")
|
||||
(point))))
|
||||
(cons 'prev-adaptive-prefix
|
||||
(lambda (_n parent &rest _)
|
||||
(save-excursion
|
||||
(re-search-backward
|
||||
(rx (not (or " " "\t" "\n"))) nil t)
|
||||
(beginning-of-line)
|
||||
(and (>= (point) (treesit-node-start parent))
|
||||
;; `adaptive-fill-regexp' will not match "/*",
|
||||
;; so we need to also try `comment-start-skip'.
|
||||
(or (and adaptive-fill-regexp
|
||||
(looking-at adaptive-fill-regexp)
|
||||
(> (- (match-end 0) (match-beginning 0)) 0)
|
||||
(match-end 0))
|
||||
(and comment-start-skip
|
||||
(looking-at comment-start-skip)
|
||||
(match-end 0)))))))
|
||||
;; TODO: Document.
|
||||
(cons 'grand-parent
|
||||
(lambda (_n parent &rest _)
|
||||
@ -1229,7 +1251,14 @@ comment-start
|
||||
|
||||
Goes to the position that `comment-start-skip' would return,
|
||||
skips whitespace backwards, and returns the resulting
|
||||
position. Assumes PARENT is a comment node.")
|
||||
position. Assumes PARENT is a comment node.
|
||||
|
||||
prev-adaptive-prefix
|
||||
|
||||
Goes to the beginning of previous non-empty line, and tries
|
||||
to match `adaptive-fill-regexp'. If it matches, return the
|
||||
end of the match, otherwise return nil. This is useful for a
|
||||
`indent-relative'-like indent behavior for block comments.")
|
||||
|
||||
(defun treesit--simple-indent-eval (exp)
|
||||
"Evaluate EXP.
|
||||
@ -1583,6 +1612,17 @@ newline after a defun, or the beginning of a defun.
|
||||
|
||||
If the value is nil, no skipping is performed.")
|
||||
|
||||
(defvar-local treesit-defun-name-function nil
|
||||
"A function called with a node and returns the name of it.
|
||||
If the node is a defun node, return the defun name. E.g., the
|
||||
function name of a function. If the node is not a defun node, or
|
||||
the defun node doesn't have a name, or the node is nil, return
|
||||
nil.")
|
||||
|
||||
(defvar-local treesit-add-log-defun-delimiter "."
|
||||
"The delimiter used to connect several defun names.
|
||||
This is used in `treesit-add-log-current-defun'.")
|
||||
|
||||
(defun treesit-beginning-of-defun (&optional arg)
|
||||
"Move backward to the beginning of a defun.
|
||||
|
||||
@ -1659,7 +1699,9 @@ previous and next sibling defuns around POS, and PARENT is the
|
||||
parent defun surrounding POS. All of three could be nil if no
|
||||
sound defun exists.
|
||||
|
||||
REGEXP and PRED are the same as in `treesit-defun-type-regexp'."
|
||||
REGEXP and PRED are the same as in `treesit-defun-type-regexp'.
|
||||
|
||||
Assumes `treesit-defun-type-regexp' is set."
|
||||
(let* ((node (treesit-node-at pos))
|
||||
;; NODE-BEFORE/AFTER = NODE when POS is completely in NODE,
|
||||
;; but if not, that means point could be in between two
|
||||
@ -1845,26 +1887,58 @@ function is called recursively."
|
||||
|
||||
;; TODO: In corporate into thing-at-point.
|
||||
(defun treesit-defun-at-point ()
|
||||
"Return the defun at point or nil if none is found.
|
||||
"Return the defun node at point or nil if none is found.
|
||||
|
||||
Respects `treesit-defun-tactic': return the top-level defun if it
|
||||
is `top-level', return the immediate parent defun if it is
|
||||
`nested'."
|
||||
(pcase-let* ((`(,regexp . ,pred)
|
||||
(if (consp treesit-defun-type-regexp)
|
||||
treesit-defun-type-regexp
|
||||
(cons treesit-defun-type-regexp nil)))
|
||||
(`(,_ ,next ,parent)
|
||||
(treesit--defuns-around (point) regexp pred))
|
||||
;; If point is at the beginning of a defun, we
|
||||
;; prioritize that defun over the parent in nested
|
||||
;; mode.
|
||||
(node (or (and (eq (treesit-node-start next) (point))
|
||||
next)
|
||||
parent)))
|
||||
(if (eq treesit-defun-tactic 'top-level)
|
||||
(treesit--top-level-defun node regexp pred)
|
||||
node)))
|
||||
`nested'.
|
||||
|
||||
Return nil if `treesit-defun-type-regexp' is not set."
|
||||
(when treesit-defun-type-regexp
|
||||
(pcase-let* ((`(,regexp . ,pred)
|
||||
(if (consp treesit-defun-type-regexp)
|
||||
treesit-defun-type-regexp
|
||||
(cons treesit-defun-type-regexp nil)))
|
||||
(`(,_ ,next ,parent)
|
||||
(treesit--defuns-around (point) regexp pred))
|
||||
;; If point is at the beginning of a defun, we
|
||||
;; prioritize that defun over the parent in nested
|
||||
;; mode.
|
||||
(node (or (and (eq (treesit-node-start next) (point))
|
||||
next)
|
||||
parent)))
|
||||
(if (eq treesit-defun-tactic 'top-level)
|
||||
(treesit--top-level-defun node regexp pred)
|
||||
node))))
|
||||
|
||||
(defun treesit-defun-name (node)
|
||||
"Return the defun name of NODE.
|
||||
|
||||
Return nil if there is no name, or if NODE is not a defun node,
|
||||
or if NODE is nil.
|
||||
|
||||
If `treesit-defun-name-function' is nil, always return nil."
|
||||
(when treesit-defun-name-function
|
||||
(funcall treesit-defun-name-function node)))
|
||||
|
||||
(defun treesit-add-log-current-defun ()
|
||||
"Return the name of the defun at point.
|
||||
|
||||
Used for `add-log-current-defun-function'.
|
||||
|
||||
The delimiter between nested defun names is controlled by
|
||||
`treesit-add-log-defun-delimiter'."
|
||||
(let ((node (treesit-defun-at-point))
|
||||
(name nil))
|
||||
(while node
|
||||
(when-let ((new-name (treesit-defun-name node)))
|
||||
(if name
|
||||
(setq name (concat new-name
|
||||
treesit-add-log-defun-delimiter
|
||||
name))
|
||||
(setq name new-name)))
|
||||
(setq node (treesit-node-parent node)))
|
||||
name))
|
||||
|
||||
;;; Activating tree-sitter
|
||||
|
||||
@ -1959,7 +2033,11 @@ before calling this function."
|
||||
;; the variables. In future we should update `end-of-defun' to
|
||||
;; work with nested defuns.
|
||||
(setq-local beginning-of-defun-function #'treesit-beginning-of-defun)
|
||||
(setq-local end-of-defun-function #'treesit-end-of-defun)))
|
||||
(setq-local end-of-defun-function #'treesit-end-of-defun))
|
||||
;; Defun name.
|
||||
(when treesit-defun-name-function
|
||||
(setq-local add-log-current-defun-function
|
||||
#'treesit-add-log-current-defun)))
|
||||
|
||||
;;; Debugging
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
This document describes how to compile a 64-bit GNU Emacs using MSYS2
|
||||
and MinGW-w64. For instructions for building a 32-bit Emacs using
|
||||
MSYS and MinGW, see the file INSTALL in this directory.
|
||||
MSYS and mingw.org's MinGW, see the file INSTALL in this directory.
|
||||
|
||||
Do not use this recipe with Cygwin. For building on Cygwin, use the normal
|
||||
installation instructions in ../INSTALL.
|
||||
@ -16,28 +16,27 @@ installation instructions in ../INSTALL.
|
||||
The total space required is 3GB: 1.8GB for MSYS2 / MinGW-w64 and 1.2GB for
|
||||
Emacs with the full repository, or less if you're using a release tarball.
|
||||
|
||||
As of December 2022, the minimum supported system, both for building
|
||||
Emacs with the MSYS2/MinGW-w64 toolchain and for running the produced
|
||||
binary, is Windows 8.1. The computer hardware should also match the
|
||||
Microsoft requirements for Windows 8.1.
|
||||
|
||||
* Set up the MinGW-w64 / MSYS2 build environment
|
||||
|
||||
MinGW-w64 provides a complete runtime for projects built with GCC for 64-bit
|
||||
Windows -- it's located at https://mingw-w64.org/.
|
||||
|
||||
MSYS2 is a Cygwin-derived software distribution for Windows which provides
|
||||
build tools for MinGW-w64 -- see https://msys2.github.io/.
|
||||
build tools for MinGW-w64 -- see https://msys2.org/.
|
||||
|
||||
** Download and install MinGW-w64 and MSYS2
|
||||
|
||||
You can download the x86_64 version of MSYS2 (i.e. msys2-x86_64-<date>.exe)
|
||||
from
|
||||
|
||||
https://sourceforge.net/projects/msys2/files/Base/x86_64
|
||||
|
||||
Run this file to install MSYS2 in your preferred directory, e.g. the default
|
||||
C:\msys64 -- this will install MinGW-w64 also. Note that directory names
|
||||
containing spaces may cause problems.
|
||||
Go to https://msys2.org and follow the instructions. It is not
|
||||
necessary to install the packages suggested on those instructions.
|
||||
|
||||
** Download and install the necessary packages
|
||||
|
||||
Run c:/msys64/msys2.exe in your MSYS2 directory and you will see a BASH window
|
||||
Run mingw64.exe in your MSYS2 directory and you will see a BASH window
|
||||
opened.
|
||||
|
||||
In the BASH prompt, use the following command to install the necessary
|
||||
@ -117,10 +116,6 @@ put the Emacs source into C:\emacs\emacs-26:
|
||||
Now you're ready to build and install Emacs with autogen, configure, make,
|
||||
and make install.
|
||||
|
||||
First we need to switch to the MinGW-w64 environment. Exit the MSYS2 BASH
|
||||
console and run mingw64.exe in the C:\msys64 folder, then cd back to
|
||||
your Emacs source directory, e.g.:
|
||||
|
||||
cd /c/emacs/emacs-26
|
||||
|
||||
** Run autogen
|
||||
|
@ -2910,6 +2910,7 @@ killed. */
|
||||
|
||||
if (!NILP (restart))
|
||||
{
|
||||
turn_on_atimers (false);
|
||||
#ifdef WINDOWSNT
|
||||
if (w32_reexec_emacs (initial_cmdline, initial_wd) < 0)
|
||||
#else
|
||||
|
138
src/treesit.c
138
src/treesit.c
@ -404,6 +404,10 @@ init_treesit_functions (void)
|
||||
|
||||
/*** Initialization */
|
||||
|
||||
/* This is the limit on recursion levels for some tree-sitter
|
||||
functions. Remember to update docstrings when changing this
|
||||
value. */
|
||||
const ptrdiff_t treesit_recursion_limit = 1000;
|
||||
bool treesit_initialized = false;
|
||||
|
||||
static bool
|
||||
@ -1762,7 +1766,7 @@ If NODE is nil, return nil. */)
|
||||
return build_string (string);
|
||||
}
|
||||
|
||||
static TSTreeCursor treesit_cursor_helper (TSNode, Lisp_Object);
|
||||
static bool treesit_cursor_helper (TSTreeCursor *, TSNode, Lisp_Object);
|
||||
|
||||
DEFUN ("treesit-node-parent",
|
||||
Ftreesit_node_parent, Streesit_node_parent, 1, 1, 0,
|
||||
@ -1778,7 +1782,10 @@ Return nil if NODE has no parent. If NODE is nil, return nil. */)
|
||||
|
||||
TSNode treesit_node = XTS_NODE (node)->node;
|
||||
Lisp_Object parser = XTS_NODE (node)->parser;
|
||||
TSTreeCursor cursor = treesit_cursor_helper (treesit_node, parser);
|
||||
TSTreeCursor cursor;
|
||||
if (!treesit_cursor_helper (&cursor, treesit_node, parser))
|
||||
return return_value;
|
||||
|
||||
if (ts_tree_cursor_goto_parent (&cursor))
|
||||
{
|
||||
TSNode parent = ts_tree_cursor_current_node (&cursor);
|
||||
@ -2637,8 +2644,59 @@ treesit_assume_true (bool val)
|
||||
eassert (val == true);
|
||||
}
|
||||
|
||||
/* Tries to move CURSOR to point to TARGET. END_POS is the end of
|
||||
TARGET. If success, return true, otherwise move CURSOR back to
|
||||
starting position and return false. LIMIT is the recursion
|
||||
limit. */
|
||||
static bool
|
||||
treesit_cursor_helper_1 (TSTreeCursor *cursor, TSNode *target,
|
||||
uint32_t end_pos, ptrdiff_t limit)
|
||||
{
|
||||
if (limit <= 0)
|
||||
return false;
|
||||
|
||||
TSNode cursor_node = ts_tree_cursor_current_node (cursor);
|
||||
if (ts_node_eq (cursor_node, *target))
|
||||
return true;
|
||||
|
||||
if (!ts_tree_cursor_goto_first_child (cursor))
|
||||
return false;
|
||||
|
||||
/* Skip nodes that definitely don't contain TARGET. */
|
||||
while (ts_node_end_byte (cursor_node) < end_pos)
|
||||
{
|
||||
if (!ts_tree_cursor_goto_next_sibling (cursor))
|
||||
break;
|
||||
cursor_node = ts_tree_cursor_current_node (cursor);
|
||||
}
|
||||
|
||||
/* Go through each sibling that could contain TARGET. Because of
|
||||
missing nodes (their width is 0), there could be multiple
|
||||
siblings that could contain TARGET. */
|
||||
while (ts_node_start_byte (cursor_node) <= end_pos)
|
||||
{
|
||||
if (treesit_cursor_helper_1 (cursor, target, end_pos, limit - 1))
|
||||
return true;
|
||||
|
||||
if (!ts_tree_cursor_goto_next_sibling (cursor))
|
||||
break;
|
||||
cursor_node = ts_tree_cursor_current_node (cursor);
|
||||
}
|
||||
|
||||
/* Couldn't find TARGET, must be not in this subtree, move cursor
|
||||
back and pray that other brothers and sisters can succeed. */
|
||||
treesit_assume_true (ts_tree_cursor_goto_parent (cursor));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Create a TSTreeCursor pointing at NODE. PARSER is the lisp parser
|
||||
that produced NODE.
|
||||
that produced NODE. If success, return true, otherwise return
|
||||
false. This function should almost always succeed, but if the parse
|
||||
tree is strangely too deep and exceeds the recursion limit, this
|
||||
function will fail and return false.
|
||||
|
||||
If this function returns true, caller needs to free CURSOR; if
|
||||
returns false, caller don't need to free CURSOR.
|
||||
|
||||
The reason we need this instead of simply using ts_tree_cursor_new
|
||||
is that we have to create the cursor on the root node and traverse
|
||||
@ -2646,56 +2704,17 @@ treesit_assume_true (bool val)
|
||||
Otherwise going to sibling or parent of NODE wouldn't work.
|
||||
|
||||
(Wow perfect filling.) */
|
||||
static TSTreeCursor
|
||||
treesit_cursor_helper (TSNode node, Lisp_Object parser)
|
||||
static bool
|
||||
treesit_cursor_helper (TSTreeCursor *cursor, TSNode node, Lisp_Object parser)
|
||||
{
|
||||
uint32_t end_pos = ts_node_end_byte (node);
|
||||
TSNode root = ts_tree_root_node (XTS_PARSER (parser)->tree);
|
||||
TSTreeCursor cursor = ts_tree_cursor_new (root);
|
||||
TSNode cursor_node = ts_tree_cursor_current_node (&cursor);
|
||||
/* This is like treesit-node-at. We go down from the root node,
|
||||
either to first child or next sibling, repeatedly, and finally
|
||||
arrive at NODE. */
|
||||
while (!ts_node_eq (node, cursor_node))
|
||||
{
|
||||
treesit_assume_true (ts_tree_cursor_goto_first_child (&cursor));
|
||||
cursor_node = ts_tree_cursor_current_node (&cursor);
|
||||
/* ts_tree_cursor_goto_first_child_for_byte is not reliable, so
|
||||
we just go through each sibling. */
|
||||
while (ts_node_is_missing (cursor_node)
|
||||
|| ts_node_end_byte (cursor_node) < end_pos)
|
||||
{
|
||||
/* A "missing" node has zero width, so it's possible that
|
||||
its end = NODE.end but it's not NODE, so we skip them.
|
||||
But we need to make sure this missing node is not the
|
||||
node we are looking for before skipping it. */
|
||||
if (ts_node_is_missing (cursor_node)
|
||||
&& ts_node_eq (node, cursor_node))
|
||||
return cursor;
|
||||
treesit_assume_true (ts_tree_cursor_goto_next_sibling (&cursor));
|
||||
cursor_node = ts_tree_cursor_current_node (&cursor);
|
||||
}
|
||||
/* Right now CURSOR.end >= NODE.end. But what if CURSOR.end =
|
||||
NODE.end, and there are missing nodes after CURSOR, and the
|
||||
missing node after CURSOR is the NODE we are looking for??
|
||||
Well, create a probe and look ahead. (This is tested by
|
||||
treesit-cursor-helper-with-missing-node.) */
|
||||
TSTreeCursor probe = ts_tree_cursor_copy (&cursor);
|
||||
TSNode probe_node;
|
||||
while (ts_tree_cursor_goto_next_sibling (&probe))
|
||||
{
|
||||
probe_node = ts_tree_cursor_current_node (&probe);
|
||||
if (!ts_node_is_missing (probe_node))
|
||||
break;
|
||||
if (ts_node_eq (probe_node, node))
|
||||
{
|
||||
ts_tree_cursor_delete (&cursor);
|
||||
return probe;
|
||||
}
|
||||
}
|
||||
ts_tree_cursor_delete (&probe);
|
||||
}
|
||||
return cursor;
|
||||
*cursor = ts_tree_cursor_new (root);
|
||||
bool success = treesit_cursor_helper_1 (cursor, &node, end_pos,
|
||||
treesit_recursion_limit);
|
||||
if (!success)
|
||||
ts_tree_cursor_delete (cursor);
|
||||
return success;
|
||||
}
|
||||
|
||||
/* Move CURSOR to the next/previous sibling. FORWARD controls the
|
||||
@ -2957,7 +2976,7 @@ Return the first matched node, or nil if none matches. */)
|
||||
|
||||
/* We use a default limit of 1000. See bug#59426 for the
|
||||
discussion. */
|
||||
ptrdiff_t the_limit = 1000;
|
||||
ptrdiff_t the_limit = treesit_recursion_limit;
|
||||
if (!NILP (limit))
|
||||
{
|
||||
CHECK_FIXNUM (limit);
|
||||
@ -2968,7 +2987,10 @@ Return the first matched node, or nil if none matches. */)
|
||||
|
||||
Lisp_Object parser = XTS_NODE (node)->parser;
|
||||
Lisp_Object return_value = Qnil;
|
||||
TSTreeCursor cursor = treesit_cursor_helper (XTS_NODE (node)->node, parser);
|
||||
TSTreeCursor cursor;
|
||||
if (!treesit_cursor_helper (&cursor, XTS_NODE (node)->node, parser))
|
||||
return return_value;
|
||||
|
||||
if (treesit_search_dfs (&cursor, predicate, parser, NILP (backward),
|
||||
NILP (all), the_limit, false))
|
||||
{
|
||||
@ -3022,7 +3044,10 @@ always traverse leaf nodes first, then upwards. */)
|
||||
|
||||
Lisp_Object parser = XTS_NODE (start)->parser;
|
||||
Lisp_Object return_value = Qnil;
|
||||
TSTreeCursor cursor = treesit_cursor_helper (XTS_NODE (start)->node, parser);
|
||||
TSTreeCursor cursor;
|
||||
if (!treesit_cursor_helper (&cursor, XTS_NODE (start)->node, parser))
|
||||
return return_value;
|
||||
|
||||
if (treesit_search_forward (&cursor, predicate, parser,
|
||||
NILP (backward), NILP (all)))
|
||||
{
|
||||
@ -3130,7 +3155,7 @@ a regexp. */)
|
||||
|
||||
/* We use a default limit of 1000. See bug#59426 for the
|
||||
discussion. */
|
||||
ptrdiff_t the_limit = 1000;
|
||||
ptrdiff_t the_limit = treesit_recursion_limit;
|
||||
if (!NILP (limit))
|
||||
{
|
||||
CHECK_FIXNUM (limit);
|
||||
@ -3141,7 +3166,10 @@ a regexp. */)
|
||||
|
||||
Lisp_Object parser = XTS_NODE (root)->parser;
|
||||
Lisp_Object parent = Fcons (Qnil, Qnil);
|
||||
TSTreeCursor cursor = treesit_cursor_helper (XTS_NODE (root)->node, parser);
|
||||
TSTreeCursor cursor;
|
||||
if (!treesit_cursor_helper (&cursor, XTS_NODE (root)->node, parser))
|
||||
return Qnil;
|
||||
|
||||
treesit_build_sparse_tree (&cursor, parent, predicate, process_fn,
|
||||
the_limit, parser);
|
||||
ts_tree_cursor_delete (&cursor);
|
||||
|
@ -16838,6 +16838,13 @@ redisplay_internal (void)
|
||||
/* Only GC scrollbars when we redisplay the whole frame. */
|
||||
= f->redisplay || !REDISPLAY_SOME_P ();
|
||||
bool f_redisplay_flag = f->redisplay;
|
||||
|
||||
/* The X error handler may have deleted that frame
|
||||
before we went back to retry_frame. This must come
|
||||
before any accesses to f->terminal. */
|
||||
if (!FRAME_LIVE_P (f))
|
||||
continue;
|
||||
|
||||
/* Mark all the scroll bars to be removed; we'll redeem
|
||||
the ones we want when we redisplay their windows. */
|
||||
if (gcscrollbars && FRAME_TERMINAL (f)->condemn_scroll_bars_hook)
|
||||
@ -16845,7 +16852,6 @@ redisplay_internal (void)
|
||||
|
||||
if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
|
||||
{
|
||||
|
||||
/* Don't allow freeing images and faces for this
|
||||
frame as long as the frame's update wasn't
|
||||
completed. This prevents crashes when some Lisp
|
||||
|
@ -82,6 +82,40 @@
|
||||
(should-not (buffer-live-p buffer-1))
|
||||
(should (buffer-live-p buffer-2))))))
|
||||
|
||||
(ert-deftest ert-test-with-buffer-selected/current ()
|
||||
(let ((origbuf (current-buffer)))
|
||||
(ert-with-test-buffer ()
|
||||
(let ((buf (current-buffer)))
|
||||
(should (not (eq buf origbuf)))
|
||||
(with-current-buffer origbuf
|
||||
(ert-with-buffer-selected buf
|
||||
(should (eq (current-buffer) buf))))))))
|
||||
|
||||
(ert-deftest ert-test-with-buffer-selected/selected ()
|
||||
(ert-with-test-buffer ()
|
||||
(ert-with-buffer-selected (current-buffer)
|
||||
(should (eq (window-buffer) (current-buffer))))))
|
||||
|
||||
(ert-deftest ert-test-with-buffer-selected/nil-buffer ()
|
||||
(ert-with-test-buffer ()
|
||||
(let ((buf (current-buffer)))
|
||||
(ert-with-buffer-selected nil
|
||||
(should (eq (window-buffer) buf))))))
|
||||
|
||||
(ert-deftest ert-test-with-buffer-selected/modification-hooks ()
|
||||
(ert-with-test-buffer ()
|
||||
(ert-with-buffer-selected (current-buffer)
|
||||
(should (null inhibit-modification-hooks)))))
|
||||
|
||||
(ert-deftest ert-test-with-buffer-selected/read-only ()
|
||||
(ert-with-test-buffer ()
|
||||
(ert-with-buffer-selected (current-buffer)
|
||||
(should (null inhibit-read-only))
|
||||
(should (null buffer-read-only)))))
|
||||
|
||||
(ert-deftest ert-test-with-buffer-selected/return-value ()
|
||||
(should (equal (ert-with-buffer-selected nil "foo") "foo")))
|
||||
|
||||
(ert-deftest ert-test-with-test-buffer-selected/selected ()
|
||||
(ert-with-test-buffer-selected ()
|
||||
(should (eq (window-buffer) (current-buffer)))))
|
||||
@ -90,6 +124,11 @@
|
||||
(ert-with-test-buffer-selected ()
|
||||
(should (null inhibit-modification-hooks))))
|
||||
|
||||
(ert-deftest ert-test-with-test-buffer-selected/read-only ()
|
||||
(ert-with-test-buffer-selected ()
|
||||
(should (null inhibit-read-only))
|
||||
(should (null buffer-read-only))))
|
||||
|
||||
(ert-deftest ert-test-with-test-buffer-selected/return-value ()
|
||||
(should (equal (ert-with-test-buffer-selected () "foo") "foo")))
|
||||
|
||||
|
@ -478,5 +478,84 @@ baz"))))
|
||||
(should (equal (diff-hunk-file-names)
|
||||
'("/tmp/ange-ftp1351895K.el" "/tmp/ange-ftp13518wvE.el")))))
|
||||
|
||||
(ert-deftest diff-mode-test-fixups-added-lines ()
|
||||
"Check that `diff-fixup-modifs' works well with hunks with added lines."
|
||||
(let ((patch "--- file
|
||||
+++ file
|
||||
@@ -0,0 +1,15 @@
|
||||
+1
|
||||
+2
|
||||
+3
|
||||
+4
|
||||
"))
|
||||
(with-temp-buffer
|
||||
(insert patch)
|
||||
(diff-fixup-modifs (point-min) (point-max))
|
||||
(should (equal (buffer-string) "--- file
|
||||
+++ file
|
||||
@@ -0,0 +1,4 @@
|
||||
+1
|
||||
+2
|
||||
+3
|
||||
+4
|
||||
"))))
|
||||
(let ((patch "--- file
|
||||
+++ file
|
||||
@@ -389,5 +398,6 @@
|
||||
while (1)
|
||||
;
|
||||
+ # not needed
|
||||
# at all
|
||||
# stop
|
||||
"))
|
||||
(with-temp-buffer
|
||||
(insert patch)
|
||||
(diff-fixup-modifs (point-min) (point-max))
|
||||
(should (equal (buffer-string) "--- file
|
||||
+++ file
|
||||
@@ -389,4 +398,5 @@
|
||||
while (1)
|
||||
;
|
||||
+ # not needed
|
||||
# at all
|
||||
# stop
|
||||
")))))
|
||||
|
||||
(ert-deftest diff-mode-test-fixups-empty-hunks ()
|
||||
"Check that `diff-fixup-modifs' works well with empty hunks."
|
||||
(let ((patch "--- file
|
||||
+++ file
|
||||
@@ -1 +1 @@
|
||||
-1
|
||||
@@ -10 +10 @@
|
||||
-1
|
||||
+1
|
||||
--- otherfile
|
||||
+++ otherfile
|
||||
@@ -1 +1 @@
|
||||
+2
|
||||
@@ -10 +10 @@
|
||||
-1
|
||||
+1
|
||||
"))
|
||||
(with-temp-buffer
|
||||
(insert patch)
|
||||
(diff-fixup-modifs (point-min) (point-max))
|
||||
(should (equal (buffer-string) "--- file
|
||||
+++ file
|
||||
@@ -1,1 +1,0 @@
|
||||
-1
|
||||
@@ -10,1 +10,1 @@
|
||||
-1
|
||||
+1
|
||||
--- otherfile
|
||||
+++ otherfile
|
||||
@@ -1,0 +1,1 @@
|
||||
+2
|
||||
@@ -10,1 +10,1 @@
|
||||
-1
|
||||
+1
|
||||
")))))
|
||||
|
||||
(provide 'diff-mode-tests)
|
||||
;;; diff-mode-tests.el ends here
|
||||
|
Loading…
Reference in New Issue
Block a user