关于ocaml:使用Merlin打印文件的模块签名

Print module signature of a file using Merlin

使用Merlin 2.5.4,在我的项目中打印OCaml文件签名的正确方法是什么?例如,假设我有:

1
2
(* foo.ml *)
let x = 1

我想得到:

1
val x : int

什么是正确的命令(或命令序列)?

我尝试过的事情:

我将文件临时package在一个子模块:module Foo = struct let x = 1 end中,然后运行:

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

但是我得到:

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

这很有意义,因为我实际上没有提到我要查询的文件,查询也没有(https://github.com/ocaml/merlin/blob/master/doc/dev/OLD-PROTOCOL。 md#type-checking)请允许我

E我应该提到我正在使用BuckleScript,而不是ocamlc,并且ocamlc -i仅在我不仅指定我的模块而且指定其所有模块依赖项时都有效;我正在寻找可以自动管理这些依赖项的东西。


让Merlin输出模块的推断签名的一种方法是向其提供一系列命令(如https://github.com/ocaml/merlin/blob/master/doc/dev上的协议中所述) /OLD-PROTOCOL.md#type-checking),它首先定义了模块,然后要求其签名。我们可以准备一个包含此命令序列的临时文件,并将其提供给Merlin作为标准输入。

棘手的部分是:用正确的命令package输入;在输入文件中转义双引号字符,以免它们与Merlin的输入格式混合使用;并解开输出以放弃Merlin的协议格式。以下是关键命令:

1
2
3
4
5
6
7
8
9
10
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/\\\
/\\
/g' | sed -e '/^ *$/d' -e 's/^  //'

注意事项:

  • 以上假设在Unix-y系统中,其touchsed以及命令路径中的ocamlmerlin
  • Merlin在其输出中不保留OCaml属性([@...])
  • 仅适用于OCaml语法,但可以适应Reason语法

更完整的脚本可以在https://gist.github.com/yawaramin/b86557ae81cbd019fcb9e071abe594de中找到。