Skip to content

Commit 8cd6716

Browse files
authored
Merge pull request #511 from bbatsov/decouple-from-tuareg
Decouple utop.el from tuareg-mode
2 parents fe6156f + 68573dd commit 8cd6716

2 files changed

Lines changed: 69 additions & 36 deletions

File tree

README.md

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ OCaml. It can run in a terminal or in Emacs. It supports line
88
editing, history, real-time and context sensitive completion, colors,
99
and more.
1010

11-
It integrates with the Tuareg, caml, ReasonML and typerex modes in Emacs.
11+
It includes built-in Emacs integration and works with Tuareg, caml,
12+
ReasonML and typerex modes. Other modes like
13+
[neocaml](https://github.com/bbatsov/neocaml) can also integrate
14+
via `utop-mode-compat-alist`.
1215

1316
![Screenshot](screenshot.png)
1417

@@ -290,11 +293,20 @@ have it enabled by default with the following configuration:
290293
If you plan to use utop with another major-mode than tuareg, replace
291294
`tuareg-mode-hook` by the appropriate hook. The utop minor mode will work out of
292295
the box with these modes: `tuareg-mode`, `caml-mode`, `reason-mode` and
293-
`typerex-mode`. For other modes you will need to set the following three
294-
variables:
296+
`typerex-mode`. Modes derived from any of these will also work automatically.
295297

296-
- `utop-skip-blank-and-comments`
297-
- `utop-skip-to-end-of-phrase`
298+
Other modes (e.g. `neocaml-mode`) can register support via
299+
`utop-mode-compat-alist`:
300+
301+
```elisp
302+
(add-to-list 'utop-mode-compat-alist
303+
'(my-ocaml-mode :next-phrase my-next-phrase
304+
:discover-phrase my-discover-phrase))
305+
```
306+
307+
Alternatively, you can set the following buffer-local variables:
308+
309+
- `utop-next-phrase-beginning`
298310
- `utop-discover-phrase`
299311

300312
You can also complete text in a buffer using the environment of the

src/top/utop.el

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
;; URL: https://github.com/ocaml-community/utop
66
;; Licence: BSD3
77
;; Version: 1.11
8-
;; Package-Requires: ((emacs "26") (tuareg "2.2.0"))
8+
;; Package-Requires: ((emacs "26"))
99
;; Keywords: ocaml languages
1010

1111
;; This file is a part of utop.
@@ -16,8 +16,8 @@
1616
;;
1717
;; utop.el has two components - a nice OCaml REPL with auto-completion and a
1818
;; minor mode (`utop-minor-mode'), which extends OCaml major modes
19-
;; (e.g. `caml-mode' and `tuareg-mode') with commands to evaluate forms directly
20-
;; in the REPL.
19+
;; (e.g. `tuareg-mode', `caml-mode') with commands to evaluate forms directly
20+
;; in the REPL. Other modes can integrate via `utop-mode-compat-alist'.
2121
;;
2222
;; See the "Integration with Emacs" section of the README for more info.
2323

@@ -27,7 +27,8 @@
2727
(require 'pcase)
2828
(require 'seq)
2929
(require 'tabulated-list)
30-
(require 'tuareg)
30+
(declare-function tuareg-discover-phrase "tuareg" (&optional pos))
31+
(declare-function tuareg-skip-blank-and-comments "tuareg" ())
3132

3233
;; +-----------------------------------------------------------------+
3334
;; | License |
@@ -247,26 +248,31 @@ backend")
247248
;; | Compatibility with different ocaml major modes |
248249
;; +-----------------------------------------------------------------+
249250

250-
(defun utop-compat-resolve (choices)
251-
"Resolve a symbol based on the current major mode. CHOICES is a
252-
list of 3 function symbols: (tuareg-symbol typerex-symbol caml-symbol)."
253-
(nth
254-
(pcase major-mode
255-
('tuareg-mode 0)
256-
('typerex-mode 1)
257-
('caml-mode 2)
258-
('reason-mode 3)
259-
(major-mode (error (format "utop doesn't support the major mode \"%s\". It
260-
supports caml, tuareg, typerex and reason modes by default. For other
261-
modes you need to set these variables:
262-
263-
- `utop-next-phrase-beginning'
264-
- `utop-discover-phrase'
265-
" major-mode))))
266-
choices))
251+
(defvar utop-mode-compat-alist
252+
'((tuareg-mode :next-phrase utop-tuareg-next-phrase
253+
:discover-phrase utop-tuareg-discover-phrase)
254+
(typerex-mode :next-phrase typerex-skip-to-end-of-phrase
255+
:discover-phrase typerex-discover-phrase)
256+
(caml-mode :next-phrase caml-skip-to-end-of-phrase
257+
:discover-phrase caml-find-phrase)
258+
(reason-mode :next-phrase reason-next-phrase
259+
:discover-phrase reason-discover-phrase))
260+
"Alist mapping major modes to their phrase navigation functions.
261+
Each entry is (MODE :next-phrase FN :discover-phrase FN).
262+
263+
:next-phrase FN should move point to the beginning of the next phrase.
264+
:discover-phrase FN should return a triple
265+
\(begin-pos end-pos end-pos-with-comments).
266+
267+
To add support for a new OCaml major mode, add an entry to this alist:
268+
269+
(add-to-list \\='utop-mode-compat-alist
270+
\\='(my-ocaml-mode :next-phrase my-next-phrase
271+
:discover-phrase my-discover-phrase))")
267272

268273
(defun utop-tuareg-next-phrase ()
269274
"Move to the next phrase after point."
275+
(require 'tuareg)
270276
(let* ((pos (save-excursion
271277
(when (looking-at-p "[;[:blank:]]*$")
272278
(skip-chars-backward ";[:blank:]")
@@ -281,19 +287,34 @@ modes you need to set these variables:
281287
(goto-char (match-end 0)))
282288
(tuareg-skip-blank-and-comments))))
283289

290+
(defun utop-tuareg-discover-phrase ()
291+
"Discover the phrase at point using tuareg."
292+
(require 'tuareg)
293+
(tuareg-discover-phrase))
294+
295+
(defun utop-compat-lookup (prop)
296+
"Look up a phrase function for the current major mode.
297+
PROP should be a keyword like :next-phrase or :discover-phrase.
298+
Also checks parent modes via `derived-mode-parent'."
299+
(let ((mode major-mode)
300+
entry)
301+
(while (and mode (not entry))
302+
(setq entry (assq mode utop-mode-compat-alist))
303+
(setq mode (get mode 'derived-mode-parent)))
304+
(if entry
305+
(or (plist-get (cdr entry) prop)
306+
(error "utop mode compat entry for \"%s\" is missing %s"
307+
(car entry) prop))
308+
(error "utop doesn't support the major mode \"%s\".
309+
To add support, either customize `utop-mode-compat-alist' or
310+
set `utop-next-phrase-beginning' and `utop-discover-phrase'
311+
as buffer-local variables" major-mode))))
312+
284313
(defun utop-compat-next-phrase-beginning ()
285-
(funcall
286-
(utop-compat-resolve '(utop-tuareg-next-phrase
287-
typerex-skip-to-end-of-phrase
288-
caml-skip-to-end-of-phrase
289-
reason-next-phrase))))
314+
(funcall (utop-compat-lookup :next-phrase)))
290315

291316
(defun utop-compat-discover-phrase ()
292-
(funcall
293-
(utop-compat-resolve '(tuareg-discover-phrase
294-
typerex-discover-phrase
295-
caml-find-phrase
296-
reason-discover-phrase))))
317+
(funcall (utop-compat-lookup :discover-phrase)))
297318

298319
;; +-----------------------------------------------------------------+
299320
;; | Utils |

0 commit comments

Comments
 (0)