How to debug reason-vscode and an error `Could not find local build dir`?


#1

I’m trying to configure autocomplete and etc. with VsCode. I installed reason-vscode 1.4.1 and there are some error in log

[Error - 1:06:59 AM] Request textDocument/hover failed.
  Message: Could not find local build dir
  Code: -32603 

and this is debug.log

Hello from /home/kakadu/.vscode/extensions/jaredly.reason-vscode-1.4.1/bin.native.linux
Previous log location: /tmp/lsp.log
Sending notification {"jsonrpc": "2.0", "method": "client/registerCapability", "params": {"registrations": [{"id": "watching", "method": "workspace/didChangeWatchedFiles", "registerOptions": {"watchers": [{"globPattern": "**/bsconfig.json", "globPattern": "**/.merlin"}]}}]}}
Sending response {"id": 0, "jsonrpc": "2.0", "result": {"capabilities": {"textDocumentSync": 1, "hoverProvider": true, "completionProvider": {"resolveProvider": true, "triggerCharacters": ["."]}, "signatureHelpProvider": {"triggerCharacters": ["("]}, "definitionProvider": true, "typeDefinitionProvider": true, "referencesProvider": true, "documentSymbolProvider": true, "codeActionProvider": true, "executeCommandProvider": {"commands": ["reason-language-server.add_to_interface_inner"]}, "codeLensProvider": {"resolveProvider": true}, "documentHighlightProvider": true, "documentRangeFormattingProvider": true, "documentFormattingProvider": true, "documentFormattingProvider": true, "renameProvider": true}}}
Read message 
{"jsonrpc":"2.0","method":"initialized","params":{}}
Read message 
{"jsonrpc":"2.0","method":"workspace/didChangeConfiguration","params":{"settings":{"reason_language_server":{"location":"","refmt":"","lispRefmt":"","format_width":"80","per_value_codelens":false,"dependencies_codelens":true,"opens_codelens":true,"show_module_path_on_hover":true,"reloadOnChange":false,"show_debug_errors":false,"autoRebuild":true}}}}
Read message 
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///media/oldhome/kakadu/prog/oleg/src/ExampleClient.re","languageId":"reason","version":1,"text":"/***\n * All credit goes to Cheng Lou. It was just too hard to figure out jengaboot + bucklescript for now.\n * Copy pasted from https://github.com/chenglou/reason-js\n **/\n[@bs.send] external toString : Js.t('a) => string = \"toString\";\n\nmodule Event = {\n  type eventT;\n  let isEnterKey: eventT => bool = [%bs.raw\n    {|\n    function (e) {\n      return e.which === 13;\n    }\n  |}\n  ];\n};\n\n/* Created a bunch of modules to keep things clean. This is just for demo purposes. */\nmodule Element = {\n  type elementT;\n  [@bs.set] external setInnerHTML : (elementT, string) => unit = \"innerHTML\";\n  [@bs.get] external getInnerHTML : elementT => string = \"innerHTML\";\n  [@bs.set] external setValue : (elementT, string) => unit = \"value\";\n  [@bs.get] external getValue : elementT => string = \"value\";\n  [@bs.send]\n  external addEventListener : (elementT, string, Event.eventT => unit) => unit =\n    \"addEventListener\";\n};\n\nmodule Document = {\n  [@bs.val]\n  external getElementById : string => Element.elementT =\n    \"document.getElementById\";\n  [@bs.val]\n  external addEventListener : (string, Event.eventT => unit) => unit =\n    \"document.addEventListener\";\n};\n\nmodule Window = {\n  type intervalIdT;\n  [@bs.val]\n  external setInterval : (unit => unit, int) => intervalIdT =\n    \"window.setInterval\";\n  [@bs.val]\n  external clearInterval : intervalIdT => unit = \"window.clearInterval\";\n};\n\nmodule MyClient = BsSocket.Client.Make(ExampleMessages);\n\nlet socket = MyClient.create();\n\nlet () = MyClient.emit(socket, `Hi);\n\nlet chatarea = Document.getElementById(\"chatarea\");\n\nlet prependLog(area, str) = {\n  let innerHTML = Element.getInnerHTML(area);\n  Element.setInnerHTML(area, str ++ innerHTML);\n};\n\nlet sendbutton = Document.getElementById(\"sendbutton\");\n\nlet chatinput = Document.getElementById(\"chatinput\");\n\nElement.addEventListener(sendbutton, \"click\", (_) => {\n  /* MyClient.emit(\n    socket,\n    Shared(Message(Data(Element.getValue(chatinput)))),\n  ); */\n  ()\n});\n\nDocument.addEventListener(\"keyup\", e =>\n  if (Event.isEnterKey(e)) {\n    /* MyClient.emit(\n      socket,\n      Shared(MessageOnEnter(Element.getValue(chatinput))),\n    ); */\n    Element.setValue(chatinput, \"\");\n  }\n);\n\n/* *********************************************************************** */\n[@bs.deriving abstract]\ntype scene_t = {\n  preload: unit => unit,\n  create:  unit => unit,\n};\n\n[@bs.deriving abstract]\ntype config = {\n  parent: string,\n  width:  int,\n  height: int,\n  scene:  scene_t,\n};\n\ntype image;\ntype circle = {\n  on: (string, unit => unit) => unit\n};\n\n[@bs.deriving abstract]\ntype gameObjectFactory =\n  { image:  (. int, int, string) => image\n    /* circle( [x] [, y] [, radius] [, fillColor] [, fillAlpha]) */\n  , circle: (. int, int, int, int) => circle\n  };\n\n[@bs.deriving abstract]\ntype g = {\n  scene: sceneManager\n}\n[@bs.deriving abstract]\nand sceneManager = {\n  getAt: int => scene\n}\n[@bs.deriving abstract]\nand scene = {\n  add : gameObjectFactory\n};\n\nlet string_to_color : string => int = [%bs.raw {|\nfunction(str) {\n  var hash = 0;\n  for (var i = 0; i < str.length; i++) {\n    hash = str.charCodeAt(i) + ((hash << 5) - hash);\n  }\n  return hash % (256*256*256);\n  /*var colour = '#';\n  for (var i = 0; i < 3; i++) {\n    var value = (hash >> (i * 8)) & 0xFF;\n    colour += ('00' + value.toString(16)).substr(-2);\n  }\n  return colour;*/\n}\n|}];\n\nlet default_scene: g => scene =\n  [%bs.raw {|\n    function(g) {\n      var ans = g.scene.scenes[0];\n      console.assert(ans);\n      return ans;\n    } |}];\n\n[@bs.new] external createGame : config => g = \"Phaser.Game\";\n\n\n[@bs.deriving abstract]\ntype data_manager = {\n  count: int,\n  has: string => bool,\n  get: 'r . string => 'r,\n  set: 'v . string => 'v => unit,\n};\n\nmodule Ship = {\n  [@bs.deriving abstract]\n  type t =  { setDataEnabled: (. unit) => unit\n            , mutable x     : int\n            , mutable y     : int\n            , on: (. string, unit => unit) => unit\n            , setInteractive: (. unit) => unit\n            };\n\n  let add_on_click : t => (unit => unit) => unit = sh => f => {\n    sh->onGet(. \"pointerup\", () => { f(); });\n  };\n  let create_ship : scene => t = sc => {\n    let ship : t = Obj.magic( sc->addGet->circleGet(. 100, 200, 5, 0x00ff00) );\n    ship->setInteractiveGet(.);\n    /* Js.log(ship); */\n    setDataEnabledGet(ship)(.);\n    ship->onGet(. \"pointerup\", () => { Js.log(\"clicked on ship\"); });\n    ship\n  };\n  let create_planet : (scene,ExampleMessages.planet_info) => t = (sc,pl) => {\n    let (x,y) = pl.ExampleMessages.pl_coords;\n    let ship : t = Obj.magic( sc->addGet->circleGet(. x, y, 20, string_to_color(pl.pl_title)) );\n    ship->setInteractiveGet(.);\n    /* Js.log(ship); */\n    setDataEnabledGet(ship)(.);\n    /* ship->onGet(. \"pointerup\", () => { Utils.Js.flog(\"clicked on planet %s\", pl.ExampleMessages.pl_title); }); */\n    ship\n  };\n  let data : t => data_manager = [%bs.raw {| function(s) { return s.data; } |}];\n  /* let id : g => int = _ship => {\n    let ans = [%bs.raw {| _ship.data.get(\"si_id\") |}];\n    ans;\n  }; */\n  let setXY: t => (int,int) => unit = ship => (x,y) => {\n    ship->xSet(x);\n    ship->ySet(y);\n  };\n};\n\nlet preload = () => {\n  /* let _ = [%bs.raw {| this.load.setBaseURL('http://labs.phaser.io')     |}];\n  let _ = [%bs.raw {| this.load.image('sky', 'assets/skies/space3.png') |}];\n  let _ = [%bs.raw {| this.load.image('ship', 'https://static.thenounproject.com/png/281034-200.png') |}]; */\n  ()\n};\n\nlet create = () => {\n  /* let scene1 = default_scene([%bs.raw {| this.game |}]); */\n  /* Js.log(scene1); */\n  /* let _sh1 = Ship.create_ship(scene1); */\n  ()\n};\n\nlet ship_objects: MyHashMap.t((Ship.t, ExampleMessages.ship_info)) =\n  MyHashMap.make(~hintSize=13);\n\nlet planet_objects: MyHashMap.t((Ship.t, ExampleMessages.planet_info)) =\n  MyHashMap.make(~hintSize=13);\n\nlet game = createGame(config( ~parent=\"phaser_here\", ~width=640, ~height = 480,\n                              ~scene = scene_t(~preload, ~create)\n                            ))\n;\n\nmodule type INTERACTION_TYPE = {\n  let on_all_ships : list(ExampleMessages.ship_info) => unit;\n  let on_all_planets: (list(ExampleMessages.planet_info), ExampleMessages.planet_id_t => unit) => unit;\n};\n\nmodule Interactions = {\n  let on_all_ships = xs => {\n    /* we should iterate over all ships. If some dissappeared then we remove sprite.\n      If new one appeared, then we add the one.\n    */\n    xs |> List.iter(fun | { ExampleMessages.si_id, si_coords: (x,y) } as sinfo => {\n      let ship =\n        if (MyHashMap.has(ship_objects, si_id)) {\n          let (s,_) = MyHashMap.get_exn(ship_objects, si_id);\n          s\n        } else {\n          let texture = Ship.create_ship(default_scene(game));\n          MyHashMap.set(ship_objects, si_id, (texture,sinfo));\n          texture;\n        };\n      Ship.setXY(ship)(x,y);\n    });\n  }\n\n  let on_all_planets = (ps,on_clicked) => {\n    ps |> List.iter(fun | { ExampleMessages.pl_id: id, pl_coords: (x,y) } as pl_info => {\n      let pl =\n        if (MyHashMap.has(planet_objects, id)) {\n          let (s,_) = MyHashMap.get_exn(planet_objects, id);\n          s\n        } else {\n          let texture = Ship.create_planet(default_scene(game), pl_info);\n          MyHashMap.set(planet_objects, id, (texture, pl_info));\n          Ship.add_on_click(texture, () => { on_clicked(id); })\n          texture;\n        };\n      Ship.setXY(pl)(x,y);\n    });\n  };\n}\n\n\n\nmodule SubscribeSocket = (I: INTERACTION_TYPE) => {\n  let on_planet_pressed = pl_id => {\n    Utils.Js.flog(\"planet %d clicked\", pl_id);\n    MyClient.emit(socket, `Ask_planet_info(pl_id));\n  }\n  let subscribe () =\n    MyClient.on(socket, fun\n    | `All_ships(ss)     => I.on_all_ships(ss)\n    | `All_planets(ps)   => I.on_all_planets(ps, on_planet_pressed)\n    | `PauseSimulation   => assert(false)\n    | `UnpauseSimulation => assert(false)\n    | `PingMsg => Js.log(\"ping from server\")\n    | `PongMsg => {\n        let innerHTML = Element.getInnerHTML(chatarea);\n        Element.setInnerHTML(\n          chatarea,\n          innerHTML\n          ++ \"<div><span style='color:red'>Message</span>: \"\n          ++ \"\"\n          ++ \"</div>\",\n        );\n      }\n      | `Planet_info(info) => {\n        Utils.Js.flog(\"planet %d is called `%s`\", info.pie_id, info.pie_title )\n      }\n    /* | _ => {\n        Js.log(\"unhandled case\");\n        assert(false);\n      } */\n    );\n};\n\nmodule SS = SubscribeSocket(Interactions);\nlet () = SS.subscribe();\n"}}}
Found a `.merlin` file at /media/oldhome/kakadu/prog/oleg/src
]] Making a new jbuilder package at /media/oldhome/kakadu/prog/oleg/src
Sending notification {"jsonrpc": "2.0", "method": "window/showMessage", "params": {"type": 1, "message": "Unable to find project root dir"}}
Read message 
{"jsonrpc":"2.0","id":1,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"file:///media/oldhome/kakadu/prog/oleg/src/ExampleClient.re"},"range":{"start":{"line":236,"character":7},"end":{"line":239,"character":7}},"context":{"diagnostics":[]}}}
[server] Got a method textDocument/codeAction
[server] processing took 0.00405311584473ms
Found a `.merlin` file at /media/oldhome/kakadu/prog/oleg/src
]] Making a new jbuilder package at /media/oldhome/kakadu/prog/oleg/src
Sending response {"id": 1, "jsonrpc": "2.0", "error": {"code": -32603, "message": "Unable to find project root dir"}}
Read message 
{"jsonrpc":"2.0","id":2,"method":"textDocument/codeLens","params":{"textDocument":{"uri":"file:///media/oldhome/kakadu/prog/oleg/src/ExampleClient.re"}}}
[server] Got a method textDocument/codeLens
[server] processing took 0.00190734863281ms
Found a `.merlin` file at /media/oldhome/kakadu/prog/oleg/src
]] Making a new jbuilder package at /media/oldhome/kakadu/prog/oleg/src
Sending response {"id": 2, "jsonrpc": "2.0", "result": [{"range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 0}}, "command": {"title": "Unable to load compilation data: Unable to find project root dir", "command": ""}}]}
Found a `.merlin` file at /media/oldhome/kakadu/prog/oleg/src
]] Making a new jbuilder package at /media/oldhome/kakadu/prog/oleg/src

Do I need to configure .merlin files somehow ? At the moment I have

➜  oleg git:(master) ✗ cat src/.merlin 
B /media/oldhome/kakadu/prog/oleg/lib/bs
FLG -open ReactTemplate
FLG -ppx '/home/kakadu/.nvm/versions/node/v10.2.1/lib/node_modules/bs-platform/lib/reactjs_jsx_ppx_2.exe'
FLG -ppx /home/kakadu/.nvm/versions/node/v10.2.1/lib/node_modules/bs-platform/lib/bsppx.exe
S /media/oldhome/kakadu/prog/oleg/node_modules/bs-platform/lib/ocaml
B /media/oldhome/kakadu/prog/oleg/node_modules/bs-platform/lib/ocaml
FLG -nostdlib -color always
FLG -w -30-40+6+7+27+32..39+44+45+101
S /media/oldhome/kakadu/prog/oleg/node_modules/bs-socket/lib/ocaml
B /media/oldhome/kakadu/prog/oleg/node_modules/bs-socket/lib/ocaml
S /media/oldhome/kakadu/prog/oleg/node_modules/reason-react/lib/ocaml
B /media/oldhome/kakadu/prog/oleg/node_modules/reason-react/lib/ocaml
S .
B ../build
B /media/oldhome/kakadu/prog/oleg/lib/bs/src
B ../lib/bs/src

I heard some rumors that I should somehow make a dune project in my source tree… Should I? I don’t target native code, only nodeJS server + client it it does matter.


#2

(as discussed on discord, the issue ended up being a stray .merlin file in the src directory. after that was removed, everything worked)