;;; hoa-mode.el --- Major mode for the Hanoi Omega Automata format ;; Copyright (C) 2015 Alexandre Duret-Lutz ;; Author: Alexandre Duret-Lutz ;; Maintainer: Alexandre Duret-Lutz ;; URL: https://gitlab.lrde.epita.fr/spot/emacs-modes ;; Keywords: major-mode, automata, convenience ;; Created: 2015-11-13 ;;; License: ;; This package 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 3, or (at your option) ;; any later version. ;; ;; This package 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. If not, see . ;;; Commentary: ;; Major mode for editing files in the Hanoi Omega Automata format. ;; (See URL `http://adl.github.io/hoaf/' for that format.) This ;; provides rules for syntax highlighting, some navigation functions, ;; and a convenient way to display the automata in Emacs. ;;; Code: ;;;###autoload (add-to-list 'auto-mode-alist '("\\.hoa\\'" . hoa-mode)) ;;;###autoload (add-to-list 'magic-mode-alist '("\\" "Regex for matching aliases.") (defvar hoa-font-lock-keywords (list '("\\_<[A-Z][a-zA-Z0-9_-]*:" . 'hoa-header-uppercase-face) '("\\_<[a-z][a-zA-Z0-9_-]*:" . 'hoa-header-lowercase-face) `(,hoa-alias-regex . 'hoa-alias-face) '("\\_<--\\(BODY\\|END\\|ABORT\\)--" . 'hoa-keyword-face) '("\\_<\\(Inf\\|Fin\\|t\\|f\\)\\_>" . 'hoa-builtin-face) '("(\\s-*\\([0-9]+\\)\\s-*)" 1 'hoa-acceptance-set-face) '("{\\(\\([0-9]\\|\\s-\\)+\\)}" 1 'hoa-acceptance-set-face) ;; numbers between brackets denote atomic propositions. '("\\[" ("\\_<[0-9]+\\_>" (save-excursion (search-forward "]" nil t)) nil (0 'hoa-ap-number-face))) ;; likewise for numbers following an Alias: definition `(,(concat "Alias:\\s-*" hoa-alias-regex) ("\\_<[0-9]+\\_>" (save-excursion (re-search-forward (concat "\\(" hoa-alias-regex "\\|[0-9|&!]\\|\\s-\\)+") nil t)) nil (0 'hoa-ap-number-face)))) "Hilighting rules for `hoa-mode'.") (defvar hoa-mode-syntax-table (let ((st (make-syntax-table))) (modify-syntax-entry ?< "." st) (modify-syntax-entry ?> "." st) (modify-syntax-entry ?| "." st) (modify-syntax-entry ?_ "_" st) (modify-syntax-entry ?- "_" st) (modify-syntax-entry ?$ "." st) (modify-syntax-entry ?& "." st) (modify-syntax-entry ?+ "." st) (modify-syntax-entry ?/ ". 14bn" st) (modify-syntax-entry ?* ". 23bn" st) st) "Syntax table for `hoa-mode'.") (defun hoa-start-of-automaton () "Move to the start of the automaton at point." (interactive) (search-backward "HOA:")) (defun hoa-end-of-automaton () "Move to the end of the automaton at point." (interactive) ; if we are pointing inside something that looks like --END-- or ; --ABORT--, back out a bit. (if (looking-at "[ENDABORT-]*-") (backward-word)) (re-search-forward "--\\(END\\|ABORT\\)--\n?")) (defun hoa-mark-automaton-at-point () "Mark the automaton at point." (interactive) (hoa-end-of-automaton) (set-mark (point)) (hoa-start-of-automaton)) (defcustom hoa-display-error-buffer "*hoa-dot-error*" "The name of the buffer to display errors from `hoa-display-command'." :group 'hoa-mode :type 'string) (defcustom hoa-display-buffer "*hoa-display*" "The name of the buffer to display automata." :group 'hoa-mode :type 'string) (defcustom hoa-display-command "autfilt --dot='barf(Lato)' | dot -Tpng" "Command used to display HOA files. The command is expected to take the automaton in HOA format on its standard input, and output an image in PNG format on its standard output. The default value uses the tools autfilt (part of the Spot package, see URL `https://spot.lrde.epita.fr/') and dot (part of the GraphViz package, see URL `http://www.graphviz.org/')." :group 'hoa-mode :type 'string) (defun hoa-display-automaton-at-point () "Display the automaton-at-point. This uses the command in `hoa-display-command' to convert HOA into PNG, and then display the result in `hoa-display-buffer'. If the command terminates with an error, its standard error is put in `hoa-display-error-buffer' and shown." (interactive) (let ((b (save-excursion (if (not (looking-at "HOA:")) (hoa-start-of-automaton) (point)))) (e (save-excursion (hoa-end-of-automaton) (point))) (dotbuf (generate-new-buffer "*hoa-dot-output*")) (errfile (make-temp-file (expand-file-name "hoadot" temporary-file-directory))) (coding-system-for-read 'no-conversion)) (with-current-buffer dotbuf (set-buffer-multibyte nil)) (let ((exit-status (call-process-region b e shell-file-name nil (list dotbuf errfile) nil shell-command-switch hoa-display-command))) (when (equal 0 exit-status) (let ((hoa-img (create-image (with-current-buffer dotbuf (buffer-string)) 'png t))) (with-current-buffer (get-buffer-create hoa-display-buffer) (erase-buffer) (insert-image hoa-img) (display-buffer (current-buffer))))) (when (file-exists-p errfile) (when (< 0 (nth 7 (file-attributes errfile))) (with-current-buffer (get-buffer-create hoa-display-error-buffer) (setq buffer-read-only nil) (erase-buffer) (format-insert-file errfile nil) (display-buffer (current-buffer)))) (delete-file errfile)) (kill-buffer dotbuf)))) (defvar hoa-mode-map (let ((map (make-keymap))) (define-key map "\M-e" 'hoa-end-of-automaton) (define-key map "\M-a" 'hoa-start-of-automaton) (define-key map "\C-\M-h" 'hoa-mark-automaton-at-point) (define-key map "\C-c\C-c" 'hoa-display-automaton-at-point) map) "Keymap for `hoa-mode'.") (defcustom hoa-mode-hook nil "Hook run whenever `hoa-mode' is activated." :group 'hoa-mode :type 'hook) ;;;### autoload (defun hoa-mode () "Major mode for editing files in the Hanoi Omega Automata format. See URL `http://adl.github.io/hoaf/' for a definition of that format. The following key bindings are installed in hoa-mode: \\{hoa-mode-map} By default the `hoa-display-automaton-at-point' function requires extra software (Spot and GraphViz), but can be configured to use other tools. See that function for details." (interactive) (kill-all-local-variables) (set-syntax-table hoa-mode-syntax-table) (set (make-local-variable 'font-lock-defaults) '(hoa-font-lock-keywords)) (use-local-map hoa-mode-map) (setq major-mode 'hoa-mode) (setq mode-name "HOA") (run-hooks 'hoa-mode-hook)) (provide 'hoa-mode) ;;; hoa-mode.el ends here