changeset 111237:6788b08ca420

Handle glyphless characters on tty.
author Kenichi Handa <handa@m17n.org>
date Mon, 01 Nov 2010 13:09:26 +0900
parents b8c31a27c558
children 00c31cf912da
files lisp/ChangeLog lisp/faces.el src/ChangeLog src/coding.c src/dispextern.h src/term.c src/termhooks.h src/xdisp.c
diffstat 8 files changed, 223 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- 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  <handa@m17n.org>
+
+	* faces.el (glyphless-char): Inherit underline for tty.
+
 2010-10-28  Kenichi Handa  <handa@m17n.org>
 
 	Implement various display methods for glyphless characters.
--- 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"
--- 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  <handa@m17n.org>
+
+	* 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  <handa@m17n.org>
 
 	* w32gui.h (STORE_XCHAR2B, XCHAR2B_BYTE1, XCHAR2B_BYTE2): Surround
--- 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;
 }
 
--- 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 *);
 
--- 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
--- 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.  */
 
--- 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