diff options
| author | Po Lu | 2023-02-12 20:32:31 +0800 |
|---|---|---|
| committer | Po Lu | 2023-02-12 20:32:31 +0800 |
| commit | 19eb27d47787bd8a519a37a8e6080ed5b56435dc (patch) | |
| tree | 61669a450983bdaa356698b6f26958bebfa191ad /src | |
| parent | 0198b8cffd82893412c738dae8e50c45a99286f1 (diff) | |
| parent | 9510e8ad68271f58b4813478703a4b8eb1ba597b (diff) | |
| download | emacs-19eb27d47787bd8a519a37a8e6080ed5b56435dc.tar.gz emacs-19eb27d47787bd8a519a37a8e6080ed5b56435dc.zip | |
Merge remote-tracking branch 'origin/master' into feature/android
Diffstat (limited to 'src')
| -rw-r--r-- | src/buffer.h | 2 | ||||
| -rw-r--r-- | src/emacs.c | 3 | ||||
| -rw-r--r-- | src/fns.c | 17 | ||||
| -rw-r--r-- | src/frame.c | 2 | ||||
| -rw-r--r-- | src/insdel.c | 38 | ||||
| -rw-r--r-- | src/lisp.h | 6 | ||||
| -rw-r--r-- | src/textconv.c | 312 | ||||
| -rw-r--r-- | src/textconv.h | 109 | ||||
| -rw-r--r-- | src/treesit.c | 46 | ||||
| -rw-r--r-- | src/window.c | 15 | ||||
| -rw-r--r-- | src/xfns.c | 303 | ||||
| -rw-r--r-- | src/xterm.c | 41 |
12 files changed, 856 insertions, 38 deletions
diff --git a/src/buffer.h b/src/buffer.h index eb32d602ad6..e700297a264 100644 --- a/src/buffer.h +++ b/src/buffer.h | |||
| @@ -690,7 +690,7 @@ struct buffer | |||
| 690 | display optimizations must be used. */ | 690 | display optimizations must be used. */ |
| 691 | bool_bf long_line_optimizations_p : 1; | 691 | bool_bf long_line_optimizations_p : 1; |
| 692 | 692 | ||
| 693 | /* The inveral tree containing this buffer's overlays. */ | 693 | /* The interval tree containing this buffer's overlays. */ |
| 694 | struct itree_tree *overlays; | 694 | struct itree_tree *overlays; |
| 695 | 695 | ||
| 696 | /* Changes in the buffer are recorded here for undo, and t means | 696 | /* Changes in the buffer are recorded here for undo, and t means |
diff --git a/src/emacs.c b/src/emacs.c index 79156c63017..d7de3c85bbe 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -2525,7 +2525,8 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 2525 | #ifdef HAVE_DBUS | 2525 | #ifdef HAVE_DBUS |
| 2526 | init_dbusbind (); | 2526 | init_dbusbind (); |
| 2527 | #endif | 2527 | #endif |
| 2528 | #if defined(USE_GTK) && !defined(HAVE_PGTK) | 2528 | |
| 2529 | #ifdef HAVE_X_WINDOWS | ||
| 2529 | init_xterm (); | 2530 | init_xterm (); |
| 2530 | #endif | 2531 | #endif |
| 2531 | 2532 | ||
| @@ -5813,8 +5813,9 @@ secure_hash (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start, | |||
| 5813 | DEFUN ("md5", Fmd5, Smd5, 1, 5, 0, | 5813 | DEFUN ("md5", Fmd5, Smd5, 1, 5, 0, |
| 5814 | doc: /* Return MD5 message digest of OBJECT, a buffer or string. | 5814 | doc: /* Return MD5 message digest of OBJECT, a buffer or string. |
| 5815 | 5815 | ||
| 5816 | A message digest is a cryptographic checksum of a document, and the | 5816 | A message digest is the string representation of the cryptographic checksum |
| 5817 | algorithm to calculate it is defined in RFC 1321. | 5817 | of a document, and the algorithm to calculate it is defined in RFC 1321. |
| 5818 | The MD5 digest is 32-character long. | ||
| 5818 | 5819 | ||
| 5819 | The two optional arguments START and END are character positions | 5820 | The two optional arguments START and END are character positions |
| 5820 | specifying for which part of OBJECT the message digest should be | 5821 | specifying for which part of OBJECT the message digest should be |
| @@ -5848,12 +5849,12 @@ anything security-related. See `secure-hash' for alternatives. */) | |||
| 5848 | DEFUN ("secure-hash", Fsecure_hash, Ssecure_hash, 2, 5, 0, | 5849 | DEFUN ("secure-hash", Fsecure_hash, Ssecure_hash, 2, 5, 0, |
| 5849 | doc: /* Return the secure hash of OBJECT, a buffer or string. | 5850 | doc: /* Return the secure hash of OBJECT, a buffer or string. |
| 5850 | ALGORITHM is a symbol specifying the hash to use: | 5851 | ALGORITHM is a symbol specifying the hash to use: |
| 5851 | - md5 corresponds to MD5 | 5852 | - md5 corresponds to MD5, produces a 32-character signature |
| 5852 | - sha1 corresponds to SHA-1 | 5853 | - sha1 corresponds to SHA-1, produces a 40-character signature |
| 5853 | - sha224 corresponds to SHA-2 (SHA-224) | 5854 | - sha224 corresponds to SHA-2 (SHA-224), produces a 56-character signature |
| 5854 | - sha256 corresponds to SHA-2 (SHA-256) | 5855 | - sha256 corresponds to SHA-2 (SHA-256), produces a 64-character signature |
| 5855 | - sha384 corresponds to SHA-2 (SHA-384) | 5856 | - sha384 corresponds to SHA-2 (SHA-384), produces a 96-character signature |
| 5856 | - sha512 corresponds to SHA-2 (SHA-512) | 5857 | - sha512 corresponds to SHA-2 (SHA-512), produces a 128-character signature |
| 5857 | 5858 | ||
| 5858 | The two optional arguments START and END are positions specifying for | 5859 | The two optional arguments START and END are positions specifying for |
| 5859 | which part of OBJECT to compute the hash. If nil or omitted, uses the | 5860 | which part of OBJECT to compute the hash. If nil or omitted, uses the |
diff --git a/src/frame.c b/src/frame.c index e98256fe9ed..a1d73d0799d 100644 --- a/src/frame.c +++ b/src/frame.c | |||
| @@ -1538,7 +1538,7 @@ do_switch_frame (Lisp_Object frame, int for_deletion, Lisp_Object norecord) | |||
| 1538 | 1538 | ||
| 1539 | if (f->select_mini_window_flag | 1539 | if (f->select_mini_window_flag |
| 1540 | && !NILP (Fminibufferp (XWINDOW (f->minibuffer_window)->contents, Qt))) | 1540 | && !NILP (Fminibufferp (XWINDOW (f->minibuffer_window)->contents, Qt))) |
| 1541 | f->selected_window = f->minibuffer_window; | 1541 | fset_selected_window (f, f->minibuffer_window); |
| 1542 | f->select_mini_window_flag = false; | 1542 | f->select_mini_window_flag = false; |
| 1543 | 1543 | ||
| 1544 | if (! FRAME_MINIBUF_ONLY_P (XFRAME (selected_frame))) | 1544 | 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) | |||
| 1715 | del_range_1 (from, to, 1, 0); | 1715 | del_range_1 (from, to, 1, 0); |
| 1716 | } | 1716 | } |
| 1717 | 1717 | ||
| 1718 | struct safe_del_range_context | ||
| 1719 | { | ||
| 1720 | /* From and to positions. */ | ||
| 1721 | ptrdiff_t from, to; | ||
| 1722 | }; | ||
| 1723 | |||
| 1724 | static Lisp_Object | ||
| 1725 | safe_del_range_1 (void *ptr) | ||
| 1726 | { | ||
| 1727 | struct safe_del_range_context *context; | ||
| 1728 | |||
| 1729 | context = ptr; | ||
| 1730 | del_range (context->from, context->to); | ||
| 1731 | return Qnil; | ||
| 1732 | } | ||
| 1733 | |||
| 1734 | static Lisp_Object | ||
| 1735 | safe_del_range_2 (enum nonlocal_exit type, Lisp_Object value) | ||
| 1736 | { | ||
| 1737 | return Qt; | ||
| 1738 | } | ||
| 1739 | |||
| 1740 | /* Like del_range; however, catch all non-local exits. Value is 0 if | ||
| 1741 | the buffer contents were really deleted. Otherwise, it is 1. */ | ||
| 1742 | |||
| 1743 | int | ||
| 1744 | safe_del_range (ptrdiff_t from, ptrdiff_t to) | ||
| 1745 | { | ||
| 1746 | struct safe_del_range_context context; | ||
| 1747 | |||
| 1748 | context.from = from; | ||
| 1749 | context.to = to; | ||
| 1750 | |||
| 1751 | return !NILP (internal_catch_all (safe_del_range_1, | ||
| 1752 | &context, | ||
| 1753 | safe_del_range_2)); | ||
| 1754 | } | ||
| 1755 | |||
| 1718 | /* Like del_range; PREPARE says whether to call prepare_to_modify_buffer. | 1756 | /* Like del_range; PREPARE says whether to call prepare_to_modify_buffer. |
| 1719 | RET_STRING says to return the deleted text. */ | 1757 | RET_STRING says to return the deleted text. */ |
| 1720 | 1758 | ||
diff --git a/src/lisp.h b/src/lisp.h index 6abde4d545e..894b939b7b9 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -4121,6 +4121,7 @@ extern void del_range_byte (ptrdiff_t, ptrdiff_t); | |||
| 4121 | extern void del_range_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, bool); | 4121 | extern void del_range_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, bool); |
| 4122 | extern Lisp_Object del_range_2 (ptrdiff_t, ptrdiff_t, | 4122 | extern Lisp_Object del_range_2 (ptrdiff_t, ptrdiff_t, |
| 4123 | ptrdiff_t, ptrdiff_t, bool); | 4123 | ptrdiff_t, ptrdiff_t, bool); |
| 4124 | extern int safe_del_range (ptrdiff_t, ptrdiff_t); | ||
| 4124 | extern void modify_text (ptrdiff_t, ptrdiff_t); | 4125 | extern void modify_text (ptrdiff_t, ptrdiff_t); |
| 4125 | extern void prepare_to_modify_buffer (ptrdiff_t, ptrdiff_t, ptrdiff_t *); | 4126 | extern void prepare_to_modify_buffer (ptrdiff_t, ptrdiff_t, ptrdiff_t *); |
| 4126 | extern void prepare_to_modify_buffer_1 (ptrdiff_t, ptrdiff_t, ptrdiff_t *); | 4127 | extern void prepare_to_modify_buffer_1 (ptrdiff_t, ptrdiff_t, ptrdiff_t *); |
| @@ -5227,6 +5228,11 @@ extern void syms_of_profiler (void); | |||
| 5227 | extern char *emacs_root_dir (void); | 5228 | extern char *emacs_root_dir (void); |
| 5228 | #endif /* DOS_NT */ | 5229 | #endif /* DOS_NT */ |
| 5229 | 5230 | ||
| 5231 | #ifdef HAVE_TEXT_CONVERSION | ||
| 5232 | /* Defined in textconv.c. */ | ||
| 5233 | extern void report_selected_window_change (struct frame *); | ||
| 5234 | #endif | ||
| 5235 | |||
| 5230 | #ifdef HAVE_NATIVE_COMP | 5236 | #ifdef HAVE_NATIVE_COMP |
| 5231 | INLINE bool | 5237 | INLINE bool |
| 5232 | SUBR_NATIVE_COMPILEDP (Lisp_Object a) | 5238 | SUBR_NATIVE_COMPILEDP (Lisp_Object a) |
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 @@ | |||
| 1 | /* String conversion support for graphics terminals. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | /* String conversion support. | ||
| 21 | |||
| 22 | Many input methods require access to text surrounding the cursor. | ||
| 23 | They may then request that the text editor remove or substitute | ||
| 24 | that text for something else, for example when providing the | ||
| 25 | ability to ``undo'' or ``edit'' previously composed text. This is | ||
| 26 | most commonly seen in input methods for CJK laguages for X Windows, | ||
| 27 | and is extensively used throughout Android by input methods for all | ||
| 28 | kinds of scripts. */ | ||
| 29 | |||
| 30 | #include <config.h> | ||
| 31 | |||
| 32 | #include "textconv.h" | ||
| 33 | #include "buffer.h" | ||
| 34 | #include "syntax.h" | ||
| 35 | |||
| 36 | |||
| 37 | |||
| 38 | /* The window system's text conversion interface. | ||
| 39 | NULL when the window system has not set up text conversion. | ||
| 40 | |||
| 41 | This interface will later be heavily extended on the | ||
| 42 | feature/android branch to deal with Android's much less | ||
| 43 | straightforward text conversion protocols. */ | ||
| 44 | |||
| 45 | static struct textconv_interface *text_interface; | ||
| 46 | |||
| 47 | |||
| 48 | |||
| 49 | /* Copy the portion of the current buffer described by BEG, BEG_BYTE, | ||
| 50 | END, END_BYTE to the buffer BUFFER, which is END_BYTE - BEG_BYTEs | ||
| 51 | long. */ | ||
| 52 | |||
| 53 | static void | ||
| 54 | copy_buffer (ptrdiff_t beg, ptrdiff_t beg_byte, | ||
| 55 | ptrdiff_t end, ptrdiff_t end_byte, | ||
| 56 | char *buffer) | ||
| 57 | { | ||
| 58 | ptrdiff_t beg0, end0, beg1, end1, size; | ||
| 59 | |||
| 60 | if (beg_byte < GPT_BYTE && GPT_BYTE < end_byte) | ||
| 61 | { | ||
| 62 | /* Two regions, before and after the gap. */ | ||
| 63 | beg0 = beg_byte; | ||
| 64 | end0 = GPT_BYTE; | ||
| 65 | beg1 = GPT_BYTE + GAP_SIZE - BEG_BYTE; | ||
| 66 | end1 = end_byte + GAP_SIZE - BEG_BYTE; | ||
| 67 | } | ||
| 68 | else | ||
| 69 | { | ||
| 70 | /* The only region. */ | ||
| 71 | beg0 = beg_byte; | ||
| 72 | end0 = end_byte; | ||
| 73 | beg1 = -1; | ||
| 74 | end1 = -1; | ||
| 75 | } | ||
| 76 | |||
| 77 | size = end0 - beg0; | ||
| 78 | memcpy (buffer, BYTE_POS_ADDR (beg0), size); | ||
| 79 | if (beg1 != -1) | ||
| 80 | memcpy (buffer, BEG_ADDR + beg1, end1 - beg1); | ||
| 81 | } | ||
| 82 | |||
| 83 | |||
| 84 | |||
| 85 | /* Conversion query. */ | ||
| 86 | |||
| 87 | /* Perform the text conversion operation specified in QUERY and return | ||
| 88 | the results. | ||
| 89 | |||
| 90 | Find the text between QUERY->position from point on F's selected | ||
| 91 | window and QUERY->factor times QUERY->direction from that | ||
| 92 | position. Return it in QUERY->text. | ||
| 93 | |||
| 94 | Then, either delete that text from the buffer if QUERY->operation | ||
| 95 | is TEXTCONV_SUBSTITUTION, or return 0. | ||
| 96 | |||
| 97 | Value is 0 if QUERY->operation was not TEXTCONV_SUBSTITUTION | ||
| 98 | or if deleting the text was successful, and 1 otherwise. */ | ||
| 99 | |||
| 100 | int | ||
| 101 | textconv_query (struct frame *f, struct textconv_callback_struct *query) | ||
| 102 | { | ||
| 103 | specpdl_ref count; | ||
| 104 | ptrdiff_t pos, pos_byte, end, end_byte; | ||
| 105 | ptrdiff_t temp, temp1; | ||
| 106 | char *buffer; | ||
| 107 | |||
| 108 | /* Save the excursion, as there will be extensive changes to the | ||
| 109 | selected window. */ | ||
| 110 | count = SPECPDL_INDEX (); | ||
| 111 | record_unwind_protect_excursion (); | ||
| 112 | |||
| 113 | /* Inhibit quitting. */ | ||
| 114 | specbind (Qinhibit_quit, Qt); | ||
| 115 | |||
| 116 | /* Temporarily switch to F's selected window. */ | ||
| 117 | Fselect_window (f->selected_window, Qt); | ||
| 118 | |||
| 119 | /* Now find the appropriate text bounds for QUERY. First, move | ||
| 120 | point QUERY->position steps forward or backwards. */ | ||
| 121 | |||
| 122 | pos = PT; | ||
| 123 | |||
| 124 | /* If pos is outside the accessible part of the buffer or if it | ||
| 125 | overflows, move back to point or to the extremes of the | ||
| 126 | accessible region. */ | ||
| 127 | |||
| 128 | if (INT_ADD_WRAPV (pos, query->position, &pos)) | ||
| 129 | pos = PT; | ||
| 130 | |||
| 131 | if (pos < BEGV) | ||
| 132 | pos = BEGV; | ||
| 133 | |||
| 134 | if (pos > ZV) | ||
| 135 | pos = ZV; | ||
| 136 | |||
| 137 | /* Move to pos. */ | ||
| 138 | set_point (pos); | ||
| 139 | pos = PT; | ||
| 140 | pos_byte = PT_BYTE; | ||
| 141 | |||
| 142 | /* Now scan forward or backwards according to what is in QUERY. */ | ||
| 143 | |||
| 144 | switch (query->direction) | ||
| 145 | { | ||
| 146 | case TEXTCONV_FORWARD_CHAR: | ||
| 147 | /* Move forward by query->factor characters. */ | ||
| 148 | if (INT_ADD_WRAPV (pos, query->factor, &end) || end > ZV) | ||
| 149 | end = ZV; | ||
| 150 | |||
| 151 | end_byte = CHAR_TO_BYTE (end); | ||
| 152 | break; | ||
| 153 | |||
| 154 | case TEXTCONV_BACKWARD_CHAR: | ||
| 155 | /* Move backward by query->factor characters. */ | ||
| 156 | if (INT_SUBTRACT_WRAPV (pos, query->factor, &end) || end < BEGV) | ||
| 157 | end = BEGV; | ||
| 158 | |||
| 159 | end_byte = CHAR_TO_BYTE (end); | ||
| 160 | break; | ||
| 161 | |||
| 162 | case TEXTCONV_FORWARD_WORD: | ||
| 163 | /* Move forward by query->factor word. */ | ||
| 164 | end = scan_words (pos, (EMACS_INT) query->factor); | ||
| 165 | |||
| 166 | if (!end) | ||
| 167 | { | ||
| 168 | end = ZV; | ||
| 169 | end_byte = ZV_BYTE; | ||
| 170 | } | ||
| 171 | else | ||
| 172 | end_byte = CHAR_TO_BYTE (end); | ||
| 173 | |||
| 174 | break; | ||
| 175 | |||
| 176 | case TEXTCONV_BACKWARD_WORD: | ||
| 177 | /* Move backwards by query->factor word. */ | ||
| 178 | end = scan_words (pos, 0 - (EMACS_INT) query->factor); | ||
| 179 | |||
| 180 | if (!end) | ||
| 181 | { | ||
| 182 | end = BEGV; | ||
| 183 | end_byte = BEGV_BYTE; | ||
| 184 | } | ||
| 185 | else | ||
| 186 | end_byte = CHAR_TO_BYTE (end); | ||
| 187 | |||
| 188 | break; | ||
| 189 | |||
| 190 | case TEXTCONV_CARET_UP: | ||
| 191 | /* Move upwards one visual line, keeping the column intact. */ | ||
| 192 | Fvertical_motion (Fcons (Fcurrent_column (), make_fixnum (-1)), | ||
| 193 | Qnil, Qnil); | ||
| 194 | end = PT; | ||
| 195 | end_byte = PT_BYTE; | ||
| 196 | break; | ||
| 197 | |||
| 198 | case TEXTCONV_CARET_DOWN: | ||
| 199 | /* Move downwards one visual line, keeping the column | ||
| 200 | intact. */ | ||
| 201 | Fvertical_motion (Fcons (Fcurrent_column (), make_fixnum (1)), | ||
| 202 | Qnil, Qnil); | ||
| 203 | end = PT; | ||
| 204 | end_byte = PT_BYTE; | ||
| 205 | break; | ||
| 206 | |||
| 207 | case TEXTCONV_NEXT_LINE: | ||
| 208 | /* Move one line forward. */ | ||
| 209 | scan_newline (pos, pos_byte, ZV, ZV_BYTE, | ||
| 210 | query->factor, false); | ||
| 211 | end = PT; | ||
| 212 | end_byte = PT_BYTE; | ||
| 213 | break; | ||
| 214 | |||
| 215 | case TEXTCONV_PREVIOUS_LINE: | ||
| 216 | /* Move one line backwards. */ | ||
| 217 | scan_newline (pos, pos_byte, BEGV, BEGV_BYTE, | ||
| 218 | 0 - (EMACS_INT) query->factor, false); | ||
| 219 | end = PT; | ||
| 220 | end_byte = PT_BYTE; | ||
| 221 | break; | ||
| 222 | |||
| 223 | case TEXTCONV_LINE_START: | ||
| 224 | /* Move to the beginning of the line. */ | ||
| 225 | Fbeginning_of_line (Qnil); | ||
| 226 | end = PT; | ||
| 227 | end_byte = PT_BYTE; | ||
| 228 | break; | ||
| 229 | |||
| 230 | case TEXTCONV_LINE_END: | ||
| 231 | /* Move to the end of the line. */ | ||
| 232 | Fend_of_line (Qnil); | ||
| 233 | end = PT; | ||
| 234 | end_byte = PT_BYTE; | ||
| 235 | break; | ||
| 236 | |||
| 237 | case TEXTCONV_ABSOLUTE_POSITION: | ||
| 238 | /* How to implement this is unclear. */ | ||
| 239 | SET_PT (query->factor); | ||
| 240 | end = PT; | ||
| 241 | end_byte = PT_BYTE; | ||
| 242 | break; | ||
| 243 | |||
| 244 | default: | ||
| 245 | unbind_to (count, Qnil); | ||
| 246 | return 1; | ||
| 247 | } | ||
| 248 | |||
| 249 | /* Sort end and pos. */ | ||
| 250 | |||
| 251 | if (end < pos) | ||
| 252 | { | ||
| 253 | eassert (end_byte < pos_byte); | ||
| 254 | temp = pos_byte; | ||
| 255 | temp1 = pos; | ||
| 256 | pos_byte = end_byte; | ||
| 257 | pos = end; | ||
| 258 | end = temp1; | ||
| 259 | end_byte = temp; | ||
| 260 | } | ||
| 261 | |||
| 262 | /* Return the string first. */ | ||
| 263 | buffer = xmalloc (end_byte - pos_byte); | ||
| 264 | copy_buffer (pos, pos_byte, end, end_byte, buffer); | ||
| 265 | query->text.text = buffer; | ||
| 266 | query->text.length = end - pos; | ||
| 267 | query->text.bytes = end_byte - pos_byte; | ||
| 268 | |||
| 269 | /* Next, perform any operation specified. */ | ||
| 270 | |||
| 271 | switch (query->operation) | ||
| 272 | { | ||
| 273 | case TEXTCONV_SUBSTITUTION: | ||
| 274 | if (safe_del_range (pos, end)) | ||
| 275 | { | ||
| 276 | /* Undo any changes to the excursion. */ | ||
| 277 | unbind_to (count, Qnil); | ||
| 278 | return 1; | ||
| 279 | } | ||
| 280 | |||
| 281 | default: | ||
| 282 | } | ||
| 283 | |||
| 284 | /* Undo any changes to the excursion. */ | ||
| 285 | unbind_to (count, Qnil); | ||
| 286 | return 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | |||
| 290 | |||
| 291 | /* Window system interface. These are called from the rest of | ||
| 292 | Emacs. */ | ||
| 293 | |||
| 294 | /* Notice that F's selected window has been set from redisplay. | ||
| 295 | Reset F's input method state. */ | ||
| 296 | |||
| 297 | void | ||
| 298 | report_selected_window_change (struct frame *f) | ||
| 299 | { | ||
| 300 | if (!text_interface) | ||
| 301 | return; | ||
| 302 | |||
| 303 | text_interface->reset (f); | ||
| 304 | } | ||
| 305 | |||
| 306 | /* Register INTERFACE as the text conversion interface. */ | ||
| 307 | |||
| 308 | void | ||
| 309 | register_texconv_interface (struct textconv_interface *interface) | ||
| 310 | { | ||
| 311 | text_interface = interface; | ||
| 312 | } | ||
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 @@ | |||
| 1 | /* String conversion support for graphics terminals. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #ifndef _TEXTCONV_H_ | ||
| 21 | |||
| 22 | #include "lisp.h" | ||
| 23 | #include "frame.h" | ||
| 24 | |||
| 25 | /* The function pointers in this structure should be filled out by | ||
| 26 | each GUI backend interested in supporting text conversion. | ||
| 27 | |||
| 28 | Finally, register_texconv_interface must be called at some point | ||
| 29 | during terminal initialization. */ | ||
| 30 | |||
| 31 | struct textconv_interface | ||
| 32 | { | ||
| 33 | /* Notice that the text conversion context has changed (which can | ||
| 34 | happen if the window is deleted or switches buffers, or an | ||
| 35 | unexpected buffer change occurs.) */ | ||
| 36 | void (*reset) (struct frame *); | ||
| 37 | }; | ||
| 38 | |||
| 39 | |||
| 40 | |||
| 41 | enum textconv_caret_direction | ||
| 42 | { | ||
| 43 | TEXTCONV_FORWARD_CHAR, | ||
| 44 | TEXTCONV_BACKWARD_CHAR, | ||
| 45 | TEXTCONV_FORWARD_WORD, | ||
| 46 | TEXTCONV_BACKWARD_WORD, | ||
| 47 | TEXTCONV_CARET_UP, | ||
| 48 | TEXTCONV_CARET_DOWN, | ||
| 49 | TEXTCONV_NEXT_LINE, | ||
| 50 | TEXTCONV_PREVIOUS_LINE, | ||
| 51 | TEXTCONV_LINE_START, | ||
| 52 | TEXTCONV_LINE_END, | ||
| 53 | TEXTCONV_ABSOLUTE_POSITION, | ||
| 54 | }; | ||
| 55 | |||
| 56 | enum textconv_operation | ||
| 57 | { | ||
| 58 | TEXTCONV_SUBSTITUTION, | ||
| 59 | TEXTCONV_RETRIEVAL, | ||
| 60 | }; | ||
| 61 | |||
| 62 | /* Structure describing text in a buffer corresponding to a ``struct | ||
| 63 | textconv_callback_struct''. */ | ||
| 64 | |||
| 65 | struct textconv_conversion_text | ||
| 66 | { | ||
| 67 | /* Length of the text in characters and bytes. */ | ||
| 68 | size_t length, bytes; | ||
| 69 | |||
| 70 | /* Pointer to the text data. This must be deallocated by the | ||
| 71 | caller. */ | ||
| 72 | char *text; | ||
| 73 | }; | ||
| 74 | |||
| 75 | /* Structure describing a single query submitted by the input | ||
| 76 | method. */ | ||
| 77 | |||
| 78 | struct textconv_callback_struct | ||
| 79 | { | ||
| 80 | /* Character position, relative to the current spot location, from | ||
| 81 | where on text should be returned. */ | ||
| 82 | EMACS_INT position; | ||
| 83 | |||
| 84 | /* The type of scanning to perform to determine either the start or | ||
| 85 | the end of the conversion. */ | ||
| 86 | enum textconv_caret_direction direction; | ||
| 87 | |||
| 88 | /* The the number of times for which to repeat the scanning in order | ||
| 89 | to determine the starting position of the text to return. */ | ||
| 90 | unsigned short factor; | ||
| 91 | |||
| 92 | /* The operation to perform upon the current buffer contents. | ||
| 93 | |||
| 94 | If this is TEXTCONV_SUBSTITUTION, then the text that is returned | ||
| 95 | will be deleted from the buffer itself. | ||
| 96 | |||
| 97 | Otherwise, the text is simply returned without modifying the | ||
| 98 | buffer contents. */ | ||
| 99 | enum textconv_operation operation; | ||
| 100 | |||
| 101 | /* Structure that will be filled with a description of the resulting | ||
| 102 | text. */ | ||
| 103 | struct textconv_conversion_text text; | ||
| 104 | }; | ||
| 105 | |||
| 106 | extern int textconv_query (struct frame *, struct textconv_callback_struct *); | ||
| 107 | extern void register_texconv_interface (struct textconv_interface *); | ||
| 108 | |||
| 109 | #endif /* _TEXTCONV_H_ */ | ||
diff --git a/src/treesit.c b/src/treesit.c index cfa3721b5e7..cab2f0d5354 100644 --- a/src/treesit.c +++ b/src/treesit.c | |||
| @@ -1475,6 +1475,15 @@ This symbol is the one used to create the parser. */) | |||
| 1475 | return XTS_PARSER (parser)->language_symbol; | 1475 | return XTS_PARSER (parser)->language_symbol; |
| 1476 | } | 1476 | } |
| 1477 | 1477 | ||
| 1478 | /* Return true if PARSER is not deleted and its buffer is live. */ | ||
| 1479 | static bool | ||
| 1480 | treesit_parser_live_p (Lisp_Object parser) | ||
| 1481 | { | ||
| 1482 | CHECK_TS_PARSER (parser); | ||
| 1483 | return ((!XTS_PARSER (parser)->deleted) && | ||
| 1484 | (!NILP (Fbuffer_live_p (XTS_PARSER (parser)->buffer)))); | ||
| 1485 | } | ||
| 1486 | |||
| 1478 | /*** Parser API */ | 1487 | /*** Parser API */ |
| 1479 | 1488 | ||
| 1480 | DEFUN ("treesit-parser-root-node", | 1489 | DEFUN ("treesit-parser-root-node", |
| @@ -1908,7 +1917,8 @@ DEFUN ("treesit-node-check", | |||
| 1908 | Ftreesit_node_check, Streesit_node_check, 2, 2, 0, | 1917 | Ftreesit_node_check, Streesit_node_check, 2, 2, 0, |
| 1909 | doc: /* Return non-nil if NODE has PROPERTY, nil otherwise. | 1918 | doc: /* Return non-nil if NODE has PROPERTY, nil otherwise. |
| 1910 | 1919 | ||
| 1911 | PROPERTY could be `named', `missing', `extra', `outdated', or `has-error'. | 1920 | PROPERTY could be `named', `missing', `extra', `outdated', |
| 1921 | `has-error', or `live'. | ||
| 1912 | 1922 | ||
| 1913 | Named nodes correspond to named rules in the language definition, | 1923 | Named nodes correspond to named rules in the language definition, |
| 1914 | whereas "anonymous" nodes correspond to string literals in the | 1924 | whereas "anonymous" nodes correspond to string literals in the |
| @@ -1924,7 +1934,10 @@ A node is "outdated" if the parser has reparsed at least once after | |||
| 1924 | the node was created. | 1934 | the node was created. |
| 1925 | 1935 | ||
| 1926 | A node "has error" if itself is a syntax error or contains any syntax | 1936 | A node "has error" if itself is a syntax error or contains any syntax |
| 1927 | errors. */) | 1937 | errors. |
| 1938 | |||
| 1939 | A node is "live" if its parser is not deleted and its buffer is | ||
| 1940 | live. */) | ||
| 1928 | (Lisp_Object node, Lisp_Object property) | 1941 | (Lisp_Object node, Lisp_Object property) |
| 1929 | { | 1942 | { |
| 1930 | if (NILP (node)) return Qnil; | 1943 | if (NILP (node)) return Qnil; |
| @@ -1947,9 +1960,11 @@ errors. */) | |||
| 1947 | result = ts_node_is_extra (treesit_node); | 1960 | result = ts_node_is_extra (treesit_node); |
| 1948 | else if (EQ (property, Qhas_error)) | 1961 | else if (EQ (property, Qhas_error)) |
| 1949 | result = ts_node_has_error (treesit_node); | 1962 | result = ts_node_has_error (treesit_node); |
| 1963 | else if (EQ (property, Qlive)) | ||
| 1964 | result = treesit_parser_live_p (XTS_NODE (node)->parser); | ||
| 1950 | else | 1965 | else |
| 1951 | signal_error ("Expecting `named', `missing', `extra', " | 1966 | signal_error ("Expecting `named', `missing', `extra', " |
| 1952 | "`outdated', or `has-error', but got", | 1967 | "`outdated', `has-error', or `live', but got", |
| 1953 | property); | 1968 | property); |
| 1954 | return result ? Qt : Qnil; | 1969 | return result ? Qt : Qnil; |
| 1955 | } | 1970 | } |
| @@ -3135,13 +3150,13 @@ the way. PREDICATE is a regexp string that matches against each | |||
| 3135 | node's type, or a function that takes a node and returns nil/non-nil. | 3150 | node's type, or a function that takes a node and returns nil/non-nil. |
| 3136 | 3151 | ||
| 3137 | By default, only traverse named nodes, but if ALL is non-nil, traverse | 3152 | By default, only traverse named nodes, but if ALL is non-nil, traverse |
| 3138 | all nodes. If BACKWARD is non-nil, traverse backwards. If LIMIT is | 3153 | all nodes. If BACKWARD is non-nil, traverse backwards. If DEPTH is |
| 3139 | non-nil, only traverse nodes up to that number of levels down in the | 3154 | non-nil, only traverse nodes up to that number of levels down in the |
| 3140 | tree. If LIMIT is nil, default to 1000. | 3155 | tree. If DEPTH is nil, default to 1000. |
| 3141 | 3156 | ||
| 3142 | Return the first matched node, or nil if none matches. */) | 3157 | Return the first matched node, or nil if none matches. */) |
| 3143 | (Lisp_Object node, Lisp_Object predicate, Lisp_Object backward, | 3158 | (Lisp_Object node, Lisp_Object predicate, Lisp_Object backward, |
| 3144 | Lisp_Object all, Lisp_Object limit) | 3159 | Lisp_Object all, Lisp_Object depth) |
| 3145 | { | 3160 | { |
| 3146 | CHECK_TS_NODE (node); | 3161 | CHECK_TS_NODE (node); |
| 3147 | CHECK_TYPE (STRINGP (predicate) || FUNCTIONP (predicate), | 3162 | CHECK_TYPE (STRINGP (predicate) || FUNCTIONP (predicate), |
| @@ -3152,10 +3167,10 @@ Return the first matched node, or nil if none matches. */) | |||
| 3152 | /* We use a default limit of 1000. See bug#59426 for the | 3167 | /* We use a default limit of 1000. See bug#59426 for the |
| 3153 | discussion. */ | 3168 | discussion. */ |
| 3154 | ptrdiff_t the_limit = treesit_recursion_limit; | 3169 | ptrdiff_t the_limit = treesit_recursion_limit; |
| 3155 | if (!NILP (limit)) | 3170 | if (!NILP (depth)) |
| 3156 | { | 3171 | { |
| 3157 | CHECK_FIXNUM (limit); | 3172 | CHECK_FIXNUM (depth); |
| 3158 | the_limit = XFIXNUM (limit); | 3173 | the_limit = XFIXNUM (depth); |
| 3159 | } | 3174 | } |
| 3160 | 3175 | ||
| 3161 | treesit_initialize (); | 3176 | treesit_initialize (); |
| @@ -3307,8 +3322,8 @@ If PROCESS-FN is non-nil, it should be a function of one argument. In | |||
| 3307 | that case, instead of returning the matched nodes, pass each node to | 3322 | that case, instead of returning the matched nodes, pass each node to |
| 3308 | PROCESS-FN, and use its return value instead. | 3323 | PROCESS-FN, and use its return value instead. |
| 3309 | 3324 | ||
| 3310 | If non-nil, LIMIT is the number of levels to go down the tree from | 3325 | If non-nil, DEPTH is the number of levels to go down the tree from |
| 3311 | ROOT. If LIMIT is nil or omitted, it defaults to 1000. | 3326 | ROOT. If DEPTH is nil or omitted, it defaults to 1000. |
| 3312 | 3327 | ||
| 3313 | Each node in the returned tree looks like (NODE . (CHILD ...)). The | 3328 | Each node in the returned tree looks like (NODE . (CHILD ...)). The |
| 3314 | root of this tree might be nil, if ROOT doesn't match PREDICATE. | 3329 | root of this tree might be nil, if ROOT doesn't match PREDICATE. |
| @@ -3319,7 +3334,7 @@ PREDICATE can also be a function that takes a node and returns | |||
| 3319 | nil/non-nil, but it is slower and more memory consuming than using | 3334 | nil/non-nil, but it is slower and more memory consuming than using |
| 3320 | a regexp. */) | 3335 | a regexp. */) |
| 3321 | (Lisp_Object root, Lisp_Object predicate, Lisp_Object process_fn, | 3336 | (Lisp_Object root, Lisp_Object predicate, Lisp_Object process_fn, |
| 3322 | Lisp_Object limit) | 3337 | Lisp_Object depth) |
| 3323 | { | 3338 | { |
| 3324 | CHECK_TS_NODE (root); | 3339 | CHECK_TS_NODE (root); |
| 3325 | CHECK_TYPE (STRINGP (predicate) || FUNCTIONP (predicate), | 3340 | CHECK_TYPE (STRINGP (predicate) || FUNCTIONP (predicate), |
| @@ -3331,10 +3346,10 @@ a regexp. */) | |||
| 3331 | /* We use a default limit of 1000. See bug#59426 for the | 3346 | /* We use a default limit of 1000. See bug#59426 for the |
| 3332 | discussion. */ | 3347 | discussion. */ |
| 3333 | ptrdiff_t the_limit = treesit_recursion_limit; | 3348 | ptrdiff_t the_limit = treesit_recursion_limit; |
| 3334 | if (!NILP (limit)) | 3349 | if (!NILP (depth)) |
| 3335 | { | 3350 | { |
| 3336 | CHECK_FIXNUM (limit); | 3351 | CHECK_FIXNUM (depth); |
| 3337 | the_limit = XFIXNUM (limit); | 3352 | the_limit = XFIXNUM (depth); |
| 3338 | } | 3353 | } |
| 3339 | 3354 | ||
| 3340 | treesit_initialize (); | 3355 | treesit_initialize (); |
| @@ -3448,6 +3463,7 @@ syms_of_treesit (void) | |||
| 3448 | DEFSYM (Qextra, "extra"); | 3463 | DEFSYM (Qextra, "extra"); |
| 3449 | DEFSYM (Qoutdated, "outdated"); | 3464 | DEFSYM (Qoutdated, "outdated"); |
| 3450 | DEFSYM (Qhas_error, "has-error"); | 3465 | DEFSYM (Qhas_error, "has-error"); |
| 3466 | DEFSYM (Qlive, "live"); | ||
| 3451 | 3467 | ||
| 3452 | DEFSYM (QCanchor, ":anchor"); | 3468 | DEFSYM (QCanchor, ":anchor"); |
| 3453 | DEFSYM (QCequal, ":equal"); | 3469 | DEFSYM (QCequal, ":equal"); |
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, | |||
| 3856 | * | 3856 | * |
| 3857 | * This function does not save and restore match data. Any functions | 3857 | * This function does not save and restore match data. Any functions |
| 3858 | * it calls are responsible for doing that themselves. | 3858 | * it calls are responsible for doing that themselves. |
| 3859 | * | ||
| 3860 | * Additionally, report changes to each frame's selected window to the | ||
| 3861 | * input method in textconv.c. | ||
| 3859 | */ | 3862 | */ |
| 3860 | void | 3863 | void |
| 3861 | run_window_change_functions (void) | 3864 | run_window_change_functions (void) |
| @@ -4015,6 +4018,18 @@ run_window_change_functions (void) | |||
| 4015 | run_window_change_functions_1 | 4018 | run_window_change_functions_1 |
| 4016 | (Qwindow_selection_change_functions, Qnil, frame); | 4019 | (Qwindow_selection_change_functions, Qnil, frame); |
| 4017 | 4020 | ||
| 4021 | #if defined HAVE_TEXT_CONVERSION | ||
| 4022 | |||
| 4023 | /* If the buffer or selected window has changed, also reset the | ||
| 4024 | input method composition state. */ | ||
| 4025 | |||
| 4026 | if ((frame_selected_window_change || frame_buffer_change) | ||
| 4027 | && FRAME_LIVE_P (f) | ||
| 4028 | && FRAME_WINDOW_P (f)) | ||
| 4029 | report_selected_window_change (f); | ||
| 4030 | |||
| 4031 | #endif | ||
| 4032 | |||
| 4018 | /* A frame has changed state when a size or buffer change | 4033 | /* A frame has changed state when a size or buffer change |
| 4019 | occurred, its selected window has changed, when it was | 4034 | occurred, its selected window has changed, when it was |
| 4020 | (de-)selected or its window state change flag was set. */ | 4035 | (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 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 37 | #include "termhooks.h" | 37 | #include "termhooks.h" |
| 38 | #include "font.h" | 38 | #include "font.h" |
| 39 | 39 | ||
| 40 | #ifdef HAVE_X_I18N | ||
| 41 | #include "textconv.h" | ||
| 42 | #endif | ||
| 43 | |||
| 40 | #include <sys/types.h> | 44 | #include <sys/types.h> |
| 41 | #include <sys/stat.h> | 45 | #include <sys/stat.h> |
| 42 | 46 | ||
| @@ -2671,24 +2675,50 @@ append_wm_protocols (struct x_display_info *dpyinfo, | |||
| 2671 | 2675 | ||
| 2672 | #ifdef HAVE_X_I18N | 2676 | #ifdef HAVE_X_I18N |
| 2673 | 2677 | ||
| 2674 | static void xic_preedit_draw_callback (XIC, XPointer, XIMPreeditDrawCallbackStruct *); | 2678 | static void xic_preedit_draw_callback (XIC, XPointer, |
| 2675 | static void xic_preedit_caret_callback (XIC, XPointer, XIMPreeditCaretCallbackStruct *); | 2679 | XIMPreeditDrawCallbackStruct *); |
| 2680 | static void xic_preedit_caret_callback (XIC, XPointer, | ||
| 2681 | XIMPreeditCaretCallbackStruct *); | ||
| 2676 | static void xic_preedit_done_callback (XIC, XPointer, XPointer); | 2682 | static void xic_preedit_done_callback (XIC, XPointer, XPointer); |
| 2677 | static int xic_preedit_start_callback (XIC, XPointer, XPointer); | 2683 | static int xic_preedit_start_callback (XIC, XPointer, XPointer); |
| 2684 | static void xic_string_conversion_callback (XIC, XPointer, | ||
| 2685 | XIMStringConversionCallbackStruct *); | ||
| 2678 | 2686 | ||
| 2679 | #ifndef HAVE_XICCALLBACK_CALLBACK | 2687 | #ifndef HAVE_XICCALLBACK_CALLBACK |
| 2680 | #define XICCallback XIMCallback | 2688 | #define XICCallback XIMCallback |
| 2681 | #define XICProc XIMProc | 2689 | #define XICProc XIMProc |
| 2682 | #endif | 2690 | #endif |
| 2683 | 2691 | ||
| 2684 | static XIMCallback Xxic_preedit_draw_callback = { NULL, | 2692 | static XIMCallback Xxic_preedit_draw_callback = |
| 2685 | (XIMProc) xic_preedit_draw_callback }; | 2693 | { |
| 2686 | static XIMCallback Xxic_preedit_caret_callback = { NULL, | 2694 | NULL, |
| 2687 | (XIMProc) xic_preedit_caret_callback }; | 2695 | (XIMProc) xic_preedit_draw_callback, |
| 2688 | static XIMCallback Xxic_preedit_done_callback = { NULL, | 2696 | }; |
| 2689 | (XIMProc) xic_preedit_done_callback }; | 2697 | |
| 2690 | static XICCallback Xxic_preedit_start_callback = { NULL, | 2698 | static XIMCallback Xxic_preedit_caret_callback = |
| 2691 | (XICProc) xic_preedit_start_callback }; | 2699 | { |
| 2700 | NULL, | ||
| 2701 | (XIMProc) xic_preedit_caret_callback, | ||
| 2702 | }; | ||
| 2703 | |||
| 2704 | static XIMCallback Xxic_preedit_done_callback = | ||
| 2705 | { | ||
| 2706 | NULL, | ||
| 2707 | (XIMProc) xic_preedit_done_callback, | ||
| 2708 | }; | ||
| 2709 | |||
| 2710 | static XICCallback Xxic_preedit_start_callback = | ||
| 2711 | { | ||
| 2712 | NULL, | ||
| 2713 | (XICProc) xic_preedit_start_callback, | ||
| 2714 | }; | ||
| 2715 | |||
| 2716 | static XIMCallback Xxic_string_conversion_callback = | ||
| 2717 | { | ||
| 2718 | /* This is actually an XICCallback! */ | ||
| 2719 | NULL, | ||
| 2720 | (XIMProc) xic_string_conversion_callback, | ||
| 2721 | }; | ||
| 2692 | 2722 | ||
| 2693 | #if defined HAVE_X_WINDOWS && defined USE_X_TOOLKIT | 2723 | #if defined HAVE_X_WINDOWS && defined USE_X_TOOLKIT |
| 2694 | /* Create an X fontset on frame F with base font name BASE_FONTNAME. */ | 2724 | /* Create an X fontset on frame F with base font name BASE_FONTNAME. */ |
| @@ -3094,6 +3124,8 @@ create_frame_xic (struct frame *f) | |||
| 3094 | XNFocusWindow, FRAME_X_WINDOW (f), | 3124 | XNFocusWindow, FRAME_X_WINDOW (f), |
| 3095 | XNStatusAttributes, status_attr, | 3125 | XNStatusAttributes, status_attr, |
| 3096 | XNPreeditAttributes, preedit_attr, | 3126 | XNPreeditAttributes, preedit_attr, |
| 3127 | XNStringConversionCallback, | ||
| 3128 | &Xxic_string_conversion_callback, | ||
| 3097 | NULL); | 3129 | NULL); |
| 3098 | else if (preedit_attr) | 3130 | else if (preedit_attr) |
| 3099 | xic = XCreateIC (xim, | 3131 | xic = XCreateIC (xim, |
| @@ -3101,6 +3133,8 @@ create_frame_xic (struct frame *f) | |||
| 3101 | XNClientWindow, FRAME_X_WINDOW (f), | 3133 | XNClientWindow, FRAME_X_WINDOW (f), |
| 3102 | XNFocusWindow, FRAME_X_WINDOW (f), | 3134 | XNFocusWindow, FRAME_X_WINDOW (f), |
| 3103 | XNPreeditAttributes, preedit_attr, | 3135 | XNPreeditAttributes, preedit_attr, |
| 3136 | XNStringConversionCallback, | ||
| 3137 | &Xxic_string_conversion_callback, | ||
| 3104 | NULL); | 3138 | NULL); |
| 3105 | else if (status_attr) | 3139 | else if (status_attr) |
| 3106 | xic = XCreateIC (xim, | 3140 | xic = XCreateIC (xim, |
| @@ -3108,12 +3142,16 @@ create_frame_xic (struct frame *f) | |||
| 3108 | XNClientWindow, FRAME_X_WINDOW (f), | 3142 | XNClientWindow, FRAME_X_WINDOW (f), |
| 3109 | XNFocusWindow, FRAME_X_WINDOW (f), | 3143 | XNFocusWindow, FRAME_X_WINDOW (f), |
| 3110 | XNStatusAttributes, status_attr, | 3144 | XNStatusAttributes, status_attr, |
| 3145 | XNStringConversionCallback, | ||
| 3146 | &Xxic_string_conversion_callback, | ||
| 3111 | NULL); | 3147 | NULL); |
| 3112 | else | 3148 | else |
| 3113 | xic = XCreateIC (xim, | 3149 | xic = XCreateIC (xim, |
| 3114 | XNInputStyle, xic_style, | 3150 | XNInputStyle, xic_style, |
| 3115 | XNClientWindow, FRAME_X_WINDOW (f), | 3151 | XNClientWindow, FRAME_X_WINDOW (f), |
| 3116 | XNFocusWindow, FRAME_X_WINDOW (f), | 3152 | XNFocusWindow, FRAME_X_WINDOW (f), |
| 3153 | XNStringConversionCallback, | ||
| 3154 | &Xxic_string_conversion_callback, | ||
| 3117 | NULL); | 3155 | NULL); |
| 3118 | 3156 | ||
| 3119 | if (!xic) | 3157 | if (!xic) |
| @@ -3377,6 +3415,7 @@ struct x_xim_text_conversion_data | |||
| 3377 | struct coding_system *coding; | 3415 | struct coding_system *coding; |
| 3378 | char *source; | 3416 | char *source; |
| 3379 | struct x_display_info *dpyinfo; | 3417 | struct x_display_info *dpyinfo; |
| 3418 | size_t size; | ||
| 3380 | }; | 3419 | }; |
| 3381 | 3420 | ||
| 3382 | static Lisp_Object | 3421 | static Lisp_Object |
| @@ -3412,6 +3451,38 @@ x_xim_text_to_utf8_unix_1 (ptrdiff_t nargs, Lisp_Object *args) | |||
| 3412 | } | 3451 | } |
| 3413 | 3452 | ||
| 3414 | static Lisp_Object | 3453 | static Lisp_Object |
| 3454 | x_encode_xim_text_1 (ptrdiff_t nargs, Lisp_Object *args) | ||
| 3455 | { | ||
| 3456 | struct x_xim_text_conversion_data *data; | ||
| 3457 | ptrdiff_t nbytes; | ||
| 3458 | Lisp_Object coding_system; | ||
| 3459 | |||
| 3460 | data = xmint_pointer (args[0]); | ||
| 3461 | |||
| 3462 | if (SYMBOLP (Vx_input_coding_system)) | ||
| 3463 | coding_system = Vx_input_coding_system; | ||
| 3464 | else if (!NILP (data->dpyinfo->xim_coding)) | ||
| 3465 | coding_system = data->dpyinfo->xim_coding; | ||
| 3466 | else | ||
| 3467 | coding_system = Vlocale_coding_system; | ||
| 3468 | |||
| 3469 | nbytes = data->size; | ||
| 3470 | |||
| 3471 | data->coding->destination = NULL; | ||
| 3472 | |||
| 3473 | setup_coding_system (coding_system, data->coding); | ||
| 3474 | data->coding->mode |= (CODING_MODE_LAST_BLOCK | ||
| 3475 | | CODING_MODE_SAFE_ENCODING); | ||
| 3476 | data->coding->source = (const unsigned char *) data->source; | ||
| 3477 | data->coding->dst_bytes = 2048; | ||
| 3478 | data->coding->destination = xmalloc (2048); | ||
| 3479 | encode_coding_object (data->coding, Qnil, 0, 0, | ||
| 3480 | nbytes, nbytes, Qnil); | ||
| 3481 | |||
| 3482 | return Qnil; | ||
| 3483 | } | ||
| 3484 | |||
| 3485 | static Lisp_Object | ||
| 3415 | x_xim_text_to_utf8_unix_2 (Lisp_Object val, ptrdiff_t nargs, | 3486 | x_xim_text_to_utf8_unix_2 (Lisp_Object val, ptrdiff_t nargs, |
| 3416 | Lisp_Object *args) | 3487 | Lisp_Object *args) |
| 3417 | { | 3488 | { |
| @@ -3468,6 +3539,46 @@ x_xim_text_to_utf8_unix (struct x_display_info *dpyinfo, | |||
| 3468 | return (char *) coding.destination; | 3539 | return (char *) coding.destination; |
| 3469 | } | 3540 | } |
| 3470 | 3541 | ||
| 3542 | /* Convert SIZE bytes of the specified text from Emacs's internal | ||
| 3543 | coding system to the input method coding system. Return the | ||
| 3544 | result, its byte length in *LENGTH, and its character length in | ||
| 3545 | *CHARS, or NULL. | ||
| 3546 | |||
| 3547 | The string returned is not NULL terminated. */ | ||
| 3548 | |||
| 3549 | static char * | ||
| 3550 | x_encode_xim_text (struct x_display_info *dpyinfo, char *text, | ||
| 3551 | size_t size, ptrdiff_t *length, | ||
| 3552 | ptrdiff_t *chars) | ||
| 3553 | { | ||
| 3554 | struct coding_system coding; | ||
| 3555 | struct x_xim_text_conversion_data data; | ||
| 3556 | Lisp_Object arg; | ||
| 3557 | bool was_waiting_for_input_p; | ||
| 3558 | |||
| 3559 | data.coding = &coding; | ||
| 3560 | data.source = text; | ||
| 3561 | data.dpyinfo = dpyinfo; | ||
| 3562 | data.size = size; | ||
| 3563 | |||
| 3564 | was_waiting_for_input_p = waiting_for_input; | ||
| 3565 | /* Otherwise Fsignal will crash. */ | ||
| 3566 | waiting_for_input = false; | ||
| 3567 | |||
| 3568 | arg = make_mint_ptr (&data); | ||
| 3569 | internal_condition_case_n (x_encode_xim_text_1, 1, &arg, | ||
| 3570 | Qt, x_xim_text_to_utf8_unix_2); | ||
| 3571 | waiting_for_input = was_waiting_for_input_p; | ||
| 3572 | |||
| 3573 | if (length) | ||
| 3574 | *length = coding.produced; | ||
| 3575 | |||
| 3576 | if (chars) | ||
| 3577 | *chars = coding.produced_char; | ||
| 3578 | |||
| 3579 | return (char *) coding.destination; | ||
| 3580 | } | ||
| 3581 | |||
| 3471 | static void | 3582 | static void |
| 3472 | xic_preedit_draw_callback (XIC xic, XPointer client_data, | 3583 | xic_preedit_draw_callback (XIC xic, XPointer client_data, |
| 3473 | XIMPreeditDrawCallbackStruct *call_data) | 3584 | XIMPreeditDrawCallbackStruct *call_data) |
| @@ -3664,6 +3775,128 @@ xic_set_xfontset (struct frame *f, const char *base_fontname) | |||
| 3664 | FRAME_XIC_FONTSET (f) = xfs; | 3775 | FRAME_XIC_FONTSET (f) = xfs; |
| 3665 | } | 3776 | } |
| 3666 | 3777 | ||
| 3778 | |||
| 3779 | |||
| 3780 | /* String conversion support. See textconv.c for more details. */ | ||
| 3781 | |||
| 3782 | static void | ||
| 3783 | xic_string_conversion_callback (XIC ic, XPointer client_data, | ||
| 3784 | XIMStringConversionCallbackStruct *call_data) | ||
| 3785 | { | ||
| 3786 | struct textconv_callback_struct request; | ||
| 3787 | ptrdiff_t length; | ||
| 3788 | struct frame *f; | ||
| 3789 | int rc; | ||
| 3790 | |||
| 3791 | /* Find the frame associated with this IC. */ | ||
| 3792 | f = x_xic_to_frame (ic); | ||
| 3793 | |||
| 3794 | if (!f) | ||
| 3795 | goto failure; | ||
| 3796 | |||
| 3797 | /* Fill in CALL_DATA as early as possible. */ | ||
| 3798 | call_data->text->feedback = NULL; | ||
| 3799 | call_data->text->encoding_is_wchar = False; | ||
| 3800 | |||
| 3801 | /* Now translate the conversion request to the format understood by | ||
| 3802 | textconv.c. */ | ||
| 3803 | request.position = call_data->position; | ||
| 3804 | |||
| 3805 | switch (call_data->direction) | ||
| 3806 | { | ||
| 3807 | case XIMForwardChar: | ||
| 3808 | request.direction = TEXTCONV_FORWARD_CHAR; | ||
| 3809 | break; | ||
| 3810 | |||
| 3811 | case XIMBackwardChar: | ||
| 3812 | request.direction = TEXTCONV_BACKWARD_CHAR; | ||
| 3813 | break; | ||
| 3814 | |||
| 3815 | case XIMForwardWord: | ||
| 3816 | request.direction = TEXTCONV_FORWARD_WORD; | ||
| 3817 | break; | ||
| 3818 | |||
| 3819 | case XIMBackwardWord: | ||
| 3820 | request.direction = TEXTCONV_BACKWARD_WORD; | ||
| 3821 | break; | ||
| 3822 | |||
| 3823 | case XIMCaretUp: | ||
| 3824 | request.direction = TEXTCONV_CARET_UP; | ||
| 3825 | break; | ||
| 3826 | |||
| 3827 | case XIMCaretDown: | ||
| 3828 | request.direction = TEXTCONV_CARET_DOWN; | ||
| 3829 | break; | ||
| 3830 | |||
| 3831 | case XIMNextLine: | ||
| 3832 | request.direction = TEXTCONV_NEXT_LINE; | ||
| 3833 | break; | ||
| 3834 | |||
| 3835 | case XIMPreviousLine: | ||
| 3836 | request.direction = TEXTCONV_PREVIOUS_LINE; | ||
| 3837 | break; | ||
| 3838 | |||
| 3839 | case XIMLineStart: | ||
| 3840 | request.direction = TEXTCONV_LINE_START; | ||
| 3841 | break; | ||
| 3842 | |||
| 3843 | case XIMLineEnd: | ||
| 3844 | request.direction = TEXTCONV_LINE_END; | ||
| 3845 | break; | ||
| 3846 | |||
| 3847 | case XIMAbsolutePosition: | ||
| 3848 | request.direction = TEXTCONV_ABSOLUTE_POSITION; | ||
| 3849 | break; | ||
| 3850 | |||
| 3851 | default: | ||
| 3852 | goto failure; | ||
| 3853 | } | ||
| 3854 | |||
| 3855 | /* factor is signed in call_data but is actually a CARD16. */ | ||
| 3856 | request.factor = call_data->factor; | ||
| 3857 | |||
| 3858 | if (call_data->operation == XIMStringConversionSubstitution) | ||
| 3859 | request.operation = TEXTCONV_SUBSTITUTION; | ||
| 3860 | else | ||
| 3861 | request.operation = TEXTCONV_RETRIEVAL; | ||
| 3862 | |||
| 3863 | /* Now perform the string conversion. */ | ||
| 3864 | rc = textconv_query (f, &request); | ||
| 3865 | |||
| 3866 | if (rc) | ||
| 3867 | { | ||
| 3868 | xfree (request.text.text); | ||
| 3869 | goto failure; | ||
| 3870 | } | ||
| 3871 | |||
| 3872 | /* Encode the text in the locale coding system and give it back to | ||
| 3873 | the input method. */ | ||
| 3874 | request.text.text = NULL; | ||
| 3875 | call_data->text->string.mbs | ||
| 3876 | = x_encode_xim_text (FRAME_DISPLAY_INFO (f), | ||
| 3877 | request.text.text, | ||
| 3878 | request.text.bytes, NULL, | ||
| 3879 | &length); | ||
| 3880 | call_data->text->length = length; | ||
| 3881 | |||
| 3882 | /* Free the encoded text. This is always set to something | ||
| 3883 | valid. */ | ||
| 3884 | xfree (request.text.text); | ||
| 3885 | |||
| 3886 | /* Detect failure. */ | ||
| 3887 | if (!call_data->text->string.mbs) | ||
| 3888 | goto failure; | ||
| 3889 | |||
| 3890 | return; | ||
| 3891 | |||
| 3892 | failure: | ||
| 3893 | /* Return a string of length 0 using the C library malloc. This | ||
| 3894 | assumes XFree is able to free data allocated with our malloc | ||
| 3895 | wrapper. */ | ||
| 3896 | call_data->text->length = 0; | ||
| 3897 | call_data->text->string.mbs = malloc (0); | ||
| 3898 | } | ||
| 3899 | |||
| 3667 | #endif /* HAVE_X_I18N */ | 3900 | #endif /* HAVE_X_I18N */ |
| 3668 | 3901 | ||
| 3669 | 3902 | ||
| @@ -9771,6 +10004,53 @@ This should be called from a variable watcher for `x-gtk-use-native-input'. */) | |||
| 9771 | 10004 | ||
| 9772 | return Qnil; | 10005 | return Qnil; |
| 9773 | } | 10006 | } |
| 10007 | |||
| 10008 | #if 0 | ||
| 10009 | |||
| 10010 | DEFUN ("x-test-string-conversion", Fx_test_string_conversion, | ||
| 10011 | Sx_test_string_conversion, 5, 5, 0, | ||
| 10012 | doc: /* Perform tests on the XIM string conversion support. */) | ||
| 10013 | (Lisp_Object frame, Lisp_Object position, | ||
| 10014 | Lisp_Object direction, Lisp_Object operation, Lisp_Object factor) | ||
| 10015 | { | ||
| 10016 | struct frame *f; | ||
| 10017 | XIMStringConversionCallbackStruct call_data; | ||
| 10018 | XIMStringConversionText text; | ||
| 10019 | |||
| 10020 | f = decode_window_system_frame (frame); | ||
| 10021 | |||
| 10022 | if (!FRAME_XIC (f)) | ||
| 10023 | error ("No XIC on FRAME!"); | ||
| 10024 | |||
| 10025 | CHECK_FIXNUM (position); | ||
| 10026 | CHECK_FIXNUM (direction); | ||
| 10027 | CHECK_FIXNUM (operation); | ||
| 10028 | CHECK_FIXNUM (factor); | ||
| 10029 | |||
| 10030 | /* xic_string_conversion_callback (XIC ic, XPointer client_data, | ||
| 10031 | XIMStringConversionCallbackStruct *call_data) */ | ||
| 10032 | |||
| 10033 | call_data.position = XFIXNUM (position); | ||
| 10034 | call_data.direction = XFIXNUM (direction); | ||
| 10035 | call_data.operation = XFIXNUM (operation); | ||
| 10036 | call_data.factor = XFIXNUM (factor); | ||
| 10037 | call_data.text = &text; | ||
| 10038 | |||
| 10039 | block_input (); | ||
| 10040 | xic_string_conversion_callback (FRAME_XIC (f), NULL, | ||
| 10041 | &call_data); | ||
| 10042 | unblock_input (); | ||
| 10043 | |||
| 10044 | /* Place a breakpoint here to inspect TEXT! */ | ||
| 10045 | |||
| 10046 | while (1) | ||
| 10047 | maybe_quit (); | ||
| 10048 | |||
| 10049 | return Qnil; | ||
| 10050 | } | ||
| 10051 | |||
| 10052 | #endif | ||
| 10053 | |||
| 9774 | 10054 | ||
| 9775 | /*********************************************************************** | 10055 | /*********************************************************************** |
| 9776 | Initialization | 10056 | Initialization |
| @@ -10217,6 +10497,9 @@ eliminated in future versions of Emacs. */); | |||
| 10217 | defsubr (&Sx_display_set_last_user_time); | 10497 | defsubr (&Sx_display_set_last_user_time); |
| 10218 | defsubr (&Sx_translate_coordinates); | 10498 | defsubr (&Sx_translate_coordinates); |
| 10219 | defsubr (&Sx_get_modifier_masks); | 10499 | defsubr (&Sx_get_modifier_masks); |
| 10500 | #if 0 | ||
| 10501 | defsubr (&Sx_test_string_conversion); | ||
| 10502 | #endif | ||
| 10220 | 10503 | ||
| 10221 | tip_timer = Qnil; | 10504 | tip_timer = Qnil; |
| 10222 | staticpro (&tip_timer); | 10505 | staticpro (&tip_timer); |
diff --git a/src/xterm.c b/src/xterm.c index eeefed34d4b..ccaacec2c57 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -636,6 +636,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 636 | #include "xterm.h" | 636 | #include "xterm.h" |
| 637 | #include <X11/cursorfont.h> | 637 | #include <X11/cursorfont.h> |
| 638 | 638 | ||
| 639 | #ifdef HAVE_X_I18N | ||
| 640 | #include "textconv.h" | ||
| 641 | #endif | ||
| 642 | |||
| 639 | #ifdef USE_XCB | 643 | #ifdef USE_XCB |
| 640 | #include <xcb/xproto.h> | 644 | #include <xcb/xproto.h> |
| 641 | #include <xcb/xcb.h> | 645 | #include <xcb/xcb.h> |
| @@ -31565,7 +31569,37 @@ x_initialize (void) | |||
| 31565 | XSetIOErrorHandler (x_io_error_quitter); | 31569 | XSetIOErrorHandler (x_io_error_quitter); |
| 31566 | } | 31570 | } |
| 31567 | 31571 | ||
| 31568 | #ifdef USE_GTK | 31572 | #ifdef HAVE_X_I18N |
| 31573 | |||
| 31574 | /* Notice that a change has occured on F that requires its input | ||
| 31575 | method state to be reset. */ | ||
| 31576 | |||
| 31577 | static void | ||
| 31578 | x_reset_conversion (struct frame *f) | ||
| 31579 | { | ||
| 31580 | char *string; | ||
| 31581 | |||
| 31582 | if (FRAME_XIC (f)) | ||
| 31583 | { | ||
| 31584 | string = XmbResetIC (FRAME_XIC (f)); | ||
| 31585 | |||
| 31586 | /* string is actually any string that was being composed at the | ||
| 31587 | time of the reset. */ | ||
| 31588 | |||
| 31589 | if (string) | ||
| 31590 | XFree (string); | ||
| 31591 | } | ||
| 31592 | } | ||
| 31593 | |||
| 31594 | /* Interface used to control input method ``text conversion''. */ | ||
| 31595 | |||
| 31596 | static struct textconv_interface text_conversion_interface = | ||
| 31597 | { | ||
| 31598 | x_reset_conversion, | ||
| 31599 | }; | ||
| 31600 | |||
| 31601 | #endif | ||
| 31602 | |||
| 31569 | void | 31603 | void |
| 31570 | init_xterm (void) | 31604 | init_xterm (void) |
| 31571 | { | 31605 | { |
| @@ -31579,8 +31613,11 @@ init_xterm (void) | |||
| 31579 | gdk_disable_multidevice (); | 31613 | gdk_disable_multidevice (); |
| 31580 | #endif | 31614 | #endif |
| 31581 | #endif | 31615 | #endif |
| 31582 | } | 31616 | |
| 31617 | #ifdef HAVE_X_I18N | ||
| 31618 | register_texconv_interface (&text_conversion_interface); | ||
| 31583 | #endif | 31619 | #endif |
| 31620 | } | ||
| 31584 | 31621 | ||
| 31585 | void | 31622 | void |
| 31586 | mark_xterm (void) | 31623 | mark_xterm (void) |