Changelog

July 10, 2026 · View on GitHub

main (unreleased)

0.10.0 (2026-07-10)

New features

  • Add neocaml-utop, an alternative toplevel backend that drives utop through its native editor protocol (utop -emacs). It runs in a comint-based transcript with input history and completion-at-point backed by utop's own engine, separates output/results/errors/warnings, and underlines the exact sub-expression a parse or type error points at in the source buffer (with the error message as the overlay's tooltip; the underline clears when you edit the code). Source evaluations cover every ;;-separated phrase in the region, and the result is shown both in the minibuffer (SLIME/CIDER style; toggle with neocaml-utop-echo-eval-result) and inline in the source buffer as a => ... overlay (toggle with neocaml-utop-inline-eval-result). In the transcript, RET submits a complete phrase and otherwise inserts a newline, so multi-line phrases can be entered naturally, and typed input is fontified with tree-sitter (toggle with neocaml-utop-fontify-input). Enable neocaml-utop-minor-mode in OCaml buffers to use it; the keybindings mirror neocaml-repl-minor-mode.

0.9.0 (2026-06-24)

New features

  • #63: Flesh out the mode and REPL menus:
    • Add an "Edit" submenu (comment/uncomment region, fill comment paragraph, indent region).
    • Add an "OCaml REPL" menu to the REPL buffer (neocaml-repl-mode) for switching back to the source, interrupting, and clearing the buffer.
    • Add a "Toggle" submenu (prettify symbols, subword mode, outline minor mode) and a "Start/Switch to REPL" entry to the mode menu.
    • Add help strings (tooltips) and "Customize" entries to the menus, and disable REPL commands that need an active region or a running process when those aren't available.
  • Add neocaml-set-font-lock-level and a "Font-Lock Level" submenu for switching the tree-sitter fontification level (1-4) in the current buffer.
  • #65: Add neocaml-format-buffer (bound to C-c C-f) to format OCaml source with ocamlformat, plus an opt-in neocaml-format-on-save.
  • #65: Make URLs and bug references in comments clickable across the OCaml source and tool modes via goto-address-prog-mode and bug-reference-prog-mode. Set bug-reference-url-format (e.g. via .dir-locals.el) to resolve issue references.
  • #65: Add neocaml-repl-restart to kill and restart the OCaml toplevel, with a matching entry in the REPL menu.
  • #68: Add neocaml-repl-send-phrase-and-step (bound to C-c C-n), which sends the phrase at point to the REPL and advances to the next one, and neocaml-repl-require for loading a findlib package via #require.
  • #69: Give each project its own dedicated REPL. The REPL buffer is now named per project (e.g. *OCaml: myproject*, derived from neocaml-repl-buffer-name), and the send commands route to the current buffer's project REPL, so multiple projects can run side by side. This also fixes neocaml-dune-utop so the send commands reach its toplevel.
  • #70: Add neocaml-repl-flavor for choosing which toplevel the REPL runs (ocaml, utop, or dune-utop); set it globally or per project via .dir-locals.el. The active flavor is shown in the REPL's mode line.
  • #71: Integrate with project.el: a directory containing a dune-project file is recognized as a project root (for non-VC projects), _build/ and _opam/ are ignored, and compile-command defaults to dune build in dune projects.
  • #72: Add completion-at-point support to neocaml-dune-mode and neocaml-opam-mode. dune files complete stanza names, the field names valid for the enclosing stanza, and library names inside libraries/pps fields (both the project's own libraries and the installed findlib libraries); opam files complete field and section names and, inside depends/depopts/conflicts, package names (via opam list). The external candidate sources are gathered from the project root, so a project-local opam switch (_opam/) is detected and used automatically (via opam exec --); they are cached per project and can be toggled with neocaml-dune-complete-libraries and neocaml-opam-complete-packages.

Bug fixes

  • #66: Correctly handle character literals and quoted strings at the syntactic layer via a syntax-propertize-function. Characters like '"', '(', and ')', and the contents of {|...|} / {id|...|id} quoted strings, no longer confuse sexp motion, electric-pair-mode, delete-pair, or syntax-ppss.

