]> code.delx.au - gnu-emacs/blobdiff - lisp/international/characters.el
Further mule-menu-keymap doc tweak
[gnu-emacs] / lisp / international / characters.el
index fb7c573ceacb48bbf8b2b510b684309fccf8fecd..c75ca8106acba984fb1820d5e785a3ee4880ecf9 100644 (file)
@@ -1,9 +1,8 @@
 ;;; characters.el --- set syntax and category for multibyte characters
 
-;; Copyright (C) 1997, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
-;;   Free Software Foundation, Inc.
+;; Copyright (C) 1997, 2000-2012  Free Software Foundation, Inc.
 ;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-;;   2005, 2006, 2007, 2008, 2009, 2010
+;;   2005, 2006, 2007, 2008, 2009, 2010, 2011
 ;;   National Institute of Advanced Industrial Science and Technology (AIST)
 ;;   Registration Number H14PRO021
 ;; Copyright (C) 2003
@@ -115,6 +114,16 @@ A character which can't be placed at end of line.")
 Base characters (Unicode General Category L,N,P,S,Zs)")
 (define-category ?^ "Combining
 Combining diacritic or mark (Unicode General Category M)")
+
+;; bidi types
+(define-category ?R "Right-to-left (strong)
+Characters with \"strong\" right-to-left directionality, i.e.
+with R, AL, RLE, or RLO Unicode bidi character type.")
+
+(define-category ?L "Left-to-right (strong)
+Characters with \"strong\" left-to-right directionality, i.e.
+with L, LRE, or LRO Unicode bidi character type.")
+
 \f
 ;;; Setting syntax and category.
 
@@ -188,6 +197,9 @@ Combining diacritic or mark (Unicode General Category M)")
                               cp932-2-byte))
   (map-charset-chars #'modify-category-entry l ?j))
 
+;; Fullwidth characters
+(modify-category-entry '(#xff01 . #xff60) ?\|)
+
 ;; Unicode equivalents of JISX0201-kana
 (let ((range '(#xff61 . #xff9f)))
   (modify-category-entry range  ?k)
@@ -398,7 +410,7 @@ Combining diacritic or mark (Unicode General Category M)")
                  ("ྐ-ྐྵྺྻྼ"       "w"     ?0) ;
                  ("ིེཻོཽྀ"       "w"       ?2) ; upper vowel
                  ("ཾྂྃ྆྇ྈྉྊྋ" "w"    ?2) ; upper modifier
-                 ("྄ཱུ༙༵༷"       "w"       ?3) ; lowel vowel/modifier
+                 ("྄ཱུ༙༵༷"       "w"       ?3) ; lower vowel/modifier
                  ("཰"                "w" ?3)             ; invisible vowel a
                  ("༠-༩༪-༳"             "w"     ?6) ; digit
                  ("་།-༒༔ཿ"        "."     ?|) ; line-break char
@@ -454,7 +466,7 @@ Combining diacritic or mark (Unicode General Category M)")
 
 ;; Tai Viet
 (let ((deflist '(;; chars      syntax  category
-                ((?ꪀ.  ?ꪯ) "w"     ?0) ; cosonant
+                ((?ꪀ.  ?ꪯ) "w"     ?0) ; consonant
                 ("ꪱꪵꪶ"           "w"     ?1) ; vowel base
                 ((?ꪹ . ?ꪽ) "w"     ?1) ; vowel base
                 ("ꪰꪲꪳꪷꪸꪾ"  "w"     ?2) ; vowel upper
@@ -476,6 +488,16 @@ Combining diacritic or mark (Unicode General Category M)")
                  (modify-category-entry x category))
              chars)))))
 
+;; Bidi categories
+
+(map-char-table (lambda (key val)
+                 (cond
+                  ((memq val '(R AL RLO RLE))
+                   (modify-category-entry key ?R))
+                  ((memq val '(L LRE LRO))
+                   (modify-category-entry key ?L))))
+               (unicode-property-table-internal 'bidi-class))
+
 ;; Latin
 
 (modify-category-entry '(#x80 . #x024F) ?l)
@@ -490,7 +512,7 @@ Combining diacritic or mark (Unicode General Category M)")
   ;; relating Unicode categories to Emacs syntax codes.
 
   ;; NBSP isn't semantically interchangeable with other whitespace chars,
-  ;; so it's more like punctation.
+  ;; so it's more like punctuation.
   (set-case-syntax ?  "." tbl)
   (set-case-syntax ?¡ "." tbl)
   (set-case-syntax ?¦ "_" tbl)
@@ -538,6 +560,7 @@ Combining diacritic or mark (Unicode General Category M)")
                       (#x01AC . #x01AD)
                       (#x01AF . #x01B0)
                       (#x01B3 . #x01B6)
+                      (#x01B8 . #x01B9)
                       (#x01BC . #x01BD)
                       (#x01CD . #x01DC)
                       (#x01DE . #x01EF)
@@ -553,8 +576,7 @@ Combining diacritic or mark (Unicode General Category M)")
          (set-case-syntax-pair from (1+ from) tbl)
          (setq from (+ from 2))))))
 
-  (set-case-syntax-pair #x189 #x256 tbl)
-  (set-case-syntax-pair #x18A #x257 tbl)
+  (set-case-syntax-pair ?Ÿ ?ÿ tbl)
 
   ;; In some languages, such as Turkish, U+0049 LATIN CAPITAL LETTER I
   ;; and U+0131 LATIN SMALL LETTER DOTLESS I make a case pair, and so
@@ -568,6 +590,26 @@ Combining diacritic or mark (Unicode General Category M)")
   ;; (set-downcase-syntax  ?İ ?i tbl)
   ;; (set-upcase-syntax    ?I ?ı tbl)
 
+  (set-case-syntax-pair ?Ɓ ?ɓ tbl)
+  (set-case-syntax-pair ?Ɔ ?ɔ tbl)
+  (set-case-syntax-pair ?Ɖ ?ɖ tbl)
+  (set-case-syntax-pair ?Ɗ ?ɗ tbl)
+  (set-case-syntax-pair ?Ǝ ?ǝ tbl)
+  (set-case-syntax-pair ?Ə ?ə tbl)
+  (set-case-syntax-pair ?Ɛ ?ɛ tbl)
+  (set-case-syntax-pair ?Ɠ ?ɠ tbl)
+  (set-case-syntax-pair ?Ɣ ?ɣ tbl)
+  (set-case-syntax-pair ?Ɩ ?ɩ tbl)
+  (set-case-syntax-pair ?Ɨ ?ɨ tbl)
+  (set-case-syntax-pair ?Ɯ ?ɯ tbl)
+  (set-case-syntax-pair ?Ɲ ?ɲ tbl)
+  (set-case-syntax-pair ?Ɵ ?ɵ tbl)
+  (set-case-syntax-pair ?Ʀ ?ʀ tbl)
+  (set-case-syntax-pair ?Ʃ ?ʃ tbl)
+  (set-case-syntax-pair ?Ʈ ?ʈ tbl)
+  (set-case-syntax-pair ?Ʊ ?ʊ tbl)
+  (set-case-syntax-pair ?Ʋ ?ʋ tbl)
+  (set-case-syntax-pair ?Ʒ ?ʒ tbl)
   (set-case-syntax-pair ?DŽ ?dž tbl)
   (set-case-syntax-pair ?Dž ?dž tbl)
   (set-case-syntax-pair ?LJ ?lj tbl)
@@ -580,6 +622,12 @@ Combining diacritic or mark (Unicode General Category M)")
   (set-case-syntax-pair ?Dz ?dz tbl)
   (set-case-syntax-pair ?Ƕ ?ƕ tbl)
   (set-case-syntax-pair ?Ƿ ?ƿ tbl)
+  (set-case-syntax-pair ?Ⱥ ?ⱥ tbl)
+  (set-case-syntax-pair ?Ƚ ?ƚ tbl)
+  (set-case-syntax-pair ?Ⱦ ?ⱦ tbl)
+  (set-case-syntax-pair ?Ƀ ?ƀ tbl)
+  (set-case-syntax-pair ?Ʉ ?ʉ tbl)
+  (set-case-syntax-pair ?Ʌ ?ʌ tbl)
 
   ;; Latin Extended Additional
   (modify-category-entry '(#x1e00 . #x1ef9) ?l)
@@ -1092,6 +1140,12 @@ Setup char-width-table appropriate for non-CJK language environment."
 \f
 ;; Setting char-script-table.
 
+;; The data is compiled from Blocks.txt and Scripts.txt in the
+;; "Unicode Character Database", simplified to lump together all the
+;; blocks belonging to the same language.  E.g., "Basic Latin",
+;; "Latin-1 Supplement", "Latin Extended-A", etc. are all lumped
+;; together under "latin".
+;;
 ;; The Unicode blocks actually extend past some of these ranges with
 ;; undefined codepoints.
 (let ((script-list nil))
@@ -1104,13 +1158,17 @@ Setup char-width-table appropriate for non-CJK language environment."
         (#x0370 #x03E1 greek)
         (#x03E2 #x03EF coptic)
         (#x03F0 #x03F3 greek)
-        (#x0400 #x04FF cyrillic)
+        (#x0400 #x052F cyrillic)
         (#x0530 #x058F armenian)
         (#x0590 #x05FF hebrew)
         (#x0600 #x06FF arabic)
         (#x0700 #x074F syriac)
-        (#x07C0 #x07FA nko)
+        (#x0750 #x077F arabic)
         (#x0780 #x07BF thaana)
+        (#x07C0 #x07FF nko)
+        (#x0800 #x083F samaritan)
+        (#x0840 #x085F mandaic)
+        (#x08A0 #x08FF arabic)
         (#x0900 #x097F devanagari)
         (#x0980 #x09FF bengali)
         (#x0A00 #x0A7F gurmukhi)
@@ -1121,10 +1179,10 @@ Setup char-width-table appropriate for non-CJK language environment."
         (#x0C80 #x0CFF kannada)
         (#x0D00 #x0D7F malayalam)
         (#x0D80 #x0DFF sinhala)
-        (#x0E00 #x0E5F thai)
-        (#x0E80 #x0EDF lao)
+        (#x0E00 #x0E7F thai)
+        (#x0E80 #x0EFF lao)
         (#x0F00 #x0FFF tibetan)
-        (#x1000 #x109F myanmar)
+        (#x1000 #x109F burmese) ; according to Unicode 6.1, should be "myanmar"
         (#x10A0 #x10FF georgian)
         (#x1100 #x11FF hangul)
         (#x1200 #x139F ethiopic)
@@ -1132,14 +1190,40 @@ Setup char-width-table appropriate for non-CJK language environment."
         (#x1400 #x167F canadian-aboriginal)
         (#x1680 #x169F ogham)
         (#x16A0 #x16FF runic)
+        (#x1700 #x171F tagalog)
+        (#x1720 #x173F hanunoo)
+        (#x1740 #x175F buhid)
+        (#x1760 #x177F tagbanwa)
         (#x1780 #x17FF khmer)
         (#x1800 #x18AF mongolian)
-        (#x1D00 #x1DFF phonetic)
-        (#x1E00 #x1EFF latin)
+        (#x18B0 #x18FF canadian-aboriginal)
+        (#x1900 #x194F limbu)
+        (#x1950 #x197F tai-le)
+        (#x1980 #x19DF tai-lue)
+        (#x19E0 #x19FF khmer)
+        (#x1A00 #x1A00 buginese)
+        (#x1A20 #x1AAF tai-tham)
+        (#x1B00 #x1B7F balinese)
+        (#x1B80 #x1BBF sundanese)
+        (#x1BC0 #x1BFF batak)
+        (#x1C00 #x1C4F lepcha)
+        (#x1C50 #x1C7F ol-chiki)
+        (#x1CC0 #x1CCF sundanese)
+        (#x1CD0 #x1CFF vedic)
+        (#x1D00 #x1DBF phonetic)
+        (#x1DC0 #x1EFF latin)
         (#x1F00 #x1FFF greek)
         (#x2000 #x27FF symbol)
         (#x2800 #x28FF braille)
+        (#x2900 #x2BFF symbol)
+        (#x2C00 #x2C5F glagolitic)
+        (#x2C60 #x2C7F latin)
+        (#x2C80 #x2CFF coptic)
+        (#x2D00 #x2D2F georgian)
+        (#x2D30 #x2D7F tifinagh)
         (#x2D80 #x2DDF ethiopic)
+        (#x2DE0 #x2DFF cyrillic)
+        (#x2E00 #x2E7F symbol)
         (#x2E80 #x2FDF han)
         (#x2FF0 #x2FFF ideographic-description)
         (#x3000 #x303F cjk-misc)
@@ -1148,47 +1232,92 @@ Setup char-width-table appropriate for non-CJK language environment."
         (#x3130 #x318F hangul)
         (#x3190 #x319F kanbun)
         (#x31A0 #x31BF bopomofo)
-        (#x3400 #x9FAF han)
+        (#x31C0 #x31EF cjk-misc)
+        (#x31F0 #x31FF kana)
+        (#x3200 #x9FAF han)
         (#xA000 #xA4CF yi)
+        (#xA4D0 #xA4FF lisu)
+        (#xA500 #xA63F vai)
+        (#xA640 #xA69F cyrillic)
+        (#xA6A0 #xA6FF bamum)
+        (#xA700 #xA7FF latin)
+        (#xA800 #xA82F syloti-nagri)
+        (#xA830 #xA83F north-indic-number)
+        (#xA840 #xA87F phags-pa)
+        (#xA880 #xA8DF saurashtra)
+        (#xA8E0 #xA8FF devanagari)
+        (#xA900 #xA92F kayah-li)
+        (#xA930 #xA95F rejang)
+        (#xA960 #xA97F hangul)
+        (#xA980 #xA9DF javanese)
         (#xAA00 #xAA5F cham)
-        (#xAA60 #xAA7B myanmar)
+        (#xAA60 #xAA7B burmese)        ; Unicode 6.1: "myanmar"
         (#xAA80 #xAADF tai-viet)
-        (#xAC00 #xD7AF hangul)
+        (#xAAE0 #xAAFF meetei-mayek)
+        (#xAB00 #xAB2F ethiopic)
+        (#xABC0 #xABFF meetei-mayek)
+        (#xAC00 #xD7FF hangul)
         (#xF900 #xFAFF han)
         (#xFB1D #xFB4F hebrew)
         (#xFB50 #xFDFF arabic)
-        (#xFE70 #xFEFC arabic)
+        (#xFE30 #xFE4F han)
+        (#xFE70 #xFEFF arabic)
         (#xFF00 #xFF5F cjk-misc)
         (#xFF61 #xFF9F kana)
         (#xFFE0 #xFFE6 cjk-misc)
         (#x10000 #x100FF linear-b)
         (#x10100 #x1013F aegean-number)
-        (#x10140 #x1018A ancient-greek-number)
-        (#x10190 #x1019B ancient-symbol)
+        (#x10140 #x1018F ancient-greek-number)
+        (#x10190 #x101CF ancient-symbol)
         (#x101D0 #x101FF phaistos-disc)
         (#x10280 #x1029F lycian)
         (#x102A0 #x102DF carian)
         (#x10300 #x1032F olt-italic)
+        (#x10330 #x1034F gothic)
         (#x10380 #x1039F ugaritic)
         (#x103A0 #x103DF old-persian)
         (#x10400 #x1044F deseret)
         (#x10450 #x1047F shavian)
         (#x10480 #x104AF osmanya)
         (#x10800 #x1083F cypriot-syllabary)
+        (#x10840 #x1085F aramaic)
         (#x10900 #x1091F phoenician)
         (#x10920 #x1093F lydian)
+        (#x10980 #x109FF meroitic)
         (#x10A00 #x10A5F kharoshthi)
+        (#x10A60 #x10A7F old-south-arabian)
+        (#x10B00 #x10B3F avestan)
+        (#x10B40 #x10B5F inscriptional-parthian)
+        (#x10B60 #x10B7F inscriptional-pahlavi)
+        (#x10C00 #x10C4F old-turkic)
+        (#x10E60 #x10E7F rumi-number)
+        (#x11000 #x1107F brahmi)
+        (#x11080 #x110CF kaithi)
+        (#x110D0 #x110FF sora-sompeng)
+        (#x11100 #x1114F chakma)
+        (#x11180 #x111DF sharada)
+        (#x11680 #x116CF takri)
         (#x12000 #x123FF cuneiform)
         (#x12400 #x1247F cuneiform-numbers-and-punctuation)
+        (#x13000 #x1342F egyptian)
+        (#x16800 #x16A3F bamum)
+        (#x16F00 #x16F9F miao)
+        (#x1B000 #x1B0FF kana)
         (#x1D000 #x1D0FF byzantine-musical-symbol)
         (#x1D100 #x1D1FF musical-symbol)
         (#x1D200 #x1D24F ancient-greek-musical-notation)
         (#x1D300 #x1D35F tai-xuan-jing-symbol)
         (#x1D360 #x1D37F counting-rod-numeral)
         (#x1D400 #x1D7FF mathematical)
+        (#x1EE00 #x1EEFF arabic)
         (#x1F000 #x1F02F mahjong-tile)
         (#x1F030 #x1F09F domino-tile)
-        (#x20000 #x2AFFF han)
+        (#x1F0A0 #x1F0FF playing-cards)
+        (#x1F100 #x1F1FF symbol)
+        (#x1F200 #x1F2FF han)
+        (#x1F300 #x1F64F symbol)
+        (#x1F680 #x1F77F symbol)
+        (#x20000 #x2B81F han)
         (#x2F800 #x2FFFF han)))
     (set-char-table-range char-script-table
                          (cons (car elt) (nth 1 elt)) (nth 2 elt))
@@ -1204,22 +1333,8 @@ Setup char-width-table appropriate for non-CJK language environment."
 \f
 ;;; Setting unicode-category-table.
 
-;; This macro is to build unicode-category-table at compile time so
-;; that C code can access the table efficiently.
-(defmacro build-unicode-category-table ()
-  (let ((table (make-char-table 'unicode-category-table nil)))
-    (dotimes (i #x110000)
-      (if (or (< i #xD800)
-             (and (>= i #xF900) (< i #x30000))
-             (and (>= i #xE0000) (< i #xE0200)))
-         (aset table i (get-char-code-property i 'general-category))))
-    (set-char-table-range table '(#xE000 . #xF8FF) 'Co)
-    (set-char-table-range table '(#xF0000 . #xFFFFD) 'Co)
-    (set-char-table-range table '(#x100000 . #x10FFFD) 'Co)
-    (optimize-char-table table 'eq)
-    table))
-
-(setq unicode-category-table (build-unicode-category-table))
+(setq unicode-category-table
+      (unicode-property-table-internal 'general-category))
 (map-char-table #'(lambda (key val)
                    (if (and val
                             (or (and (/= (aref (symbol-name val) 0) ?M)
@@ -1230,6 +1345,170 @@ Setup char-width-table appropriate for non-CJK language environment."
 
 (optimize-char-table (standard-category-table))
 
+\f
+;; Display of glyphless characters.
+
+(defvar char-acronym-table
+  (make-char-table 'char-acronym-table nil)
+  "Char table of acronyms for non-graphic characters.")
+
+(let ((c0-acronyms '("NUL" "SOH" "STX" "ETX" "EOT" "ENQ" "ACK" "BEL"
+                    "BS"   nil   nil  "VT"  "FF"  "CR"  "SO"  "SI"
+                    "DLE" "DC1" "DC2" "DC3" "DC4" "NAK" "SYN" "ETB"
+                    "CAN" "EM"  "SUB" "ESC" "FC"  "GS"  "RS"  "US")))
+  (dotimes (i 32)
+    (aset char-acronym-table i (car c0-acronyms))
+    (setq c0-acronyms (cdr c0-acronyms))))
+
+(let ((c1-acronyms '("XXX" "XXX" "BPH" "NBH" "IND" "NEL" "SSA" "ESA"
+                    "HTS" "HTJ" "VTS" "PLD" "PLU" "R1"  "SS2" "SS1"
+                    "DCS" "PU1" "PU2" "STS" "CCH" "MW"  "SPA" "EPA"
+                    "SOS" "XXX" "SC1" "CSI" "ST"  "OSC" "PM"  "APC")))
+  (dotimes (i 32)
+    (aset char-acronym-table (+ #x0080 i) (car c1-acronyms))
+    (setq c1-acronyms (cdr c1-acronyms))))
+
+(aset char-acronym-table #x17B4 "KIVAQ")   ; KHMER VOWEL INHERENT AQ
+(aset char-acronym-table #x17B5 "KIVAA")   ; KHMER VOWEL INHERENT AA
+(aset char-acronym-table #x200B "ZWSP")    ; ZERO WIDTH SPACE
+(aset char-acronym-table #x200C "ZWNJ")    ; ZERO WIDTH NON-JOINER
+(aset char-acronym-table #x200D "ZWJ")    ; ZERO WIDTH JOINER
+(aset char-acronym-table #x200E "LRM")    ; LEFT-TO-RIGHT MARK
+(aset char-acronym-table #x200F "RLM")    ; RIGHT-TO-LEFT MARK
+(aset char-acronym-table #x202A "LRE")    ; LEFT-TO-RIGHT EMBEDDING
+(aset char-acronym-table #x202B "RLE")    ; RIGHT-TO-LEFT EMBEDDING
+(aset char-acronym-table #x202C "PDF")    ; POP DIRECTIONAL FORMATTING
+(aset char-acronym-table #x202D "LRO")    ; LEFT-TO-RIGHT OVERRIDE
+(aset char-acronym-table #x202E "RLO")    ; RIGHT-TO-LEFT OVERRIDE
+(aset char-acronym-table #x2060 "WJ")     ; WORD JOINER
+(aset char-acronym-table #x206A "ISS")    ; INHIBIT SYMMETRIC SWAPPING
+(aset char-acronym-table #x206B "ASS")    ; ACTIVATE SYMMETRIC SWAPPING
+(aset char-acronym-table #x206C "IAFS")    ; INHIBIT ARABIC FORM SHAPING
+(aset char-acronym-table #x206D "AAFS")    ; ACTIVATE ARABIC FORM SHAPING
+(aset char-acronym-table #x206E "NADS")    ; NATIONAL DIGIT SHAPES
+(aset char-acronym-table #x206F "NODS")    ; NOMINAL DIGIT SHAPES
+(aset char-acronym-table #xFEFF "ZWNBSP")  ; ZERO WIDTH NO-BREAK SPACE
+(aset char-acronym-table #xFFF9 "IAA")    ; INTERLINEAR ANNOTATION ANCHOR
+(aset char-acronym-table #xFFFA "IAS")     ; INTERLINEAR ANNOTATION SEPARATOR
+(aset char-acronym-table #xFFFB "IAT")     ; INTERLINEAR ANNOTATION TERMINATOR
+(aset char-acronym-table #x1D173 "BEGBM")  ; MUSICAL SYMBOL BEGIN BEAM
+(aset char-acronym-table #x1D174 "ENDBM")  ; MUSICAL SYMBOL END BEAM
+(aset char-acronym-table #x1D175 "BEGTIE") ; MUSICAL SYMBOL BEGIN TIE
+(aset char-acronym-table #x1D176 "END")           ; MUSICAL SYMBOL END TIE
+(aset char-acronym-table #x1D177 "BEGSLR") ; MUSICAL SYMBOL BEGIN SLUR
+(aset char-acronym-table #x1D178 "ENDSLR") ; MUSICAL SYMBOL END SLUR
+(aset char-acronym-table #x1D179 "BEGPHR") ; MUSICAL SYMBOL BEGIN PHRASE
+(aset char-acronym-table #x1D17A "ENDPHR") ; MUSICAL SYMBOL END PHRASE
+(aset char-acronym-table #xE0001 "|->TAG") ; LANGUAGE TAG
+(aset char-acronym-table #xE0020 "SP TAG") ; TAG SPACE
+(dotimes (i 94)
+  (aset char-acronym-table (+ #xE0021 i) (format " %c TAG" (+ 33 i))))
+(aset char-acronym-table #xE007F "->|TAG") ; CANCEL TAG
+
+(defun update-glyphless-char-display (&optional variable value)
+  "Make the setting of `glyphless-char-display-control' take effect.
+This function updates the char-table `glyphless-char-display'."
+  (when value
+    (set-default variable value))
+  (dolist (elt value)
+    (let ((target (car elt))
+         (method (cdr elt)))
+      (or (memq method '(zero-width thin-space empty-box acronym hex-code))
+         (error "Invalid glyphless character display method: %s" method))
+      (cond ((eq target 'c0-control)
+            (set-char-table-range glyphless-char-display '(#x00 . #x1F)
+                                  method)
+            ;; Users will not expect their newlines and TABs be
+            ;; displayed as anything but themselves, so exempt those
+            ;; two characters from c0-control.
+            (set-char-table-range glyphless-char-display #x9 nil)
+            (set-char-table-range glyphless-char-display #xa nil))
+           ((eq target 'c1-control)
+            (set-char-table-range glyphless-char-display '(#x80 . #x9F)
+                                  method))
+           ((eq target 'format-control)
+            (map-char-table
+             #'(lambda (char category)
+                 (if (eq category 'Cf)
+                     (let ((this-method method)
+                           from to)
+                       (if (consp char)
+                           (setq from (car char) to (cdr char))
+                         (setq from char to char))
+                       (while (<= from to)
+                         (when (/= from #xAD)
+                           (if (eq method 'acronym)
+                               (setq this-method
+                                     (aref char-acronym-table from)))
+                           (set-char-table-range glyphless-char-display
+                                                 from this-method))
+                         (setq from (1+ from))))))
+             unicode-category-table))
+           ((eq target 'no-font)
+            (set-char-table-extra-slot glyphless-char-display 0 method))
+           (t
+            (error "Invalid glyphless character group: %s" target))))))
+
+;;; Control of displaying glyphless characters.
+(defcustom glyphless-char-display-control
+  '((format-control . thin-space)
+    (no-font . hex-code))
+  "List of directives to control display of glyphless characters.
+
+Each element has the form (GROUP . METHOD), where GROUP is a
+symbol specifying the character group, and METHOD is a symbol
+specifying the method of displaying characters belonging to that
+group.
+
+GROUP must be one of these symbols:
+  `c0-control':     U+0000..U+001F, but excluding newline and TAB.
+  `c1-control':     U+0080..U+009F.
+  `format-control': Characters of Unicode General Category `Cf',
+                    such as U+200C (ZWNJ), U+200E (LRM), but
+                    excluding characters that have graphic images,
+                    such as U+00AD (SHY).
+  `no-font':        characters for which no suitable font is found.
+                    For character terminals, characters that cannot
+                    be encoded by `terminal-coding-system'.
+
+METHOD must be one of these symbols:
+  `zero-width': don't display.
+  `thin-space': display a thin (1-pixel width) space.  On character
+                terminals, display as 1-character space.
+  `empty-box':  display an empty box.
+  `acronym':    display an acronym of the character in a box.  The
+                acronym is taken from `char-acronym-table', which see.
+  `hex-code':   display the hexadecimal character code in a box."
+  :version "24.1"
+  :type '(alist :key-type (symbol :tag "Character Group")
+               :value-type (symbol :tag "Display Method"))
+  :options '((c0-control
+             (choice (const :tag "Don't display" zero-width)
+                     (const :tag "Display as thin space" thin-space)
+                     (const :tag "Display as empty box" empty-box)
+                     (const :tag "Display acronym" acronym)
+                     (const :tag "Display hex code in a box" hex-code)))
+            (c1-control
+             (choice (const :tag "Don't display" zero-width)
+                     (const :tag "Display as thin space" thin-space)
+                     (const :tag "Display as empty box" empty-box)
+                     (const :tag "Display acronym" acronym)
+                     (const :tag "Display hex code in a box" hex-code)))
+            (format-control
+             (choice (const :tag "Don't display" zero-width)
+                     (const :tag "Display as thin space" thin-space)
+                     (const :tag "Display as empty box" empty-box)
+                     (const :tag "Display acronym" acronym)
+                     (const :tag "Display hex code in a box" hex-code)))
+            (no-font
+             (choice (const :tag "Don't display" zero-width)
+                     (const :tag "Display as thin space" thin-space)
+                     (const :tag "Display as empty box" empty-box)
+                     (const :tag "Display acronym" acronym)
+                     (const :tag "Display hex code in a box" hex-code))))
+  :set 'update-glyphless-char-display
+  :group 'display)
+
 \f
 ;;; Setting word boundary.
 
@@ -1247,5 +1526,4 @@ Setup char-width-table appropriate for non-CJK language environment."
 ;; coding: utf-8
 ;; End:
 
-;; arch-tag: 85889c35-9f4d-4912-9bf5-82de31b0d42d
 ;;; characters.el ends here