diff options
| author | Paul Eggert | 2015-08-14 15:50:35 -0700 |
|---|---|---|
| committer | Paul Eggert | 2015-08-14 15:55:57 -0700 |
| commit | 244c801689d2f7a80480d83cd7d092d4762ebe08 (patch) | |
| tree | 6a07abc8b26966002de304b3546f3ccbebb2c865 /src | |
| parent | 293775f10555f7da7e61ed8dbdb78d72f30f7e2d (diff) | |
| download | emacs-244c801689d2f7a80480d83cd7d092d4762ebe08.tar.gz emacs-244c801689d2f7a80480d83cd7d092d4762ebe08.zip | |
Extend ‘format’ to translate curved quotes
This is a followup to the recent doc string change, and deals with
diagnostics and the like. This patch is more conservative than
the doc string change, in that the behavior of ‘format’ changes
only if its first arg contains curved quotes and the user prefers
straight or grave quotes. (Come to think of it, perhaps we should
be similarly conservative with doc strings too, but that can wait.)
The upside of this conservatism is that existing usage is almost
surely unaffected. The downside is that we'll eventually have to
change Emacs's format strings to use curved quotes in places where
the user might want curved quotes, but that's a simple and
mechanical translation that I'm willing to do later. (Bug#21222)
* doc/lispref/help.texi (Keys in Documentation):
Move description of text-quoting-style from here ...
* doc/lispref/strings.texi (Formatting Strings):
... to here, and describe new behavior of ‘format’.
* etc/NEWS: Describe new behavior.
* lisp/calc/calc-help.el (calc-describe-thing):
* lisp/emacs-lisp/derived.el (derived-mode-make-docstring):
* lisp/info.el (Info-find-index-name):
Use ‘concat’ rather than ‘format’ to avoid misinterpretation
of recently-added curved quotes.
* src/doc.c (uLSQM0, uLSQM1, uLSQM2, uRSQM0, uRSQM1, uRSQM2):
Move from here ...
* src/lisp.h: ... to here.
* src/doc.c (text_quoting_style): New function.
(Fsubstitute_command_keys): Use it.
* src/editfns.c (Fformat): Implement new behavior.
* src/lisp.h (enum text_quoting_style): New enum.
Diffstat (limited to 'src')
| -rw-r--r-- | src/doc.c | 52 | ||||
| -rw-r--r-- | src/editfns.c | 202 | ||||
| -rw-r--r-- | src/lisp.h | 19 |
3 files changed, 162 insertions, 111 deletions
| @@ -684,19 +684,32 @@ the same file name is found in the `doc-directory'. */) | |||
| 684 | return unbind_to (count, Qnil); | 684 | return unbind_to (count, Qnil); |
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | /* Declare named constants for U+2018 LEFT SINGLE QUOTATION MARK and | 687 | /* Curved quotation marks. */ |
| 688 | U+2019 RIGHT SINGLE QUOTATION MARK, which have UTF-8 encodings | ||
| 689 | "\xE2\x80\x98" and "\xE2\x80\x99", respectively. */ | ||
| 690 | enum | ||
| 691 | { | ||
| 692 | uLSQM0 = 0xE2, uLSQM1 = 0x80, uLSQM2 = 0x98, | ||
| 693 | uRSQM0 = 0xE2, uRSQM1 = 0x80, uRSQM2 = 0x99, | ||
| 694 | }; | ||
| 695 | static unsigned char const LSQM[] = { uLSQM0, uLSQM1, uLSQM2 }; | 688 | static unsigned char const LSQM[] = { uLSQM0, uLSQM1, uLSQM2 }; |
| 696 | static unsigned char const RSQM[] = { uRSQM0, uRSQM1, uRSQM2 }; | 689 | static unsigned char const RSQM[] = { uRSQM0, uRSQM1, uRSQM2 }; |
| 697 | #define uLSQM "\xE2\x80\x98" | 690 | #define uLSQM "\xE2\x80\x98" |
| 698 | #define uRSQM "\xE2\x80\x99" | 691 | #define uRSQM "\xE2\x80\x99" |
| 699 | 692 | ||
| 693 | /* Return the current effective text quoting style. */ | ||
| 694 | enum text_quoting_style | ||
| 695 | text_quoting_style (void) | ||
| 696 | { | ||
| 697 | if (EQ (Vtext_quoting_style, Qgrave)) | ||
| 698 | return GRAVE_QUOTING_STYLE; | ||
| 699 | else if (EQ (Vtext_quoting_style, Qstraight)) | ||
| 700 | return STRAIGHT_QUOTING_STYLE; | ||
| 701 | else if (NILP (Vtext_quoting_style) | ||
| 702 | && DISP_TABLE_P (Vstandard_display_table)) | ||
| 703 | { | ||
| 704 | Lisp_Object dv = DISP_CHAR_VECTOR (XCHAR_TABLE (Vstandard_display_table), | ||
| 705 | LEFT_SINGLE_QUOTATION_MARK); | ||
| 706 | if (VECTORP (dv) && ASIZE (dv) == 1 | ||
| 707 | && EQ (AREF (dv, 0), make_number ('`'))) | ||
| 708 | return GRAVE_QUOTING_STYLE; | ||
| 709 | } | ||
| 710 | return CURVE_QUOTING_STYLE; | ||
| 711 | } | ||
| 712 | |||
| 700 | DEFUN ("substitute-command-keys", Fsubstitute_command_keys, | 713 | DEFUN ("substitute-command-keys", Fsubstitute_command_keys, |
| 701 | Ssubstitute_command_keys, 1, 1, 0, | 714 | Ssubstitute_command_keys, 1, 1, 0, |
| 702 | doc: /* Substitute key descriptions for command names in STRING. | 715 | doc: /* Substitute key descriptions for command names in STRING. |
| @@ -751,20 +764,7 @@ Otherwise, return a new string. */) | |||
| 751 | name = Qnil; | 764 | name = Qnil; |
| 752 | GCPRO4 (string, tem, keymap, name); | 765 | GCPRO4 (string, tem, keymap, name); |
| 753 | 766 | ||
| 754 | enum { unicode, grave_accent, apostrophe } quote_translation = unicode; | 767 | enum text_quoting_style quoting_style = text_quoting_style (); |
| 755 | if (EQ (Vtext_quoting_style, Qgrave)) | ||
| 756 | quote_translation = grave_accent; | ||
| 757 | else if (EQ (Vtext_quoting_style, Qstraight)) | ||
| 758 | quote_translation = apostrophe; | ||
| 759 | else if (NILP (Vtext_quoting_style) | ||
| 760 | && DISP_TABLE_P (Vstandard_display_table)) | ||
| 761 | { | ||
| 762 | Lisp_Object dv = DISP_CHAR_VECTOR (XCHAR_TABLE (Vstandard_display_table), | ||
| 763 | LEFT_SINGLE_QUOTATION_MARK); | ||
| 764 | if (VECTORP (dv) && ASIZE (dv) == 1 | ||
| 765 | && EQ (AREF (dv, 0), make_number ('`'))) | ||
| 766 | quote_translation = grave_accent; | ||
| 767 | } | ||
| 768 | 768 | ||
| 769 | multibyte = STRING_MULTIBYTE (string); | 769 | multibyte = STRING_MULTIBYTE (string); |
| 770 | nchars = 0; | 770 | nchars = 0; |
| @@ -966,7 +966,7 @@ Otherwise, return a new string. */) | |||
| 966 | strp = SDATA (string) + idx; | 966 | strp = SDATA (string) + idx; |
| 967 | } | 967 | } |
| 968 | } | 968 | } |
| 969 | else if (strp[0] == '`' && quote_translation == unicode) | 969 | else if (strp[0] == '`' && quoting_style == CURVE_QUOTING_STYLE) |
| 970 | { | 970 | { |
| 971 | in_quote = true; | 971 | in_quote = true; |
| 972 | start = LSQM; | 972 | start = LSQM; |
| @@ -976,7 +976,7 @@ Otherwise, return a new string. */) | |||
| 976 | idx = strp - SDATA (string) + 1; | 976 | idx = strp - SDATA (string) + 1; |
| 977 | goto subst; | 977 | goto subst; |
| 978 | } | 978 | } |
| 979 | else if (strp[0] == '`' && quote_translation == apostrophe) | 979 | else if (strp[0] == '`' && quoting_style == STRAIGHT_QUOTING_STYLE) |
| 980 | { | 980 | { |
| 981 | *bufp++ = '\''; | 981 | *bufp++ = '\''; |
| 982 | strp++; | 982 | strp++; |
| @@ -991,9 +991,9 @@ Otherwise, return a new string. */) | |||
| 991 | } | 991 | } |
| 992 | else if (strp[0] == uLSQM0 && strp[1] == uLSQM1 | 992 | else if (strp[0] == uLSQM0 && strp[1] == uLSQM1 |
| 993 | && (strp[2] == uLSQM2 || strp[2] == uRSQM2) | 993 | && (strp[2] == uLSQM2 || strp[2] == uRSQM2) |
| 994 | && quote_translation != unicode) | 994 | && quoting_style != CURVE_QUOTING_STYLE) |
| 995 | { | 995 | { |
| 996 | *bufp++ = (strp[2] == uLSQM2 && quote_translation == grave_accent | 996 | *bufp++ = (strp[2] == uLSQM2 && quoting_style == GRAVE_QUOTING_STYLE |
| 997 | ? '`' : '\''); | 997 | ? '`' : '\''); |
| 998 | strp += 3; | 998 | strp += 3; |
| 999 | nchars++; | 999 | nchars++; |
diff --git a/src/editfns.c b/src/editfns.c index 9ff39f9bf19..ed57d8aee09 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -3800,8 +3800,9 @@ DEFUN ("format", Fformat, Sformat, 1, MANY, 0, | |||
| 3800 | The first argument is a format control string. | 3800 | The first argument is a format control string. |
| 3801 | The other arguments are substituted into it to make the result, a string. | 3801 | The other arguments are substituted into it to make the result, a string. |
| 3802 | 3802 | ||
| 3803 | The format control string may contain %-sequences meaning to substitute | 3803 | The format control string may contain ordinary characters, |
| 3804 | the next available argument: | 3804 | %-sequences meaning to substitute the next available argument, |
| 3805 | and curved single quotation marks meaning to substitute quotes. | ||
| 3805 | 3806 | ||
| 3806 | %s means print a string argument. Actually, prints any object, with `princ'. | 3807 | %s means print a string argument. Actually, prints any object, with `princ'. |
| 3807 | %d means print as number in decimal (%o octal, %x hex). | 3808 | %d means print as number in decimal (%o octal, %x hex). |
| @@ -3846,6 +3847,12 @@ precision specifier says how many decimal places to show; if zero, the | |||
| 3846 | decimal point itself is omitted. For %s and %S, the precision | 3847 | decimal point itself is omitted. For %s and %S, the precision |
| 3847 | specifier truncates the string to the given width. | 3848 | specifier truncates the string to the given width. |
| 3848 | 3849 | ||
| 3850 | \\=‘ and \\=’ means print left and right quotes as per | ||
| 3851 | ‘text-quoting-style’. | ||
| 3852 | |||
| 3853 | Return the first argument if it contains no format directives. | ||
| 3854 | Otherwise, return a new string. | ||
| 3855 | |||
| 3849 | usage: (format STRING &rest OBJECTS) */) | 3856 | usage: (format STRING &rest OBJECTS) */) |
| 3850 | (ptrdiff_t nargs, Lisp_Object *args) | 3857 | (ptrdiff_t nargs, Lisp_Object *args) |
| 3851 | { | 3858 | { |
| @@ -3858,6 +3865,7 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3858 | ptrdiff_t buf_save_value_index IF_LINT (= 0); | 3865 | ptrdiff_t buf_save_value_index IF_LINT (= 0); |
| 3859 | char *format, *end, *format_start; | 3866 | char *format, *end, *format_start; |
| 3860 | ptrdiff_t formatlen, nchars; | 3867 | ptrdiff_t formatlen, nchars; |
| 3868 | bool changed = false; | ||
| 3861 | /* True if the format is multibyte. */ | 3869 | /* True if the format is multibyte. */ |
| 3862 | bool multibyte_format = 0; | 3870 | bool multibyte_format = 0; |
| 3863 | /* True if the output should be a multibyte string, | 3871 | /* True if the output should be a multibyte string, |
| @@ -3921,6 +3929,8 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 3921 | if (STRINGP (args[n]) && STRING_MULTIBYTE (args[n])) | 3929 | if (STRINGP (args[n]) && STRING_MULTIBYTE (args[n])) |
| 3922 | multibyte = 1; | 3930 | multibyte = 1; |
| 3923 | 3931 | ||
| 3932 | enum text_quoting_style quoting_style = text_quoting_style (); | ||
| 3933 | |||
| 3924 | /* If we start out planning a unibyte result, | 3934 | /* If we start out planning a unibyte result, |
| 3925 | then discover it has to be multibyte, we jump back to retry. */ | 3935 | then discover it has to be multibyte, we jump back to retry. */ |
| 3926 | retry: | 3936 | retry: |
| @@ -4005,6 +4015,7 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 4005 | if (format == end) | 4015 | if (format == end) |
| 4006 | error ("Format string ends in middle of format specifier"); | 4016 | error ("Format string ends in middle of format specifier"); |
| 4007 | 4017 | ||
| 4018 | changed = true; | ||
| 4008 | memset (&discarded[format0 - format_start], 1, format - format0); | 4019 | memset (&discarded[format0 - format_start], 1, format - format0); |
| 4009 | conversion = *format; | 4020 | conversion = *format; |
| 4010 | if (conversion == '%') | 4021 | if (conversion == '%') |
| @@ -4426,6 +4437,20 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 4426 | 4437 | ||
| 4427 | convbytes = format - src; | 4438 | convbytes = format - src; |
| 4428 | memset (&discarded[src + 1 - format_start], 2, convbytes - 1); | 4439 | memset (&discarded[src + 1 - format_start], 2, convbytes - 1); |
| 4440 | |||
| 4441 | if (quoting_style != CURVE_QUOTING_STYLE && convbytes == 3 | ||
| 4442 | && (unsigned char) src[0] == uLSQM0 | ||
| 4443 | && (unsigned char) src[1] == uLSQM1 | ||
| 4444 | && ((unsigned char) src[2] == uLSQM2 | ||
| 4445 | || (unsigned char) src[2] == uRSQM2)) | ||
| 4446 | { | ||
| 4447 | convbytes = 1; | ||
| 4448 | str[0] = (((unsigned char) src[2] == uLSQM2 | ||
| 4449 | && quoting_style == GRAVE_QUOTING_STYLE) | ||
| 4450 | ? '`' : '\''); | ||
| 4451 | src = (char *) str; | ||
| 4452 | changed = true; | ||
| 4453 | } | ||
| 4429 | } | 4454 | } |
| 4430 | else | 4455 | else |
| 4431 | { | 4456 | { |
| @@ -4437,6 +4462,7 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 4437 | int c = BYTE8_TO_CHAR (uc); | 4462 | int c = BYTE8_TO_CHAR (uc); |
| 4438 | convbytes = CHAR_STRING (c, str); | 4463 | convbytes = CHAR_STRING (c, str); |
| 4439 | src = (char *) str; | 4464 | src = (char *) str; |
| 4465 | changed = true; | ||
| 4440 | } | 4466 | } |
| 4441 | } | 4467 | } |
| 4442 | 4468 | ||
| @@ -4484,113 +4510,119 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 4484 | if (bufsize < p - buf) | 4510 | if (bufsize < p - buf) |
| 4485 | emacs_abort (); | 4511 | emacs_abort (); |
| 4486 | 4512 | ||
| 4487 | if (maybe_combine_byte) | 4513 | if (!changed) |
| 4488 | nchars = multibyte_chars_in_text ((unsigned char *) buf, p - buf); | 4514 | val = args[0]; |
| 4489 | val = make_specified_string (buf, nchars, p - buf, multibyte); | 4515 | else |
| 4490 | |||
| 4491 | /* If the format string has text properties, or any of the string | ||
| 4492 | arguments has text properties, set up text properties of the | ||
| 4493 | result string. */ | ||
| 4494 | |||
| 4495 | if (string_intervals (args[0]) || arg_intervals) | ||
| 4496 | { | 4516 | { |
| 4497 | Lisp_Object len, new_len, props; | 4517 | if (maybe_combine_byte) |
| 4498 | struct gcpro gcpro1; | 4518 | nchars = multibyte_chars_in_text ((unsigned char *) buf, p - buf); |
| 4519 | val = make_specified_string (buf, nchars, p - buf, multibyte); | ||
| 4499 | 4520 | ||
| 4500 | /* Add text properties from the format string. */ | 4521 | /* If the format string has text properties, or any of the string |
| 4501 | len = make_number (SCHARS (args[0])); | 4522 | arguments has text properties, set up text properties of the |
| 4502 | props = text_property_list (args[0], make_number (0), len, Qnil); | 4523 | result string. */ |
| 4503 | GCPRO1 (props); | ||
| 4504 | 4524 | ||
| 4505 | if (CONSP (props)) | 4525 | if (string_intervals (args[0]) || arg_intervals) |
| 4506 | { | 4526 | { |
| 4507 | ptrdiff_t bytepos = 0, position = 0, translated = 0; | 4527 | Lisp_Object len, new_len, props; |
| 4508 | ptrdiff_t argn = 1; | 4528 | struct gcpro gcpro1; |
| 4509 | Lisp_Object list; | 4529 | |
| 4510 | 4530 | /* Add text properties from the format string. */ | |
| 4511 | /* Adjust the bounds of each text property | 4531 | len = make_number (SCHARS (args[0])); |
| 4512 | to the proper start and end in the output string. */ | 4532 | props = text_property_list (args[0], make_number (0), len, Qnil); |
| 4513 | 4533 | GCPRO1 (props); | |
| 4514 | /* Put the positions in PROPS in increasing order, so that | 4534 | |
| 4515 | we can do (effectively) one scan through the position | 4535 | if (CONSP (props)) |
| 4516 | space of the format string. */ | ||
| 4517 | props = Fnreverse (props); | ||
| 4518 | |||
| 4519 | /* BYTEPOS is the byte position in the format string, | ||
| 4520 | POSITION is the untranslated char position in it, | ||
| 4521 | TRANSLATED is the translated char position in BUF, | ||
| 4522 | and ARGN is the number of the next arg we will come to. */ | ||
| 4523 | for (list = props; CONSP (list); list = XCDR (list)) | ||
| 4524 | { | 4536 | { |
| 4525 | Lisp_Object item; | 4537 | ptrdiff_t bytepos = 0, position = 0, translated = 0; |
| 4526 | ptrdiff_t pos; | 4538 | ptrdiff_t argn = 1; |
| 4539 | Lisp_Object list; | ||
| 4540 | |||
| 4541 | /* Adjust the bounds of each text property | ||
| 4542 | to the proper start and end in the output string. */ | ||
| 4543 | |||
| 4544 | /* Put the positions in PROPS in increasing order, so that | ||
| 4545 | we can do (effectively) one scan through the position | ||
| 4546 | space of the format string. */ | ||
| 4547 | props = Fnreverse (props); | ||
| 4548 | |||
| 4549 | /* BYTEPOS is the byte position in the format string, | ||
| 4550 | POSITION is the untranslated char position in it, | ||
| 4551 | TRANSLATED is the translated char position in BUF, | ||
| 4552 | and ARGN is the number of the next arg we will come to. */ | ||
| 4553 | for (list = props; CONSP (list); list = XCDR (list)) | ||
| 4554 | { | ||
| 4555 | Lisp_Object item; | ||
| 4556 | ptrdiff_t pos; | ||
| 4527 | 4557 | ||
| 4528 | item = XCAR (list); | 4558 | item = XCAR (list); |
| 4529 | 4559 | ||
| 4530 | /* First adjust the property start position. */ | 4560 | /* First adjust the property start position. */ |
| 4531 | pos = XINT (XCAR (item)); | 4561 | pos = XINT (XCAR (item)); |
| 4532 | 4562 | ||
| 4533 | /* Advance BYTEPOS, POSITION, TRANSLATED and ARGN | 4563 | /* Advance BYTEPOS, POSITION, TRANSLATED and ARGN |
| 4534 | up to this position. */ | 4564 | up to this position. */ |
| 4535 | for (; position < pos; bytepos++) | 4565 | for (; position < pos; bytepos++) |
| 4536 | { | ||
| 4537 | if (! discarded[bytepos]) | ||
| 4538 | position++, translated++; | ||
| 4539 | else if (discarded[bytepos] == 1) | ||
| 4540 | { | 4566 | { |
| 4541 | position++; | 4567 | if (! discarded[bytepos]) |
| 4542 | if (translated == info[argn].start) | 4568 | position++, translated++; |
| 4569 | else if (discarded[bytepos] == 1) | ||
| 4543 | { | 4570 | { |
| 4544 | translated += info[argn].end - info[argn].start; | 4571 | position++; |
| 4545 | argn++; | 4572 | if (translated == info[argn].start) |
| 4573 | { | ||
| 4574 | translated += info[argn].end - info[argn].start; | ||
| 4575 | argn++; | ||
| 4576 | } | ||
| 4546 | } | 4577 | } |
| 4547 | } | 4578 | } |
| 4548 | } | ||
| 4549 | 4579 | ||
| 4550 | XSETCAR (item, make_number (translated)); | 4580 | XSETCAR (item, make_number (translated)); |
| 4551 | 4581 | ||
| 4552 | /* Likewise adjust the property end position. */ | 4582 | /* Likewise adjust the property end position. */ |
| 4553 | pos = XINT (XCAR (XCDR (item))); | 4583 | pos = XINT (XCAR (XCDR (item))); |
| 4554 | 4584 | ||
| 4555 | for (; position < pos; bytepos++) | 4585 | for (; position < pos; bytepos++) |
| 4556 | { | ||
| 4557 | if (! discarded[bytepos]) | ||
| 4558 | position++, translated++; | ||
| 4559 | else if (discarded[bytepos] == 1) | ||
| 4560 | { | 4586 | { |
| 4561 | position++; | 4587 | if (! discarded[bytepos]) |
| 4562 | if (translated == info[argn].start) | 4588 | position++, translated++; |
| 4589 | else if (discarded[bytepos] == 1) | ||
| 4563 | { | 4590 | { |
| 4564 | translated += info[argn].end - info[argn].start; | 4591 | position++; |
| 4565 | argn++; | 4592 | if (translated == info[argn].start) |
| 4593 | { | ||
| 4594 | translated += info[argn].end - info[argn].start; | ||
| 4595 | argn++; | ||
| 4596 | } | ||
| 4566 | } | 4597 | } |
| 4567 | } | 4598 | } |
| 4599 | |||
| 4600 | XSETCAR (XCDR (item), make_number (translated)); | ||
| 4568 | } | 4601 | } |
| 4569 | 4602 | ||
| 4570 | XSETCAR (XCDR (item), make_number (translated)); | 4603 | add_text_properties_from_list (val, props, make_number (0)); |
| 4571 | } | 4604 | } |
| 4572 | 4605 | ||
| 4573 | add_text_properties_from_list (val, props, make_number (0)); | 4606 | /* Add text properties from arguments. */ |
| 4574 | } | 4607 | if (arg_intervals) |
| 4575 | 4608 | for (n = 1; n < nargs; ++n) | |
| 4576 | /* Add text properties from arguments. */ | 4609 | if (info[n].intervals) |
| 4577 | if (arg_intervals) | 4610 | { |
| 4578 | for (n = 1; n < nargs; ++n) | 4611 | len = make_number (SCHARS (args[n])); |
| 4579 | if (info[n].intervals) | 4612 | new_len = make_number (info[n].end - info[n].start); |
| 4580 | { | 4613 | props = text_property_list (args[n], make_number (0), |
| 4581 | len = make_number (SCHARS (args[n])); | 4614 | len, Qnil); |
| 4582 | new_len = make_number (info[n].end - info[n].start); | 4615 | props = extend_property_ranges (props, new_len); |
| 4583 | props = text_property_list (args[n], make_number (0), len, Qnil); | 4616 | /* If successive arguments have properties, be sure that |
| 4584 | props = extend_property_ranges (props, new_len); | 4617 | the value of `composition' property be the copy. */ |
| 4585 | /* If successive arguments have properties, be sure that | 4618 | if (n > 1 && info[n - 1].end) |
| 4586 | the value of `composition' property be the copy. */ | 4619 | make_composition_value_copy (props); |
| 4587 | if (n > 1 && info[n - 1].end) | 4620 | add_text_properties_from_list (val, props, |
| 4588 | make_composition_value_copy (props); | 4621 | make_number (info[n].start)); |
| 4589 | add_text_properties_from_list (val, props, | 4622 | } |
| 4590 | make_number (info[n].start)); | ||
| 4591 | } | ||
| 4592 | 4623 | ||
| 4593 | UNGCPRO; | 4624 | UNGCPRO; |
| 4625 | } | ||
| 4594 | } | 4626 | } |
| 4595 | 4627 | ||
| 4596 | /* If we allocated BUF or INFO with malloc, free it too. */ | 4628 | /* If we allocated BUF or INFO with malloc, free it too. */ |
diff --git a/src/lisp.h b/src/lisp.h index 2545203a674..d3dcaecd2bb 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -4300,6 +4300,25 @@ extern void set_initial_environment (void); | |||
| 4300 | extern void syms_of_callproc (void); | 4300 | extern void syms_of_callproc (void); |
| 4301 | 4301 | ||
| 4302 | /* Defined in doc.c. */ | 4302 | /* Defined in doc.c. */ |
| 4303 | enum | ||
| 4304 | { | ||
| 4305 | /* Named constants for the UTF-8 encodings of U+2018 LEFT SINGLE | ||
| 4306 | QUOTATION MARK and U+2019 RIGHT SINGLE QUOTATION MARK. */ | ||
| 4307 | uLSQM0 = 0xE2, uLSQM1 = 0x80, uLSQM2 = 0x98, | ||
| 4308 | uRSQM0 = 0xE2, uRSQM1 = 0x80, uRSQM2 = 0x99 | ||
| 4309 | }; | ||
| 4310 | enum text_quoting_style | ||
| 4311 | { | ||
| 4312 | /* Use curved single quotes ‘like this’. */ | ||
| 4313 | CURVE_QUOTING_STYLE, | ||
| 4314 | |||
| 4315 | /* Use grave accent and apostrophe `like this'. */ | ||
| 4316 | GRAVE_QUOTING_STYLE, | ||
| 4317 | |||
| 4318 | /* Use apostrophes 'like this'. */ | ||
| 4319 | STRAIGHT_QUOTING_STYLE | ||
| 4320 | }; | ||
| 4321 | extern enum text_quoting_style text_quoting_style (void); | ||
| 4303 | extern Lisp_Object read_doc_string (Lisp_Object); | 4322 | extern Lisp_Object read_doc_string (Lisp_Object); |
| 4304 | extern Lisp_Object get_doc_string (Lisp_Object, bool, bool); | 4323 | extern Lisp_Object get_doc_string (Lisp_Object, bool, bool); |
| 4305 | extern void syms_of_doc (void); | 4324 | extern void syms_of_doc (void); |