Changes

  • Switch the ocaml and ocaml-interface grammars to tree-sitter-ocaml v0.25.0, pinned to the upstream v0.25.0-abi14 tag (an ABI 14 regeneration of the same grammar, since v0.25.0 itself generates an ABI 15 parser most Emacs builds can't load yet). This brings in the OCaml 5.5 grammar support.
  • #60: Highlight function-typed val specifications in .mli files with the function face, matching how function let bindings are highlighted in implementations.
  • Handle OCaml 5.5 external type declarations (type t = external "caml_foo") in sexp navigation, so C-M-f/C-M-b step over the whole declaration body instead of just the external keyword.

0.8.1 (2026-05-13)

Bug fixes

  • #57: Stop passing -emacs to utop in neocaml-dune-utop (and drop it from the recommended config in the docs). That flag activates utop's structured protocol intended for the old utop.el, which neocaml-repl doesn't implement, so the protocol output was leaking into the REPL buffer.
  • #58: neocaml-backward-up-list now jumps out of optional parameters with defaults (e.g., ?(foo = 123)) instead of erroring with "At top level".
  • #53: Capture stderr separately when running dune format-dune-file, so the Entering directory / Leaving directory markers newer dune versions emit on stderr no longer wrap the formatted buffer.

Changes

  • #42: Lower the tree-sitter ABI requirement from 15 to 14 across neocaml-opam-mode, neocaml-dune-mode, and neocaml-ocamllex-mode, so they work on Emacs built against tree-sitter 0.24 (e.g., the homebrew Emacs 30 on macOS). Switch the menhir recipe to tmcgilchrist/tree-sitter-menhir and pin the ocamllex recipe back to v0.24.0, both of which target ABI 14.

0.8.0 (2026-04-10)

New features

  • #47: Add neocaml-backward-up-list, bound to C-M-u, for jumping out of the enclosing OCaml block (struct/sig/object, records, arrays, etc.). The built-in backward-up-list doesn't understand keyword-delimited constructs on Emacs 29/30.
  • #41: neocaml-dune-mode now activates for dune-workspace file variants like dune-workspace.ci and dune-workspace.5.3.
  • Add neocaml-cram-mode for editing cram test (.t) files with tree-sitter font-lock, indentation, and imenu.
  • Add neocaml-dune-format-buffer for formatting dune files via dune format-dune-file.
  • Register neocaml modes with dape for ocamlearlybird debugging support.
  • Register file associations for .ocamlinit, .ocamlformat, and .ocp-indent files.
  • Extend neocaml-opam-mode to activate for .opam.template files.
  • Include per-grammar ABI version in neocaml-bug-report-info output.

Changes

  • The _build/ directory redirect is now optional (controlled by neocaml-redirect-build-files).

0.7.1 (2026-03-31)

Bug fixes

  • Fix malformed eglot-server-programs entry that prevented eglot-ensure from starting ocamllsp for neocaml modes.

0.7.0 (2026-03-31)

New features

  • #36: Add neocaml-ocamllex-mode for editing OCamllex (.mll) files with tree-sitter font-lock, indentation, imenu, and defun navigation. Embedded OCaml code inside { } blocks gets full syntax highlighting via language injection when the OCaml grammar is installed. Based on the tree-sitter-ocamllex grammar.
  • #36: Add neocaml-menhir-mode for editing Menhir (.mly) files with tree-sitter font-lock, indentation, imenu, and defun navigation. Embedded OCaml code inside { } and %{ %} blocks gets full syntax highlighting via language injection. Based on the tree-sitter-menhir grammar.
  • Register neocaml-mode and neocaml-interface-mode with eglot-server-programs so eglot-ensure works out of the box with ocamllsp.

Bug fixes

  • #37: Guard ABI 15 grammars (ocamllex, menhir) on Emacs 30+ and include ABI version in neocaml-bug-report-info.
  • Language injection in ocamllex and menhir modes now requires Emacs 30+ (injection queries are not supported on Emacs 29).

0.6.0 (2026-03-25)

Bug fixes

  • #34: Fix indentation of continuation lines inside multi-line comments. Lines now align with the body text after the opening delimiter.

New features

  • Add neocaml-dune-mode for editing dune, dune-project, and dune-workspace files with tree-sitter font-lock, indentation, imenu, and defun navigation. Based on the tree-sitter-dune grammar.
  • Add neocaml-opam-mode for editing opam package files with tree-sitter font-lock, indentation, and imenu. Based on the tree-sitter-opam grammar.
  • Add neocaml-dune-interaction-mode, a minor mode for running dune commands (build, test, clean, promote, fmt, utop, exec) from any neocaml buffer via compile. Includes watch mode support via prefix argument and a Dune menu.
  • Add flymake backend for opam lint in neocaml-opam-mode. Enabled by default when the opam executable is found.
  • Add tree-sitter font-locking for REPL input via comint-fontify-input-mode. Code typed in the REPL now gets the same syntax highlighting as regular .ml buffers. Controlled by neocaml-repl-fontify-input (default t).

0.5.0 (2026-03-16)

Bug fixes

  • #26: Preserve list items and odoc tags as paragraph boundaries when filling comments.
  • #27: neocaml-install-grammars now accepts a prefix argument (C-u) to force reinstallation of grammars, even if they are already installed.
  • Avoid the superfluous spaces after the prompt of the REPL when sending code to the REPL via the commands neocaml-repl-send-*.
  • #28: Fix delete-pair deleting the wrong closing delimiter. Add a list thing to treesit-thing-settings and a hybrid forward-sexp that falls back to syntax-table matching on delimiter characters.

New features

  • Support outline-minor-mode for folding top-level definitions (Emacs 30+).
  • Support which-func-mode for displaying the current definition name in the mode line.
  • Add neocaml-objinfo-mode for viewing OCaml compiled artifacts (.cmi, .cmo, .cmx, .cma, .cmxa, .cmxs, .cmt, .cmti) via ocamlobjinfo. Includes font-lock, imenu navigation, and revert support.
  • Set treesit-primary-parser for Emacs 31+ compatibility.

0.4.1 (2026-03-10)

Bug fixes

  • #24: Fix grammar compatibility check always warning even with up-to-date grammars. treesit-query-compile doesn't validate field names, so the check now uses treesit-node-child-by-field-name on an actual parse tree instead.

0.4.0 (2026-03-10)

Bug fixes

  • #20: Work around broken transpose-sexps on Emacs 30 (bug#60655). Falls back to default transpose behavior; Emacs 31 has a proper fix.
  • #22: Fix compilation regexp to handle arbitrary leading whitespace in OCaml error messages.
  • #22: Fix off-by-one in compilation column positions. OCaml uses 0-indexed columns; the begin-column is now correctly converted to Emacs's 1-indexed columns.

Changes

  • Bump required tree-sitter-ocaml grammar from v0.24.0 to v0.24.2. Users must reinstall their grammars via M-x neocaml-install-grammars. The upstream release includes breaking changes to the parse tree structure (see tree-sitter-ocaml#126).
  • neocaml now warns at startup if the installed grammar is older than expected.
  • Reorganize font-lock feature levels to align with Emacs conventions: type moved to level 2, number moved to level 3, escape-sequence split into its own feature at level 3, and property and label split into their own features at level 4.

New features

  • Add neocaml-mark-sentence command to mark the current statement around point.
  • Add neocaml-bug-report-info command for collecting debug information in bug reports.
  • Add "Navigate" submenu to the OCaml menu with structural navigation commands.
  • Add mark and transpose commands to the OCaml menu.
  • Highlight escape sequences (\n, \t, etc.) in strings with font-lock-escape-face.
  • Highlight conversion specifications (%d, %s, etc.) in format strings with font-lock-regexp-face.
  • Highlight match+ and similar binding operators as keywords in match expressions.
  • #23: Add iarray to the list of builtin types.

0.3.0 (2026-02-26)

Bug fixes

  • Fix M-q (fill-paragraph) not indenting continuation lines in comments.
  • Fix M-; (comment-dwim) failing to remove *) when uncommenting a region.

New features

  • Add comment-indent-new-line support: M-j inside comments continues the comment with proper indentation.
  • Highlight binding operators (let*, let+, and*, and+) as keywords.
  • Add electric-indent-chars for {}() so electric-indent-mode reindents after typing delimiters.
  • Add fill-paragraph support for OCaml (* ... *) comments via tree-sitter.
  • Document outline-minor-mode and treesit-fold for code folding in README.

0.2.0 (2026-02-17)

Bug fixes

  • Fix compile-goto-error landing one column before the actual error position. OCaml uses 0-indexed columns; compilation-first-column is now set to 0 accordingly.
  • Fix neocaml-repl-send-definition signaling an error when point is not inside a definition.
  • Fix ;; terminator detection: only check whether input ends with ;; instead of searching anywhere in the string, avoiding false positives from ;; inside strings or comments.
  • Fix neocaml-repl-send-phrase to skip ;; inside strings and comments when locating phrase boundaries.

New features

  • Add neocaml-repl-load-file (C-c C-l): load the current file into the REPL via the #use directive.
  • Add REPL input history persistence across sessions via neocaml-repl-history-file and neocaml-repl-history-size.
  • Flash the sent region when evaluating code in the REPL (send-region, send-definition, send-phrase, send-buffer).

Changes

  • Introduce neocaml-base-mode as the shared parent for neocaml-mode and neocaml-interface-mode. Users can hook into neocaml-base-mode-hook to configure both modes at once.
  • Improve utop support: strip ANSI escape sequences and recognize utop's prompt format so point is correctly placed after the prompt.
  • Make C-c C-z reversible: from a source buffer it switches to the REPL, from the REPL it switches back.
  • Add _build directory awareness: when opening a file under _build/, offer to switch to the source copy (supports dune and ocamlbuild layouts).
  • Split neocaml-prettify-symbols-alist into a column-width-safe base list and neocaml-prettify-symbols-extra-alist (fun->λ, ->->→, not->¬). Control extra symbols with the neocaml-prettify-symbols-full toggle.
  • Register OCaml build artifact extensions (.cmo, .cmx, .cmi, etc.) in completion-ignored-extensions to declutter find-file completion.
  • Bind C-c C-c to compile in neocaml-mode (shadowed by neocaml-repl-send-definition when the REPL minor mode is active).
  • Extend neocaml-other-file-alist to support .mll, .mly, and .eliom/.eliomi file pairs for ff-find-other-file.
  • Register OCaml compilation error regexp for M-x compile support (errors, warnings, alerts, backtraces).
  • Add treesit-thing-settings for sexp, sentence, text, and comment navigation (Emacs 30+).
  • Add sentence navigation (M-a/M-e) for moving between top-level definitions.
  • transpose-sexps now works with tree-sitter awareness (Emacs 30+).
  • Replace automatic grammar installation with the interactive command M-x neocaml-install-grammars.
  • Remove neocaml-ensure-grammars defcustom.
  • Remove neocaml-use-prettify-symbols and neocaml-repl-use-prettify-symbols defcustoms. prettify-symbols-alist is now always set; users enable prettify-symbols-mode via hooks.

0.1.0 (2026-02-13)

Initial release.

Features

  • Tree-sitter based font-locking with 4 levels of highlighting for .ml and .mli files.
  • Tree-sitter based indentation with cycle-indent support.
  • Imenu integration with language-specific categories for .ml and .mli.
  • Navigation support (beginning-of-defun, end-of-defun, forward-sexp).
  • OCaml toplevel (REPL) integration via neocaml-repl.
  • Automatic grammar installation via treesit-install-language-grammar.
  • Switch between .ml and .mli files with ff-find-other-file.
  • Prettify-symbols support for common OCaml operators.
  • Eglot integration for LSP support (e.g. ocamllsp).