/* Composite sequence support.
- Copyright (C) 1999 Electrotechnical Laboratory, JAPAN.
- Licensed to the Free Software Foundation.
+ Copyright (C) 2001, 2002, 2003, 2004, 2005,
+ 2006 Free Software Foundation, Inc.
+ Copyright (C) 1999
+ National Institute of Advanced Industrial Science and Technology (AIST)
+ Registration Number H14PRO021
This file is part of GNU Emacs.
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#include <config.h>
#include "lisp.h"
The former is a hash table in which keys are COMPONENTS-VECs and
values are the corresponding COMPOSITION-IDs. This hash table is
- weak, but as each key (COMPONENTS-VEC) is also kept as a value of
+ weak, but as each key (COMPONENTS-VEC) is also kept as a value of the
`composition' property, it won't be collected as garbage until all
- text that have the same COMPONENTS-VEC are deleted.
+ bits of text that have the same COMPONENTS-VEC are deleted.
The latter is a table of pointers to `struct composition' indexed
- by COMPOSITION-ID. This structure keep the other information (see
+ by COMPOSITION-ID. This structure keeps the other information (see
composite.h).
In general, a text property holds information about individual
characters. But, a `composition' property holds information about
- a sequence of characters (in this sense, it is like `intangible'
+ a sequence of characters (in this sense, it is like the `intangible'
property). That means that we should not share the property value
- in adjacent compositions we can't distinguish them if they have the
+ in adjacent compositions -- we can't distinguish them if they have the
same property. So, after any changes, we call
`update_compositions' and change a property of one of adjacent
compositions to a copy of it. This function also runs a proper
composition modification function to make a composition that gets
invalid by the change valid again.
- As a value of `composition' property holds information about a
+ As the value of the `composition' property holds information about a
specific range of text, the value gets invalid if we change the
- text in the range. We treat `composition' property always
+ text in the range. We treat the `composition' property as always
rear-nonsticky (currently by setting default-text-properties to
(rear-nonsticky (composition))) and we never make properties of
adjacent compositions identical. Thus, any such changes make the
- range just shorter. So, we can check the validity of `composition'
+ range just shorter. So, we can check the validity of the `composition'
property by comparing LENGTH information with the actual length of
the composition.
/* Function to call to adjust composition. */
Lisp_Object Vcompose_chars_after_function;
+/* Char-table of patterns and functions to make a composition. */
+Lisp_Object Vcomposition_function_table;
+Lisp_Object Qcomposition_function_table;
+
/* Temporary variable used in macros COMPOSITION_XXX. */
Lisp_Object composition_temp;
\f
#define CHAR_WIDTH(c) \
(SINGLE_BYTE_CHAR_P (c) ? 1 : CHARSET_WIDTH (CHAR_CHARSET (c)))
-/* The following macros for hash table are copied from fns.c. */
-/* Return the contents of vector V at index IDX. */
-#define AREF(V, IDX) XVECTOR (V)->contents[IDX]
-/* Value is the key part of entry IDX in hash table H. */
-#define HASH_KEY(H, IDX) AREF ((H)->key_and_value, 2 * (IDX))
-/* Value is the value part of entry IDX in hash table H. */
-#define HASH_VALUE(H, IDX) AREF ((H)->key_and_value, 2 * (IDX) + 1)
-
/* Return COMPOSITION-ID of a composition at buffer position
CHARPOS/BYTEPOS and length NCHARS. The `composition' property of
the sequence is PROP. STRING, if non-nil, is a string that
modify the cons cell of PROP because it is not shared. */
key = HASH_KEY (hash_table, hash_index);
id = HASH_VALUE (hash_table, hash_index);
- XCAR (prop) = id;
- XCDR (prop) = Fcons (make_number (nchars), Fcons (key, XCDR (prop)));
+ XSETCAR (prop, id);
+ XSETCDR (prop, Fcons (make_number (nchars), Fcons (key, XCDR (prop))));
return XINT (id);
}
/* This composition is a new one. We must register it. */
-
+
/* Check if we have sufficient memory to store this information. */
if (composition_table_size == 0)
{
/* Change PROP from Form-A above to Form-B. We can directly modify
the cons cell of PROP because it is not shared. */
XSETFASTINT (id, n_compositions);
- XCAR (prop) = id;
- XCDR (prop) = Fcons (make_number (nchars), Fcons (key, XCDR (prop)));
+ XSETCAR (prop, id);
+ XSETCDR (prop, Fcons (make_number (nchars), Fcons (key, XCDR (prop))));
/* Register the composition in composition_hash_table. */
hash_index = hash_put (hash_table, key, id, hash_code);
return 0;
if (limit > pos) /* search forward */
- val = Fnext_single_property_change (make_number (pos), Qcomposition,
- object, make_number (limit));
+ {
+ val = Fnext_single_property_change (make_number (pos), Qcomposition,
+ object, make_number (limit));
+ pos = XINT (val);
+ if (pos == limit)
+ return 0;
+ }
else /* search backward */
- val = Fprevious_single_property_change (make_number (pos), Qcomposition,
- object, make_number (limit));
- pos = XINT (val);
- if (pos == limit)
- return 0;
+ {
+ if (get_property_and_range (pos - 1, Qcomposition, prop, start, end,
+ object))
+ return 1;
+ val = Fprevious_single_property_change (make_number (pos), Qcomposition,
+ object, make_number (limit));
+ pos = XINT (val);
+ if (pos == limit)
+ return 0;
+ pos--;
+ }
get_property_and_range (pos, Qcomposition, prop, start, end, object);
return 1;
}
int from, to;
Lisp_Object prop;
{
- Lisp_Object func, val;
+ Lisp_Object func;
int start, end;
func = COMPOSITION_MODIFICATION_FUNC (prop);
&& find_composition (to, -1, &start, &end, &prop, Qnil)
&& !COMPOSITION_VALID_P (start, end, prop))
to = end;
- if (!NILP (func))
+ if (!NILP (Ffboundp (func)))
call2 (func, make_number (from), make_number (to));
else if (!NILP (Ffboundp (Vcompose_chars_after_function)))
- call2 (Vcompose_chars_after_function,
- make_number (from), make_number (to));
+ call3 (Vcompose_chars_after_function,
+ make_number (from), make_number (to), Qnil);
}
/* Make invalid compositions adjacent to or inside FROM and TO valid.
void
update_compositions (from, to, check_mask)
- int from, to;
+ int from, to, check_mask;
{
- Lisp_Object prop, hook;
+ Lisp_Object prop;
int start, end;
+ if (inhibit_modification_hooks)
+ return;
+
/* If FROM and TO are not in a valid range, do nothing. */
if (! (BEGV <= from && from <= to && to <= ZV))
return;
run_composition_function (start, end, prop);
from = end;
}
- else if (from < end
+ else if (from < ZV
&& find_composition (from, -1, &start, &from, &prop, Qnil))
run_composition_function (start, from, prop);
}
{
if (EQ (XCAR (plist), Qcomposition)
&& (val = XCAR (XCDR (plist)), CONSP (val)))
- XCAR (XCDR (plist)) = Fcons (XCAR (val), XCDR (val));
+ XSETCAR (XCDR (plist), Fcons (XCAR (val), XCDR (val)));
plist = XCDR (XCDR (plist));
}
}
DEFUN ("compose-region-internal", Fcompose_region_internal,
Scompose_region_internal, 2, 4, 0,
- "Internal use only.\n\
-\n\
-Compose text in the region between START and END.\n\
-Optional 3rd and 4th arguments are COMPONENTS and MODIFICATION-FUNC\n\
-for the composition. See `compose-region' for more detial.")
- (start, end, components, mod_func)
- Lisp_Object start, end, components, mod_func;
+ doc: /* Internal use only.
+
+Compose text in the region between START and END.
+Optional 3rd and 4th arguments are COMPONENTS and MODIFICATION-FUNC
+for the composition. See `compose-region' for more detail. */)
+ (start, end, components, modification_func)
+ Lisp_Object start, end, components, modification_func;
{
validate_region (&start, &end);
if (!NILP (components)
&& !INTEGERP (components)
&& !CONSP (components)
&& !STRINGP (components))
- CHECK_VECTOR (components, 2);
+ CHECK_VECTOR (components);
- compose_text (XINT (start), XINT (end), components, mod_func, Qnil);
+ compose_text (XINT (start), XINT (end), components, modification_func, Qnil);
return Qnil;
}
DEFUN ("compose-string-internal", Fcompose_string_internal,
Scompose_string_internal, 3, 5, 0,
- "Internal use only.\n\
-\n\
-Compose text between indices START and END of STRING.\n\
-Optional 4th and 5th arguments are COMPONENTS and MODIFICATION-FUNC\n\
-for the composition. See `compose-string' for more detial.")
- (string, start, end, components, mod_func)
- Lisp_Object string, start, end, components, mod_func;
+ doc: /* Internal use only.
+
+Compose text between indices START and END of STRING.
+Optional 4th and 5th arguments are COMPONENTS and MODIFICATION-FUNC
+for the composition. See `compose-string' for more detail. */)
+ (string, start, end, components, modification_func)
+ Lisp_Object string, start, end, components, modification_func;
{
- CHECK_STRING (string, 0);
- CHECK_NUMBER (start, 1);
- CHECK_NUMBER (end, 2);
+ CHECK_STRING (string);
+ CHECK_NUMBER (start);
+ CHECK_NUMBER (end);
if (XINT (start) < 0 ||
XINT (start) > XINT (end)
- || XINT (end) > XSTRING (string)->size)
+ || XINT (end) > SCHARS (string))
args_out_of_range (start, end);
- compose_text (XINT (start), XINT (end), components, mod_func, string);
+ compose_text (XINT (start), XINT (end), components, modification_func, string);
return string;
}
DEFUN ("find-composition-internal", Ffind_composition_internal,
- Sfind_composition_internal, 4, 4, 0,
- "Internal use only.\n\
-\n\
-Return information about composition at or nearest to position POS.\n\
-See `find-composition' for more detail.")
- (pos, limit, string, detail_p)
+ Sfind_composition_internal, 4, 4, 0,
+ doc: /* Internal use only.
+
+Return information about composition at or nearest to position POS.
+See `find-composition' for more detail. */)
+ (pos, limit, string, detail_p)
Lisp_Object pos, limit, string, detail_p;
{
Lisp_Object prop, tail;
int start, end;
int id;
- CHECK_NUMBER_COERCE_MARKER (pos, 0);
+ CHECK_NUMBER_COERCE_MARKER (pos);
start = XINT (pos);
if (!NILP (limit))
{
- CHECK_NUMBER_COERCE_MARKER (limit, 1);
+ CHECK_NUMBER_COERCE_MARKER (limit);
end = XINT (limit);
}
else
end = -1;
+
if (!NILP (string))
- CHECK_STRING (string, 2);
+ {
+ CHECK_STRING (string);
+ if (XINT (pos) < 0 || XINT (pos) > SCHARS (string))
+ args_out_of_range (string, pos);
+ }
+ else
+ {
+ if (XINT (pos) < BEGV || XINT (pos) > ZV)
+ args_out_of_range (Fcurrent_buffer (), pos);
+ }
if (!find_composition (start, end, &start, &end, &prop, string))
return Qnil;
{
Lisp_Object args[6];
extern Lisp_Object QCsize;
-
+
args[0] = QCtest;
args[1] = Qequal;
+ /* We used to make the hash table weak so that unreferenced
+ compostions can be garbage-collected. But, usually once
+ created compositions are repeatedly used in an Emacs session,
+ and thus it's not worth to save memory in such a way. So, we
+ make the table not weak. */
args[2] = QCweakness;
args[3] = Qnil;
args[4] = QCsize;
= Fcons (Fcons (Qcomposition, Qt), Vtext_property_default_nonsticky);
DEFVAR_LISP ("compose-chars-after-function", &Vcompose_chars_after_function,
- "Function to adjust composition of buffer text.\n\
-\n\
-This function is called after a text with `composition' property is\n\
-inserted or deleted to keep `composition' property of buffer text\n\
-valid.\n\
-\n\
-The function is called with two arguments FROM and TO. They specify\n\
-the range of text of which composition should be adjusted.\n\
-\n\
-The default value is the function `compose-chars-after'.");
+ doc: /* Function to adjust composition of buffer text.
+
+The function is called with three arguments FROM, TO, and OBJECT.
+FROM and TO specify the range of text of which composition should be
+adjusted. OBJECT, if non-nil, is a string that contains the text.
+
+This function is called after a text with `composition' property is
+inserted or deleted to keep `composition' property of buffer text
+valid.
+
+The default value is the function `compose-chars-after'. */);
Vcompose_chars_after_function = intern ("compose-chars-after");
+ Qcomposition_function_table = intern ("composition-function-table");
+ staticpro (&Qcomposition_function_table);
+
+ /* Intern this now in case it isn't already done.
+ Setting this variable twice is harmless.
+ But don't staticpro it here--that is done in alloc.c. */
+ Qchar_table_extra_slots = intern ("char-table-extra-slots");
+
+ Fput (Qcomposition_function_table, Qchar_table_extra_slots, make_number (0));
+
+ DEFVAR_LISP ("composition-function-table", &Vcomposition_function_table,
+ doc: /* Char table of patterns and functions to make a composition.
+
+Each element is nil or an alist of PATTERNs vs FUNCs, where PATTERNs
+are regular expressions and FUNCs are functions. FUNC is responsible
+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);
+
defsubr (&Scompose_region_internal);
defsubr (&Scompose_string_internal);
defsubr (&Sfind_composition_internal);
}
+
+/* arch-tag: 79cefaf8-ca48-4eed-97e5-d5afb290d272
+ (do not change this comment) */