From b18fad6db4efeda274dcb36706a4146650570e6b Mon Sep 17 00:00:00 2001 From: Kenichi Handa Date: Mon, 1 Nov 2010 13:09:26 +0900 Subject: [PATCH] Handle glyphless characters on tty. --- lisp/ChangeLog | 4 ++ lisp/faces.el | 4 +- src/ChangeLog | 18 +++++ src/coding.c | 7 +- src/dispextern.h | 2 +- src/term.c | 182 +++++++++++++++++++++++++++++++++++++++++++++-- src/termhooks.h | 5 ++ src/xdisp.c | 14 ++-- 8 files changed, 222 insertions(+), 14 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 46160f878b3..5d2e442a1c1 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,7 @@ +2010-11-01 Kenichi Handa + + * faces.el (glyphless-char): Inherit underline for tty. + 2010-10-28 Kenichi Handa Implement various display methods for glyphless characters. diff --git a/lisp/faces.el b/lisp/faces.el index 562bde6ed41..5e421f3f70a 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -2483,7 +2483,9 @@ Note: Other faces cannot inherit from the cursor face." "Face to highlight argument names in *Help* buffers." :group 'help) -(defface glyphless-char '((t :height 0.6)) +(defface glyphless-char + '((((type tty)) :inherit underline) + (t :height 0.6)) "Face for displaying non-graphic characters (e.g. U+202A (LRE)). It is used for characters of no fonts too." :version "24.1" diff --git a/src/ChangeLog b/src/ChangeLog index eecad1f9689..2d1ed5a96fb 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,21 @@ +2010-11-01 Kenichi Handa + + * dispextern.h (lookup_glyphless_char_display): Extern it. + + * termhooks.h (struct terminal): New member charset_list. + + * coding.c (Fset_terminal_coding_system_internal): Set the + `charset_list' member of struct terminal. + + * term.c (produce_glyphs): Handle the case it->what == + IT_GLYPHLESS. + (append_glyphless_glyph, produce_glyphless_glyph): New functions. + + * xdisp.c (lookup_glyphless_char_display): Make it non-static. + (lookup_glyphless_char_display): Set it->what at the end. + (last_glyphless_glyph_frame, last_glyphless_glyph_face_id) + (last_glyphless_glyph_merged_face_id): Make them non-static. + 2010-10-29 Kenichi Handa * 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 doc: /* Internal use only. */) (Lisp_Object coding_system, Lisp_Object terminal) { - struct coding_system *terminal_coding = TERMINAL_TERMINAL_CODING (get_terminal (terminal, 1)); + struct terminal *term = get_terminal (terminal, 1); + struct coding_system *terminal_coding = TERMINAL_TERMINAL_CODING (term); CHECK_SYMBOL (coding_system); setup_coding_system (Fcheck_coding_system (coding_system), terminal_coding); /* We had better not send unsafe characters to terminal. */ @@ -9306,6 +9307,10 @@ DEFUN ("set-terminal-coding-system-internal", Fset_terminal_coding_system_intern terminal_coding->common_flags &= ~CODING_ANNOTATE_COMPOSITION_MASK; terminal_coding->src_multibyte = 1; terminal_coding->dst_multibyte = 0; + if (terminal_coding->common_flags & CODING_REQUIRE_ENCODING_MASK) + term->charset_list = coding_charset_list (terminal_coding); + else + term->charset_list = Fcons (Qascii, Qnil); return Qnil; } 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; extern Lisp_Object Vglyphless_char_display; extern void reseat_at_previous_visible_line_start (struct it *); - +extern Lisp_Object lookup_glyphless_char_display (int, struct it *); extern int calc_pixel_width_or_height (double *, struct it *, Lisp_Object, struct font *, int, int *); 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 *); static void produce_stretch_glyph (struct it *); static void append_composite_glyph (struct it *); static void produce_composite_glyph (struct it *); +static void append_glyphless_glyph (struct it *, int, char *); +static void produce_glyphless_glyph (struct it *, int, Lisp_Object); /* Append glyphs to IT's glyph_row. Called from produce_glyphs for terminal frames if IT->glyph_row != NULL. IT->char_to_display is @@ -1609,6 +1611,12 @@ produce_glyphs (struct it *it) goto done; } + if (it->what == IT_GLYPHLESS) + { + produce_glyphless_glyph (it, 0, Qnil); + goto done; + } + if (it->char_to_display >= 040 && it->char_to_display < 0177) { it->pixel_width = it->nglyphs = 1; @@ -1660,11 +1668,22 @@ produce_glyphs (struct it *it) } else { - it->pixel_width = CHAR_WIDTH (it->char_to_display); - it->nglyphs = it->pixel_width; + Lisp_Object charset_list = FRAME_TERMINAL (it->f)->charset_list; - if (it->glyph_row) - append_glyph (it); + if (char_charset (it->char_to_display, charset_list, NULL)) + { + it->pixel_width = CHAR_WIDTH (it->char_to_display); + it->nglyphs = it->pixel_width; + if (it->glyph_row) + append_glyph (it); + } + else + { + Lisp_Object acronym = lookup_glyphless_char_display (-1, it); + + xassert (it->what == IT_GLYPHLESS); + produce_glyphless_glyph (it, 1, acronym); + } } done: @@ -1844,6 +1863,161 @@ produce_composite_glyph (struct it *it) } +/* Append a glyph for a glyphless character to IT->glyph_row. FACE_ID + is a face ID to be used for the glyph. What actually appended are + glyphs of type CHAR_GLYPH of which characters are in STR + (it->nglyphs bytes). */ + +static void +append_glyphless_glyph (struct it *it, int face_id, char *str) +{ + struct glyph *glyph, *end; + bidi_type_t bidi_type; + int resolved_level; + int i; + + xassert (it->glyph_row); + glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area]; + end = it->glyph_row->glyphs[1 + it->area]; + + /* If the glyph row is reversed, we need to prepend the glyph rather + than append it. */ + if (it->glyph_row->reversed_p && it->area == TEXT_AREA) + { + struct glyph *g; + int move_by = it->pixel_width; + + /* Make room for the new glyphs. */ + if (move_by > end - glyph) /* don't overstep end of this area */ + move_by = end - glyph; + for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--) + g[move_by] = *g; + glyph = it->glyph_row->glyphs[it->area]; + end = glyph + move_by; + } + + if (glyph >= end) + return; + glyph->type = CHAR_GLYPH; + glyph->pixel_width = 1; + glyph->face_id = face_id; + glyph->padding_p = 0; + glyph->charpos = CHARPOS (it->position); + glyph->object = it->object; + if (it->bidi_p) + { + glyph->resolved_level = it->bidi_it.resolved_level; + if ((it->bidi_it.type & 7) != it->bidi_it.type) + abort (); + glyph->bidi_type = it->bidi_it.type; + } + else + { + glyph->resolved_level = 0; + glyph->bidi_type = UNKNOWN_BT; + } + + /* BIDI Note: we put the glyphs of characters left to right, even in + the REVERSED_P case because we write to the terminal + left-to-right. */ + for (i = 0; i < it->nglyphs && glyph < end; ++i) + { + if (i > 0) + glyph[0] = glyph[-1]; + glyph->u.ch = str[i]; + ++it->glyph_row->used[it->area]; + ++glyph; + } +} + +/* Declared in xdisp.c */ +extern struct frame *last_glyphless_glyph_frame; +extern unsigned last_glyphless_glyph_face_id; +extern int last_glyphless_glyph_merged_face_id; +extern Lisp_Object Qglyphless_char; + +/* Produce glyphs for a glyphless character for iterator IT. + IT->glyphless_method specifies which method to use for displaying + the character. See the description of enum + glyphless_display_method in dispextern.h for the detail. + + FOR_NO_FONT is nonzero if and only if this is for a character that + is not supproted by the coding system of the terminal. ACRONYM, if + non-nil, is an acronym string for the character. + + The glyphs actually produced are of type CHAR_GLYPH. */ + +static void +produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym) +{ + int face_id; + struct face *face; + int width, len; + char buf[9], *str = " "; + + /* Get a face ID for the glyph by utilizing a cache (the same way as + doen for `escape-glyph' in get_next_display_element). */ + if (it->f == last_glyphless_glyph_frame + && it->face_id == last_glyphless_glyph_face_id) + { + face_id = last_glyphless_glyph_merged_face_id; + } + else + { + /* Merge the `glyphless-char' face into the current face. */ + face_id = merge_faces (it->f, Qglyphless_char, 0, it->face_id); + last_glyphless_glyph_frame = it->f; + last_glyphless_glyph_face_id = it->face_id; + last_glyphless_glyph_merged_face_id = face_id; + } + + if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE) + { + /* As there's no way to produce a thin space, we produce + a space of canonical width.. */ + len = 1; + } + else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX) + { + len = CHAR_WIDTH (it->c); + if (len == 0) + len = 1; + else if (width > 4) + len = 4; + } + else + { + if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM) + { + int i; + + if (! STRINGP (acronym) && CHAR_TABLE_P (Vglyphless_char_display)) + acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c); + buf[0] = '['; + str = STRINGP (acronym) ? (char *) SDATA (acronym) : ""; + for (len = 0; len < 6 && str[len] && ASCII_BYTE_P (str[len]); len++) + buf[1 + len] = str[len]; + buf[1 + len] = ']'; + len += 2; + } + else + { + xassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEXA_CODE); + len = (it->c < 0x100 ? sprintf (buf, "U+%02X", it->c) + : it->c < 0x10000 ? sprintf (buf, "U+%04X", it->c) + : it->c <= MAX_UNICODE_CHAR ? sprintf (buf, "U+%06X", it->c) + : sprintf (buf, "E+%06X", it->c)); + } + str = buf; + } + + it->pixel_width = len; + it->nglyphs = len; + if (len > 0 && it->glyph_row) + append_glyphless_glyph (it, face_id, str); +} + + /* Get information about special display element WHAT in an environment described by IT. WHAT is one of IT_TRUNCATION or 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 /* Parameter alist of this terminal. */ Lisp_Object param_alist; + /* List of charsets supported by the terminal. It is set by + Fset_terminal_coding_system_internal along with + the member terminal_coding. */ + Lisp_Object charset_list; + /* All fields before `next_terminal' should be Lisp_Object and are traced by the GC. All fields afterwards are ignored by the GC. */ 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) = get_next_display_element for each character element, and from x_produce_glyphs when no suitable font was found. */ -static Lisp_Object +Lisp_Object lookup_glyphless_char_display (int c, struct it *it) { Lisp_Object glyphless_method = Qnil; @@ -5780,7 +5780,6 @@ lookup_glyphless_char_display (int c, struct it *it) /* This method can't be used for the no-font case. */ glyphless_method = Qempty_box; } - it->what = IT_GLYPHLESS; if (EQ (glyphless_method, Qthin_space)) it->glyphless_method = GLYPHLESS_DISPLAY_THIN_SPACE; else if (EQ (glyphless_method, Qempty_box)) @@ -5795,6 +5794,7 @@ lookup_glyphless_char_display (int c, struct it *it) glyphless_method = Qnil; goto retry; } + it->what = IT_GLYPHLESS; return glyphless_method; } @@ -5806,9 +5806,9 @@ static struct frame *last_escape_glyph_frame = NULL; static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS); static int last_escape_glyph_merged_face_id = 0; -static struct frame *last_glyphless_glyph_frame = NULL; -static unsigned last_glyphless_glyph_face_id = (1 << FACE_ID_BITS); -static int last_glyphless_glyph_merged_face_id = 0; +struct frame *last_glyphless_glyph_frame = NULL; +unsigned last_glyphless_glyph_face_id = (1 << FACE_ID_BITS); +int last_glyphless_glyph_merged_face_id = 0; int 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, /* Produce a glyph for a glyphless character for iterator IT. IT->glyphless_method specifies which method to use for displaying - the glyph. See the description of enum glyphless_display_method in - dispextern.h for the default of the display methods. + the character. See the description of enum + glyphless_display_method in dispextern.h for the detail. FOR_NO_FONT is nonzero if and only if this is for a character for which no font was found. ACRONYM, if non-nil, is an acronym string -- 2.39.5