Ada TS Mode by Troy Brown is an Emacs-based IDE for Ada.
It’s a replacement for Emacs Ada Mode by Stephe Leake and others.
It’s prompted by Ada Mode’s difficult installation procedure, which requires building support packages on the user’s computer. This build process is somewhat sensitive to the compiler version used. Also, Ada Mode is no longer maintained, since the sole active maintainer retired.
Ada TS Mode uses Tree-sitter for parsing, and Ada Language Server for language support. Ada Language Server is an implementation of Microsoft’s Language Server Protocol for Ada.
Installing
Ada TS Mode
Ada TS Mode’s main documentation is in the README of the Github repository. It covers the prerequisites and installation. The important prerequisite is the use of Emacs 29 or later.
As well as the package ada-ts-mode
, install the following packages:
gpr-ts-mode
gpr-yasnippets
lsp-mode
company
If you’re planning to use eglot
instead of lsp-mode
, install the updated 1.18 version from the gnu-devel
archive.
Ada Language Server
Download the latest ALS for your OS and architecture.
If you’re on a Mac, remove the ‘quarantine’ attribute on the downloaded archive by running
xattr -d com.apple.quarantine als-{rel}-{os}-{arch}.tar.gz
and unpack it. To support Visual Studio Code, this unpacks into integration/vscode/ada/{arch}/{os}/
- that last directory contains ada_language_server
, and needs to be on your PATH.
Setting up
Lisp setup script
My setup script, to be invoked from ~/.emacs
by (load "~/.emacs-ada.el")
, is here. It’s based on Troy Brown’s init.el
.
The main alteration is the method of finding the root of the project (LSP deals with all the files at and below the project root).
The default behaviour is to look for a repository, but this fails when your main project has subprojects (for instance, with Alire, a test crate contained in the main crate). Also, of course, you might not be in an Alire crate or a repo anyway, so probably a GPR file would be a reasonable choice.
The solution was to define two functions: to look for alire.toml
,
(defun ada-mode--find-alire (dir)
;; Look up-tree, starting at dir, for alire.toml; return its full
;; path name if found, nil if not.
(let ((alire (locate-dominating-file dir "alire.toml")))
(if alire
(cons 'transient alire)
nil)))
and to look for a .gpr
file,
(defun ada-mode--find-gpr (dir)
;; Look up-tree, starting at dir, for a .gpr file, returning its
;; full path name if found, nil if not.
(let ((gpr (locate-dominating-file
dir
(lambda (dir) (directory-files dir nil "gpr"))
)))
(if gpr
(cons 'transient gpr)
nil)))
and to invoke them from the project
package:
(use-package project
:config
(add-hook 'project-find-functions #'ada-mode--find-gpr)
(add-hook 'project-find-functions #'ada-mode--find-alire)
)
(the last hook installed is the first used).
It would have been possible to say this:
:custom
(project-vc-extra-root-markers '("alire.toml" "*.gpr")
but I prefer alire.toml
to a .gpr
file in a lower directory.
Customisations
Emacs customisations
Note, ada-ts-mode
customisations are in the group ada-ts
, gpr-ts-mode
’s in the group gpr-ts
.
I didn’t find any customisations necessary.
Formatting options
Currently, ada-ts-mode
asks the Ada Language Server to apply formatting options using the GPR package Pretty_Printer
.
This package can be used to provide options to the stand-alone GNATpp
. ALS uses the same formatting engine, but be aware that
- not all the options available in
gnatpp
are available in ALS, specifically--dictionary=casing-dictionary-file
, and - some options may cause errors, specifically
--call-threshold=nnn
,--par-threshold=nnn
(but ALS uses default 1 in both cases, which works well).
The default casing options, basically to use the same case as the declaration, work extremely well.
AdaCore intend to retire GNATpp in favour of the new GNATFormat, which is controlled by the GPR package Format
. Ada TS Mode doesn’t yet have an option to select this.
Be aware that at present GNATformat doesn’t provide any casing support at all.
Usage notes
Since the general setup instructions assume you’re using package
, you should put something like this in your ~/.emacs
:
(require 'package)
(package-initialize)
(load "~/.emacs-ada.el")
(see here for my ~/.emacs-ada.el
).
Key bindings
Meaning | |
---|---|
M-. | find definition |
M-, | go back |
M-C-, | go forward |
M-? | find references |
M-C-. | find apropos |
C-x 4 . | find definitions in other window |
C-x 5 . | find definitions in other frame |
C-c C-b | create a comment box for the current subprogram |
C-c C-o | find the other file (spec-> body, body->spec) |
C-c C-p | find the project file |
C-<down-mouse-1> | find definition |
If you use mouse-buffer-menu
, and have got used to using C-<down-mouse-1>
to show a popup menu to select live buffers, you’ll need to consider the clash between that binding and the above binding in Ada TS Mode. I’ve resolved it by using Control-Shift-mouse button 1 for that purpose:
(global-set-key [C-S-down-mouse-1] #'mouse-buffer-menu)
though muscle memory makes me think I should maybe resolve that the other way.
Use with Alire
For Ada TS Mode to work well, it needs to have GPR_PROJECT_PATH
set up. The best way to do this is to use alr edit
(at the top of the crate), which you can set up with
alr settings --set --global editor.cmd 'open -n -a emacs ${GPR_FILE}'
which opens a new instance of Emacs, displaying the crate’s GPR file.
If you replace ${GPR_FILE}
with just .
(a period) the new instance will open a dired buffer on the current directory (which doesn’t have to be at the top of the crate, but must be in the crate).
No comments:
Post a Comment