commit 4a1a4bf0e2dfe3987b18cfd2122d43db1e8a58c1 (HEAD, refs/remotes/origin/master) Author: F. Jason Park Date: Fri Oct 7 21:55:30 2022 -0700 Accommodate missing spec values in erc-format-message * lisp/erc/erc.el (erc-format-message): Although not mentioned in its log message, commit 5281946fbf6b3cdbec5ce82e0057c71849faf4d2 "Make format-spec accept function substitutions" also fixed a bug involving the `ignore-missing' parameter of `format-spec'. Until now, ERC has been relying on the old behavior to gracefully handle malformed server messages. This commit tries to regain that functionality. diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index f128387bcf..db39e341b2 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -6961,6 +6961,8 @@ shortened server name instead." (defvar tabbar--local-hlf) +;; FIXME when 29.1 is cut and `format-spec' is added to ELPA Compat, +;; remove the function invocations from the spec form below. (defun erc-update-mode-line-buffer (buffer) "Update the mode line in a single ERC buffer BUFFER." (with-current-buffer buffer @@ -7325,7 +7327,7 @@ See also `format-spec'." (error "No format spec for message %s" msg)) (when (functionp entry) (setq entry (apply entry args))) - (format-spec entry (apply #'format-spec-make args)))) + (format-spec entry (apply #'format-spec-make args) 'ignore))) ;;; Various hook functions commit 92703e00dc44af604355858bf227b07e99fb2c4c Author: Philipp Stephani Date: Tue Oct 11 02:52:51 2022 +0200 Add gettid to seccomp-filter * lib-src/seccomp-filter.c (main): gettid is necessary on RHEL 9.0 (bug#56359). diff --git a/lib-src/seccomp-filter.c b/lib-src/seccomp-filter.c index e45aa0c17f..7e54b878a2 100644 --- a/lib-src/seccomp-filter.c +++ b/lib-src/seccomp-filter.c @@ -221,6 +221,7 @@ main (int argc, char **argv) RULE (SCMP_ACT_ALLOW, SCMP_SYS (getuid)); RULE (SCMP_ACT_ALLOW, SCMP_SYS (geteuid)); RULE (SCMP_ACT_ALLOW, SCMP_SYS (getpid)); + RULE (SCMP_ACT_ALLOW, SCMP_SYS (gettid)); RULE (SCMP_ACT_ALLOW, SCMP_SYS (getpgrp)); /* Allow operations on open file descriptors. File descriptors are commit cf9ac857857e52a337864b3ea0dc39c186d56158 Author: Lars Ingebrigtsen Date: Tue Oct 11 02:39:05 2022 +0200 Remove the view-remove-frame-by-deleting variable * lisp/view.el (view-remove-frame-by-deleting): Remove variable that hasn't been used since 2011 -- 357f93d245344 reworked the code and stopped using it (bug#58413). diff --git a/lisp/view.el b/lisp/view.el index 1207f01db2..d9b1a2d0e7 100644 --- a/lisp/view.el +++ b/lisp/view.el @@ -68,13 +68,6 @@ the F command in `view-mode', but you can set it to t if you want the action for all scroll commands in view mode." :type 'boolean) -;;;###autoload -(defcustom view-remove-frame-by-deleting t - "Determine how View mode removes a frame no longer needed. -If nil, make an icon of the frame. If non-nil, delete the frame." - :type 'boolean - :version "23.1") - (defcustom view-exits-all-viewing-windows nil "Non-nil means restore all windows used to view buffer. Commands that restore windows when finished viewing a buffer, commit b0585441a321a144f2bbdc269b3cfc6c14bab7cf Author: kobarity Date: Mon Oct 10 22:24:17 2022 +0900 Fix Python completion failure under certain conditions * lisp/progmodes/python.el (python-shell-send-string-no-output): Save and restore `comint-last-prompt-overlay' or `comint-last-prompt'. * test/lisp/progmodes/python-tests.el (python-tests-shell-wait-for-prompt): New helper function. (python-tests-with-temp-buffer-with-shell): New helper macro. (python-shell-completion-1, python-shell-completion-native-1) (python-shell-completion-native-with-ffap-1) (python-shell-completion-native-with-eldoc-1): New tests (bug#58389). diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 80c5b31b6e..680b57fc3e 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -3413,15 +3413,25 @@ detecting a prompt at the end of the buffer." "Send STRING to PROCESS and inhibit output. Return the output." (or process (setq process (python-shell-get-process-or-error))) - (cl-letf (((process-filter process) - (lambda (_proc str) - (with-current-buffer (process-buffer process) - (python-shell-output-filter str)))) - (python-shell-output-filter-in-progress t) - (inhibit-quit t)) + (cl-letf* (((process-filter process) + (lambda (_proc str) + (with-current-buffer (process-buffer process) + (python-shell-output-filter str)))) + (python-shell-output-filter-in-progress t) + (inhibit-quit t) + (buffer (process-buffer process)) + (last-prompt (cond ((boundp 'comint-last-prompt-overlay) + 'comint-last-prompt-overlay) + ((boundp 'comint-last-prompt) + 'comint-last-prompt))) + (last-prompt-value (buffer-local-value last-prompt buffer))) (or (with-local-quit - (python-shell-send-string string process) + (unwind-protect + (python-shell-send-string string process) + (when (not (null last-prompt)) + (with-current-buffer buffer + (set last-prompt last-prompt-value)))) (while python-shell-output-filter-in-progress ;; `python-shell-output-filter' takes care of setting ;; `python-shell-output-filter-in-progress' to NIL after it @@ -3430,7 +3440,7 @@ Return the output." (prog1 python-shell-output-filter-buffer (setq python-shell-output-filter-buffer nil))) - (with-current-buffer (process-buffer process) + (with-current-buffer buffer (comint-interrupt-subjob))))) (defun python-shell-internal-send-string (string) diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el index fdaedb5fd7..60ff9bb613 100644 --- a/test/lisp/progmodes/python-tests.el +++ b/test/lisp/progmodes/python-tests.el @@ -43,6 +43,37 @@ always located at the beginning of buffer." (goto-char (point-min)) ,@body))) +(defun python-tests-shell-wait-for-prompt () + "Wait for the prompt in the shell buffer." + (python-shell-with-shell-buffer + (while (not (if-let ((prompt (python-util-comint-last-prompt))) + (python-shell-comint-end-of-output-p + (buffer-substring-no-properties + (car prompt) (cdr prompt))))) + (sit-for 0.1)))) + +(defmacro python-tests-with-temp-buffer-with-shell (contents &rest body) + "Create a `python-mode' enabled temp buffer with CONTENTS and `run-python'. +BODY is code to be executed within the temp buffer. Point is +always located at the beginning of buffer. Native completion is +turned off. Shell buffer will be killed on exit." + (declare (indent 1) (debug t)) + `(with-temp-buffer + (let ((python-indent-guess-indent-offset nil) + (python-shell-completion-native-enable nil)) + (python-mode) + (unwind-protect + (progn + (run-python nil t) + (insert ,contents) + (goto-char (point-min)) + (python-tests-shell-wait-for-prompt) + ,@body) + (when (python-shell-get-buffer) + (python-shell-with-shell-buffer + (let (kill-buffer-hook kill-buffer-query-functions) + (kill-buffer)))))))) + (defmacro python-tests-with-temp-file (contents &rest body) "Create a `python-mode' enabled file with CONTENTS. BODY is code to be executed within the temp buffer. Point is @@ -4365,6 +4396,68 @@ def foo(): (python-shell-interpreter "/some/path/to/bin/pypy")) (should (python-shell-completion-native-interpreter-disabled-p)))) +(ert-deftest python-shell-completion-1 () + (skip-unless (executable-find python-tests-shell-interpreter)) + (python-tests-with-temp-buffer-with-shell + " +import abc +" + (let ((inhibit-message t)) + (python-shell-send-buffer) + (python-tests-shell-wait-for-prompt) + (goto-char (point-max)) + (insert "abc.") + (should (completion-at-point)) + (insert "A") + (should (completion-at-point))))) + +(ert-deftest python-shell-completion-native-1 () + (skip-unless (executable-find python-tests-shell-interpreter)) + (python-tests-with-temp-buffer-with-shell + " +import abc +" + (let ((inhibit-message t)) + (python-shell-completion-native-turn-on) + (python-shell-send-buffer) + (python-tests-shell-wait-for-prompt) + (goto-char (point-max)) + (insert "abc.") + (should (completion-at-point)) + (insert "A") + (should (completion-at-point))))) + +(ert-deftest python-shell-completion-native-with-ffap-1 () + (skip-unless (executable-find python-tests-shell-interpreter)) + (python-tests-with-temp-buffer-with-shell + " +import abc +" + (let ((inhibit-message t)) + (python-shell-completion-native-turn-on) + (python-shell-send-buffer) + (python-tests-shell-wait-for-prompt) + (goto-char (point-max)) + (insert "abc.") + ;; This is called when FFAP is enabled and a find-file function is called. + (python-ffap-module-path "abc.") + (should (completion-at-point))))) + +(ert-deftest python-shell-completion-native-with-eldoc-1 () + (skip-unless (executable-find python-tests-shell-interpreter)) + (python-tests-with-temp-buffer-with-shell + " +import abc +" + (let ((inhibit-message t)) + (python-shell-completion-native-turn-on) + (python-shell-send-buffer) + (python-tests-shell-wait-for-prompt) + (goto-char (point-max)) + (insert "abc.") + ;; This is called by idle-timer when ElDoc is enabled. + (python-eldoc-function) + (should (completion-at-point))))) commit 36ab1644964ae5a933bd9808536f60d4ae64c99f Author: Lars Ingebrigtsen Date: Tue Oct 11 02:18:19 2022 +0200 Improve error message from sqlite-execute * src/sqlite.c (sqlite_prepare_errmsg): New function. (Fsqlite_execute): Use it to get the same error format for both execute and select. (Fsqlite_select): Factored out from here. diff --git a/src/sqlite.c b/src/sqlite.c index 65b1dc492f..1526e344e5 100644 --- a/src/sqlite.c +++ b/src/sqlite.c @@ -421,6 +421,19 @@ row_to_value (sqlite3_stmt *stmt) return Fnreverse (values); } +static Lisp_Object +sqlite_prepare_errmsg (int code, sqlite3 *sdb) +{ + Lisp_Object errmsg = build_string (sqlite3_errstr (code)); + /* More details about what went wrong. */ + const char *sql_error = sqlite3_errmsg (sdb); + if (sql_error) + return CALLN (Fformat, build_string ("%s (%s)"), + errmsg, build_string (sql_error)); + else + return errmsg; +} + DEFUN ("sqlite-execute", Fsqlite_execute, Ssqlite_execute, 2, 3, 0, doc: /* Execute a non-select SQL statement. If VALUES is non-nil, it should be a vector or a list of values @@ -437,8 +450,8 @@ Value is the number of affected rows. */) xsignal1 (Qerror, build_string ("VALUES must be a list or a vector")); sqlite3 *sdb = XSQLITE (db)->db; - const char *errmsg = NULL; - Lisp_Object encoded = encode_string (query); + Lisp_Object errmsg = Qnil, + encoded = encode_string (query); sqlite3_stmt *stmt = NULL; /* We only execute the first statement -- if there's several @@ -453,7 +466,7 @@ Value is the number of affected rows. */) sqlite3_reset (stmt); } - errmsg = sqlite3_errmsg (sdb); + errmsg = sqlite_prepare_errmsg (ret, sdb); goto exit; } @@ -463,7 +476,7 @@ Value is the number of affected rows. */) const char *err = bind_values (sdb, stmt, values); if (err != NULL) { - errmsg = err; + errmsg = build_string (err); goto exit; } } @@ -487,13 +500,13 @@ Value is the number of affected rows. */) return rows; } else - errmsg = sqlite3_errmsg (sdb); + errmsg = build_string (sqlite3_errmsg (sdb)); exit: sqlite3_finalize (stmt); xsignal1 (ret == SQLITE_LOCKED || ret == SQLITE_BUSY? Qsqlite_locked_error: Qerror, - build_string (errmsg)); + errmsg); } static Lisp_Object @@ -540,12 +553,7 @@ which means that we return a set object that can be queried with { if (stmt) sqlite3_finalize (stmt); - errmsg = build_string (sqlite3_errstr (ret)); - /* More details about what went wrong. */ - const char *sql_error = sqlite3_errmsg (sdb); - if (sql_error) - errmsg = CALLN (Fformat, build_string ("%s (%s)"), - errmsg, build_string (sql_error)); + errmsg = sqlite_prepare_errmsg (ret, sdb); goto exit; } commit ebc19f56aaeb98b834eea1ce8768ca13bed8578c Author: Jim Porter Date: Sun Oct 9 15:53:27 2022 -0700 Don't prompt when killing an Emacs client if it's the last client * lisp/server.el (server-kill-emacs-query-function): Ignore the current client (if any) when checking for live clients (bug#58404). diff --git a/lisp/server.el b/lisp/server.el index 3caa335c4e..90d97c1538 100644 --- a/lisp/server.el +++ b/lisp/server.el @@ -1589,14 +1589,19 @@ specifically for the clients and did not exist before their request for it." (server-buffer-done (current-buffer)))) (defun server-kill-emacs-query-function () - "Ask before exiting Emacs if it has live clients. + "Ask before exiting Emacs if it has other live clients. A \"live client\" is a client with at least one live buffer -associated with it." - (or (not (seq-some (lambda (proc) - (seq-some #'buffer-live-p - (process-get proc 'buffers))) - server-clients)) - (yes-or-no-p "This Emacs session has clients; exit anyway? "))) +associated with it. These clients were (probably) started by +external processes that are waiting for some buffers to be +edited. If there are any other clients, we don't want to fail +their waiting processes, so ask the user to be sure." + (let ((this-client (frame-parameter nil 'client))) + (or (not (seq-some (lambda (proc) + (unless (eq proc this-client) + (seq-some #'buffer-live-p + (process-get proc 'buffers)))) + server-clients)) + (yes-or-no-p "This Emacs session has other clients; exit anyway? ")))) (defun server-kill-buffer () "Remove the current buffer from its clients' buffer list. commit 5df95ba039d93b26b11adcf61646467cd7174740 Author: Michael Albinus Date: Mon Oct 10 21:46:24 2022 +0200 Fix Tramp completion on MS Windows * lisp/net/tramp.el (tramp-build-remote-file-name-spec-regexp): Revert previous change, it's too complicate. (tramp-build-completion-file-name-regexp): Use `tramp-prefix-format' instead of `tramp-prefix-regexp'. (Bug#558133) diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 03dc47a053..4ff57e5d56 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -1088,34 +1088,18 @@ Derived from `tramp-postfix-host-format'.") (defun tramp-build-remote-file-name-spec-regexp () "Construct a regexp matching a Tramp file name for a Tramp syntax. It is expected, that `tramp-syntax' has the proper value." - ;; Starting with Emacs 27, we can use `rx-let'. - (let* ((user-regexp - (tramp-compat-rx - (group-n 6 (regexp tramp-user-regexp)) - (regexp tramp-postfix-user-regexp))) - (host-regexp - (tramp-compat-rx - (group-n 7 (| (regexp tramp-host-regexp) - (: (regexp tramp-prefix-ipv6-regexp) - (? (regexp tramp-ipv6-regexp)) - (regexp tramp-postfix-ipv6-regexp))) - ;; Optional port. - (? (regexp tramp-prefix-port-regexp) - (regexp tramp-port-regexp))))) - (user-host-regexp - (if (eq tramp-syntax 'simplified) - ;; There must be either user or host. - (tramp-compat-rx - (| (: (regexp user-regexp) (? (regexp host-regexp))) - (: (? (regexp user-regexp)) (regexp host-regexp)))) - (tramp-compat-rx - (? (regexp user-regexp)) (? (regexp host-regexp)))))) - (tramp-compat-rx - ;; Method. - (group-n 5 (regexp tramp-method-regexp)) - (regexp tramp-postfix-method-regexp) - ;; User and host. - (regexp user-host-regexp)))) + (tramp-compat-rx + ;; Method. + (group (regexp tramp-method-regexp)) (regexp tramp-postfix-method-regexp) + ;; Optional user. This includes domain. + (? (group (regexp tramp-user-regexp)) (regexp tramp-postfix-user-regexp)) + ;; Optional host. + (? (group (| (regexp tramp-host-regexp) + (: (regexp tramp-prefix-ipv6-regexp) + (? (regexp tramp-ipv6-regexp)) + (regexp tramp-postfix-ipv6-regexp))) + ;; Optional port. + (? (regexp tramp-prefix-port-regexp) (regexp tramp-port-regexp)))))) (defvar tramp-remote-file-name-spec-regexp nil ; Initialized when defining `tramp-syntax'! @@ -1214,7 +1198,8 @@ The `ftp' syntax does not support methods.") ;; "/ssh:host:~/path" becomes "c:/ssh:host:~/path". See also ;; `tramp-drop-volume-letter'. (? (regexp tramp-volume-letter-regexp)) - (regexp tramp-prefix-regexp) + ;; We cannot use `tramp-prefix-regexp', because it starts with `bol'. + (literal tramp-prefix-format) ;; Optional multi hops. (* (regexp tramp-remote-file-name-spec-regexp) @@ -1862,7 +1847,8 @@ the form (METHOD USER DOMAIN HOST PORT LOCALNAME &optional HOP)." tramp-prefix-regexp "" (replace-regexp-in-string (tramp-compat-rx - (regexp tramp-postfix-host-regexp) eos) tramp-postfix-hop-format + (regexp tramp-postfix-host-regexp) eos) + tramp-postfix-hop-format (tramp-make-tramp-file-name vec 'noloc))))) (defun tramp-completion-make-tramp-file-name (method user host localname) commit 345de32a5db8ef165feeda77c99ce56e4d6e911c Author: Paul Eggert Date: Mon Oct 10 12:35:56 2022 -0700 Port bwrap/allows-stdout test to Ubuntu 22.04.1 Without this patch, Ubuntu 22.04.1 x86-64 "make check" reports a failure in test/src/emacs-tests.el’s emacs-tests/bwrap/allows-stdout. One can reproduce the bug without using the Emacs executable, by running this script: #!/bin/bash export LC_ALL=C exec strace -f -o /tmp/tr bwrap --ro-bind / / --seccomp 20 -- \ cat /dev/null 20< lib-src/seccomp-filter-exec.bpf This script exits with status 159, because "cat" didn’t get started (it got a SIGSYS signal early on). The command "journalctl -g SECCOMP" indicated that rseq (syscall 334) was the problem. This syscall is issued by /lib64/ld-linux-x86-64.so.2 before ‘main’ is called. There’s another problem with the clone3 syscall, which is used by pthread_create starting in glibc 2.34. pthread_create is called by g_child_watch_source_new, which is called by init_process_emacs. * lib-src/seccomp-filter.c (main): Allow rseq, clone3. This causes the test to pass. Perhaps a fancier, more accurate patch could be written by someone who has the time. diff --git a/lib-src/seccomp-filter.c b/lib-src/seccomp-filter.c index 041bf5c749..e45aa0c17f 100644 --- a/lib-src/seccomp-filter.c +++ b/lib-src/seccomp-filter.c @@ -206,6 +206,9 @@ main (int argc, char **argv) SCMP_A2_32 (SCMP_CMP_MASKED_EQ, ~(PROT_NONE | PROT_READ | PROT_WRITE), 0)); + /* Allow restartable sequences. The dynamic linker uses them. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (rseq)); + /* Futexes are used everywhere. */ RULE (SCMP_ACT_ALLOW, SCMP_SYS (futex), SCMP_A1_32 (SCMP_CMP_EQ, FUTEX_WAKE_PRIVATE)); @@ -324,6 +327,8 @@ main (int argc, char **argv) | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID), 0)); + /* glibc 2.34+ pthread_create uses clone3. */ + RULE (SCMP_ACT_ALLOW, SCMP_SYS (clone3)); RULE (SCMP_ACT_ALLOW, SCMP_SYS (sigaltstack)); RULE (SCMP_ACT_ALLOW, SCMP_SYS (set_robust_list)); commit 8851a75ca7642ce071a23c24a81e22e443be0b05 Author: Lars Ingebrigtsen Date: Mon Oct 10 14:09:54 2022 +0200 Add a test for sqlite "insert ... returning" * test/src/sqlite-tests.el (sqlite-returning): Add a test for "insert ... returning". diff --git a/test/src/sqlite-tests.el b/test/src/sqlite-tests.el index 5af4392301..be4f60ab57 100644 --- a/test/src/sqlite-tests.el +++ b/test/src/sqlite-tests.el @@ -241,4 +241,17 @@ (should (multibyte-string-p c1)) (should-not (multibyte-string-p c2))))))) +(ert-deftest sqlite-returning () + (skip-unless (sqlite-available-p)) + (let (db) + (progn + (setq db (sqlite-open)) + (sqlite-execute db "CREATE TABLE people1 (people_id INTEGER PRIMARY KEY, first TEXT, last TEXT)") + (should (null (sqlite-select db "select * from people1"))) + (should + (equal + (sqlite-execute db "INSERT INTO people1 (first, last) values (?, ?) RETURNING people_id, first" + '("Joe" "Doe")) + '((1 "Joe"))))))) + ;;; sqlite-tests.el ends here commit e25bdd794629909020247ad6da13f9f0dab9a6e8 Author: Robert Pluim Date: Mon Oct 10 12:45:45 2022 +0200 Fix `vc-prepare-patch' docstring * lisp/vc/vc.el (vc-prepare-patch): Correct description of `vc-prepare-patches-separately'. diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index ba3a4c58cf..60481318e3 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -3332,12 +3332,14 @@ If nil, no default will be used. This option may be set locally." ;;;###autoload (defun vc-prepare-patch (addressee subject revisions) "Compose an Email sending patches for REVISIONS to ADDRESSEE. -If `vc-prepare-patches-separately' is non-nil, SUBJECT will be used -as the default subject for the message. Otherwise a separate -message will be composed for each revision. +If `vc-prepare-patches-separately' is nil, SUBJECT will be used +as the default subject for the message (and it will be prompted +for when called interactively). Otherwise a separate message +will be composed for each revision, with SUBJECT derived from the +invidividual commits. When invoked interactively in a Log View buffer with marked -revisions, these revisions will be used." +revisions, those revisions will be used." (interactive (let ((revs (or (log-view-get-marked) (vc-read-multiple-revisions "Revisions: "))) commit b7802190fe3735704bba72b5c3030f67d9c1d3da Author: Eli Zaretskii Date: Mon Oct 10 12:37:04 2022 +0300 ; Update the doc string of 'compilation-auto-jump-to-first-error' * lisp/progmodes/compile.el (compilation-auto-jump-to-first-error): Doc fix. (Bug#58407) diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el index ded5d2130e..6473b50778 100644 --- a/lisp/progmodes/compile.el +++ b/lisp/progmodes/compile.el @@ -980,12 +980,17 @@ Faces `compilation-error-face', `compilation-warning-face', "Face name to use for leaving directory messages.") (defcustom compilation-auto-jump-to-first-error nil - "If non-nil, automatically jump to the first error during compilation." + "If non-nil, automatically jump to the first error during compilation. + +The value `if-location-known' means automatically jump to the first error +if the error's file can be found. The value `first-known' means jump to +the first error whose file can be found. Any other non-nil value means +jump to the first error unconditionally." :type '(choice (const :tag "Never" nil) (const :tag "Always" t) (const :tag "If location known" if-location-known) (const :tag "First known location" first-known)) - :version "23.1") + :version "29.1") (defvar-local compilation-auto-jump-to-next nil "If non-nil, automatically jump to the next error encountered.") commit ed436db1320339862fad5ac754a6ec42de06c766 Author: Eli Zaretskii Date: Mon Oct 10 12:14:33 2022 +0300 ; * doc/lispref/text.texi (Database): Fix markup in last change. diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index e0768721d9..509ce56725 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -5325,8 +5325,8 @@ interpolation). For instance, an @samp{insert} statement will typically return @samp{1}, whereas an @samp{update} statement may return zero or a higher number. However, when using @acronym{SQL} statements like -@samp{insert into ... returning ...} and the like, the values -specified by @samp{returning ...} will be returned instead. +@w{@samp{insert into @dots{} returning @dots{}}} and the like, the values +specified by @w{@samp{returning @dots{}}} will be returned instead. Strings in SQLite are, by default, stored as @code{utf-8}, and selecting a text column will decode the string using that charset. commit 7e7dc74ffbab5eac863657ef719e9f47165708b3 Author: Lars Ingebrigtsen Date: Mon Oct 10 10:58:33 2022 +0200 Support "insert into ... returning ..." in sqlite-execute * doc/lispref/text.texi (Database): Mention it. * src/sqlite.c (Fsqlite_execute): Support syntax like "insert into ... returning ..." (bug#58390). diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index 8b859042ad..e0768721d9 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -5321,9 +5321,12 @@ This has exactly the same effect as the previous example, but is more efficient and safer (because it doesn't involve any string parsing or interpolation). -@code{sqlite-execute} returns the number of affected rows. For -instance, an @samp{insert} statement will return @samp{1}, whereas an -@samp{update} statement may return zero or a higher number. +@code{sqlite-execute} usually returns the number of affected rows. +For instance, an @samp{insert} statement will typically return +@samp{1}, whereas an @samp{update} statement may return zero or a +higher number. However, when using @acronym{SQL} statements like +@samp{insert into ... returning ...} and the like, the values +specified by @samp{returning ...} will be returned instead. Strings in SQLite are, by default, stored as @code{utf-8}, and selecting a text column will decode the string using that charset. diff --git a/src/sqlite.c b/src/sqlite.c index 7af3760eb4..65b1dc492f 100644 --- a/src/sqlite.c +++ b/src/sqlite.c @@ -377,6 +377,50 @@ bind_values (sqlite3 *db, sqlite3_stmt *stmt, Lisp_Object values) return NULL; } +static Lisp_Object +row_to_value (sqlite3_stmt *stmt) +{ + int len = sqlite3_column_count (stmt); + Lisp_Object values = Qnil; + + for (int i = 0; i < len; ++i) + { + Lisp_Object v = Qnil; + + switch (sqlite3_column_type (stmt, i)) + { + case SQLITE_INTEGER: + v = make_int (sqlite3_column_int64 (stmt, i)); + break; + + case SQLITE_FLOAT: + v = make_float (sqlite3_column_double (stmt, i)); + break; + + case SQLITE_BLOB: + v = make_unibyte_string (sqlite3_column_blob (stmt, i), + sqlite3_column_bytes (stmt, i)); + break; + + case SQLITE_NULL: + v = Qnil; + break; + + case SQLITE_TEXT: + v = + code_convert_string_norecord + (make_unibyte_string ((const char *)sqlite3_column_text (stmt, i), + sqlite3_column_bytes (stmt, i)), + Qutf_8, false); + break; + } + + values = Fcons (v, values); + } + + return Fnreverse (values); +} + DEFUN ("sqlite-execute", Fsqlite_execute, Ssqlite_execute, 2, 3, 0, doc: /* Execute a non-select SQL statement. If VALUES is non-nil, it should be a vector or a list of values @@ -393,7 +437,6 @@ Value is the number of affected rows. */) xsignal1 (Qerror, build_string ("VALUES must be a list or a vector")); sqlite3 *sdb = XSQLITE (db)->db; - Lisp_Object retval = Qnil; const char *errmsg = NULL; Lisp_Object encoded = encode_string (query); sqlite3_stmt *stmt = NULL; @@ -426,66 +469,31 @@ Value is the number of affected rows. */) } ret = sqlite3_step (stmt); - sqlite3_finalize (stmt); - if (ret != SQLITE_OK && ret != SQLITE_DONE) - { - errmsg = sqlite3_errmsg (sdb); - goto exit; - } - retval = make_fixnum (sqlite3_changes (sdb)); - - exit: - if (errmsg != NULL) - xsignal1 (ret == SQLITE_LOCKED || ret == SQLITE_BUSY? - Qsqlite_locked_error: Qerror, - build_string (errmsg)); - - return retval; -} - -static Lisp_Object -row_to_value (sqlite3_stmt *stmt) -{ - int len = sqlite3_column_count (stmt); - Lisp_Object values = Qnil; - - for (int i = 0; i < len; ++i) + if (ret == SQLITE_ROW) { - Lisp_Object v = Qnil; - - switch (sqlite3_column_type (stmt, i)) - { - case SQLITE_INTEGER: - v = make_int (sqlite3_column_int64 (stmt, i)); - break; - - case SQLITE_FLOAT: - v = make_float (sqlite3_column_double (stmt, i)); - break; + Lisp_Object data = Qnil; + do + data = Fcons (row_to_value (stmt), data); + while (sqlite3_step (stmt) == SQLITE_ROW); - case SQLITE_BLOB: - v = make_unibyte_string (sqlite3_column_blob (stmt, i), - sqlite3_column_bytes (stmt, i)); - break; - - case SQLITE_NULL: - v = Qnil; - break; - - case SQLITE_TEXT: - v = - code_convert_string_norecord - (make_unibyte_string ((const char *)sqlite3_column_text (stmt, i), - sqlite3_column_bytes (stmt, i)), - Qutf_8, false); - break; - } - - values = Fcons (v, values); + sqlite3_finalize (stmt); + return Fnreverse (data); } + else if (ret == SQLITE_OK || ret == SQLITE_DONE) + { + Lisp_Object rows = make_fixnum (sqlite3_changes (sdb)); + sqlite3_finalize (stmt); + return rows; + } + else + errmsg = sqlite3_errmsg (sdb); - return Fnreverse (values); + exit: + sqlite3_finalize (stmt); + xsignal1 (ret == SQLITE_LOCKED || ret == SQLITE_BUSY? + Qsqlite_locked_error: Qerror, + build_string (errmsg)); } static Lisp_Object commit 7ab6ec364d56c292de2d6294e9424824866691b3 Author: Lars Ingebrigtsen Date: Sun Oct 9 17:06:46 2022 +0200 Fix some indentation in Fsqlite_execute * src/sqlite.c (Fsqlite_execute): Fix indentation. diff --git a/src/sqlite.c b/src/sqlite.c index ababa73b99..7af3760eb4 100644 --- a/src/sqlite.c +++ b/src/sqlite.c @@ -415,14 +415,15 @@ Value is the number of affected rows. */) } /* Bind ? values. */ - if (!NILP (values)) { - const char *err = bind_values (sdb, stmt, values); - if (err != NULL) - { - errmsg = err; - goto exit; - } - } + if (!NILP (values)) + { + const char *err = bind_values (sdb, stmt, values); + if (err != NULL) + { + errmsg = err; + goto exit; + } + } ret = sqlite3_step (stmt); sqlite3_finalize (stmt); commit 28904d78a59b0057c4a4fbaaaf63577be6a19f77 Author: Eli Zaretskii Date: Mon Oct 10 11:09:43 2022 +0300 ; Fix last change. diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi index 671d4dd422..ad4a3ea350 100644 --- a/doc/emacs/maintaining.texi +++ b/doc/emacs/maintaining.texi @@ -2338,7 +2338,7 @@ them. @item M-? Find all the references for the identifier at point. -@item r@r{, Xref command} +@item r @itemx M-x xref-query-replace-in-results @key{RET} @var{replacement} @key{RET} @itemx C-u M-x xref-query-replace-in-results @key{RET} @var{regexp} @key{RET} @var{replacement} @key{RET} Interactively replace @var{regexp} with @var{replacement} in the names diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index 47b4b3d15c..afb4509913 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -897,7 +897,8 @@ ITEMS is an xref item which " ; FIXME: Expand documentation. (setq continue (perform-replace from to t t nil nil multi-query-replace-map))) (unless did-it-once - (user-error "Cannot use subset of matches for global renaming")) + (user-error + "Cannot use subset of matches of identifier for global renaming")) (when (and continue (not buf-pairs)) (message "All results processed")))) commit e016e60a0452bc26f562780f43c2bcd4aab21bdc Author: Eli Zaretskii Date: Mon Oct 10 11:05:18 2022 +0300 ; Clarify correct use of 'xref-query-replace-in-results' * lisp/progmodes/xref.el (xref--query-replace-1): Improve the user-error message. (xref-query-replace-in-results): Clarify restrictions in the doc string. * doc/emacs/maintaining.texi (Xref Commands, Identifier Search): Clarify the correct usage of 'xref-query-replace-in-results'. diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi index 6857e67def..671d4dd422 100644 --- a/doc/emacs/maintaining.texi +++ b/doc/emacs/maintaining.texi @@ -2302,7 +2302,9 @@ Display the reference on the current line in the other window @item r @var{pattern} @key{RET} @var{replacement} @key{RET} Perform interactive query-replace on references that match @var{pattern} (@code{xref-query-replace-in-results}), replacing -the match with @var{replacement}. @xref{Identifier Search}. +the match with @var{replacement}. This command can only be used in +@file{*xref*} buffers that show all the matches for an identifier in +all the relevant files. @xref{Identifier Search}. @item g @findex xref-revert-buffer @@ -2336,7 +2338,8 @@ them. @item M-? Find all the references for the identifier at point. -@item M-x xref-query-replace-in-results @key{RET} @var{replacement} @key{RET} +@item r@r{, Xref command} +@itemx M-x xref-query-replace-in-results @key{RET} @var{replacement} @key{RET} @itemx C-u M-x xref-query-replace-in-results @key{RET} @var{regexp} @key{RET} @var{replacement} @key{RET} Interactively replace @var{regexp} with @var{replacement} in the names of all the identifiers shown in the @file{*xref*} buffer. @@ -2382,16 +2385,18 @@ shown. The default value is @code{nil}, which just shows the results in the @file{*xref*} buffer, but doesn't select any of them. @findex xref-query-replace-in-results - @kbd{M-x xref-query-replace-in-results} reads a @var{replacement} + @kbd{r} (@code{xref-query-replace-in-results}) reads a @var{replacement} string, just like ordinary @kbd{M-x query-replace-regexp}. It then renames the identifiers shown in the @file{*xref*} buffer in all the places in all the files where these identifiers are referenced, such that their new name is @var{replacement}. This is useful when you rename your identifiers as part of refactoring. This command should -be invoked in the @file{*xref*} buffer generated by @kbd{M-?}. With a -prefix argument, the command also prompts for a regexp to match -identifier names, and renames that regexp in the names of the matching -identifiers with @var{replacement}. +be invoked in the @file{*xref*} buffer generated by @kbd{M-?}. By +default, the command replaces the entire name of each identifier with +@var{replacement}, but if invoked with a prefix argument, the command +prompts for a regexp to match identifier names, and replaces only the +matches of that regexp in the names of the identifiers with +@var{replacement}. @findex xref-find-references-and-replace @kbd{M-x xref-find-references-and-replace} works similarly to diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index ac04b64ce5..47b4b3d15c 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -751,17 +751,22 @@ quit the *xref* buffer." (defun xref-query-replace-in-results (from to) "Perform interactive replacement of FROM with TO in all displayed xrefs. -This command interactively replaces FROM with TO in the names of the +This function interactively replaces FROM with TO in the names of the references displayed in the current *xref* buffer. -When called interactively, it uses '.*' as FROM, which means -replace the whole name. Unless called with prefix argument, in -which case the user is prompted for both FROM and TO. +When called interactively, it uses '.*' as FROM, which means replace +the whole name, and prompts the user for TO. +If invoked with prefix argument, it prompts the user for both FROM and TO. As each match is found, the user must type a character saying what to do with it. Type SPC or `y' to replace the match, DEL or `n' to skip and go to the next match. For more directions, -type \\[help-command] at that time." +type \\[help-command] at that time. + +Note that this function cannot be used in *xref* buffers that show +a partial list of all references, such as the *xref* buffer created +by \\[xref-find-definitions] and its variants, since those list only +some of the references to the identifiers." (interactive (let* ((fr (if current-prefix-arg @@ -891,7 +896,8 @@ ITEMS is an xref item which " ; FIXME: Expand documentation. (setq pairs (cdr buf-pairs)) (setq continue (perform-replace from to t t nil nil multi-query-replace-map))) - (unless did-it-once (user-error "No suitable matches here")) + (unless did-it-once + (user-error "Cannot use subset of matches for global renaming")) (when (and continue (not buf-pairs)) (message "All results processed"))))