diff options
| author | Kenichi Handa | 2010-11-01 13:09:26 +0900 |
|---|---|---|
| committer | Kenichi Handa | 2010-11-01 13:09:26 +0900 |
| commit | b18fad6db4efeda274dcb36706a4146650570e6b (patch) | |
| tree | 5534ead2ed9b34b021ac3e92c88cf70350f26351 /src | |
| parent | 0269bd906626243b117136d6ea9eb98d2947b9f8 (diff) | |
| download | emacs-b18fad6db4efeda274dcb36706a4146650570e6b.tar.gz emacs-b18fad6db4efeda274dcb36706a4146650570e6b.zip | |
Handle glyphless characters on tty.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 18 | ||||
| -rw-r--r-- | src/coding.c | 7 | ||||
| -rw-r--r-- | src/dispextern.h | 2 | ||||
| -rw-r--r-- | src/term.c | 182 | ||||
| -rw-r--r-- | src/termhooks.h | 5 | ||||
| -rw-r--r-- | src/xdisp.c | 14 |
6 files changed, 215 insertions, 13 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index eecad1f9689..2d1ed5a96fb 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,21 @@ | |||
| 1 | 2010-11-01 Kenichi Handa <handa@m17n.org> | ||
| 2 | |||
| 3 | * dispextern.h (lookup_glyphless_char_display): Extern it. | ||
| 4 | |||
| 5 | * termhooks.h (struct terminal): New member charset_list. | ||
| 6 | |||
| 7 | * coding.c (Fset_terminal_coding_system_internal): Set the | ||
| 8 | `charset_list' member of struct terminal. | ||
| 9 | |||
| 10 | * term.c (produce_glyphs): Handle the case it->what == | ||
| 11 | IT_GLYPHLESS. | ||
| 12 | (append_glyphless_glyph, produce_glyphless_glyph): New functions. | ||
| 13 | |||
| 14 | * xdisp.c (lookup_glyphless_char_display): Make it non-static. | ||
| 15 | (lookup_glyphless_char_display): Set it->what at the end. | ||
| 16 | (last_glyphless_glyph_frame, last_glyphless_glyph_face_id) | ||
| 17 | (last_glyphless_glyph_merged_face_id): Make them non-static. | ||
| 18 | |||
| 1 | 2010-10-29 Kenichi Handa <handa@m17n.org> | 19 | 2010-10-29 Kenichi Handa <handa@m17n.org> |
| 2 | 20 | ||
| 3 | * w32gui.h (STORE_XCHAR2B, XCHAR2B_BYTE1, XCHAR2B_BYTE2): Surround | 21 | * w32gui.h (STORE_XCHAR2B, XCHAR2B_BYTE1, XCHAR2B_BYTE2): Surround |
diff --git a/src/coding.c b/src/coding.c index 7a3bc40b9c7..59deb22a3d7 100644 --- a/src/coding.c +++ b/src/coding.c | |||
| @@ -9297,7 +9297,8 @@ DEFUN ("set-terminal-coding-system-internal", Fset_terminal_coding_system_intern | |||
| 9297 | doc: /* Internal use only. */) | 9297 | doc: /* Internal use only. */) |
| 9298 | (Lisp_Object coding_system, Lisp_Object terminal) | 9298 | (Lisp_Object coding_system, Lisp_Object terminal) |
| 9299 | { | 9299 | { |
| 9300 | struct coding_system *terminal_coding = TERMINAL_TERMINAL_CODING (get_terminal (terminal, 1)); | 9300 | struct terminal *term = get_terminal (terminal, 1); |
| 9301 | struct coding_system *terminal_coding = TERMINAL_TERMINAL_CODING (term); | ||
| 9301 | CHECK_SYMBOL (coding_system); | 9302 | CHECK_SYMBOL (coding_system); |
| 9302 | setup_coding_system (Fcheck_coding_system (coding_system), terminal_coding); | 9303 | setup_coding_system (Fcheck_coding_system (coding_system), terminal_coding); |
| 9303 | /* We had better not send unsafe characters to terminal. */ | 9304 | /* We had better not send unsafe characters to terminal. */ |
| @@ -9306,6 +9307,10 @@ DEFUN ("set-terminal-coding-system-internal", Fset_terminal_coding_system_intern | |||
| 9306 | terminal_coding->common_flags &= ~CODING_ANNOTATE_COMPOSITION_MASK; | 9307 | terminal_coding->common_flags &= ~CODING_ANNOTATE_COMPOSITION_MASK; |
| 9307 | terminal_coding->src_multibyte = 1; | 9308 | terminal_coding->src_multibyte = 1; |
| 9308 | terminal_coding->dst_multibyte = 0; | 9309 | terminal_coding->dst_multibyte = 0; |
| 9310 | if (terminal_coding->common_flags & CODING_REQUIRE_ENCODING_MASK) | ||
| 9311 | term->charset_list = coding_charset_list (terminal_coding); | ||
| 9312 | else | ||
| 9313 | term->charset_list = Fcons (Qascii, Qnil); | ||
| 9309 | return Qnil; | 9314 | return Qnil; |
| 9310 | } | 9315 | } |
| 9311 | 9316 | ||
diff --git a/src/dispextern.h b/src/dispextern.h index af09ec5d3de..c2eeb6ec527 100644 --- a/src/dispextern.h +++ b/src/dispextern.h | |||
| @@ -3021,7 +3021,7 @@ extern EMACS_INT underline_minimum_offset; | |||
| 3021 | extern Lisp_Object Vglyphless_char_display; | 3021 | extern Lisp_Object Vglyphless_char_display; |
| 3022 | 3022 | ||
| 3023 | extern void reseat_at_previous_visible_line_start (struct it *); | 3023 | extern void reseat_at_previous_visible_line_start (struct it *); |
| 3024 | 3024 | extern Lisp_Object lookup_glyphless_char_display (int, struct it *); | |
| 3025 | extern int calc_pixel_width_or_height (double *, struct it *, Lisp_Object, | 3025 | extern int calc_pixel_width_or_height (double *, struct it *, Lisp_Object, |
| 3026 | struct font *, int, int *); | 3026 | struct font *, int, int *); |
| 3027 | 3027 | ||
diff --git a/src/term.c b/src/term.c index 4baea231de3..7593f02e607 100644 --- a/src/term.c +++ b/src/term.c | |||
| @@ -1501,6 +1501,8 @@ static void append_glyph (struct it *); | |||
| 1501 | static void produce_stretch_glyph (struct it *); | 1501 | static void produce_stretch_glyph (struct it *); |
| 1502 | static void append_composite_glyph (struct it *); | 1502 | static void append_composite_glyph (struct it *); |
| 1503 | static void produce_composite_glyph (struct it *); | 1503 | static void produce_composite_glyph (struct it *); |
| 1504 | static void append_glyphless_glyph (struct it *, int, char *); | ||
| 1505 | static void produce_glyphless_glyph (struct it *, int, Lisp_Object); | ||
| 1504 | 1506 | ||
| 1505 | /* Append glyphs to IT's glyph_row. Called from produce_glyphs for | 1507 | /* Append glyphs to IT's glyph_row. Called from produce_glyphs for |
| 1506 | terminal frames if IT->glyph_row != NULL. IT->char_to_display is | 1508 | terminal frames if IT->glyph_row != NULL. IT->char_to_display is |
| @@ -1609,6 +1611,12 @@ produce_glyphs (struct it *it) | |||
| 1609 | goto done; | 1611 | goto done; |
| 1610 | } | 1612 | } |
| 1611 | 1613 | ||
| 1614 | if (it->what == IT_GLYPHLESS) | ||
| 1615 | { | ||
| 1616 | produce_glyphless_glyph (it, 0, Qnil); | ||
| 1617 | goto done; | ||
| 1618 | } | ||
| 1619 | |||
| 1612 | if (it->char_to_display >= 040 && it->char_to_display < 0177) | 1620 | if (it->char_to_display >= 040 && it->char_to_display < 0177) |
| 1613 | { | 1621 | { |
| 1614 | it->pixel_width = it->nglyphs = 1; | 1622 | it->pixel_width = it->nglyphs = 1; |
| @@ -1660,11 +1668,22 @@ produce_glyphs (struct it *it) | |||
| 1660 | } | 1668 | } |
| 1661 | else | 1669 | else |
| 1662 | { | 1670 | { |
| 1663 | it->pixel_width = CHAR_WIDTH (it->char_to_display); | 1671 | Lisp_Object charset_list = FRAME_TERMINAL (it->f)->charset_list; |
| 1664 | it->nglyphs = it->pixel_width; | ||
| 1665 | 1672 | ||
| 1666 | if (it->glyph_row) | 1673 | if (char_charset (it->char_to_display, charset_list, NULL)) |
| 1667 | append_glyph (it); | 1674 | { |
| 1675 | it->pixel_width = CHAR_WIDTH (it->char_to_display); | ||
| 1676 | it->nglyphs = it->pixel_width; | ||
| 1677 | if (it->glyph_row) | ||
| 1678 | append_glyph (it); | ||
| 1679 | } | ||
| 1680 | else | ||
| 1681 | { | ||
| 1682 | Lisp_Object acronym = lookup_glyphless_char_display (-1, it); | ||
| 1683 | |||
| 1684 | xassert (it->what == IT_GLYPHLESS); | ||
| 1685 | produce_glyphless_glyph (it, 1, acronym); | ||
| 1686 | } | ||
| 1668 | } | 1687 | } |
| 1669 | 1688 | ||
| 1670 | done: | 1689 | done: |
| @@ -1844,6 +1863,161 @@ produce_composite_glyph (struct it *it) | |||
| 1844 | } | 1863 | } |
| 1845 | 1864 | ||
| 1846 | 1865 | ||
| 1866 | /* Append a glyph for a glyphless character to IT->glyph_row. FACE_ID | ||
| 1867 | is a face ID to be used for the glyph. What actually appended are | ||
| 1868 | glyphs of type CHAR_GLYPH of which characters are in STR | ||
| 1869 | (it->nglyphs bytes). */ | ||
| 1870 | |||
| 1871 | static void | ||
| 1872 | append_glyphless_glyph (struct it *it, int face_id, char *str) | ||
| 1873 | { | ||
| 1874 | struct glyph *glyph, *end; | ||
| 1875 | bidi_type_t bidi_type; | ||
| 1876 | int resolved_level; | ||
| 1877 | int i; | ||
| 1878 | |||
| 1879 | xassert (it->glyph_row); | ||
| 1880 | glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area]; | ||
| 1881 | end = it->glyph_row->glyphs[1 + it->area]; | ||
| 1882 | |||
| 1883 | /* If the glyph row is reversed, we need to prepend the glyph rather | ||
| 1884 | than append it. */ | ||
| 1885 | if (it->glyph_row->reversed_p && it->area == TEXT_AREA) | ||
| 1886 | { | ||
| 1887 | struct glyph *g; | ||
| 1888 | int move_by = it->pixel_width; | ||
| 1889 | |||
| 1890 | /* Make room for the new glyphs. */ | ||
| 1891 | if (move_by > end - glyph) /* don't overstep end of this area */ | ||
| 1892 | move_by = end - glyph; | ||
| 1893 | for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--) | ||
| 1894 | g[move_by] = *g; | ||
| 1895 | glyph = it->glyph_row->glyphs[it->area]; | ||
| 1896 | end = glyph + move_by; | ||
| 1897 | } | ||
| 1898 | |||
| 1899 | if (glyph >= end) | ||
| 1900 | return; | ||
| 1901 | glyph->type = CHAR_GLYPH; | ||
| 1902 | glyph->pixel_width = 1; | ||
| 1903 | glyph->face_id = face_id; | ||
| 1904 | glyph->padding_p = 0; | ||
| 1905 | glyph->charpos = CHARPOS (it->position); | ||
| 1906 | glyph->object = it->object; | ||
| 1907 | if (it->bidi_p) | ||
| 1908 | { | ||
| 1909 | glyph->resolved_level = it->bidi_it.resolved_level; | ||
| 1910 | if ((it->bidi_it.type & 7) != it->bidi_it.type) | ||
| 1911 | abort (); | ||
| 1912 | glyph->bidi_type = it->bidi_it.type; | ||
| 1913 | } | ||
| 1914 | else | ||
| 1915 | { | ||
| 1916 | glyph->resolved_level = 0; | ||
| 1917 | glyph->bidi_type = UNKNOWN_BT; | ||
| 1918 | } | ||
| 1919 | |||
| 1920 | /* BIDI Note: we put the glyphs of characters left to right, even in | ||
| 1921 | the REVERSED_P case because we write to the terminal | ||
| 1922 | left-to-right. */ | ||
| 1923 | for (i = 0; i < it->nglyphs && glyph < end; ++i) | ||
| 1924 | { | ||
| 1925 | if (i > 0) | ||
| 1926 | glyph[0] = glyph[-1]; | ||
| 1927 | glyph->u.ch = str[i]; | ||
| 1928 | ++it->glyph_row->used[it->area]; | ||
| 1929 | ++glyph; | ||
| 1930 | } | ||
| 1931 | } | ||
| 1932 | |||
| 1933 | /* Declared in xdisp.c */ | ||
| 1934 | extern struct frame *last_glyphless_glyph_frame; | ||
| 1935 | extern unsigned last_glyphless_glyph_face_id; | ||
| 1936 | extern int last_glyphless_glyph_merged_face_id; | ||
| 1937 | extern Lisp_Object Qglyphless_char; | ||
| 1938 | |||
| 1939 | /* Produce glyphs for a glyphless character for iterator IT. | ||
| 1940 | IT->glyphless_method specifies which method to use for displaying | ||
| 1941 | the character. See the description of enum | ||
| 1942 | glyphless_display_method in dispextern.h for the detail. | ||
| 1943 | |||
| 1944 | FOR_NO_FONT is nonzero if and only if this is for a character that | ||
| 1945 | is not supproted by the coding system of the terminal. ACRONYM, if | ||
| 1946 | non-nil, is an acronym string for the character. | ||
| 1947 | |||
| 1948 | The glyphs actually produced are of type CHAR_GLYPH. */ | ||
| 1949 | |||
| 1950 | static void | ||
| 1951 | produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym) | ||
| 1952 | { | ||
| 1953 | int face_id; | ||
| 1954 | struct face *face; | ||
| 1955 | int width, len; | ||
| 1956 | char buf[9], *str = " "; | ||
| 1957 | |||
| 1958 | /* Get a face ID for the glyph by utilizing a cache (the same way as | ||
| 1959 | doen for `escape-glyph' in get_next_display_element). */ | ||
| 1960 | if (it->f == last_glyphless_glyph_frame | ||
| 1961 | && it->face_id == last_glyphless_glyph_face_id) | ||
| 1962 | { | ||
| 1963 | face_id = last_glyphless_glyph_merged_face_id; | ||
| 1964 | } | ||
| 1965 | else | ||
| 1966 | { | ||
| 1967 | /* Merge the `glyphless-char' face into the current face. */ | ||
| 1968 | face_id = merge_faces (it->f, Qglyphless_char, 0, it->face_id); | ||
| 1969 | last_glyphless_glyph_frame = it->f; | ||
| 1970 | last_glyphless_glyph_face_id = it->face_id; | ||
| 1971 | last_glyphless_glyph_merged_face_id = face_id; | ||
| 1972 | } | ||
| 1973 | |||
| 1974 | if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE) | ||
| 1975 | { | ||
| 1976 | /* As there's no way to produce a thin space, we produce | ||
| 1977 | a space of canonical width.. */ | ||
| 1978 | len = 1; | ||
| 1979 | } | ||
| 1980 | else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX) | ||
| 1981 | { | ||
| 1982 | len = CHAR_WIDTH (it->c); | ||
| 1983 | if (len == 0) | ||
| 1984 | len = 1; | ||
| 1985 | else if (width > 4) | ||
| 1986 | len = 4; | ||
| 1987 | } | ||
| 1988 | else | ||
| 1989 | { | ||
| 1990 | if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM) | ||
| 1991 | { | ||
| 1992 | int i; | ||
| 1993 | |||
| 1994 | if (! STRINGP (acronym) && CHAR_TABLE_P (Vglyphless_char_display)) | ||
| 1995 | acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c); | ||
| 1996 | buf[0] = '['; | ||
| 1997 | str = STRINGP (acronym) ? (char *) SDATA (acronym) : ""; | ||
| 1998 | for (len = 0; len < 6 && str[len] && ASCII_BYTE_P (str[len]); len++) | ||
| 1999 | buf[1 + len] = str[len]; | ||
| 2000 | buf[1 + len] = ']'; | ||
| 2001 | len += 2; | ||
| 2002 | } | ||
| 2003 | else | ||
| 2004 | { | ||
| 2005 | xassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEXA_CODE); | ||
| 2006 | len = (it->c < 0x100 ? sprintf (buf, "U+%02X", it->c) | ||
| 2007 | : it->c < 0x10000 ? sprintf (buf, "U+%04X", it->c) | ||
| 2008 | : it->c <= MAX_UNICODE_CHAR ? sprintf (buf, "U+%06X", it->c) | ||
| 2009 | : sprintf (buf, "E+%06X", it->c)); | ||
| 2010 | } | ||
| 2011 | str = buf; | ||
| 2012 | } | ||
| 2013 | |||
| 2014 | it->pixel_width = len; | ||
| 2015 | it->nglyphs = len; | ||
| 2016 | if (len > 0 && it->glyph_row) | ||
| 2017 | append_glyphless_glyph (it, face_id, str); | ||
| 2018 | } | ||
| 2019 | |||
| 2020 | |||
| 1847 | /* Get information about special display element WHAT in an | 2021 | /* Get information about special display element WHAT in an |
| 1848 | environment described by IT. WHAT is one of IT_TRUNCATION or | 2022 | environment described by IT. WHAT is one of IT_TRUNCATION or |
| 1849 | IT_CONTINUATION. Maybe produce glyphs for WHAT if IT has a | 2023 | IT_CONTINUATION. Maybe produce glyphs for WHAT if IT has a |
diff --git a/src/termhooks.h b/src/termhooks.h index b9358896bae..e71c1159f0c 100644 --- a/src/termhooks.h +++ b/src/termhooks.h | |||
| @@ -328,6 +328,11 @@ struct terminal | |||
| 328 | /* Parameter alist of this terminal. */ | 328 | /* Parameter alist of this terminal. */ |
| 329 | Lisp_Object param_alist; | 329 | Lisp_Object param_alist; |
| 330 | 330 | ||
| 331 | /* List of charsets supported by the terminal. It is set by | ||
| 332 | Fset_terminal_coding_system_internal along with | ||
| 333 | the member terminal_coding. */ | ||
| 334 | Lisp_Object charset_list; | ||
| 335 | |||
| 331 | /* All fields before `next_terminal' should be Lisp_Object and are traced | 336 | /* All fields before `next_terminal' should be Lisp_Object and are traced |
| 332 | by the GC. All fields afterwards are ignored by the GC. */ | 337 | by the GC. All fields afterwards are ignored by the GC. */ |
| 333 | 338 | ||
diff --git a/src/xdisp.c b/src/xdisp.c index 52938417aac..ad90d57865b 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -5754,7 +5754,7 @@ static int (* get_next_element[NUM_IT_METHODS]) (struct it *it) = | |||
| 5754 | get_next_display_element for each character element, and from | 5754 | get_next_display_element for each character element, and from |
| 5755 | x_produce_glyphs when no suitable font was found. */ | 5755 | x_produce_glyphs when no suitable font was found. */ |
| 5756 | 5756 | ||
| 5757 | static Lisp_Object | 5757 | Lisp_Object |
| 5758 | lookup_glyphless_char_display (int c, struct it *it) | 5758 | lookup_glyphless_char_display (int c, struct it *it) |
| 5759 | { | 5759 | { |
| 5760 | Lisp_Object glyphless_method = Qnil; | 5760 | Lisp_Object glyphless_method = Qnil; |
| @@ -5780,7 +5780,6 @@ lookup_glyphless_char_display (int c, struct it *it) | |||
| 5780 | /* This method can't be used for the no-font case. */ | 5780 | /* This method can't be used for the no-font case. */ |
| 5781 | glyphless_method = Qempty_box; | 5781 | glyphless_method = Qempty_box; |
| 5782 | } | 5782 | } |
| 5783 | it->what = IT_GLYPHLESS; | ||
| 5784 | if (EQ (glyphless_method, Qthin_space)) | 5783 | if (EQ (glyphless_method, Qthin_space)) |
| 5785 | it->glyphless_method = GLYPHLESS_DISPLAY_THIN_SPACE; | 5784 | it->glyphless_method = GLYPHLESS_DISPLAY_THIN_SPACE; |
| 5786 | else if (EQ (glyphless_method, Qempty_box)) | 5785 | else if (EQ (glyphless_method, Qempty_box)) |
| @@ -5795,6 +5794,7 @@ lookup_glyphless_char_display (int c, struct it *it) | |||
| 5795 | glyphless_method = Qnil; | 5794 | glyphless_method = Qnil; |
| 5796 | goto retry; | 5795 | goto retry; |
| 5797 | } | 5796 | } |
| 5797 | it->what = IT_GLYPHLESS; | ||
| 5798 | return glyphless_method; | 5798 | return glyphless_method; |
| 5799 | } | 5799 | } |
| 5800 | 5800 | ||
| @@ -5806,9 +5806,9 @@ static struct frame *last_escape_glyph_frame = NULL; | |||
| 5806 | static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS); | 5806 | static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS); |
| 5807 | static int last_escape_glyph_merged_face_id = 0; | 5807 | static int last_escape_glyph_merged_face_id = 0; |
| 5808 | 5808 | ||
| 5809 | static struct frame *last_glyphless_glyph_frame = NULL; | 5809 | struct frame *last_glyphless_glyph_frame = NULL; |
| 5810 | static unsigned last_glyphless_glyph_face_id = (1 << FACE_ID_BITS); | 5810 | unsigned last_glyphless_glyph_face_id = (1 << FACE_ID_BITS); |
| 5811 | static int last_glyphless_glyph_merged_face_id = 0; | 5811 | int last_glyphless_glyph_merged_face_id = 0; |
| 5812 | 5812 | ||
| 5813 | int | 5813 | int |
| 5814 | get_next_display_element (struct it *it) | 5814 | get_next_display_element (struct it *it) |
| @@ -22329,8 +22329,8 @@ append_glyphless_glyph (struct it *it, int face_id, int for_no_font, int len, | |||
| 22329 | 22329 | ||
| 22330 | /* Produce a glyph for a glyphless character for iterator IT. | 22330 | /* Produce a glyph for a glyphless character for iterator IT. |
| 22331 | IT->glyphless_method specifies which method to use for displaying | 22331 | IT->glyphless_method specifies which method to use for displaying |
| 22332 | the glyph. See the description of enum glyphless_display_method in | 22332 | the character. See the description of enum |
| 22333 | dispextern.h for the default of the display methods. | 22333 | glyphless_display_method in dispextern.h for the detail. |
| 22334 | 22334 | ||
| 22335 | FOR_NO_FONT is nonzero if and only if this is for a character for | 22335 | FOR_NO_FONT is nonzero if and only if this is for a character for |
| 22336 | which no font was found. ACRONYM, if non-nil, is an acronym string | 22336 | which no font was found. ACRONYM, if non-nil, is an acronym string |