opam, dune & Cram Support¶
neocaml includes dedicated tree-sitter modes for opam and dune files,
plus a mode for dune's cram test files.
neocaml-opam-mode activates automatically for .opam, .opam.template,
and bare opam files;
neocaml-dune-mode activates for dune, dune-project, and dune-workspace
files (including variants like dune-workspace.ci). Both provide font-lock,
indentation, and imenu.
opam lint¶
neocaml-opam-mode registers an opam lint flymake backend so you get
inline diagnostics for missing fields, deprecated constructs, and syntax errors.
To enable it, activate flymake-mode in opam buffers:
(add-hook 'neocaml-opam-mode-hook #'flymake-mode)
flycheck users get opam lint support
out of the box via flycheck's built-in opam checker.
dune Commands¶
neocaml-dune-interaction-mode is a minor mode that provides keybindings for
running common dune commands from any neocaml buffer. All commands run via
compile, so you get error navigation (M-g n / M-g p), clickable source
locations, and the full compilation-mode interface.
Enable it in OCaml buffers:
(add-hook 'neocaml-base-mode-hook #'neocaml-dune-interaction-mode)
Or in all neocaml-related buffers (including dune and opam files):
(dolist (hook '(neocaml-base-mode-hook
neocaml-dune-mode-hook
neocaml-opam-mode-hook))
(add-hook hook #'neocaml-dune-interaction-mode))
Available commands (all under the C-c C-d prefix):
| Keybinding | Command | Description |
|---|---|---|
C-c C-d b |
neocaml-dune-build |
Build the project |
C-c C-d t |
neocaml-dune-test |
Run tests |
C-c C-d c |
neocaml-dune-clean |
Clean build artifacts |
C-c C-d p |
neocaml-dune-promote |
Promote test corrections |
C-c C-d f |
neocaml-dune-fmt |
Format code |
C-c C-d u |
neocaml-dune-utop |
Launch utop with project libraries |
C-c C-d r |
neocaml-dune-exec |
Run an executable (prompts for name) |
C-c C-d d |
neocaml-dune-command |
Run any dune command (with history) |
C-c C-d . |
neocaml-dune-find-dune-file |
Find the nearest dune file |
With a prefix argument (C-u), build, test, and fmt commands run in watch
mode (--watch), rebuilding automatically when files change. For example,
C-u C-c C-d b runs dune build --watch.
The project root is determined by walking up from the current file to find
dune-project.
If Emacs doesn't inherit your opam environment (common when launching
from a desktop shortcut), you can prefix all dune commands with
opam exec --:
(setq neocaml-dune-use-opam-exec t)
dune File Formatting¶
neocaml-dune-mode can format the current buffer using dune format-dune-file.
Use C-c C-f (neocaml-dune-format-buffer) to format on demand, or enable
automatic formatting on save:
(setq neocaml-dune-format-on-save t)
Note: this formats individual dune files via dune format-dune-file, which is
different from dune fmt (available via C-c C-d f) that formats the entire
project.
Completion¶
Both neocaml-dune-mode and neocaml-opam-mode add a
completion-at-point function, so M-x completion-at-point (C-M-i)
offers context-aware candidates. They also plug into UIs built on
completion-at-point, like the built-in completion-preview-mode,
corfu, and
company.
In dune files you get:
- stanza names (
library,executable,rule, ...) at the head of a top-level form - field names for the enclosing stanza (so a
libraryofferslibraries,modules,public_name, ... while aruleofferstargets,deps,action, ...) - library names inside
librariesandppsfields - both your own project's libraries (scanned from itsdunefiles) and the installed findlib libraries (fromocamlfind list)
In opam files you get:
- field and section names (
synopsis,depends,build,url, ...) at the start of a line - package names inside the
depends,depopts, andconflictsfields, sourced fromopam list
The external candidate sources are cached per project. Run
M-x neocaml-dune-refresh-libraries or M-x neocaml-opam-refresh-packages
after changing your opam switch or adding a library to pick up the change.
You can turn the external sources off with neocaml-dune-complete-libraries
and neocaml-opam-complete-packages; the static stanza/field completion
keeps working either way and needs no OCaml tooling installed.
Project-local switches
When the project root has a local switch (an _opam/ directory), the
library and package lists are gathered through opam exec -- from that
root, so the project's switch is used automatically - no configuration
needed. For a global switch where Emacs doesn't inherit the opam
environment (e.g. a GUI Emacs launched from a desktop shortcut), set
neocaml-dune-use-opam-exec / neocaml-opam-use-opam-exec to force the
listings through opam exec -- as well. This mirrors the same option
used for dune commands.
Cram Tests¶
neocaml-cram-mode provides syntax highlighting for cram test (.t) files, as
used by dune's expect-test framework. It highlights shell commands, expected
output, output modifiers ((re), (glob), (no-eol), (esc)), exit codes,
and prose comments.
The mode activates automatically for .t files. Use dune promote (available
via C-c C-d p with neocaml-dune-interaction-mode) to accept corrected test
output.
Note
The .t extension is also used by Perl test files. If you work with
both OCaml and Perl, you may need to override the association for Perl
projects:
;; Use cperl-mode for .t files in Perl projects
(add-to-list 'auto-mode-alist '("/t/.*\\.t\\'" . cperl-mode))
Entries added later to auto-mode-alist take priority, so the more specific
pattern above will win for .t files under a t/ directory (Perl convention).