diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/bufhist.el | 20 | ||||
-rw-r--r-- | lib/holes-load.el | 14 | ||||
-rw-r--r-- | lib/holes.el | 55 | ||||
-rw-r--r-- | lib/local-vars-list.el | 2 | ||||
-rw-r--r-- | lib/maths-menu.el | 47 | ||||
-rw-r--r-- | lib/pg-dev.el | 2 | ||||
-rw-r--r-- | lib/pg-fontsets.el | 7 | ||||
-rw-r--r-- | lib/proof-compat.el | 387 | ||||
-rw-r--r-- | lib/span-extent.el | 139 | ||||
-rw-r--r-- | lib/span-overlay.el | 222 | ||||
-rw-r--r-- | lib/span.el | 209 | ||||
-rw-r--r-- | lib/unicode-tokens.el | 1202 | ||||
-rw-r--r-- | lib/xml-fixed.el | 508 |
13 files changed, 831 insertions, 1983 deletions
diff --git a/lib/bufhist.el b/lib/bufhist.el index 4917819f..c6e70c9d 100644 --- a/lib/bufhist.el +++ b/lib/bufhist.el @@ -73,18 +73,14 @@ indicator 'help-echo desc 'keymap (eval-when-compile - (cond - ((featurep 'xemacs) - nil) - (t - (let ((map (make-sparse-keymap))) - ;; FIXME: clicking can go wrong here because the - ;; current buffer can be something else which has no hist! - (define-key map [mode-line mouse-1] 'bufhist-prev) - (define-key map [mode-line mouse-3] 'bufhist-next) - ;; (define-key map [mode-line control mouse-1] 'bufhist-first) - ;; (define-key map [mode-line control mouse-3] 'bufhist-last) - map)))) + (let ((map (make-sparse-keymap))) + ;; FIXME: clicking can go wrong here because the + ;; current buffer can be something else which has no hist! + (define-key map [mode-line mouse-1] 'bufhist-prev) + (define-key map [mode-line mouse-3] 'bufhist-next) + ;; (define-key map [mode-line control mouse-1] 'bufhist-first) + ;; (define-key map [mode-line control mouse-3] 'bufhist-last) + map)) 'mouse-face 'mode-line-highlight)))) ;simple: diff --git a/lib/holes-load.el b/lib/holes-load.el deleted file mode 100644 index 0c0a8b80..00000000 --- a/lib/holes-load.el +++ /dev/null @@ -1,14 +0,0 @@ -; To use holes-mode, require this file in your .emacs and add path to -; holes.el in the load-path of emacs - -(autoload 'holes-mode "holes" - "Minor mode for using \"holes\" in your buffers." t) -(autoload 'holes-set-make-active-hole "holes" - "Makes a new hole and make it active." t) -(autoload 'holes-abbrev-complete "holes" - "Completes an abbreviation, and replace #s ans @{}s by holes.") -(autoload 'holes-insert-and-expand "holes" - "insert and expand an abbreviation, and replace #s ans @{}s by holes.") - -(provide 'holes-load) - diff --git a/lib/holes.el b/lib/holes.el index 8fe9139f..65b1cc18 100644 --- a/lib/holes.el +++ b/lib/holes.el @@ -1,6 +1,7 @@ ;;; holes.el --- a little piece of elisp to define holes in your buffer ;; ;; Copyright (C) 2001 Pierre Courtieu +;; ;; $Id$ ;; ;; This file uses spans, an interface for extent (XEmacs) and overlays @@ -29,7 +30,7 @@ ;;; History: ;; -(require 'span) +(eval-when-compile (require 'span)) (require 'cl) ;;; Help: @@ -128,19 +129,6 @@ is), which is annoying. ;;; Code: -(cond - ((featurep 'xemacs) - (defalias 'holes-region-exists-p 'region-exists-p) - (defalias 'holes-get-selection 'get-selection)) - (t - ;;Pierre: should do almost what region-exists-p does in XEmacs - (defun holes-region-exists-p nil - "Return t if the mark is active, nil otherwise." - mark-active) - (defun holes-get-selection nil "See `current-kill'." - (current-kill 0)))) - - ;;; initialization (defvar holes-default-hole (make-detached-span) "An empty detached hole used as the default hole. @@ -204,17 +192,17 @@ which should be removed when making the text into a hole.") (defun holes-region-beginning-or-nil () "Internal." - (and (holes-region-exists-p) (region-beginning)) + (and mark-active (region-beginning)) ) (defun holes-region-end-or-nil () "Internal." - (and (holes-region-exists-p) (region-end)) + (and mark-active (region-end)) ) (defun holes-copy-active-region () "Internal." - (assert (holes-region-exists-p) nil "the region is not active now.") + (assert mark-active nil "the region is not active now.") (copy-region-as-kill (region-beginning) (region-end)) (car kill-ring) ) @@ -540,7 +528,7 @@ goal(FIXME?). Use `replace-active-hole' instead." "Replace the active hole by STR, if no str is given, then put the selection instead." (if (not (holes-active-hole-exist-p)) () (holes-replace - (or str (holes-get-selection) (error "Nothing to put in hole")) + (or str (current-kill 0) (error "Nothing to put in hole")) holes-active-hole) )) @@ -557,8 +545,8 @@ following hole if it exists." (let ((nxthole (holes-next-after-active-hole))) (holes-replace-active-hole (or str - (and (holes-region-exists-p) (holes-copy-active-region)) - (holes-get-selection) (error "Nothing to put in hole"))) + (and mark-active (holes-copy-active-region)) + (current-kill 0) (error "Nothing to put in hole"))) (if nxthole (holes-set-active-hole nxthole) (setq holes-active-hole holes-default-hole)) ) @@ -573,6 +561,8 @@ Sets `holes-active-hole' to the next hole if it exists." (holes-replace-update-active-hole "") ) + +;;;###autoload (defun holes-set-make-active-hole (&optional start end) "Make a new hole between START and END or at point, and make it active." @@ -628,11 +618,11 @@ Sets `holes-active-hole' to the next hole if it exists." (save-excursion ;;HACK: nothing if one click (but a second is perhaps coming) (if (and (eq (holes-track-mouse-clicks) 1) - (not (holes-region-exists-p))) + (not mark-active)) () - (if (not (holes-region-exists-p)) + (if (not mark-active) (error "Nothing to put in hole") - (holes-replace-update-active-hole (holes-get-selection)) + (holes-replace-update-active-hole (current-kill 0)) (message "hole replaced") ) ) @@ -696,10 +686,10 @@ Sets `holes-active-hole' to the next hole if it exists." (holes-track-mouse-selection event) (if (and (eq (holes-track-mouse-clicks) 1) - (not (holes-region-exists-p))) + (not mark-active)) (holes-set-make-active-hole (point) (point)) - (if (holes-region-exists-p) + (if mark-active (holes-set-make-active-hole) (let ((ext (holes-hole-at-event event))) (if (and ext (holes-is-hole-p ext)) @@ -740,15 +730,9 @@ Destroy it and makes the next hole active if any." (defvar hole-map (let ((map (make-sparse-keymap))) - (cond - ((featurep 'xemacs) - (define-key map [(button1)] 'holes-mouse-set-active-hole) - (define-key map [(button3)] 'holes-mouse-destroy-hole) - (define-key map [(button2)] 'holes-mouse-forget-hole)) - (t - (define-key map [(mouse-1)] 'holes-mouse-set-active-hole) - (define-key map [(mouse-3)] 'holes-mouse-destroy-hole) - (define-key map [(mouse-2)] 'holes-mouse-forget-hole))) + (define-key map [(mouse-1)] 'holes-mouse-set-active-hole) + (define-key map [(mouse-3)] 'holes-mouse-destroy-hole) + (define-key map [(mouse-2)] 'holes-mouse-forget-hole) map) "Keymap to use on the holes's overlays. This keymap is used only when @@ -842,6 +826,7 @@ created. Return the number of holes created." +;;;###autoload (defun holes-abbrev-complete () "Complete abbrev by putting holes and indenting. Moves point at beginning of expanded text. Put this function as @@ -850,7 +835,7 @@ become holes." (holes-replace-string-by-holes-backward-jump last-abbrev-location)) - +;;;###autoload (defun holes-insert-and-expand (s) "Insert S, expand it and replace #s and @{]s by holes." ;; insert the expansion of abbrev s, and replace #s by holes. It was diff --git a/lib/local-vars-list.el b/lib/local-vars-list.el index f0b6678e..c55cee44 100644 --- a/lib/local-vars-list.el +++ b/lib/local-vars-list.el @@ -29,7 +29,7 @@ "From Emacs Info: A file can contain a \"local variables list\", which specifies the values to use for -certain Emacs variables when that file is edited. See info node \"(xemacs)File +certain Emacs variables when that file is edited. See info node \"(emacs)File Variables\". local-vars-list provides two useful functions: diff --git a/lib/maths-menu.el b/lib/maths-menu.el index ab15439f..5e75eba7 100644 --- a/lib/maths-menu.el +++ b/lib/maths-menu.el @@ -5,7 +5,9 @@ ;; Author: Dave Love <fx@gnu.org> ;; Keywords: convenience -;; Version for Proof General minimally modified by David Aspinall, 2007-8. +;; Version for Proof General modified by David Aspinall, 2007-8. +;; - Hooks added to insert tokenised versions of unicode characters. +;; - Added more characters to the menus. ;; $Id$ @@ -48,6 +50,12 @@ ;;; Code: +(defvar maths-menu-filter-predicate '(lambda (char) t) + "Predicate function used to filter menu elements") + +(defvar maths-menu-tokenise-insert '(lambda (char) (insert char)) + "Function used to insert possibly formatted or escaped character.") + (defun maths-menu-build-menu (spec) (let ((map (make-sparse-keymap "Characters"))) (dolist (pane spec) @@ -57,19 +65,25 @@ (dolist (elt pane) (define-key-after pane-map (vector (intern (string (car elt)))) ; convenient unique symbol - (cons (format "%c (%s)" (car elt) (cadr elt)) - ;; Using a string here doesn't work. You get a - ;; `Wrong type argument: commandp,' error. - ;; That looks like a bug, since - ;; (commandp "a") => t + (list 'menu-item + (format "%c (%s)" (car elt) (cadr elt)) `(lambda () (interactive) - (insert ,(car elt)))))))) + (funcall maths-menu-tokenise-insert ,(car elt))) + :visible `(funcall maths-menu-filter-predicate ,(car elt))))))) map)) (defvar maths-menu-menu (maths-menu-build-menu - '(("Binops 1" + '(("Logic" + (?$A!D(B "and") + (?$A!E(B "or") + (?$,1x (B "for all") + (?$,1x#(B "there exists") + (?$,1x$(B "there does not exist") + (?$,1yd(B "down tack") + (?$,1ye(B "up tack")) + ("Binops 1" (?,A1(B "plus-minus sign") (?$,1x3(B "minus-or-plus sign") (?,AW(B "multiplication sign") @@ -175,6 +189,17 @@ (?$,1vy(B "south west arrow") (?$,1vv(B "north west arrow") (?$,1w[(B "rightwards triple arrow")) + ("Long arrows" + (?$,2'v(B "long rightwards arrow") + (?$,2'w(B "long left right arrow") + (?$,2'x(B "long left double arrow") + (?$,2'y(B "long right double arrow") + (?$,2'z(B "long left right double arrow") + (?$,2'{(B "long left arrow from bar") + (?$,2'|(B "long right arrow from bar") + (?$,2'}(B "long left double arrow bar") + (?$,2'~(B "long right double arrow from bar") + (?$,2'(B "long rightwards squiggle arrow")) ("Symbols 1" (?$,1uu(B "alef symbol") ; don't use letter alef (avoid bidi confusion) (?$,1uO(B "planck constant over two pi") @@ -189,12 +214,7 @@ (?$,1x'(B "nabla") (?$,1x:(B "square root") (?$,1x;(B "cube root") - (?$,1yd(B "down tack") - (?$,1ye(B "up tack") (?$,1x@(B "angle") - (?$,1x (B "for all") - (?$,1x#(B "there exists") - (?$,1x$(B "there does not exist") (?,A,(B "not sign") (?$,2#o(B "music sharp sign") (?$,1x"(B "partial differential") @@ -214,6 +234,7 @@ (?$,1z (B "n-ary logical and") (?$,1uU(B "double-struck capital n") (?$,1uY(B "double-struck capital p") + (?$,1uZ(B "double-struck capital q") (?$,1u](B "double-struck capital r") (?$,1ud(B "double-struck capital z") (?$,1uP(B "script capital i") diff --git a/lib/pg-dev.el b/lib/pg-dev.el index 692b4bef..ffcf3597 100644 --- a/lib/pg-dev.el +++ b/lib/pg-dev.el @@ -79,7 +79,7 @@ proof-autoloads pg-response pg-goals proof-toolbar proof-easy-config proof-config proof-mmm proof proof-utils proof-syntax pg-user pg-custom - proof-x-symbol proof-maths-menu proof-unicode-tokens + proof-maths-menu proof-unicode-tokens pg-thymodes pg-autotest ;; isar-syntax isar-find-theorems x-symbol-isar diff --git a/lib/pg-fontsets.el b/lib/pg-fontsets.el index 67d57598..a860929c 100644 --- a/lib/pg-fontsets.el +++ b/lib/pg-fontsets.el @@ -17,6 +17,11 @@ ;; ;; DejaVu LGC (Sans and Sans Mono). See http://dejavu.sourceforge.net ;; - missing Uplus, smile, frown, join +;; +;; TODO: +;; -- make a fontset which combines symbol characters from a +;; symbol-rich font +;; ;;; Code: @@ -61,5 +66,5 @@ gnu-unifont:-*-%F-medium-r-normal--%S-*-*-*-*-*-iso10646-1" (pg-fontsets-make-fontsets) - +(provide 'pg-fontsets) ;;; pg-fontsets.el ends here diff --git a/lib/proof-compat.el b/lib/proof-compat.el index 9e3a2b7c..0142364b 100644 --- a/lib/proof-compat.el +++ b/lib/proof-compat.el @@ -11,8 +11,10 @@ ;; track of them. ;; ;; The development policy for Proof General (since v3.7) is for the -;; main codebase to be written for the latest stable version of GNU -;; Emacs, following GNU Emacs advice on obsolete function calls. +;; main codebase to be written for the latest stable version of +;; GNU Emacs, following GNU Emacs advice on obsolete function calls. +;; +;; Since Proof General 4.0, XEmacs is not supported at all. ;; (eval-when-compile @@ -40,7 +42,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; -;;; Emacs and XEmacs modifications and adjustments +;;; Modifications and adjustments ;;; ;; Remove a custom setting. Needed to support dynamic reconfiguration. @@ -77,18 +79,6 @@ Done by `makunbound' and removing all properties mentioned by custom library." ;;; XEmacs compatibility ;;; -;; browse-url function isn't autoloaded in XEmacs 20.4 -(or (fboundp 'browse-url) - (autoload 'browse-url "browse-url" - "Ask a WWW browser to load URL." t)) - -;; executable-find isn't autoloaded in XEmacs 21.4.6 -(or (fboundp 'executable-find) - (autoload 'executable-find "executable" "\ -Search for COMMAND in exec-path and return the absolute file name. -Return nil if COMMAND is not found anywhere in `exec-path'." nil nil)) - - ;; Compatibility with XEmacs 20.3 (or (fboundp 'split-path) (defun split-path (path) @@ -98,158 +88,6 @@ with `path-separator'." (split-string path (regexp-quote path-separator)))) -;; Compatibility with XEmacs 21.4, API change in add-hook -(when - (and (featurep 'xemacs) - (eq emacs-major-version 21) - (<= emacs-minor-version 4)) - - (fset 'old-add-hook (symbol-function 'add-hook)) - (defun add-hook (hook function &optional append local) - "Add to the value of HOOK the function FUNCTION. -FUNCTION is not added if already present. -FUNCTION is added (if necessary) at the beginning of the hook list -unless the optional argument APPEND is non-nil, in which case -FUNCTION is added at the end. - -The optional fourth argument, LOCAL, if non-nil, says to modify -the hook's buffer-local value rather than its default value. -This makes the hook buffer-local if needed. -To make a hook variable buffer-local, always use -`make-local-hook', not `make-local-variable'. - -HOOK should be a symbol, and FUNCTION may be any valid function. If -HOOK is void, it is first set to nil. If HOOK's value is a single -function, it is changed to a list of functions. - -You can remove this hook yourself using `remove-hook'. - -See also `add-one-shot-hook'." - (if local (make-local-hook hook)) - (old-add-hook hook function append local))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; -;;; XEmacs compatibility with GNU Emacs -;;; - - -(or (fboundp 'subst-char-in-string) -;; Code is taken from Emacs 21.2.1/subr.el -(defun subst-char-in-string (fromchar tochar string &optional inplace) - "Replace FROMCHAR with TOCHAR in STRING each time it occurs. -Unless optional argument INPLACE is non-nil, return a new string." - (let ((i (length string)) - (newstr (if inplace string (copy-sequence string)))) - (while (> i 0) - (setq i (1- i)) - (if (eq (aref newstr i) fromchar) - (aset newstr i tochar))) - newstr))) - -;; Required by xmltok.el [not used at present], proof-shell.el -(or (fboundp 'replace-regexp-in-string) - -;; Code is taken from Emacs 21.1.1/subr.el. Now in XEmacs (21.5b28, at least) -(defun replace-regexp-in-string (regexp rep string &optional - fixedcase literal subexp start) - "Replace all matches for REGEXP with REP in STRING. - -Return a new string containing the replacements. - -Optional arguments FIXEDCASE, LITERAL and SUBEXP are like the -arguments with the same names of function `replace-match'. If START -is non-nil, start replacements at that index in STRING. - -REP is either a string used as the NEWTEXT arg of `replace-match' or a -function. If it is a function it is applied to each match to generate -the replacement passed to `replace-match'; the match-data at this -point are such that match 0 is the function's argument. - -To replace only the first match (if any), make REGEXP match up to \\' -and replace a sub-expression, e.g. - (replace-regexp-in-string \"\\(foo\\).*\\'\" \"bar\" \" foo foo\" nil nil 1) - => \" bar foo\" -" - - ;; To avoid excessive consing from multiple matches in long strings, - ;; don't just call `replace-match' continually. Walk down the - ;; string looking for matches of REGEXP and building up a (reversed) - ;; list MATCHES. This comprises segments of STRING which weren't - ;; matched interspersed with replacements for segments that were. - ;; [For a `large' number of replacments it's more efficient to - ;; operate in a temporary buffer; we can't tell from the function's - ;; args whether to choose the buffer-based implementation, though it - ;; might be reasonable to do so for long enough STRING.] - (let ((l (length string)) - (start (or start 0)) - matches str mb me) - (save-match-data - (while (and (< start l) (string-match regexp string start)) - (setq mb (match-beginning 0) - me (match-end 0)) - ;; If we matched the empty string, make sure we advance by one char - (when (= me mb) (setq me (min l (1+ mb)))) - ;; Generate a replacement for the matched substring. - ;; Operate only on the substring to minimize string consing. - ;; Set up match data for the substring for replacement; - ;; presumably this is likely to be faster than munging the - ;; match data directly in Lisp. - (string-match regexp (setq str (substring string mb me))) - (setq matches - (cons (replace-match (if (stringp rep) - rep - (funcall rep (match-string 0 str))) - fixedcase literal str subexp) - (cons (substring string start mb) ; unmatched prefix - matches))) - (setq start me)) - ;; Reconstruct a string from the pieces. - (setq matches (cons (substring string start l) matches)) ; leftover - (apply #'concat (nreverse matches)))))) - - -;; The GNU Emacs implementation of easy-menu-define has a very handy -;; :visible keyword. To use that when it's available, we set a -;; constant to be :visible or :active - -(defconst menuvisiblep (if (featurep 'xemacs) :active :visible) - ":visible (on GNU Emacs) or :active (otherwise). -The GNU Emacs implementation of easy-menu-define has a very handy -:visible keyword. To use that when it's available, we use this constant.") - - -(or (fboundp 'frame-parameter) - (defalias 'frame-parameter 'frame-property)) - -(or (boundp 'window-size-fixed) - (defvar window-size-fixed nil - "Fudged version of GNU Emacs' setting. Completely ignored.")) - -(or (fboundp 'window-text-height) - (defalias 'window-text-height 'window-text-area-height)) - -(or (fboundp 'set-window-text-height) -(defun set-window-text-height (window height) - "Sets the height in lines of the text display area of WINDOW to HEIGHT. -This doesn't include the mode-line (or header-line if any) or any -partial-height lines in the text display area. - -If WINDOW is nil, the selected window is used. - -Note that the current implementation of this function cannot always set -the height exactly, but attempts to be conservative, by allocating more -lines than are actually needed in the case where some error may be present." - (let ((delta (- height (window-text-height window)))) - (unless (zerop delta) - (let ((window-min-height 1)) - (if (and window (not (eq window (selected-window)))) - (save-selected-window - (select-window window) - (enlarge-window delta)) - (enlarge-window delta))))))) - - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; GNU Emacs compatibility with XEmacs @@ -265,46 +103,15 @@ The value returned is the value of the last form in BODY." (progn ,@body) (select-frame ,old-frame)))))) -;; Chars (borrowed from x-symbol-emacs.el compatability file) - -(unless (fboundp 'characterp) (defalias 'characterp 'integerp)) -(unless (fboundp 'int-to-char) (defalias 'int-to-char 'identity)) -(unless (fboundp 'char-to-int) (defalias 'char-to-int 'identity)) - ;; Missing function, but anyway Emacs has no datatype for events... (unless (fboundp 'events-to-keys) (defalias 'events-to-keys 'identity)) -(unless (fboundp 'region-exists-p) - (defun region-exists-p () mark-active)) - ;; completion not autoloaded in GNU 20.6.1; we must call ;; dynamic-completion-mode after loading it. (or (fboundp 'complete) (autoload 'complete "completion")) -(unless (featurep 'xemacs) - (eval-after-load "completion" - '(dynamic-completion-mode))) - - -;; These days cl is dumped with XEmacs (20.4,21.1) but not GNU Emacs -;; 20.2. Would rather it was autoloaded but the autoloads are broken -;; in GNU so we load it now. -(require 'cl) - -;; Give a warning, -(or (fboundp 'warn) -(defun warn (str &rest args) - "Issue a warning STR. Defined by PG for GNU compatibility." - (apply 'message str args) - (sit-for 2))) - -;; Modeline redrawing (actually force-mode-line-update is alias on XEmacs) -(or (fboundp 'redraw-modeline) -(defun redraw-modeline (&rest args) - "Dummy function for Proof General on GNU Emacs." - (force-mode-line-update))) ;; Replace in string: XEmacs original now in GNU Emacs as replace-regexp-in-string (or (fboundp 'replace-in-string) @@ -336,14 +143,9 @@ The returned value is one of the following symbols: ;; In case Emacs is not aware of the function read-shell-command, ;; we duplicate some code adjusted from minibuf.el distributed -;; with XEmacs 21.1.9 -;; -;; This code is still required as of GNU Emacs 20.6.1 -;; -;; da: I think bothering with this just to give completion for -;; when proof-prog-name-ask=t is rather a big overkill! -;; Still, now it's here we'll leave it in as a pleasant surprise -;; for GNU Emacs users. +;; with XEmacs 21.1.9. Bothering with this just to give completion for +;; when proof-prog-name-ask=t is a bit of an overkill! +;; Still, now it's here we'll leave it in as a pleasant surprise. ;; (or (fboundp 'read-shell-command) (defvar read-shell-command-map @@ -372,33 +174,6 @@ The returned value is one of the following symbols: nil (or history 'shell-command-history))))) -;; Emulate a useful builtin from XEmacs. - -(or (fboundp 'remassq) -;; NB: Emacs has assoc package with assq-delete-all function -(defun remassq (key alist) - "Delete any elements of ALIST whose car is `eq' to KEY. -The modified ALIST is returned." -;; The builtin version deletes by side-effect, but don't bother here. - (let (newalist) - (while alist - (unless (eq key (caar alist)) - (setq newalist (cons (car alist) newalist))) - (setq alist (cdr alist))) - (nreverse newalist)))) - -(or (fboundp 'remassoc) -(defun remassoc (key alist) - "Delete any elements of ALIST whose car is `equal' to KEY. -The modified ALIST is returned." -;; The builtin version deletes by side-effect, but don't bother here. - (let (newalist) - (while alist - (unless (equal key (caar alist)) - (setq newalist (cons (car alist) newalist))) - (setq alist (cdr alist))) - (nreverse newalist)))) - (or (fboundp 'frames-of-buffer) ;; From XEmacs 21.4.12, aliases expanded (defun frames-of-buffer (&optional buffer visible-only) @@ -438,6 +213,11 @@ is first in the list. VISIBLE-ONLY will only list non-iconified frames." (>= (nth 2 (window-edges window)) (frame-width (window-frame window))))) +(or (fboundp 'window-bottom-p) + (defun window-bottom-p (window) + (>= (nth 3 (window-edges window)) + (frame-height (window-frame window))))) + ;; with-selected-window from XEmacs 21.4.12 (or (fboundp 'with-selected-window) (defmacro with-selected-window (window &rest body) @@ -471,88 +251,18 @@ The value returned is the value of the last form in BODY." (funcall (get this-command 'completion-function))))) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; -;;; Attempt to harmonise pop-to-buffer behaviour -;;; - -(or (featurep 'xemacs) - ;; NB: GNU Emacs version has fewer args - (defalias 'pg-pop-to-buffer 'pop-to-buffer)) - -(if (featurep 'xemacs) -;; Version from XEmacs 21.4.12, with args to match GNU Emacs -;; NB: GNU Emacs version has fewer args, we don't use ON-FRAME -(defun pg-pop-to-buffer (bufname &optional not-this-window-p no-record on-frame) - "Select buffer BUFNAME in some window, preferably a different one. -If BUFNAME is nil, then some other buffer is chosen. -If `pop-up-windows' is non-nil, windows can be split to do this. -If optional second arg NOT-THIS-WINDOW-P is non-nil, insist on finding -another window even if BUFNAME is already visible in the selected window. -If optional fourth arg is non-nil, it is the frame to pop to this -buffer on. -If optional third arg is non-nil, do not record this in switching history. -(addition for PG). - -If `focus-follows-mouse' is non-nil, keyboard focus is left unchanged." - (let ((oldbuf (current-buffer)) - buf window frame) - (if (null bufname) - (setq buf (other-buffer (current-buffer))) - (setq buf (get-buffer bufname)) - (if (null buf) - (progn - (setq buf (get-buffer-create bufname)) - (set-buffer-major-mode buf)))) - (push-window-configuration) - (set-buffer buf) - (setq window (display-buffer buf not-this-window-p on-frame)) - (setq frame (window-frame window)) - ;; if the display-buffer hook decided to show this buffer in another - ;; frame, then select that frame, (unless obeying focus-follows-mouse -sb). - (if (and (not focus-follows-mouse) - (not (eq frame (selected-frame)))) - (select-frame frame)) - (unless no-record (record-buffer buf)) - (if (and focus-follows-mouse - on-frame - (not (eq on-frame (selected-frame)))) - (set-buffer oldbuf) - ;; select-window will modify the internal keyboard focus of XEmacs - (select-window window)) - buf)) -) - - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; -;;; Old Emacs version compatibility (to be gradually removed...) -;;; - -;; Create a menu from a customize group, for older/non-existent customize - (or (fboundp 'process-live-p) (defun process-live-p (obj) "Return t if OBJECT is a process that is alive" (and (processp obj) (memq (process-status obj) '(open run stop))))) -(or (fboundp 'buffer-substring-no-properties) - (defalias 'buffer-substring-no-properties 'buffer-substring)) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; General Emacs version compatibility ;;; -;; Handle buggy buffer-syntactic-context workaround in XEmacs, -;; and GNU Emacs non-implementation. -;; Latest: block comment is unreliable still in XEmacs 21.5, -;; doesn't seem worth attempting to use the native function at all. - (defalias 'proof-buffer-syntactic-context 'proof-buffer-syntactic-context-emulate) @@ -562,77 +272,6 @@ If `focus-follows-mouse' is non-nil, keyboard focus is left unchanged." ;;; Nasty: Emacs bug/problem fix section ;;; -;; NB: customize-menu-create is buggy in some versions of GNU Emacs -;; (bad in 21.1.0, good in 21.1.1, bad in 21.2.1, ...). Comment -;; these next lines out if you must use one of these versions. -;; PG 3.5.1: add hack in proof-compat.el to deal with this -(if - (and - (not (featurep 'xemacs)) - (or - (string-equal emacs-version "21.2.1") - (string-equal emacs-version "21.1.0"))) - (defun customize-menu-create (symbol &optional name) - (cons - (or name "Customize") - (list - ["Your version of Emacs is buggy; update to get this menu" - '(w3-goto-url "http://www.gnu.org/software/emacs/") - t])))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; -;;; Tweak to XEmacs buffer tabs (not really compatibility) -;;; - -;; We remove PG auxiliary buffers from tabs. -;; TODO: complain to XEmacs developers about overly generous matching -;; in this function. In XEmacs post 21.5 one can set names of buffers -;; to omit just from tabs list. - -(if (featurep 'xemacs) - (progn - - (fset 'select-buffers-tab-buffers-by-mode-old - (symbol-function 'select-buffers-tab-buffers-by-mode)) - - (defun select-buffers-tab-buffers-by-mode (buf1 buf2) - (let* ((mode1 (symbol-value-in-buffer 'major-mode buf1)) ;; candidate buf - (mode2 (symbol-value-in-buffer 'major-mode buf2)) ;; displayed buf - (auxes '(proof-goals-mode proof-shell-mode proof-response-mode)) - (mode1aux (memq (get mode1 'derived-mode-parent) auxes)) - (mode2aux (memq (get mode2 'derived-mode-parent) auxes))) - (cond - (mode1aux mode2aux) - (mode2aux nil) - (t (select-buffers-tab-buffers-by-mode-old buf1 buf2))))) - )) ;; end XEmacs featurep - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; Workaround GNU Emacs problems in easymenu-add -;; - -(if (not (featurep 'xemacs)) - ;; This has a nasty side effect of removing accelerators - ;; from existing menus when easy-menu-add is called. - ;; Problem confirmed in versions: 21.4.1, OK: 22.1.1 - (or (< emacs-major-version 22) - (setq easy-menu-precalculate-equivalent-keybindings nil))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; XEmacs/x-symbol compatibility for XEmacs 21.5 -;; -;; See http://thread.gmane.org/gmane.emacs.xemacs.beta/20171/focus=20172 - -(if (and (fboundp 'valid-specifier-tag-p) - (not (valid-specifier-tag-p 'mule-fonts))) - (if (fboundp 'define-specifier-tag) - (define-specifier-tag 'mule-fonts))) - ;; End of proof-compat.el (provide 'proof-compat) diff --git a/lib/span-extent.el b/lib/span-extent.el deleted file mode 100644 index 8af787c7..00000000 --- a/lib/span-extent.el +++ /dev/null @@ -1,139 +0,0 @@ -;; This file implements spans in terms of extents, for xemacs. -;; -;; Copyright (C) 1998 LFCS Edinburgh -;; Author: Healfdene Goguen -;; Maintainer: David Aspinall <David.Aspinall@ed.ac.uk> -;; License: GPL (GNU GENERAL PUBLIC LICENSE) -;; -;; $Id$ - -;; XEmacs-Emacs compatibility: define "spans" in terms of extents. - -(defsubst span-make (start end) - "Make a span for the range [START, END) in current buffer." - (make-extent start end)) - -(defsubst span-detach (span) - "Remove SPAN from its buffer." - (detach-extent span)) - -(defsubst span-set-endpoints (span start end) - "Set the endpoints of SPAN to START, END." - (set-extent-endpoints span start end)) - -(defsubst span-set-property (span name value) - "Set SPAN's property NAME to VALUE." - (set-extent-property span name value)) - -(defsubst span-read-only (span) - "Set SPAN to be read only." - (span-set-property span 'read-only t)) - -(defsubst span-read-write (span) - "Set SPAN to be writeable." - (span-set-property span 'read-only nil)) - -(defun span-give-warning (&rest args) - "Give a warning message." - (message "You should not edit here!")) - -(defun span-write-warning (span) - "Give a warning message when SPAN is changed." - ;; FIXME: implement this in XEmacs, perhaps with after-change-functions - (span-set-property span 'read-only nil)) - -(defsubst span-property (span name) - "Return SPAN's value for property PROPERTY." - (extent-property span name)) - -(defsubst span-delete (span) - "Delete SPAN." - (let ((predelfn (span-property span 'span-delete-action))) - (and predelfn (funcall predelfn))) - (delete-extent span)) - -(defsubst span-mapcar-spans (fn start end prop &optional val) - "Apply function FN to all spans between START and END with property PROP set" - (mapcar-extents fn nil (current-buffer) start end nil prop val)) - -(defsubst spans-at-region-prop (start end prop &optional val) - "Return a list of the spans in START END with PROP [set to VAL]." - (extent-list (current-buffer) start end nil prop val)) - -(defsubst span-at (pt prop) - "Return the smallest SPAN at point PT with property PROP." - (extent-at pt nil prop)) - -(defsubst span-at-before (pt prop) - "Return the smallest SPAN at before PT with property PROP. -A span is before PT if it covers the character before PT." - (extent-at pt nil prop nil 'before)) - -(defsubst span-start (span) - "Return the start position of SPAN, or nil if SPAN is detatched." - (extent-start-position span)) - -(defsubst span-end (span) - "Return the end position of SPAN, or nil if SPAN is detatched." - (extent-end-position span)) - -(defsubst prev-span (span prop) - "Return span before SPAN with property PROP." - (extent-at (extent-start-position span) nil prop nil 'before)) - -(defsubst next-span (span prop) - "Return span after SPAN with property PROP." - (extent-at (extent-end-position span) nil prop nil 'after)) - -(defsubst span-live-p (span) - "Return non-nil if SPAN is live and in a live buffer." - (and span - (extent-live-p span) - (buffer-live-p (extent-object span)) - ;; PG 3.4: add third test here to see not detached. - (not (extent-detached-p span)))) - -(defun span-raise (span) - "Function added for FSF Emacs compatibility. Do nothing here." - nil) - -(defalias 'span-object 'extent-object) -(defalias 'span-string 'extent-string) - -;Pierre: new utility functions for "holes" -(defsubst make-detached-span () - (make-extent nil nil) - ) - - -(defsubst span-buffer (span) - "Return the buffer owning span." - (extent-object span) - ) - -(defsubst span-detached-p (span) - "is this span detached? nil for no, t for yes" - (extent-detached-p span) -) - -(defsubst set-span-face (span face) - "set the face of a span" - (set-extent-face span face)) - -(defsubst fold-spans (function &optional object from to maparg flags property value) - "map on span, see map-extent on xemacs" - (map-extents function object from to maparg flags property value)) - -(defsubst set-span-properties (span plist) - "see extent-properties" - (set-extent-properties span plist)) - -(defsubst set-span-keymap (span map) - "Set the keymap of SPAN to MAP" - (set-extent-keymap span map)) - -;there are more args to extent-at-event -(defsubst span-at-event (event &optional prop) - (extent-at-event event prop)) - -(provide 'span-extent) diff --git a/lib/span-overlay.el b/lib/span-overlay.el deleted file mode 100644 index fe51ebc6..00000000 --- a/lib/span-overlay.el +++ /dev/null @@ -1,222 +0,0 @@ -;; This file implements spans in terms of extents, for emacs19. -;; -;; Copyright (C) 1998 LFCS Edinburgh -;; Author: Healfdene Goguen -;; Maintainer: David Aspinall <David.Aspinall@ed.ac.uk> -;; License: GPL (GNU GENERAL PUBLIC LICENSE) -;; -;; $Id$ - -;; XEmacs-Emacs compatibility: define "spans" in terms of overlays. - -(defalias 'span-start 'overlay-start) -(defalias 'span-end 'overlay-end) -(defalias 'span-set-property 'overlay-put) -(defalias 'span-property 'overlay-get) -(defalias 'span-make 'make-overlay) -(defalias 'span-detach 'delete-overlay) -(defalias 'span-set-endpoints 'move-overlay) -(defalias 'span-buffer 'overlay-buffer) - -(defun span-read-only-hook (overlay after start end &optional len) - (unless inhibit-read-only - (error "Region is read-only"))) - -(defun span-read-only (span) - "Set SPAN to be read only." - ;; This function may be called on spans which are detached from a - ;; buffer, which gives an error here, since text-properties are - ;; associated with text in a particular buffer position. So we use - ;; our own read only hook. - ;(add-text-properties (span-start span) (span-end span) '(read-only t))) - ;; 30.8.02: tested using overlay-put as below with Emacs 21.2.1, - ;; bit this seems to have no effect when the overlay is added to - ;; the buffer. (Maybe read-only is only a text property, not an - ;; overlay property?). - ;; (overlay-put span 'read-only t)) - (span-set-property span 'modification-hooks '(span-read-only-hook)) - (span-set-property span 'insert-in-front-hooks '(span-read-only-hook))) - -(defun span-read-write (span) - "Set SPAN to be writeable." - ;; See comment above for text properties problem. - (span-set-property span 'modification-hooks nil) - (span-set-property span 'insert-in-front-hooks nil)) - -(defun span-give-warning (&rest args) - "Give a warning message." - (message "You should not edit here!")) - -(defun span-write-warning (span) - "Give a warning message when SPAN is changed." - (span-set-property span 'modification-hooks '(span-give-warning)) - (span-set-property span 'insert-in-front-hooks '(span-give-warning))) - -;; We use end first because proof-locked-queue is often changed, and -;; its starting point is always 1 -(defun span-lt (s u) - (or (< (span-end s) (span-end u)) - (and (eq (span-end s) (span-end u)) - (< (span-start s) (span-start u))))) - -(defun spans-at-point-prop (pt prop) - (let ((ols ())) - (dolist (ol (overlays-at pt)) - (if (or (null prop) (overlay-get ol prop)) (push ol ols))) - ols)) - -(defun spans-at-region-prop (start end prop &optional val) - "Return a list of the spans in START END with PROP [set to VAL]." - (let ((ols ())) - (dolist (ol (overlays-in start end)) - (if (or (null prop) - (if val (eq val (overlay-get ol prop)) (overlay-get ol prop))) - (push ol ols))) - ols)) - -(defun span-at (pt prop) - "Return the SPAN at point PT with property PROP. -For XEmacs, span-at gives smallest extent at pos. -For Emacs, we assume that spans don't overlap." - (car (spans-at-point-prop pt prop))) - -(defsubst span-delete (span) - "Delete SPAN." - (let ((predelfn (span-property span 'span-delete-action))) - (and predelfn (funcall predelfn))) - (delete-overlay span)) - -;; The next two change ordering of list of spans: -(defsubst span-mapcar-spans (fn start end prop &optional val) - "Apply function FN to all spans between START and END with property PROP set" - (mapcar fn (spans-at-region-prop start end prop (or val nil)))) - -(defun span-at-before (pt prop) - "Return the smallest SPAN at before PT with property PROP. -A span is before PT if it begins before the character before PT." - (let ((ols (if (eq (point-min) pt) - nil ;; (overlays-at pt) - (overlays-in (1- pt) pt)))) - ;; Check the PROP is set. - (when prop - (dolist (ol (prog1 ols (setq ols nil))) - (if (overlay-get ol prop) (push ol ols)))) - ;; Eliminate the case of an empty overlay at (1- pt). - (dolist (ol (prog1 ols (setq ols nil))) - (if (>= (overlay-end ol) pt) (push ol ols))) - ;; "Get the smallest". I have no idea what that means, so I just do - ;; something somewhat random but vaguely meaningful. -Stef - (car (last (sort ols 'span-lt))))) - -(defun prev-span (span prop) - "Return span before SPAN with property PROP." - (span-at-before (span-start span) prop)) - -; overlays are [start, end) - -(defun next-span (span prop) - "Return span after SPAN with property PROP." - ;; Presuming the span-extents.el is the reference, its code does the same - ;; as the code below. - (span-at (span-end span) prop) - ;; ;; 3.4 fix here: Now we do a proper search, so this should work with - ;; ;; nested overlays, after a fashion. Use overlays-in to get a list - ;; ;; for the entire buffer, this avoids repeatedly checking the same - ;; ;; overlays in an ever expanding list (see v6.1). (However, this - ;; ;; list may be huge: is it a bottleneck?) - ;; ;; [Why has this function never used the before-list ?] - ;; (let* ((start (overlay-start span)) - ;; ;; (pos start) - ;; (nextos (overlays-in (overlay-end span) - ;; (1+ start) - ;; (point-max))) - ;; (resstart (1+ (point-max))) - ;; spanres) - ;; ;; overlays are returned in an unspecified order; we - ;; ;; must search whole list for a closest-next one. - ;; (dolist (newres nextos spanres) - ;; (if (and (span-property newres prop) - ;; (< start (span-start newres)) - ;; (< (span-start newres) resstart)) - ;; (progn - ;; (setq spanres newres) - ;; (setq resstart (span-start spanres)))))) -) - -(defsubst span-live-p (span) - "Return non-nil if SPAN is in a live buffer." - (and span - (overlay-buffer span) - (buffer-live-p (overlay-buffer span)))) - -(defun span-raise (span) - "Set priority of span to make it appear above other spans. -FIXME: new hack added nov 99 because of disappearing overlays. -Behaviour is still worse than before." ;??? --Stef - (span-set-property span 'priority 100)) - -(defalias 'span-object 'overlay-buffer) - -(defun span-string (span) - (with-current-buffer (overlay-buffer span) - (buffer-substring (overlay-start span) (overlay-end span)))) - - -;Pierre: new utility functions for "holes" -(defun set-span-properties (span plist) - "Set SPAN's properties, plist is a plist." - (let ((pl plist)) - (while pl - (let* ((name (car pl)) - (value (car (cdr pl)))) - (overlay-put span name value) - (setq pl (cdr (cdr pl)))) - ) - ) - ) - -(defun span-find-span (overlay-list &optional prop) - "Returns the first overlay of overlay-list having property prop (default 'span), nil if no such overlay belong to the list." - (let ((l overlay-list)) - (while (and l (not (overlay-get (car l) (or prop 'span)))) - (setq l (cdr l))) - (car l))) - -(defsubst span-at-event (event &optional prop) - (span-find-span (overlays-at (posn-point (event-start event))) prop)) - - -(defun make-detached-span () - (let ((ol (make-overlay 0 0))) - (delete-overlay ol) - ol)) - -(defun fold-spans (f &optional buffer from to maparg ignored-flags prop val) - (with-current-buffer (or buffer (current-buffer)) - (let ((ols (overlays-in (or from (point-min)) (or to (point-max)))) - res) - ;; Check the PROP. - (when prop - (dolist (ol (prog1 ols (setq ols nil))) - (if (if val (eq val (overlay-get ol prop)) (overlay-get ol prop)) - (push ol ols)))) - ;; Iterate in order. - (setq ols (sort ols 'span-lt)) - (while (and ols (not (setq res (funcall f (pop ols) maparg))))) - res))) - - -(defsubst span-detached-p (span) - "is this span detached? nil for no, t for yes" - (null (overlay-buffer span))) - -(defsubst set-span-face (span face) - "set the face of a span" - (overlay-put span 'face face)) - -(defun set-span-keymap (span map) - "Set the keymap of SPAN to MAP" - (overlay-put span 'keymap map) - (overlay-put span 'local-map map)) - -(provide 'span-overlay) diff --git a/lib/span.el b/lib/span.el index a07da038..5f87e015 100644 --- a/lib/span.el +++ b/lib/span.el @@ -1,19 +1,204 @@ -;; span.el Datatype of "spans" for Proof General. +;;; span.el --- Datatype of "spans" for Proof General ;; -;; Copyright (C) 1998 LFCS Edinburgh -;; Author: Healfdene Goguen -;; License: GPL (GNU GENERAL PUBLIC LICENSE) +;; Copyright (C) 1998-2008 LFCS Edinburgh +;; Author: Healfdene Goguen +;; Maintainer: David Aspinall <David.Aspinall@ed.ac.uk> +;; License: GPL (GNU GENERAL PUBLIC LICENSE) ;; ;; $Id$ ;; -;; Spans are our abstraction of extents/overlays. +;;; Commentary: +;; +;; Spans are our abstraction of extents/overlays. Nowadays +;; we implement them directly with overlays. +;; +;; In future this module should be used to implement the abstraction +;; for script buffers (only) more directly. ;; -(eval-and-compile - (if (featurep 'xemacs) - (require 'span-extent)) - (if (not (featurep 'xemacs)) - (require 'span-overlay))) +;;; Code: +(eval-when-compile (require 'cl)) ;For lexical-let. + +(defalias 'span-start 'overlay-start) +(defalias 'span-end 'overlay-end) +(defalias 'span-set-property 'overlay-put) +(defalias 'span-property 'overlay-get) +(defalias 'span-make 'make-overlay) +(defalias 'span-detach 'delete-overlay) +(defalias 'span-set-endpoints 'move-overlay) +(defalias 'span-buffer 'overlay-buffer) + +(defun span-read-only-hook (overlay after start end &optional len) + (unless inhibit-read-only + (error "Region is read-only"))) +(add-to-list 'debug-ignored-errors "Region is read-only") + +(defun span-read-only (span) + "Set SPAN to be read only." + ;; Note: using the standard 'read-only property does not work. + ;; (overlay-put span 'read-only t)) + (span-set-property span 'modification-hooks '(span-read-only-hook)) + (span-set-property span 'insert-in-front-hooks '(span-read-only-hook))) + +(defun span-read-write (span) + "Set SPAN to be writeable." + (span-set-property span 'modification-hooks nil) + (span-set-property span 'insert-in-front-hooks nil)) + +(defun span-give-warning (&rest args) + "Give a warning message. +Optional argument ARGS is ignored." + (message "You should not edit here!")) + +(defun span-write-warning (span &optional fun) + "Give a warning message when SPAN is changed. +Optional argument FUN is used in place of `span-give-warning'." + (unless fun (setq fun 'span-give-warning)) + (lexical-let ((fun fun)) + (let ((funs (list (lambda (span afterp beg end &rest args) + (if (not afterp) (funcall fun beg end)))))) + (span-set-property span 'modification-hooks funs) + (span-set-property span 'insert-in-front-hooks funs)))) + +;; We use end first because proof-locked-queue is often changed, and +;; its starting point is always 1 +(defun span-lt (s u) + (or (< (span-end s) (span-end u)) + (and (eq (span-end s) (span-end u)) + (< (span-start s) (span-start u))))) + +(defun spans-at-point-prop (pt prop) + (let ((ols ())) + (dolist (ol (overlays-at pt)) + (if (or (null prop) (overlay-get ol prop)) (push ol ols))) + ols)) + +(defun spans-at-region-prop (start end prop &optional val) + "Return a list of the spans in START END with PROP [set to VAL]." + (let ((ols ())) + (dolist (ol (overlays-in start end)) + (if (or (null prop) + (if val (eq val (overlay-get ol prop)) (overlay-get ol prop))) + (push ol ols))) + ols)) + +(defun span-at (pt prop) + "Return the SPAN at point PT with property PROP. +For XEmacs, `span-at' gives smallest extent at pos. +For Emacs, we assume that spans don't overlap." + (car (spans-at-point-prop pt prop))) + +(defsubst span-delete (span) + "Delete SPAN." + (let ((predelfn (span-property span 'span-delete-action))) + (and predelfn (funcall predelfn))) + (delete-overlay span)) + +;; The next two change ordering of list of spans: +(defsubst span-mapcar-spans (fn start end prop &optional val) + "Apply function FN to all spans between START and END with property PROP set. +Optional argument VAL filters value of property." + (mapcar fn (spans-at-region-prop start end prop (or val nil)))) + +(defun span-at-before (pt prop) + "Return the smallest SPAN at before PT with property PROP. +A span is before PT if it begins before the character before PT." + (let ((ols (if (eq (point-min) pt) + nil ;; (overlays-at pt) + (overlays-in (1- pt) pt)))) + ;; Check the PROP is set. + (when prop + (dolist (ol (prog1 ols (setq ols nil))) + (if (overlay-get ol prop) (push ol ols)))) + ;; Eliminate the case of an empty overlay at (1- pt). + (dolist (ol (prog1 ols (setq ols nil))) + (if (>= (overlay-end ol) pt) (push ol ols))) + ;; "Get the smallest". I have no idea what that means, so I just do + ;; something somewhat random but vaguely meaningful. -Stef + (car (last (sort ols 'span-lt))))) + +(defun prev-span (span prop) + "Return span before SPAN with property PROP." + (span-at-before (span-start span) prop)) + +; overlays are [start, end) + +(defun next-span (span prop) + "Return span after SPAN with property PROP." + ;; Presuming the span-extents.el is the reference, its code does the same + ;; as the code below. + (span-at (span-end span) prop) +) + +(defsubst span-live-p (span) + "Return non-nil if SPAN is in a live buffer." + (and span + (overlay-buffer span) + (buffer-live-p (overlay-buffer span)))) + +(defun span-raise (span) + "Set priority of SPAN to make it appear above other spans." + (span-set-property span 'priority 100)) + +(defalias 'span-object 'overlay-buffer) + +(defun span-string (span) + (with-current-buffer (overlay-buffer span) + (buffer-substring (overlay-start span) (overlay-end span)))) + + +(defun set-span-properties (span plist) + "Set SPAN's properties, PLIST is a plist." + (let ((pl plist)) + (while pl + (let* ((name (car pl)) + (value (car (cdr pl)))) + (overlay-put span name value) + (setq pl (cdr (cdr pl)))) + ))) + +(defun span-find-span (overlay-list &optional prop) + "Return the first overlay of OVERLAY-LIST having property PROP (default 'span), nil if no such overlay belong to the list." + (let ((l overlay-list)) + (while (and l (not (overlay-get (car l) (or prop 'span)))) + (setq l (cdr l))) + (car l))) + +(defsubst span-at-event (event &optional prop) + (span-find-span (overlays-at (posn-point (event-start event))) prop)) + + +(defun make-detached-span () + (let ((ol (make-overlay 0 0))) + (delete-overlay ol) + ol)) + +(defun fold-spans (f &optional buffer from to maparg ignored-flags prop val) + (with-current-buffer (or buffer (current-buffer)) + (let ((ols (overlays-in (or from (point-min)) (or to (point-max)))) + res) + ;; Check the PROP. + (when prop + (dolist (ol (prog1 ols (setq ols nil))) + (if (if val (eq val (overlay-get ol prop)) (overlay-get ol prop)) + (push ol ols)))) + ;; Iterate in order. + (setq ols (sort ols 'span-lt)) + (while (and ols (not (setq res (funcall f (pop ols) maparg))))) + res))) + +(defsubst span-detached-p (span) + "Is this SPAN detached? nil for no, t for yes." + (null (overlay-buffer span))) + +(defsubst set-span-face (span face) + "Set the FACE of a SPAN." + (overlay-put span 'face face)) + +(defun set-span-keymap (span map) + "Set the keymap of SPAN to MAP." + (overlay-put span 'keymap map) + (overlay-put span 'local-map map)) ;; ;; Generic functions built on low-level concrete ones. @@ -35,5 +220,7 @@ "Set the end point of SPAN to VALUE." (span-set-endpoints span (span-start span) value)) + (provide 'span) -;; span.el ends here. + +;;; span.el ends here diff --git a/lib/unicode-tokens.el b/lib/unicode-tokens.el index b789be93..98ff325e 100644 --- a/lib/unicode-tokens.el +++ b/lib/unicode-tokens.el @@ -1,4 +1,4 @@ -;;; unicode-tokens.el --- Support for editing tokens for Unicode characters +;;; unicode-tokens.el --- Support for control and symbol tokens ;; ;; Copyright(C) 2008 David Aspinall / LFCS Edinburgh ;; Author: David Aspinall <David.Aspinall@ed.ac.uk> @@ -6,9 +6,6 @@ ;; ;; $Id$ ;; -;; A few functions are adapted from `xmlunicode.el' by Norman Walsh. -;; Created: 2004-07-21, Version: 1.6, Copyright (C) 2003 Norman Walsh -;; ;; This is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) @@ -26,93 +23,142 @@ ;;; Commentary: ;; -;; This is a partial replacement for X-Symbol for Proof General. -;; STATUS: experimental. +;; This is a replacement for X-Symbol for Proof General. ;; -;; Functions to help insert tokens that represent Unicode characters -;; and control code sequences for changing the layout. Character -;; tokens are useful for programs that do not understand a Unicode -;; encoding. +;; Functions to display tokens that represent Unicode characters and +;; control code sequences for changing the layout. Tokens are useful +;; for programs that do not understand a Unicode encoding. ;; ;; TODO: -;; -- saving of font-lock-face annotations unreliable, possible confusion -;; over handling of lists in format.el -;; -- add input methods for subscript/superscripts (further props in general) -;; -- after change function so inserting control sequences works? or other support -;; -- one-char subs should not be sticky so doesn't extend -;; -- make property removal more accurate/patch in font-lock -;; -- disentangle Isabelle specific code -;; -- perhaps separate out short-cut input method and don't use for tokens -;; -- cleanup insertion functions -;; -- investigate testing for an appropriate glyph +;; -- insert tokens via numeric code (extra format string) +;; -- insert unicode character as token (reverse lookup) (require 'cl) -(require 'unicode-chars) ; list of Unicode characters +(eval-when-compile + (require 'maths-menu)) ; nuke compile warnings ;; -;; Variables that should be set -;; (default settings are for XML, but configuration incomplete; -;; use xmlunicode.el instead) +;; Variables that can be overridden in instances: symbol tokens ;; -(defvar unicode-tokens-charref-format "&#x%x;" - "The format for numeric character references") +(defvar unicode-tokens-token-symbol-map nil + "Mapping of token names to compositions. +Each element is a list -(defvar unicode-tokens-token-format "&%x;" - "The format for token character references") + (TOKNAME COMPOSITION FONTSYMB ...) -(defvar unicode-tokens-token-name-alist nil - "Mapping of token names to Unicode strings.") +A composition is typically a single Unicode character string, but +can be more complex: see documentation of `compose-region'. -(defvar unicode-tokens-glyph-list nil - "List of available glyphs, as characters. -If not set, constructed to include glyphs for all tokens. ") +The list of FONTSYMB are optional. Each FONTSYMB is a symbol +indicating a set of text properties, looked up in +`unicode-tokens-fontsymb-properties'.") -(defvar unicode-tokens-token-prefix "&" - "Prefix for start of tokens to insert.") +(defvar unicode-tokens-token-format "%s" + "Format string for formatting token a name into a token. +Will be regexp quoted for matching. Not used for matching if +`unicode-tokens-token-variant-format-regexp' is set. +Also used to format shortcuts.") -(defvar unicode-tokens-token-suffix ";" - "Suffix for end of tokens to insert.") +(defvar unicode-tokens-token-variant-format-regexp nil + "A regular expression which matches a token variant. +Will not be regexp quoted, and after format is applied, must -(defvar unicode-tokens-control-token-match nil - "Regexp matching tokens") +An example would be: \\\\(%s\\\\)\\\\(:?\\w+\\\\) -(defvar unicode-tokens-token-match "&\\([A-Za-z]\\);" - "Regexp matching tokens") +which matches plain token strings optionally followed by a colon and +variant name. -(defvar unicode-tokens-hexcode-match "&#[xX]\\([0-9a-fA-F]+\\);" - "Regexp matching numeric token string") +If set, this variable is used instead of `unicode-tokens-token-format'.") +;; (setq ut-tvfr "\\(%s\\)\\(:?\\w+\\)") +;; (string-match (format ut-tvfr ".*?") "alpha:x") -(defvar unicode-tokens-next-character-regexp "&#[xX]\\([0-9a-fA-F]+\\);\\|." - "Regexp matching a logical character following a control code.") +(defvar unicode-tokens-fontsymb-properties nil + "Association list mapping a symbol to a list of text properties. +Used in `unicode-tokens-token-symbol-map', `unicode-tokens-control-regions', +and `unicode-tokens-control-characters'.") -(defvar unicode-tokens-shortcut-alist +(defvar unicode-tokens-shortcut-alist nil "An alist of keyboard shortcuts to unicode strings. The alist is added to the input mode for tokens. Behaviour is much like abbrev.") + ;; -;; Faces +;; Variables that can be overridden in instances: control tokens ;; +;; TODO: docs +(defvar unicode-tokens-control-region-format-regexp nil) +(defvar unicode-tokens-control-char-format-regexp nil) +(defvar unicode-tokens-control-regions nil) +(defvar unicode-tokens-control-characters nil) + +(defvar unicode-tokens-control-region-format-beg nil) +(defvar unicode-tokens-control-region-format-end nil) +(defvar unicode-tokens-control-char-format nil) + +;; +;; A list of the above variables +;; + +(defconst unicode-tokens-configuration-variables + '(token-symbol-map + token-format + token-variant-format-regexp + fontsymb-properties + shortcut-alist + control-region-format-regexp + control-region-format-beg + control-region-format-end + control-char-format-regexp + control-char-format + control-regions + control-characters)) + +;; +;; Variables set in the mode ;; -;; TODO: make these into faces but extract attributes -;; to use in `unicode-tokens-annotation-translations'. -;; Let that be dynamically changeable -;; TODO: choose family acccording to likely architecture and what's available -(cond - ((not (featurep 'xemacs)) + +(defvar unicode-tokens-token-list nil + "List of usable token names in order from `unicode-tokens-token-symbol-map'.") + +(defvar unicode-tokens-hash-table nil + "Hash table mapping token names (strings) to composition and properties.") + +(defvar unicode-tokens-token-match-regexp nil + "Regular expression used by font-lock to match tokens.") + +(defvar unicode-tokens-uchar-hash-table nil + "Hash table mapping unicode strings to symbolic token names. +This is used for an approximate reverse mapping, see `unicode-tokens-paste'.") + +(defvar unicode-tokens-uchar-regexp nil + "Regular expression matching converted tokens. +This is used for an approximate reverse mapping, see `unicode-tokens-paste'.") + + + +;; +;; Constants +;; + +(defgroup unicode-tokens-faces nil + "The faces used in Unicode Tokens mode." + :group 'faces) + (defface unicode-tokens-script-font-face (cond ((eq window-system 'x) ; Linux/Unix - '((t :family "URW Chancery L"))) + '((t :family "PakTypeNaqsh"))) ; ((or ; Mac (eq window-system 'ns) (eq window-system 'carbon)) '((t :family "Lucida Calligraphy")))) - "Script font face") + "Script font face" + :group 'unicode-tokens-faces) (defface unicode-tokens-fraktur-font-face (cond @@ -122,7 +168,8 @@ Behaviour is much like abbrev.") (eq window-system 'ns) (eq window-system 'carbon)) '((t :family "Lucida Blackletter")))) - "Fraktur font face") + "Fraktur font face" + :group 'unicode-tokens-faces) (defface unicode-tokens-serif-font-face (cond @@ -132,220 +179,166 @@ Behaviour is much like abbrev.") (eq window-system 'ns) (eq window-system 'carbon)) '((t :family "Lucida")))) - "Serif (roman) font face"))) + "Serif (roman) font face" + :group 'unicode-tokens-faces) +(defconst unicode-tokens-font-lock-extra-managed-props + '(composition help-echo display invisible) + "Value for `font-lock-extra-managed-props' here.") ;; -;; Variables initialised in unicode-tokens-initialise +;;; Code: ;; -(defvar unicode-tokens-max-token-length 10 - "Maximum length of a token in underlying encoding.") - -(defvar unicode-tokens-codept-charname-alist nil - "Alist mapping unicode code point to character names.") +(defun unicode-tokens-font-lock-keywords () + "Calculate and return value for `font-lock-keywords'. +This function also initialises the important tables for the mode." + ;; Credit to Stefan Monnier for much slimmer original version + (let ((hash (make-hash-table :test 'equal)) + (ucharhash (make-hash-table :test 'equal)) + toks uchars) + (dolist (x unicode-tokens-token-symbol-map) + (let ((tok (car x)) + (comp (cadr x))) + (when (unicode-tokens-usable-composition comp) + (unless (gethash tok hash) + (puthash tok (cdr x) hash) + (push tok toks) + (if (stringp comp) ;; reverse map only for string comps + (unless (or (gethash comp ucharhash) + ;; ignore plain chars for reverse map + (string-match "[a-zA-Z0-9]+" comp)) + (push comp uchars) + (puthash comp tok ucharhash))))))) + (when toks + (setq unicode-tokens-hash-table hash) + (setq unicode-tokens-uchar-hash-table ucharhash) + (setq unicode-tokens-token-list (reverse toks)) + (setq unicode-tokens-uchar-regexp (regexp-opt uchars)) + (setq unicode-tokens-token-match-regexp + (if unicode-tokens-token-variant-format-regexp + (format unicode-tokens-token-variant-format-regexp + (regexp-opt toks t)) + (regexp-opt (mapcar (lambda (tok) + (format unicode-tokens-token-format tok)) + toks) t))) + (cons + `(,unicode-tokens-token-match-regexp + (0 (unicode-tokens-help-echo) 'prepend) + (0 (unicode-tokens-font-lock-compose-symbol + ,(- (regexp-opt-depth unicode-tokens-token-match-regexp) 2)) + 'prepend)) + (unicode-tokens-control-font-lock-keywords))))) + +(defun unicode-tokens-usable-composition (comp) + (cond + ((stringp comp) + (reduce (lambda (x y) (and x (char-displayable-p y))) + comp + :initial-value t)) + ((char-valid-p comp) + (char-displayable-p comp)) + (comp ;; assume any other non-null is OK + t))) + +(defun unicode-tokens-help-echo () + "Return a help-echo text property to display the contents of match string" + (list 'face nil 'help-echo (match-string 0))) + +(defvar unicode-tokens-show-symbols nil + "Non-nil to reveal symbol (composed) tokens instead of compositions.") + +(defun unicode-tokens-font-lock-compose-symbol (match) + "Compose a sequence of chars into a symbol, maybe returning a face property. +Regexp match data number MATCH selects the token name, while 0 matches the +whole expression. +Token symbol is searched for in `unicode-tokens-hash-table'." + (let* ((start (match-beginning 0)) + (end (match-end 0)) + (compps (gethash (match-string match) + unicode-tokens-hash-table)) + (props (cdr-safe compps))) + (if (and compps (not unicode-tokens-show-symbols)) + (compose-region start end (car compps))) + (if props + (add-text-properties ;; font-lock should do this but fails? + start end (unicode-tokens-symbs-to-props props))) + nil)) + +(defun unicode-tokens-show-symbols (&optional arg) + "Toggle `unicode-tokens-show-symbols'. With ARG, turn on iff positive." + (interactive "P") + (setq unicode-tokens-show-symbols + (if (null arg) (not unicode-tokens-show-symbols) + (> (prefix-numeric-value arg) 0))) + (font-lock-fontify-buffer)) + +(defun unicode-tokens-symbs-to-props (symbs &optional facenil) + (let (props p) + (dolist (s symbs) + (setq p (car-safe + (cdr-safe (assoc s unicode-tokens-fontsymb-properties)))) + (if (consp p) + (setq props (cons (car p) (cons (cadr p) props))) + (setq props (cons p props)))) + (if (and facenil + (not (memq 'face props))) + (setq props (append '(face nil) props))) + props)) -(defvar unicode-tokens-token-alist nil - "Mapping of tokens to Unicode strings. -Also used as a flag to detect if `unicode-tokens-initialise' has been called.") +;; +;; Control tokens: as "characters" CTRL <stuff> +;; and regions BEGINCTRL <stuff> ENDCTRL +;; -(defvar unicode-tokens-ustring-alist nil - "Mapping of Unicode strings to tokens.") +(defvar unicode-tokens-show-controls nil + "Non-nil supresses hiding of control tokens.") +(defun unicode-tokens-show-controls (&optional arg) + "Toggle `unicode-tokens-show-controls'. With ARG, turn on iff positive." + (interactive "P") + (setq unicode-tokens-show-controls + (if (null arg) (not unicode-tokens-show-controls) + (> (prefix-numeric-value arg) 0))) + (when unicode-tokens-show-controls + (remove-from-invisibility-spec 'unicode-tokens-show-controls)) + (when (not unicode-tokens-show-controls) + (add-to-invisibility-spec 'unicode-tokens-show-controls))) + +(defun unicode-tokens-control-char (name s &rest props) + `(,(format unicode-tokens-control-char-format-regexp s) + (1 '(face nil invisible unicode-tokens-show-controls) prepend) + (2 ',(unicode-tokens-symbs-to-props props t) prepend))) + +(defun unicode-tokens-control-region (name start end &rest props) + `(,(format unicode-tokens-control-region-format-regexp start end) + (1 '(face nil invisible unicode-tokens-show-controls) prepend) + (2 ',(unicode-tokens-symbs-to-props props t) prepend) + (3 '(face nil invisible unicode-tokens-show-controls) prepend))) + +(defun unicode-tokens-control-font-lock-keywords () + (append + (mapcar (lambda (args) (apply 'unicode-tokens-control-char args)) + unicode-tokens-control-characters) + (mapcar (lambda (args) (apply 'unicode-tokens-control-region args)) + unicode-tokens-control-regions))) ;; -;;; Code: +;; Shortcuts for typing, using quail ;; - -(defun unicode-tokens-insert-char (arg codepoint) - "Insert the Unicode character identified by CODEPOINT. -If ARG is non-nil, ignore available glyphs." - (let ((glyph (memq codepoint unicode-tokens-glyph-list))) - (cond - ((and (decode-char 'ucs codepoint) (or arg glyph)) - (ucs-insert codepoint)) ;; glyph converted to token on save - (t - (insert (format unicode-tokens-charref-format codepoint)))))) - -(defun unicode-tokens-insert-string (arg ustring) - "Insert a Unicode string. -If a prefix is given, the string will be inserted regardless -of whether or not it has displayable glyphs; otherwise, a -numeric character reference for whichever codepoints are not -in the unicode-tokens-glyph-list." - (mapcar (lambda (char) - (unicode-tokens-insert-char arg char)) - ustring)) - -(defun unicode-tokens-character-insert (arg &optional argname) - "Insert a Unicode character by character name, with completion. -If a prefix is given, the character will be inserted regardless -of whether or not it has a displayable glyph; otherwise, a -numeric character reference is inserted if the codepoint is not -in the `unicode-tokens-glyph-list'. If argname is given, it is used for -the prompt. If argname uniquely identifies a character, that -character is inserted without the prompt." - (interactive "P") - (let* ((completion-ignore-case t) - (uniname (if (stringp argname) argname "")) - (charname - (if (eq (try-completion uniname unicode-chars-alist) t) - uniname - (completing-read - "Unicode name: " - unicode-chars-alist - nil t uniname))) - codepoint glyph) - (setq codepoint (cdr (assoc charname unicode-chars-alist))) - (unicode-tokens-insert-char arg codepoint))) - -(defun unicode-tokens-token-insert (arg &optional argname) - "Insert a Unicode string by a token name, with completion. -If a prefix is given, the string will be inserted regardless -of whether or not it has displayable glyphs; otherwise, a -numeric character reference for whichever codepoints are not -in the unicode-tokens-glyph-list. If argname is given, it is used for -the prompt. If argname uniquely identifies a character, that -character is inserted without the prompt." - (interactive "P") - (let* ((stokname (if (stringp argname) argname "")) - (tokname - (if (eq (try-completion stokname unicode-tokens-token-name-alist) t) - stokname - (completing-read - "Token name: " - unicode-tokens-token-name-alist - nil t stokname))) - charname ustring) - (setq ustring (cdr (assoc tokname unicode-tokens-token-name-alist))) - (unicode-tokens-insert-string arg ustring))) - -(defun unicode-tokens-replace-token-after (length) - (let ((bpoint (point)) ustring) - (save-excursion - (forward-char length) - (save-match-data - (while (re-search-backward - unicode-tokens-token-match - (max (- bpoint unicode-tokens-max-token-length) - (point-min)) t nil) - (setq ustring - (assoc (match-string 1) unicode-tokens-token-name-alist)) - (if ustring ;; TODO: should check on glyphs here - (progn - (let ((matchlen (- (match-end 0) (match-beginning 0)))) - (replace-match (replace-quote (cdr ustring))) - ;; was: (format "%c" (decode-char 'ucs (cadr codept))) - (setq length - (+ (- length matchlen) (length (cdr ustring))))))))))) - length) - - -;;stolen from hen.el which in turn claims to have stolen it from cxref -(defun unicode-tokens-looking-backward-at (regexp) - "Return t if text before point matches regular expression REGEXP. -This function modifies the match data that `match-beginning', -`match-end' and `match-data' access; save and restore the match -data if you want to preserve them." - (save-excursion - (let ((here (point))) - (if (re-search-backward regexp (point-min) t) - (if (re-search-forward regexp here t) - (= (point) here)))))) - -;; TODO: make this work for control tokens. -;; But it's a bit nasty and introduces font-lock style complexity again. -;; Better if we stick with dedicated input methods. -(defun unicode-tokens-electric-suffix () - "Detect tokens and replace them with the appropriate string. -This is bound to the character ending `unicode-tokens-token-suffix' -if there is such a unique character." - (interactive) - (let ((pos (point)) - (case-fold-search nil) - amppos codept ustring) - (search-backward unicode-tokens-token-prefix nil t nil) - (setq amppos (point)) - (goto-char pos) - (cond - ((unicode-tokens-looking-backward-at unicode-tokens-token-match) - (progn - (re-search-backward unicode-tokens-token-match nil t nil) - (if (= amppos (point)) - (progn - (setq ustring - (assoc (match-string 1) - unicode-tokens-token-name-alist)) - (if ustring ;; todo: check glyphs avail/use insert fn - (replace-match (replace-quote (cdr ustring))) - ;; was (format "%c" (decode-char 'ucs (cdr codept)))) - (progn - (goto-char pos) - (insert unicode-tokens-token-suffix)))) - (progn - (goto-char pos) - (insert unicode-tokens-token-suffix))))) - ((unicode-tokens-looking-backward-at unicode-tokens-hexcode-match) - (progn - (re-search-backward unicode-tokens-hexcode-match nil t nil) - (if (= amppos (point)) - (progn - (setq codept (string-to-number (match-string 1) 16)) - (if ;; todo : check glyph (memq codept unicode-tokens-glyph-list) - codept - (replace-match (format "%c" (decode-char 'ucs (cdr codept)))) - (progn - (goto-char pos) - (insert unicode-tokens-token-suffix)))) - (progn - (goto-char pos) - (insert unicode-tokens-token-suffix))))) - (t - (insert unicode-tokens-token-suffix))))) - -(defvar unicode-tokens-rotate-glyph-last-char nil) - -(defun unicode-tokens-rotate-glyph-forward (&optional n) - "Rotate the character before point in the current code page, by N steps. -If no character is found at the new codepoint, no change is made. -This function may only work reliably for GNU Emacs >= 23." - (interactive "p") - (if (> (point) (point-min)) - (let* ((codept (or (if (or (eq last-command - 'unicode-tokens-rotate-glyph-forward) - (eq last-command - 'unicode-tokens-rotate-glyph-backward)) - unicode-tokens-rotate-glyph-last-char) - (char-before (point)))) - (page (/ codept 256)) - (pt (mod codept 256)) - (newpt (mod (+ pt (or n 1)) 256)) - (newcode (+ (* 256 page) newpt)) - (newname (assoc newcode - unicode-tokens-codept-charname-alist)) - ;; NOTE: decode-char 'ucs here seems to fail on Emacs <23 - (newchar (decode-char 'ucs newcode))) - (when (and newname newchar) - (delete-char -1) - (insert-char newchar 1) - (message (cdr newname)) - (setq unicode-tokens-rotate-glyph-last-char nil)) - (unless (and newname newchar) - (message "No character at code %d" newcode) - (setq unicode-tokens-rotate-glyph-last-char newcode))))) - -(defun unicode-tokens-rotate-glyph-backward (&optional n) - "Rotate the character before point in the current code page, by -N steps. -If no character is found at the new codepoint, no change is made. -This function may only work reliably for GNU Emacs >= 23." - (interactive "p") - (unicode-tokens-rotate-glyph-forward (if n (- n) -1))) +(defvar unicode-tokens-use-shortcuts t + "Non-nil means use `unicode-tokens-shortcut-alist' if set.") - -;; -;; Setup quail for Unicode tokens mode -;; +(defun unicode-tokens-use-shortcuts (&optional arg) + "Toggle `unicode-tokens-use-shortcuts'. With ARG, turn on iff positive." + (interactive "P") + (setq unicode-tokens-use-shortcuts + (if (null arg) (not unicode-tokens-use-shortcuts) + (> (prefix-numeric-value arg) 0))) + (if unicode-tokens-use-shortcuts + (set-input-method "Unicode tokens") + (set-input-method nil))) (require 'quail) @@ -359,57 +352,12 @@ This function may only work reliably for GNU Emacs >= 23." "Ordering on (car S1, car S2): order longer strings first." (>= (length (car s1)) (length (car s2)))) -(defun unicode-tokens-propertise-after-quail (tostring) - (add-text-properties (- (point) (length tostring)) (point) - (list 'utoks tostring))) - - (defun unicode-tokens-quail-define-rules () "Define the token and shortcut input rules. Calculated from `unicode-tokens-token-name-alist' and -`unicode-tokens-shortcut-alist'. -Also sets `unicode-tokens-token-alist'." +`unicode-tokens-shortcut-alist'." (let ((unicode-tokens-quail-define-rules (list 'quail-define-rules))) -;; failed experiment (wrong place for rule/wrong type?): attempt to propertise -;; after translation -;; '((advice . unicode-tokens-propertise-after-quail -;; (face . proof-declaration-name-face))))) - (let ((ulist (copy-list unicode-tokens-token-name-alist)) - ustring tokname token) - ;; sort in case of non-terminated token syntax (empty suffix) - (setq ulist (sort ulist 'unicode-tokens-map-ordering)) - (setq unicode-tokens-token-alist nil) - (while ulist - (setq tokname (caar ulist)) - (setq ustring (cdar ulist)) - (setq token (format unicode-tokens-token-format tokname)) - (cond - ;; Some error checking (but not enough) - ((eq (length tokname) 0) - (warn "Empty token name (mapped to \"%s\") in unicode tokens list" - ustring)) - ((eq (length ustring) 0) - (warn "Empty token mapping, ignoring token \"%s\" in unicode tokens list" - token)) - ((assoc token unicode-tokens-token-alist) - (warn "Duplicated token entry, ignoring subsequent mapping of %s" token)) - ((rassoc ustring unicode-tokens-token-alist) - (warn "Duplicated target \"%s\", ignoring token %s" ustring token)) - (t - (nconc unicode-tokens-quail-define-rules - (list (list token - (vector ustring)))) - (setq unicode-tokens-token-alist - (nconc unicode-tokens-token-alist - (list (cons token ustring)))))) - (setq ulist (cdr ulist)))) - ;; make reverse map: convert longer ustring sequences first - (setq unicode-tokens-ustring-alist - (sort - (mapcar (lambda (c) (cons (cdr c) (car c))) - unicode-tokens-token-alist) - 'unicode-tokens-map-ordering)) (let ((ulist (copy-list unicode-tokens-shortcut-alist)) ustring shortcut) (setq ulist (sort ulist 'unicode-tokens-map-ordering)) @@ -423,379 +371,329 @@ Also sets `unicode-tokens-token-alist'." (eval unicode-tokens-quail-define-rules))) - ;; -;; File format for saving tokens in plain ASCII. +;; User-level functions ;; -(defvar unicode-tokens-format-entry - '(unicode-tokens "Tokens encoding unicode characters." - nil - unicode-tokens-tokens-to-unicode ; decode - unicode-tokens-unicode-to-tokens ; encode - t nil) - "Value for `format-alist'.") - -(add-to-list 'format-alist unicode-tokens-format-entry) - -(defconst unicode-tokens-ignored-properties - '(vanilla type fontified face auto-composed - rear-nonsticky field inhibit-line-move-field-capture - utoks) - "Text properties to ignore when saving files.") - -(put 'font-lock-face 'format-list-valued t) - -(defconst unicode-tokens-annotation-translations - `((font-lock-face - ;; FIXME: this is faulty; format.el makes wrong calculations with - ;; list valued properties, and sometimes loses these settings. - ((:weight bold) "bold") - ((:slant italic) "italic") - ; ,(face-all-attributes 'unicode-tokens-script-font-face) "script") - ; ,(face-all-attributes 'unicode-tokens-fraktur-font-face) "fraktur") - ; ,(face-all-attributes 'unicode-tokens-serif-font-face) "serif") - ((:family "PakTypeNaqsh") "script") - ((:family "URW Bookman L") "fraktur") - ((:family "Liberation Serif") "serif") - (proof-declaration-name-face "loc1") - (default )) - (display - ((raise 0.4) "superscript") - ((raise -0.4) "subscript") - ((raise 0.35) "superscript1") - ((raise -0.35) "subscript1") - ((raise 0.3) "idsuperscript1") - ((raise -0.3) "idsubscript1") - (default ))) - "Text property table for annotations.") - - -(defun unicode-tokens-remove-properties (start end) - "Remove text properties we manage between START and END." - (remove-text-properties - ;; NB: this is approximate and clashes with anyone else who - ;; looks after font-lock-face or display - start end (mapcar 'car unicode-tokens-annotation-translations))) - - -(defun unicode-tokens-tokens-to-unicode (&optional start end) - "Decode a tokenised file for display in Emacs." - (save-excursion - (save-restriction - (narrow-to-region start (or end (point-max))) - (let ((case-fold-search proof-case-fold-search) - (buffer-undo-list t) - (modified (buffer-modified-p)) - (inhibit-read-only t)) - (setq unicode-tokens-next-control-token-seen-token nil) - (format-replace-strings unicode-tokens-token-alist nil (point-min) - (point-max)) -;; alternative experiment: store original tokens inside text properties -;; (unicode-tokens-replace-strings-propertise unicode-tokens-token-alist) - (format-deannotate-region (point-min) - (point-max) - unicode-tokens-annotation-translations - 'unicode-tokens-next-control-token) - (set-buffer-modified-p modified)) - (goto-char (point-max))))) - -(defvar unicode-tokens-next-control-token-seen-token nil - "Records currently open single-character control token.") - -(defun unicode-tokens-next-control-token () - "Find next control token and interpret it. -If `unicode-tokens-next-control-token' is non-nil, end current control sequence -after next character (single character control sequence)." - (let (result) - (when unicode-tokens-next-control-token-seen-token - (if (re-search-forward unicode-tokens-next-character-regexp nil t) - (setq result (list (match-end 0) (match-end 0) - unicode-tokens-next-control-token-seen-token - nil))) - (setq unicode-tokens-next-control-token-seen-token nil)) - (while (and (not result) - (re-search-forward unicode-tokens-control-token-match nil t)) - (let* - ((tok (match-string 1)) - (annot - (cond - ((equal tok "bsup") '("superscript" t)) - ((equal tok "esup") '("superscript" nil)) - ((equal tok "bsub") '("subscript" t)) - ((equal tok "esub") '("subscript" nil)) - ((equal tok "bbold") '("bold" t)) - ((equal tok "ebold") '("bold" nil)) - ((equal tok "bitalic") '("italic" t)) - ((equal tok "eitalic") '("italic" nil)) - ((equal tok "bscript") '("script" t)) - ((equal tok "escript") '("script" nil)) - ((equal tok "bfrak") '("fraktur" t)) - ((equal tok "efrak") '("fraktur" nil)) - ((equal tok "bserif") '("serif" t)) - ((equal tok "eserif") '("serif" nil)) - ((equal tok "loc") - (list (setq unicode-tokens-next-control-token-seen-token - "loc1") t)) - ((equal tok "sup") - (list (setq unicode-tokens-next-control-token-seen-token - "superscript1") t)) - ((equal tok "sub") - (list (setq unicode-tokens-next-control-token-seen-token - "subscript1") t)) - ((equal tok "isup") - (list (setq unicode-tokens-next-control-token-seen-token - "idsuperscript1") t)) - ((equal tok "isub") - (list (setq unicode-tokens-next-control-token-seen-token - "idsubscript1") t))))) - (if annot - (setq result - (append - (list (match-beginning 0) (match-end 0)) - annot))))) - result)) - -;; TODO: this should be instance specific -(defconst unicode-tokens-annotation-control-token-alist - '(("bold" . ("bbold" . "ebold")) - ("subscript" . ("bsub" . "esub")) - ("superscript" . ("bsup" . "esup")) - ("subscript1" . ("sub")) - ("superscript1" . ("sup")) - ("idsubscript1" . ("isub")) - ("idsuperscript1" . ("isup")) - ("loc1" . ("loc")) - ;; non-standard - ("italic" . ("bitalic" . "eitalic")) - ("script" . ("bscript" . "escript")) - ("fraktur" . ("bfrak" . "efrak")) - ("serif" . ("bserif" . "eserif")))) - -(defun unicode-tokens-make-token-annotation (annot positive) - "Encode a text property start/end by adding an annotation in the file." - (let ((toks (cdr-safe - (assoc annot unicode-tokens-annotation-control-token-alist)))) - (cond - ((and toks positive) - (format unicode-tokens-control-token-format (car toks))) - ((and toks (cdr toks)) - (format unicode-tokens-control-token-format (cdr toks))) - (t "")))) - -(defun unicode-tokens-find-property (name) - (let ((props unicode-tokens-annotation-translations) - prop vals val vname) - (catch 'return - (while props - (setq prop (caar props)) - (setq vals (cdar props)) - (while vals - (setq val (car vals)) - (if (member name (cdr val)) - (throw 'return (list prop (car val)))) - (setq vals (cdr vals))) - (setq props (cdr props)))))) - -(defun unicode-tokens-annotate-region (beg end &optional annot) +(defun unicode-tokens-insert-token (tok) + "Insert symbolic token named TOK, giving a message." + (interactive (list + (completing-read + "Insert token: " + unicode-tokens-hash-table) t)) + (let ((ins (format unicode-tokens-token-format tok))) + (insert ins) + (message "Inserted %s" ins))) + +(defun unicode-tokens-annotate-region (name) + "Annotate region with region markup tokens for scheme NAME." + (interactive (let ((completion-ignore-case t)) + (list (completing-read + "Annotate region with: " + unicode-tokens-control-regions nil + 'requirematch)))) + (assert (assoc name unicode-tokens-control-regions)) + (let* ((entry (assoc name unicode-tokens-control-regions)) + (beg (region-beginning)) + (end (region-end)) + (begtok + (format unicode-tokens-control-region-format-end (nth 1 entry))) + (endtok + (format unicode-tokens-control-region-format-end (nth 2 entry)))) + (when (> beg end) + (setq beg end) + (setq end (region-beginning))) + (goto-char beg) + (insert begtok) + (goto-char (+ end (- (point) beg))) + (insert endtok))) + +(defun unicode-tokens-insert-control (name) + (interactive (list (completing-read + "Insert control symbol: " + unicode-tokens-control-characters))) + (insert (format unicode-tokens-control-char-format name))) + +(defun unicode-tokens-insert-uchar-as-token (char) + "Insert CHAR as a symbolic token, if possible." + (let ((tok (gethash char unicode-tokens-uchar-hash-table))) + (when tok + (unicode-tokens-insert-token tok)))) + +;;unused +(defun unicode-tokens-delete-token-at-point () + (interactive) + (when (looking-at unicode-tokens-token-match-regexp) + (kill-region (match-beginning 0) (match-end 0)))) + +(defvar unicode-tokens-rotate-token-last-token nil) + +(defun unicode-tokens-prev-token () + (let ((match (re-search-backward unicode-tokens-token-match-regexp + (save-excursion + (beginning-of-line 0) (point)) t))) + (if match + (match-string + (1- (regexp-opt-depth unicode-tokens-token-match-regexp)))))) + +(defun unicode-tokens-rotate-token-forward (&optional n) + "Rotate the token before point by N steps in the table." + (interactive "p") + (if (> (point) (point-min)) + (save-match-data + (let* ((token (or (if (or (eq last-command + 'unicode-tokens-rotate-token-forward) + (eq last-command + 'unicode-tokens-rotate-token-backward)) + unicode-tokens-rotate-token-last-token) + (unicode-tokens-prev-token))) + (tokennumber + (if token + (search (list token) unicode-tokens-token-list :test 'equal))) + (numtoks + (hash-table-count unicode-tokens-hash-table)) + (newtok + (if tokennumber + (nth (mod (+ tokennumber (or n 1)) numtoks) + unicode-tokens-token-list)))) + (when (and newtok + (looking-at unicode-tokens-token-match-regexp)) + (delete-region (match-beginning 0) (match-end 0)) + (insert (format unicode-tokens-token-format newtok))))))) + +(defun unicode-tokens-rotate-token-backward (&optional n) + "Rotate the token before point, by -N steps in the token list." + (interactive "p") + (unicode-tokens-rotate-token-forward (if n (- n) -1))) + +(defun unicode-tokens-copy-token (tokname) + (interactive "s") + (kill-new + (format unicode-tokens-token-format tokname) + (eq last-command 'unicode-tokens-copy-token))) + +(define-button-type 'unicode-tokens-list + 'help-echo "mouse-2, RET: copy this character" + 'face nil + 'action #'(lambda (button) + (unicode-tokens-copy-token (button-get button 'unicode-token)))) + +;; TODO: improve layout, can we use tabs +(defun unicode-tokens-list-tokens () + "Show a buffer of all tokens." + (interactive) + (with-output-to-temp-buffer "*Unicode Tokens List*" + (with-current-buffer standard-output + (unicode-tokens-mode) + (insert "Click or RET on a character to copy into kill ring.\n\n") + (let ((count 0) toks) + ;; display in originally given order + (dolist (tok unicode-tokens-token-list) + (insert-text-button + (format unicode-tokens-token-format tok) + :type 'unicode-tokens-list + 'unicode-token tok) + (incf count) + (if (< count 10) + (insert "\t") + (insert "\n") + (setq count 0))))))) + + +(defun unicode-tokens-copy (beg end) + "Copy presentation of region between BEG and END. +This is an approximation; it makes assumptions about the behaviour +of symbol compositions, and will lose layout information." (interactive "r") - (or annot - (if (interactive-p) - (setq annot - (completing-read "Annotate region as: " - unicode-tokens-annotation-control-token-alist - nil t)) - (error "In unicode-tokens-annotation-control-token-alist: TYPE must be given."))) - (add-text-properties beg end - (unicode-tokens-find-property annot))) - -(defun unicode-tokens-annotate-region-with (annot) - `(lambda (beg end) - (interactive "r") - (unicode-tokens-annotate-region beg end ,annot))) - -(defun unicode-tokens-annotate-string (annot string) - (add-text-properties 0 (length string) - (unicode-tokens-find-property annot) - string) - string) - -(defun unicode-tokens-unicode-to-tokens (&optional start end buffer) - "Encode a buffer to save as a tokenised file." - (let ((case-fold-search proof-case-fold-search) - (buffer-undo-list t) - (modified (buffer-modified-p))) - (save-restriction - (save-excursion - (narrow-to-region (or start (point-min)) (or end (point-max))) - (format-insert-annotations - (format-annotate-region (point-min) (point-max) - unicode-tokens-annotation-translations - 'unicode-tokens-make-token-annotation - unicode-tokens-ignored-properties)) -;; alternative experiment: store original tokens inside text properties -;; (unicode-tokens-replace-strings-unpropertise) - (format-replace-strings unicode-tokens-ustring-alist - nil (point-min) (point-max)) - (set-buffer-modified-p modified))))) - - -(defun unicode-tokens-replace-strings-propertise (alist &optional beg end) - "Do multiple replacements on the buffer. -ALIST is a list of (FROM . TO) pairs, which should be proper arguments to -`search-forward' and `replace-match', respectively. -The original contents FROM are retained in the buffer in the text property `utoks'. -Optional args BEG and END specify a region of the buffer on which to operate." - (save-excursion - (save-restriction - (or beg (setq beg (point-min))) - (if end (narrow-to-region (point-min) end)) - (while alist - (let ((from (car (car alist))) - (to (cdr (car alist))) - (case-fold-search nil)) - (goto-char beg) - (while (search-forward from nil t) - (goto-char (match-beginning 0)) - (insert to) - (set-text-properties (- (point) (length to)) (point) - (cons 'utoks - (cons from - (text-properties-at (point))))) - (delete-region (point) (+ (point) (- (match-end 0) - (match-beginning 0))))) - (setq alist (cdr alist))))))) - -;; NB: this is OK, except that now if we edit with raw symbols, we -;; don't get desired effect but instead rely on hidden annotations. -;; Also doesn't work as easily with quail. -;; Can we have a sensible mixture of both things? -(defun unicode-tokens-replace-strings-unpropertise (&optional beg end) - "Reverse the effect of `unicode-tokens-replace-strings-unpropertise'. -Replaces contiguous text with 'utoks' property with property value." - (let ((pos (or beg (point-min))) - (lim (or end (point-max))) - start to) - (save-excursion - (while (and - (setq pos (next-single-property-change pos 'utoks nil lim)) - (< pos lim)) - (if start - (progn - (setq to (get-text-property start 'utoks)) - (goto-char start) - (insert to) - (set-text-properties start (point) - (text-properties-at start)) - (delete-region (point) (+ (point) (- pos start))) - (setq start nil)) - (setq start pos)))))) - - - - + ;; cf kill-ring-save, uncode-tokens-font-lock-compose-symbol + (let ((visible + ;; actually: leave in control tokens as they can have logical meaning + ;; (proof-visible-buffer-substring beg end) + (buffer-substring-no-properties beg end)) + (match (- (regexp-opt-depth unicode-tokens-token-match-regexp) 2))) + (with-temp-buffer + (insert visible) + (goto-char (point-min)) + (while (re-search-forward unicode-tokens-token-match-regexp nil t) + ;; TODO: interpret more exotic compositions here + (let* ((tstart (match-beginning 0)) + (tend (match-end 0)) + (comp (car-safe + (gethash (match-string match) + unicode-tokens-hash-table)))) + (when comp + (delete-region tstart tend) + ;; TODO: improve this: interpret vector, strip tabs + (insert comp)))) ;; gross approximation to compose-region + (copy-region-as-kill (point-min) (point-max))))) + +(defun unicode-tokens-paste () + (interactive) + (let ((start (point)) end) + (clipboard-yank) + (setq end (point-marker)) + (while (re-search-backward unicode-tokens-uchar-regexp start t) + (let* ((useq (match-string 0)) + (token (gethash useq unicode-tokens-uchar-hash-table)) + (pos (point))) + (when token + (replace-match (format unicode-tokens-token-format token) t t) + (goto-char pos)))) + (goto-char end) + (set-marker end nil))) ;; ;; Minor mode ;; +;;;###autoload +(defun unicode-tokens-initialise () + (interactive) + (let ((flks (unicode-tokens-font-lock-keywords))) + (put 'unicode-tokens-font-lock-keywords major-mode flks) + (unicode-tokens-quail-define-rules) + flks)) + (defvar unicode-tokens-mode-map (make-sparse-keymap) "Key map used for Unicode Tokens mode.") +;;;###autoload (define-minor-mode unicode-tokens-mode "Minor mode for unicode token input." nil " Utoks" unicode-tokens-mode-map - (unless unicode-tokens-token-alist - (unicode-tokens-initialise)) - (when unicode-tokens-mode - (when (boundp 'text-property-default-nonsticky) - (make-variable-buffer-local 'text-property-default-nonsticky) - (setq text-property-default-nonsticky - ;; We want to use display property with stickyness - (delete '(display . t) text-property-default-nonsticky))) - (if (and - (fboundp 'set-buffer-multibyte) - (not (buffer-base-buffer))) - (set-buffer-multibyte t)) - (let ((inhibit-read-only t)) - ;; format is supposed to manage undo, but doesn't remap - (setq buffer-undo-list nil) - (format-decode-buffer 'unicode-tokens)) - (set-input-method "Unicode tokens")) - (unless unicode-tokens-mode - (when (boundp 'text-property-default-nonsticky) - (add-to-list 'text-property-default-nonsticky '(display . t))) - ;; leave buffer encoding as is - (let ((inhibit-read-only t) - (modified (buffer-modified-p))) - ;; format is supposed to manage undo, but doesn't remap - (setq buffer-undo-list nil) - (format-encode-buffer 'unicode-tokens) - (unicode-tokens-remove-properties (point-min) (point-max)) - (set-buffer-modified-p modified)) - (inactivate-input-method))) + (let ((flks (get 'unicode-tokens-font-lock-keywords major-mode))) + (when unicode-tokens-mode + (unless flks + (setq flks (unicode-tokens-initialise))) + (make-local-variable 'font-lock-extra-managed-props) + ;; make sure buffer can display 16 bit chars + (if (and + (fboundp 'set-buffer-multibyte) + (not (buffer-base-buffer))) + (set-buffer-multibyte t)) + + (add-to-invisibility-spec 'unicode-tokens-show-controls) + + ;; our conventions: + ;; 1. set default for font-lock-extra-managed-props + ;; as property on major mode symbol (ordinarily nil). + (font-lock-add-keywords nil flks) + + (setq font-lock-extra-managed-props + (get 'font-lock-extra-managed-props major-mode)) + (mapcar + (lambda (p) (add-to-list 'font-lock-extra-managed-props p)) + unicode-tokens-font-lock-extra-managed-props) + + (font-lock-fontify-buffer) + + (if unicode-tokens-use-shortcuts + (set-input-method "Unicode tokens")) + + ;; adjust maths menu to insert tokens + (set (make-local-variable 'maths-menu-filter-predicate) + (lambda (uchar) (gethash uchar unicode-tokens-uchar-hash-table))) + (set (make-local-variable 'maths-menu-tokenise-insert) + (lambda (uchar) + (unicode-tokens-insert-token + (gethash uchar unicode-tokens-uchar-hash-table))))) + + (when (not unicode-tokens-mode) + (when flks + (font-lock-unfontify-buffer) + (setq font-lock-extra-managed-props + (get 'font-lock-extra-managed-props major-mode)) + (setq font-lock-set-defaults nil) ; force font-lock-set-defaults to reinit + (font-lock-fontify-buffer) + (set-input-method nil)) + + ;; Remove hooks from maths menu + (kill-local-variable 'maths-menu-filter-predicate) + (kill-local-variable 'maths-menu-tokenise-insert)))) ;; -;; Initialisation +;; Key bindings ;; -(defun unicode-tokens-initialise () - "Initialise tables." - ;; Calculate max token length - (let ((tlist unicode-tokens-token-name-alist) - (len 0) tok) - (while tlist - (when (> (length (caar tlist)) 0) - (setq len (length (caar tlist))) - (setq tok (caar tlist))) - (setq tlist (cdr tlist))) - (setq unicode-tokens-max-token-length - (length (format unicode-tokens-token-format tok)))) - ;; Names from code points - (setq unicode-tokens-codept-charname-alist - (mapcar (lambda (namechar) - (cons (cdr namechar) (car namechar))) - unicode-chars-alist)) - ;; Default assumed available glyph list based on tokens; - ;; TODO: filter with what's really available, if can find out. - ;; TODO: allow altering of this when the token-name-alist is reset - ;; in proof-token-name-alist (unless test here is for specific setting) - (unless unicode-tokens-glyph-list - (setq unicode-tokens-glyph-list - (reduce (lambda (glyphs tokustring) - (append glyphs (string-to-list (cdr tokustring)))) - unicode-tokens-token-name-alist - :initial-value nil))) - (unicode-tokens-quail-define-rules) - ;; Key bindings - (if (= (length unicode-tokens-token-suffix) 1) - (define-key unicode-tokens-mode-map - (vector (string-to-char unicode-tokens-token-suffix)) - 'unicode-tokens-electric-suffix)) - (define-key unicode-tokens-mode-map [(control ?,)] - 'unicode-tokens-rotate-glyph-backward) - (define-key unicode-tokens-mode-map [(control ?.)] - 'unicode-tokens-rotate-glyph-forward) - ) +(define-key unicode-tokens-mode-map [(control ?,)] + 'unicode-tokens-rotate-token-backward) +(define-key unicode-tokens-mode-map [(control ?.)] + 'unicode-tokens-rotate-token-forward) +(define-key unicode-tokens-mode-map + [(control c) (control t) (control t)] 'unicode-tokens-insert-token) +(define-key unicode-tokens-mode-map + [(control c) (control t) (control r)] 'unicode-tokens-annotate-region) +(define-key unicode-tokens-mode-map + [(control c) (control t) (control e)] 'unicode-tokens-insert-control) +(define-key unicode-tokens-mode-map + [(control c) (control t) (control z)] 'unicode-tokens-show-symbols) +(define-key unicode-tokens-mode-map + [(control c) (control t) (control x)] 'unicode-tokens-show-controls) + ;; ;; Menu ;; (easy-menu-define unicode-tokens-menu unicode-tokens-mode-map - "Format menu" - (cons "Format" - (mapcar - (lambda (fmt) - (vector fmt - (unicode-tokens-annotate-region-with (downcase fmt)) - :active 'region-exists-p)) - '("Subscript" "Superscript" - "Supscript1" "Superscript1" - "Idsubscript1" "Idsuperscript1" - ;; don't encourage these as saving seems unreliable - ;; "Bold" "Italic" "Script" "Fraktur" "Serif" - )))) - + "Tokens menu" + (cons "Tokens" + (list + ["Insert token..." unicode-tokens-insert-token] + ["Next token" unicode-tokens-rotate-token-forward] + ["Prev token" unicode-tokens-rotate-token-backward] + ["List tokens" unicode-tokens-list-tokens] + (cons "Format char" + (mapcar + (lambda (fmt) + (vector (car fmt) + `(lambda () (interactive) + (apply 'unicode-tokens-insert-control ',(car fmt))) + :help (concat "Format next item as " + (downcase (car fmt))))) + unicode-tokens-control-characters)) + (cons "Format region" + (mapcar + (lambda (fmt) + (vector (car fmt) + `(lambda () (interactive) + (funcall 'unicode-tokens-annotate-region ',(car fmt))) + :help (concat "Format region as " + (downcase (car fmt))) + :active 'mark-active)) + unicode-tokens-control-regions)) + "---" + ["Copy as unicode" unicode-tokens-copy + :active 'mark-active + :help "Copy text from buffer, converting tokens to Unicode"] + ["Paste from unicode" unicode-tokens-paste + :active (and kill-ring (not buffer-read-only)) + :help "Paste from clipboard, converting Unicode to tokens"] + "---" + ["Show control tokens" unicode-tokens-show-controls + :style toggle + :selected unicode-tokens-show-controls + :active (or + unicode-tokens-control-region-format-regexp + unicode-tokens-control-char-format-regexp) + :help "Prevent hiding of control tokens"] + ["Show symbol tokens" unicode-tokens-show-symbols + :style toggle + :selected unicode-tokens-show-symbols + :help "Show tokens for symbols"] + ["Enable shortcuts" unicode-tokens-use-shortcuts + :style toggle + :selected unicode-tokens-use-shortcuts + :active unicode-tokens-shortcut-alist + :help "Use short cuts for typing tokens"] + ["Make fontsets" + (lambda () (interactive) (require 'pg-fontsets)) + :active (not (featurep 'pg-fontsets)) + :help "Define fontsets (for Options->Set fontsets)" + :visible (< emacs-major-version 23) ; not useful on 23 + ]))) + + + (provide 'unicode-tokens) ;;; unicode-tokens.el ends here diff --git a/lib/xml-fixed.el b/lib/xml-fixed.el deleted file mode 100644 index c79bdd64..00000000 --- a/lib/xml-fixed.el +++ /dev/null @@ -1,508 +0,0 @@ -;;; xml.el --- XML parser - -;;; !!! This version has been modified from the version distributed with -;;; XEmacs to fix a bug parsing empty elements, for Proof General. - -;; Copyright (C) 2000, 2001 Free Software Foundation, Inc. - -;; Author: Emmanuel Briot <briot@gnat.com> -;; Maintainer: Emmanuel Briot <briot@gnat.com> -;; Keywords: xml - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - -;;; Commentary: - -;; This file contains a full XML parser. It parses a file, and returns a list -;; that can be used internally by any other lisp file. -;; See some example in todo.el - -;;; FILE FORMAT - -;; It does not parse the DTD, if present in the XML file, but knows how to -;; ignore it. The XML file is assumed to be well-formed. In case of error, the -;; parsing stops and the XML file is shown where the parsing stopped. -;; -;; It also knows how to ignore comments, as well as the special ?xml? tag -;; in the XML file. -;; -;; The XML file should have the following format: -;; <node1 attr1="name1" attr2="name2" ...>value -;; <node2 attr3="name3" attr4="name4">value2</node2> -;; <node3 attr5="name5" attr6="name6">value3</node3> -;; </node1> -;; Of course, the name of the nodes and attributes can be anything. There can -;; be any number of attributes (or none), as well as any number of children -;; below the nodes. -;; -;; There can be only top level node, but with any number of children below. - -;;; LIST FORMAT - -;; The functions `xml-parse-file' and `xml-parse-tag' return a list with -;; the following format: -;; -;; xml-list ::= (node node ...) -;; node ::= (tag_name attribute-list . child_node_list) -;; child_node_list ::= child_node child_node ... -;; child_node ::= node | string -;; tag_name ::= string -;; attribute_list ::= (("attribute" . "value") ("attribute" . "value") ...) -;; | nil -;; string ::= "..." -;; -;; Some macros are provided to ease the parsing of this list - -;;; Code: - -(eval-and-compile - (defalias 'match-string-no-properties 'match-string)) - -;;******************************************************************* -;;** -;;** Macros to parse the list -;;** -;;******************************************************************* - -(defsubst xml-node-name (node) - "Return the tag associated with NODE. -The tag is a lower-case symbol." - (car node)) - -(defsubst xml-node-attributes (node) - "Return the list of attributes of NODE. -The list can be nil." - (nth 1 node)) - -(defsubst xml-node-children (node) - "Return the list of children of NODE. -This is a list of nodes, and it can be nil." - (cddr node)) - -(defun xml-get-children (node child-name) - "Return the children of NODE whose tag is CHILD-NAME. -CHILD-NAME should be a lower case symbol." - (let ((match ())) - (dolist (child (xml-node-children node)) - (if child - (if (equal (xml-node-name child) child-name) - (push child match)))) - (nreverse match))) - -(defun xml-get-attribute (node attribute) - "Get from NODE the value of ATTRIBUTE. -An empty string is returned if the attribute was not found." - (if (xml-node-attributes node) - (let ((value (assoc attribute (xml-node-attributes node)))) - (if value - (cdr value) - "")) - "")) - -;;******************************************************************* -;;** -;;** Creating the list -;;** -;;******************************************************************* - -(defun xml-parse-file (file &optional parse-dtd) - "Parse the well-formed XML FILE. -If FILE is already edited, this will keep the buffer alive. -Returns the top node with all its children. -If PARSE-DTD is non-nil, the DTD is parsed rather than skipped." - (let ((keep)) - (if (get-file-buffer file) - (progn - (set-buffer (get-file-buffer file)) - (setq keep (point))) - (find-file file)) - - (let ((xml (xml-parse-region (point-min) - (point-max) - (current-buffer) - parse-dtd))) - (if keep - (goto-char keep) - (kill-buffer (current-buffer))) - xml))) - -(defun xml-parse-region (beg end &optional buffer parse-dtd) - "Parse the region from BEG to END in BUFFER. -If BUFFER is nil, it defaults to the current buffer. -Returns the XML list for the region, or raises an error if the region -is not a well-formed XML file. -If PARSE-DTD is non-nil, the DTD is parsed rather than skipped, -and returned as the first element of the list" - (let (xml result dtd) - (save-excursion - (if buffer - (set-buffer buffer)) - (goto-char beg) - (while (< (point) end) - (if (search-forward "<" end t) - (progn - (forward-char -1) - (if (null xml) - (progn - (setq result (xml-parse-tag end parse-dtd)) - (cond - ((null result)) - ((listp (car result)) - (setq dtd (car result)) - (add-to-list 'xml (cdr result))) - (t - (add-to-list 'xml result)))) - - ;; translation of rule [1] of XML specifications - (error "XML files can have only one toplevel tag"))) - (goto-char end))) - (if parse-dtd - (cons dtd (nreverse xml)) - (nreverse xml))))) - - -(defun xml-parse-tag (end &optional parse-dtd) - "Parse the tag that is just in front of point. -The end tag must be found before the position END in the current buffer. -If PARSE-DTD is non-nil, the DTD of the document, if any, is parsed and -returned as the first element in the list. -Returns one of: - - a list : the matching node - - nil : the point is not looking at a tag. - - a cons cell: the first element is the DTD, the second is the node" - (cond - ;; Processing instructions (like the <?xml version="1.0"?> tag at the - ;; beginning of a document) - ((looking-at "<\\?") - (search-forward "?>" end) - (skip-chars-forward " \t\n") - (xml-parse-tag end)) - ;; Character data (CDATA) sections, in which no tag should be interpreted - ((looking-at "<!\\[CDATA\\[") - (let ((pos (match-end 0))) - (unless (search-forward "]]>" end t) - (error "CDATA section does not end anywhere in the document")) - (buffer-substring-no-properties pos (match-beginning 0)))) - ;; DTD for the document - ((looking-at "<!DOCTYPE") - (let (dtd) - (if parse-dtd - (setq dtd (xml-parse-dtd end)) - (xml-skip-dtd end)) - (skip-chars-forward " \t\n") - (if dtd - (cons dtd (xml-parse-tag end)) - (xml-parse-tag end)))) - ;; skip comments - ((looking-at "<!--") - (search-forward "-->" end) - nil) - ;; end tag - ((looking-at "</") - '()) - ;; opening tag - ((looking-at "<\\([^/> \t\n]+\\)") - (goto-char (match-end 1)) - (let* ((case-fold-search nil) ;; XML is case-sensitive. - (node-name (match-string 1)) - ;; Parse the attribute list. - (children (list (xml-parse-attlist end) (intern node-name))) - pos) - - ;; is this an empty element ? - (if (looking-at "/>") - (progn - (forward-char 2) - (nreverse children)) - - ;; is this a valid start tag ? - (if (eq (char-after) ?>) - (progn - (forward-char 1) - ;; Now check that we have the right end-tag. Note that this - ;; one might contain spaces after the tag name - (while (not (looking-at (concat "</" node-name "[ \t\n]*>"))) - (cond - ((looking-at "</") - (error (concat - "XML: invalid syntax -- invalid end tag (expecting " - node-name - ") at pos " (number-to-string (point))))) - ((= (char-after) ?<) - (let ((tag (xml-parse-tag end))) - (when tag - (push tag children)))) - (t - (setq pos (point)) - (search-forward "<" end) - (forward-char -1) - (let ((string (buffer-substring-no-properties pos (point))) - (pos 0)) - - ;; Clean up the string (no newline characters) - ;; Not done, since as per XML specifications, the XML processor - ;; should always pass the whole string to the application. - ;; (while (string-match "\\s +" string pos) - ;; (setq string (replace-match " " t t string)) - ;; (setq pos (1+ (match-beginning 0)))) - - (setq string (xml-substitute-special string)) - (setq children - (if (stringp (car children)) - ;; The two strings were separated by a comment. - (cons (concat (car children) string) - (cdr children)) - (cons string children))))))) - (goto-char (match-end 0)) - (if (> (point) end) - (error "XML: End tag for %s not found before end of region" - node-name)) - (nreverse children)) - - ;; This was an invalid start tag - (error "XML: Invalid attribute list") - )))) - (t ;; This is not a tag. - (error "XML: Invalid character")) - )) - -(defun xml-parse-attlist (end) - "Return the attribute-list that point is looking at. -The search for attributes end at the position END in the current buffer. -Leaves the point on the first non-blank character after the tag." - (let ((attlist ()) - name) - (skip-chars-forward " \t\n") - (while (looking-at "\\([a-zA-Z_:][-a-zA-Z0-9._:]*\\)[ \t\n]*=[ \t\n]*") - (setq name (intern (match-string 1))) - (goto-char (match-end 0)) - - ;; Do we have a string between quotes (or double-quotes), - ;; or a simple word ? - (unless (looking-at "\"\\([^\"]*\\)\"") - (unless (looking-at "'\\([^']*\\)'") - (error "XML: Attribute values must be given between quotes"))) - - ;; Each attribute must be unique within a given element - (if (assoc name attlist) - (error "XML: each attribute must be unique within an element")) - - (push (cons name (match-string-no-properties 1)) attlist) - (goto-char (match-end 0)) - (skip-chars-forward " \t\n") - (if (> (point) end) - (error "XML: end of attribute list not found before end of region")) - ) - (nreverse attlist))) - -;;******************************************************************* -;;** -;;** The DTD (document type declaration) -;;** The following functions know how to skip or parse the DTD of -;;** a document -;;** -;;******************************************************************* - -(defun xml-skip-dtd (end) - "Skip the DTD that point is looking at. -The DTD must end before the position END in the current buffer. -The point must be just before the starting tag of the DTD. -This follows the rule [28] in the XML specifications." - (forward-char (length "<!DOCTYPE")) - (if (looking-at "[ \t\n]*>") - (error "XML: invalid DTD (excepting name of the document)")) - (condition-case nil - (progn - (forward-word 1) ;; name of the document - (skip-chars-forward " \t\n") - (if (looking-at "\\[") - (re-search-forward "\\][ \t\n]*>" end) - (search-forward ">" end))) - (error (error "XML: No end to the DTD")))) - -(defun xml-parse-dtd (end) - "Parse the DTD that point is looking at. -The DTD must end before the position END in the current buffer." - (forward-char (length "<!DOCTYPE")) - (skip-chars-forward " \t\n") - (if (looking-at ">") - (error "XML: invalid DTD (excepting name of the document)")) - - ;; Get the name of the document - (looking-at "\\sw+") - (let ((dtd (list (match-string-no-properties 0) 'dtd)) - type element end-pos) - (goto-char (match-end 0)) - - (skip-chars-forward " \t\n") - - ;; External DTDs => don't know how to handle them yet - (if (looking-at "SYSTEM") - (error "XML: Don't know how to handle external DTDs")) - - (if (not (= (char-after) ?\[)) - (error "XML: Unknown declaration in the DTD")) - - ;; Parse the rest of the DTD - (forward-char 1) - (while (and (not (looking-at "[ \t\n]*\\]")) - (<= (point) end)) - (cond - - ;; Translation of rule [45] of XML specifications - ((looking-at - "[\t \n]*<!ELEMENT[ \t\n]+\\([a-zA-Z0-9.%;]+\\)[ \t\n]+\\([^>]+\\)>") - - (setq element (intern (match-string-no-properties 1)) - type (match-string-no-properties 2)) - (setq end-pos (match-end 0)) - - ;; Translation of rule [46] of XML specifications - (cond - ((string-match "^EMPTY[ \t\n]*$" type) ;; empty declaration - (setq type 'empty)) - ((string-match "^ANY[ \t\n]*$" type) ;; any type of contents - (setq type 'any)) - ((string-match "^(\\(.*\\))[ \t\n]*$" type) ;; children ([47]) - (setq type (xml-parse-elem-type (match-string-no-properties 1 type)))) - ((string-match "^%[^;]+;[ \t\n]*$" type) ;; substitution - nil) - (t - (error "XML: Invalid element type in the DTD"))) - - ;; rule [45]: the element declaration must be unique - (if (assoc element dtd) - (error "XML: elements declaration must be unique in a DTD (<%s>)" - (symbol-name element))) - - ;; Store the element in the DTD - (push (list element type) dtd) - (goto-char end-pos)) - - - (t - (error "XML: Invalid DTD item")) - ) - ) - - ;; Skip the end of the DTD - (search-forward ">" end) - (nreverse dtd))) - - -(defun xml-parse-elem-type (string) - "Convert a STRING for an element type into an elisp structure." - - (let (elem modifier) - (if (string-match "(\\([^)]+\\))\\([+*?]?\\)" string) - (progn - (setq elem (match-string 1 string) - modifier (match-string 2 string)) - (if (string-match "|" elem) - (setq elem (cons 'choice - (mapcar 'xml-parse-elem-type - (split-string elem "|")))) - (if (string-match "," elem) - (setq elem (cons 'seq - (mapcar 'xml-parse-elem-type - (split-string elem ",")))) - ))) - (if (string-match "[ \t\n]*\\([^+*?]+\\)\\([+*?]?\\)" string) - (setq elem (match-string 1 string) - modifier (match-string 2 string)))) - - (if (and (stringp elem) (string= elem "#PCDATA")) - (setq elem 'pcdata)) - - (cond - ((string= modifier "+") - (list '+ elem)) - ((string= modifier "*") - (list '* elem)) - ((string= modifier "?") - (list '? elem)) - (t - elem)))) - - -;;******************************************************************* -;;** -;;** Substituting special XML sequences -;;** -;;******************************************************************* - -(defun xml-substitute-special (string) - "Return STRING, after subsituting special XML sequences." - (while (string-match "&" string) - (setq string (replace-match "&" t nil string))) - (while (string-match "<" string) - (setq string (replace-match "<" t nil string))) - (while (string-match ">" string) - (setq string (replace-match ">" t nil string))) - (while (string-match "'" string) - (setq string (replace-match "'" t nil string))) - (while (string-match """ string) - (setq string (replace-match "\"" t nil string))) - string) - -;;******************************************************************* -;;** -;;** Printing a tree. -;;** This function is intended mainly for debugging purposes. -;;** -;;******************************************************************* - -(defun xml-debug-print (xml) - (dolist (node xml) - (xml-debug-print-internal node ""))) - -(defun xml-debug-print-internal (xml indent-string) - "Outputs the XML tree in the current buffer. -The first line indented with INDENT-STRING." - (let ((tree xml) - attlist) - (insert indent-string "<" (symbol-name (xml-node-name tree))) - - ;; output the attribute list - (setq attlist (xml-node-attributes tree)) - (while attlist - (insert " ") - (insert (symbol-name (caar attlist)) "=\"" (cdar attlist) "\"") - (setq attlist (cdr attlist))) - - (insert ">") - - (setq tree (xml-node-children tree)) - - ;; output the children - (dolist (node tree) - (cond - ((listp node) - (insert "\n") - (xml-debug-print-internal node (concat indent-string " "))) - ((stringp node) (insert node)) - (t - (error "Invalid XML tree")))) - - (insert "\n" indent-string - "</" (symbol-name (xml-node-name xml)) ">"))) - -(provide 'xml) -(provide 'xml-fixed) - -;;; xml.el ends here |