commit 69e1aca041c57ba425425d31471e1c8f86d3bf04 (HEAD, refs/remotes/origin/master) Author: Po Lu Date: Wed Sep 11 13:26:17 2024 +0800 ; * exec/configure.ac: Update version. diff --git a/exec/configure.ac b/exec/configure.ac index 41c4c8b5d42..634daa7906a 100644 --- a/exec/configure.ac +++ b/exec/configure.ac @@ -22,7 +22,7 @@ dnl You should have received a copy of the GNU General Public License dnl along with GNU Emacs. If not, see . AC_PREREQ([2.65]) -AC_INIT([libexec], [30.0.90], [bug-gnu-emacs@gnu.org], [], +AC_INIT([libexec], [31.0.50], [bug-gnu-emacs@gnu.org], [], [https://www.gnu.org/software/emacs/]) AH_TOP([/* Copyright (C) 2024 Free Software Foundation, Inc. commit a139c3d6d888219bb3cb3c0c5a3eb6268c9b7a29 Author: Po Lu Date: Wed Sep 11 13:25:48 2024 +0800 * src/treesit.h (struct Lisp_TS_Parser): Correct merge error. diff --git a/src/treesit.h b/src/treesit.h index 40b8b531ac4..14ffd553712 100644 --- a/src/treesit.h +++ b/src/treesit.h @@ -89,6 +89,10 @@ struct Lisp_TS_Parser associated buffer. This is for parsers created by treesit-parse-string, which uses a hidden temp buffer. */ bool need_to_gc_buffer; + /* This field is set to true when treesit_ensure_parsed runs, to + prevent infinite recursion due to calling after change + functions. */ + bool within_reparse; }; /* A wrapper around a tree-sitter node. */ commit 76487b7454b88557d7c8dec7136b7a09aacfb5bf Merge: 652a8a0838b ee3e3a63111 Author: Po Lu Date: Wed Sep 11 13:21:58 2024 +0800 Merge from savannah/emacs-30 ee3e3a63111 ; Update version number of exec/configure.ac c5925b6ba5f Fix heex-ts-mode indentation following previews elixir-mo... c3383be5f04 ; * admin/make-tarball.txt: Improve last change. 8ddb54117f1 ; * admin/make-tarball.txt: Remove now unnecessary config... 7e194d33f90 * lisp/ldefs-boot.el: Update. 9019536ea66 Fix use of Uniscribe font driver in MinGW build 5c55c860db7 Avoid crashes in redisplay in batch-mode testing ba2190e1ae7 ; * etc/NEWS: Fix indentation. 818c0cc9a51 eglot-test-rust-completion-exit-function: Fix failure in ... f47297782bd ; * doc/lispref/searching.texi (Rx Notation): Simplify rx... 03e56981675 Clarify the semantics of 'string-pixel-width' 9f0603207b1 ; * src/treesit.c: Minor cleanups of recent changes. e0d3f743957 * src/treesit.c (treesit_debug_print_parser_list): Fix fo... bed38ded730 ; * src/treesit.c (treesit_debug_print_parser_list): Fix ... 18c6487dbd0 ; * src/treesit.c: Add a prototype so there's no warning ... bf23382f1f2 Read more on each call to treesit's buffer reader 3435464452b Fix the range handling in treesit.c 3fcec09f754 Add debugging function for treesit.c 0fd259d166c Fix elixir-ts-mode's range query 2329b36b1fb ; project-files-relative-names: Update docstring (bug#72701) e55e2e1c6ba Make json-serialize always return a unibyte string (bug#7... 89c99891b2b ; * doc/lispref/os.texi (Suspending Emacs): Fix last change. 4f044d0d3df ; Improve documentation of 'suspend-emacs' commit ee3e3a6311196129104881d6e9097bb54d8843af (refs/remotes/origin/emacs-30) Author: Po Lu Date: Wed Sep 11 12:53:29 2024 +0800 ; Update version number of exec/configure.ac * admin/admin.el (set-version): Update AC_INIT expansion in exec/configure.ac. * exec/configure.ac: Update version to 30.0.90. diff --git a/admin/admin.el b/admin/admin.el index edd3246a1a3..b3f63eef5bb 100644 --- a/admin/admin.el +++ b/admin/admin.el @@ -112,6 +112,10 @@ Root must be the root of an Emacs source tree." (rx (and "AC_INIT" (1+ (not (in ?,))) ?, (0+ space) ?\[ (submatch (1+ (in "0-9.")))))) + (set-version-in-file root "exec/configure.ac" version + (rx (and "AC_INIT" (1+ (not (in ?,))) + ?, (0+ space) ?\[ + (submatch (1+ (in "0-9.")))))) (set-version-in-file root "nt/README.W32" version (rx (and "version" (1+ space) (submatch (1+ (in "0-9.")))))) diff --git a/exec/configure.ac b/exec/configure.ac index a473a1dc633..3c8d066b0e6 100644 --- a/exec/configure.ac +++ b/exec/configure.ac @@ -22,7 +22,7 @@ dnl You should have received a copy of the GNU General Public License dnl along with GNU Emacs. If not, see . AC_PREREQ([2.65]) -AC_INIT([libexec], [30.0.50], [bug-gnu-emacs@gnu.org], [], +AC_INIT([libexec], [30.0.90], [bug-gnu-emacs@gnu.org], [], [https://www.gnu.org/software/emacs/]) AH_TOP([/* Copyright (C) 2024 Free Software Foundation, Inc. commit c5925b6ba5f7821ea72ebd26b76e405cecaabb8e Author: Yuan Fu Date: Tue Sep 10 19:29:31 2024 -0700 Fix heex-ts-mode indentation following previews elixir-mode change After the previous fix in elixir-ts-mode (0fd259d166c), embedded heex code are indented like this: 1 defmodule Foo do 2 def foo(assigns) do 3 ~H""" 4 5 text 6 7 """ 8 end 9 end The indent rule finds the beginning of the parent heex node, and uses the indentation of that line as anchor with an offset of 0. Previously the parent heex node (fragment) starts at EOL of line 3; after the previous commit, it now starts at BOL of line 4. To fix the indentation, I changed the anchor to the beginning of the elixir (rather than heex) node at point, which is at EOL at line 3. * lisp/progmodes/heex-ts-mode.el (heex-ts--indent-rules): Use the elixir node that contains the heex code as the anchor, instead of the heex root node. diff --git a/lisp/progmodes/heex-ts-mode.el b/lisp/progmodes/heex-ts-mode.el index 07b8bfdc74f..b527d96b579 100644 --- a/lisp/progmodes/heex-ts-mode.el +++ b/lisp/progmodes/heex-ts-mode.el @@ -64,16 +64,18 @@ (let ((offset heex-ts-indent-offset)) `((heex ((parent-is "fragment") - (lambda (node parent &rest _) + (lambda (_node _parent bol &rest _) ;; If HEEx is embedded indent to parent ;; otherwise indent to the bol. (if (eq (treesit-language-at (point-min)) 'heex) (point-min) (save-excursion - (goto-char (treesit-node-start parent)) + (goto-char (treesit-node-start + (treesit-node-at bol 'elixir))) (back-to-indentation) (point)) - )) 0) + )) + 0) ((node-is "end_tag") parent-bol 0) ((node-is "end_component") parent-bol 0) ((node-is "end_slot") parent-bol 0) commit c3383be5f043a1efe6f9650e8d0a6d4616ca4eeb Author: Andrea Corallo Date: Wed Sep 11 00:43:47 2024 +0200 ; * admin/make-tarball.txt: Improve last change. diff --git a/admin/make-tarball.txt b/admin/make-tarball.txt index 9c37a8b2bb1..8e23165b257 100644 --- a/admin/make-tarball.txt +++ b/admin/make-tarball.txt @@ -56,7 +56,7 @@ General steps (for each step, check for possible errors): Makefiles to be present. ./autogen.sh - ./configure && make + ./configure --without-native-compilation && make For a release (as opposed to pretest), visit etc/NEWS and use the "M-x emacs-news-delete-temporary-markers" command to delete any commit 8ddb54117f175d8e11f936c850513dcbd6697280 Author: Andrea Corallo Date: Wed Sep 11 00:39:26 2024 +0200 ; * admin/make-tarball.txt: Remove now unnecessary configure flag. diff --git a/admin/make-tarball.txt b/admin/make-tarball.txt index 85a8ef2624d..9c37a8b2bb1 100644 --- a/admin/make-tarball.txt +++ b/admin/make-tarball.txt @@ -55,14 +55,8 @@ General steps (for each step, check for possible errors): because some of the commands below run Make, so they need Makefiles to be present. - For Emacs 28 and later, as long as --with-native-compilation is - not the default, the tree needs to be configured with - native-compilation enabled, to ensure all the pertinent *.elc - files will end up in the tarball. Otherwise, the *.eln files - might not build correctly on the user's system. - ./autogen.sh - ./configure --with-native-compilation && make + ./configure && make For a release (as opposed to pretest), visit etc/NEWS and use the "M-x emacs-news-delete-temporary-markers" command to delete any commit 7e194d33f90a0e4b9b88d90c4759f14e8fffda07 (tag: refs/tags/emacs-30.0.90) Author: Andrea Corallo Date: Tue Sep 10 23:39:34 2024 +0200 * lisp/ldefs-boot.el: Update. diff --git a/lisp/ldefs-boot.el b/lisp/ldefs-boot.el index d4eb42472d8..51a2333826e 100644 --- a/lisp/ldefs-boot.el +++ b/lisp/ldefs-boot.el @@ -9497,7 +9497,7 @@ Turn on EDT Emulation." t) ;;; Generated autoloads from progmodes/eglot.el -(push (purecopy '(eglot 1 17)) package--builtin-versions) +(push (purecopy '(eglot 1 17 30)) package--builtin-versions) (define-obsolete-function-alias 'eglot-update #'eglot-upgrade-eglot "29.1") (autoload 'eglot "eglot" "\ Start LSP server for PROJECT's buffers under MANAGED-MAJOR-MODES. @@ -20493,7 +20493,7 @@ Makefile mode can be configured by modifying the following variables: to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \"it seems necessary\". `makefile-special-targets-list': - List of special targets. You will be offered to complete + List of special targets. You will be offered to complete on one of those in the minibuffer whenever you enter a `.'. at the beginning of a line in Makefile mode. @@ -23043,7 +23043,7 @@ Coloring: ;;; Generated autoloads from org/org.el -(push (purecopy '(org 9 7 10)) package--builtin-versions) +(push (purecopy '(org 9 7 11)) package--builtin-versions) (autoload 'org-babel-do-load-languages "org" "\ Load the languages defined in `org-babel-load-languages'. @@ -31146,6 +31146,10 @@ This construct can only be used with lexical binding. (autoload 'string-pixel-width "subr-x" "\ Return the width of STRING in pixels. +If you call this function to measure pixel width of a string +with embedded newlines, it returns the width of the widest +substring that does not include newlines. + (fn STRING)") (function-put 'string-pixel-width 'important-return-value 't) (autoload 'string-glyph-split "subr-x" "\ @@ -31372,6 +31376,14 @@ disabled. (autoload 'tab-line-mode "tab-line" "\ Toggle display of tab line in the windows displaying the current buffer. +When this mode is enabled, each window displays a tab line on its +top screen line. The tab line is a row of tabs -- buttons which +you can click to have the window display the buffer whose name is +shown on the button. Clicking on the \"x\" icon of the button +removes the button (but does not kill the corresponding buffer). +In addition, the tab line shows a \"+\" button which adds a new +button, so you could have one more buffer shown on the tab line. + This is a minor mode. If called interactively, toggle the `Tab-Line mode' mode. If the prefix argument is positive, enable the mode, and if it is zero or negative, disable the mode. commit 9019536ea66ac0d47ea6f1ef690efd16e32c7ec4 Author: Eli Zaretskii Date: Tue Sep 10 15:14:47 2024 +0300 Fix use of Uniscribe font driver in MinGW build This was inadvertently broken when Windows 9X support was fixed in June 2024. * src/w32uniscribe.c (syms_of_w32uniscribe_for_pdumper): Set 'uniscribe_available' non-zero in non-Cygwin builds. (Bug#73159) diff --git a/src/w32uniscribe.c b/src/w32uniscribe.c index 471bdf544d8..da5d843acec 100644 --- a/src/w32uniscribe.c +++ b/src/w32uniscribe.c @@ -1573,9 +1573,9 @@ syms_of_w32uniscribe_for_pdumper (void) pfnScriptGetGlyphABCWidth = &ScriptGetGlyphABCWidth; pfnScriptFreeCache = &ScriptFreeCache; pfnScriptGetCMap = &ScriptGetCMap; +#endif /* Cygwin */ uniscribe_available = 1; -#endif /* Cygwin */ register_font_driver (&uniscribe_font_driver, NULL); commit 5c55c860db7891d1301d0bac78c03a8751ebe642 Author: Eli Zaretskii Date: Tue Sep 10 14:43:52 2024 +0300 Avoid crashes in redisplay in batch-mode testing * src/xdisp.c (try_window_id): Don't crash for "initial" frame. (Bug#72765) diff --git a/src/xdisp.c b/src/xdisp.c index bf7d84cdcb7..a1319e76f49 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -22089,7 +22089,8 @@ try_window_id (struct window *w) /* Window must either use window-based redisplay or be full width. */ if (!FRAME_WINDOW_P (f) - && (!FRAME_LINE_INS_DEL_OK (f) + && (FRAME_INITIAL_P (f) + || !FRAME_LINE_INS_DEL_OK (f) || !WINDOW_FULL_WIDTH_P (w))) GIVE_UP (4); commit 652a8a0838b38a6eab85c55fc61cedd1c61ef20f Author: Michael Albinus Date: Tue Sep 10 10:04:01 2024 +0200 Avoid 100% CPU load in Tramp * lisp/net/tramp.el (tramp-wait-for-regexp): Add (sit-for 0.005) prior calling `tramp-accept-process-output'. This avoids 100% CPU load. (Bug#73046) diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 5834b496e1b..dc6a8105730 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -6041,6 +6041,8 @@ nil." (let ((found (tramp-check-for-regexp proc regexp))) (with-tramp-timeout (timeout) (while (not found) + ;; This is needed to yield the CPU, otherwise we'll see 100% CPU load. + (sit-for 0.005) (tramp-accept-process-output proc) (unless (process-live-p proc) (tramp-error-with-buffer commit ba2190e1ae761b11d5fcb9393869f04d0a1d42a7 Author: Michael Albinus Date: Tue Sep 10 09:24:33 2024 +0200 ; * etc/NEWS: Fix indentation. diff --git a/etc/NEWS b/etc/NEWS index 239182427bb..18d4c6b2158 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3076,7 +3076,7 @@ entire SQL file. This is appropriate since it is an encoding operation. In the unlikely event that a multibyte string is needed, the result can be decoded using - (decode-coding-string RESULT 'utf-8) + (decode-coding-string RESULT 'utf-8) --- *** The parser keeps duplicated object keys in alist and plist output. commit 818c0cc9a51a1d678749404cdacdf640d6f32d6e Author: Dmitry Gutov Date: Tue Sep 10 04:34:53 2024 +0300 eglot-test-rust-completion-exit-function: Fix failure in -Q session * test/lisp/progmodes/eglot-tests.el (eglot--call-with-fixture): Check for buffer liveness (https://debbugs.gnu.org/72765#29). (eglot-test-rust-completion-exit-function): Don't expect snippet expansion to happen (no yasnippet in batch mode). diff --git a/test/lisp/progmodes/eglot-tests.el b/test/lisp/progmodes/eglot-tests.el index e0168baee54..77b808e01ee 100644 --- a/test/lisp/progmodes/eglot-tests.el +++ b/test/lisp/progmodes/eglot-tests.el @@ -136,9 +136,11 @@ directory hierarchy." (jsonrpc-events-buffer server))))) (cond (noninteractive (dolist (buffer buffers) - (eglot--test-message "contents of `%s':" (buffer-name buffer)) - (princ (with-current-buffer buffer (buffer-string)) - 'external-debugging-output))) + (eglot--test-message "contents of `%s' %S:" (buffer-name buffer) buffer) + (if (buffer-live-p buffer) + (princ (with-current-buffer buffer (buffer-string)) + 'external-debugging-output) + (princ "Killed\n" #'external-debugging-output)))) (t (eglot--test-message "Preserved for inspection: %s" (mapconcat #'buffer-name buffers ", ")))))))) @@ -724,7 +726,7 @@ directory hierarchy." (minibuffer-choose-completion t)) (should (equal - "fn test() -> i32 { let v: usize = 1; v.count_ones().1234567890;" + "fn test() -> i32 { let v: usize = 1; v.count_ones.1234567890;" (buffer-string)))))) (ert-deftest eglot-test-basic-xref () commit f47297782bdb5e5a07e02f119c8013d11f7d7fae Author: Mattias Engdegård Date: Mon Sep 9 15:18:36 2024 +0200 ; * doc/lispref/searching.texi (Rx Notation): Simplify rx example diff --git a/doc/lispref/searching.texi b/doc/lispref/searching.texi index 7b4a9100e77..4691a6557e8 100644 --- a/doc/lispref/searching.texi +++ b/doc/lispref/searching.texi @@ -1028,13 +1028,13 @@ programming language: @example @group -(rx "/*" ; Initial /* +(rx "/*" ; Initial /* (zero-or-more - (or (not (any "*")) ; Either non-*, - (seq "*" ; or * followed by - (not (any "/"))))) ; non-/ - (one-or-more "*") ; At least one star, - "/") ; and the final / + (or (not "*") ; Either non-*, + (seq "*" ; or * followed by + (not "/")))) ; non-/ + (one-or-more "*") ; At least one star, + "/") ; and the final / @end group @end example commit 03e56981675c9533f844257bc7f0bc5603bb58fa Author: Eli Zaretskii Date: Mon Sep 9 14:28:12 2024 +0300 Clarify the semantics of 'string-pixel-width' * doc/lispref/display.texi (Size of Displayed Text): * lisp/emacs-lisp/subr-x.el (string-pixel-width): * src/xdisp.c (Fwindow_text_pixel_size, Fbuffer_text_pixel_size): Doc fixes. (Bug#73129) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 9a43ad0568a..c0fbde5d96a 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -2238,7 +2238,7 @@ displayed in a given window. This function is used by it contains. @defun window-text-pixel-size &optional window from to x-limit y-limit mode-lines ignore-line-at-end -This function returns the size of the text of @var{window}'s buffer in +This function returns the dimensions of the text of @var{window}'s buffer in pixels. @var{window} must be a live window and defaults to the selected one. The return value is a cons of the maximum pixel-width of any text line and the maximum pixel-height of all text lines. This @@ -2387,7 +2387,11 @@ meaning as with @code{window-text-pixel-size}. @defun string-pixel-width string This is a convenience function that uses @code{window-text-pixel-size} -to compute the width of @var{string} (in pixels). +to compute the width of @var{string} (in pixels). Caveat: if you call +this function to measure the width of a string with embedded newlines, +it will then return the width of the widest substring that does not +include newlines. The meaning of this result is the widest line taken +by the string if inserted into a buffer. @end defun @defun line-pixel-height diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el index e725c490aba..d5ed934f805 100644 --- a/lisp/emacs-lisp/subr-x.el +++ b/lisp/emacs-lisp/subr-x.el @@ -338,7 +338,11 @@ This construct can only be used with lexical binding." ;;;###autoload (defun string-pixel-width (string) - "Return the width of STRING in pixels." + "Return the width of STRING in pixels. + +If you call this function to measure pixel width of a string +with embedded newlines, it returns the width of the widest +substring that does not include newlines." (declare (important-return-value t)) (if (zerop (length string)) 0 diff --git a/src/xdisp.c b/src/xdisp.c index 5add42ef11b..bf7d84cdcb7 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -11774,7 +11774,7 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, } DEFUN ("window-text-pixel-size", Fwindow_text_pixel_size, Swindow_text_pixel_size, 0, 7, 0, - doc: /* Return the size of the text of WINDOW's buffer in pixels. + doc: /* Return the dimensions of the text of WINDOW's buffer in pixels. WINDOW must be a live window and defaults to the selected one. The return value is a cons of the maximum pixel-width of any text line and the pixel-height of all the text lines in the accessible portion of @@ -11854,7 +11854,7 @@ screen line that includes TO to the returned height of the text. */) } DEFUN ("buffer-text-pixel-size", Fbuffer_text_pixel_size, Sbuffer_text_pixel_size, 0, 4, 0, - doc: /* Return size of whole text of BUFFER-OR-NAME in WINDOW. + doc: /* Return the dimensions of whole text of BUFFER-OR-NAME in WINDOW. BUFFER-OR-NAME must specify a live buffer or the name of a live buffer and defaults to the current buffer. WINDOW must be a live window and defaults to the selected one. The return value is a cons of the maximum commit 9f0603207b17084563c73f271c397c0c469bf3e9 Author: Eli Zaretskii Date: Mon Sep 9 14:03:15 2024 +0300 ; * src/treesit.c: Minor cleanups of recent changes. diff --git a/src/treesit.c b/src/treesit.c index 548dfeb8c6e..ee83486b92a 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -487,8 +487,7 @@ treesit_initialize (void) /*** Debugging */ -void -treesit_debug_print_parser_list (char *, Lisp_Object); +void treesit_debug_print_parser_list (char *, Lisp_Object); void treesit_debug_print_parser_list (char *msg, Lisp_Object parser) @@ -1233,7 +1232,7 @@ treesit_read_buffer (void *parser, uint32_t byte_index, else { beg = (char *) BUF_BYTE_ADDRESS (buffer, byte_pos); - ptrdiff_t gap_bytepos = buffer->text->gpt_byte; + ptrdiff_t gap_bytepos = BUF_GPT_BYTE (buffer); len = (byte_pos < gap_bytepos) ? gap_bytepos - byte_pos : visible_end - byte_pos; } commit e0d3f7439573f2c5bde95dbb9005a4efc954aa0b Author: Andrea Corallo Date: Mon Sep 9 09:09:48 2024 +0200 * src/treesit.c (treesit_debug_print_parser_list): Fix format string. diff --git a/src/treesit.c b/src/treesit.c index d1c50771e23..548dfeb8c6e 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -521,7 +521,7 @@ treesit_debug_print_parser_list (char *msg, Lisp_Object parser) for (int idx = 0; idx < len; idx++) { TSRange range = ranges[idx]; - printf (" [%d, %d)", range.start_byte, range.end_byte); + printf (" [%"PRIu32", %"PRIu32")", range.start_byte, range.end_byte); /* if (!parser->need_reparse) */ /* { */ commit bed38ded730130d63f08af7ad4049d87efe9bcf8 Author: Yuan Fu Date: Sun Sep 8 21:14:00 2024 -0700 ; * src/treesit.c (treesit_debug_print_parser_list): Fix formatting. diff --git a/src/treesit.c b/src/treesit.c index 0effb5d13b5..d1c50771e23 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -487,8 +487,11 @@ treesit_initialize (void) /*** Debugging */ -void treesit_debug_print_parser_list (char *, Lisp_Object); -void treesit_debug_print_parser_list (char *msg, Lisp_Object parser) +void +treesit_debug_print_parser_list (char *, Lisp_Object); + +void +treesit_debug_print_parser_list (char *msg, Lisp_Object parser) { struct buffer *buf = XBUFFER (XTS_PARSER (parser)->buffer); char *buf_name = SSDATA (BVAR (buf, name)); commit 18c6487dbd06ed01b5736d8c94582c5b72006b65 Author: Yuan Fu Date: Sun Sep 8 21:04:29 2024 -0700 ; * src/treesit.c: Add a prototype so there's no warning about it. diff --git a/src/treesit.c b/src/treesit.c index b047f0344cc..0effb5d13b5 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -487,6 +487,7 @@ treesit_initialize (void) /*** Debugging */ +void treesit_debug_print_parser_list (char *, Lisp_Object); void treesit_debug_print_parser_list (char *msg, Lisp_Object parser) { struct buffer *buf = XBUFFER (XTS_PARSER (parser)->buffer); commit bf23382f1f2d6ea072db4e4750f8a345f77a3ef2 Author: Yuan Fu Date: Sun Sep 8 17:46:18 2024 -0700 Read more on each call to treesit's buffer reader * src/treesit.c (treesit_read_buffer): Read until the gap or visible end, instead of reading a single char. diff --git a/src/treesit.c b/src/treesit.c index 970754f3c1b..b047f0344cc 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -1225,11 +1225,13 @@ treesit_read_buffer (void *parser, uint32_t byte_index, beg = NULL; len = 0; } - /* Normal case, read a character. */ + /* Normal case, read until the gap or visible end. */ else { beg = (char *) BUF_BYTE_ADDRESS (buffer, byte_pos); - len = BYTES_BY_CHAR_HEAD ((int) *beg); + ptrdiff_t gap_bytepos = buffer->text->gpt_byte; + len = (byte_pos < gap_bytepos) + ? gap_bytepos - byte_pos : visible_end - byte_pos; } /* We never let tree-sitter to parse buffers that large so this assertion should never hit. */ commit 3435464452b4947098b8ccbe93e5c0afdd2ed06e Author: Yuan Fu Date: Sun Sep 8 17:50:52 2024 -0700 Fix the range handling in treesit.c 1. In treesit_sync_visible_region, reduce the ranges for a parser so it doesn't go beyond the visible range. 2. To avoid possible infinite recursion, add a within_reparse field to parsers. Previously we were using the need_reparse field to avoid infinite recursion, but lisp programs in a parser's after change hook might make some buffer edit which turns need_reparse to true. To avoid that, we now use an explicit field. If a parser's after change function makes a buffer edit, lisp program ends up with a desynced parse tree, but that's better than possible infinite recursion. Also after change function shouldn't edit the buffer. 3. In treesit_make_ranges, use parser's visible_beg instead of buffer's BEGV. I mean technically whenever we make ranges, buffer's BEGV should be equal to parser's visible_beg, but better not take that uncertainty, also makes the code more readable. 4. In Ftreesit_parser_included_ranges, move visible region sync code before the body of the function. * src/treesit.c (treesit_sync_visible_region): Minimally fix ranges so it doesn't exceed parser's visible range. (treesit_call_after_change_functions): Update calling sigature to treesit_make_ranges. (treesit_ensure_parsed, make_treesit_parser): Use the new field within_reparse. (treesit_make_ranges): Use parser's visible_beg instead of buffer's BEGV. (Ftreesit_parser_included_ranges): Move visible region check before function body. * src/treesit.h (Lisp_TS_Parser): Add new field within_reparse. diff --git a/src/treesit.c b/src/treesit.c index 351bd65819a..970754f3c1b 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -1045,6 +1045,48 @@ treesit_sync_visible_region (Lisp_Object parser) XTS_PARSER (parser)->visible_beg = visible_beg; XTS_PARSER (parser)->visible_end = visible_end; + + /* Fix ranges so that the ranges stays with in visible_end. Here we + try to do minimal work so that the ranges is minimally correct such + that there's no OOB error. Usually treesit-update-ranges should + update the parser with actually correct ranges. */ + if (NILP (XTS_PARSER (parser)->last_set_ranges)) return; + uint32_t len; + const TSRange *ranges + = ts_parser_included_ranges (XTS_PARSER (parser)->parser, &len); + /* We might need to discard some ranges that exceeds visible_end, in + that case, new_len is the length of the new ranges array (which + will be shorter than len). */ + uint32_t new_len = 0; + uint32_t new_end = 0; + for (int idx = 0; idx < len; idx++) + { + TSRange range = ranges[idx]; + /* If this range starts after visible_end, we don't include this + range and the ranges after it in the new ranges. */ + if (range.start_byte + visible_beg >= visible_end) + break; + /* If this range's end is after visible_end, we don't include any + ranges after it, and changes the end of this range to + visible_end. */ + if (range.end_byte + visible_beg > visible_end) + { + new_end = visible_end - visible_beg; + new_len++; + break; + } + new_len++; + } + if (new_len != len || new_end != 0) + { + TSRange *new_ranges = xmalloc (sizeof (TSRange) * new_len); + memcpy (new_ranges, ranges, sizeof (TSRange) * new_len); + new_ranges[new_len - 1].end_byte = new_end; + /* TODO: What should we do if this fails? */ + ts_parser_set_included_ranges (XTS_PARSER (parser)->parser, + new_ranges, new_len); + xfree (new_ranges); + } } static void @@ -1057,7 +1099,8 @@ treesit_check_buffer_size (struct buffer *buffer) make_fixnum (buffer_size_bytes)); } -static Lisp_Object treesit_make_ranges (const TSRange *, uint32_t, struct buffer *); +static Lisp_Object treesit_make_ranges (const TSRange *, uint32_t, + Lisp_Object, struct buffer *); static void treesit_call_after_change_functions (TSTree *old_tree, TSTree *new_tree, @@ -1071,7 +1114,7 @@ treesit_call_after_change_functions (TSTree *old_tree, TSTree *new_tree, { uint32_t len; TSRange *ranges = ts_tree_get_changed_ranges (old_tree, new_tree, &len); - lisp_ranges = treesit_make_ranges (ranges, len, buf); + lisp_ranges = treesit_make_ranges (ranges, len, parser, buf); xfree (ranges); } else @@ -1098,6 +1141,9 @@ treesit_call_after_change_functions (TSTree *old_tree, TSTree *new_tree, static void treesit_ensure_parsed (Lisp_Object parser) { + if (XTS_PARSER (parser)->within_reparse) return; + XTS_PARSER (parser)->within_reparse = true; + struct buffer *buffer = XBUFFER (XTS_PARSER (parser)->buffer); /* Before we parse, catch up with the narrowing situation. */ @@ -1106,10 +1152,11 @@ treesit_ensure_parsed (Lisp_Object parser) because it might set the flag to true. */ treesit_sync_visible_region (parser); - /* Make sure this comes before everything else, see comment - (ref:notifier-inside-ensure-parsed) for more detail. */ if (!XTS_PARSER (parser)->need_reparse) - return; + { + XTS_PARSER (parser)->within_reparse = false; + return; + } TSParser *treesit_parser = XTS_PARSER (parser)->parser; TSTree *tree = XTS_PARSER (parser)->tree; @@ -1134,14 +1181,10 @@ treesit_ensure_parsed (Lisp_Object parser) XTS_PARSER (parser)->need_reparse = false; XTS_PARSER (parser)->timestamp++; - /* After-change functions should run at the very end, most crucially - after need_reparse is set to false, this way if the function - calls some tree-sitter function which invokes - treesit_ensure_parsed again, it returns early and do not - recursively call the after change functions again. - (ref:notifier-inside-ensure-parsed) */ treesit_call_after_change_functions (tree, new_tree, parser); ts_tree_delete (tree); + + XTS_PARSER (parser)->within_reparse = false; } /* This is the read function provided to tree-sitter to read from a @@ -1224,6 +1267,7 @@ make_treesit_parser (Lisp_Object buffer, TSParser *parser, lisp_parser->visible_end = BUF_ZV_BYTE (XBUFFER (buffer)); lisp_parser->timestamp = 0; lisp_parser->deleted = false; + lisp_parser->within_reparse = false; eassert (lisp_parser->visible_beg <= lisp_parser->visible_end); return make_lisp_ptr (lisp_parser, Lisp_Vectorlike); } @@ -1672,14 +1716,14 @@ treesit_check_range_argument (Lisp_Object ranges) convert between tree-sitter buffer offset and buffer position. */ static Lisp_Object treesit_make_ranges (const TSRange *ranges, uint32_t len, - struct buffer *buffer) + Lisp_Object parser, struct buffer *buffer) { Lisp_Object list = Qnil; for (int idx = 0; idx < len; idx++) { TSRange range = ranges[idx]; - uint32_t beg_byte = range.start_byte + BUF_BEGV_BYTE (buffer); - uint32_t end_byte = range.end_byte + BUF_BEGV_BYTE (buffer); + uint32_t beg_byte = range.start_byte + XTS_PARSER (parser)->visible_beg; + uint32_t end_byte = range.end_byte + XTS_PARSER (parser)->visible_beg; eassert (BUF_BEGV_BYTE (buffer) <= beg_byte); eassert (beg_byte <= end_byte); eassert (end_byte <= BUF_ZV_BYTE (buffer)); @@ -1725,11 +1769,9 @@ buffer. */) if (NILP (ranges)) { /* If RANGES is nil, make parser to parse the whole document. - To do that we give tree-sitter a 0 length, the range is a - dummy. */ - TSRange treesit_range = {{0, 0}, {0, 0}, 0, 0}; + To do that we give tree-sitter a 0 length. */ success = ts_parser_set_included_ranges (XTS_PARSER (parser)->parser, - &treesit_range , 0); + NULL , 0); } else { @@ -1742,7 +1784,6 @@ buffer. */) /* We can use XFIXNUM, XCAR, XCDR freely because we have checked the input by treesit_check_range_argument. */ - for (int idx = 0; !NILP (ranges); idx++, ranges = XCDR (ranges)) { Lisp_Object range = XCAR (ranges); @@ -1787,6 +1828,10 @@ See also `treesit-parser-set-included-ranges'. */) treesit_check_parser (parser); treesit_initialize (); + /* Our return value depends on the buffer state (BUF_BEGV_BYTE, + etc), so we need to sync up. */ + treesit_check_buffer_size (XBUFFER (XTS_PARSER (parser)->buffer)); + treesit_sync_visible_region (parser); /* When the parser doesn't have a range set and we call ts_parser_included_ranges on it, it doesn't return an empty list, but rather return DEFAULT_RANGE. (A single range where start_byte @@ -1799,13 +1844,10 @@ See also `treesit-parser-set-included-ranges'. */) const TSRange *ranges = ts_parser_included_ranges (XTS_PARSER (parser)->parser, &len); - /* Our return value depends on the buffer state (BUF_BEGV_BYTE, - etc), so we need to sync up. */ - treesit_check_buffer_size (XBUFFER (XTS_PARSER (parser)->buffer)); - treesit_sync_visible_region (parser); - struct buffer *buffer = XBUFFER (XTS_PARSER (parser)->buffer); - return treesit_make_ranges (ranges, len, buffer); + + + return treesit_make_ranges (ranges, len, parser, buffer); } DEFUN ("treesit-parser-notifiers", Ftreesit_parser_notifiers, diff --git a/src/treesit.h b/src/treesit.h index d3c6aa4c250..f8227a64b0a 100644 --- a/src/treesit.h +++ b/src/treesit.h @@ -45,9 +45,12 @@ struct Lisp_TS_Parser same tag. A tag is primarily used to differentiate between parsers for the same language. */ Lisp_Object tag; - /* The Lisp ranges last set. This is use to compare to the new - ranges the users wants to set, and avoid reparse if the new - ranges is the same as the last set one. */ + /* The Lisp ranges last set. This is use to compare to the new ranges + the users wants to set, and avoid reparse if the new ranges is the + same as the last set one. This might go out of sync with the + ranges we return from Ftreesit_parser_included_ranges, if we did a + ranges fix in treesit_sync_visible_region, but I don't think + that'll cause any harm. */ Lisp_Object last_set_ranges; /* The buffer associated with this parser. */ Lisp_Object buffer; @@ -82,6 +85,10 @@ struct Lisp_TS_Parser /* If this field is true, parser functions raises treesit-parser-deleted signal. */ bool deleted; + /* This field is set to true when treesit_ensure_parsed runs, to + prevent infinite recursion due to calling after change + functions. */ + bool within_reparse; }; /* A wrapper around a tree-sitter node. */ commit 3fcec09f754af9822339eff3ea15d43eb7d19014 Author: Yuan Fu Date: Sun Sep 8 17:30:21 2024 -0700 Add debugging function for treesit.c * src/treesit.c (treesit_debug_print_parser_list): New function. diff --git a/src/treesit.c b/src/treesit.c index 6e806039df0..351bd65819a 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -484,6 +484,53 @@ treesit_initialize (void) } } + +/*** Debugging */ + +void treesit_debug_print_parser_list (char *msg, Lisp_Object parser) +{ + struct buffer *buf = XBUFFER (XTS_PARSER (parser)->buffer); + char *buf_name = SSDATA (BVAR (buf, name)); + printf ("%s (%s) [%s] <%s>: %ld(%ld)-(%ld)%ld {\n", + msg == NULL ? "" : msg, + SSDATA (SYMBOL_NAME (Vthis_command)), + SSDATA (SYMBOL_NAME (XTS_PARSER (parser)->language_symbol)), + buf_name, BUF_BEG (buf), + BUF_BEGV (buf), BUF_Z (buf), BUF_ZV (buf)); + Lisp_Object tail = BVAR (buf, ts_parser_list); + + FOR_EACH_TAIL (tail) + { + struct Lisp_TS_Parser *parser = XTS_PARSER (XCAR (tail)); + printf ("[%s %s %s %ld-%ld T:%ld]\n", SSDATA (SYMBOL_NAME (parser->language_symbol)), + SSDATA (SYMBOL_NAME (parser->tag)), + parser->need_reparse ? "NEED-R" : "NONEED", + parser->visible_beg, parser->visible_end, + parser->timestamp); + /* Print ranges. */ + uint32_t len; + const TSRange *ranges + = ts_parser_included_ranges (parser->parser, &len); + + if (!(len == 1 && ranges[0].start_byte == 0 && ranges[0].end_byte == -1)) + { + for (int idx = 0; idx < len; idx++) + { + TSRange range = ranges[idx]; + printf (" [%d, %d)", range.start_byte, range.end_byte); + + /* if (!parser->need_reparse) */ + /* { */ + /* eassert (BUF_BEGV_BYTE (buf) <= range.start_byte + parser->visible_beg); */ + /* eassert (range.end_byte + parser->visible_beg <= BUF_ZV_BYTE (buf)); */ + /* } */ + } + printf ("\n"); + } + } + printf ("}\n\n"); +} + /*** Loading language library */ commit 0fd259d166c0dca4d097ad026ac748748ba88497 Author: Yuan Fu Date: Sun Sep 8 17:28:26 2024 -0700 Fix elixir-ts-mode's range query * lisp/progmodes/elixir-ts-mode.el: (elixir-ts--treesit-range-rules): Add underscore in front of the name capture, so Emacs won't put heex parser on it. diff --git a/lisp/progmodes/elixir-ts-mode.el b/lisp/progmodes/elixir-ts-mode.el index 9804152d9ab..815827ed13c 100644 --- a/lisp/progmodes/elixir-ts-mode.el +++ b/lisp/progmodes/elixir-ts-mode.el @@ -572,7 +572,9 @@ (treesit-range-rules :embed 'heex :host 'elixir - '((sigil (sigil_name) @name (:match "^[HF]$" @name) (quoted_content) @heex))))) + '((sigil (sigil_name) @_name + (:match "^[HF]$" @_name) + (quoted_content) @heex))))) (defvar heex-ts--sexp-regexp) (defvar heex-ts--indent-rules) commit 2329b36b1fb0dab969554eb9e1617e31a9755084 Author: Dmitry Gutov Date: Sun Sep 8 23:50:58 2024 +0300 ; project-files-relative-names: Update docstring (bug#72701) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index c38d3f0048a..78f5c127900 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -331,7 +331,10 @@ end it with `/'. DIR must be either `project-root' or one of The file names should be relative to the project root. And this can only happen when all returned files are in the same directory. In other words, the DIRS argument of `project-files' has to be nil or a -list of only one element.") +list of only one element. + +This variable is only meant to be set by Lisp code, not customized by +the user.") (cl-defgeneric project-files (project &optional dirs) "Return a list of files in directories DIRS in PROJECT. commit e55e2e1c6baebbd105f930fa553ec65c74a3000d Author: Mattias Engdegård Date: Sun Sep 8 20:02:34 2024 +0200 Make json-serialize always return a unibyte string (bug#70007) The JSON format is defined as a byte sequence and will always be used as such, so returning a multibyte string makes little sense. * src/json.c (json_out_to_string): Remove. (Fjson_serialize): Return unibyte string. * test/src/json-tests.el (json-serialize/roundtrip) (json-serialize/roundtrip-scalars, json-serialize/string): Update tests. * doc/lispref/text.texi (Parsing JSON): Document. * etc/NEWS: Announce. diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index 278b53d7f65..df56433fd18 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -5844,7 +5844,7 @@ can be serialized to JSON@. Likewise, the parsing functions will return any of the possible types described above. @defun json-serialize object &rest args -This function returns a new Lisp string which contains the JSON +This function returns a new Lisp unibyte string which contains the JSON representation of @var{object}. The argument @var{args} is a list of keyword/argument pairs. The following keywords are accepted: diff --git a/etc/NEWS b/etc/NEWS index a61bdc4a7f3..239182427bb 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3071,6 +3071,13 @@ entire SQL file. ** JSON ++++ +*** 'json-serialize' now always returns a unibyte string. +This is appropriate since it is an encoding operation. In the unlikely +event that a multibyte string is needed, the result can be decoded using + + (decode-coding-string RESULT 'utf-8) + --- *** The parser keeps duplicated object keys in alist and plist output. A JSON object such as '{"a":1,"a":2}' will now be translated into the diff --git a/src/json.c b/src/json.c index 21066d21328..41566f8369b 100644 --- a/src/json.c +++ b/src/json.c @@ -559,16 +559,6 @@ json_out_something (json_out_t *jo, Lisp_Object obj) wrong_type_argument (Qjson_value_p, obj); } -static Lisp_Object -json_out_to_string (json_out_t *jo) -{ - /* FIXME: should this be a unibyte or multibyte string? - Right now we make a multibyte string for test compatibility, - but we are really encoding so unibyte would make more sense. */ - ptrdiff_t nchars = jo->size - jo->chars_delta; - return make_multibyte_string (jo->buf, nchars, jo->size); -} - static void json_serialize (json_out_t *jo, Lisp_Object object, ptrdiff_t nargs, Lisp_Object *args) @@ -596,7 +586,7 @@ json_serialize (json_out_t *jo, Lisp_Object object, DEFUN ("json-serialize", Fjson_serialize, Sjson_serialize, 1, MANY, NULL, - doc: /* Return the JSON representation of OBJECT as a string. + doc: /* Return the JSON representation of OBJECT as a unibyte string. OBJECT is translated as follows: @@ -629,7 +619,7 @@ usage: (json-serialize OBJECT &rest ARGS) */) specpdl_ref count = SPECPDL_INDEX (); json_out_t jo; json_serialize (&jo, args[0], nargs - 1, args + 1); - return unbind_to (count, json_out_to_string (&jo)); + return unbind_to (count, make_unibyte_string (jo.buf, jo.size)); } DEFUN ("json-insert", Fjson_insert, Sjson_insert, 1, MANY, diff --git a/test/src/json-tests.el b/test/src/json-tests.el index ebac70fb1c7..1d7491a4593 100644 --- a/test/src/json-tests.el +++ b/test/src/json-tests.el @@ -36,7 +36,7 @@ (json "[null,false,true,0,123,-456,3.75,\"abc\uFFFFαβγ𝔸𝐁𝖢\\\"\\\\\"]") (json-bytes (encode-coding-string json 'utf-8))) - (should (equal (json-serialize lisp) json)) ; or `json-bytes'? + (should (equal (json-serialize lisp) json-bytes)) (with-temp-buffer ;; multibyte buffer (json-insert lisp) @@ -82,28 +82,29 @@ "\"abc\uFFFFαβγ𝔸𝐁𝖢\\\"\\\\\""))) (cl-destructuring-bind (lisp json) case (ert-info ((format "%S ↔ %S" lisp json)) - (should (equal (json-serialize lisp) json)) - (with-temp-buffer - (json-insert lisp) - (should (equal (buffer-string) json)) - (should (eobp))) - (with-temp-buffer - (set-buffer-multibyte nil) - (json-insert lisp) - (should (equal (buffer-string) (encode-coding-string json 'utf-8))) - (should (eobp))) - (should (equal (json-parse-string json) lisp)) - (with-temp-buffer - (insert json) - (goto-char 1) - (should (equal (json-parse-buffer) lisp)) - (should (eobp))) - (with-temp-buffer - (set-buffer-multibyte nil) - (insert (encode-coding-string json 'utf-8)) - (goto-char 1) - (should (equal (json-parse-buffer) lisp)) - (should (eobp))))))) + (let ((json-bytes (encode-coding-string json 'utf-8))) + (should (equal (json-serialize lisp) json-bytes)) + (with-temp-buffer + (json-insert lisp) + (should (equal (buffer-string) json)) + (should (eobp))) + (with-temp-buffer + (set-buffer-multibyte nil) + (json-insert lisp) + (should (equal (buffer-string) (encode-coding-string json 'utf-8))) + (should (eobp))) + (should (equal (json-parse-string json) lisp)) + (with-temp-buffer + (insert json) + (goto-char 1) + (should (equal (json-parse-buffer) lisp)) + (should (eobp))) + (with-temp-buffer + (set-buffer-multibyte nil) + (insert (encode-coding-string json 'utf-8)) + (goto-char 1) + (should (equal (json-parse-buffer) lisp)) + (should (eobp)))))))) (ert-deftest json-serialize/object () (let ((table (make-hash-table :test #'equal))) @@ -226,7 +227,8 @@ (should (equal (json-serialize ["foo"]) "[\"foo\"]")) (should (equal (json-serialize ["a\n\fb"]) "[\"a\\n\\fb\"]")) (should (equal (json-serialize ["\nasdфыв\u001f\u007ffgh\t"]) - "[\"\\nasdфыв\\u001F\u007ffgh\\t\"]")) + (encode-coding-string "[\"\\nasdфыв\\u001F\u007ffgh\\t\"]" + 'utf-8))) (should (equal (json-serialize ["a\0b"]) "[\"a\\u0000b\"]")) (should-error (json-serialize ["\xC3\x84"])) (should-error (json-serialize ["\u00C4\xC3\x84"]))) commit 89c99891b2b3ab087cd7e824cef391ef26800ab4 Author: Eli Zaretskii Date: Sat Sep 7 19:41:36 2024 +0300 ; * doc/lispref/os.texi (Suspending Emacs): Fix last change. diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi index fe84c2c3403..1f1c54e559c 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi @@ -846,7 +846,8 @@ Really suspend? @kbd{y} @group ---------- Parent Shell ---------- -bash$ /home/username +bash$ pwd +/home/username bash$ fg @end group commit 4f044d0d3df019e9a7717b443fe4b4c172854c7c Author: Eli Zaretskii Date: Sat Sep 7 18:38:40 2024 +0300 ; Improve documentation of 'suspend-emacs' * doc/lispref/os.texi (Suspending Emacs): * src/keyboard.c (Fsuspend_emacs): Document possible failures in sending STUFFSTRING to the shell. (Bug#73100). diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi index 3ab4b66ba30..fe84c2c3403 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi @@ -811,9 +811,6 @@ before suspending Emacs, or this function signals an error. If @var{string} is non-@code{nil}, its characters are sent to Emacs's superior shell, to be read as terminal input. -@c FIXME? It seems to me that shell does echo STRING. -The characters in @var{string} are not echoed by the superior shell; -only the results appear. Before suspending, @code{suspend-emacs} runs the normal hook @code{suspend-hook}. After the user resumes Emacs, @@ -859,9 +856,13 @@ Resumed! @end group @end smallexample -@c FIXME? AFAICS, it is echoed. -Note that @samp{pwd} is not echoed after Emacs is suspended. But it -is read and executed by the shell. +Note that on some operating systems, sending @var{string} to the Emacs +parent shell might require special privileges, in which case it might +silently fail to send @var{string} to the shell for execution. On other +systems this is not supported, and Emacs will signal an error if you +try. Also, @var{string} might not be echoed, even if it is executed by +the shell. So we don't recommend relying on this feature in portable +Lisp programs. @end deffn @defvar suspend-hook diff --git a/src/keyboard.c b/src/keyboard.c index e7b0af9f63c..c5c761955fb 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -11913,7 +11913,12 @@ Before suspending, run the normal hook `suspend-hook'. After resumption run the normal hook `suspend-resume-hook'. Some operating systems cannot stop the Emacs process and resume it later. -On such systems, Emacs starts a subshell instead of suspending. */) +On such systems, Emacs starts a subshell instead of suspending. + +On some operating systems, stuffing characters into terminal input +buffer requires special privileges or is not supported at all. +On such systems, calling this function with non-nil STUFFSTRING might +either signal an error or silently fail to stuff the characters. */) (Lisp_Object stuffstring) { specpdl_ref count = SPECPDL_INDEX ();