tlamode/tla+-mode.el

318 lines
9.7 KiB
EmacsLisp
Raw Normal View History

;; Copyright (C) 2019 Christian Barthel <bch@online.de>
;; Author: Christian Barthel
;; Keywords: TLA+
;; This file 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.
;; This file 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 package defines TLA+ Major Mode to manipulate TLA+
;; specifications.
;;; Code:
(defcustom tla+-mode-hook '()
"Normal hook run when entering TLA+ mode."
:type 'hook
:options '()
:group 'tla+)
(defcustom tla+-java-path "java"
"Path to the `java' program"
:type 'file
:group 'tla+)
(defcustom tla+-tlatools-path
"/usr/home/bch/tmp/tlaplus/tlatools/dist/tla2tools.jar"
"Path to the TLA+ `tlatools.jar' file"
:type 'file
:group 'tla+)
(defcustom tla+-dvipdf-path
"dvipdf"
"Path to the `dvipdf' program"
:type 'file
:group 'tla+)
(defcustom tla+-dvips-path
"dvips"
"Path to the `dvips' program"
:type 'file
:group 'tla+)
(defvar tla+-mode-map
(let
((map (make-sparse-keymap))
(menu-map (make-sparse-keymap "TLA+"))
(operator-map (make-sparse-keymap))
(action-operator-map (make-sparse-keymap))
(temporal-operator-map (make-sparse-keymap))
(export-map (make-sparse-keymap)))
(set-keymap-parent map lisp-mode-shared-map)
(define-key map "\e\t" 'ispell-complete-word)
;; Main TLA+ Menu:
(bindings--define-key map [menu-bar tla+]
(cons "TLA+" menu-map))
;; Operators
(bindings--define-key menu-map [operator]
(cons "Insert Operator.." operator-map))
;; Action Operators
(bindings--define-key operator-map [action-operator]
(cons "Action Operator" action-operator-map))
(bindings--define-key
action-operator-map [primed-operator]
'(menu-item "e'" tla+-operator-primed
:help "Value of e in final state of a step"))
(bindings--define-key
action-operator-map [stutter-operator]
'(menu-item "[A]_e" tla+-operator-stutter
:help "A \\/ (e' = e)"))
(bindings--define-key
action-operator-map [nonstutter-operator]
'(menu-item "<<A>>_e" tla+-operator-nonstutter
:help "A /\ (e' \\= e)"))
(bindings--define-key
action-operator-map [enabled-operator]
'(menu-item "ENABLED A" tla+-operator-enabled
:help "An A step is possible"))
(bindings--define-key
action-operator-map [unchanged-operator]
'(menu-item "UNCHANGED e" tla+-operator-unchanged
:help "e = e'"))
(bindings--define-key
action-operator-map [composition-operator]
'(menu-item "A \\cdot B" tla+-operator-composition
:help "Composition of actions"))
;; Temporal operators:
(bindings--define-key operator-map [temporal-operator]
(cons "Temporal Operator" temporal-operator-map))
(bindings--define-key
temporal-operator-map [always-temporal-operator]
'(menu-item "[]F" tla+-operator-alwaystrue
:help "F is always true"))
(bindings--define-key
temporal-operator-map [eventually-temporal-operator]
'(menu-item "<>F" tla+-operator-eventually
:help "F is eventually true"))
(bindings--define-key
temporal-operator-map [wf-temporal-operator]
'(menu-item "WF_e(A)" tla+-operator-weakfairness
:help "Weak fairness for action A"))
(bindings--define-key
temporal-operator-map [sf-temporal-operator]
'(menu-item "SF_e(A)" tla+-operator-strongfairness
:help "Strong fairness for action A"))
(bindings--define-key
temporal-operator-map [leadsto-temporal-operator]
'(menu-item "F ~> G" tla+-operator-leadsto
:help "F leads to G"))
;; Export Menu:
(bindings--define-key menu-map [export] (cons "Export.." export-map))
(bindings--define-key export-map [export-pdf]
'(menu-item "Run TLatex and create PDF" tla+-run-tlatex-pdf
:help "Typeset TLaTex and create PDF Document"))
(bindings--define-key export-map [export-dvi]
'(menu-item "Run TLatex and create DVI" tla+-run-tlatex-dvi
:help "Typeset TLaTex and create DVI Document"))
(bindings--define-key export-map [export-ps]
'(menu-item "Run TLatex and create PS" tla+-run-tlatex-ps
:help "Typeset TLaTex and create PS Document"))
(bindings--define-key export-map [export-open]
'(menu-item "Open DVI Viewer" tla+-open-dvi
:help "Open DVI Viewer"))
;; Main Menu
(bindings--define-key map [menu-bar tla+ sep] menu-bar-separator)
(bindings--define-key map [menu-bar tla+ tla+-run-sany]
'(menu-item "Run Syntax Checker" tla+-run-sany
:help
"Run SANY2 "
"(parser/syntax checker for TLA+ specifications.) "))
(bindings--define-key map [menu-bar tla+ tla+-create-module]
'(menu-item "Create new Module" tla+-create-module
:help "Create a new TLA+ Module"))
(bindings--define-key map [menu-bar tla+ sep] menu-bar-separator)
map)
"Keymap for `tla+-mode'.")
(defconst tla+-font-lock-keywords
(list
'("\\<\\(MODULE\\|CONSTANTS?\\|UNCHANGED\\|VARIABLES?\\|THEOREM\\|INSTANCE\\|LOCAL\\|ASUME\\|EXCEPT\\|EXTENDS?\\)\\>"
. font-lock-builtin-face)
'("\\<\\(TRUE\\|FALSE\\|OTHER\\|BOOLEAN\\)\\>" . font-lock-type-face)
'("\\<\\(CONSTANT\\|SUBSET\\|ENABLED\\|UNCHANGED\\|UNION\\|DOMAIN\\|EXCEPT\\|IF\\|THEN\\|ELSE\\|CHOOSE\\)\\>" . font-lock-keyword-face)
'("\\\\\\*.*$" . font-lock-comment-face)
'("(\\*.*\\*)" . font-lock-comment-face)
'("\\('\\w*'\\)" . font-lock-variable-name-face)
"Highlighting for TLA+ Operators, Keywords etc."))
;;;###autoload (add-to-list 'auto-mode-alist '("\\.tla\\'" . tla+-mode))
;;;###autoload
(define-derived-mode tla+-mode nil "TLA+"
"Major mode for editing TLA+ specifications.
In this mode, syntax highlighting is activated for TLA+ specification
files. Various operators can be inserted by `tla+-operator-NAME'.
\\{text-mode-map}
Turning on Text mode runs the normal hook `text-mode-hook'."
(setq-local font-lock-defaults
'(tla+-font-lock-keywords))
(setq-local text-mode-variant t)
(setq-local comment-start "\\* ")
(setq-local require-final-newline mode-require-final-newline))
(defun tla+-create-module ()
(interactive)
(insert
(concat
"------------------- MODULE ......... -----------------------\n"
"EXTENDS Naturals, ...\n"
"VARIABLE ..\n"
"------------------------------------------------------------\n"
"============================================================\n"
"\\* Modification History\n"
"\\* Created "
(current-time-string) " by " user-full-name "\n")))
(defun tla+-run-sany ()
"TODO: jump to line.."
(interactive)
(let* ((filename (buffer-file-name))
(sanybuffer (get-buffer-create "*tla2sany.SANY*"))
(output (shell-command-to-string (concat
tla+-java-path
" -cp "
tla+-tlatools-path
" tla2sany.SANY "
filename))))
(save-excursion
(split-window-below)
(other-window 1)
(switch-to-buffer sanybuffer)
(erase-buffer)
(insert output))))
(defun tla+-open-dvi (buffername)
(interactive "b")
(save-excursion
(switch-to-buffer buffername)
(let* ((filename (buffer-file-name))
(dviname (replace-regexp-in-string
".tla$" ".dvi" filename)))
(shell-command (concat "xdvi " dviname " &")))))
(defun tla+-operator-alwaystrue ()
(interactive) (insert " []F"))
(defun tla+-operator-eventually ()
(interactive) (insert " <>F"))
(defun tla+-operator-weakfairness ()
(interactive) (insert " WF_e(A)"))
(defun tla+-operator-strongfairness ()
(interactive) (insert " SF_e(A)"))
(defun tla+-operator-leadsto ()
(interactive) (insert " F~>G "))
(defun tla+-operator-stutter ()
(interactive) (insert " [A]_e"))
(defun tla+-operator-primed ()
(interactive) (insert " e'"))
(defun tla+-operator-nonstutter ()
(interactive) (insert " <<A>>_e"))
(defun tla+-operator-enabled ()
(interactive) (insert " ENABLED A"))
(defun tla+-operator-unchanged ()
(interactive) (insert " UNCHANGED e"))
(defun tla+-operator-unchanged ()
(interactive) (insert " A \\cdot B"))
(defun tla+-run-tlatex (type)
"TODO: jump to line.."
(interactive
(list
(completing-read
"Format: "
'(("pdf" 1) ("dvi" 2) ("ps" 3)) nil t "")))
(let* ((filename (buffer-file-name))
(output (shell-command (concat
tla+-java-path
" -cp "
tla+-tlatools-path
" tla2tex.TLA "
filename)))
(dvipath (replace-regexp-in-string
".tla$" ".dvi" filename))
(convert2pdf (concat
tla+-dvipdf-path " " dvipath))
(convert2ps (concat
tla+-dvips-path " " dvipath)))
(progn
(cond
((eq type 'pdf)
(shell-command convert2pdf))
((eq type 'ps)
(shell-command convert2ps)))
type)))
;; (save-excursion
;; (split-window-below)
;; (other-window 1)
;; (switch-to-buffer sanybuffer)
;; (insert output))))
(defun tla+-run-tlatex-pdf ()
(interactive) (tla+-run-tlatex 'pdf))
(defun tla+-run-tlatex-dvi ()
(interactive) (tla+-run-tlatex 'dvi))
(defun tla+-run-tlatex-ps ()
(interactive) (tla+-run-tlatex 'ps))
(provide 'tla+-mode)