aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark E. Shoulson <mark@kli.org>2019-12-18 16:08:09 -0500
committerMark E. Shoulson <mark@kli.org>2020-08-18 19:26:22 -0400
commitb0e7edb0e51ce414d312dd2a86d2815a6b709b1b (patch)
tree28f864c1fc2ae18fcdc1394869df9ba8dc6362c3
parentStart playing with an xcompose-mode.el (diff)
downloaddotXCompose-b0e7edb0e51ce414d312dd2a86d2815a6b709b1b.tar.gz
dotXCompose-b0e7edb0e51ce414d312dd2a86d2815a6b709b1b.tar.bz2
dotXCompose-b0e7edb0e51ce414d312dd2a86d2815a6b709b1b.zip
Make an emacs-mode for editing these files.
I'm sure many of you will hate it, but I didn't make it for you.
-rw-r--r--xcompose-mode.el216
1 files changed, 190 insertions, 26 deletions
diff --git a/xcompose-mode.el b/xcompose-mode.el
index 769b68e..4140bcb 100644
--- a/xcompose-mode.el
+++ b/xcompose-mode.el
@@ -1,46 +1,98 @@
-;; Blah blah add headers here.
-;; Playing with the notion of a major mode for .XCompose files.
-;; Maybe eventually smart enough to keep columns lined up.
-;; For now, settling for pretty colors.
+;;; xcompose.el --- major mode for editing .XCompose files
+;; Copyright (C) 2019 Mark Shoulson
+
+;; Author: Mark Shoulson
+;; Maintainer: Mark Shoulson
+;; URL:
+
+;; This file is NOT part of GNU Emacs
+
+;; Permission is hereby granted, free of charge, to any person
+;; obtaining a copy of this software and associated documentation
+;; files (the "Software"), to deal in the Software without
+;; restriction, including without limitation the rights to use, copy,
+;; modify, merge, publish, distribute, sublicense, and/or sell copies
+;; of the Software, and to permit persons to whom the Software is
+;; furnished to do so, subject to the following conditions:
+
+;; The above copyright notice and this permission notice shall be
+;; included in all copies or substantial portions of the Software.
+
+;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+;; SOFTWARE.
+
+;;; Commentary:
+
+;; This file provides the major mode xcompose-mode, for use in editing
+;; .XCompose files, which are used in X-windows systems to define the
+;; behavior certain sequential keystroke combinations, usually involving
+;; the "Multi-Key". It was also built with an eye towards use with "base"
+;; files, which are slightly simplified compose files I use for
+;; convenience.
+
+;; Mainly fontifying; eventually should do better formatting, finding the
+;; right tab stops etc.
+
+;;; Code:
(defface xcompose-angle-face
- '((t (:inherit font-lock-keyword-face)))
- "Face for the <>s"
+ ;; Black seems to stand out best, what can I say?
+ '((t (:inherit bold)))
+ "Face for the angle brackets (<>) around key-names."
:group 'xcompose-mode)
(defface xcompose-keys-face
'((t (:inherit font-lock-constant-face)))
- "Face for the key names"
+ "Face for the key names."
:group 'xcompose-mode)
(defface xcompose-string-face
+ ;; I feel like these should really stand out, not just plain-jane
+ ;; font-lock-string-face. Even to the point of increasing the size and
+ ;; drawing boxes.
'((t (:inherit font-lock-string-face
:height 1.2
:box "black")))
- "Face for the strings. Not straight font-lock-string-face in case I want
-to make it big or something."
+ "Face for the quoted strings containing the character(s) to be produced."
:group 'xcompose-mode)
+
(defface xcompose-quotemark-face
'((t (:inherit font-lock-string-face
:foreground "dark orchid")))
- "Face for quotes around strings"
+ "Face for quote-marks around character strings."
:group 'xcompose-mode)
+;; Yes, kind of a lot of faces and a lot of fine-tuning of the line's
+;; appearance. Maybe a bit too much.
(defface xcompose-num-face
'((t (:inherit font-lock-preprocessor-face :weight bold)))
- "Face for the hex numbers"
+ "Face for the hex numbers identifying the code-point."
:group 'xcompose-mode)
(defface xcompose-U-face
'((t (:inherit font-lock-preprocessor-face)))
- "Face for the U before the hex numbers"
+ "Face for the U before the hex numbers."
:group 'xcompose-mode)
(defface xcompose-colon-face
'((t (:inherit bold)))
- "Face for the \":\"."
+ "Face for the \":\" separating the keystrokes from the character string."
:group 'xcompose-mode)
+;; There are LOTS of comments (commented-out lines) in some of these files;
+;; I'd like them to fade into the background a bit, and I use a white
+;; background.
+(defface xcompose-comment-face
+ `((t (:inherit font-lock-comment-face
+ :foreground "light coral")))
+ "Face for comments in xcompose files."
+ :group 'xcompose-mode)
(defvar xcompose-mode-syntax-table
(let ((st (make-syntax-table text-mode-syntax-table)))
@@ -49,12 +101,17 @@ to make it big or something."
(modify-syntax-entry ?# "< " st)
(modify-syntax-entry ?_ "_ " st)
(modify-syntax-entry ?\n "> " st)
+ (modify-syntax-entry ?{ "| " st)
+ (modify-syntax-entry ?} "| " st)
st)
"Syntax table for xcompose-mode")
(defvar xcompose-mode-map
(let ((map (make-sparse-keymap)))
- ;; ADD BINDINGS
+ (define-key map (kbd "C-c u") 'xcompose-fill-in-char-string)
+ (define-key map (kbd "C-c C-u") 'xcompose-fill-in-char-code)
+ ;; (define-key map (kbd "C-c C-i") 'xcompose-insert-char-name)
+ (define-key map (kbd "C-c ;") 'xcompose-insert-char-name)
map)
"Keymap for xcompose-mode")
@@ -68,23 +125,130 @@ to make it big or something."
("\\(U\\)\\([0-9A-Fa-f]*\\)" .
((1 'xcompose-U-face) (2 'xcompose-num-face)))
(":" . 'xcompose-colon-face)
- (" #.*" . 'glyphless-char)
- ))
+ ;; I want to be able to open my "base" files too, and automatically
+ ;; de-emphasize (comment-out) things that won't be expanded (because of
+ ;; too long a string.)
+ ("^.*{[^}]\\{8,\\}}.*$" 0 'xcompose-comment-face prepend)
+ )
+ "Keywords for xcompose-mode")
+
+(defvar xcompose-key-re "<[a-zA-Z0-9_]+"
+ "Regexp matching the beginning of a keystroke.")
+
+;; I wonder if this will be useful or really annoying.
+(define-abbrev-table 'xcompose-mode-abbrev-table
+ '(("<Mu" "<Multi_key>" nil :system t)
+ ("<ap" "<apostrophe>" nil :system t)
+ ("<am" "<ampersand>" nil :system t)
+ ("<asciic" "<asciicircum>" nil :system t)
+ ("<asciit" "<asciitilde>" nil :system t)
+ ("<ast" "<asterisk>" nil :system t)
+ ("<bac" "<backslash>" nil :system t)
+ ("<bar" "<bar>" nil :system t) ; ?
+ ("<bracel" "<braceleft>" nil :system t)
+ ("<bracer" "<braceright>" nil :system t)
+ ("<bracketl" "<brakcetleft>" nil :system t)
+ ("<bracketr" "<brakcetright>" nil :system t)
+ ("<col" "<colon>" nil :system t)
+ ("<com" "<comma>" nil :system t)
+ ("<do" "<dollar>" nil :system t)
+ ("<gra" "<grave>" nil :system t)
+ ("<gre" "<greater>" nil :system t)
+ ("<le" "<less>" nil :system t)
+ ("<mi" "<minus>" nil :system t)
+ ("<nu" "<numbersign>" nil :system t)
+ ("<parenl" "<parenleft>" nil :system t)
+ ("<parenr" "<parenright>" nil :system t)
+ ("<perc" "<percent>" nil :system t)
+ ("<peri" "<period>" nil :system t)
+ ("<pl" "<plus>" nil :system t)
+ ("<quo" "<quotedbl>" nil :system t)
+ ("<se" "<semicolon>" nil :system t)
+ ("<sp" "<space>" nil :system t)
+ ("<un" "<underscore>" nil :system t)
+ )
+ "Abbrev table"
+ :regexp "\\(<[a-zA-Z0-9_]+\\)"
+ :case-fixed t)
+
+;; See https://emacs.stackexchange.com/questions/51216/how-to-expand-abbrevs-without-hitting-another-extra-key
+(defun xcompose-expand-abbrev ()
+ "Run `expand-abbrev' when text before point matches `xcompose-key-re'"
+ (when (looking-back xcompose-key-re (line-beginning-position))
+ (expand-abbrev)))
+
+;; Not really all that useful, since I can fill in the comment automatically
+(defun xcompose-capitalize-comment nil
+ "Set any trailing comment on the current line to all-caps."
+ (interactive)
+ (save-excursion
+ (let* ((eol (progn (end-of-line) (point)))
+ (bol (progn (beginning-of-line) (point))))
+ (if (search-forward comment-start eol t)
+ (upcase-region (point) eol)))))
+
+(defun xcompose-find-quoted-char (&optional pos)
+ "Find the character in quotes in the current line (or that given by pos)."
+ (save-excursion
+ (let* ((pos (or pos (point)))
+ (chr nil)
+ (eol (progn (end-of-line) (point)))
+ (bol (progn (beginning-of-line) (point))))
+ (if (search-forward ":" eol t)
+ (progn
+ (if (search-forward "\"" eol t)
+ (setq chr (char-after)))))
+ chr)))
+
+;; If you can type the char but don't know its code (using C-x 8 RET is
+;; great for this, if you know the character name)
+(defun xcompose-fill-in-char-code (&optional pos)
+ "Look up character in string on line given and fill in the UXXXX code at point."
+ (interactive)
+ (let* ((pos (or pos (point)))
+ (chr (xcompose-find-quoted-char pos)))
+ (goto-char pos)
+ (insert (format "U%.04X" chr))))
+
+;; Conversely, if you know the character code but for some reason can't
+;; type it (C-x 8 RET not working for you?) you can do it the other way.
+(defun xcompose-fill-in-char-string (&optional pos)
+ "Look up character given by UXXXX code on line given and insert into string before it, separated by a space."
+ ;; Probably needs some reformatting afterwards
+ (interactive)
+ (let* ((pos (or pos (point)))
+ (eol (progn (end-of-line) (point)))
+ (bol (progn (beginning-of-line) (point))))
+ ;; search not necessarily as precise
+ (if (search-forward-regexp "\\<U\\([[:xdigit:]]+\\)" eol)
+ (let* ((hex (match-string 1))
+ (num (string-to-number hex 16))
+ (str (char-to-string num)))
+ (goto-char (match-beginning 0))
+ (insert (format "\"%s\" " str))))))
+
+(defun xcompose-insert-char-name nil
+ "Find the (first) quoted character on the line, and insert its name as
+a comment at the end of the line."
+ (interactive)
+ (let* ((pos (point))
+ (chr (xcompose-find-quoted-char pos)))
+ (goto-char pos)
+ (move-to-column (max (+ 4 (current-column)) comment-column) t)
+ (insert (format "# %s" (get-char-code-property chr 'name)))))
+
+(define-derived-mode xcompose-mode fundamental-mode "XCompose"
+ "Major mode for .XCompose files
-(define-derived-mode xcompose-mode text-mode "XCompose"
- "Major mode for .XCompose files"
+\\{xcompose-mode-map}"
(font-lock-add-keywords nil xcompose-font-lock-keywords)
- (setq-local comment-start "#")
+ ;; (setq-local comment-start "\\s-#")
(setq-local comment-end "\n")
(setq-local comment-continue " *")
(setq-local comment-start-skip "/[*/]+[ \t]*")
(setq-local comment-end-skip "[ \t]*\\(?:\n\\|\\*+/\\)")
- ;; Bizarrely enough, this actually works.
- ;; But I think I might not want to use it.
- ;; (setq-local font-lock-comment-face
- ;; '(:height 0.95 :inherit font-lock-comment-face))
- ;; But lighten the color a little, since there's so much comment text...
- (setq-local font-lock-comment-face
- '(:inherit font-lock-comment-face :foreground "light coral"))
+ (setq-local font-lock-comment-face 'xcompose-comment-face)
+ (add-hook 'post-self-insert-hook #'xcompose-expand-abbrev nil t)
+ (auto-fill-mode 0)
)