emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 6e5d81f: Improvements for curved quotes on Linux co


From: Paul Eggert
Subject: [Emacs-diffs] master 6e5d81f: Improvements for curved quotes on Linux consule
Date: Wed, 09 Sep 2015 09:22:28 +0000

branch: master
commit 6e5d81ff4536ed117dfac269357c46dbdc1890c9
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>

    Improvements for curved quotes on Linux consule
    
    This should help Emacs work better out-of-the-box on Linux consoles,
    which have only limited support for displaying Unicode characters.
    Also, undo the recent change that caused text-quoting-style to
    affect quote display on terminals, so that the two features are
    independent.  See Alan Mackenzie in:
    http://lists.gnu.org/archive/html/emacs-devel/2015-09/msg00244.html
    Finally, add a style parameter to startup--setup-quote-display,
    so that this function can also be invoked after startup, with
    different styles depending on user preference at the time.
    * configure.ac: Check for linux/kd.h header.
    * doc/emacs/display.texi (Text Display): Document quote display.
    * doc/lispref/display.texi (Active Display Table):
    * etc/NEWS:
    * lisp/startup.el (startup--setup-quote-display, command-line):
    text-quoting-style no longer affects quote display.
    * doc/lispref/frames.texi (Terminal Parameters): Fix typo.
    * lisp/international/mule-util.el (char-displayable-p):
    * lisp/startup.el (startup--setup-quote-display):
    On a text terminal supporting glyph codes, use the reported
    glyph codes instead of the terminal coding system, as this
    is more accurate on the Linux console.
    * lisp/startup.el (startup--setup-quote-display):
    New optional arg STYLE.
    * src/fontset.c (Finternal_char_font):
    Report glyph codes for a text terminal, if they are available.
    Currently this is supported only for the Linux console.
    * src/termhooks.h (struct terminal): New member glyph-code-table.
    * src/terminal.c [HAVE_LINUX_KD_H]: Include <errno.h>, <linux/kd.h>.
    (calculate_glyph_code_table) [HAVE_LINUX_KD_H]: New function.
    (terminal_glyph_code): New function.
---
 configure.ac                    |    1 +
 doc/emacs/display.texi          |    9 +++++
 doc/lispref/display.texi        |    6 +--
 doc/lispref/frames.texi         |    2 +-
 etc/NEWS                        |    3 +-
 lisp/international/mule-util.el |   77 +++++++++++++++++++++------------------
 lisp/startup.el                 |   73 ++++++++++++++++++++++++++++---------
 src/fontset.c                   |   21 +++++++----
 src/termhooks.h                 |    6 +++
 src/terminal.c                  |   66 +++++++++++++++++++++++++++++++++-
 10 files changed, 195 insertions(+), 69 deletions(-)

