Print module signature of a file using Merlin

318 views Asked by At

Using Merlin 2.5.4, what is the correct way to print the signature of an OCaml file in my project? E.g., suppose I have:

(* foo.ml *)
let x = 1

And I want to get:

val x : int

What is the proper command (or sequence of commands)?

What I've tried:

I temporarily wrapped up the file in a submodule: module Foo = struct let x = 1 end, then ran:

$ ocamlmerlin
["type","expression","Foo","at",{"line":1,"col":7}]

But I get:

["error",{"start":{"line":1,"col":0},"end":{"line":1,"col":3},"type":"type","sub":[],"valid":true,"message":"Error: Unbound constructor Foo"}]

Which makes sense, because I haven't actually mentioned which file I'm querying, nor does the query ( https://github.com/ocaml/merlin/blob/master/doc/dev/OLD-PROTOCOL.md#type-checking ) allow me to.

E I should mention that I'm using BuckleScript, not ocamlc, and also ocamlc -i only works if I specify not just my module but all its module dependencies; I'm looking for something that automatically manages those dependencies.

1

There are 1 answers

0
Yawar On

One way to get Merlin to output the inferred signature of a module is to feed it a sequence of commands (as described in its protocol at https://github.com/ocaml/merlin/blob/master/doc/dev/OLD-PROTOCOL.md#type-checking ) that first define the module and then ask for its signature. We can prepare a temporary file that contains this sequence of commands and give it to Merlin as standard input.

The tricky parts are: wrapping the input with the correct commands; escaping double-quote characters in the input file so they don't mix with Merlin's input format; and unwrapping the output to discard Merlin's protocol formatting. Here are the crucial commands:

it=~/tmp/it

echo '["tell","start","end","module It = struct' >$it
sed 's/"/\\"/g' ${1%i} >>$it
echo ' end let () = ()"]' >>$it
echo '["type","expression","It","at","end"]' >>$it

ocamlmerlin <$it | sed -e '/^\["return",true\]$/d' -e 's/^\["return","sig *//' -e 's/ *end"\]$//' -e 's/\\"/"/g' -e 's/\\n/\
/g' | sed -e '/^ *$/d' -e 's/^  //'

Caveats:

  • The above assumes a Unix-y system with touch and sed, and also ocamlmerlin in the command path
  • Merlin doesn't preserve OCaml attributes ([@...]) in its output
  • Works only for OCaml syntax, but can be adapted to Reason syntax

A more full-fledged script can be found at https://gist.github.com/yawaramin/b86557ae81cbd019fcb9e071abe594de .