# HG changeset patch # User Kenichi Handa # Date 1288584566 -32400 # Node ID 6788b08ca42097419d7ba6964b00b44cd1457462 # Parent b8c31a27c55890a70eebf5aa56037ac1e7c7701f Handle glyphless characters on tty. diff -r b8c31a27c558 -r 6788b08ca420 lisp/ChangeLog --- a/lisp/ChangeLog Fri Oct 29 11:01:41 2010 +0900 +++ b/lisp/ChangeLog Mon Nov 01 13:09:26 2010 +0900 @@ -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 -r b8c31a27c558 -r 6788b08ca420 lisp/faces.el --- a/lisp/faces.el Fri Oct 29 11:01:41 2010 +0900 +++ b/lisp/faces.el Mon Nov 01 13:09:26 2010 +0900 @@ -2483,7 +2483,9 @@ "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 -r b8c31a27c558 -r 6788b08ca420 src/ChangeLog --- a/src/ChangeLog Fri Oct 29 11:01:41 2010 +0900 +++ b/src/ChangeLog Mon Nov 01 13:09:26 2010 +0900 @@ -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 -r b8c31a27c558 -r 6788b08ca420 src/coding.c --- a/src/coding.c Fri Oct 29 11:01:41 2010 +0900 +++ b/src/coding.c Mon Nov 01 13:09:26 2010 +0900 @@ -9297,7 +9297,8 @@ 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 @@ 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 -r b8c31a27c558 -r 6788b08ca420 src/dispextern.h --- a/src/dispextern.h Fri Oct 29 11:01:41 2010 +0900 +++ b/src/dispextern.h Mon Nov 01 13:09:26 2010 +0900 @@ -3021,7 +3021,7 @@ 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 -r b8c31a27c558 -r 6788b08ca420 src/term.c --- a/src/term.c Fri Oct 29 11:01:41 2010 +0900 +++ b/src/term.c Mon Nov 01 13:09:26 2010 +0900 @@ -1501,6 +1501,8 @@ 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 @@ 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 @@ } else { - it->pixel_width = CHAR_WIDTH (it->char_to_display); - it->nglyphs = it->pixel_width; - - if (it->glyph_row) - append_glyph (it); + Lisp_Object charset_list = FRAME_TERMINAL (it->f)->charset_list; + + 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 @@ } +/* 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 -r b8c31a27c558 -r 6788b08ca420 src/termhooks.h --- a/src/termhooks.h Fri Oct 29 11:01:41 2010 +0900 +++ b/src/termhooks.h Mon Nov 01 13:09:26 2010 +0900 @@ -328,6 +328,11 @@ /* 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 -r b8c31a27c558 -r 6788b08ca420 src/xdisp.c --- a/src/xdisp.c Fri Oct 29 11:01:41 2010 +0900 +++ b/src/xdisp.c Mon Nov 01 13:09:26 2010 +0900 @@ -5754,7 +5754,7 @@ 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 @@ /* 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 @@ glyphless_method = Qnil; goto retry; } + it->what = IT_GLYPHLESS; return glyphless_method; } @@ -5806,9 +5806,9 @@ 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 @@ /* 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