diff --git a/configure.ac b/configure.ac
index 9f8089f..cd828de 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1582,6 +1582,7 @@ fi
 
 dnl checks for header files
 AC_CHECK_HEADERS_ONCE(
+  linux/kd.h
   sys/systeminfo.h
   sys/sysinfo.h
   coff.h pty.h
diff --git a/doc/emacs/display.texi b/doc/emacs/display.texi
index 601a40b..92b0002 100644
--- a/doc/emacs/display.texi
+++ b/doc/emacs/display.texi
@@ -1480,6 +1480,15 @@ customizing the variable 
@code{glyphless-char-display-control}.
 @xref{Glyphless Chars,, Glyphless Character Display, elisp, The Emacs
 Lisp Reference Manual}, for details.
 
address@hidden curly quotes
address@hidden curved quotes
address@hidden escape-glyph face
+  If the curved quotes @samp{‘}, @samp{’}, @samp{“}, and @samp{”} are
+known to look just like @acronym{ASCII} characters, they are shown
+with the @code{escape-glyph} face.  Curved quotes that cannot be
+displayed are shown as their @acronym{ASCII} approximations @samp{`},
address@hidden'}, and @samp{"} with the @code{escape-glyph} face.
+
 @node Cursor Display
 @section Displaying the Cursor
 @cindex text cursor
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 14e2cd3..b5ff9cb 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -6533,10 +6533,8 @@ used when Emacs is displaying a buffer in a window with 
neither a
 window display table nor a buffer display table defined, or when Emacs
 is outputting text to the standard output or error streams.  Although its
 default is typically @code{nil}, in an interactive session if the
-locale cannot display curved quotes, or if the initial value of
address@hidden specifies a preference for ASCII, its
-default maps curved quotes to ASCII approximations.  @xref{Keys in
-Documentation}.
+terminal cannot display curved quotes, its default maps curved quotes
+to ASCII approximations.  @xref{Keys in Documentation}.
 @end defvar
 
 The @file{disp-table} library defines several functions for changing
diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi
index 16fc495..23590af 100644
--- a/doc/lispref/frames.texi
+++ b/doc/lispref/frames.texi
@@ -1781,7 +1781,7 @@ symbol) of @var{terminal}.  If @var{terminal} has no 
setting for
 @end defun
 
 @defun set-terminal-parameter terminal parameter value
-This function sets the parameter @var{parm} of @var{terminal} to the
+This function sets the parameter @var{parameter} of @var{terminal} to the
 specified @var{value}, and returns the previous value of that
 parameter.
 @end defun
diff --git a/etc/NEWS b/etc/NEWS
index 8a08a06..2f2bd15 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1125,8 +1125,7 @@ integers.
 of the Emacs process to binary I/O mode.
 
 ** ASCII approximations to curved quotes are put in standard-display-table
-if the locale cannot display curved quotes, or if text-quoting-style
-initially specifies a preference for ASCII.
+if the terminal cannot display curved quotes.
 
 ** Standard output and error streams now transliterate characters via
 standard-display-table, and encode output using locale-coding-system.
diff --git a/lisp/international/mule-util.el b/lisp/international/mule-util.el
index f3aa70f..9025863 100644
--- a/lisp/international/mule-util.el
+++ b/lisp/international/mule-util.el
@@ -273,43 +273,48 @@ per-character basis, this may not be accurate."
        ((not enable-multibyte-characters)
         ;; Maybe there's a font for it, but we can't put it in the buffer.
         nil)
-       ((display-multi-font-p)
-        ;; On a window system, a character is displayable if we have
-        ;; a font for that character in the default face of the
-        ;; currently selected frame.
-        (car (internal-char-font nil char)))
        (t
-        ;; On a terminal, a character is displayable if the coding
-        ;; system for the terminal can encode it.
-        (let ((coding (terminal-coding-system)))
-          (when coding
-            (let ((cs-list (coding-system-get coding :charset-list)))
-              (cond
-                ((listp cs-list)
-                 (catch 'tag
-                   (mapc #'(lambda (charset)
-                             (if (encode-char char charset)
-                                 (throw 'tag charset)))
-                         cs-list)
-                   nil))
-                ((eq cs-list 'iso-2022)
-                 (catch 'tag2
-                   (mapc #'(lambda (charset)
-                             (if (and (plist-get (charset-plist charset)
-                                                 :iso-final-char)
-                                      (encode-char char charset))
-                                 (throw 'tag2 charset)))
-                         charset-list)
-                   nil))
-                ((eq cs-list 'emacs-mule)
-                 (catch 'tag3
-                   (mapc #'(lambda (charset)
-                             (if (and (plist-get (charset-plist charset)
-                                                 :emacs-mule-id)
-                                      (encode-char char charset))
-                                 (throw 'tag3 charset)))
-                         charset-list)
-                   nil)))))))))
+        (let ((font-glyph (internal-char-font nil char)))
+          (if font-glyph
+              (if (consp font-glyph)
+                  ;; On a window system, a character is displayable
+                  ;; if a font for that character is in the default
+                  ;; face of the currently selected frame.
+                  (car font-glyph)
+                ;; On a text terminal supporting glyph codes, CHAR is
+                ;; displayable if its glyph code is nonnegative.
+                (<= 0 font-glyph))
+            ;; On a teext terminal without glyph codes, CHAR is displayable
+            ;; if the coding system for the terminal can encode it.
+            (let ((coding (terminal-coding-system)))
+              (when coding
+                (let ((cs-list (coding-system-get coding :charset-list)))
+                  (cond
+                   ((listp cs-list)
+                    (catch 'tag
+                      (mapc #'(lambda (charset)
+                                (if (encode-char char charset)
+                                    (throw 'tag charset)))
+                            cs-list)
+                      nil))
+                   ((eq cs-list 'iso-2022)
+                    (catch 'tag2
+                      (mapc #'(lambda (charset)
+                                (if (and (plist-get (charset-plist charset)
+                                                    :iso-final-char)
+                                         (encode-char char charset))
+                                    (throw 'tag2 charset)))
+                            charset-list)
+                      nil))
+                   ((eq cs-list 'emacs-mule)
+                    (catch 'tag3
+                      (mapc #'(lambda (charset)
+                                (if (and (plist-get (charset-plist charset)
+                                                    :emacs-mule-id)
+                                         (encode-char char charset))
+                                    (throw 'tag3 charset)))
+                            charset-list)
+                      nil)))))))))))
 
 (defun filepos-to-bufferpos--dos (byte f)
   (let ((eol-offset 0)
diff --git a/lisp/startup.el b/lisp/startup.el
index 9caf485..971841f 100644
--- a/lisp/startup.el
+++ b/lisp/startup.el
@@ -803,19 +803,61 @@ to prepare for opening the first frame (e.g. open a 
connection to an X server)."
 (defvar server-name)
 (defvar server-process)
 
-(defun startup--setup-quote-display ()
-  "Display ASCII approximations on user request or if curved quotes don't 
work."
-  (when (memq text-quoting-style '(nil grave straight))
-    (dolist (char-repl '((?‘ . ?\`) (?’ . ?\') (?“ . ?\") (?” . ?\")))
-      (let ((char (car char-repl))
-            (repl (cdr char-repl)))
-        (when (or text-quoting-style (not (char-displayable-p char)))
-          (when (and (eq repl ?\`) (eq text-quoting-style 'straight))
-            (setq repl ?\'))
-          (unless standard-display-table
-            (setq standard-display-table (make-display-table)))
-          (aset standard-display-table char
-                (vector (make-glyph-code repl 'shadow))))))))
+(defun startup--setup-quote-display (&optional style)
+  "If needed, display ASCII approximations to curved quotes.
+Do this by modifying `standard-display-table'.  Optional STYLE
+specifies the desired quoting style, as in `text-quoting-style'.
+If STYLE is nil, display appropriately for the terminal."
+  (let ((repls (let ((style-repls (assq style '((grave . "`'\"\"")
+                                                (straight . "''\"\"")))))
+                 (if style-repls (cdr style-repls) (make-vector 4 nil))))
+        glyph-count)
+    ;; REPLS is a sequence of the four replacements for "‘’“”", respectively.
+    ;; If STYLE is nil, infer REPLS from terminal characteristics.
+    (unless style
+      ;; On a terminal that supports glyph codes,
+      ;; GLYPH-COUNT[i] is the number of times that glyph code I
+      ;; represents either an ASCII character or one of the 4
+      ;; quote characters.  This assumes glyph codes are valid
+      ;; Elisp characters, which is a safe assumption in practice.
+      (when (integerp (internal-char-font nil (max-char)))
+        (setq glyph-count (make-char-table nil 0))
+        (dotimes (i 132)
+          (let ((glyph (internal-char-font
+                        nil (if (< i 128) i (aref "‘’“”" (- i 128))))))
+            (when (<= 0 glyph)
+              (aset glyph-count glyph (1+ (aref glyph-count glyph)))))))
+      (dotimes (i 2)
+        (let ((lq (aref "‘“" i)) (rq (aref "’”" i))
+              (lr (aref "`\"" i)) (rr (aref "'\"" i))
+              (i2 (* i 2)))
+          (unless (if glyph-count
+                      ;; On a terminal that supports glyph codes, use
+                      ;; ASCII replacements unless both quotes are displayable.
+                      ;; If not using ASCII replacements, highlight
+                      ;; quotes unless they are both unique among the
+                      ;; 128 + 4 characters of concern.
+                      (let ((lglyph (internal-char-font nil lq))
+                            (rglyph (internal-char-font nil rq)))
+                        (when (and (<= 0 lglyph) (<= 0 rglyph))
+                          (setq lr lq rr rq)
+                          (and (= 1 (aref glyph-count lglyph))
+                               (= 1 (aref glyph-count rglyph)))))
+                    ;; On a terminal that does not support glyph codes, use
+                    ;; ASCII replacements unless both quotes are displayable.
+                    (and (char-displayable-p lq)
+                         (char-displayable-p rq)))
+            (aset repls i2 lr)
+            (aset repls (1+ i2) rr)))))
+    (dotimes (i 4)
+      (let ((char (aref "‘’“”" i))
+            (repl (aref repls i)))
+        (if repl
+            (aset (or standard-display-table
+                      (setq standard-display-table (make-display-table)))
+                  char (vector (make-glyph-code repl 'escape-glyph)))
+          (when standard-display-table
+            (aset standard-display-table char nil)))))))
 
 (defun command-line ()
   "A subroutine of `normal-top-level'.
@@ -1239,11 +1281,6 @@ the `--debug-init' option to view a complete error 
backtrace."
        ;; unibyte (display table, terminal coding system &c).
        (set-language-environment current-language-environment)))
 
-    ;; Setup quote display again, if the init file sets
-    ;; text-quoting-style to a non-nil value.
-    (when (and (not noninteractive) text-quoting-style)
-      (startup--setup-quote-display))
-
     ;; Do this here in case the init file sets mail-host-address.
     (if (equal user-mail-address "")
        (setq user-mail-address (or (getenv "EMAIL")
diff --git a/src/fontset.c b/src/fontset.c
index 50fcc64..f8334f1 100644
--- a/src/fontset.c
+++ b/src/fontset.c
@@ -1786,18 +1786,23 @@ update_auto_fontset_alist (Lisp_Object font_object, 
Lisp_Object fontset)
       }
 }
 
+/* Return a description of the font at POSITION in the current buffer.
+   If the 2nd optional arg CH is non-nil, it is a character to check
+   the font instead of the character at POSITION.
 
-/* Return a cons (FONT-OBJECT . GLYPH-CODE).
+   For a graphical display, return a cons (FONT-OBJECT . GLYPH-CODE).
    FONT-OBJECT is the font for the character at POSITION in the current
    buffer.  This is computed from all the text properties and overlays
    that apply to POSITION.  POSITION may be nil, in which case,
    FONT-SPEC is the font for displaying the character CH with the
-   default face.
+   default face.  GLYPH-CODE is the glyph code in the font to use for
+   the character.
 
-   GLYPH-CODE is the glyph code in the font to use for the character.
-
-   If the 2nd optional arg CH is non-nil, it is a character to check
-   the font instead of the character at POSITION.
+   For a text terminal, return a nonnegative integer glyph code for
+   the character, or a negative integer if the character is not
+   displayable.  Terminal glyph codes are system-dependent integers
+   that represent displayable characters: for example, on a Linux x86
+   console they represent VGA code points.
 
    It returns nil in the following cases:
 
@@ -1809,6 +1814,8 @@ update_auto_fontset_alist (Lisp_Object font_object, 
Lisp_Object fontset)
    (3) If POSITION is not nil, and the current buffer is not displayed
    in any window.
 
+   (4) For a text terminal, the terminal does not report glyph codes.
+
    In addition, the returned font name may not take into account of
    such redisplay engine hooks as what used in jit-lock-mode if
    POSITION is currently not visible.  */
@@ -1860,7 +1867,7 @@ DEFUN ("internal-char-font", Finternal_char_font, 
Sinternal_char_font, 1, 2, 0,
   if (! CHAR_VALID_P (c))
     return Qnil;
   if (!FRAME_WINDOW_P (f))
-    return Qnil;
+    return terminal_glyph_code (FRAME_TERMINAL (f), c);
   /* We need the basic faces to be valid below, so recompute them if
      some code just happened to clear the face cache.  */
   if (FRAME_FACE_CACHE (f)->used == 0)
diff --git a/src/termhooks.h b/src/termhooks.h
index 168bc35..88c62df 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -383,6 +383,11 @@ struct terminal
     the selection-values.  */
   Lisp_Object Vselection_alist;
 
+  /* If a char-table, this maps characters to terminal glyph codes.
+     If t, the mapping is not available.  If nil, it is not known
+     whether the mapping is available.  */
+  Lisp_Object glyph_code_table;
+
   /* All fields before `next_terminal' should be Lisp_Object and are traced
      by the GC.  All fields afterwards are ignored by the GC.  */
 
@@ -690,6 +695,7 @@ extern struct terminal *get_named_terminal (const char *);
 extern struct terminal *create_terminal (enum output_method,
                                         struct redisplay_interface *);
 extern void delete_terminal (struct terminal *);
+extern Lisp_Object terminal_glyph_code (struct terminal *, int);
 
 /* The initial terminal device, created by initial_term_init.  */
 extern struct terminal *initial_terminal;
diff --git a/src/terminal.c b/src/terminal.c
index b48d062..15d74f4 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -28,6 +28,11 @@ along with GNU Emacs.  If not, see 
<http://www.gnu.org/licenses/>.  */
 #include "coding.h"
 #include "keyboard.h"
 
+#ifdef HAVE_LINUX_KD_H
+# include <errno.h>
+# include <linux/kd.h>
+#endif
+
 /* Chain of all terminals currently in use.  */
 struct terminal *terminal_list;
 
@@ -193,7 +198,7 @@ ins_del_lines (struct frame *f, int vpos, int n)
 }
 
 /* Return the terminal object specified by TERMINAL.  TERMINAL may
-   be a terminal object, a frame, or nil for the terminal device of
+”   be a terminal object, a frame, or nil for the terminal device of
    the current frame.  If TERMINAL is neither from the above or the
    resulting terminal object is deleted, return NULL.  */
 
@@ -526,6 +531,65 @@ selected frame's terminal).  */)
   return store_terminal_param (decode_live_terminal (terminal), parameter, 
value);
 }
 
