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.
This commit is contained in:
Paul Eggert 2015-09-09 02:21:16 -07:00
parent 39dca94701
commit 6e5d81ff45
10 changed files with 195 additions and 69 deletions

View 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

View 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

View 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

View 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

View file

@ -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.

View 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)

View 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")

View 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)

View 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;

View 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. */