]> git.eshelyaron.com Git - emacs.git/commitdiff
Improvements for curved quotes on Linux consule
authorPaul Eggert <eggert@cs.ucla.edu>
Wed, 9 Sep 2015 09:21:16 +0000 (02:21 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Wed, 9 Sep 2015 09:22:24 +0000 (02:22 -0700)
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
doc/emacs/display.texi
doc/lispref/display.texi
doc/lispref/frames.texi
etc/NEWS
lisp/international/mule-util.el
lisp/startup.el
src/fontset.c
src/termhooks.h
src/terminal.c

index 9f8089f8809f93e51c9e317c6113d0fe8eecbaa5..cd828dedc9d3b1020cb1e584a8ba554380f00f59 100644 (file)
@@ -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
index 601a40bd176d505e88d7e021126b787d3903cb6a..92b0002990f57a98195863b5df4c5978cb243e15 100644 (file)
@@ -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.
 
+@cindex curly quotes
+@cindex curved quotes
+@cindex 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{`},
+@samp{'}, and @samp{"} with the @code{escape-glyph} face.
+
 @node Cursor Display
 @section Displaying the Cursor
 @cindex text cursor
index 14e2cd363a4eff1e2fbe6639327bf3017a7e4dd9..b5ff9cb6e76404400ab6c2c74bf11c0c4212dcf8 100644 (file)
@@ -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
-@code{text-quoting-style} 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
index 16fc4958d1f5c9facd84cb3f7816af1a43f2bda9..23590af77746fa36b81d7402e5d0421b6142007a 100644 (file)
@@ -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
index 8a08a065ba98a527cbeb0a4f81a659ad9273bd73..2f2bd157dd7da354c50fa201337887b3bb433abc 100644 (file)
--- 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.
index f3aa70fd66c5cc36bc413753807001ecf243ce4d..90258636464579805622d18988e64cf848ff76a9 100644 (file)
@@ -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)
index 9caf485c1e831e46ba62c9cbd330c8c619042b9e..971841fc0db092e4837232d3513a368c56c095e9 100644 (file)
@@ -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")
index 50fcc64854803daa06168aac67e86b689be92d11..f8334f16e55f49b8fa2deba57cf5658a89fb771f 100644 (file)
@@ -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)
index 168bc3510fac3a57b113f7b1113e9dd1b022bbe7..88c62df7205397785489125a6ff2291239b4201f 100644 (file)
@@ -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;
index b48d0623e126822ec197cb8859eacfe2c253361a..15d74f4e812ce811db67bd016152e296345b6e05 100644 (file)
@@ -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.  */