1 |
/* Composite sequence support. |
/* Composite sequence support. |
2 |
Copyright (C) 1999 Electrotechnical Laboratory, JAPAN. |
Copyright (C) 1999 Electrotechnical Laboratory, JAPAN. |
3 |
Licensed to the Free Software Foundation. |
Licensed to the Free Software Foundation. |
4 |
Copyright (C) 2001 Free Software Foundation, Inc. |
Copyright (C) 2001 Free Software Foundation, Inc. |
5 |
|
Copyright (C) 2003 |
6 |
|
National Institute of Advanced Industrial Science and Technology (AIST) |
7 |
|
Registration Number H13PRO009 |
8 |
|
|
9 |
This file is part of GNU Emacs. |
This file is part of GNU Emacs. |
10 |
|
|
26 |
#include <config.h> |
#include <config.h> |
27 |
#include "lisp.h" |
#include "lisp.h" |
28 |
#include "buffer.h" |
#include "buffer.h" |
29 |
#include "charset.h" |
#include "character.h" |
30 |
#include "intervals.h" |
#include "intervals.h" |
31 |
|
|
32 |
/* Emacs uses special text property `composition' to support character |
/* Emacs uses special text property `composition' to support character |
148 |
/* Function to call to adjust composition. */ |
/* Function to call to adjust composition. */ |
149 |
Lisp_Object Vcompose_chars_after_function; |
Lisp_Object Vcompose_chars_after_function; |
150 |
|
|
151 |
/* Char-table of patterns and functions to make a composition. */ |
Lisp_Object Qauto_composed; |
152 |
Lisp_Object Vcomposition_function_table; |
Lisp_Object Vauto_composition_function; |
153 |
Lisp_Object Qcomposition_function_table; |
Lisp_Object Qauto_composition_function; |
154 |
|
|
155 |
/* Temporary variable used in macros COMPOSITION_XXX. */ |
/* Temporary variable used in macros COMPOSITION_XXX. */ |
156 |
Lisp_Object composition_temp; |
Lisp_Object composition_temp; |
157 |
|
|
|
/* Return how many columns C will occupy on the screen. It always |
|
|
returns 1 for control characters and 8-bit characters because those |
|
|
are just ignored in a composition. */ |
|
|
#define CHAR_WIDTH(c) \ |
|
|
(SINGLE_BYTE_CHAR_P (c) ? 1 : CHARSET_WIDTH (CHAR_CHARSET (c))) |
|
|
|
|
158 |
/* Return COMPOSITION-ID of a composition at buffer position |
/* Return COMPOSITION-ID of a composition at buffer position |
159 |
CHARPOS/BYTEPOS and length NCHARS. The `composition' property of |
CHARPOS/BYTEPOS and length NCHARS. The `composition' property of |
160 |
the sequence is PROP. STRING, if non-nil, is a string that |
the sequence is PROP. STRING, if non-nil, is a string that |
461 |
to = end; |
to = end; |
462 |
if (!NILP (Ffboundp (func))) |
if (!NILP (Ffboundp (func))) |
463 |
call2 (func, make_number (from), make_number (to)); |
call2 (func, make_number (from), make_number (to)); |
|
else if (!NILP (Ffboundp (Vcompose_chars_after_function))) |
|
|
call3 (Vcompose_chars_after_function, |
|
|
make_number (from), make_number (to), Qnil); |
|
464 |
} |
} |
465 |
|
|
466 |
/* Make invalid compositions adjacent to or inside FROM and TO valid. |
/* Make invalid compositions adjacent to or inside FROM and TO valid. |
467 |
CHECK_MASK is bitwise `or' of mask bits defined by macros |
CHECK_MASK is bitwise `or' of mask bits defined by macros |
468 |
CHECK_XXX (see the comment in composite.h). |
CHECK_XXX (see the comment in composite.h). |
469 |
|
|
470 |
|
It also resets the text-property `auto-composed' to a proper region |
471 |
|
so that automatic character composition works correctly later while |
472 |
|
displaying the region. |
473 |
|
|
474 |
This function is called when a buffer text is changed. If the |
This function is called when a buffer text is changed. If the |
475 |
change is deletion, FROM == TO. Otherwise, FROM < TO. */ |
change is deletion, FROM == TO. Otherwise, FROM < TO. */ |
476 |
|
|
480 |
{ |
{ |
481 |
Lisp_Object prop; |
Lisp_Object prop; |
482 |
int start, end; |
int start, end; |
483 |
|
/* The beginning and end of the region to set the property |
484 |
|
`auto-composed' to nil. */ |
485 |
|
int min_pos = from, max_pos = to; |
486 |
|
|
487 |
if (inhibit_modification_hooks) |
if (inhibit_modification_hooks) |
488 |
return; |
return; |
501 |
if (from > BEGV |
if (from > BEGV |
502 |
&& find_composition (from - 1, -1, &start, &end, &prop, Qnil)) |
&& find_composition (from - 1, -1, &start, &end, &prop, Qnil)) |
503 |
{ |
{ |
504 |
|
min_pos = start; |
505 |
|
if (end > to) |
506 |
|
max_pos = end; |
507 |
if (from < end) |
if (from < end) |
508 |
Fput_text_property (make_number (from), make_number (end), |
Fput_text_property (make_number (from), make_number (end), |
509 |
Qcomposition, |
Qcomposition, |
513 |
} |
} |
514 |
else if (from < ZV |
else if (from < ZV |
515 |
&& find_composition (from, -1, &start, &from, &prop, Qnil)) |
&& find_composition (from, -1, &start, &from, &prop, Qnil)) |
516 |
run_composition_function (start, from, prop); |
{ |
517 |
|
if (from > to) |
518 |
|
max_pos = from; |
519 |
|
run_composition_function (start, from, prop); |
520 |
|
} |
521 |
} |
} |
522 |
|
|
523 |
if (check_mask & CHECK_INSIDE) |
if (check_mask & CHECK_INSIDE) |
542 |
To avoid it, in such a case, we change the property of |
To avoid it, in such a case, we change the property of |
543 |
the former to the copy of it. */ |
the former to the copy of it. */ |
544 |
if (to < end) |
if (to < end) |
545 |
Fput_text_property (make_number (start), make_number (to), |
{ |
546 |
Qcomposition, |
Fput_text_property (make_number (start), make_number (to), |
547 |
Fcons (XCAR (prop), XCDR (prop)), Qnil); |
Qcomposition, |
548 |
|
Fcons (XCAR (prop), XCDR (prop)), Qnil); |
549 |
|
max_pos = end; |
550 |
|
} |
551 |
run_composition_function (start, end, prop); |
run_composition_function (start, end, prop); |
552 |
} |
} |
553 |
else if (to < ZV |
else if (to < ZV |
554 |
&& find_composition (to, -1, &start, &end, &prop, Qnil)) |
&& find_composition (to, -1, &start, &end, &prop, Qnil)) |
555 |
run_composition_function (start, end, prop); |
{ |
556 |
|
run_composition_function (start, end, prop); |
557 |
|
max_pos = end; |
558 |
|
} |
559 |
} |
} |
560 |
|
if (min_pos < max_pos) |
561 |
|
Fremove_list_of_text_properties (make_number (min_pos), |
562 |
|
make_number (max_pos), |
563 |
|
Fcons (Qauto_composed, Qnil), Qnil); |
564 |
} |
} |
565 |
|
|
566 |
|
|
606 |
Fput_text_property (make_number (start), make_number (end), |
Fput_text_property (make_number (start), make_number (end), |
607 |
Qcomposition, prop, string); |
Qcomposition, prop, string); |
608 |
} |
} |
|
|
|
|
/* Compose sequences of characters in the region between START and END |
|
|
by functions registered in Vcomposition_function_table. If STRING |
|
|
is non-nil, operate on characters contained between indices START |
|
|
and END in STRING. */ |
|
|
|
|
|
void |
|
|
compose_chars_in_text (start, end, string) |
|
|
int start, end; |
|
|
Lisp_Object string; |
|
|
{ |
|
|
int count = 0; |
|
|
struct gcpro gcpro1; |
|
|
Lisp_Object tail, elt, val, to; |
|
|
/* Set to nonzero if we don't have to compose ASCII characters. */ |
|
|
int skip_ascii; |
|
|
int i, len, stop, c; |
|
|
const unsigned char *ptr, *pend; |
|
|
|
|
|
if (! CHAR_TABLE_P (Vcomposition_function_table)) |
|
|
return; |
|
|
|
|
|
if (STRINGP (string)) |
|
|
{ |
|
|
count = SPECPDL_INDEX (); |
|
|
GCPRO1 (string); |
|
|
stop = end; |
|
|
ptr = SDATA (string) + string_char_to_byte (string, start); |
|
|
pend = ptr + SBYTES (string); |
|
|
} |
|
|
else |
|
|
{ |
|
|
record_unwind_protect (save_excursion_restore, save_excursion_save ()); |
|
|
TEMP_SET_PT (start); |
|
|
stop = (start < GPT && GPT < end ? GPT : end); |
|
|
ptr = CHAR_POS_ADDR (start); |
|
|
pend = CHAR_POS_ADDR (end); |
|
|
} |
|
|
|
|
|
/* Preserve the match data. */ |
|
|
record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil)); |
|
|
|
|
|
/* If none of ASCII characters have composition functions, we can |
|
|
skip them quickly. */ |
|
|
for (i = 0; i < 128; i++) |
|
|
if (!NILP (CHAR_TABLE_REF (Vcomposition_function_table, i))) |
|
|
break; |
|
|
skip_ascii = (i == 128); |
|
|
|
|
|
|
|
|
while (1) |
|
|
{ |
|
|
if (skip_ascii) |
|
|
while (start < stop && ASCII_BYTE_P (*ptr)) |
|
|
start++, ptr++; |
|
|
|
|
|
if (start >= stop) |
|
|
{ |
|
|
if (stop == end || start >= end) |
|
|
break; |
|
|
stop = end; |
|
|
if (STRINGP (string)) |
|
|
ptr = SDATA (string) + string_char_to_byte (string, start); |
|
|
else |
|
|
ptr = CHAR_POS_ADDR (start); |
|
|
} |
|
|
|
|
|
c = STRING_CHAR_AND_LENGTH (ptr, pend - ptr, len); |
|
|
tail = CHAR_TABLE_REF (Vcomposition_function_table, c); |
|
|
while (CONSP (tail)) |
|
|
{ |
|
|
elt = XCAR (tail); |
|
|
if (CONSP (elt) |
|
|
&& STRINGP (XCAR (elt)) |
|
|
&& !NILP (Ffboundp (XCDR (elt)))) |
|
|
{ |
|
|
if (STRINGP (string)) |
|
|
val = Fstring_match (XCAR (elt), string, make_number (start)); |
|
|
else |
|
|
{ |
|
|
val = Flooking_at (XCAR (elt)); |
|
|
if (!NILP (val)) |
|
|
val = make_number (start); |
|
|
} |
|
|
if (INTEGERP (val) && XFASTINT (val) == start) |
|
|
{ |
|
|
to = Fmatch_end (make_number (0)); |
|
|
val = call4 (XCDR (elt), val, to, XCAR (elt), string); |
|
|
if (INTEGERP (val) && XINT (val) > 1) |
|
|
{ |
|
|
start += XINT (val); |
|
|
if (STRINGP (string)) |
|
|
ptr = SDATA (string) + string_char_to_byte (string, start); |
|
|
else |
|
|
ptr = CHAR_POS_ADDR (start); |
|
|
} |
|
|
else |
|
|
{ |
|
|
start++; |
|
|
ptr += len; |
|
|
} |
|
|
break; |
|
|
} |
|
|
} |
|
|
tail = XCDR (tail); |
|
|
} |
|
|
if (!CONSP (tail)) |
|
|
{ |
|
|
/* No composition done. Try the next character. */ |
|
|
start++; |
|
|
ptr += len; |
|
|
} |
|
|
} |
|
|
|
|
|
unbind_to (count, Qnil); |
|
|
if (STRINGP (string)) |
|
|
UNGCPRO; |
|
|
} |
|
609 |
|
|
610 |
/* Emacs Lisp APIs. */ |
/* Emacs Lisp APIs. */ |
611 |
|
|
768 |
The default value is the function `compose-chars-after'. */); |
The default value is the function `compose-chars-after'. */); |
769 |
Vcompose_chars_after_function = intern ("compose-chars-after"); |
Vcompose_chars_after_function = intern ("compose-chars-after"); |
770 |
|
|
771 |
Qcomposition_function_table = intern ("composition-function-table"); |
Qauto_composed = intern ("auto-composed"); |
772 |
staticpro (&Qcomposition_function_table); |
staticpro (&Qauto_composed); |
773 |
|
|
774 |
|
Qauto_composition_function = intern ("auto-composition-function"); |
775 |
|
staticpro (&Qauto_composition_function); |
776 |
|
|
777 |
/* Intern this now in case it isn't already done. |
DEFVAR_LISP ("auto-composition-function", &Vauto_composition_function, |
778 |
Setting this variable twice is harmless. |
doc: /* Function to call to compose characters automatically. |
779 |
But don't staticpro it here--that is done in alloc.c. */ |
The function is called from the display routine with two arguments, |
780 |
Qchar_table_extra_slots = intern ("char-table-extra-slots"); |
POS and STRING. |
781 |
|
|
782 |
Fput (Qcomposition_function_table, Qchar_table_extra_slots, make_number (0)); |
If STRING is nil, the function must compose characters following POS |
783 |
|
in the current buffer. |
784 |
DEFVAR_LISP ("composition-function-table", &Vcomposition_function_table, |
|
785 |
doc: /* Char table of patterns and functions to make a composition. |
Otherwise, STRING is a string, and POS is an index to the string. In |
786 |
|
this case, the function must compose characters following POS in |
787 |
Each element is nil or an alist of PATTERNs vs FUNCs, where PATTERNs |
the string. */); |
788 |
are regular expressions and FUNCs are functions. FUNC is responsible |
Vauto_composition_function = Qnil; |
|
for composing text matching the corresponding PATTERN. FUNC is called |
|
|
with three arguments FROM, TO, and PATTERN. See the function |
|
|
`compose-chars-after' for more detail. |
|
|
|
|
|
This table is looked up by the first character of a composition when |
|
|
the composition gets invalid after a change in a buffer. */); |
|
|
Vcomposition_function_table |
|
|
= Fmake_char_table (Qcomposition_function_table, Qnil); |
|
789 |
|
|
790 |
defsubr (&Scompose_region_internal); |
defsubr (&Scompose_region_internal); |
791 |
defsubr (&Scompose_string_internal); |
defsubr (&Scompose_string_internal); |