From 9510e8ad68271f58b4813478703a4b8eb1ba597b Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sun, 12 Feb 2023 19:56:11 +0800 Subject: [PATCH] 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. --- src/textconv.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++++ src/textconv.h | 109 +++++++++++++++++ 2 files changed, 421 insertions(+) create mode 100644 src/textconv.c create mode 100644 src/textconv.h 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_ */ -- 2.39.2