An open API service indexing awesome lists of open source software.

https://github.com/viperproject/gobra-mode

Support for Gobra in emacs
https://github.com/viperproject/gobra-mode

Last synced: 2 months ago
JSON representation

Support for Gobra in emacs

Awesome Lists containing this project

README

          

* Gobra-mode for Emacs

Adds support to Emacs for [[https://www.pm.inf.ethz.ch/research/gobra.html][Gobra]]. Features include:
- Syntax highlighting for Gobra keywords.
- Interface to the Gobra executable.
- Error highlighting after running Gobra.
- Jump to error functionality.
- Interface for manipulating Gobra parameters.
- Various manipulations of ghost code blocks in ~.go~ files.

* Installation

This package is under development (many changes may be non backwards compatible). Thus, it is not published in any package archives.

To install it, one must clone the repository:

#+BEGIN_SRC shell
git clone git@github.com:viperproject/gobra-mode.git
#+END_SRC

Then, add the following lines in your init file.

#+BEGIN_SRC emacs-lisp
(add-to-list 'load-path "")
(use-package gobra-mode)
(setq gobra-jar-path "")
(setq gobra-z3-path "")
#+END_SRC
* Usage

Default keybindings provided by the gobra minor mode:
- ~C-c g v~: Verifies the file corresponding to the current buffer.
- ~C-c g c~: Opens the generated Viper code in a new buffer.
- ~C-c g a~: Spawns a construction buffer through which the parameters passed to gobra are manipulated.
- ~C-c g s~: Gobra mode creates the command that Gobra should run serializing the parameters and copying it to the kill-ring. Useful if working with the sbt shell of Gobra directly.
- ~C-c g b~: Gobra mode defines a hook called ~gobra-verification-hook~. Anything added to that will be called when verification finishes if the variable ~gobra-enable-verification-hook~ is non-nil. Useful if you want to be notified after a large verification task finishes. This command toggles the variable ~gobra-enable-verification-hook~.
- ~C-c g k~: Toggles the popping up of the verification buffer when verifying something. Useful if you need the verification buffer on a frame on a different monitor.
- ~C-c g l~: Verify the function under the cursor only. This assumes the parameters explicitly have the current file for verification (not its directory or package).
- ~C-c g h~: Fold or unfold ghost code chunk under cursor (works for ~.go~ files where the comment syntax (~// @~) is used.
- ~C-c g j~: Unfold every folded piece of ghost code in the current buffer.
- ~C-c g f~: Format the ghost code chunk under cursor. This currently converts ~//@~ annotations to ~// @~ annotations and aligns the arguments of the keywords ~preserves~, ~requires~ and ~ensures~ in function contracts.
- ~C-c g C-f~: Format ghost code in the whole buffer.
- ~C-c g p~: Jump to previous ghost code chunk.
- ~C-c g n~: Jump to next ghost code chunk.

If [[https://github.com/abo-abo/hydra][Hydra]] is installed, pressing ~C-c g~ will spawn a hydra menu with all these commands available.

The construction buffer for the parameters can be used to set, unset or modify the existing parameters of Gobra. It contains a checklist of possible Gobra parameters for which the following operations are defined:

- ~c~: Set or unset the current parameter. If the parameter has itself arguments, the user is prompted to fill them.
- ~a~: Add arguments to an already set parameter.
- ~d~: Delete the current argument of a parameter.
- ~?~: Print documentation about the current parameter.
- ~s~: Save the current set of parameters (and their arguments) to a file.
- ~l~: Load a configuration from a file.
- ~q~: Exit and return to the Gobra buffer.
- ~j~: Jump to a specific parameter.
- ~n~ - ~p~: Move up and down.

When the verifier is running, it lives in an async command in a buffer by default called ~*Gobra Command Output*~. That buffer also supports some extra functionality, namely:

- ~n~: Go to the next reported error.
- ~p~: Go to the previous reported error.
- ~RET~: Go to the location of the error reported under the cursor at the corresponding file. If the file is not open, it is opened. If the cursor is over an error of the Gobra implementation, ~RET~ opens the corresponding file where the exception was raised. This only works if ~gobra-development-path~ is set to point to the src directory of Gobra.

When the Gobra command terminates, the errors are highlighted in the already open buffers that are getting verified.

* Minor mode

The minor mode can be enabled automatically when a ~.go~ file is opened with:

#+begin_src emacs-lisp
(add-hook 'go-mode-hook 'gobra-minor-mode)
#+end_src

Note that the minor mode is responsible for almost everything so it should be enabled for ~.gobra~ files as well. ~gobra-mode~ however is a major mode deriving from ~go-mode~ so hooking the minor mode to ~go-mode~ will enable it for Gobra buffers as well.

* Overriding Go mode hooks

~gobra-mode~ is a derived mode from ~go-mode~. This means that when opening a ~.gobra~ file the ~go-mode-hook~ functions will be invoked. This creates a problem for example with the use of LSP mode if it is configured to start automatically for go files because there is no LSP backend for Gobra. To override that hook, a local variable ~gobra-actions-before-go-mode~ is defined which holds a function with stuff to do before the ~go-mode~ hooked functions run. The following hack is then possible to stop LSP from starting in a Gobra buffer:

First define a buffer-local variable:
#+begin_src emacs-lisp
(defvar-local my/conditional-lsp-flag t)
#+end_src

Then define a function starting LSP when that variable is true:
#+begin_src emacs-lisp
(defun my/conditional-lsp ()
(when my/conditional-lsp-flag
(lsp)))
#+end_src

Hook this to ~go-mode~ instead of just LSP:
#+begin_src emacs-lisp
(add-hook go-mode-hook 'my/conditional-lsp)
#+end_src

Use the ~gobra-actions-before-go-mode~ variable to turn the local variable to nil:
#+begin_src emacs-lisp
(setq gobra-actions-before-go-mode
(lambda ()
(setq-local my/conditional-lsp-flag nil)))
#+end_src

Now whenever a ~.gobra~ file is opened, ~lsp~ won't be invoked.

* Who do I talk to?
This project is maintained by [[https://github.com/Dspil][Dionisios Spiliopoulos]]