Delete all menu-enable properties.
[bpt/emacs.git] / src / category.c
CommitLineData
4ed46869
KH
1/* GNU Emacs routines to deal with category tables.
2 Ver.1.0
4ed46869
KH
3 Copyright (C) 1995 Free Software Foundation, Inc.
4 Copyright (C) 1995 Electrotechnical Laboratory, JAPAN.
5
6This file is part of GNU Emacs.
7
8GNU Emacs is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2, or (at your option)
11any later version.
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with GNU Emacs; see the file COPYING. If not, write to
369314dc
KH
20the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21Boston, MA 02111-1307, USA. */
4ed46869
KH
22
23
24/* Here we handle three objects: category, category set, and category
25 table. Read comments in the file category.h to understand them. */
26
27#include <config.h>
28#include <ctype.h>
29#include "lisp.h"
30#include "buffer.h"
31#include "charset.h"
32#include "category.h"
33
34/* The version number of the latest category table. Each category
35 table has a unique version number. It is assigned a new number
36 also when it is modified. When a regular expression is compiled
37 into the struct re_pattern_buffer, the version number of the
38 category table (of the current buffer) at that moment is also
39 embedded in the structure.
40
41 For the moment, we are not using this feature. */
42static int category_table_version;
43
44Lisp_Object Qcategory_table, Qcategoryp, Qcategorysetp, Qcategory_table_p;
45
46/* Variables to determine word boundary. */
47Lisp_Object Vword_combining_categories, Vword_separating_categories;
48
49/* Temporary internal variable used in macro CHAR_HAS_CATEGORY. */
50Lisp_Object _temp_category_set;
51
52\f
53/* Category set staff. */
54
55DEFUN ("make-category-set", Fmake_category_set, Smake_category_set, 1, 1, 0,
56 "Return a newly created category-set which contains CATEGORIES.\n\
57CATEGORIES is a string of category mnemonics.")
58 (categories)
59 Lisp_Object categories;
60{
61 Lisp_Object val;
62 int len;
63
64 CHECK_STRING (categories, 0);
65 val = MAKE_CATEGORY_SET;
66
67 len = XSTRING (categories)->size;
68 while (--len >= 0)
69 {
15c60737 70 Lisp_Object category;
4ed46869 71
15c60737 72 XSETFASTINT (category, XSTRING (categories)->data[len]);
4ed46869
KH
73 CHECK_CATEGORY (category, 0);
74 SET_CATEGORY_SET (val, category, Qt);
75 }
76 return val;
77}
78
79\f
80/* Category staff. */
81
82Lisp_Object check_category_table ();
83
84DEFUN ("define-category", Fdefine_category, Sdefine_category, 2, 3, 0,
85 "Define CHAR as a category which is described by DOCSTRING.\n\
86CHAR should be a visible letter of ` ' thru `~'.\n\
87DOCSTRING is a documentation string of the category.\n\
88The category is defined only in category table TABLE, which defaults to\n\
89 the current buffer's category table.")
90 (category, docstring, table)
91 Lisp_Object category, docstring, table;
92{
93 CHECK_CATEGORY (category, 0);
94 CHECK_STRING (docstring, 1);
95 table = check_category_table (table);
96
97 if (!NILP (CATEGORY_DOCSTRING (table, XFASTINT (category))))
98 error ("Category `%c' is already defined", XFASTINT (category));
99 CATEGORY_DOCSTRING (table, XFASTINT (category)) = docstring;
100
101 return Qnil;
102}
103
104DEFUN ("category-docstring", Fcategory_docstring, Scategory_docstring, 1, 2, 0,
105 "Return a documentation string of CATEGORY.\n\
106Optional second arg specifies CATEGORY-TABLE,\n\
107 which defaults to the current buffer's category table.")
108 (category, table)
109 Lisp_Object category, table;
110{
111 Lisp_Object doc;
112
113 CHECK_CATEGORY (category, 0);
114 table = check_category_table (table);
115
116 return CATEGORY_DOCSTRING (table, XFASTINT (category));
117}
118
119DEFUN ("get-unused-category", Fget_unused_category, Sget_unused_category,
120 0, 1, 0,
121 "Return a category which is not yet defined.\n\
122If total number of categories has reached the limit (95), return nil.\n\
123Optional argument specifies CATEGORY-TABLE,\n\
124 which defaults to the current buffer's category table.")
125 (table)
126 Lisp_Object table;
127{
128 int i;
129 Lisp_Object docstring_vector;
130
131 table = check_category_table (table);
132
133 for (i = ' '; i <= '~'; i++)
134 if (NILP (CATEGORY_DOCSTRING (table, i)))
135 return make_number (i);
136
137 return Qnil;
138}
139
140\f
141/* Category-table staff. */
142
143DEFUN ("category-table-p", Fcategory_table_p, Scategory_table_p, 1, 1, 0,
144 "Return t if ARG is a category table.")
145 (arg)
146 Lisp_Object arg;
147{
148 if (CHAR_TABLE_P (arg)
ed8ec86d 149 && EQ (XCHAR_TABLE (arg)->purpose, Qcategory_table))
4ed46869
KH
150 return Qt;
151 return Qnil;
152}
153
154/* If TABLE is nil, return the current category table. If TABLE is
155 not nil, check the validity of TABLE as a category table. If
156 valid, return TABLE itself, but if not valid, signal an error of
157 wrong-type-argument. */
158
159Lisp_Object
160check_category_table (table)
161 Lisp_Object table;
162{
163 register Lisp_Object tem;
164 if (NILP (table))
165 return current_buffer->category_table;
166 while (tem = Fcategory_table_p (table), NILP (tem))
167 table = wrong_type_argument (Qcategory_table_p, table);
168 return table;
169}
170
171DEFUN ("category-table", Fcategory_table, Scategory_table, 0, 0, 0,
172 "Return the current category table.\n\
173This is the one specified by the current buffer.")
174 ()
175{
176 return current_buffer->category_table;
177}
178
179DEFUN ("standard-category-table", Fstandard_category_table,
180 Sstandard_category_table, 0, 0, 0,
181 "Return the standard category table.\n\
182This is the one used for new buffers.")
183 ()
184{
185 return Vstandard_category_table;
186}
187
188/* Return a copy of category table TABLE. We can't simply use the
189 function copy-sequence because no contents should be shared between
ed8ec86d
KH
190 the original and the copy. This function is called recursively by
191 biding TABLE to a sub char table. */
4ed46869
KH
192
193Lisp_Object
ed8ec86d 194copy_category_table (table)
4ed46869
KH
195 Lisp_Object table;
196{
ed8ec86d
KH
197 Lisp_Object tmp;
198 int i, to;
4ed46869 199
ed8ec86d
KH
200 if (!NILP (XCHAR_TABLE (table)->top))
201 {
202 /* TABLE is a top level char table.
203 At first, make a copy of tree structure of the table. */
204 table = Fcopy_sequence (table);
205
206 /* Then, copy elements for single byte characters one by one. */
207 for (i = 0; i < CHAR_TABLE_SINGLE_BYTE_SLOTS; i++)
208 if (!NILP (tmp = XCHAR_TABLE (table)->contents[i]))
209 XCHAR_TABLE (table)->contents[i] = Fcopy_sequence (tmp);
210 to = CHAR_TABLE_ORDINARY_SLOTS;
211 }
212 else
4ed46869 213 {
ed8ec86d
KH
214 i = 32;
215 to = SUB_CHAR_TABLE_ORDINARY_SLOTS;
4ed46869
KH
216 }
217
ed8ec86d
KH
218 /* If the table has non-nil default value, copy it. */
219 if (!NILP (tmp = XCHAR_TABLE (table)->defalt))
220 XCHAR_TABLE (table)->defalt = Fcopy_sequence (tmp);
221
222 /* At last, copy the remaining elements while paying attention to a
223 sub char table. */
224 for (; i < to; i++)
225 if (!NILP (tmp = XCHAR_TABLE (table)->contents[i]))
226 XCHAR_TABLE (table)->contents[i]
227 = (SUB_CHAR_TABLE_P (tmp)
228 ? copy_category_table (tmp) : Fcopy_sequence (tmp));
229
4ed46869
KH
230 return table;
231}
232
233DEFUN ("copy-category-table", Fcopy_category_table, Scopy_category_table,
234 0, 1, 0,
235 "Construct a new category table and return it.\n\
236It is a copy of the TABLE, which defaults to the standard category table.")
237 (table)
238 Lisp_Object table;
239{
240 if (!NILP (table))
241 check_category_table (table);
242 else
243 table = Vstandard_category_table;
244
245 return copy_category_table (table, 1);
246}
247
248DEFUN ("set-category-table", Fset_category_table, Sset_category_table, 1, 1, 0,
249 "Select a new category table for the current buffer.\n\
250One argument, a category table.")
251 (table)
252 Lisp_Object table;
253{
254 table = check_category_table (table);
255 current_buffer->category_table = table;
256 /* Indicate that this buffer now has a specified category table. */
257 current_buffer->local_var_flags
258 |= XFASTINT (buffer_local_flags.category_table);
259 return table;
260}
261
262\f
263DEFUN ("char-category-set", Fchar_category_set, Schar_category_set, 1, 1, 0,
264 "Return a category set of CHAR.")
265 (ch)
266 Lisp_Object ch;
267{
268 Lisp_Object val;
269 int charset;
270 unsigned char c1, c2;
271
272 CHECK_NUMBER (ch, 0);
273 return CATEGORY_SET (XFASTINT (ch));
274}
275
276DEFUN ("category-set-mnemonics", Fcategory_set_mnemonics,
277 Scategory_set_mnemonics, 1, 1, 0,
278 "Return a string of mnemonics of all categories in CATEGORY-SET.")
279 (category_set)
280 Lisp_Object category_set;
281{
282 int i, j;
283 char str[96];
284
285 CHECK_CATEGORY_SET (category_set, 0);
286
287 j = 0;
288 for (i = 32; i < 127; i++)
289 if (CATEGORY_MEMBER (i, category_set))
290 str[j++] = i;
291 str[j] = '\0';
292
293 return build_string (str);
294}
295
ed8ec86d 296/* Modify all category sets stored under sub char-table TABLE so that
4ed46869
KH
297 they contain (SET_VALUE is t) or don't contain (SET_VALUE is nil)
298 CATEGORY. */
299
300void
301modify_lower_category_set (table, category, set_value)
302 Lisp_Object table, category, set_value;
303{
304 Lisp_Object val;
305 int i;
306
307 if (NILP (XCHAR_TABLE (table)->defalt))
308 {
309 val = MAKE_CATEGORY_SET;
310 SET_CATEGORY_SET (val, category, set_value);
311 XCHAR_TABLE (table)->defalt = val;
312 }
313
ed8ec86d 314 for (i = 32; i < SUB_CHAR_TABLE_ORDINARY_SLOTS; i++)
4ed46869
KH
315 {
316 val = XCHAR_TABLE (table)->contents[i];
317
318 if (CATEGORY_SET_P (val))
319 SET_CATEGORY_SET (val, category, set_value);
ed8ec86d 320 else if (SUB_CHAR_TABLE_P (val))
4ed46869
KH
321 modify_lower_category_set (val, category, set_value);
322 }
323}
324
325void
326set_category_set (category_set, category, val)
327 Lisp_Object category_set, category, val;
328{
329 do {
330 int idx = XINT (category) / 8;
331 unsigned char bits = 1 << (XINT (category) % 8);
332
333 if (NILP (val))
334 XCATEGORY_SET (category_set)->data[idx] &= ~bits;
335 else
336 XCATEGORY_SET (category_set)->data[idx] |= bits;
337 } while (0);
338}
339
340DEFUN ("modify-category-entry", Fmodify_category_entry,
341 Smodify_category_entry, 2, 4, 0,
342 "Modify the category set of CHAR by adding CATEGORY to it.\n\
343The category is changed only for table TABLE, which defaults to\n\
344 the current buffer's category table.\n\
345If optional forth argument RESET is non NIL,\n\
346 CATEGORY is deleted from the category set instead of being added.")
347 (ch, category, table, reset)
348 Lisp_Object ch, category, table, reset;
349{
350 int c, charset, c1, c2;
351 Lisp_Object set_value; /* Actual value to be set in category sets. */
352 Lisp_Object val, category_set;
353
354 CHECK_NUMBER (ch, 0);
355 c = XINT (ch);
356 CHECK_CATEGORY (category, 1);
357 table = check_category_table (table);
358
359 if (NILP (CATEGORY_DOCSTRING (table, XFASTINT (category))))
360 error ("Undefined category: %c", XFASTINT (category));
361
362 set_value = NILP (reset) ? Qt : Qnil;
363
ed8ec86d 364 if (c < CHAR_TABLE_SINGLE_BYTE_SLOTS)
4ed46869
KH
365 {
366 val = XCHAR_TABLE (table)->contents[c];
367 if (!CATEGORY_SET_P (val))
368 XCHAR_TABLE (table)->contents[c] = (val = MAKE_CATEGORY_SET);
369 SET_CATEGORY_SET (val, category, set_value);
370 return Qnil;
371 }
372
4ed46869
KH
373 SPLIT_NON_ASCII_CHAR (c, charset, c1, c2);
374
375 /* The top level table. */
cecda314 376 val = XCHAR_TABLE (table)->contents[charset + 128];
ed8ec86d
KH
377 if (CATEGORY_SET_P (val))
378 category_set = val;
379 else if (!SUB_CHAR_TABLE_P (val))
4ed46869 380 {
ed8ec86d 381 category_set = val = MAKE_CATEGORY_SET;
cecda314 382 XCHAR_TABLE (table)->contents[charset + 128] = category_set;
4ed46869 383 }
4ed46869 384
ed8ec86d 385 if (c1 <= 0)
4ed46869
KH
386 {
387 /* Only a charset is specified. */
ed8ec86d
KH
388 if (SUB_CHAR_TABLE_P (val))
389 /* All characters in CHARSET should be the same as for having
390 CATEGORY or not. */
4ed46869
KH
391 modify_lower_category_set (val, category, set_value);
392 else
393 SET_CATEGORY_SET (category_set, category, set_value);
394 return Qnil;
395 }
396
397 /* The second level table. */
ed8ec86d 398 if (!SUB_CHAR_TABLE_P (val))
4ed46869 399 {
ed8ec86d 400 val = make_sub_char_table (Qnil);
cecda314 401 XCHAR_TABLE (table)->contents[charset + 128] = val;
4ed46869
KH
402 /* We must set default category set of CHARSET in `defalt' slot. */
403 XCHAR_TABLE (val)->defalt = category_set;
404 }
405 table = val;
406
407 val = XCHAR_TABLE (table)->contents[c1];
ed8ec86d
KH
408 if (CATEGORY_SET_P (val))
409 category_set = val;
410 else if (!SUB_CHAR_TABLE_P (val))
4ed46869 411 {
ed8ec86d 412 category_set = val = Fcopy_sequence (XCHAR_TABLE (table)->defalt);
4ed46869
KH
413 XCHAR_TABLE (table)->contents[c1] = category_set;
414 }
4ed46869 415
ed8ec86d 416 if (c2 <= 0)
4ed46869 417 {
ed8ec86d 418 if (SUB_CHAR_TABLE_P (val))
4ed46869
KH
419 /* All characters in C1 group of CHARSET should be the same as
420 for CATEGORY. */
421 modify_lower_category_set (val, category, set_value);
422 else
423 SET_CATEGORY_SET (category_set, category, set_value);
424 return Qnil;
425 }
426
427 /* The third (bottom) level table. */
ed8ec86d 428 if (!SUB_CHAR_TABLE_P (val))
4ed46869 429 {
53740deb 430 val = make_sub_char_table (Qnil);
4ed46869
KH
431 XCHAR_TABLE (table)->contents[c1] = val;
432 /* We must set default category set of CHARSET and C1 in
433 `defalt' slot. */
434 XCHAR_TABLE (val)->defalt = category_set;
435 }
436 table = val;
437
438 val = XCHAR_TABLE (table)->contents[c2];
ed8ec86d
KH
439 if (CATEGORY_SET_P (val))
440 category_set = val;
441 else if (!SUB_CHAR_TABLE_P (val))
4ed46869
KH
442 {
443 category_set = Fcopy_sequence (XCHAR_TABLE (table)->defalt);
444 XCHAR_TABLE (table)->contents[c2] = category_set;
445 }
4ed46869
KH
446 else
447 /* This should never happen. */
448 error ("Invalid category table");
449
450 SET_CATEGORY_SET (category_set, category, set_value);
451
452 return Qnil;
453}
454\f
455/* Dump category table to buffer in human-readable format */
456
457static void
458describe_category (value)
459 Lisp_Object value;
460{
461 Lisp_Object mnemonics;
462
463 Findent_to (make_number (16), make_number (1));
464
465 if (NILP (value))
466 {
467 insert_string ("default\n");
468 return;
469 }
470
471 if (!CATEGORY_SET_P (value))
472 {
473 insert_string ("invalid\n");
474 return;
475 }
476
477 mnemonics = Fcategory_set_mnemonics (value);
478 insert_from_string (mnemonics, 0, XSTRING (mnemonics)->size, 0);
479 insert_string ("\n");
480 return;
481}
482
483static Lisp_Object
484describe_category_1 (vector)
485 Lisp_Object vector;
486{
487 struct buffer *old = current_buffer;
488 set_buffer_internal (XBUFFER (Vstandard_output));
489 describe_vector (vector, Qnil, describe_category, 0, Qnil, Qnil);
490 {
491 int i;
492 Lisp_Object docs = XCHAR_TABLE (vector)->extras[0];
493 Lisp_Object elt;
494
495 if (!VECTORP (docs) || XVECTOR (docs)->size != 95)
496 {
497 insert_string ("Invalid first extra slot in this char table\n");
498 return Qnil;
499 }
500
501 insert_string ("Meanings of mnemonice characters are:\n");
502 for (i = 0; i < 95; i++)
503 {
504 elt = XVECTOR (docs)->contents[i];
505 if (NILP (elt))
506 continue;
507
508 insert_char (i + 32);
509 insert (": ", 2);
510 insert_from_string (elt, 0, XSTRING (elt)->size, 0);
511 insert ("\n", 1);
512 }
513 }
514
515 while (! NILP (XCHAR_TABLE (vector)->parent))
516 {
517 vector = XCHAR_TABLE (vector)->parent;
518 insert_string ("\nThe parent category table is:");
519 describe_vector (vector, Qnil, describe_category, 0, Qnil, Qnil);
520 }
521
522 call0 (intern ("help-mode"));
523 set_buffer_internal (old);
524 return Qnil;
525}
526
527DEFUN ("describe-category", Fdescribe_category, Sdescribe_category, 0, 0, "",
528 "Describe the category specifications in the category table.\n\
529The descriptions are inserted in a buffer, which is then displayed.")
530 ()
531{
532 internal_with_output_to_temp_buffer
533 ("*Help*", describe_category_1, current_buffer->category_table);
534
535 return Qnil;
536}
537\f
538/* Return 1 if there is a word boundary between two word-constituent
539 characters C1 and C2 if they appear in this order, else return 0.
540 Use the macro WORD_BOUNDARY_P instead of calling this function
541 directly. */
542
543int
544word_boundary_p (c1, c2)
545 int c1, c2;
546{
547 Lisp_Object category_set1, category_set2;
548 Lisp_Object tail;
549 int default_result;
550
551 if (CHAR_CHARSET (c1) == CHAR_CHARSET (c2))
552 {
553 tail = Vword_separating_categories;
554 default_result = 0;
555 }
556 else
557 {
558 tail = Vword_combining_categories;
559 default_result = 1;
560 }
561
562 category_set1 = CATEGORY_SET (c1);
563 if (NILP (category_set1))
564 return default_result;
565 category_set2 = CATEGORY_SET (c2);
566 if (NILP (category_set2))
567 return default_result;
568
569 for (; CONSP (tail); tail = XCONS (tail)->cdr)
570 {
571 Lisp_Object elt = XCONS(tail)->car;
572
573 if (CONSP (elt)
574 && CATEGORYP (XCONS (elt)->car)
575 && CATEGORYP (XCONS (elt)->cdr)
576 && CATEGORY_MEMBER (XCONS (elt)->car, category_set1)
577 && CATEGORY_MEMBER (XCONS (elt)->cdr, category_set2))
578 return !default_result;
579 }
580 return default_result;
581}
582
583\f
584init_category_once ()
585{
586 /* This has to be done here, before we call Fmake_char_table. */
587 Qcategory_table = intern ("category-table");
588 staticpro (&Qcategory_table);
589
590 /* Intern this now in case it isn't already done.
591 Setting this variable twice is harmless.
592 But don't staticpro it here--that is done in alloc.c. */
593 Qchar_table_extra_slots = intern ("char-table-extra-slots");
594
595 /* Now we are ready to set up this property, so we can
596 create category tables. */
597 Fput (Qcategory_table, Qchar_table_extra_slots, make_number (2));
598
599 Vstandard_category_table = Fmake_char_table (Qcategory_table, Qnil);
600 /* Set a category set which contains nothing to the default. */
601 XCHAR_TABLE (Vstandard_category_table)->defalt = MAKE_CATEGORY_SET;
602 Fset_char_table_extra_slot (Vstandard_category_table, 0,
603 Fmake_vector (make_number (95), Qnil));
604}
605
606syms_of_category ()
607{
608 Qcategoryp = intern ("categoryp");
609 staticpro (&Qcategoryp);
610 Qcategorysetp = intern ("categorysetp");
611 staticpro (&Qcategorysetp);
612 Qcategory_table_p = intern ("category-table-p");
613 staticpro (&Qcategory_table_p);
614
615 DEFVAR_LISP ("word-combining-categories", &Vword_combining_categories,
616 "List of pair (cons) of categories to determine word boundary.\n\
617\n\
618Emacs treats a sequence of word constituent characters as a single\n\
619word (i.e. finds no word boundary between them) iff they belongs to\n\
620the same charset. But, exceptions are allowed in the following cases.\n\
621\n\
622(1) The case that characters are in different charsets is controlled\n\
623by the variable `word-combining-categories'.\n\
624\n\
625Emacs finds no word boundary between characters of different charsets\n\
626if they have categories matching some element of this list.\n\
627\n\
628More precisely, if an element of this list is a cons of category CAT1\n\
629and CAT2, and a multibyte character C1 which has CAT1 is followed by\n\
630C2 which has CAT2, there's no word boundary between C1 and C2.\n\
631\n\
632For instance, to tell that ASCII characters and Latin-1 characters can\n\
633form a single word, the element `(?l . ?l)' should be in this list\n\
634because both characters have the category `l' (Latin characters).\n\
635\n\
636(2) The case that character are in the same charset is controlled by\n\
637the variable `word-separating-categories'.\n\
638\n\
639Emacs find a word boundary between characters of the same charset\n\
640if they have categories matching some element of this list.\n\
641\n\
642More precisely, if an element of this list is a cons of category CAT1\n\
643and CAT2, and a multibyte character C1 which has CAT1 is followed by\n\
644C2 which has CAT2, there's a word boundary between C1 and C2.\n\
645\n\
646For instance, to tell that there's a word boundary between Japanese\n\
647Hiragana and Japanese Kanji (both are in the same charset), the\n\
648element `(?H . ?C) should be in this list.");
649
650 Vword_combining_categories = Qnil;
651
652 DEFVAR_LISP ("word-separating-categories", &Vword_separating_categories,
653 "List of pair (cons) of categories to determine word boundary.\n\
654See the documentation of the variable `word-combining-categories'.");
655
656 Vword_separating_categories = Qnil;
657
658 defsubr (&Smake_category_set);
659 defsubr (&Sdefine_category);
660 defsubr (&Scategory_docstring);
661 defsubr (&Sget_unused_category);
662 defsubr (&Scategory_table_p);
663 defsubr (&Scategory_table);
664 defsubr (&Sstandard_category_table);
665 defsubr (&Scopy_category_table);
666 defsubr (&Sset_category_table);
667 defsubr (&Schar_category_set);
668 defsubr (&Scategory_set_mnemonics);
669 defsubr (&Smodify_category_entry);
670 defsubr (&Sdescribe_category);
671
672 category_table_version = 0;
673}