THANK YOU for OCaml Platform 'Switch implemention/interface' feature!

I just wanted to give a shout-out to the VSCode OCaml Platform developers, you’ve done an amazing job on this. Clicking the ‘Switch’ button or pressing Option-O immediately opens up the corresponding file, creating it if it doesn’t exist. Makes it super simple to quickly set up interfaces and switch between them.

9 Likes

You should see what we have for the next release of vscode ocaml platform & OCaml LSP!

7 Likes

Super stoked and looking forward to it! I’ll also to try dive into the codebase. Very impressed by the work.

Just curious, not trolling, is that something you recently discovered or did that only happen now ?

I mean I don’t have a beard but unless I’m mistaken caml-mode had that ever since I started using it around 2002. I would get crazy and quit OCaml programming if my editor hadn’t such a basic feature. How can you even try to write good doc strings if it’s a pain to make such a simple switch ?

Also I hope it doesn’t create the file if it doesn’t exist but just a buffer to save case happening. You don’t want your editor pooping .mli/.ml files if they don’t exist if your are just checking out for an existing correspondance.

It also reminds me that a more sophisticated feature would be for merlin to switch between the location of an ID in the .ml and .mli when you are on the definition/sig rather than give up with "Already at definition point". But IIRC when I complained to the wizards they told me it was easier to say than to do.

3 Likes

Yeah, I’ve really never used this feature before. Likely Merlin has it, but I’ve never looked it up. Before the VSCode extension, it’s never been so discoverable (to me at least).

And yes you’re right, it doesn’t create the file but loads it in a buffer, ready to save. Quite elegant because you can easily generate the interface, and then edit and save it if you want.

For reference to the Emacs users reading the thread, the default binding for this in Tuareg-mode in Emacs is C-c C-a.

2 Likes

Interesting. Is this a new feature in Tuareg-mode? I don’t remember hearing about it before, e.g. no one suggested it here Merlin: Possible to view inferred interface/mli? - #4 by thomas_ridge

Going off of the git blame it seems to have been around for a quite a while at least - however, it doesn’t auto insert the inferred signature of the current module if the implementation doesn’t exist, it just creates an empty file, does the VScode switch interface/implementation keybinding do this?

1 Like

It seems the VScode implementation does indeed do this.

If anyone’s interested, you can get roughly the same functionality on Emacs using the following code (call init-ocaml/find-alternate-file to switch between files):

(defun init-ocaml/get-module-signature ()
  "Return a string representing the file's signature."
  (interactive)
  (let ((buffer-text (buffer-substring-no-properties (point-min) (point-max)))
        module-text
        module-sig)
    (setq module-text
          (concat "module M = struct\n" buffer-text "\nend"))
    (setq module-sig
          (with-temp-buffer
            (insert module-text)
            (goto-char 0)
            (merlin--type-enclosing-query)))
    (unless module-sig
      (error "Could not type expression."))
    (setq module-sig (caar module-sig))
    (if (and module-sig (>= (length module-sig) 8))
        (substring module-sig 4 (- (length module-sig) 4))
      "")))

(defun init-ocaml/find-alternate-file ()
  "Switch between interface/implementation OCaml files
auto-inserting module signature if needed."
  (interactive)
  (let ((name (buffer-file-name)))
    (if (string-match "\\`\\(.*\\)\\.ml\\'" name)
        (let ((module-signature (init-ocaml/get-module-signature)))
          (tuareg-find-alternate-file)
          (setq name (buffer-file-name))
          (when (and
                 (string-match "\\`\\(.*\\)\\.mli\\'" name)
                 (string-empty-p (buffer-substring-no-properties (point-min) (point-max))))
            (insert module-signature)))
      (tuareg-find-alternate-file))))```
1 Like

Note it’s not merlin that provide that, it’s caml-mode.

In practice I don’t find generating the interface that useful since it’s often what you start from – or at least you should :–). I’d rather have it the other way round, a tool synthetising my code from specifications (see for example the last chapter of this lovely functional pearl).

Also the whole interface generation is useless for evolving them.

For the latter merlin has C-c t to ask for the type of anything, if you follow up with C-w it copies the type to the kill ring which you can gladly paste at the right place in the interface file. It may require a bit of cleaning up (qualifications not matching the opens of the mli, too general or weak types, etc.) but it’s a good start to declare the signature of your new entry.

6 Likes

Sending this code as a PR to ‘tuareg-mode’ Pull requests · ocaml/tuareg · GitHub might be interesting.

1 Like

Oh, if Merlin doesn’t have it, then I would’ve never used it. And I suspect many others wouldn’t either. At least those of us who don’t use Emacs :slight_smile:

Just for historical color, the ability to switch between implementation and interface in caml-mode (the precursor/basis for tuareg) using C-c C-a in emacs has existed since very early versions of caml-mode in ~1996 (around OCaml 1.04) by J Garrigue,

Cheers,
Nicolas

3 Likes

I’m not sure if it’s quite in a state where it would be worthwhile to include into Tuareg itself.

As you can see from the code, it’s just a small hack using merlin’s type-enclosing to generate a signature for the current file, then using substrings to remove the sig,end.

It works well enough for personal use, but it’s a bit unpolished - I think the VScode version calls out to some dedicated language server command that generates exactly the signature for the current file (without having to do this rigmarole wrapping everything in a struct).

Ideally, I’d like to do the same in Emacs, but I looked briefly at both the merlin elisp code and the ocamlmerlin cli tool, but I couldn’t find a command that would do the equivalent of generating a signature of the current file/buffer.

Tuareg now offers to fill the .mli buffer when the .mli file does not exist.

4 Likes