+#if HAVE_LINUX_KD_H
+
+/* Compute the glyph code table for T.  */
+
+static void
+calculate_glyph_code_table (struct terminal *t)
+{
+  Lisp_Object glyphtab = Qt;
+  enum { initial_unipairs = 1000 };
+  int entry_ct = initial_unipairs;
+  struct unipair unipair_buffer[initial_unipairs];
+  struct unipair *entries = unipair_buffer;
+  struct unipair *alloced = 0;
+
+  while (true)
+    {
+      int fd = fileno (t->display_info.tty->output);
+      struct unimapdesc unimapdesc = { entry_ct, entries };
+      if (ioctl (fd, GIO_UNIMAP, &unimapdesc) == 0)
+       {
+         glyphtab = Fmake_char_table (Qnil, make_number (-1));
+         for (int i = 0; i < unimapdesc.entry_ct; i++)
+           char_table_set (glyphtab, entries[i].unicode,
+                           make_number (entries[i].fontpos));
+         break;
+       }
+      if (errno != ENOMEM)
+       break;
+      entry_ct = unimapdesc.entry_ct;
+      entries = alloced = xrealloc (alloced, entry_ct * sizeof *alloced);
+    }
+
+  xfree (alloced);
+  t->glyph_code_table = glyphtab;
+}
+#endif
+
+/* Return the glyph code in T of character CH, or -1 if CH does not
+   have a font position in T, or nil if T does not report glyph codes.  */
+
+Lisp_Object
+terminal_glyph_code (struct terminal *t, int ch)
+{
+#if HAVE_LINUX_KD_H
+  if (t->type == output_termcap)
+    {
+      /* As a hack, recompute the table when CH is the maximum
+        character.  */
+      if (NILP (t->glyph_code_table) || ch == MAX_CHAR)
+       calculate_glyph_code_table (t);
+
+      if (! EQ (t->glyph_code_table, Qt))
+       return char_table_ref (t->glyph_code_table, ch);
+    }
+#endif
+
+  return Qnil;
+}
+
 /* Initial frame has no device-dependent output data, but has
    face cache which should be freed when the frame is deleted.  */
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]