commit 609319da870eac75cf4715de8abfaac9233d98f9 (HEAD, refs/remotes/origin/master) Merge: b3dda79facd f2114e8d89f Author: Stefan Kangas Date: Mon Feb 13 06:30:12 2023 +0100 Merge from origin/emacs-29 f2114e8d89f Fix indentation for closing bracket in c-ts-mode (bug#61398) f49caaa8925 ; * src/pdumper.c (dump_buffer): Update hash. fe2ea5ddd8d Update to Org 9.6.1-31-gaf1bb1 commit b3dda79facd433c768fdeadd9056ffcab14cf590 Merge: bf60b3bfe7b 8280d721d7c Author: Stefan Kangas Date: Mon Feb 13 06:30:12 2023 +0100 ; Merge from origin/emacs-29 The following commit was skipped: 8280d721d7c * src/.gdbinit (nextcons): Amend $.u.cdr to $.u.s.u.cdr (... commit bf60b3bfe7b42e61f34843d007b4c6df2fe644b5 Merge: e0b60120a1c eb2b0931cf1 Author: Stefan Kangas Date: Mon Feb 13 06:30:12 2023 +0100 Merge from origin/emacs-29 eb2b0931cf1 Add lambda_expression to c-ts-common-indent-type-regexp-a... 2da05876edb ; Use the right name when specifying VC packages d4fc7012978 Tolerate missing elpa-packages.eld files 8bc1b7d0b27 Avoid warning about 'load-path' in non-interactive sessions 3d17aee13d9 ; Fix installation of dependencies for VC packages 86ca7df6a34 ; Mention Hunspell private-dictionary misfeature in doc s... 7287b7b53a1 Support webkit2gtk-4.1 048a2dabfc4 ; Fix typo commit f2114e8d89feed154a1c523c925ff2fb9fa9ba9a Author: Yuan Fu Date: Sun Feb 12 19:49:47 2023 -0800 Fix indentation for closing bracket in c-ts-mode (bug#61398) * lisp/progmodes/c-ts-mode.el: (c-ts-mode--indent-styles): Move the rule earlier. (c-ts-base-mode): Add move block type. * test/lisp/progmodes/c-ts-mode-resources/indent.erts: New tests. diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index b898f7d9ee3..af7aa1c3a0e 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -272,6 +272,11 @@ c-ts-mode--indent-styles ;; Indent the body of namespace definitions. ((parent-is "declaration_list") parent-bol c-ts-mode-indent-offset))) + ;; Closing bracket. This should be before initializer_list + ;; (and probably others) rule because that rule (and other + ;; similar rules) will match the closing bracket. (Bug#61398) + ((node-is "}") point-min c-ts-common-statement-offset) + ;; int[5] a = { 0, 0, 0, 0 }; ((parent-is "initializer_list") parent-bol c-ts-mode-indent-offset) ;; Statement in enum. @@ -281,8 +286,6 @@ c-ts-mode--indent-styles ;; Statement in {} blocks. ((parent-is "compound_statement") point-min c-ts-common-statement-offset) - ;; Closing bracket. - ((node-is "}") point-min c-ts-common-statement-offset) ;; Opening bracket. ((node-is "compound_statement") point-min c-ts-common-statement-offset) ;; Bug#61291. @@ -768,7 +771,9 @@ c-ts-base-mode (setq-local c-ts-common-indent-type-regexp-alist `((block . ,(rx (or "compound_statement" "field_declaration_list" - "enumerator_list"))) + "enumerator_list" + "initializer_list" + "field_declaration_list"))) (if . "if_statement") (else . ("if_statement" . "alternative")) (do . "do_statement") diff --git a/test/lisp/progmodes/c-ts-mode-resources/indent.erts b/test/lisp/progmodes/c-ts-mode-resources/indent.erts index 21b84c2e7e3..05d59c10a42 100644 --- a/test/lisp/progmodes/c-ts-mode-resources/indent.erts +++ b/test/lisp/progmodes/c-ts-mode-resources/indent.erts @@ -182,6 +182,20 @@ else if (false) return 3; =-=-= +Name: Initializer List (Bug#61398) + +=-= +int main() +{ + const char *emoticons[][2] = + { + {":-)", "SLIGHTLY SMILING FACE"}, + {";-)", "WINKING FACE"}, + {":-(", "SLIGHTLY FROWNING FACE"}, + }; +} +=-=-= + Name: Multiline Block Comments 1 (bug#60270) =-= @@ -327,3 +341,16 @@ void foo( } } =-=-= + +Name: Initializer List (Linux Style) (Bug#61398) + +=-= +int main() +{ + const char *emoticons[][2] = { + {":-)", "SLIGHTLY SMILING FACE"}, + {";-)", "WINKING FACE"}, + {":-(", "SLIGHTLY FROWNING FACE"}, + }; +} +=-=-= commit f49caaa892576e5fa95373c38e6a99904249551c Author: Basil L. Contovounesios Date: Sun Feb 12 21:07:45 2023 +0000 ; * src/pdumper.c (dump_buffer): Update hash. This follows commit 8f3091defb3 of 2023-02-12 "; Fix typo in buffer.h". diff --git a/src/pdumper.c b/src/pdumper.c index 800fc2e9d05..4809fb5dce7 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -2748,7 +2748,7 @@ dump_hash_table (struct dump_context *ctx, static dump_off dump_buffer (struct dump_context *ctx, const struct buffer *in_buffer) { -#if CHECK_STRUCTS && !defined HASH_buffer_DB34E5D09F +#if CHECK_STRUCTS && !defined HASH_buffer_85D317CE74 # error "buffer changed. See CHECK_STRUCTS comment in config.h." #endif struct buffer munged_buffer = *in_buffer; commit fe2ea5ddd8da91c8a0f3064f1447fc4fbbda68ab Author: Kyle Meyer Date: Sun Feb 12 15:43:07 2023 -0500 Update to Org 9.6.1-31-gaf1bb1 diff --git a/doc/misc/org.org b/doc/misc/org.org index 14699e77395..ad889a5c622 100644 --- a/doc/misc/org.org +++ b/doc/misc/org.org @@ -5291,7 +5291,7 @@ The following commands help to work with properties: Set a property in the current entry. Both the property and the value can be inserted using completion. -- {{{kbd(S-RIGHT)}}} (~org-property-next-allowed-values~), {{{kbd(S-LEFT)}}} (~org-property-previous-allowed-value~) :: +- {{{kbd(S-RIGHT)}}} (~org-property-next-allowed-value~), {{{kbd(S-LEFT)}}} (~org-property-previous-allowed-value~) :: #+kindex: S-RIGHT #+kindex: S-LEFT @@ -10252,9 +10252,9 @@ the other commands, point needs to be in the desired line. Unmark entry for bulk action. -- {{{kbd(U)}}} (~org-agenda-bulk-remove-all-marks~) :: +- {{{kbd(U)}}} (~org-agenda-bulk-unmark-all~) :: #+kindex: U - #+findex: org-agenda-bulk-remove-all-marks + #+findex: org-agenda-bulk-unmark-all Unmark all marked entries for bulk action. @@ -11692,9 +11692,9 @@ When the variable ~org-export-dispatch-use-expert-ui~ is set to a non-~nil~ value, Org prompts in the minibuffer. To switch back to the hierarchical menu, press {{{kbd(?)}}}. -- {{{kbd(C-c C-e)}}} (~org-export~) :: +- {{{kbd(C-c C-e)}}} (~org-export-dispatch~) :: #+kindex: C-c C-e - #+findex: org-export + #+findex: org-export-dispatch Invokes the export dispatcher interface. The options show default settings. The {{{kbd(C-u)}}} prefix argument preserves options from @@ -12232,7 +12232,7 @@ with the custom ID =theory=, you can use The following command allows navigating to the included document: -- {{{kbd(C-c ')}}} (~org-edit~special~) :: +- {{{kbd(C-c ')}}} (~org-edit-special~) :: #+kindex: C-c ' #+findex: org-edit-special @@ -14363,10 +14363,10 @@ executable. Without it, export cannot finish. :DESCRIPTION: Invoking export. :END: -- {{{kbd(C-c C-e o o)}}} (~org-export-to-odt~) :: +- {{{kbd(C-c C-e o o)}}} (~org-odt-export-to-odt~) :: #+kindex: C-c C-e o o - #+findex: org-export-to-odt + #+findex: org-odt-export-to-odt Export as OpenDocument Text file. #+cindex: @samp{EXPORT_FILE_NAME}, property diff --git a/lisp/org/ob-eval.el b/lisp/org/ob-eval.el index 6f6edb949cc..07e53077253 100644 --- a/lisp/org/ob-eval.el +++ b/lisp/org/ob-eval.el @@ -59,7 +59,7 @@ org-babel-eval (let ((error-buffer (get-buffer-create " *Org-Babel Error*")) exit-code) (with-current-buffer error-buffer (erase-buffer)) (with-temp-buffer - (insert query) + (insert query "\n") (setq exit-code (org-babel--shell-command-on-region command error-buffer)) diff --git a/lisp/org/ob-sql.el b/lisp/org/ob-sql.el index 39a4573a54e..f73e7003f6d 100644 --- a/lisp/org/ob-sql.el +++ b/lisp/org/ob-sql.el @@ -234,7 +234,7 @@ org-babel-find-db-connection-param (:database . sql-database))) (mapped-name (cdr (assq name name-mapping)))) (cadr (assq mapped-name - (cdr (assoc dbconnection sql-connection-alist)))))))) + (cdr (assoc-string dbconnection sql-connection-alist t)))))))) (defun org-babel-execute:sql (body params) "Execute a block of Sql code with Babel. diff --git a/lisp/org/org-agenda.el b/lisp/org/org-agenda.el index 63107e8e6a4..3db33c4d63e 100644 --- a/lisp/org/org-agenda.el +++ b/lisp/org/org-agenda.el @@ -8211,7 +8211,7 @@ org-agenda-filter-by-category (if (and org-agenda-filtered-by-category org-agenda-category-filter) (org-agenda-filter-show-all-cat) - (let ((cat (org-no-properties (org-get-at-eol 'org-category 1)))) + (let ((cat (org-no-properties (org-agenda-get-category)))) (cond ((and cat strip) (org-agenda-filter-apply diff --git a/lisp/org/org-compat.el b/lisp/org/org-compat.el index 6c50852553c..d5bf2191ae7 100644 --- a/lisp/org/org-compat.el +++ b/lisp/org/org-compat.el @@ -196,11 +196,13 @@ org-file-has-changed-p--hash-table ;;; Emacs < 27.1 compatibility -(unless (fboundp 'combine-change-calls) - ;; A stub when `combine-change-calls' was not yet there. - (defmacro combine-change-calls (_beg _end &rest body) - (declare (debug (form form def-body)) (indent 2)) - `(progn ,@body))) +(if (version< emacs-version "29") + ;; A stub when `combine-change-calls' was not yet there or had + ;; critical bugs (see Emacs bug#60467). + (defmacro org-combine-change-calls (_beg _end &rest body) + (declare (debug (form form def-body)) (indent 2)) + `(progn ,@body)) + (defalias 'org-combine-change-calls 'combine-change-calls)) (if (version< emacs-version "27.1") (defsubst org-replace-buffer-contents (source &optional _max-secs _max-costs) diff --git a/lisp/org/org-element.el b/lisp/org/org-element.el index 389acf82500..4f4eebfcc2d 100644 --- a/lisp/org/org-element.el +++ b/lisp/org/org-element.el @@ -7406,14 +7406,16 @@ org-element-cache-map (org-element-at-point to-pos) (cl-macrolet ((cache-root ;; Use the most optimal version of cache available. - () `(if (memq granularity '(headline headline+inlinetask)) - (org-element--headline-cache-root) - (org-element--cache-root))) + () `(org-with-base-buffer nil + (if (memq granularity '(headline headline+inlinetask)) + (org-element--headline-cache-root) + (org-element--cache-root)))) (cache-size ;; Use the most optimal version of cache available. - () `(if (memq granularity '(headline headline+inlinetask)) - org-element--headline-cache-size - org-element--cache-size)) + () `(org-with-base-buffer nil + (if (memq granularity '(headline headline+inlinetask)) + org-element--headline-cache-size + org-element--cache-size))) (cache-walk-restart ;; Restart tree traversal after AVL tree re-balance. () `(when node @@ -7443,8 +7445,9 @@ org-element-cache-map ;; Avoid extra staff like timer cancels et al ;; and only call `org-element--cache-sync-requests' when ;; there are pending requests. - (when org-element--cache-sync-requests - (org-element--cache-sync (current-buffer))) + (org-with-base-buffer nil + (when org-element--cache-sync-requests + (org-element--cache-sync (current-buffer)))) ;; Call `org-element--parse-to' directly avoiding any ;; kind of `org-element-at-point' overheads. (if restrict-elements @@ -7515,8 +7518,9 @@ org-element-cache-map tmpnext-start)) ;; Check if cache does not have gaps. (cache-gapless-p - () `(eq org-element--cache-change-tic - (alist-get granularity org-element--cache-gapless)))) + () `(org-with-base-buffer nil + (eq org-element--cache-change-tic + (alist-get granularity org-element--cache-gapless))))) ;; The core algorithm is simple walk along binary tree. However, ;; instead of checking all the tree elements from first to last ;; (like in `avl-tree-mapcar'), we begin from FROM-POS skipping @@ -7644,7 +7648,9 @@ org-element-cache-map ;; In the process, we may alter the buffer, ;; so also keep track of the cache state. (progn - (setq modified-tic org-element--cache-change-tic) + (setq modified-tic + (org-with-base-buffer nil + org-element--cache-change-tic)) (setq cache-size (cache-size)) ;; When NEXT-RE/FAIL-RE is provided, skip to ;; next regexp match after :begin of the current @@ -7678,7 +7684,7 @@ org-element-cache-map ;; ;; Call FUNC. FUNC may move point. (setq org-element-cache-map-continue-from nil) - (if org-element--cache-map-statistics + (if (org-with-base-buffer nil org-element--cache-map-statistics) (progn (setq before-time (float-time)) (push (funcall func data) result) @@ -7697,7 +7703,15 @@ org-element-cache-map (when org-element-cache-map-continue-from (goto-char org-element-cache-map-continue-from)) (when (> (point) start) - (move-start-to-next-match nil)) + (move-start-to-next-match nil) + ;; (point) inside matching element. + ;; Go further. + (when (> (point) start) + (setq data (element-match-at-point)) + (if (not data) + (cache-walk-abort) + (goto-char (next-element-start)) + (move-start-to-next-match next-element-re)))) ;; Drop nil. (unless (car result) (pop result))) ;; If FUNC did not move the point and we @@ -7710,8 +7724,9 @@ org-element-cache-map start)) (setq start nil)) ;; Check if the buffer has been modified. - (unless (and (eq modified-tic org-element--cache-change-tic) - (eq cache-size (cache-size))) + (unless (org-with-base-buffer nil + (and (eq modified-tic org-element--cache-change-tic) + (eq cache-size (cache-size)))) ;; START may no longer be valid, update ;; it to beginning of real element. ;; Upon modification, START may lay diff --git a/lisp/org/org-footnote.el b/lisp/org/org-footnote.el index c83026d1d8f..6bdd0b32fed 100644 --- a/lisp/org/org-footnote.el +++ b/lisp/org/org-footnote.el @@ -853,7 +853,7 @@ org-footnote-sort ;; Insert un-referenced footnote definitions at the end. ;; Combine all insertions into one to create a single cache ;; update call. - (combine-change-calls (point) (point) + (org-combine-change-calls (point) (point) (pcase-dolist (`(,label . ,definition) definitions) (unless (member label inserted) (insert "\n" definition "\n")))))))))) diff --git a/lisp/org/org-version.el b/lisp/org/org-version.el index 8372a0be4a5..5f587fb3fd8 100644 --- a/lisp/org/org-version.el +++ b/lisp/org/org-version.el @@ -11,7 +11,7 @@ org-release (defun org-git-version () "The Git version of Org mode. Inserted by installing Org or when a release is made." - (let ((org-git-version "release_9.6.1-23-gc45a05")) + (let ((org-git-version "release_9.6.1-31-gaf1bb1")) org-git-version)) (provide 'org-version) diff --git a/lisp/org/org.el b/lisp/org/org.el index 1b829d837c7..9a4f7803cf4 100644 --- a/lisp/org/org.el +++ b/lisp/org/org.el @@ -723,6 +723,10 @@ org-set-modules (set-default-toplevel-value var value) (when (featurep 'org) (org-load-modules-maybe 'force) + ;; FIXME: We can't have all the requires at top-level due to + ;; circular dependencies. Yet, this function might sometimes be + ;; called when 'org-element is not loaded. + (require 'org-element) (org-element-cache-reset 'all))) (defcustom org-modules '(ol-doi ol-w3m ol-bbdb ol-bibtex ol-docview ol-gnus ol-info ol-irc ol-mhe ol-rmail ol-eww) @@ -6556,7 +6560,7 @@ org-promote-subtree (interactive) (save-excursion (org-back-to-heading t) - (combine-change-calls (point) (save-excursion (org-end-of-subtree t)) + (org-combine-change-calls (point) (save-excursion (org-end-of-subtree t)) (org-with-limited-levels (org-map-tree 'org-promote)))) (org-fix-position-after-promote)) @@ -6566,7 +6570,7 @@ org-demote-subtree (interactive) (save-excursion (org-back-to-heading t) - (combine-change-calls (point) (save-excursion (org-end-of-subtree t)) + (org-combine-change-calls (point) (save-excursion (org-end-of-subtree t)) (org-with-limited-levels (org-map-tree 'org-demote)))) (org-fix-position-after-promote)) @@ -7135,7 +7139,7 @@ org-paste-subtree (setq beg (point)) ;; Avoid re-parsing cache elements when i.e. level 1 heading ;; is inserted and then promoted. - (combine-change-calls beg beg + (org-combine-change-calls beg beg (when (fboundp 'org-id-paste-tracker) (org-id-paste-tracker txt)) (insert txt) (unless (string-suffix-p "\n" txt) (insert "\n")) @@ -18844,7 +18848,7 @@ org--align-node-property (when (save-excursion (beginning-of-line) (looking-at org-property-re)) - (combine-change-calls (match-beginning 0) (match-end 0) + (org-combine-change-calls (match-beginning 0) (match-end 0) (let ((newtext (concat (match-string 4) (org-trim (format org-property-format (match-string 1) (match-string 3)))))) commit 8280d721d7c0f6fb2e04f23128c0d2cccf2be1d5 Author: Alan Mackenzie Date: Sun Feb 12 19:06:50 2023 +0000 * src/.gdbinit (nextcons): Amend $.u.cdr to $.u.s.u.cdr (bug#61453). (cherry picked from commit dde023b63ab82c38d33815409de5552f5bf349d1) diff --git a/src/.gdbinit b/src/.gdbinit index c96c2b597bd..c97e78559f1 100644 --- a/src/.gdbinit +++ b/src/.gdbinit @@ -926,7 +926,7 @@ Print the contents of $ as an Emacs Lisp cons. end define nextcons - p $.u.cdr + p $.u.s.u.cdr xcons end document nextcons commit e0b60120a1c3433fe332bff56b5b7483b0424d5c Author: Michael Albinus Date: Sun Feb 12 20:22:10 2023 +0100 Support Tramp multi-hop completion * lisp/net/tramp.el (tramp-completion-handle-expand-file-name) (tramp-completion-handle-file-exists-p) (tramp-completion-handle-file-name-directory): Support multi-hop completion. * test/lisp/net/tramp-tests.el (tramp-test26-interactive-file-name-completion): Fix test. diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 1cda8fc4c61..115048d59db 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -2961,6 +2961,8 @@ tramp-completion-handle-expand-file-name (concat dir filename)) ((string-match-p (rx bos (regexp tramp-prefix-regexp) + (* (regexp tramp-remote-file-name-spec-regexp) + (regexp tramp-postfix-hop-regexp)) (? (regexp tramp-method-regexp) (regexp tramp-postfix-method-regexp) (? (regexp tramp-user-regexp) (regexp tramp-postfix-user-regexp))) eos) @@ -2984,6 +2986,8 @@ tramp-completion-handle-file-exists-p (string-match (rx (regexp tramp-prefix-regexp) + (* (regexp tramp-remote-file-name-spec-regexp) + (regexp tramp-postfix-hop-regexp)) (group (regexp tramp-method-regexp)) (? (regexp tramp-postfix-method-regexp)) eos) @@ -2993,6 +2997,8 @@ tramp-completion-handle-file-exists-p ((string-match (rx (regexp tramp-prefix-regexp) + (* (regexp tramp-remote-file-name-spec-regexp) + (regexp tramp-postfix-hop-regexp)) (group (regexp tramp-remote-file-name-spec-regexp)) eos) filename) @@ -3249,30 +3255,31 @@ tramp-completion-handle-file-name-directory ;; method. In the `separate' file name syntax, we return "/[" when ;; `filename' is "/[string" w/o a trailing method separator "/". (cond - ((and (not (string-empty-p tramp-method-regexp)) - (string-match + ((string-match + (rx (group (regexp tramp-prefix-regexp) + (* (regexp tramp-remote-file-name-spec-regexp) + (regexp tramp-postfix-hop-regexp))) + (? (regexp tramp-completion-method-regexp)) eos) + filename) + (match-string 1 filename)) + ((and (string-match (rx (group (regexp tramp-prefix-regexp) + (* (regexp tramp-remote-file-name-spec-regexp) + (regexp tramp-postfix-hop-regexp)) (group (regexp tramp-method-regexp)) (regexp tramp-postfix-method-regexp) (? (regexp tramp-user-regexp) - (regexp tramp-postfix-user-regexp)))) + (regexp tramp-postfix-user-regexp))) + (? (| (regexp tramp-host-regexp) + (: (regexp tramp-prefix-ipv6-regexp) + (? (regexp tramp-ipv6-regexp) + (? (regexp tramp-postfix-ipv6-regexp)))))) + eos) filename) ;; Is it a valid method? - (assoc (match-string 2 filename) tramp-methods)) - (match-string 1 filename)) - ((and (string-empty-p tramp-method-regexp) - (string-match - (rx (group - (regexp tramp-prefix-regexp) - (? (regexp tramp-user-regexp) - (regexp tramp-postfix-user-regexp)))) - filename)) - (match-string 1 filename)) - ((string-match - (rx (group (regexp tramp-prefix-regexp)) - (regexp tramp-completion-method-regexp) eos) - filename) + (or (tramp-string-empty-or-nil-p (match-string 2 filename)) + (assoc (match-string 2 filename) tramp-methods))) (match-string 1 filename)) (t (tramp-run-real-handler #'file-name-directory (list filename))))) diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index 33afe820c58..51fc07117c5 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el @@ -4638,7 +4638,6 @@ tramp-test26-file-name-completion ;; This test is inspired by Bug#51386, Bug#52758, Bug#53513, Bug#54042 ;; and Bug#60505. -;; TODO: Add tests for user names and multi-hop file names. (ert-deftest tramp-test26-interactive-file-name-completion () "Check interactive completion with different `completion-styles'." (tramp-cleanup-connection tramp-test-vec nil 'keep-password) @@ -4649,12 +4648,15 @@ tramp-test26-interactive-file-name-completion (let ((method (file-remote-p ert-remote-temporary-file-directory 'method)) (user (file-remote-p ert-remote-temporary-file-directory 'user)) (host (file-remote-p ert-remote-temporary-file-directory 'host)) + (hop (file-remote-p ert-remote-temporary-file-directory 'hop)) (orig-syntax tramp-syntax) (non-essential t) (inhibit-message t)) (when (and (stringp host) (string-match tramp-host-with-port-regexp host)) (setq host (match-string 1 host))) + ;; (trace-function #'tramp-completion-file-name-handler) + ;; (trace-function #'completion-file-name-table) (unwind-protect (dolist (syntax (if (tramp--test-expensive-test-p) (tramp-syntax-values) `(,orig-syntax))) @@ -4689,25 +4691,29 @@ tramp-test26-interactive-file-name-completion (ipv6-postfix (and (string-match-p tramp-ipv6-regexp host) tramp-postfix-ipv6-format)) + ;; The hop string fits only the initial syntax. + (hop (and (eq tramp-syntax orig-syntax) hop)) test result completions) (dolist (test-and-result - ;; These are triples (TEST-STRING SINGLE-RESULT - ;; COMPLETION-RESULT). + ;; These are triples (TEST-STRING RESULT-CHECK + ;; COMPLETION-CHECK). (append ;; Complete method name. (unless (string-empty-p tramp-method-regexp) `((,(concat - tramp-prefix-format - (substring-no-properties method 0 2)) + tramp-prefix-format hop + (substring-no-properties + method 0 (min 2 (length method)))) ,(concat tramp-prefix-format method-string) ,method-string))) ;; Complete user name. (unless (tramp-string-empty-or-nil-p user) `((,(concat - tramp-prefix-format method-string - (substring-no-properties user 0 2)) + tramp-prefix-format hop method-string + (substring-no-properties + user 0 (min 2 (length user)))) ,(concat tramp-prefix-format method-string user tramp-postfix-user-format) @@ -4716,8 +4722,10 @@ tramp-test26-interactive-file-name-completion ;; Complete host name. (unless (tramp-string-empty-or-nil-p host) `((,(concat - tramp-prefix-format method-string - ipv6-prefix (substring-no-properties host 0 2)) + tramp-prefix-format hop method-string + ipv6-prefix + (substring-no-properties + host 0 (min 2 (length host)))) ,(concat tramp-prefix-format method-string ipv6-prefix host @@ -4729,9 +4737,11 @@ tramp-test26-interactive-file-name-completion (unless (or (tramp-string-empty-or-nil-p user) (tramp-string-empty-or-nil-p host)) `((,(concat - tramp-prefix-format method-string + tramp-prefix-format hop method-string user tramp-postfix-user-format - ipv6-prefix (substring-no-properties host 0 2)) + ipv6-prefix + (substring-no-properties + host 0 (min 2 (length host)))) ,(concat tramp-prefix-format method-string user tramp-postfix-user-format @@ -4742,12 +4752,14 @@ tramp-test26-interactive-file-name-completion ipv6-postfix tramp-postfix-host-format)))))) (ignore-errors (kill-buffer "*Completions*")) + ;; (and (bufferp trace-buffer) (kill-buffer trace-buffer)) (discard-input) (setq test (car test-and-result) unread-command-events (mapcar #'identity (concat test "\t\t\n")) completions nil result (read-file-name "Prompt: ")) + (if (not (get-buffer "*Completions*")) (progn ;; (tramp--test-message @@ -4776,6 +4788,9 @@ tramp-test26-interactive-file-name-completion (should (member (caddr test-and-result) completions))))))) ;; Cleanup. + ;; (tramp--test-message "%s" (tramp-get-buffer-string trace-buffer)) + ;; (untrace-function #'tramp-completion-file-name-handler) + ;; (untrace-function #'completion-file-name-table) (tramp-change-syntax orig-syntax))))) (ert-deftest tramp-test27-load () commit dde023b63ab82c38d33815409de5552f5bf349d1 Author: Alan Mackenzie Date: Sun Feb 12 19:06:50 2023 +0000 * src/.gdbinit (nextcons): Amend $.u.cdr to $.u.s.u.cdr diff --git a/src/.gdbinit b/src/.gdbinit index c96c2b597bd..c97e78559f1 100644 --- a/src/.gdbinit +++ b/src/.gdbinit @@ -926,7 +926,7 @@ Print the contents of $ as an Emacs Lisp cons. end define nextcons - p $.u.cdr + p $.u.s.u.cdr xcons end document nextcons commit eb2b0931cf1258b875b031f81a3685eda8ddf5cb Author: Theodor Thornhill Date: Sun Feb 12 18:57:40 2023 +0100 Add lambda_expression to c-ts-common-indent-type-regexp-alist * lisp/progmodes/java-ts-mode.el (java-ts-mode): Tweak regexp. diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el index dc651c11a00..e15da7110f1 100644 --- a/lisp/progmodes/java-ts-mode.el +++ b/lisp/progmodes/java-ts-mode.el @@ -309,6 +309,7 @@ java-ts-mode "constructor_body" "annotation_type_body" "interface_body" + "lambda_expression" "enum_body" "switch_block" "record_declaration_body" commit 2da05876edb5bc8ec0f39ac679c806930e16e5c7 Author: Philip Kaludercic Date: Sun Feb 12 14:29:26 2023 +0100 ; Use the right name when specifying VC packages * lisp/emacs-lisp/package-vc.el (package-vc-install-selected-packages): Generate dummy package descriptors in here, if necessary. (package-vc--unpack): Remove dummy-descriptor generation. diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el index a3d5200f0f8..bf49f274bfd 100644 --- a/lisp/emacs-lisp/package-vc.el +++ b/lisp/emacs-lisp/package-vc.el @@ -134,7 +134,10 @@ package-vc-install-selected-packages (package-vc-install name spec)) ((listp spec) (package-vc--archives-initialize) - (package-vc--unpack (cadr pkg-descs) spec))))))) + (package-vc--unpack + (or (cadr (assoc name package-archive-contents)) + (package-desc-create :name name :kind 'vc)) + spec))))))) ;;;###autoload (defcustom package-vc-selected-packages '() @@ -600,8 +603,6 @@ package-vc--unpack how to fetch and build the package. See `package-vc--archive-spec-alist' for details. The optional argument REV specifies a specific revision to checkout. This overrides the `:branch' attribute in PKG-SPEC." - (unless pkg-desc - (setq pkg-desc (package-desc-create :name (car pkg-spec) :kind 'vc))) (pcase-let* (((map :lisp-dir) pkg-spec) (name (package-desc-name pkg-desc)) (dirname (package-desc-full-name pkg-desc)) commit ac2c7a28da0b1bbed0fc92723c041b739b821977 Author: Po Lu Date: Sun Feb 12 20:39:23 2023 +0800 ; * src/textconv.c (textconv_query): Fix build on non-GCC compilers. diff --git a/src/textconv.c b/src/textconv.c index e91e127b71c..d5db6d11717 100644 --- a/src/textconv.c +++ b/src/textconv.c @@ -279,6 +279,7 @@ textconv_query (struct frame *f, struct textconv_callback_struct *query) } default: + break; } /* Undo any changes to the excursion. */ commit d4fc70129786f0c90f76e1868203d63a59f3f92d Author: Philip Kaludercic Date: Sun Feb 12 13:25:54 2023 +0100 Tolerate missing elpa-packages.eld files * lisp/emacs-lisp/package-vc.el (package-vc--download-and-read-archives): Replace 'condition-case-unless-debug' with a regular 'condition-case'. It appears a few people using third-party archives that don't serve package specifications have been having issues with package-vc, when toggle-on-error is enabled. In their case, package-vc would raise an error in its first invocation, but it would go on working normally afterwards. As this behaviour is confusing and the user can't do much about a missing elpa-packages.eld to begin with, we satisfy ourselves with printing out a message and continuing on. diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el index 1bc5c883161..a3d5200f0f8 100644 --- a/lisp/emacs-lisp/package-vc.el +++ b/lisp/emacs-lisp/package-vc.el @@ -269,9 +269,9 @@ package-vc--download-and-read-archives If optional argument ASYNC is non-nil, perform the downloads asynchronously." (dolist (archive package-archives) - (condition-case-unless-debug nil + (condition-case err (package--download-one-archive archive "elpa-packages.eld" async) - (error (message "Failed to download `%s' archive." (car archive)))))) + (error (message "Failed to download `%s' archive: %S" (car archive) err))))) (add-hook 'package-read-archive-hook #'package-vc--read-archive-data 20) commit 8bc1b7d0b27176e1d9039aec40d6e6f4d50f34b7 Author: Eli Zaretskii Date: Sun Feb 12 14:20:48 2023 +0200 Avoid warning about 'load-path' in non-interactive sessions * lisp/startup.el (command-line): Emit the warning about 'user-emacs-directory' in 'load-path' only in interactive sessions. (Bug#61014) diff --git a/lisp/startup.el b/lisp/startup.el index bb6250d3968..e5ec15eebea 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -1596,7 +1596,8 @@ command-line ;; or EMACSLOADPATH, so we basically always have to check. (let (warned) (dolist (dir load-path) - (and (not warned) + (and (not noninteractive) + (not warned) (stringp dir) (string-equal (file-name-as-directory (expand-file-name dir)) (expand-file-name user-emacs-directory)) commit 3d17aee13d9fa02f6b4cc03be7f323a48d480f09 Author: Philip Kaludercic Date: Sun Feb 12 13:10:04 2023 +0100 ; Fix installation of dependencies for VC packages * lisp/emacs-lisp/package-vc.el (package-vc-install-dependencies): Maintain a list of package-desc objects instead of package names to install. diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el index 33bd0bfd5cd..1bc5c883161 100644 --- a/lisp/emacs-lisp/package-vc.el +++ b/lisp/emacs-lisp/package-vc.el @@ -426,8 +426,8 @@ package-vc-install-dependencies ((let* ((pac package-archive-contents) (desc (cadr (assoc (car pkg) pac)))) (if desc - (let ((reqs (package-desc-reqs pkg))) - (push pkg to-install) + (let ((reqs (package-desc-reqs desc))) + (push desc to-install) (mapc #'search reqs)) (push pkg missing)))))) (version-order (a b) commit 86ca7df6a345f743f381c67bb0d14879b2858f13 Author: Eli Zaretskii Date: Sun Feb 12 14:05:44 2023 +0200 ; Mention Hunspell private-dictionary misfeature in doc strings * lisp/textmodes/ispell.el (ispell-personal-dictionary) (ispell-local-pdict): Mention Hunspell misfeatures in doc strings. (Bug#61190) diff --git a/lisp/textmodes/ispell.el b/lisp/textmodes/ispell.el index 3da6effbcfe..bb2bcfd8052 100644 --- a/lisp/textmodes/ispell.el +++ b/lisp/textmodes/ispell.el @@ -318,7 +318,9 @@ ispell-use-framepop-p ;;;###autoload (defcustom ispell-personal-dictionary nil "File name of your personal spelling dictionary, or nil. -If nil, the default personal dictionary for your spelling checker is used." +If nil, the default personal dictionary for your spelling checker is used. +Due to a misfeature of Hunspell, if the value is an absolute file name, the +file by that name must already exist for Hunspell to be able to use it." :type '(choice file (const :tag "default" nil))) @@ -1730,7 +1732,10 @@ ispell-local-pdict different from the current personal dictionary, the effect is similar to calling \\[ispell-change-dictionary]. This variable is automatically set when defined in the file with either `ispell-pdict-keyword' or the -local variable syntax.") +local variable syntax. + +Due to a misfeature of Hunspell, if the value is an absolute file name, the +file by that name must already exist for Hunspell to be able to use it.") ;;;###autoload(put 'ispell-local-pdict 'safe-local-variable 'stringp) commit 9510e8ad68271f58b4813478703a4b8eb1ba597b Author: Po Lu Date: Sun Feb 12 19:56:11 2023 +0800 Check in new files * src/textconv.c (copy_buffer): (textconv_query): (report_selected_window_change): (register_texconv_interface): * src/textconv.h (struct textconv_interface): (enum textconv_caret_direction): (enum textconv_operation): (struct textconv_conversion_text): (struct textconv_callback_struct): New files. diff --git a/src/textconv.c b/src/textconv.c new file mode 100644 index 00000000000..e91e127b71c --- /dev/null +++ b/src/textconv.c @@ -0,0 +1,312 @@ +/* String conversion support for graphics terminals. + +Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see . */ + +/* String conversion support. + + Many input methods require access to text surrounding the cursor. + They may then request that the text editor remove or substitute + that text for something else, for example when providing the + ability to ``undo'' or ``edit'' previously composed text. This is + most commonly seen in input methods for CJK laguages for X Windows, + and is extensively used throughout Android by input methods for all + kinds of scripts. */ + +#include + +#include "textconv.h" +#include "buffer.h" +#include "syntax.h" + + + +/* The window system's text conversion interface. + NULL when the window system has not set up text conversion. + + This interface will later be heavily extended on the + feature/android branch to deal with Android's much less + straightforward text conversion protocols. */ + +static struct textconv_interface *text_interface; + + + +/* Copy the portion of the current buffer described by BEG, BEG_BYTE, + END, END_BYTE to the buffer BUFFER, which is END_BYTE - BEG_BYTEs + long. */ + +static void +copy_buffer (ptrdiff_t beg, ptrdiff_t beg_byte, + ptrdiff_t end, ptrdiff_t end_byte, + char *buffer) +{ + ptrdiff_t beg0, end0, beg1, end1, size; + + if (beg_byte < GPT_BYTE && GPT_BYTE < end_byte) + { + /* Two regions, before and after the gap. */ + beg0 = beg_byte; + end0 = GPT_BYTE; + beg1 = GPT_BYTE + GAP_SIZE - BEG_BYTE; + end1 = end_byte + GAP_SIZE - BEG_BYTE; + } + else + { + /* The only region. */ + beg0 = beg_byte; + end0 = end_byte; + beg1 = -1; + end1 = -1; + } + + size = end0 - beg0; + memcpy (buffer, BYTE_POS_ADDR (beg0), size); + if (beg1 != -1) + memcpy (buffer, BEG_ADDR + beg1, end1 - beg1); +} + + + +/* Conversion query. */ + +/* Perform the text conversion operation specified in QUERY and return + the results. + + Find the text between QUERY->position from point on F's selected + window and QUERY->factor times QUERY->direction from that + position. Return it in QUERY->text. + + Then, either delete that text from the buffer if QUERY->operation + is TEXTCONV_SUBSTITUTION, or return 0. + + Value is 0 if QUERY->operation was not TEXTCONV_SUBSTITUTION + or if deleting the text was successful, and 1 otherwise. */ + +int +textconv_query (struct frame *f, struct textconv_callback_struct *query) +{ + specpdl_ref count; + ptrdiff_t pos, pos_byte, end, end_byte; + ptrdiff_t temp, temp1; + char *buffer; + + /* Save the excursion, as there will be extensive changes to the + selected window. */ + count = SPECPDL_INDEX (); + record_unwind_protect_excursion (); + + /* Inhibit quitting. */ + specbind (Qinhibit_quit, Qt); + + /* Temporarily switch to F's selected window. */ + Fselect_window (f->selected_window, Qt); + + /* Now find the appropriate text bounds for QUERY. First, move + point QUERY->position steps forward or backwards. */ + + pos = PT; + + /* If pos is outside the accessible part of the buffer or if it + overflows, move back to point or to the extremes of the + accessible region. */ + + if (INT_ADD_WRAPV (pos, query->position, &pos)) + pos = PT; + + if (pos < BEGV) + pos = BEGV; + + if (pos > ZV) + pos = ZV; + + /* Move to pos. */ + set_point (pos); + pos = PT; + pos_byte = PT_BYTE; + + /* Now scan forward or backwards according to what is in QUERY. */ + + switch (query->direction) + { + case TEXTCONV_FORWARD_CHAR: + /* Move forward by query->factor characters. */ + if (INT_ADD_WRAPV (pos, query->factor, &end) || end > ZV) + end = ZV; + + end_byte = CHAR_TO_BYTE (end); + break; + + case TEXTCONV_BACKWARD_CHAR: + /* Move backward by query->factor characters. */ + if (INT_SUBTRACT_WRAPV (pos, query->factor, &end) || end < BEGV) + end = BEGV; + + end_byte = CHAR_TO_BYTE (end); + break; + + case TEXTCONV_FORWARD_WORD: + /* Move forward by query->factor word. */ + end = scan_words (pos, (EMACS_INT) query->factor); + + if (!end) + { + end = ZV; + end_byte = ZV_BYTE; + } + else + end_byte = CHAR_TO_BYTE (end); + + break; + + case TEXTCONV_BACKWARD_WORD: + /* Move backwards by query->factor word. */ + end = scan_words (pos, 0 - (EMACS_INT) query->factor); + + if (!end) + { + end = BEGV; + end_byte = BEGV_BYTE; + } + else + end_byte = CHAR_TO_BYTE (end); + + break; + + case TEXTCONV_CARET_UP: + /* Move upwards one visual line, keeping the column intact. */ + Fvertical_motion (Fcons (Fcurrent_column (), make_fixnum (-1)), + Qnil, Qnil); + end = PT; + end_byte = PT_BYTE; + break; + + case TEXTCONV_CARET_DOWN: + /* Move downwards one visual line, keeping the column + intact. */ + Fvertical_motion (Fcons (Fcurrent_column (), make_fixnum (1)), + Qnil, Qnil); + end = PT; + end_byte = PT_BYTE; + break; + + case TEXTCONV_NEXT_LINE: + /* Move one line forward. */ + scan_newline (pos, pos_byte, ZV, ZV_BYTE, + query->factor, false); + end = PT; + end_byte = PT_BYTE; + break; + + case TEXTCONV_PREVIOUS_LINE: + /* Move one line backwards. */ + scan_newline (pos, pos_byte, BEGV, BEGV_BYTE, + 0 - (EMACS_INT) query->factor, false); + end = PT; + end_byte = PT_BYTE; + break; + + case TEXTCONV_LINE_START: + /* Move to the beginning of the line. */ + Fbeginning_of_line (Qnil); + end = PT; + end_byte = PT_BYTE; + break; + + case TEXTCONV_LINE_END: + /* Move to the end of the line. */ + Fend_of_line (Qnil); + end = PT; + end_byte = PT_BYTE; + break; + + case TEXTCONV_ABSOLUTE_POSITION: + /* How to implement this is unclear. */ + SET_PT (query->factor); + end = PT; + end_byte = PT_BYTE; + break; + + default: + unbind_to (count, Qnil); + return 1; + } + + /* Sort end and pos. */ + + if (end < pos) + { + eassert (end_byte < pos_byte); + temp = pos_byte; + temp1 = pos; + pos_byte = end_byte; + pos = end; + end = temp1; + end_byte = temp; + } + + /* Return the string first. */ + buffer = xmalloc (end_byte - pos_byte); + copy_buffer (pos, pos_byte, end, end_byte, buffer); + query->text.text = buffer; + query->text.length = end - pos; + query->text.bytes = end_byte - pos_byte; + + /* Next, perform any operation specified. */ + + switch (query->operation) + { + case TEXTCONV_SUBSTITUTION: + if (safe_del_range (pos, end)) + { + /* Undo any changes to the excursion. */ + unbind_to (count, Qnil); + return 1; + } + + default: + } + + /* Undo any changes to the excursion. */ + unbind_to (count, Qnil); + return 0; +} + + + +/* Window system interface. These are called from the rest of + Emacs. */ + +/* Notice that F's selected window has been set from redisplay. + Reset F's input method state. */ + +void +report_selected_window_change (struct frame *f) +{ + if (!text_interface) + return; + + text_interface->reset (f); +} + +/* Register INTERFACE as the text conversion interface. */ + +void +register_texconv_interface (struct textconv_interface *interface) +{ + text_interface = interface; +} diff --git a/src/textconv.h b/src/textconv.h new file mode 100644 index 00000000000..f6e7eb7925f --- /dev/null +++ b/src/textconv.h @@ -0,0 +1,109 @@ +/* String conversion support for graphics terminals. + +Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see . */ + +#ifndef _TEXTCONV_H_ + +#include "lisp.h" +#include "frame.h" + +/* The function pointers in this structure should be filled out by + each GUI backend interested in supporting text conversion. + + Finally, register_texconv_interface must be called at some point + during terminal initialization. */ + +struct textconv_interface +{ + /* Notice that the text conversion context has changed (which can + happen if the window is deleted or switches buffers, or an + unexpected buffer change occurs.) */ + void (*reset) (struct frame *); +}; + + + +enum textconv_caret_direction + { + TEXTCONV_FORWARD_CHAR, + TEXTCONV_BACKWARD_CHAR, + TEXTCONV_FORWARD_WORD, + TEXTCONV_BACKWARD_WORD, + TEXTCONV_CARET_UP, + TEXTCONV_CARET_DOWN, + TEXTCONV_NEXT_LINE, + TEXTCONV_PREVIOUS_LINE, + TEXTCONV_LINE_START, + TEXTCONV_LINE_END, + TEXTCONV_ABSOLUTE_POSITION, + }; + +enum textconv_operation + { + TEXTCONV_SUBSTITUTION, + TEXTCONV_RETRIEVAL, + }; + +/* Structure describing text in a buffer corresponding to a ``struct + textconv_callback_struct''. */ + +struct textconv_conversion_text +{ + /* Length of the text in characters and bytes. */ + size_t length, bytes; + + /* Pointer to the text data. This must be deallocated by the + caller. */ + char *text; +}; + +/* Structure describing a single query submitted by the input + method. */ + +struct textconv_callback_struct +{ + /* Character position, relative to the current spot location, from + where on text should be returned. */ + EMACS_INT position; + + /* The type of scanning to perform to determine either the start or + the end of the conversion. */ + enum textconv_caret_direction direction; + + /* The the number of times for which to repeat the scanning in order + to determine the starting position of the text to return. */ + unsigned short factor; + + /* The operation to perform upon the current buffer contents. + + If this is TEXTCONV_SUBSTITUTION, then the text that is returned + will be deleted from the buffer itself. + + Otherwise, the text is simply returned without modifying the + buffer contents. */ + enum textconv_operation operation; + + /* Structure that will be filled with a description of the resulting + text. */ + struct textconv_conversion_text text; +}; + +extern int textconv_query (struct frame *, struct textconv_callback_struct *); +extern void register_texconv_interface (struct textconv_interface *); + +#endif /* _TEXTCONV_H_ */ commit ae4ff4f25fbf704446f8f38d8e818f223b79042b Author: Po Lu Date: Sun Feb 12 19:55:28 2023 +0800 Support input method ``text conversion'' on X Windows * configure.ac (HAVE_TEXT_CONVERSION): Define on X. * etc/NEWS: Announce new change. * src/emacs.c (main): Always call init_xterm. * src/frame.c (do_switch_frame): Use `fset_selected_window'. * src/insdel.c (struct safe_del_range_context): New structure. (safe_del_range_1, safe_del_range_2, safe_del_range): New functions. * src/lisp.h: Export new functions. * src/window.c (run_window_change_functions): Report selected window and buffer changes so that the input method can be reset. * src/xfns.c (XICCallback, Xxic_preedit_caret_callback) (Xxic_preedit_done_callback, Xxic_preedit_start_callback) (Xxic_preedit_draw_callback): Fix coding style. (Xxic_string_conversion_callback): New callback. (create_frame_xic): Register string conversion callback. (struct x_xim_text_conversion_data): New field `size'. (x_encode_xim_text_1, x_encode_xim_text): New functions. (xic_string_conversion_callback): New function. * src/xterm.c (x_reset_conversion): New function. (text_conversion_interface): New variable. (init_xterm): Initialize text conversion interface. diff --git a/configure.ac b/configure.ac index fc17dbd8318..7bb0df88cb3 100644 --- a/configure.ac +++ b/configure.ac @@ -6502,6 +6502,12 @@ AC_DEFUN AC_DEFINE([POLL_FOR_INPUT], [1], [Define if you poll periodically to detect C-g.]) WINDOW_SYSTEM_OBJ="fontset.o fringe.o image.o" + + if test "$window_system" = "x11"; then + AC_DEFINE([HAVE_TEXT_CONVERSION], [1], + [Define if the window system has text conversion support.]) + WINDOW_SYSTEM_OBJ="$WINDOW_SYSTEM_OBJ textconv.o" + fi fi AC_SUBST([WINDOW_SYSTEM_OBJ]) diff --git a/etc/NEWS b/etc/NEWS index e0175bacfdf..d3eafaadf19 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -59,6 +59,13 @@ This allows the user to customize the prompt that is appended by * Editing Changes in Emacs 30.1 +--- +** On X, Emacs now supports input methods which perform "string conversion". +This means an input method can now ask Emacs to delete text +surrounding point and replace it with something else, as well as query +Emacs for surrounding text. If your input method allows you to "undo" +mistaken compositions, this will now work as well. + --- ** New command 'kill-matching-buffers-no-ask'. This works like 'kill-matching-buffers', but without asking for diff --git a/src/emacs.c b/src/emacs.c index 214e2e2a296..282e2f48100 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -2447,7 +2447,8 @@ main (int argc, char **argv) #ifdef HAVE_DBUS init_dbusbind (); #endif -#if defined(USE_GTK) && !defined(HAVE_PGTK) + +#ifdef HAVE_X_WINDOWS init_xterm (); #endif diff --git a/src/frame.c b/src/frame.c index 983424b0bee..2cea96d4a32 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1526,7 +1526,7 @@ do_switch_frame (Lisp_Object frame, int for_deletion, Lisp_Object norecord) if (f->select_mini_window_flag && !NILP (Fminibufferp (XWINDOW (f->minibuffer_window)->contents, Qt))) - f->selected_window = f->minibuffer_window; + fset_selected_window (f, f->minibuffer_window); f->select_mini_window_flag = false; if (! FRAME_MINIBUF_ONLY_P (XFRAME (selected_frame))) diff --git a/src/insdel.c b/src/insdel.c index e459d0cfa17..b65a3fbd805 100644 --- a/src/insdel.c +++ b/src/insdel.c @@ -1715,6 +1715,44 @@ del_range (ptrdiff_t from, ptrdiff_t to) del_range_1 (from, to, 1, 0); } +struct safe_del_range_context +{ + /* From and to positions. */ + ptrdiff_t from, to; +}; + +static Lisp_Object +safe_del_range_1 (void *ptr) +{ + struct safe_del_range_context *context; + + context = ptr; + del_range (context->from, context->to); + return Qnil; +} + +static Lisp_Object +safe_del_range_2 (enum nonlocal_exit type, Lisp_Object value) +{ + return Qt; +} + +/* Like del_range; however, catch all non-local exits. Value is 0 if + the buffer contents were really deleted. Otherwise, it is 1. */ + +int +safe_del_range (ptrdiff_t from, ptrdiff_t to) +{ + struct safe_del_range_context context; + + context.from = from; + context.to = to; + + return !NILP (internal_catch_all (safe_del_range_1, + &context, + safe_del_range_2)); +} + /* Like del_range; PREPARE says whether to call prepare_to_modify_buffer. RET_STRING says to return the deleted text. */ diff --git a/src/lisp.h b/src/lisp.h index 0bc400ba78f..cacd318c26f 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4116,6 +4116,7 @@ verify (FLT_RADIX == 2 || FLT_RADIX == 16); extern void del_range_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, bool); extern Lisp_Object del_range_2 (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, bool); +extern int safe_del_range (ptrdiff_t, ptrdiff_t); extern void modify_text (ptrdiff_t, ptrdiff_t); extern void prepare_to_modify_buffer (ptrdiff_t, ptrdiff_t, ptrdiff_t *); extern void prepare_to_modify_buffer_1 (ptrdiff_t, ptrdiff_t, ptrdiff_t *); @@ -5212,6 +5213,11 @@ maybe_disable_address_randomization (int argc, char **argv) extern char *emacs_root_dir (void); #endif /* DOS_NT */ +#ifdef HAVE_TEXT_CONVERSION +/* Defined in textconv.c. */ +extern void report_selected_window_change (struct frame *); +#endif + #ifdef HAVE_NATIVE_COMP INLINE bool SUBR_NATIVE_COMPILEDP (Lisp_Object a) diff --git a/src/window.c b/src/window.c index 6201a6f4a36..9334f922f89 100644 --- a/src/window.c +++ b/src/window.c @@ -3856,6 +3856,9 @@ run_window_change_functions_1 (Lisp_Object symbol, Lisp_Object buffer, * * This function does not save and restore match data. Any functions * it calls are responsible for doing that themselves. + * + * Additionally, report changes to each frame's selected window to the + * input method in textconv.c. */ void run_window_change_functions (void) @@ -4015,6 +4018,18 @@ run_window_change_functions (void) run_window_change_functions_1 (Qwindow_selection_change_functions, Qnil, frame); +#if defined HAVE_TEXT_CONVERSION + + /* If the buffer or selected window has changed, also reset the + input method composition state. */ + + if ((frame_selected_window_change || frame_buffer_change) + && FRAME_LIVE_P (f) + && FRAME_WINDOW_P (f)) + report_selected_window_change (f); + +#endif + /* A frame has changed state when a size or buffer change occurred, its selected window has changed, when it was (de-)selected or its window state change flag was set. */ diff --git a/src/xfns.c b/src/xfns.c index 3a129211463..9e004f6a678 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -37,6 +37,10 @@ Copyright (C) 1989, 1992-2023 Free Software Foundation, Inc. #include "termhooks.h" #include "font.h" +#ifdef HAVE_X_I18N +#include "textconv.h" +#endif + #include #include @@ -2671,24 +2675,50 @@ append_wm_protocols (struct x_display_info *dpyinfo, #ifdef HAVE_X_I18N -static void xic_preedit_draw_callback (XIC, XPointer, XIMPreeditDrawCallbackStruct *); -static void xic_preedit_caret_callback (XIC, XPointer, XIMPreeditCaretCallbackStruct *); +static void xic_preedit_draw_callback (XIC, XPointer, + XIMPreeditDrawCallbackStruct *); +static void xic_preedit_caret_callback (XIC, XPointer, + XIMPreeditCaretCallbackStruct *); static void xic_preedit_done_callback (XIC, XPointer, XPointer); static int xic_preedit_start_callback (XIC, XPointer, XPointer); +static void xic_string_conversion_callback (XIC, XPointer, + XIMStringConversionCallbackStruct *); #ifndef HAVE_XICCALLBACK_CALLBACK #define XICCallback XIMCallback #define XICProc XIMProc #endif -static XIMCallback Xxic_preedit_draw_callback = { NULL, - (XIMProc) xic_preedit_draw_callback }; -static XIMCallback Xxic_preedit_caret_callback = { NULL, - (XIMProc) xic_preedit_caret_callback }; -static XIMCallback Xxic_preedit_done_callback = { NULL, - (XIMProc) xic_preedit_done_callback }; -static XICCallback Xxic_preedit_start_callback = { NULL, - (XICProc) xic_preedit_start_callback }; +static XIMCallback Xxic_preedit_draw_callback = + { + NULL, + (XIMProc) xic_preedit_draw_callback, + }; + +static XIMCallback Xxic_preedit_caret_callback = + { + NULL, + (XIMProc) xic_preedit_caret_callback, + }; + +static XIMCallback Xxic_preedit_done_callback = + { + NULL, + (XIMProc) xic_preedit_done_callback, + }; + +static XICCallback Xxic_preedit_start_callback = + { + NULL, + (XICProc) xic_preedit_start_callback, + }; + +static XIMCallback Xxic_string_conversion_callback = + { + /* This is actually an XICCallback! */ + NULL, + (XIMProc) xic_string_conversion_callback, + }; #if defined HAVE_X_WINDOWS && defined USE_X_TOOLKIT /* Create an X fontset on frame F with base font name BASE_FONTNAME. */ @@ -3094,6 +3124,8 @@ create_frame_xic (struct frame *f) XNFocusWindow, FRAME_X_WINDOW (f), XNStatusAttributes, status_attr, XNPreeditAttributes, preedit_attr, + XNStringConversionCallback, + &Xxic_string_conversion_callback, NULL); else if (preedit_attr) xic = XCreateIC (xim, @@ -3101,6 +3133,8 @@ create_frame_xic (struct frame *f) XNClientWindow, FRAME_X_WINDOW (f), XNFocusWindow, FRAME_X_WINDOW (f), XNPreeditAttributes, preedit_attr, + XNStringConversionCallback, + &Xxic_string_conversion_callback, NULL); else if (status_attr) xic = XCreateIC (xim, @@ -3108,12 +3142,16 @@ create_frame_xic (struct frame *f) XNClientWindow, FRAME_X_WINDOW (f), XNFocusWindow, FRAME_X_WINDOW (f), XNStatusAttributes, status_attr, + XNStringConversionCallback, + &Xxic_string_conversion_callback, NULL); else xic = XCreateIC (xim, XNInputStyle, xic_style, XNClientWindow, FRAME_X_WINDOW (f), XNFocusWindow, FRAME_X_WINDOW (f), + XNStringConversionCallback, + &Xxic_string_conversion_callback, NULL); if (!xic) @@ -3377,6 +3415,7 @@ xic_preedit_done_callback (XIC xic, XPointer client_data, struct coding_system *coding; char *source; struct x_display_info *dpyinfo; + size_t size; }; static Lisp_Object @@ -3411,6 +3450,38 @@ x_xim_text_to_utf8_unix_1 (ptrdiff_t nargs, Lisp_Object *args) return Qnil; } +static Lisp_Object +x_encode_xim_text_1 (ptrdiff_t nargs, Lisp_Object *args) +{ + struct x_xim_text_conversion_data *data; + ptrdiff_t nbytes; + Lisp_Object coding_system; + + data = xmint_pointer (args[0]); + + if (SYMBOLP (Vx_input_coding_system)) + coding_system = Vx_input_coding_system; + else if (!NILP (data->dpyinfo->xim_coding)) + coding_system = data->dpyinfo->xim_coding; + else + coding_system = Vlocale_coding_system; + + nbytes = data->size; + + data->coding->destination = NULL; + + setup_coding_system (coding_system, data->coding); + data->coding->mode |= (CODING_MODE_LAST_BLOCK + | CODING_MODE_SAFE_ENCODING); + data->coding->source = (const unsigned char *) data->source; + data->coding->dst_bytes = 2048; + data->coding->destination = xmalloc (2048); + encode_coding_object (data->coding, Qnil, 0, 0, + nbytes, nbytes, Qnil); + + return Qnil; +} + static Lisp_Object x_xim_text_to_utf8_unix_2 (Lisp_Object val, ptrdiff_t nargs, Lisp_Object *args) @@ -3468,6 +3539,46 @@ x_xim_text_to_utf8_unix (struct x_display_info *dpyinfo, return (char *) coding.destination; } +/* Convert SIZE bytes of the specified text from Emacs's internal + coding system to the input method coding system. Return the + result, its byte length in *LENGTH, and its character length in + *CHARS, or NULL. + + The string returned is not NULL terminated. */ + +static char * +x_encode_xim_text (struct x_display_info *dpyinfo, char *text, + size_t size, ptrdiff_t *length, + ptrdiff_t *chars) +{ + struct coding_system coding; + struct x_xim_text_conversion_data data; + Lisp_Object arg; + bool was_waiting_for_input_p; + + data.coding = &coding; + data.source = text; + data.dpyinfo = dpyinfo; + data.size = size; + + was_waiting_for_input_p = waiting_for_input; + /* Otherwise Fsignal will crash. */ + waiting_for_input = false; + + arg = make_mint_ptr (&data); + internal_condition_case_n (x_encode_xim_text_1, 1, &arg, + Qt, x_xim_text_to_utf8_unix_2); + waiting_for_input = was_waiting_for_input_p; + + if (length) + *length = coding.produced; + + if (chars) + *chars = coding.produced_char; + + return (char *) coding.destination; +} + static void xic_preedit_draw_callback (XIC xic, XPointer client_data, XIMPreeditDrawCallbackStruct *call_data) @@ -3664,6 +3775,128 @@ xic_set_xfontset (struct frame *f, const char *base_fontname) FRAME_XIC_FONTSET (f) = xfs; } + + +/* String conversion support. See textconv.c for more details. */ + +static void +xic_string_conversion_callback (XIC ic, XPointer client_data, + XIMStringConversionCallbackStruct *call_data) +{ + struct textconv_callback_struct request; + ptrdiff_t length; + struct frame *f; + int rc; + + /* Find the frame associated with this IC. */ + f = x_xic_to_frame (ic); + + if (!f) + goto failure; + + /* Fill in CALL_DATA as early as possible. */ + call_data->text->feedback = NULL; + call_data->text->encoding_is_wchar = False; + + /* Now translate the conversion request to the format understood by + textconv.c. */ + request.position = call_data->position; + + switch (call_data->direction) + { + case XIMForwardChar: + request.direction = TEXTCONV_FORWARD_CHAR; + break; + + case XIMBackwardChar: + request.direction = TEXTCONV_BACKWARD_CHAR; + break; + + case XIMForwardWord: + request.direction = TEXTCONV_FORWARD_WORD; + break; + + case XIMBackwardWord: + request.direction = TEXTCONV_BACKWARD_WORD; + break; + + case XIMCaretUp: + request.direction = TEXTCONV_CARET_UP; + break; + + case XIMCaretDown: + request.direction = TEXTCONV_CARET_DOWN; + break; + + case XIMNextLine: + request.direction = TEXTCONV_NEXT_LINE; + break; + + case XIMPreviousLine: + request.direction = TEXTCONV_PREVIOUS_LINE; + break; + + case XIMLineStart: + request.direction = TEXTCONV_LINE_START; + break; + + case XIMLineEnd: + request.direction = TEXTCONV_LINE_END; + break; + + case XIMAbsolutePosition: + request.direction = TEXTCONV_ABSOLUTE_POSITION; + break; + + default: + goto failure; + } + + /* factor is signed in call_data but is actually a CARD16. */ + request.factor = call_data->factor; + + if (call_data->operation == XIMStringConversionSubstitution) + request.operation = TEXTCONV_SUBSTITUTION; + else + request.operation = TEXTCONV_RETRIEVAL; + + /* Now perform the string conversion. */ + rc = textconv_query (f, &request); + + if (rc) + { + xfree (request.text.text); + goto failure; + } + + /* Encode the text in the locale coding system and give it back to + the input method. */ + request.text.text = NULL; + call_data->text->string.mbs + = x_encode_xim_text (FRAME_DISPLAY_INFO (f), + request.text.text, + request.text.bytes, NULL, + &length); + call_data->text->length = length; + + /* Free the encoded text. This is always set to something + valid. */ + xfree (request.text.text); + + /* Detect failure. */ + if (!call_data->text->string.mbs) + goto failure; + + return; + + failure: + /* Return a string of length 0 using the C library malloc. This + assumes XFree is able to free data allocated with our malloc + wrapper. */ + call_data->text->length = 0; + call_data->text->string.mbs = malloc (0); +} + #endif /* HAVE_X_I18N */ @@ -9771,6 +10004,53 @@ DEFUN ("x-internal-focus-input-context", Fx_internal_focus_input_context, return Qnil; } + +#if 0 + +DEFUN ("x-test-string-conversion", Fx_test_string_conversion, + Sx_test_string_conversion, 5, 5, 0, + doc: /* Perform tests on the XIM string conversion support. */) + (Lisp_Object frame, Lisp_Object position, + Lisp_Object direction, Lisp_Object operation, Lisp_Object factor) +{ + struct frame *f; + XIMStringConversionCallbackStruct call_data; + XIMStringConversionText text; + + f = decode_window_system_frame (frame); + + if (!FRAME_XIC (f)) + error ("No XIC on FRAME!"); + + CHECK_FIXNUM (position); + CHECK_FIXNUM (direction); + CHECK_FIXNUM (operation); + CHECK_FIXNUM (factor); + + /* xic_string_conversion_callback (XIC ic, XPointer client_data, + XIMStringConversionCallbackStruct *call_data) */ + + call_data.position = XFIXNUM (position); + call_data.direction = XFIXNUM (direction); + call_data.operation = XFIXNUM (operation); + call_data.factor = XFIXNUM (factor); + call_data.text = &text; + + block_input (); + xic_string_conversion_callback (FRAME_XIC (f), NULL, + &call_data); + unblock_input (); + + /* Place a breakpoint here to inspect TEXT! */ + + while (1) + maybe_quit (); + + return Qnil; +} + +#endif + /*********************************************************************** Initialization @@ -10217,6 +10497,9 @@ syms_of_xfns (void) defsubr (&Sx_display_set_last_user_time); defsubr (&Sx_translate_coordinates); defsubr (&Sx_get_modifier_masks); +#if 0 + defsubr (&Sx_test_string_conversion); +#endif tip_timer = Qnil; staticpro (&tip_timer); diff --git a/src/xterm.c b/src/xterm.c index 1325d923be9..5feaa4aef0f 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -636,6 +636,10 @@ Copyright (C) 1989, 1993-2023 Free Software Foundation, Inc. #include "xterm.h" #include +#ifdef HAVE_X_I18N +#include "textconv.h" +#endif + #ifdef USE_XCB #include #include @@ -31506,7 +31510,37 @@ x_initialize (void) XSetIOErrorHandler (x_io_error_quitter); } -#ifdef USE_GTK +#ifdef HAVE_X_I18N + +/* Notice that a change has occured on F that requires its input + method state to be reset. */ + +static void +x_reset_conversion (struct frame *f) +{ + char *string; + + if (FRAME_XIC (f)) + { + string = XmbResetIC (FRAME_XIC (f)); + + /* string is actually any string that was being composed at the + time of the reset. */ + + if (string) + XFree (string); + } +} + +/* Interface used to control input method ``text conversion''. */ + +static struct textconv_interface text_conversion_interface = + { + x_reset_conversion, + }; + +#endif + void init_xterm (void) { @@ -31520,8 +31554,11 @@ init_xterm (void) gdk_disable_multidevice (); #endif #endif -} + +#ifdef HAVE_X_I18N + register_texconv_interface (&text_conversion_interface); #endif +} void mark_xterm (void) commit 7287b7b53a17f9b2d1b474466106806a9d57af47 Author: Ulrich Müller Date: Thu Feb 9 10:58:48 2023 +0100 Support webkit2gtk-4.1 * configure.ac: Check for webkit2gtk API version 4.1 first, then fall back to 4.0. diff --git a/configure.ac b/configure.ac index 645082c9746..bc7e61048c3 100644 --- a/configure.ac +++ b/configure.ac @@ -3613,8 +3613,12 @@ AC_DEFUN if test "$with_xwidgets" != "no"; then if test "$USE_GTK_TOOLKIT" = "GTK3" && test "$window_system" != "none"; then WEBKIT_REQUIRED=2.12 - WEBKIT_MODULES="webkit2gtk-4.0 >= $WEBKIT_REQUIRED" + WEBKIT_MODULES="webkit2gtk-4.1 >= $WEBKIT_REQUIRED" EMACS_CHECK_MODULES([WEBKIT], [$WEBKIT_MODULES]) + if test "$HAVE_WEBKIT" = "no"; then + WEBKIT_MODULES="webkit2gtk-4.0 >= $WEBKIT_REQUIRED" + EMACS_CHECK_MODULES([WEBKIT], [$WEBKIT_MODULES]) + fi HAVE_XWIDGETS=$HAVE_WEBKIT XWIDGETS_OBJ="xwidget.o" if test "$HAVE_X_WINDOWS" = "yes" && test "${with_cairo}" = "no"; then commit 048a2dabfc4aab33d9097bce2971839e051f9d0d Author: Stefan Kangas Date: Sun Feb 12 07:47:09 2023 +0100 ; Fix typo diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi index e1a4613875c..6a8aaf8ebaf 100644 --- a/doc/lispref/internals.texi +++ b/doc/lispref/internals.texi @@ -2550,7 +2550,7 @@ Buffer Internals @code{mode_line_format} stores the value of @code{mode-line-format}. @item overlays -The inveral tree containing this buffer's overlays. +The interval tree containing this buffer's overlays. @item last_selected_window This is the last window that was selected with this buffer in it, or @code{nil}