From 8e9f0fbb2a1af6e016fcef69aa80fe53803a6e85 Mon Sep 17 00:00:00 2001 From: Cheng Lou Date: Wed, 7 Apr 2021 02:54:50 -0700 Subject: [PATCH 1/2] Convert everything over to unmonad (#91) * Convert Hover to unmonad * Convert MessengerHandlers to unmonad * Convert NotificationHandlers to unmonad * Convert Packages to unmonad * Convert Process_406 to unmonad * Convert ProcessExtra to unmonad * Convert Protocol to unmonad * Convert NewCompletions to unmonad * Convert Query to unmonad * Convert References to unmonad * Convert RescriptEditorSupport.re to unmonad * Convert State over to unmonad --- src/rescript-editor-support/Hover.re | 118 ++-- .../MessageHandlers.re | 667 ++++++++++-------- src/rescript-editor-support/NewCompletions.re | 111 +-- .../NotificationHandlers.re | 112 +-- src/rescript-editor-support/Packages.re | 250 ++++--- src/rescript-editor-support/ProcessExtra.re | 76 +- src/rescript-editor-support/Process_406.re | 23 +- src/rescript-editor-support/Protocol.re | 30 +- src/rescript-editor-support/Query.re | 143 ++-- src/rescript-editor-support/References.re | 618 ++++++++++------ .../RescriptEditorSupport.re | 73 +- src/rescript-editor-support/State.re | 71 +- 12 files changed, 1359 insertions(+), 933 deletions(-) diff --git a/src/rescript-editor-support/Hover.re b/src/rescript-editor-support/Hover.re index baec517d..075d8ec3 100644 --- a/src/rescript-editor-support/Hover.re +++ b/src/rescript-editor-support/Hover.re @@ -2,12 +2,19 @@ let digConstructor = (~env, ~getModule, path) => { switch (Query.resolveFromCompilerPath(~env, ~getModule, path)) { | `Not_found => None | `Stamp(stamp) => - let%opt t = Hashtbl.find_opt(env.file.stamps.types, stamp); - Some((env, t)); + switch (Hashtbl.find_opt(env.file.stamps.types, stamp)) { + | None => None + | Some(t) => Some((env, t)) + } | `Exported(env, name) => - let%opt stamp = Hashtbl.find_opt(env.exported.types, name); - let%opt t = Hashtbl.find_opt(env.file.stamps.types, stamp); - Some((env, t)); + switch (Hashtbl.find_opt(env.exported.types, name)) { + | None => None + | Some(stamp) => + switch (Hashtbl.find_opt(env.file.stamps.types, stamp)) { + | None => None + | Some(t) => Some((env, t)) + } + } | _ => None }; }; @@ -67,38 +74,60 @@ let newHover = (~file: SharedTypes.file, ~getModule, loc) => { Some(codeBlock(typeDef)); | LModule(Definition(stamp, _tip)) | LModule(LocalReference(stamp, _tip)) => - let%opt md = Hashtbl.find_opt(file.stamps.modules, stamp); - let%opt (file, declared) = - References.resolveModuleReference(~file, ~getModule, md); - let (name, docstring) = - switch (declared) { - | Some(d) => (d.name.txt, d.docstring) - | None => (file.moduleName, file.contents.docstring) - }; - showModule(~docstring, ~name, ~file, declared); + switch (Hashtbl.find_opt(file.stamps.modules, stamp)) { + | None => None + | Some(md) => + switch (References.resolveModuleReference(~file, ~getModule, md)) { + | None => None + | Some((file, declared)) => + let (name, docstring) = + switch (declared) { + | Some(d) => (d.name.txt, d.docstring) + | None => (file.moduleName, file.contents.docstring) + }; + showModule(~docstring, ~name, ~file, declared); + } + } | LModule(GlobalReference(moduleName, path, tip)) => - let%opt file = getModule(moduleName); - let env = Query.fileEnv(file); - let%opt (env, name) = Query.resolvePath(~env, ~path, ~getModule); - let%opt stamp = Query.exportedForTip(~env, name, tip); - let%opt md = Hashtbl.find_opt(file.stamps.modules, stamp); - let%opt (file, declared) = - References.resolveModuleReference(~file, ~getModule, md); - let (name, docstring) = - switch (declared) { - | Some(d) => (d.name.txt, d.docstring) - | None => (file.moduleName, file.contents.docstring) + switch (getModule(moduleName)) { + | None => None + | Some(file) => + let env = Query.fileEnv(file); + switch (Query.resolvePath(~env, ~path, ~getModule)) { + | None => None + | Some((env, name)) => + switch (Query.exportedForTip(~env, name, tip)) { + | None => None + | Some(stamp) => + switch (Hashtbl.find_opt(file.stamps.modules, stamp)) { + | None => None + | Some(md) => + switch (References.resolveModuleReference(~file, ~getModule, md)) { + | None => None + | Some((file, declared)) => + let (name, docstring) = + switch (declared) { + | Some(d) => (d.name.txt, d.docstring) + | None => (file.moduleName, file.contents.docstring) + }; + showModule(~docstring, ~name, ~file, declared); + } + } + } }; - showModule(~docstring, ~name, ~file, declared); + } | LModule(NotFound) => None | TopLevelModule(name) => - let%opt file = getModule(name); - showModule( - ~docstring=file.contents.docstring, - ~name=file.moduleName, - ~file, - None, - ); + switch (getModule(name)) { + | None => None + | Some(file) => + showModule( + ~docstring=file.contents.docstring, + ~name=file.moduleName, + ~file, + None, + ) + } | Typed(_, Definition(_, Field(_) | Constructor(_))) => None | Constant(t) => Some( @@ -117,15 +146,20 @@ let newHover = (~file: SharedTypes.file, ~getModule, loc) => { let typeString = codeBlock(typ |> Shared.typeToString); let extraTypeInfo = { let env = Query.fileEnv(file); - let%opt path = typ |> Shared.digConstructor; - let%opt (_env, {docstring, name: {txt}, item: {decl}}) = - digConstructor(~env, ~getModule, path); - let isUncurriedInternal = - Utils.startsWith(Path.name(path), "Js.Fn.arity"); - if (isUncurriedInternal) { - None; - } else { - Some((decl |> Shared.declToString(txt), docstring)); + switch (typ |> Shared.digConstructor) { + | None => None + | Some(path) => + switch (digConstructor(~env, ~getModule, path)) { + | None => None + | Some((_env, {docstring, name: {txt}, item: {decl}})) => + let isUncurriedInternal = + Utils.startsWith(Path.name(path), "Js.Fn.arity"); + if (isUncurriedInternal) { + None; + } else { + Some((decl |> Shared.declToString(txt), docstring)); + }; + } }; }; let (typeString, docstring) = diff --git a/src/rescript-editor-support/MessageHandlers.re b/src/rescript-editor-support/MessageHandlers.re index 0c135c4c..dd4029a8 100644 --- a/src/rescript-editor-support/MessageHandlers.re +++ b/src/rescript-editor-support/MessageHandlers.re @@ -8,348 +8,427 @@ let handlers: ( "textDocument/definition", (state, params) => { - let%try (uri, pos) = Protocol.rPositionParams(params); - let%try (package, {file, extra}) = State.getFullFromCmt(~state, ~uri); - - let position = Utils.cmtLocFromVscode(pos); - - { - let%opt (uri, loc) = - References.definitionForPos( - ~pathsForModule=package.pathsForModule, - ~file, - ~extra, - ~getUri=State.fileForUri(state), - ~getModule=State.fileForModule(state, ~package), - position, - ); - Some( - Ok(( - state, - Json.Object([ - ("uri", Json.String(Uri2.toString(uri))), - ("range", Protocol.rangeOfLoc(loc)), - ]), - )), - ); + switch (Protocol.rPositionParams(params)) { + | Error(e) => Error(e) + | Ok((uri, pos)) => + switch (State.getFullFromCmt(~state, ~uri)) { + | Error(e) => Error(e) + | Ok((package, {file, extra})) => + let position = Utils.cmtLocFromVscode(pos); + ( + switch ( + References.definitionForPos( + ~pathsForModule=package.pathsForModule, + ~file, + ~extra, + ~getUri=State.fileForUri(state), + ~getModule=State.fileForModule(state, ~package), + position, + ) + ) { + | None => None + | Some((uri, loc)) => + Some( + Ok(( + state, + Json.Object([ + ("uri", Json.String(Uri2.toString(uri))), + ("range", Protocol.rangeOfLoc(loc)), + ]), + )), + ); + } + ) + |? Ok((state, Json.Null)); + } } - |? Ok((state, Json.Null)); - }, + } ), ( "textDocument/completion", (state, params) => { - let%try (uri, pos) = Protocol.rPositionParams(params); - let maybeText = - switch (Hashtbl.find_opt(state.documentText, uri)) { - | Some(text) => Some(text) - | None => None + switch (Protocol.rPositionParams(params)) { + | Error(e) => Error(e) + | Ok((uri, pos)) => + let maybeText = + switch (Hashtbl.find_opt(state.documentText, uri)) { + | Some(text) => Some(text) + | None => None + }; + switch (State.getFullFromCmt(~state, ~uri)) { + | Error(e) => Error(e) + | Ok((package, full)) => + let completions = + NewCompletions.computeCompletions( + ~full, + ~maybeText, + ~package, + ~pos, + ~state, + ); + Ok((state, completions)); }; - let%try (package, full) = State.getFullFromCmt(~state, ~uri); - let completions = - NewCompletions.computeCompletions( - ~full, - ~maybeText, - ~package, - ~pos, - ~state, - ); - Ok((state, completions)); - }, + } + } ), ( "textDocument/documentHighlight", (state, params) => { - let%try (uri, pos) = Protocol.rPositionParams(params); - - let pos = Utils.cmtLocFromVscode(pos); - let refs = - switch (State.fileForUri(state, uri) |> toOptionAndLog) { - | None => None - | Some((file, extra)) => References.refsForPos(~file, ~extra, pos) - }; - Ok(( - state, - switch (refs) { - | None => J.null - | Some(refs) => - J.l( - refs - |> List.map(loc => - J.o([ - ("range", Protocol.rangeOfLoc(loc)), - ("kind", J.i(2)), - ]) - ), - ) - }, - )); - }, + switch (Protocol.rPositionParams(params)) { + | Error(e) => Error(e) + | Ok((uri, pos)) => + let pos = Utils.cmtLocFromVscode(pos); + let refs = + switch (State.fileForUri(state, uri) |> toOptionAndLog) { + | None => None + | Some((file, extra)) => References.refsForPos(~file, ~extra, pos) + }; + Ok(( + state, + switch (refs) { + | None => J.null + | Some(refs) => + J.l( + refs + |> List.map(loc => + J.o([ + ("range", Protocol.rangeOfLoc(loc)), + ("kind", J.i(2)), + ]) + ), + ) + }, + )); + } + } ), ( "textDocument/references", (state, params) => { - let%try (uri, pos) = Protocol.rPositionParams(params); - let%try package = Packages.getPackage(uri, state); - let%try_wrap (file, extra) = State.fileForUri(state, uri); - Infix.( - { - let%opt (_, loc) = - References.locForPos(~extra, Utils.cmtLocFromVscode(pos)); - let%opt allReferences = - References.allReferencesForLoc( - ~pathsForModule=package.pathsForModule, - ~file, - ~extra, - ~allModules=package.localModules, - ~getUri=State.fileForUri(state), - ~getModule=State.fileForModule(state, ~package), - ~getExtra=State.extraForModule(state, ~package), - loc, + switch (Protocol.rPositionParams(params)) { + | Error(e) => Error(e) + | Ok((uri, pos)) => + switch (Packages.getPackage(uri, state)) { + | Error(e) => Error(e) + | Ok(package) => + switch (State.fileForUri(state, uri)) { + | Error(e) => Error(e) + | Ok((file, extra)) => + Ok( + Infix.( + ( + switch ( + References.locForPos(~extra, Utils.cmtLocFromVscode(pos)) + ) { + | None => None + | Some((_, loc)) => + switch ( + References.allReferencesForLoc( + ~pathsForModule=package.pathsForModule, + ~file, + ~extra, + ~allModules=package.localModules, + ~getUri=State.fileForUri(state), + ~getModule=State.fileForModule(state, ~package), + ~getExtra=State.extraForModule(state, ~package), + loc, + ) + |> toOptionAndLog + ) { + | None => None + | Some(allReferences) => + Some(( + state, + J.l( + allReferences + |> List.map(((fname, references)) => { + let locs = + fname == uri + ? List.filter( + loc => !Protocol.locationContains(loc, pos), + references, + ) + : references; + locs + |> List.map(loc => Protocol.locationOfLoc(~fname, loc)); + }) + |> List.concat, + ), + )); + } + } + ) + |? (state, J.null) + ), ) - |> toOptionAndLog; - Some(( - state, - J.l( - allReferences - |> List.map(((fname, references)) => { - let locs = - fname == uri - ? List.filter( - loc => !Protocol.locationContains(loc, pos), - references, - ) - : references; - locs - |> List.map(loc => Protocol.locationOfLoc(~fname, loc)); - }) - |> List.concat, - ), - )); + } } - |? (state, J.null) - ); - }, + } + } ), ( "textDocument/rename", (state, params) => { - let%try (uri, pos) = Protocol.rPositionParams(params); - let%try package = Packages.getPackage(uri, state); - let%try (file, extra) = State.fileForUri(state, uri); - let%try newName = RJson.get("newName", params); - Infix.( - { - let%opt (_, loc) = - References.locForPos(~extra, Utils.cmtLocFromVscode(pos)); - let%opt allReferences = - References.allReferencesForLoc( - ~file, - ~extra, - ~pathsForModule=package.pathsForModule, - ~allModules=package.localModules, - ~getModule=State.fileForModule(state, ~package), - ~getUri=State.fileForUri(state), - ~getExtra=State.extraForModule(state, ~package), - loc, - ) - |> toOptionAndLog; - Some( - Ok(( - state, - J.o([ - ( - "changes", - J.o( - allReferences - |> List.map(((fname, references)) => - ( - fname |> Uri2.toString, - J.l( - references - |> List.map(loc => - J.o([ - ("range", Protocol.rangeOfLoc(loc)), - ("newText", newName), - ]) - ), - ), - ) - ), - ), - ), - ]), - )), - ); + switch (Protocol.rPositionParams(params)) { + | Error(e) => Error(e) + | Ok((uri, pos)) => + switch (Packages.getPackage(uri, state)) { + | Error(e) => Error(e) + | Ok(package) => + switch (State.fileForUri(state, uri)) { + | Error(e) => Error(e) + | Ok((file, extra)) => + switch (RJson.get("newName", params)) { + | Error(e) => Error(e) + | Ok(newName) => + open Infix; + ( + switch ( + References.locForPos(~extra, Utils.cmtLocFromVscode(pos)) + ) { + | None => None + | Some((_, loc)) => + switch ( + References.allReferencesForLoc( + ~file, + ~extra, + ~pathsForModule=package.pathsForModule, + ~allModules=package.localModules, + ~getModule=State.fileForModule(state, ~package), + ~getUri=State.fileForUri(state), + ~getExtra=State.extraForModule(state, ~package), + loc, + ) + |> toOptionAndLog + ) { + | None => None + | Some(allReferences) => + Some( + Ok(( + state, + J.o([ + ( + "changes", + J.o( + allReferences + |> List.map(((fname, references)) => + ( + fname |> Uri2.toString, + J.l( + references + |> List.map(loc => + J.o([ + ( "range", Protocol.rangeOfLoc(loc)), + ("newText", newName), + ]) + ), + ), + ) + ), + ), + ), + ]), + ), + )) + } + } + ) + |? Ok((state, J.null)) + } + } } - |? Ok((state, J.null)) - ); - }, + } + } ), ( "textDocument/codeLens", (state, params) => { open InfixResult; - let%try uri = + switch ( params |> RJson.get("textDocument") |?> RJson.get("uri") - |?> RJson.string; - let%try uri = Uri2.parse(uri) |> RResult.orError("Not a uri"); - - /* Log.log("<< codleens me please"); */ - - let topLoc = { - Location.loc_start: { - Lexing.pos_fname: "", - pos_lnum: 1, - pos_bol: 0, - pos_cnum: 0, - }, - Location.loc_end: { - Lexing.pos_fname: "", - pos_lnum: 1, - pos_bol: 0, - pos_cnum: 0, - }, - loc_ghost: false, - }; - - let getLensItems = ({SharedTypes.file, extra}) => { - /* getTypeLensTopLevel gives the list of per-value type codeLens - for every value in a module topLevel */ - let rec getTypeLensTopLevel = topLevel => { - switch (topLevel) { - | [] => [] - | [{SharedTypes.name: {loc}, item}, ...tlp] => - let currentCl = - switch (item) { - | SharedTypes.MValue(typ) => [ - (typ |> Shared.typeToString, loc), - ] - | Module(Structure({topLevel})) => - getTypeLensTopLevel(topLevel) - | _ => [] + |?> RJson.string + ) { + | Error(e) => Error(e) + | Ok(uri) => + switch (Uri2.parse(uri) |> RResult.orError("Not a uri")) { + | Error(e) => Error(e) + | Ok(uri) => + /* Log.log("<< codleens me please"); */ + let topLoc = { + Location.loc_start: { + Lexing.pos_fname: "", + pos_lnum: 1, + pos_bol: 0, + pos_cnum: 0, + }, + Location.loc_end: { + Lexing.pos_fname: "", + pos_lnum: 1, + pos_bol: 0, + pos_cnum: 0, + }, + loc_ghost: false, + }; + let getLensItems = ({SharedTypes.file, extra}) => { + /* getTypeLensTopLevel gives the list of per-value type codeLens + for every value in a module topLevel */ + let rec getTypeLensTopLevel = topLevel => { + switch (topLevel) { + | [] => [] + | [{SharedTypes.name: {loc}, item}, ...tlp] => + let currentCl = + switch (item) { + | SharedTypes.MValue(typ) => [ + (typ |> Shared.typeToString, loc), + ] + | Module(Structure({topLevel})) => + getTypeLensTopLevel(topLevel) + | _ => [] + }; + List.append(currentCl, getTypeLensTopLevel(tlp)); }; - List.append(currentCl, getTypeLensTopLevel(tlp)); + }; + let lenses = file.contents.topLevel |> getTypeLensTopLevel; + let lenses = lenses @ CodeLens.forOpens(extra); + let depsList = + List.map(fst, SharedTypes.hashList(extra.externalReferences)); + let depsString = + depsList == [] ? "[none]" : String.concat(", ", depsList); + let lenses = [("Dependencies: " ++ depsString, topLoc), ...lenses]; + lenses; }; - }; - let lenses = file.contents.topLevel |> getTypeLensTopLevel; - let lenses = lenses @ CodeLens.forOpens(extra); - - let depsList = - List.map(fst, SharedTypes.hashList(extra.externalReferences)); - let depsString = - depsList == [] ? "[none]" : String.concat(", ", depsList); - let lenses = [("Dependencies: " ++ depsString, topLoc), ...lenses]; - - lenses; - }; + let items = + switch (State.getFullFromCmt(~state, ~uri)) { + | Error(message) => [(message, topLoc)] + | Ok((_package, full)) => getLensItems(full) + }; + Ok(( + state, + J.l( + items + |> List.map(((text, loc)) => + J.o([ + ("range", Protocol.rangeOfLoc(loc)), + ( + "command", + J.o([("title", J.s(text)), ("command", J.s(""))]), + ), + ]) + ), + ), + )); + } + } - let items = { - switch (State.getFullFromCmt(~state, ~uri)) { - | Error(message) => [(message, topLoc)] - | Ok((_package, full)) => getLensItems(full) - }; - }; - Ok(( - state, - J.l( - items - |> List.map(((text, loc)) => - J.o([ - ("range", Protocol.rangeOfLoc(loc)), - ( - "command", - J.o([("title", J.s(text)), ("command", J.s(""))]), - ), - ]) - ), - ), - )); - }, + } ), ( "textDocument/hover", (state, params) => { - let%try (uri, pos) = Protocol.rPositionParams(params); - let%try package = Packages.getPackage(uri, state); - let%try (file, extra) = State.fileForUri(state, uri); - - { - let pos = Utils.cmtLocFromVscode(pos); - let%opt (location, loc) = References.locForPos(~extra, pos); - let%opt text = - Hover.newHover( - ~file, - ~getModule=State.fileForModule(state, ~package), - loc, - ); - Some( - Ok(( - state, - J.o([ - ("range", Protocol.rangeOfLoc(location)), - ("contents", text |> Protocol.contentKind), - ]), - )), - ); + switch (Protocol.rPositionParams(params)) { + | Error(e) => Error(e) + | Ok((uri, pos)) => + switch (Packages.getPackage(uri, state)) { + | Error(e) => Error(e) + | Ok(package) => + switch (State.fileForUri(state, uri)) { + | Error(e) => Error(e) + | Ok((file, extra)) => + { + let pos = Utils.cmtLocFromVscode(pos); + switch (References.locForPos(~extra, pos)) { + | None => None + | Some((location, loc)) => + switch ( + Hover.newHover( + ~file, + ~getModule=State.fileForModule(state, ~package), + loc, + ) + ) { + | None => None + | Some(text) => + Some( + Ok(( + state, + J.o([ + ("range", Protocol.rangeOfLoc(location)), + ("contents", text |> Protocol.contentKind), + ]), + ), + )) + } + }; + } + |? Ok((state, J.null)) + } + } } - |? Ok((state, J.null)); - }, + } ), ( "textDocument/documentSymbol", (state, params) => { open InfixResult; - let%try uri = + switch ( params |> RJson.get("textDocument") |?> RJson.get("uri") - |?> RJson.string; - let%try uri = Uri2.parse(uri) |> RResult.orError("Not a uri"); + |?> RJson.string + ) { + | Error(e) => Error(e) + | Ok(uri) => + switch (Uri2.parse(uri) |> RResult.orError("Not a uri")) { + | Error(e) => Error(e) + | Ok(uri) => + switch (State.fileForUri(state, uri)) { + | Error(e) => Error(e) + | Ok((file, _extra)) => + open SharedTypes; - let%try (file, _extra) = State.fileForUri(state, uri); - open SharedTypes; - - let rec getItems = ({topLevel}) => { - let fn = ({name: {txt}, extentLoc, item}) => { - let (item, siblings) = - switch (item) { - | MValue(v) => (v |> Shared.variableKind, []) - | MType(t, _) => (t.decl |> Shared.declarationKind, []) - | Module(Structure(contents)) => (Module, getItems(contents)) - | Module(Ident(_)) => (Module, []) + let rec getItems = ({topLevel}) => { + let fn = ({name: {txt}, extentLoc, item}) => { + let (item, siblings) = + switch (item) { + | MValue(v) => (v |> Shared.variableKind, []) + | MType(t, _) => (t.decl |> Shared.declarationKind, []) + | Module(Structure(contents)) => (Module, getItems(contents)) + | Module(Ident(_)) => (Module, []) + }; + if (extentLoc.loc_ghost) { + siblings; + } else { + [(txt, extentLoc, item), ...siblings]; + }; + }; + let x = topLevel |> List.map(fn) |> List.concat; + x; }; - if (extentLoc.loc_ghost) { - siblings; - } else { - [(txt, extentLoc, item), ...siblings]; - }; - }; - let x = topLevel |> List.map(fn) |> List.concat; - x; - }; - getItems(file.contents) - |> ( - items => { - Ok(( - state, - J.l( - items - |> List.map(((name, loc, typ)) => - J.o([ - ("name", J.s(name)), - ("kind", J.i(Protocol.symbolKind(typ))), - ("location", Protocol.locationOfLoc(loc)), - /* ("containerName", s(String.concat(".", path))) */ - ]) - ), - ), - )); + getItems(file.contents) + |> ( + items => { + Ok(( + state, + J.l( + items + |> List.map(((name, loc, typ)) => + J.o([ + ("name", J.s(name)), + ("kind", J.i(Protocol.symbolKind(typ))), + ("location", Protocol.locationOfLoc(loc)), + /* ("containerName", s(String.concat(".", path))) */ + ]) + ), + ), + )); + } + ); + } } - ); - }, + } + } ), ]; diff --git a/src/rescript-editor-support/NewCompletions.re b/src/rescript-editor-support/NewCompletions.re index db0d1055..87c30783 100644 --- a/src/rescript-editor-support/NewCompletions.re +++ b/src/rescript-editor-support/NewCompletions.re @@ -220,11 +220,14 @@ let getEnvWithOpens = | Tip(_) => None | Nested(top, path) => Log.log("Getting module " ++ top); - let%opt file = getModule(top); - Log.log("got it"); - let env = Query.fileEnv(file); - Query.resolvePath(~env, ~getModule, ~path) - |> Infix.logIfAbsent("Unable to resolve the path"); + switch (getModule(top)) { + | None => None + | Some(file) => + Log.log("got it"); + let env = Query.fileEnv(file); + Query.resolvePath(~env, ~getModule, ~path) + |> Infix.logIfAbsent("Unable to resolve the path"); + }; } }; loop(opens); @@ -519,44 +522,66 @@ let getItems = | [] => None | [first, ...rest] => Log.log("-------------- Looking for " ++ first); - let%opt declared = - Query.findInScope(pos, first, env.file.stamps.values); - Log.log("Found it! " ++ declared.name.txt); - let%opt path = declared.item |> Shared.digConstructor; - let%opt (env, typ) = Hover.digConstructor(~env, ~getModule, path); - let%opt (env, typ) = - rest - |> List.fold_left( - (current, name) => { - let%opt (env, typ) = current; - switch (typ.item.SharedTypes.Type.kind) { - | Record(fields) => - let%opt attr = - fields |> List.find_opt(f => f.fname.txt == name); - Log.log("Found attr " ++ name); - let%opt path = attr.typ |> Shared.digConstructor; - Hover.digConstructor(~env, ~getModule, path); - | _ => None - }; - }, - Some((env, typ)), - ); - switch (typ.item.kind) { - | Record(fields) => - Some( - fields - |> Utils.filterMap(f => - if (Utils.startsWith(f.fname.txt, suffix)) { - Some(( - env.file.uri, - {...emptyDeclared(f.fname.txt), item: Field(f, typ)}, - )); - } else { - None; - } - ), - ) - | _ => None + switch (Query.findInScope(pos, first, env.file.stamps.values)) { + | None => None + | Some(declared) => + Log.log("Found it! " ++ declared.name.txt); + switch (declared.item |> Shared.digConstructor) { + | None => None + | Some(path) => + switch (Hover.digConstructor(~env, ~getModule, path)) { + | None => None + | Some((env, typ)) => + switch ( + rest + |> List.fold_left( + (current, name) => + switch (current) { + | None => None + | Some((env, typ)) => + switch (typ.item.SharedTypes.Type.kind) { + | Record(fields) => + switch ( + fields + |> List.find_opt(f => f.fname.txt == name) + ) { + | None => None + | Some(attr) => + Log.log("Found attr " ++ name); + switch (attr.typ |> Shared.digConstructor) { + | None => None + | Some(path) => + Hover.digConstructor(~env, ~getModule, path) + }; + } + | _ => None + } + }, + Some((env, typ)), + ) + ) { + | None => None + | Some((env, typ)) => + switch (typ.item.kind) { + | Record(fields) => + Some( + fields + |> Utils.filterMap(f => + if (Utils.startsWith(f.fname.txt, suffix)) { + Some(( + env.file.uri, + {...emptyDeclared(f.fname.txt), item: Field(f, typ)}, + )); + } else { + None; + } + ), + ) + | _ => None + } + } + } + }; }; }; } diff --git a/src/rescript-editor-support/NotificationHandlers.re b/src/rescript-editor-support/NotificationHandlers.re index 7599b405..56be5515 100644 --- a/src/rescript-editor-support/NotificationHandlers.re +++ b/src/rescript-editor-support/NotificationHandlers.re @@ -3,48 +3,58 @@ open RResult; open TopTypes; module J = JsonShort; -let getTextDocument = doc => { - let%opt uri = Json.get("uri", doc) |?> Json.string |?> Uri2.parse; - let%opt text = Json.get("text", doc) |?> Json.string; - Some((uri, text)); -}; +let getTextDocument = doc => + switch (Json.get("uri", doc) |?> Json.string |?> Uri2.parse) { + | None => None + | Some(uri) => + switch (Json.get("text", doc) |?> Json.string) { + | None => None + | Some(text) => Some((uri, text)) + } + }; let notificationHandlers: list((string, (state, Json.t) => result(state, string))) = [ ( "textDocument/didOpen", (state, params) => { - let%try (uri, text) = + switch ( Json.get("textDocument", params) |?> getTextDocument - |> RResult.orError("Invalid params"); - Hashtbl.replace(state.documentText, uri, text); - - let path = Uri2.toPath(uri); - if (FindFiles.isSourceFile(path)) { - let%try package = Packages.getPackage(uri, state); - /* let name = FindFiles.getName(path); */ - if (!Hashtbl.mem(package.nameForPath, path)) { - /* TODO: figure out what the name should be, and process it. */ - package.nameForPath - |> Hashtbl.iter((name, _) => Log.log(" > " ++ name)); - Log.log("Reloading because you created a new file: " ++ path); - Ok(state); - /* Ok(reloadAllState(state)) */ - /* Hashtbl.add(package.nameForPath, path, name); - Hashtbl.add(package.pathsForModule, name, Impl(path, Some(path))); - Hashtbl.replace(state.packagesByRoot, package.basePath, { - ...package, - localModules: [name, ...package.localModules] - }); - Ok(state) */ + |> RResult.orError("Invalid params") + ) { + | Error(e) => Error(e) + | Ok((uri, text)) => + Hashtbl.replace(state.documentText, uri, text); + let path = Uri2.toPath(uri); + if (FindFiles.isSourceFile(path)) { + switch (Packages.getPackage(uri, state)) { + | Error(e) => Error(e) + | Ok(package) => + /* let name = FindFiles.getName(path); */ + if (!Hashtbl.mem(package.nameForPath, path)) { + /* TODO: figure out what the name should be, and process it. */ + package.nameForPath + |> Hashtbl.iter((name, _) => Log.log(" > " ++ name)); + Log.log("Reloading because you created a new file: " ++ path); + Ok(state); + /* Ok(reloadAllState(state)) */ + /* Hashtbl.add(package.nameForPath, path, name); + Hashtbl.add(package.pathsForModule, name, Impl(path, Some(path))); + Hashtbl.replace(state.packagesByRoot, package.basePath, { + ...package, + localModules: [name, ...package.localModules] + }); + Ok(state) */ + } else { + Ok(state); + } + }; } else { Ok(state); }; - } else { - Ok(state); - }; - }, + } + } ), ( "workspace/didChangeConfiguration", @@ -62,18 +72,34 @@ let notificationHandlers: "textDocument/didChange", (state, params) => { open InfixResult; - let%try doc = params |> RJson.get("textDocument"); - let%try uri = RJson.get("uri", doc) |?> RJson.string; - let%try uri = Uri2.parse(uri) |> RResult.orError("Not a uri"); - let%try changes = RJson.get("contentChanges", params) |?> RJson.array; - let%try text = - List.nth(changes, List.length(changes) - 1) - |> RJson.get("text") - |?> RJson.string; - /* Hmm how do I know if it's modified? */ - let state = State.updateContents(uri, text, state); - Ok(state); - }, + switch (params |> RJson.get("textDocument")) { + | Error(e) => Error(e) + | Ok(doc) => + switch (RJson.get("uri", doc) |?> RJson.string) { + | Error(e) => Error(e) + | Ok(uri) => + switch (Uri2.parse(uri) |> RResult.orError("Not a uri")) { + | Error(e) => Error(e) + | Ok(uri) => + switch (RJson.get("contentChanges", params) |?> RJson.array) { + | Error(e) => Error(e) + | Ok(changes) => + switch ( + List.nth(changes, List.length(changes) - 1) + |> RJson.get("text") + |?> RJson.string + ) { + | Error(e) => Error(e) + | Ok(text) => + /* Hmm how do I know if it's modified? */ + let state = State.updateContents(uri, text, state); + Ok(state); + } + } + } + } + } + } ), ( "workspace/didChangeWatchedFiles", diff --git a/src/rescript-editor-support/Packages.re b/src/rescript-editor-support/Packages.re index 16f1d6c7..dd6aff32 100644 --- a/src/rescript-editor-support/Packages.re +++ b/src/rescript-editor-support/Packages.re @@ -50,104 +50,115 @@ let makePathsForModule = (pathsForModule, nameForPath); }; -let newBsPackage = rootPath => { - let%try raw = Files.readFileResult(rootPath /+ "bsconfig.json"); - let config = Json.parse(raw); - - Log.log({|📣 📣 NEW BSB PACKAGE 📣 📣|}); - /* failwith("Wat"); */ - Log.log("- location: " ++ rootPath); - - let compiledBase = BuildSystem.getCompiledBase(rootPath); - let%try (dependencyDirectories, dependencyModules) = - FindFiles.findDependencyFiles(~debug=true, rootPath, config); - let%try_wrap compiledBase = - compiledBase - |> RResult.orError( - "You need to run bsb first so that reason-language-server can access the compiled artifacts.\nOnce you've run bsb, restart the language server.", - ); - - let namespace = FindFiles.getNamespace(config); - let localSourceDirs = - FindFiles.getSourceDirectories(~includeDev=true, rootPath, config); - Log.log( - "Got source directories " ++ String.concat(" - ", localSourceDirs), - ); - let localModules = - FindFiles.findProjectFiles( - ~debug=true, - namespace, - rootPath, - localSourceDirs, - compiledBase, - ); - /* |> List.map(((name, paths)) => (switch (namespace) { - | None => name - | Some(n) => name ++ "-" ++ n }, paths)); */ - Log.log( - "-- All local modules found: " - ++ string_of_int(List.length(localModules)), - ); - localModules - |> List.iter(((name, paths)) => { - Log.log(name); - switch (paths) { - | SharedTypes.Impl(cmt, _) => Log.log("impl " ++ cmt) - | Intf(cmi, _) => Log.log("intf " ++ cmi) - | _ => Log.log("Both") - }; - }); - - let (pathsForModule, nameForPath) = - makePathsForModule(localModules, dependencyModules); - - let opens = - switch (namespace) { - | None => [] - | Some(namespace) => - let cmt = compiledBase /+ namespace ++ ".cmt"; - Log.log("############ Namespaced as " ++ namespace ++ " at " ++ cmt); - Hashtbl.add(pathsForModule, namespace, Impl(cmt, None)); - [FindFiles.nameSpaceToName(namespace)]; - }; - Log.log("Dependency dirs " ++ String.concat(" ", dependencyDirectories)); - - let opens = { - let flags = - MerlinFile.getFlags(rootPath) - |> RResult.withDefault([""]) - |> List.map(escapePreprocessingFlags); - let opens = - List.fold_left( - (opens, item) => { - let parts = Utils.split_on_char(' ', item); - let rec loop = items => - switch (items) { - | ["-open", name, ...rest] => [name, ...loop(rest)] - | [_, ...rest] => loop(rest) - | [] => [] +let newBsPackage = rootPath => + switch (Files.readFileResult(rootPath /+ "bsconfig.json")) { + | Error(e) => Error(e) + | Ok(raw) => + let config = Json.parse(raw); + + Log.log({|📣 📣 NEW BSB PACKAGE 📣 📣|}); + /* failwith("Wat"); */ + Log.log("- location: " ++ rootPath); + + let compiledBase = BuildSystem.getCompiledBase(rootPath); + switch (FindFiles.findDependencyFiles(~debug=true, rootPath, config)) { + | Error(e) => Error(e) + | Ok((dependencyDirectories, dependencyModules)) => + switch ( + compiledBase + |> RResult.orError( + "You need to run bsb first so that reason-language-server can access the compiled artifacts.\nOnce you've run bsb, restart the language server.", + ) + ) { + | Error(e) => Error(e) + | Ok(compiledBase) => + Ok( + { + let namespace = FindFiles.getNamespace(config); + let localSourceDirs = + FindFiles.getSourceDirectories(~includeDev=true, rootPath, config); + Log.log( + "Got source directories " ++ String.concat(" - ", localSourceDirs), + ); + let localModules = + FindFiles.findProjectFiles( + ~debug=true, + namespace, + rootPath, + localSourceDirs, + compiledBase, + ); + /* |> List.map(((name, paths)) => (switch (namespace) { + | None => name + | Some(n) => name ++ "-" ++ n }, paths)); */ + Log.log( + "-- All local modules found: " + ++ string_of_int(List.length(localModules)), + ); + localModules + |> List.iter(((name, paths)) => { + Log.log(name); + switch (paths) { + | SharedTypes.Impl(cmt, _) => Log.log("impl " ++ cmt) + | Intf(cmi, _) => Log.log("intf " ++ cmi) + | _ => Log.log("Both") + }; + }); + + let (pathsForModule, nameForPath) = + makePathsForModule(localModules, dependencyModules); + + let opens = + switch (namespace) { + | None => [] + | Some(namespace) => + let cmt = compiledBase /+ namespace ++ ".cmt"; + Log.log("############ Namespaced as " ++ namespace ++ " at " ++ cmt); + Hashtbl.add(pathsForModule, namespace, Impl(cmt, None)); + [FindFiles.nameSpaceToName(namespace)]; + }; + Log.log("Dependency dirs " ++ String.concat(" ", dependencyDirectories)); + + let opens = { + let flags = + MerlinFile.getFlags(rootPath) + |> RResult.withDefault([""]) + |> List.map(escapePreprocessingFlags); + let opens = + List.fold_left( + (opens, item) => { + let parts = Utils.split_on_char(' ', item); + let rec loop = items => + switch (items) { + | ["-open", name, ...rest] => [name, ...loop(rest)] + | [_, ...rest] => loop(rest) + | [] => [] + }; + opens @ loop(parts); + }, + opens, + flags, + ); + opens; }; - opens @ loop(parts); - }, - opens, - flags, - ); - opens; - }; - - let interModuleDependencies = Hashtbl.create(List.length(localModules)); - { - rootPath, - localModules: localModules |> List.map(fst), - dependencyModules: dependencyModules |> List.map(fst), - pathsForModule, - nameForPath, - opens, - namespace, - interModuleDependencies, + let interModuleDependencies = Hashtbl.create(List.length(localModules)); + + { + rootPath, + localModules: localModules |> List.map(fst), + dependencyModules: dependencyModules |> List.map(fst), + pathsForModule, + nameForPath, + opens, + namespace, + interModuleDependencies, + }; + }, + ) + } + }; }; -}; let findRoot = (~uri, packagesByRoot) => { let path = Uri2.toPath(uri); @@ -173,25 +184,34 @@ let getPackage = (~uri, state) => ), ); } else { - let%try root = + switch ( findRoot(~uri, state.packagesByRoot) - |> RResult.orError("No root directory found"); - let%try package = - switch (root) { - | `Root(rootPath) => - Hashtbl.replace(state.rootForUri, uri, rootPath); - Ok( - Hashtbl.find( - state.packagesByRoot, - Hashtbl.find(state.rootForUri, uri), - ), - ); - | `Bs(rootPath) => - let%try package = newBsPackage(rootPath); - Hashtbl.replace(state.rootForUri, uri, package.rootPath); - Hashtbl.replace(state.packagesByRoot, package.rootPath, package); - Ok(package); - }; - - Ok(package); + |> RResult.orError("No root directory found") + ) { + | Error(e) => Error(e) + | Ok(root) => + switch ( + switch (root) { + | `Root(rootPath) => + Hashtbl.replace(state.rootForUri, uri, rootPath); + Ok( + Hashtbl.find( + state.packagesByRoot, + Hashtbl.find(state.rootForUri, uri), + ), + ); + | `Bs(rootPath) => + switch (newBsPackage(rootPath)) { + | Error(e) => Error(e) + | Ok(package) => + Hashtbl.replace(state.rootForUri, uri, package.rootPath); + Hashtbl.replace(state.packagesByRoot, package.rootPath, package); + Ok(package); + } + } + ) { + | Error(e) => Error(e) + | Ok(package) => Ok(package) + } + }; }; diff --git a/src/rescript-editor-support/ProcessExtra.re b/src/rescript-editor-support/ProcessExtra.re index 04dba6b4..6d033dc8 100644 --- a/src/rescript-editor-support/ProcessExtra.re +++ b/src/rescript-editor-support/ProcessExtra.re @@ -29,30 +29,31 @@ let rec relative = (ident, path) => | _ => None }; -let findClosestMatchingOpen = (opens, path, ident, loc) => { - let%opt openNeedle = relative(ident, path); - - let matching = - Hashtbl.fold( - (_, op, res) => - if (Utils.locWithinLoc(loc, op.extent) - && Path.same(op.path, openNeedle)) { - [op, ...res]; - } else { - res; - }, - opens, - [], - ) - |> List.sort((a: SharedTypes.openTracker, b) => - b.loc.loc_start.pos_cnum - a.loc.loc_start.pos_cnum - ); +let findClosestMatchingOpen = (opens, path, ident, loc) => + switch (relative(ident, path)) { + | None => None + | Some(openNeedle) => + let matching = + Hashtbl.fold( + (_, op, res) => + if (Utils.locWithinLoc(loc, op.extent) + && Path.same(op.path, openNeedle)) { + [op, ...res]; + } else { + res; + }, + opens, + [], + ) + |> List.sort((a: SharedTypes.openTracker, b) => + b.loc.loc_start.pos_cnum - a.loc.loc_start.pos_cnum + ); - switch (matching) { - | [] => None - | [first, ..._] => Some(first) + switch (matching) { + | [] => None + | [first, ..._] => Some(first) + }; }; -}; let getTypeAtPath = (~env, path) => { switch (Query.fromCompilerPath(~env, path)) { @@ -60,14 +61,16 @@ let getTypeAtPath = (~env, path) => { | `Global(moduleName, path) => `Global((moduleName, path)) | `Not_found => `Not_found | `Exported(env, name) => - let res = { - let%opt stamp = Hashtbl.find_opt(env.exported.types, name); - let declaredType = Hashtbl.find_opt(env.file.stamps.types, stamp); - switch (declaredType) { - | Some(declaredType) => Some(`Local(declaredType)) + let res = + switch (Hashtbl.find_opt(env.exported.types, name)) { | None => None + | Some(stamp) => + let declaredType = Hashtbl.find_opt(env.file.stamps.types, stamp); + switch (declaredType) { + | Some(declaredType) => Some(`Local(declaredType)) + | None => None + }; }; - }; res |? `Not_found; | `Stamp(stamp) => let res = { @@ -91,13 +94,16 @@ module F = ) => { let extra = Collector.extra; - let maybeAddUse = (path, ident, loc, tip) => { - let%opt_consume tracker = - findClosestMatchingOpen(extra.opens, path, ident, loc); - let%opt_consume relpath = Query.makeRelativePath(tracker.path, path); - - tracker.used = [(relpath, tip, loc), ...tracker.used]; - }; + let maybeAddUse = (path, ident, loc, tip) => + switch (findClosestMatchingOpen(extra.opens, path, ident, loc)) { + | None => () + | Some(tracker) => + switch (Query.makeRelativePath(tracker.path, path)) { + | None => () + | Some(relpath) => + tracker.used = [(relpath, tip, loc), ...tracker.used] + } + }; let addLocation = (loc, ident) => extra.locations = [(loc, ident), ...extra.locations]; diff --git a/src/rescript-editor-support/Process_406.re b/src/rescript-editor-support/Process_406.re index f5918f79..673000a3 100644 --- a/src/rescript-editor-support/Process_406.re +++ b/src/rescript-editor-support/Process_406.re @@ -1,15 +1,18 @@ open SharedTypes; -let fileForCmt = (~moduleName, ~uri, cmt, processDoc) => { - let%try infos = Shared.tryReadCmt(cmt); - Ok(ProcessCmt.forCmt(~moduleName, ~uri, processDoc, infos)); -}; +let fileForCmt = (~moduleName, ~uri, cmt, processDoc) => + switch (Shared.tryReadCmt(cmt)) { + | Error(e) => Error(e) + | Ok(infos) => Ok(ProcessCmt.forCmt(~moduleName, ~uri, processDoc, infos)) + }; -let fullForCmt = (~moduleName, ~uri, cmt, processDoc) => { - let%try infos = Shared.tryReadCmt(cmt); - let file = ProcessCmt.forCmt(~moduleName, ~uri, processDoc, infos); - let extra = ProcessExtra.forCmt(~file, infos); - Ok({file, extra}); -}; +let fullForCmt = (~moduleName, ~uri, cmt, processDoc) => + switch (Shared.tryReadCmt(cmt)) { + | Error(e) => Error(e) + | Ok(infos) => + let file = ProcessCmt.forCmt(~moduleName, ~uri, processDoc, infos); + let extra = ProcessExtra.forCmt(~file, infos); + Ok({file, extra}); + }; module PrintType = PrintType; diff --git a/src/rescript-editor-support/Protocol.re b/src/rescript-editor-support/Protocol.re index 3b6aae4e..44dc53da 100644 --- a/src/rescript-editor-support/Protocol.re +++ b/src/rescript-editor-support/Protocol.re @@ -2,18 +2,32 @@ module J = JsonShort; let rgetPosition = pos => { open RResult.InfixResult; - let%try line = RJson.get("line", pos) |?> RJson.number; - let%try character = RJson.get("character", pos) |?> RJson.number; - Ok((int_of_float(line), int_of_float(character))); + switch (RJson.get("line", pos) |?> RJson.number) { + | Error(e) => Error(e) + | Ok(line) => + switch (RJson.get("character", pos) |?> RJson.number) { + | Error(e) => Error(e) + | Ok(character) => Ok((int_of_float(line), int_of_float(character))) + } + } }; let rPositionParams = params => { open RResult.InfixResult; - let%try uri = - RJson.get("textDocument", params) |?> RJson.get("uri") |?> RJson.string; - let%try uri = Uri2.parse(uri) |> RResult.orError("Not a uri"); - let%try pos = RJson.get("position", params) |?> rgetPosition; - Ok((uri, pos)); + switch ( + RJson.get("textDocument", params) |?> RJson.get("uri") |?> RJson.string + ) { + | Error(e) => Error(e) + | Ok(uri) => + switch (Uri2.parse(uri) |> RResult.orError("Not a uri")) { + | Error(e) => Error(e) + | Ok(uri) => + switch (RJson.get("position", params) |?> rgetPosition) { + | Error(e) => Error(e) + | Ok(pos) => Ok((uri, pos)) + } + } + } }; let posOfLexing = ({Lexing.pos_lnum, pos_cnum, pos_bol}) => diff --git a/src/rescript-editor-support/Query.re b/src/rescript-editor-support/Query.re index 3a84d043..37b59356 100644 --- a/src/rescript-editor-support/Query.re +++ b/src/rescript-editor-support/Query.re @@ -80,10 +80,15 @@ let rec resolvePathInner = (~env, ~path) => { switch (path) { | Tip(name) => Some(`Local((env, name))) | Nested(subName, subPath) => - let%opt stamp = Hashtbl.find_opt(env.exported.modules, subName); - let%opt {item: kind} = Hashtbl.find_opt(env.file.stamps.modules, stamp); - findInModule(~env, kind, subPath); - }; + switch (Hashtbl.find_opt(env.exported.modules, subName)) { + | None => None + | Some(stamp) => + switch (Hashtbl.find_opt(env.file.stamps.modules, stamp)) { + | None => None + | Some({item: kind}) => findInModule(~env, kind, subPath) + } + } + } } and findInModule = (~env, kind, path) => { switch (kind) { @@ -94,9 +99,10 @@ and findInModule = (~env, kind, path) => { if (stamp == 0) { Some(`Global((moduleName, fullPath))); } else { - let%opt {item: kind} = - Hashtbl.find_opt(env.file.stamps.modules, stamp); - findInModule(~env, kind, fullPath); + switch (Hashtbl.find_opt(env.file.stamps.modules, stamp)) { + | None => None + | Some({item: kind}) => findInModule(~env, kind, fullPath) + }; }; }; }; @@ -104,12 +110,18 @@ and findInModule = (~env, kind, path) => { /* let rec findSubModule = (~env, ~getModule) */ let rec resolvePath = (~env, ~path, ~getModule) => { - let%opt result = resolvePathInner(~env, ~path); - switch (result) { - | `Local(env, name) => Some((env, name)) - | `Global(moduleName, fullPath) => - let%opt file = getModule(moduleName); - resolvePath(~env=fileEnv(file), ~path=fullPath, ~getModule); + switch (resolvePathInner(~env, ~path)) { + | None => None + | Some(result) => + switch (result) { + | `Local(env, name) => Some((env, name)) + | `Global(moduleName, fullPath) => + switch (getModule(moduleName)) { + | None => None + | Some(file) => + resolvePath(~env=fileEnv(file), ~path=fullPath, ~getModule) + } + } }; }; @@ -118,15 +130,24 @@ let resolveFromStamps = (~env, ~path, ~getModule, ~pos) => { | Tip(name) => Some((env, name)) | Nested(name, inner) => /* Log.log("Finding from stamps " ++ name); */ - let%opt declared = findInScope(pos, name, env.file.stamps.modules); - /* Log.log("found it"); */ - let%opt res = findInModule(~env, declared.item, inner); - switch (res) { - | `Local(env, name) => Some((env, name)) - | `Global(moduleName, fullPath) => - let%opt file = getModule(moduleName); - resolvePath(~env=fileEnv(file), ~path=fullPath, ~getModule); - }; + switch (findInScope(pos, name, env.file.stamps.modules)) { + | None => None + | Some(declared) => + /* Log.log("found it"); */ + switch (findInModule(~env, declared.item, inner)) { + | None => None + | Some(res) => + switch (res) { + | `Local(env, name) => Some((env, name)) + | `Global(moduleName, fullPath) => + switch (getModule(moduleName)) { + | None => None + | Some(file) => + resolvePath(~env=fileEnv(file), ~path=fullPath, ~getModule) + } + } + } + } }; }; @@ -154,24 +175,45 @@ let fromCompilerPath = (~env, path) => { let resolveModuleFromCompilerPath = (~env, ~getModule, path) => { switch (fromCompilerPath(~env, path)) { | `Global(moduleName, path) => - let%opt file = getModule(moduleName); - let env = fileEnv(file); - let%opt (env, name) = resolvePath(~env, ~getModule, ~path); - let%opt stamp = Hashtbl.find_opt(env.exported.modules, name); - let%opt declared = Hashtbl.find_opt(env.file.stamps.modules, stamp); - Some((env, Some(declared))); + switch (getModule(moduleName)) { + | None => None + | Some(file) => + let env = fileEnv(file); + switch (resolvePath(~env, ~getModule, ~path)) { + | None => None + | Some((env, name)) => + switch (Hashtbl.find_opt(env.exported.modules, name)) { + | None => None + | Some(stamp) => + switch (Hashtbl.find_opt(env.file.stamps.modules, stamp)) { + | None => None + | Some(declared) => Some((env, Some(declared))) + } + } + }; + } | `Stamp(stamp) => - let%opt declared = Hashtbl.find_opt(env.file.stamps.modules, stamp); - Some((env, Some(declared))); + switch (Hashtbl.find_opt(env.file.stamps.modules, stamp)) { + | None => None + | Some(declared) => Some((env, Some(declared))) + } | `GlobalMod(moduleName) => - let%opt file = getModule(moduleName); - let env = fileEnv(file); - Some((env, None)); + switch (getModule(moduleName)) { + | None => None + | Some(file) => + let env = fileEnv(file); + Some((env, None)); + } | `Not_found => None | `Exported(env, name) => - let%opt stamp = Hashtbl.find_opt(env.exported.modules, name); - let%opt declared = Hashtbl.find_opt(env.file.stamps.modules, stamp); - Some((env, Some(declared))); + switch (Hashtbl.find_opt(env.exported.modules, name)) { + | None => None + | Some(stamp) => + switch (Hashtbl.find_opt(env.file.stamps.modules, stamp)) { + | None => None + | Some(declared) => Some((env, Some(declared))) + } + } }; }; @@ -234,21 +276,28 @@ let declaredForTip = (~stamps, stamp, tip) => }; let getField = (file, stamp, name) => { - let%opt {item: {kind}} = Hashtbl.find_opt(file.stamps.types, stamp); - switch (kind) { - | Record(fields) => fields |> List.find_opt(f => f.fname.txt == name) - | _ => None + switch (Hashtbl.find_opt(file.stamps.types, stamp)) { + | None => None + | Some({item: {kind}}) => + switch (kind) { + | Record(fields) => fields |> List.find_opt(f => f.fname.txt == name) + | _ => None + } }; }; let getConstructor = (file, stamp, name) => { - let%opt {item: {kind}} = Hashtbl.find_opt(file.stamps.types, stamp); - switch (kind) { - | Variant(constructors) => - let%opt const = - constructors |> List.find_opt(const => const.cname.txt == name); - Some(const); - | _ => None + switch (Hashtbl.find_opt(file.stamps.types, stamp)) { + | None => None + | Some({item: {kind}}) => + switch (kind) { + | Variant(constructors) => + switch (constructors |> List.find_opt(const => const.cname.txt == name)) { + | None => None + | Some(const) => Some(const) + } + | _ => None + } }; }; diff --git a/src/rescript-editor-support/References.re b/src/rescript-editor-support/References.re index 8f1204d5..4d520b7a 100644 --- a/src/rescript-editor-support/References.re +++ b/src/rescript-editor-support/References.re @@ -72,14 +72,18 @@ let localReferencesForLoc = (~file, ~extra, loc) => | LModule(LocalReference(stamp, tip) | Definition(stamp, tip)) | Typed(_, LocalReference(stamp, tip) | Definition(stamp, tip)) => open Infix; - let%opt localStamp = + switch ( switch (tip) { | Constructor(name) => Query.getConstructor(file, stamp, name) |?>> (x => x.stamp) | Field(name) => Query.getField(file, stamp, name) |?>> (x => x.stamp) | _ => Some(stamp) - }; - Hashtbl.find_opt(extra.internalReferences, localStamp); + } + ) { + | None => None + | Some(localStamp) => + Hashtbl.find_opt(extra.internalReferences, localStamp) + } | LModule(GlobalReference(moduleName, path, tip)) | Typed(_, GlobalReference(moduleName, path, tip)) => switch (Hashtbl.find_opt(extra.externalReferences, moduleName)) { @@ -98,11 +102,15 @@ let definedForLoc = (~file, ~getModule, locKind) => { let inner = (~file, stamp, tip) => { switch (tip) { | Constructor(name) => - let%opt constructor = Query.getConstructor(file, stamp, name); - Some(([], `Constructor(constructor))); + switch (Query.getConstructor(file, stamp, name)) { + | None => None + | Some(constructor) => Some(([], `Constructor(constructor))) + } | Field(name) => - let%opt field = Query.getField(file, stamp, name); - Some(([], `Field(field))); + switch (Query.getField(file, stamp, name)) { + | None => None + | Some(field) => Some(([], `Field(field))) + } | _ => maybeLog( "Trying for declared " @@ -112,9 +120,10 @@ let definedForLoc = (~file, ~getModule, locKind) => { ++ " in file " ++ Uri2.toString(file.uri), ); - let%opt declared = - Query.declaredForTip(~stamps=file.stamps, stamp, tip); - Some((declared.docstring, `Declared)); + switch (Query.declaredForTip(~stamps=file.stamps, stamp, tip)) { + | None => None + | Some(declared) => Some((declared.docstring, `Declared)) + }; }; }; @@ -125,62 +134,95 @@ let definedForLoc = (~file, ~getModule, locKind) => { | GlobalReference(moduleName, path, tip) => { maybeLog("Getting global " ++ moduleName); - let%try file = + switch ( getModule(moduleName) - |> RResult.orError("Cannot get module " ++ moduleName); - let env = Query.fileEnv(file); - let%try (env, name) = - Query.resolvePath(~env, ~path, ~getModule) - |> RResult.orError("Cannot resolve path " ++ pathToString(path)); - let%try stamp = - Query.exportedForTip(~env, name, tip) - |> RResult.orError( - "Exported not found for tip " - ++ name - ++ " > " - ++ tipToString(tip), - ); - maybeLog("Getting for " ++ string_of_int(stamp) ++ " in " ++ name); - let%try res = - inner(~file=env.file, stamp, tip) - |> RResult.orError("could not get defined"); - maybeLog("Yes!! got it"); - Ok(res); + |> RResult.orError("Cannot get module " ++ moduleName) + ) { + | Error(e) => Error(e) + | Ok(file) => + let env = Query.fileEnv(file); + switch ( + Query.resolvePath(~env, ~path, ~getModule) + |> RResult.orError("Cannot resolve path " ++ pathToString(path)) + ) { + | Error(e) => Error(e) + | Ok((env, name)) => + switch ( + Query.exportedForTip(~env, name, tip) + |> RResult.orError( + "Exported not found for tip " + ++ name + ++ " > " + ++ tipToString(tip), + ) + ) { + | Error(e) => Error(e) + | Ok(stamp) => + maybeLog( + "Getting for " ++ string_of_int(stamp) ++ " in " ++ name, + ); + switch ( + inner(~file=env.file, stamp, tip) + |> RResult.orError("could not get defined") + ) { + | Error(e) => Error(e) + | Ok(res) => + maybeLog("Yes!! got it"); + Ok(res); + }; + } + }; + }; } |> RResult.toOptionAndLog }; }; let alternateDeclared = (~file, ~pathsForModule, ~getUri, declared, tip) => { - let%opt paths = Hashtbl.find_opt(pathsForModule, file.moduleName); - maybeLog("paths for " ++ file.moduleName); - switch (paths) { - | IntfAndImpl(_, intf, _, impl) => - maybeLog("Have both!!"); - let intfUri = Uri2.fromPath(intf); - let implUri = Uri2.fromPath(impl); - if (intfUri == file.uri) { - let%opt (file, extra) = getUri(implUri) |> RResult.toOptionAndLog; - let%opt declared = - Query.declaredForExportedTip( - ~stamps=file.stamps, - ~exported=file.contents.exported, - declared.name.txt, - tip, - ); - Some((file, extra, declared)); - } else { - let%opt (file, extra) = getUri(intfUri) |> RResult.toOptionAndLog; - let%opt declared = - Query.declaredForExportedTip( - ~stamps=file.stamps, - ~exported=file.contents.exported, - declared.name.txt, - tip, - ); - Some((file, extra, declared)); + switch (Hashtbl.find_opt(pathsForModule, file.moduleName)) { + | None => None + | Some(paths) => + maybeLog("paths for " ++ file.moduleName); + switch (paths) { + | IntfAndImpl(_, intf, _, impl) => + maybeLog("Have both!!"); + let intfUri = Uri2.fromPath(intf); + let implUri = Uri2.fromPath(impl); + if (intfUri == file.uri) { + switch (getUri(implUri) |> RResult.toOptionAndLog) { + | None => None + | Some((file, extra)) => + switch ( + Query.declaredForExportedTip( + ~stamps=file.stamps, + ~exported=file.contents.exported, + declared.name.txt, + tip, + ) + ) { + | None => None + | Some(declared) => Some((file, extra, declared)) + } + }; + } else { + switch (getUri(intfUri) |> RResult.toOptionAndLog) { + | None => None + | Some((file, extra)) => + switch ( + Query.declaredForExportedTip( + ~stamps=file.stamps, + ~exported=file.contents.exported, + declared.name.txt, + tip, + ) + ) { + | None => None + | Some(declared) => Some((file, extra, declared)) + } + }; + }; + | _ => None }; - | _ => None }; }; @@ -193,26 +235,50 @@ let resolveModuleReference = switch (Query.fromCompilerPath(~env, path)) { | `Not_found => None | `Exported(env, name) => - let%opt stamp = Hashtbl.find_opt(env.exported.modules, name); - let%opt md = Hashtbl.find_opt(env.file.stamps.modules, stamp); - Some((env.file, Some(md))); - /* Some((env.file.uri, validateLoc(md.name.loc, md.extentLoc))) */ + switch (Hashtbl.find_opt(env.exported.modules, name)) { + | None => None + | Some(stamp) => + switch (Hashtbl.find_opt(env.file.stamps.modules, stamp)) { + | None => None + | Some(md) => + Some((env.file, Some(md))) + /* Some((env.file.uri, validateLoc(md.name.loc, md.extentLoc))) */ + } + } | `Global(moduleName, path) => - let%opt file = getModule(moduleName); - let env = Query.fileEnv(file); - let%opt (env, name) = Query.resolvePath(~env, ~getModule, ~path); - let%opt stamp = Hashtbl.find_opt(env.exported.modules, name); - let%opt md = Hashtbl.find_opt(env.file.stamps.modules, stamp); - Some((env.file, Some(md))); - /* Some((env.file.uri, validateLoc(md.name.loc, md.extentLoc))) */ + switch (getModule(moduleName)) { + | None => None + | Some(file) => + let env = Query.fileEnv(file); + switch (Query.resolvePath(~env, ~getModule, ~path)) { + | None => None + | Some((env, name)) => + switch (Hashtbl.find_opt(env.exported.modules, name)) { + | None => None + | Some(stamp) => + switch (Hashtbl.find_opt(env.file.stamps.modules, stamp)) { + | None => None + | Some(md) => + Some((env.file, Some(md))) + /* Some((env.file.uri, validateLoc(md.name.loc, md.extentLoc))) */ + } + } + }; + } | `Stamp(stamp) => - let%opt md = Hashtbl.find_opt(file.stamps.modules, stamp); - Some((file, Some(md))); - /* Some((file.uri, validateLoc(md.name.loc, md.extentLoc))) */ + switch (Hashtbl.find_opt(file.stamps.modules, stamp)) { + | None => None + | Some(md) => + Some((file, Some(md))) + /* Some((file.uri, validateLoc(md.name.loc, md.extentLoc))) */ + } | `GlobalMod(name) => - let%opt file = getModule(name); - /* maybeLog("Congrats, found a global mod"); */ - Some((file, None)); + switch (getModule(name)) { + | None => None + | Some(file) => + /* maybeLog("Congrats, found a global mod"); */ + Some((file, None)) + } | _ => None }; }; @@ -232,93 +298,125 @@ let forLocalStamp = ) => { let env = Query.fileEnv(file); open Infix; - let%opt localStamp = + switch ( switch (tip) { | Constructor(name) => Query.getConstructor(file, stamp, name) |?>> (x => x.stamp) | Field(name) => Query.getField(file, stamp, name) |?>> (x => x.stamp) | _ => Some(stamp) - }; - let%opt local = Hashtbl.find_opt(extra.internalReferences, localStamp); - open Infix; - let externals = - { - maybeLog("Checking externals: " ++ string_of_int(stamp)); - let%opt declared = - Query.declaredForTip(~stamps=env.file.stamps, stamp, tip); - if (isVisible(declared)) { - /** - if this file has a corresponding interface or implementation file - also find the references in that file. - */ - let alternativeReferences = - { - let%opt (file, extra, {stamp}) = - alternateDeclared( - ~pathsForModule, - ~file, - ~getUri, - declared, - tip, - ); - let%opt localStamp = - switch (tip) { - | Constructor(name) => - Query.getConstructor(file, stamp, name) |?>> (x => x.stamp) - | Field(name) => - Query.getField(file, stamp, name) |?>> (x => x.stamp) - | _ => Some(stamp) + } + ) { + | None => None + | Some(localStamp) => + switch (Hashtbl.find_opt(extra.internalReferences, localStamp)) { + | None => None + | Some(local) => + open Infix; + let externals = + { + maybeLog("Checking externals: " ++ string_of_int(stamp)); + switch (Query.declaredForTip(~stamps=env.file.stamps, stamp, tip)) { + | None => None + | Some(declared) => + if (isVisible(declared)) { + /** + if this file has a corresponding interface or implementation file + also find the references in that file. + */ + let alternativeReferences = + ( + switch ( + alternateDeclared( + ~pathsForModule, + ~file, + ~getUri, + declared, + tip, + ) + ) { + | None => None + | Some((file, extra, {stamp})) => + switch ( + switch (tip) { + | Constructor(name) => + Query.getConstructor(file, stamp, name) |?>> (x => x.stamp) + | Field(name) => + Query.getField(file, stamp, name) |?>> (x => x.stamp) + | _ => Some(stamp) + } + ) { + | None => None + | Some(localStamp) => + switch (Hashtbl.find_opt(extra.internalReferences, localStamp)) { + | None => None + | Some(local) => Some([(file.uri, local)]) + } + } + } + ) + |? []; + switch ( + pathFromVisibility(declared.modulePath, declared.name.txt) + ) { + | None => None + | Some(path) => + maybeLog("Now checking path " ++ pathToString(path)); + let thisModuleName = file.moduleName; + let externals = + allModules + |> List.filter(name => name != file.moduleName) + |> Utils.filterMap(name => + { + switch ( + getModule(name) + |> RResult.orError( + "Could not get file for module " ++ name, + ) + ) { + | Error(e) => Error(e) + | Ok(file) => + switch ( + getExtra(name) + |> RResult.orError( + "Could not get extra for module " ++ name, + ) + ) { + | Error(e) => Error(e) + | Ok(extra) => + switch ( + Hashtbl.find_opt(extra.externalReferences, thisModuleName) + |> RResult.orError( + "No references in " + ++ name + ++ " for " + ++ thisModuleName, + ) + ) { + | Error(e) => Error(e) + | Ok(refs) => + let refs = + refs + |> Utils.filterMap(((p, t, l)) => + p == path && t == tip ? Some(l) : None + ); + Ok((file.uri, refs)); + } + } + } + } |> RResult.toOptionAndLog + ); + Some(alternativeReferences @ externals); }; - let%opt local = - Hashtbl.find_opt(extra.internalReferences, localStamp); - Some([(file.uri, local)]); - } - |? []; - - let%opt path = - pathFromVisibility(declared.modulePath, declared.name.txt); - maybeLog("Now checking path " ++ pathToString(path)); - let thisModuleName = file.moduleName; - let externals = - allModules - |> List.filter(name => name != file.moduleName) - |> Utils.filterMap(name => - { - let%try file = - getModule(name) - |> RResult.orError( - "Could not get file for module " ++ name, - ); - let%try extra = - getExtra(name) - |> RResult.orError( - "Could not get extra for module " ++ name, - ); - let%try refs = - Hashtbl.find_opt(extra.externalReferences, thisModuleName) - |> RResult.orError( - "No references in " - ++ name - ++ " for " - ++ thisModuleName, - ); - let refs = - refs - |> Utils.filterMap(((p, t, l)) => - p == path && t == tip ? Some(l) : None - ); - Ok((file.uri, refs)); - } - |> RResult.toOptionAndLog - ); - Some(alternativeReferences @ externals); - } else { - maybeLog("Not visible"); - Some([]); - }; + } else { + maybeLog("Not visible"); + Some([]); + } + }; + } + |? []; + Some([(file.uri, local), ...externals]); } - |? []; - Some([(file.uri, local), ...externals]); + }; }; let allReferencesForLoc = @@ -375,47 +473,64 @@ let allReferencesForLoc = |> RResult.orError("Could not get for local stamp"); | LModule(GlobalReference(moduleName, path, tip)) | Typed(_, GlobalReference(moduleName, path, tip)) => - let%try file = + switch ( getModule(moduleName) - |> RResult.orError("Cannot get module " ++ moduleName); - let env = Query.fileEnv(file); - let%try (env, name) = - Query.resolvePath(~env, ~path, ~getModule) - |> RResult.orError("Cannot resolve path " ++ pathToString(path)); - let%try stamp = - Query.exportedForTip(~env, name, tip) - |> RResult.orError( - "Exported not found for tip " ++ name ++ " > " ++ tipToString(tip), - ); - let%try (file, extra) = getUri(env.file.uri); - maybeLog( - "Finding references for (global) " - ++ Uri2.toString(env.file.uri) - ++ " and stamp " - ++ string_of_int(stamp) - ++ " and tip " - ++ tipToString(tip), - ); - forLocalStamp( - ~pathsForModule, - ~getUri, - ~file, - ~extra, - ~allModules, - ~getModule, - ~getExtra, - stamp, - tip, - ) - |> RResult.orError("Could not get for local stamp"); + |> RResult.orError("Cannot get module " ++ moduleName) + ) { + | Error(e) => Error(e) + | Ok(file) => + let env = Query.fileEnv(file); + switch ( + Query.resolvePath(~env, ~path, ~getModule) + |> RResult.orError("Cannot resolve path " ++ pathToString(path)) + ) { + | Error(e) => Error(e) + | Ok((env, name)) => + switch ( + Query.exportedForTip(~env, name, tip) + |> RResult.orError( + "Exported not found for tip " ++ name ++ " > " ++ tipToString(tip) + ) + ) { + | Error(e) => Error(e) + | Ok(stamp) => + switch (getUri(env.file.uri)) { + | Error(e) => Error(e) + | Ok((file, extra)) => + maybeLog( + "Finding references for (global) " + ++ Uri2.toString(env.file.uri) + ++ " and stamp " + ++ string_of_int(stamp) + ++ " and tip " + ++ tipToString(tip), + ); + forLocalStamp( + ~pathsForModule, + ~getUri, + ~file, + ~extra, + ~allModules, + ~getModule, + ~getExtra, + stamp, + tip, + ) + |> RResult.orError("Could not get for local stamp"); + } + } + }; + } }; }; let refsForPos = (~file, ~extra, pos) => { - let%opt (_, loc) = locForPos(~extra, pos); - maybeLog("Got a loc for pos"); - let%opt refs = localReferencesForLoc(~file, ~extra, loc); - Some(refs); + switch (locForPos(~extra, pos)) { + | None => None + | Some((_, loc)) => + maybeLog("Got a loc for pos"); + localReferencesForLoc(~file, ~extra, loc); + } }; let validateLoc = (loc: Location.t, backup: Location.t) => @@ -444,32 +559,46 @@ let validateLoc = (loc: Location.t, backup: Location.t) => }; let resolveModuleDefinition = (~file, ~getModule, stamp) => { - let%opt md = Hashtbl.find_opt(file.stamps.modules, stamp); - let%opt (file, declared) = resolveModuleReference(~file, ~getModule, md); - let loc = - switch (declared) { - | None => Utils.topLoc(Uri2.toPath(file.uri)) - | Some(declared) => validateLoc(declared.name.loc, declared.extentLoc) - }; - Some((file.uri, loc)); + switch (Hashtbl.find_opt(file.stamps.modules, stamp)) { + | None => None + | Some(md) => + switch (resolveModuleReference(~file, ~getModule, md)) { + | None => None + | Some((file, declared)) => + let loc = + switch (declared) { + | None => Utils.topLoc(Uri2.toPath(file.uri)) + | Some(declared) => + validateLoc(declared.name.loc, declared.extentLoc) + }; + Some((file.uri, loc)); + } + }; }; let definition = (~file, ~getModule, stamp, tip) => { switch (tip) { | Constructor(name) => - let%opt constructor = Query.getConstructor(file, stamp, name); - Some((file.uri, constructor.cname.loc)); + switch (Query.getConstructor(file, stamp, name)) { + | None => None + | Some(constructor) => Some((file.uri, constructor.cname.loc)) + } | Field(name) => - let%opt field = Query.getField(file, stamp, name); - Some((file.uri, field.fname.loc)); + switch (Query.getField(file, stamp, name)) { + | None => None + | Some(field) => Some((file.uri, field.fname.loc)) + } | Module => resolveModuleDefinition(~file, ~getModule, stamp) | _ => - let%opt declared = Query.declaredForTip(~stamps=file.stamps, stamp, tip); - let loc = validateLoc(declared.name.loc, declared.extentLoc); - let env = Query.fileEnv(file); - let uri = Query.getSourceUri(~env, ~getModule, declared.modulePath); - maybeLog("Inner uri " ++ Uri2.toString(uri)); - Some((uri, loc)); + switch (Query.declaredForTip(~stamps=file.stamps, stamp, tip)) { + | None => None + | Some(declared) => + let loc = validateLoc(declared.name.loc, declared.extentLoc); + let env = Query.fileEnv(file); + let uri = Query.getSourceUri(~env, ~getModule, declared.modulePath); + maybeLog("Inner uri " ++ Uri2.toString(uri)); + Some((uri, loc)); + } }; }; @@ -485,16 +614,23 @@ let definitionForLoc = (~pathsForModule, ~file, ~getUri, ~getModule, loc) => { switch (loc) { | Typed(_, Definition(stamp, tip)) => maybeLog("Trying to find a defintion for a definition"); - let%opt declared = Query.declaredForTip(~stamps=file.stamps, stamp, tip); - maybeLog("Declared"); - if (declared.exported) { - maybeLog("exported, looking for alternate " ++ file.moduleName); - let%opt (file, _extra, declared) = - alternateDeclared(~pathsForModule, ~file, ~getUri, declared, tip); - let loc = validateLoc(declared.name.loc, declared.extentLoc); - Some((file.uri, loc)); - } else { - None; + switch (Query.declaredForTip(~stamps=file.stamps, stamp, tip)) { + | None => None + | Some(declared) => + maybeLog("Declared"); + if (declared.exported) { + maybeLog("exported, looking for alternate " ++ file.moduleName); + switch ( + alternateDeclared(~pathsForModule, ~file, ~getUri, declared, tip) + ) { + | None => None + | Some((file, _extra, declared)) => + let loc = validateLoc(declared.name.loc, declared.extentLoc); + Some((file.uri, loc)); + }; + } else { + None; + }; }; | Explanation(_) | Typed(_, NotFound) @@ -504,12 +640,15 @@ let definitionForLoc = (~pathsForModule, ~file, ~getUri, ~getModule, loc) => { | TopLevelModule(name) => maybeLog("Toplevel " ++ name); open Infix; - let%opt src = + switch ( Hashtbl.find_opt(pathsForModule, name) |> orLog("No paths found") |?> getSrc - |> orLog("No src found"); - Some((Uri2.fromPath(src), Utils.topLoc(src))); + |> orLog("No src found") + ) { + | None => None + | Some(src) => Some((Uri2.fromPath(src), Utils.topLoc(src))) + } | LModule(LocalReference(stamp, tip)) | Typed(_, LocalReference(stamp, tip)) => maybeLog("Local defn " ++ tipToString(tip)); @@ -524,19 +663,30 @@ let definitionForLoc = (~pathsForModule, ~file, ~getUri, ~getModule, loc) => { ++ " : " ++ tipToString(tip), ); - let%opt file = getModule(moduleName); - let env = Query.fileEnv(file); - let%opt (env, name) = Query.resolvePath(~env, ~path, ~getModule); - let%opt stamp = Query.exportedForTip(~env, name, tip); - /** oooh wht do I do if the stamp is inside a pseudo-file? */ - maybeLog("Got stamp " ++ string_of_int(stamp)); - definition(~file=env.file, ~getModule, stamp, tip); + switch (getModule(moduleName)) { + | None => None + | Some(file) => + let env = Query.fileEnv(file); + switch (Query.resolvePath(~env, ~path, ~getModule)) { + | None => None + | Some((env, name)) => + switch (Query.exportedForTip(~env, name, tip)) { + | None => None + | Some(stamp) => + /** oooh wht do I do if the stamp is inside a pseudo-file? */ + maybeLog("Got stamp " ++ string_of_int(stamp)); + definition(~file=env.file, ~getModule, stamp, tip); + } + }; + }; }; }; let definitionForPos = - (~pathsForModule, ~file, ~extra, ~getUri, ~getModule, pos) => { - let%opt (_, loc) = locForPos(~extra, pos); - maybeLog("Got a loc for pos"); - definitionForLoc(~pathsForModule, ~file, ~getUri, ~getModule, loc); -}; + (~pathsForModule, ~file, ~extra, ~getUri, ~getModule, pos) => + switch (locForPos(~extra, pos)) { + | None => None + | Some((_, loc)) => + maybeLog("Got a loc for pos"); + definitionForLoc(~pathsForModule, ~file, ~getUri, ~getModule, loc); + }; diff --git a/src/rescript-editor-support/RescriptEditorSupport.re b/src/rescript-editor-support/RescriptEditorSupport.re index fd246bfc..60c0b2c6 100644 --- a/src/rescript-editor-support/RescriptEditorSupport.re +++ b/src/rescript-editor-support/RescriptEditorSupport.re @@ -25,44 +25,47 @@ let capabilities = let getInitialState = params => { let rootUri = Json.get("rootUri", params) |?> Json.string |?> Uri2.parse; - let%try rootUri = rootUri |> RResult.orError("Not a uri"); - let rootPath = Uri2.toPath(rootUri); - - Files.mkdirp(rootPath /+ "node_modules" /+ ".lsp"); - Log.setLocation(rootPath /+ "node_modules" /+ ".lsp" /+ "debug.log"); - Log.log("Hello - from " ++ Sys.executable_name); - - Rpc.sendNotification( - stdout, - "client/registerCapability", - J.o([ - ( - "registrations", - J.l([ - J.o([ - ("id", J.s("watching")), - ("method", J.s("workspace/didChangeWatchedFiles")), - ( - "registerOptions", - J.o([ - ( - "watchers", - J.l([ - J.o([("globPattern", J.s("**/bsconfig.json"))]), - J.o([("globPattern", J.s("**/.merlin"))]), - ]), - ), - ]), - ), + switch (rootUri |> RResult.orError("Not a uri")) { + | Error(e) => Error(e) + | Ok(rootUri) => + let rootPath = Uri2.toPath(rootUri); + + Files.mkdirp(rootPath /+ "node_modules" /+ ".lsp"); + Log.setLocation(rootPath /+ "node_modules" /+ ".lsp" /+ "debug.log"); + Log.log("Hello - from " ++ Sys.executable_name); + + Rpc.sendNotification( + stdout, + "client/registerCapability", + J.o([ + ( + "registrations", + J.l([ + J.o([ + ("id", J.s("watching")), + ("method", J.s("workspace/didChangeWatchedFiles")), + ( + "registerOptions", + J.o([ + ( + "watchers", + J.l([ + J.o([("globPattern", J.s("**/bsconfig.json"))]), + J.o([("globPattern", J.s("**/.merlin"))]), + ]), + ), + ]), + ), + ]), ]), - ]), - ), - ]), - ); + ), + ]), + ); - let state = TopTypes.empty(); + let state = TopTypes.empty(); - Ok(state); + Ok(state); + }; }; let parseArgs = args => { diff --git a/src/rescript-editor-support/State.re b/src/rescript-editor-support/State.re index b963716c..88f0098a 100644 --- a/src/rescript-editor-support/State.re +++ b/src/rescript-editor-support/State.re @@ -15,11 +15,15 @@ let converter = src => { let newDocsForCmt = (~moduleName, cmtCache, changed, cmt, src) => { let uri = Uri2.fromPath(src |? cmt); - let%opt file = + switch ( Process_406.fileForCmt(~moduleName, ~uri, cmt, converter(src)) - |> RResult.toOptionAndLog; - Hashtbl.replace(cmtCache, cmt, (changed, file)); - Some(file); + |> RResult.toOptionAndLog + ) { + | None => None + | Some(file) => + Hashtbl.replace(cmtCache, cmt, (changed, file)); + Some(file); + }; }; let docsForCmt = (~moduleName, cmt, src, state) => @@ -56,21 +60,27 @@ open Infix; let getFullFromCmt = (~state, ~uri) => { let path = Uri2.toPath(uri); - let%try package = Packages.getPackage(uri, state); - let moduleName = - BuildSystem.namespacedName(package.namespace, FindFiles.getName(path)); - switch (Hashtbl.find_opt(package.pathsForModule, moduleName)) { - | Some(paths) => - let cmt = - SharedTypes.getCmt(~interface=Utils.endsWith(path, "i"), paths); - let%try full = Process_406.fullForCmt(~moduleName, ~uri, cmt, x => [x]); - Hashtbl.replace( - package.interModuleDependencies, - moduleName, - SharedTypes.hashList(full.extra.externalReferences) |> List.map(fst), - ); - Ok((package, full)); - | None => Error("can't find module " ++ moduleName) + switch (Packages.getPackage(uri, state)) { + | Error(e) => Error(e) + | Ok(package) => + let moduleName = + BuildSystem.namespacedName(package.namespace, FindFiles.getName(path)); + switch (Hashtbl.find_opt(package.pathsForModule, moduleName)) { + | Some(paths) => + let cmt = + SharedTypes.getCmt(~interface=Utils.endsWith(path, "i"), paths); + switch (Process_406.fullForCmt(~moduleName, ~uri, cmt, x => [x])) { + | Error(e) => Error(e) + | Ok(full) => + Hashtbl.replace( + package.interModuleDependencies, + moduleName, + SharedTypes.hashList(full.extra.externalReferences) |> List.map(fst), + ); + Ok((package, full)); + }; + | None => Error("can't find module " ++ moduleName) + }; }; }; @@ -92,23 +102,30 @@ let docsForModule = (modname, state, ~package) => }; let fileForUri = (state, uri) => { - let%try (_package, {extra, file}) = getFullFromCmt(~state, ~uri); - Ok((file, extra)); + switch (getFullFromCmt(~state, ~uri)) { + | Error(e) => Error(e) + | Ok((_package, {extra, file})) => Ok((file, extra)) + } }; let fileForModule = (state, ~package, modname) => { - let%opt (file, _) = docsForModule(modname, state, ~package); - Some(file); + switch (docsForModule(modname, state, ~package)) { + | None => None + | Some((file, _)) => Some(file) + } }; let extraForModule = (state, ~package, modname) => if (Hashtbl.mem(package.pathsForModule, modname)) { let paths = Hashtbl.find(package.pathsForModule, modname); /* TODO do better? */ - let%opt src = SharedTypes.getSrc(paths); - switch (getFullFromCmt(~state, ~uri=Uri2.fromPath(src))) { - | Ok((_package, {extra})) => Some(extra) - | Error(_) => None + switch (SharedTypes.getSrc(paths)) { + | None => None + | Some(src) => + switch (getFullFromCmt(~state, ~uri=Uri2.fromPath(src))) { + | Ok((_package, {extra})) => Some(extra) + | Error(_) => None + } }; } else { None; From af75e201877da79993217436f3e7a3e3a6eab742 Mon Sep 17 00:00:00 2001 From: Cheng Lou Date: Wed, 7 Apr 2021 02:55:54 -0700 Subject: [PATCH 2/2] Revert "Convert everything over to unmonad (#91)" This reverts commit 8e9f0fbb2a1af6e016fcef69aa80fe53803a6e85. --- src/rescript-editor-support/Hover.re | 118 ++-- .../MessageHandlers.re | 667 ++++++++---------- src/rescript-editor-support/NewCompletions.re | 111 ++- .../NotificationHandlers.re | 112 ++- src/rescript-editor-support/Packages.re | 250 +++---- src/rescript-editor-support/ProcessExtra.re | 76 +- src/rescript-editor-support/Process_406.re | 23 +- src/rescript-editor-support/Protocol.re | 30 +- src/rescript-editor-support/Query.re | 143 ++-- src/rescript-editor-support/References.re | 618 ++++++---------- .../RescriptEditorSupport.re | 73 +- src/rescript-editor-support/State.re | 71 +- 12 files changed, 933 insertions(+), 1359 deletions(-) diff --git a/src/rescript-editor-support/Hover.re b/src/rescript-editor-support/Hover.re index 075d8ec3..baec517d 100644 --- a/src/rescript-editor-support/Hover.re +++ b/src/rescript-editor-support/Hover.re @@ -2,19 +2,12 @@ let digConstructor = (~env, ~getModule, path) => { switch (Query.resolveFromCompilerPath(~env, ~getModule, path)) { | `Not_found => None | `Stamp(stamp) => - switch (Hashtbl.find_opt(env.file.stamps.types, stamp)) { - | None => None - | Some(t) => Some((env, t)) - } + let%opt t = Hashtbl.find_opt(env.file.stamps.types, stamp); + Some((env, t)); | `Exported(env, name) => - switch (Hashtbl.find_opt(env.exported.types, name)) { - | None => None - | Some(stamp) => - switch (Hashtbl.find_opt(env.file.stamps.types, stamp)) { - | None => None - | Some(t) => Some((env, t)) - } - } + let%opt stamp = Hashtbl.find_opt(env.exported.types, name); + let%opt t = Hashtbl.find_opt(env.file.stamps.types, stamp); + Some((env, t)); | _ => None }; }; @@ -74,60 +67,38 @@ let newHover = (~file: SharedTypes.file, ~getModule, loc) => { Some(codeBlock(typeDef)); | LModule(Definition(stamp, _tip)) | LModule(LocalReference(stamp, _tip)) => - switch (Hashtbl.find_opt(file.stamps.modules, stamp)) { - | None => None - | Some(md) => - switch (References.resolveModuleReference(~file, ~getModule, md)) { - | None => None - | Some((file, declared)) => - let (name, docstring) = - switch (declared) { - | Some(d) => (d.name.txt, d.docstring) - | None => (file.moduleName, file.contents.docstring) - }; - showModule(~docstring, ~name, ~file, declared); - } - } + let%opt md = Hashtbl.find_opt(file.stamps.modules, stamp); + let%opt (file, declared) = + References.resolveModuleReference(~file, ~getModule, md); + let (name, docstring) = + switch (declared) { + | Some(d) => (d.name.txt, d.docstring) + | None => (file.moduleName, file.contents.docstring) + }; + showModule(~docstring, ~name, ~file, declared); | LModule(GlobalReference(moduleName, path, tip)) => - switch (getModule(moduleName)) { - | None => None - | Some(file) => - let env = Query.fileEnv(file); - switch (Query.resolvePath(~env, ~path, ~getModule)) { - | None => None - | Some((env, name)) => - switch (Query.exportedForTip(~env, name, tip)) { - | None => None - | Some(stamp) => - switch (Hashtbl.find_opt(file.stamps.modules, stamp)) { - | None => None - | Some(md) => - switch (References.resolveModuleReference(~file, ~getModule, md)) { - | None => None - | Some((file, declared)) => - let (name, docstring) = - switch (declared) { - | Some(d) => (d.name.txt, d.docstring) - | None => (file.moduleName, file.contents.docstring) - }; - showModule(~docstring, ~name, ~file, declared); - } - } - } + let%opt file = getModule(moduleName); + let env = Query.fileEnv(file); + let%opt (env, name) = Query.resolvePath(~env, ~path, ~getModule); + let%opt stamp = Query.exportedForTip(~env, name, tip); + let%opt md = Hashtbl.find_opt(file.stamps.modules, stamp); + let%opt (file, declared) = + References.resolveModuleReference(~file, ~getModule, md); + let (name, docstring) = + switch (declared) { + | Some(d) => (d.name.txt, d.docstring) + | None => (file.moduleName, file.contents.docstring) }; - } + showModule(~docstring, ~name, ~file, declared); | LModule(NotFound) => None | TopLevelModule(name) => - switch (getModule(name)) { - | None => None - | Some(file) => - showModule( - ~docstring=file.contents.docstring, - ~name=file.moduleName, - ~file, - None, - ) - } + let%opt file = getModule(name); + showModule( + ~docstring=file.contents.docstring, + ~name=file.moduleName, + ~file, + None, + ); | Typed(_, Definition(_, Field(_) | Constructor(_))) => None | Constant(t) => Some( @@ -146,20 +117,15 @@ let newHover = (~file: SharedTypes.file, ~getModule, loc) => { let typeString = codeBlock(typ |> Shared.typeToString); let extraTypeInfo = { let env = Query.fileEnv(file); - switch (typ |> Shared.digConstructor) { - | None => None - | Some(path) => - switch (digConstructor(~env, ~getModule, path)) { - | None => None - | Some((_env, {docstring, name: {txt}, item: {decl}})) => - let isUncurriedInternal = - Utils.startsWith(Path.name(path), "Js.Fn.arity"); - if (isUncurriedInternal) { - None; - } else { - Some((decl |> Shared.declToString(txt), docstring)); - }; - } + let%opt path = typ |> Shared.digConstructor; + let%opt (_env, {docstring, name: {txt}, item: {decl}}) = + digConstructor(~env, ~getModule, path); + let isUncurriedInternal = + Utils.startsWith(Path.name(path), "Js.Fn.arity"); + if (isUncurriedInternal) { + None; + } else { + Some((decl |> Shared.declToString(txt), docstring)); }; }; let (typeString, docstring) = diff --git a/src/rescript-editor-support/MessageHandlers.re b/src/rescript-editor-support/MessageHandlers.re index dd4029a8..0c135c4c 100644 --- a/src/rescript-editor-support/MessageHandlers.re +++ b/src/rescript-editor-support/MessageHandlers.re @@ -8,427 +8,348 @@ let handlers: ( "textDocument/definition", (state, params) => { - switch (Protocol.rPositionParams(params)) { - | Error(e) => Error(e) - | Ok((uri, pos)) => - switch (State.getFullFromCmt(~state, ~uri)) { - | Error(e) => Error(e) - | Ok((package, {file, extra})) => - let position = Utils.cmtLocFromVscode(pos); - ( - switch ( - References.definitionForPos( - ~pathsForModule=package.pathsForModule, - ~file, - ~extra, - ~getUri=State.fileForUri(state), - ~getModule=State.fileForModule(state, ~package), - position, - ) - ) { - | None => None - | Some((uri, loc)) => - Some( - Ok(( - state, - Json.Object([ - ("uri", Json.String(Uri2.toString(uri))), - ("range", Protocol.rangeOfLoc(loc)), - ]), - )), - ); - } - ) - |? Ok((state, Json.Null)); - } + let%try (uri, pos) = Protocol.rPositionParams(params); + let%try (package, {file, extra}) = State.getFullFromCmt(~state, ~uri); + + let position = Utils.cmtLocFromVscode(pos); + + { + let%opt (uri, loc) = + References.definitionForPos( + ~pathsForModule=package.pathsForModule, + ~file, + ~extra, + ~getUri=State.fileForUri(state), + ~getModule=State.fileForModule(state, ~package), + position, + ); + Some( + Ok(( + state, + Json.Object([ + ("uri", Json.String(Uri2.toString(uri))), + ("range", Protocol.rangeOfLoc(loc)), + ]), + )), + ); } - } + |? Ok((state, Json.Null)); + }, ), ( "textDocument/completion", (state, params) => { - switch (Protocol.rPositionParams(params)) { - | Error(e) => Error(e) - | Ok((uri, pos)) => - let maybeText = - switch (Hashtbl.find_opt(state.documentText, uri)) { - | Some(text) => Some(text) - | None => None - }; - switch (State.getFullFromCmt(~state, ~uri)) { - | Error(e) => Error(e) - | Ok((package, full)) => - let completions = - NewCompletions.computeCompletions( - ~full, - ~maybeText, - ~package, - ~pos, - ~state, - ); - Ok((state, completions)); + let%try (uri, pos) = Protocol.rPositionParams(params); + let maybeText = + switch (Hashtbl.find_opt(state.documentText, uri)) { + | Some(text) => Some(text) + | None => None }; - } - } + let%try (package, full) = State.getFullFromCmt(~state, ~uri); + let completions = + NewCompletions.computeCompletions( + ~full, + ~maybeText, + ~package, + ~pos, + ~state, + ); + Ok((state, completions)); + }, ), ( "textDocument/documentHighlight", (state, params) => { - switch (Protocol.rPositionParams(params)) { - | Error(e) => Error(e) - | Ok((uri, pos)) => - let pos = Utils.cmtLocFromVscode(pos); - let refs = - switch (State.fileForUri(state, uri) |> toOptionAndLog) { - | None => None - | Some((file, extra)) => References.refsForPos(~file, ~extra, pos) - }; - Ok(( - state, - switch (refs) { - | None => J.null - | Some(refs) => - J.l( - refs - |> List.map(loc => - J.o([ - ("range", Protocol.rangeOfLoc(loc)), - ("kind", J.i(2)), - ]) - ), - ) - }, - )); - } - } + let%try (uri, pos) = Protocol.rPositionParams(params); + + let pos = Utils.cmtLocFromVscode(pos); + let refs = + switch (State.fileForUri(state, uri) |> toOptionAndLog) { + | None => None + | Some((file, extra)) => References.refsForPos(~file, ~extra, pos) + }; + Ok(( + state, + switch (refs) { + | None => J.null + | Some(refs) => + J.l( + refs + |> List.map(loc => + J.o([ + ("range", Protocol.rangeOfLoc(loc)), + ("kind", J.i(2)), + ]) + ), + ) + }, + )); + }, ), ( "textDocument/references", (state, params) => { - switch (Protocol.rPositionParams(params)) { - | Error(e) => Error(e) - | Ok((uri, pos)) => - switch (Packages.getPackage(uri, state)) { - | Error(e) => Error(e) - | Ok(package) => - switch (State.fileForUri(state, uri)) { - | Error(e) => Error(e) - | Ok((file, extra)) => - Ok( - Infix.( - ( - switch ( - References.locForPos(~extra, Utils.cmtLocFromVscode(pos)) - ) { - | None => None - | Some((_, loc)) => - switch ( - References.allReferencesForLoc( - ~pathsForModule=package.pathsForModule, - ~file, - ~extra, - ~allModules=package.localModules, - ~getUri=State.fileForUri(state), - ~getModule=State.fileForModule(state, ~package), - ~getExtra=State.extraForModule(state, ~package), - loc, - ) - |> toOptionAndLog - ) { - | None => None - | Some(allReferences) => - Some(( - state, - J.l( - allReferences - |> List.map(((fname, references)) => { - let locs = - fname == uri - ? List.filter( - loc => !Protocol.locationContains(loc, pos), - references, - ) - : references; - locs - |> List.map(loc => Protocol.locationOfLoc(~fname, loc)); - }) - |> List.concat, - ), - )); - } - } - ) - |? (state, J.null) - ), + let%try (uri, pos) = Protocol.rPositionParams(params); + let%try package = Packages.getPackage(uri, state); + let%try_wrap (file, extra) = State.fileForUri(state, uri); + Infix.( + { + let%opt (_, loc) = + References.locForPos(~extra, Utils.cmtLocFromVscode(pos)); + let%opt allReferences = + References.allReferencesForLoc( + ~pathsForModule=package.pathsForModule, + ~file, + ~extra, + ~allModules=package.localModules, + ~getUri=State.fileForUri(state), + ~getModule=State.fileForModule(state, ~package), + ~getExtra=State.extraForModule(state, ~package), + loc, ) - } + |> toOptionAndLog; + Some(( + state, + J.l( + allReferences + |> List.map(((fname, references)) => { + let locs = + fname == uri + ? List.filter( + loc => !Protocol.locationContains(loc, pos), + references, + ) + : references; + locs + |> List.map(loc => Protocol.locationOfLoc(~fname, loc)); + }) + |> List.concat, + ), + )); } - } - } + |? (state, J.null) + ); + }, ), ( "textDocument/rename", (state, params) => { - switch (Protocol.rPositionParams(params)) { - | Error(e) => Error(e) - | Ok((uri, pos)) => - switch (Packages.getPackage(uri, state)) { - | Error(e) => Error(e) - | Ok(package) => - switch (State.fileForUri(state, uri)) { - | Error(e) => Error(e) - | Ok((file, extra)) => - switch (RJson.get("newName", params)) { - | Error(e) => Error(e) - | Ok(newName) => - open Infix; - ( - switch ( - References.locForPos(~extra, Utils.cmtLocFromVscode(pos)) - ) { - | None => None - | Some((_, loc)) => - switch ( - References.allReferencesForLoc( - ~file, - ~extra, - ~pathsForModule=package.pathsForModule, - ~allModules=package.localModules, - ~getModule=State.fileForModule(state, ~package), - ~getUri=State.fileForUri(state), - ~getExtra=State.extraForModule(state, ~package), - loc, - ) - |> toOptionAndLog - ) { - | None => None - | Some(allReferences) => - Some( - Ok(( - state, - J.o([ - ( - "changes", - J.o( - allReferences - |> List.map(((fname, references)) => - ( - fname |> Uri2.toString, - J.l( - references - |> List.map(loc => - J.o([ - ( "range", Protocol.rangeOfLoc(loc)), - ("newText", newName), - ]) - ), - ), - ) - ), - ), - ), - ]), - ), - )) - } - } - ) - |? Ok((state, J.null)) - } - } + let%try (uri, pos) = Protocol.rPositionParams(params); + let%try package = Packages.getPackage(uri, state); + let%try (file, extra) = State.fileForUri(state, uri); + let%try newName = RJson.get("newName", params); + Infix.( + { + let%opt (_, loc) = + References.locForPos(~extra, Utils.cmtLocFromVscode(pos)); + let%opt allReferences = + References.allReferencesForLoc( + ~file, + ~extra, + ~pathsForModule=package.pathsForModule, + ~allModules=package.localModules, + ~getModule=State.fileForModule(state, ~package), + ~getUri=State.fileForUri(state), + ~getExtra=State.extraForModule(state, ~package), + loc, + ) + |> toOptionAndLog; + Some( + Ok(( + state, + J.o([ + ( + "changes", + J.o( + allReferences + |> List.map(((fname, references)) => + ( + fname |> Uri2.toString, + J.l( + references + |> List.map(loc => + J.o([ + ("range", Protocol.rangeOfLoc(loc)), + ("newText", newName), + ]) + ), + ), + ) + ), + ), + ), + ]), + )), + ); } - } - } + |? Ok((state, J.null)) + ); + }, ), ( "textDocument/codeLens", (state, params) => { open InfixResult; - switch ( + let%try uri = params |> RJson.get("textDocument") |?> RJson.get("uri") - |?> RJson.string - ) { - | Error(e) => Error(e) - | Ok(uri) => - switch (Uri2.parse(uri) |> RResult.orError("Not a uri")) { - | Error(e) => Error(e) - | Ok(uri) => - /* Log.log("<< codleens me please"); */ - let topLoc = { - Location.loc_start: { - Lexing.pos_fname: "", - pos_lnum: 1, - pos_bol: 0, - pos_cnum: 0, - }, - Location.loc_end: { - Lexing.pos_fname: "", - pos_lnum: 1, - pos_bol: 0, - pos_cnum: 0, - }, - loc_ghost: false, - }; - let getLensItems = ({SharedTypes.file, extra}) => { - /* getTypeLensTopLevel gives the list of per-value type codeLens - for every value in a module topLevel */ - let rec getTypeLensTopLevel = topLevel => { - switch (topLevel) { - | [] => [] - | [{SharedTypes.name: {loc}, item}, ...tlp] => - let currentCl = - switch (item) { - | SharedTypes.MValue(typ) => [ - (typ |> Shared.typeToString, loc), - ] - | Module(Structure({topLevel})) => - getTypeLensTopLevel(topLevel) - | _ => [] - }; - List.append(currentCl, getTypeLensTopLevel(tlp)); + |?> RJson.string; + let%try uri = Uri2.parse(uri) |> RResult.orError("Not a uri"); + + /* Log.log("<< codleens me please"); */ + + let topLoc = { + Location.loc_start: { + Lexing.pos_fname: "", + pos_lnum: 1, + pos_bol: 0, + pos_cnum: 0, + }, + Location.loc_end: { + Lexing.pos_fname: "", + pos_lnum: 1, + pos_bol: 0, + pos_cnum: 0, + }, + loc_ghost: false, + }; + + let getLensItems = ({SharedTypes.file, extra}) => { + /* getTypeLensTopLevel gives the list of per-value type codeLens + for every value in a module topLevel */ + let rec getTypeLensTopLevel = topLevel => { + switch (topLevel) { + | [] => [] + | [{SharedTypes.name: {loc}, item}, ...tlp] => + let currentCl = + switch (item) { + | SharedTypes.MValue(typ) => [ + (typ |> Shared.typeToString, loc), + ] + | Module(Structure({topLevel})) => + getTypeLensTopLevel(topLevel) + | _ => [] }; - }; - let lenses = file.contents.topLevel |> getTypeLensTopLevel; - let lenses = lenses @ CodeLens.forOpens(extra); - let depsList = - List.map(fst, SharedTypes.hashList(extra.externalReferences)); - let depsString = - depsList == [] ? "[none]" : String.concat(", ", depsList); - let lenses = [("Dependencies: " ++ depsString, topLoc), ...lenses]; - lenses; + List.append(currentCl, getTypeLensTopLevel(tlp)); }; - let items = - switch (State.getFullFromCmt(~state, ~uri)) { - | Error(message) => [(message, topLoc)] - | Ok((_package, full)) => getLensItems(full) - }; - Ok(( - state, - J.l( - items - |> List.map(((text, loc)) => - J.o([ - ("range", Protocol.rangeOfLoc(loc)), - ( - "command", - J.o([("title", J.s(text)), ("command", J.s(""))]), - ), - ]) - ), - ), - )); - } - } + }; + let lenses = file.contents.topLevel |> getTypeLensTopLevel; + let lenses = lenses @ CodeLens.forOpens(extra); + + let depsList = + List.map(fst, SharedTypes.hashList(extra.externalReferences)); + let depsString = + depsList == [] ? "[none]" : String.concat(", ", depsList); + let lenses = [("Dependencies: " ++ depsString, topLoc), ...lenses]; + + lenses; + }; - } + let items = { + switch (State.getFullFromCmt(~state, ~uri)) { + | Error(message) => [(message, topLoc)] + | Ok((_package, full)) => getLensItems(full) + }; + }; + Ok(( + state, + J.l( + items + |> List.map(((text, loc)) => + J.o([ + ("range", Protocol.rangeOfLoc(loc)), + ( + "command", + J.o([("title", J.s(text)), ("command", J.s(""))]), + ), + ]) + ), + ), + )); + }, ), ( "textDocument/hover", (state, params) => { - switch (Protocol.rPositionParams(params)) { - | Error(e) => Error(e) - | Ok((uri, pos)) => - switch (Packages.getPackage(uri, state)) { - | Error(e) => Error(e) - | Ok(package) => - switch (State.fileForUri(state, uri)) { - | Error(e) => Error(e) - | Ok((file, extra)) => - { - let pos = Utils.cmtLocFromVscode(pos); - switch (References.locForPos(~extra, pos)) { - | None => None - | Some((location, loc)) => - switch ( - Hover.newHover( - ~file, - ~getModule=State.fileForModule(state, ~package), - loc, - ) - ) { - | None => None - | Some(text) => - Some( - Ok(( - state, - J.o([ - ("range", Protocol.rangeOfLoc(location)), - ("contents", text |> Protocol.contentKind), - ]), - ), - )) - } - }; - } - |? Ok((state, J.null)) - } - } + let%try (uri, pos) = Protocol.rPositionParams(params); + let%try package = Packages.getPackage(uri, state); + let%try (file, extra) = State.fileForUri(state, uri); + + { + let pos = Utils.cmtLocFromVscode(pos); + let%opt (location, loc) = References.locForPos(~extra, pos); + let%opt text = + Hover.newHover( + ~file, + ~getModule=State.fileForModule(state, ~package), + loc, + ); + Some( + Ok(( + state, + J.o([ + ("range", Protocol.rangeOfLoc(location)), + ("contents", text |> Protocol.contentKind), + ]), + )), + ); } - } + |? Ok((state, J.null)); + }, ), ( "textDocument/documentSymbol", (state, params) => { open InfixResult; - switch ( + let%try uri = params |> RJson.get("textDocument") |?> RJson.get("uri") - |?> RJson.string - ) { - | Error(e) => Error(e) - | Ok(uri) => - switch (Uri2.parse(uri) |> RResult.orError("Not a uri")) { - | Error(e) => Error(e) - | Ok(uri) => - switch (State.fileForUri(state, uri)) { - | Error(e) => Error(e) - | Ok((file, _extra)) => - open SharedTypes; + |?> RJson.string; + let%try uri = Uri2.parse(uri) |> RResult.orError("Not a uri"); - let rec getItems = ({topLevel}) => { - let fn = ({name: {txt}, extentLoc, item}) => { - let (item, siblings) = - switch (item) { - | MValue(v) => (v |> Shared.variableKind, []) - | MType(t, _) => (t.decl |> Shared.declarationKind, []) - | Module(Structure(contents)) => (Module, getItems(contents)) - | Module(Ident(_)) => (Module, []) - }; - if (extentLoc.loc_ghost) { - siblings; - } else { - [(txt, extentLoc, item), ...siblings]; - }; - }; - let x = topLevel |> List.map(fn) |> List.concat; - x; + let%try (file, _extra) = State.fileForUri(state, uri); + open SharedTypes; + + let rec getItems = ({topLevel}) => { + let fn = ({name: {txt}, extentLoc, item}) => { + let (item, siblings) = + switch (item) { + | MValue(v) => (v |> Shared.variableKind, []) + | MType(t, _) => (t.decl |> Shared.declarationKind, []) + | Module(Structure(contents)) => (Module, getItems(contents)) + | Module(Ident(_)) => (Module, []) }; + if (extentLoc.loc_ghost) { + siblings; + } else { + [(txt, extentLoc, item), ...siblings]; + }; + }; + let x = topLevel |> List.map(fn) |> List.concat; + x; + }; - getItems(file.contents) - |> ( - items => { - Ok(( - state, - J.l( - items - |> List.map(((name, loc, typ)) => - J.o([ - ("name", J.s(name)), - ("kind", J.i(Protocol.symbolKind(typ))), - ("location", Protocol.locationOfLoc(loc)), - /* ("containerName", s(String.concat(".", path))) */ - ]) - ), - ), - )); - } - ); - } + getItems(file.contents) + |> ( + items => { + Ok(( + state, + J.l( + items + |> List.map(((name, loc, typ)) => + J.o([ + ("name", J.s(name)), + ("kind", J.i(Protocol.symbolKind(typ))), + ("location", Protocol.locationOfLoc(loc)), + /* ("containerName", s(String.concat(".", path))) */ + ]) + ), + ), + )); } - } - } + ); + }, ), ]; diff --git a/src/rescript-editor-support/NewCompletions.re b/src/rescript-editor-support/NewCompletions.re index 87c30783..db0d1055 100644 --- a/src/rescript-editor-support/NewCompletions.re +++ b/src/rescript-editor-support/NewCompletions.re @@ -220,14 +220,11 @@ let getEnvWithOpens = | Tip(_) => None | Nested(top, path) => Log.log("Getting module " ++ top); - switch (getModule(top)) { - | None => None - | Some(file) => - Log.log("got it"); - let env = Query.fileEnv(file); - Query.resolvePath(~env, ~getModule, ~path) - |> Infix.logIfAbsent("Unable to resolve the path"); - }; + let%opt file = getModule(top); + Log.log("got it"); + let env = Query.fileEnv(file); + Query.resolvePath(~env, ~getModule, ~path) + |> Infix.logIfAbsent("Unable to resolve the path"); } }; loop(opens); @@ -522,66 +519,44 @@ let getItems = | [] => None | [first, ...rest] => Log.log("-------------- Looking for " ++ first); - switch (Query.findInScope(pos, first, env.file.stamps.values)) { - | None => None - | Some(declared) => - Log.log("Found it! " ++ declared.name.txt); - switch (declared.item |> Shared.digConstructor) { - | None => None - | Some(path) => - switch (Hover.digConstructor(~env, ~getModule, path)) { - | None => None - | Some((env, typ)) => - switch ( - rest - |> List.fold_left( - (current, name) => - switch (current) { - | None => None - | Some((env, typ)) => - switch (typ.item.SharedTypes.Type.kind) { - | Record(fields) => - switch ( - fields - |> List.find_opt(f => f.fname.txt == name) - ) { - | None => None - | Some(attr) => - Log.log("Found attr " ++ name); - switch (attr.typ |> Shared.digConstructor) { - | None => None - | Some(path) => - Hover.digConstructor(~env, ~getModule, path) - }; - } - | _ => None - } - }, - Some((env, typ)), - ) - ) { - | None => None - | Some((env, typ)) => - switch (typ.item.kind) { - | Record(fields) => - Some( - fields - |> Utils.filterMap(f => - if (Utils.startsWith(f.fname.txt, suffix)) { - Some(( - env.file.uri, - {...emptyDeclared(f.fname.txt), item: Field(f, typ)}, - )); - } else { - None; - } - ), - ) - | _ => None - } - } - } - }; + let%opt declared = + Query.findInScope(pos, first, env.file.stamps.values); + Log.log("Found it! " ++ declared.name.txt); + let%opt path = declared.item |> Shared.digConstructor; + let%opt (env, typ) = Hover.digConstructor(~env, ~getModule, path); + let%opt (env, typ) = + rest + |> List.fold_left( + (current, name) => { + let%opt (env, typ) = current; + switch (typ.item.SharedTypes.Type.kind) { + | Record(fields) => + let%opt attr = + fields |> List.find_opt(f => f.fname.txt == name); + Log.log("Found attr " ++ name); + let%opt path = attr.typ |> Shared.digConstructor; + Hover.digConstructor(~env, ~getModule, path); + | _ => None + }; + }, + Some((env, typ)), + ); + switch (typ.item.kind) { + | Record(fields) => + Some( + fields + |> Utils.filterMap(f => + if (Utils.startsWith(f.fname.txt, suffix)) { + Some(( + env.file.uri, + {...emptyDeclared(f.fname.txt), item: Field(f, typ)}, + )); + } else { + None; + } + ), + ) + | _ => None }; }; } diff --git a/src/rescript-editor-support/NotificationHandlers.re b/src/rescript-editor-support/NotificationHandlers.re index 56be5515..7599b405 100644 --- a/src/rescript-editor-support/NotificationHandlers.re +++ b/src/rescript-editor-support/NotificationHandlers.re @@ -3,58 +3,48 @@ open RResult; open TopTypes; module J = JsonShort; -let getTextDocument = doc => - switch (Json.get("uri", doc) |?> Json.string |?> Uri2.parse) { - | None => None - | Some(uri) => - switch (Json.get("text", doc) |?> Json.string) { - | None => None - | Some(text) => Some((uri, text)) - } - }; +let getTextDocument = doc => { + let%opt uri = Json.get("uri", doc) |?> Json.string |?> Uri2.parse; + let%opt text = Json.get("text", doc) |?> Json.string; + Some((uri, text)); +}; let notificationHandlers: list((string, (state, Json.t) => result(state, string))) = [ ( "textDocument/didOpen", (state, params) => { - switch ( + let%try (uri, text) = Json.get("textDocument", params) |?> getTextDocument - |> RResult.orError("Invalid params") - ) { - | Error(e) => Error(e) - | Ok((uri, text)) => - Hashtbl.replace(state.documentText, uri, text); - let path = Uri2.toPath(uri); - if (FindFiles.isSourceFile(path)) { - switch (Packages.getPackage(uri, state)) { - | Error(e) => Error(e) - | Ok(package) => - /* let name = FindFiles.getName(path); */ - if (!Hashtbl.mem(package.nameForPath, path)) { - /* TODO: figure out what the name should be, and process it. */ - package.nameForPath - |> Hashtbl.iter((name, _) => Log.log(" > " ++ name)); - Log.log("Reloading because you created a new file: " ++ path); - Ok(state); - /* Ok(reloadAllState(state)) */ - /* Hashtbl.add(package.nameForPath, path, name); - Hashtbl.add(package.pathsForModule, name, Impl(path, Some(path))); - Hashtbl.replace(state.packagesByRoot, package.basePath, { - ...package, - localModules: [name, ...package.localModules] - }); - Ok(state) */ - } else { - Ok(state); - } - }; + |> RResult.orError("Invalid params"); + Hashtbl.replace(state.documentText, uri, text); + + let path = Uri2.toPath(uri); + if (FindFiles.isSourceFile(path)) { + let%try package = Packages.getPackage(uri, state); + /* let name = FindFiles.getName(path); */ + if (!Hashtbl.mem(package.nameForPath, path)) { + /* TODO: figure out what the name should be, and process it. */ + package.nameForPath + |> Hashtbl.iter((name, _) => Log.log(" > " ++ name)); + Log.log("Reloading because you created a new file: " ++ path); + Ok(state); + /* Ok(reloadAllState(state)) */ + /* Hashtbl.add(package.nameForPath, path, name); + Hashtbl.add(package.pathsForModule, name, Impl(path, Some(path))); + Hashtbl.replace(state.packagesByRoot, package.basePath, { + ...package, + localModules: [name, ...package.localModules] + }); + Ok(state) */ } else { Ok(state); }; - } - } + } else { + Ok(state); + }; + }, ), ( "workspace/didChangeConfiguration", @@ -72,34 +62,18 @@ let notificationHandlers: "textDocument/didChange", (state, params) => { open InfixResult; - switch (params |> RJson.get("textDocument")) { - | Error(e) => Error(e) - | Ok(doc) => - switch (RJson.get("uri", doc) |?> RJson.string) { - | Error(e) => Error(e) - | Ok(uri) => - switch (Uri2.parse(uri) |> RResult.orError("Not a uri")) { - | Error(e) => Error(e) - | Ok(uri) => - switch (RJson.get("contentChanges", params) |?> RJson.array) { - | Error(e) => Error(e) - | Ok(changes) => - switch ( - List.nth(changes, List.length(changes) - 1) - |> RJson.get("text") - |?> RJson.string - ) { - | Error(e) => Error(e) - | Ok(text) => - /* Hmm how do I know if it's modified? */ - let state = State.updateContents(uri, text, state); - Ok(state); - } - } - } - } - } - } + let%try doc = params |> RJson.get("textDocument"); + let%try uri = RJson.get("uri", doc) |?> RJson.string; + let%try uri = Uri2.parse(uri) |> RResult.orError("Not a uri"); + let%try changes = RJson.get("contentChanges", params) |?> RJson.array; + let%try text = + List.nth(changes, List.length(changes) - 1) + |> RJson.get("text") + |?> RJson.string; + /* Hmm how do I know if it's modified? */ + let state = State.updateContents(uri, text, state); + Ok(state); + }, ), ( "workspace/didChangeWatchedFiles", diff --git a/src/rescript-editor-support/Packages.re b/src/rescript-editor-support/Packages.re index dd6aff32..16f1d6c7 100644 --- a/src/rescript-editor-support/Packages.re +++ b/src/rescript-editor-support/Packages.re @@ -50,116 +50,105 @@ let makePathsForModule = (pathsForModule, nameForPath); }; -let newBsPackage = rootPath => - switch (Files.readFileResult(rootPath /+ "bsconfig.json")) { - | Error(e) => Error(e) - | Ok(raw) => - let config = Json.parse(raw); - - Log.log({|📣 📣 NEW BSB PACKAGE 📣 📣|}); - /* failwith("Wat"); */ - Log.log("- location: " ++ rootPath); - - let compiledBase = BuildSystem.getCompiledBase(rootPath); - switch (FindFiles.findDependencyFiles(~debug=true, rootPath, config)) { - | Error(e) => Error(e) - | Ok((dependencyDirectories, dependencyModules)) => - switch ( - compiledBase - |> RResult.orError( - "You need to run bsb first so that reason-language-server can access the compiled artifacts.\nOnce you've run bsb, restart the language server.", - ) - ) { - | Error(e) => Error(e) - | Ok(compiledBase) => - Ok( - { - let namespace = FindFiles.getNamespace(config); - let localSourceDirs = - FindFiles.getSourceDirectories(~includeDev=true, rootPath, config); - Log.log( - "Got source directories " ++ String.concat(" - ", localSourceDirs), - ); - let localModules = - FindFiles.findProjectFiles( - ~debug=true, - namespace, - rootPath, - localSourceDirs, - compiledBase, - ); - /* |> List.map(((name, paths)) => (switch (namespace) { - | None => name - | Some(n) => name ++ "-" ++ n }, paths)); */ - Log.log( - "-- All local modules found: " - ++ string_of_int(List.length(localModules)), - ); - localModules - |> List.iter(((name, paths)) => { - Log.log(name); - switch (paths) { - | SharedTypes.Impl(cmt, _) => Log.log("impl " ++ cmt) - | Intf(cmi, _) => Log.log("intf " ++ cmi) - | _ => Log.log("Both") - }; - }); - - let (pathsForModule, nameForPath) = - makePathsForModule(localModules, dependencyModules); - - let opens = - switch (namespace) { - | None => [] - | Some(namespace) => - let cmt = compiledBase /+ namespace ++ ".cmt"; - Log.log("############ Namespaced as " ++ namespace ++ " at " ++ cmt); - Hashtbl.add(pathsForModule, namespace, Impl(cmt, None)); - [FindFiles.nameSpaceToName(namespace)]; - }; - Log.log("Dependency dirs " ++ String.concat(" ", dependencyDirectories)); - - let opens = { - let flags = - MerlinFile.getFlags(rootPath) - |> RResult.withDefault([""]) - |> List.map(escapePreprocessingFlags); - let opens = - List.fold_left( - (opens, item) => { - let parts = Utils.split_on_char(' ', item); - let rec loop = items => - switch (items) { - | ["-open", name, ...rest] => [name, ...loop(rest)] - | [_, ...rest] => loop(rest) - | [] => [] - }; - opens @ loop(parts); - }, - opens, - flags, - ); - opens; - }; +let newBsPackage = rootPath => { + let%try raw = Files.readFileResult(rootPath /+ "bsconfig.json"); + let config = Json.parse(raw); - let interModuleDependencies = Hashtbl.create(List.length(localModules)); - - { - rootPath, - localModules: localModules |> List.map(fst), - dependencyModules: dependencyModules |> List.map(fst), - pathsForModule, - nameForPath, - opens, - namespace, - interModuleDependencies, - }; - }, - ) - } + Log.log({|📣 📣 NEW BSB PACKAGE 📣 📣|}); + /* failwith("Wat"); */ + Log.log("- location: " ++ rootPath); + + let compiledBase = BuildSystem.getCompiledBase(rootPath); + let%try (dependencyDirectories, dependencyModules) = + FindFiles.findDependencyFiles(~debug=true, rootPath, config); + let%try_wrap compiledBase = + compiledBase + |> RResult.orError( + "You need to run bsb first so that reason-language-server can access the compiled artifacts.\nOnce you've run bsb, restart the language server.", + ); + + let namespace = FindFiles.getNamespace(config); + let localSourceDirs = + FindFiles.getSourceDirectories(~includeDev=true, rootPath, config); + Log.log( + "Got source directories " ++ String.concat(" - ", localSourceDirs), + ); + let localModules = + FindFiles.findProjectFiles( + ~debug=true, + namespace, + rootPath, + localSourceDirs, + compiledBase, + ); + /* |> List.map(((name, paths)) => (switch (namespace) { + | None => name + | Some(n) => name ++ "-" ++ n }, paths)); */ + Log.log( + "-- All local modules found: " + ++ string_of_int(List.length(localModules)), + ); + localModules + |> List.iter(((name, paths)) => { + Log.log(name); + switch (paths) { + | SharedTypes.Impl(cmt, _) => Log.log("impl " ++ cmt) + | Intf(cmi, _) => Log.log("intf " ++ cmi) + | _ => Log.log("Both") + }; + }); + + let (pathsForModule, nameForPath) = + makePathsForModule(localModules, dependencyModules); + + let opens = + switch (namespace) { + | None => [] + | Some(namespace) => + let cmt = compiledBase /+ namespace ++ ".cmt"; + Log.log("############ Namespaced as " ++ namespace ++ " at " ++ cmt); + Hashtbl.add(pathsForModule, namespace, Impl(cmt, None)); + [FindFiles.nameSpaceToName(namespace)]; }; + Log.log("Dependency dirs " ++ String.concat(" ", dependencyDirectories)); + + let opens = { + let flags = + MerlinFile.getFlags(rootPath) + |> RResult.withDefault([""]) + |> List.map(escapePreprocessingFlags); + let opens = + List.fold_left( + (opens, item) => { + let parts = Utils.split_on_char(' ', item); + let rec loop = items => + switch (items) { + | ["-open", name, ...rest] => [name, ...loop(rest)] + | [_, ...rest] => loop(rest) + | [] => [] + }; + opens @ loop(parts); + }, + opens, + flags, + ); + opens; }; + let interModuleDependencies = Hashtbl.create(List.length(localModules)); + + { + rootPath, + localModules: localModules |> List.map(fst), + dependencyModules: dependencyModules |> List.map(fst), + pathsForModule, + nameForPath, + opens, + namespace, + interModuleDependencies, + }; +}; + let findRoot = (~uri, packagesByRoot) => { let path = Uri2.toPath(uri); let rec loop = path => @@ -184,34 +173,25 @@ let getPackage = (~uri, state) => ), ); } else { - switch ( + let%try root = findRoot(~uri, state.packagesByRoot) - |> RResult.orError("No root directory found") - ) { - | Error(e) => Error(e) - | Ok(root) => - switch ( - switch (root) { - | `Root(rootPath) => - Hashtbl.replace(state.rootForUri, uri, rootPath); - Ok( - Hashtbl.find( - state.packagesByRoot, - Hashtbl.find(state.rootForUri, uri), - ), - ); - | `Bs(rootPath) => - switch (newBsPackage(rootPath)) { - | Error(e) => Error(e) - | Ok(package) => - Hashtbl.replace(state.rootForUri, uri, package.rootPath); - Hashtbl.replace(state.packagesByRoot, package.rootPath, package); - Ok(package); - } - } - ) { - | Error(e) => Error(e) - | Ok(package) => Ok(package) - } - }; + |> RResult.orError("No root directory found"); + let%try package = + switch (root) { + | `Root(rootPath) => + Hashtbl.replace(state.rootForUri, uri, rootPath); + Ok( + Hashtbl.find( + state.packagesByRoot, + Hashtbl.find(state.rootForUri, uri), + ), + ); + | `Bs(rootPath) => + let%try package = newBsPackage(rootPath); + Hashtbl.replace(state.rootForUri, uri, package.rootPath); + Hashtbl.replace(state.packagesByRoot, package.rootPath, package); + Ok(package); + }; + + Ok(package); }; diff --git a/src/rescript-editor-support/ProcessExtra.re b/src/rescript-editor-support/ProcessExtra.re index 6d033dc8..04dba6b4 100644 --- a/src/rescript-editor-support/ProcessExtra.re +++ b/src/rescript-editor-support/ProcessExtra.re @@ -29,31 +29,30 @@ let rec relative = (ident, path) => | _ => None }; -let findClosestMatchingOpen = (opens, path, ident, loc) => - switch (relative(ident, path)) { - | None => None - | Some(openNeedle) => - let matching = - Hashtbl.fold( - (_, op, res) => - if (Utils.locWithinLoc(loc, op.extent) - && Path.same(op.path, openNeedle)) { - [op, ...res]; - } else { - res; - }, - opens, - [], - ) - |> List.sort((a: SharedTypes.openTracker, b) => - b.loc.loc_start.pos_cnum - a.loc.loc_start.pos_cnum - ); +let findClosestMatchingOpen = (opens, path, ident, loc) => { + let%opt openNeedle = relative(ident, path); + + let matching = + Hashtbl.fold( + (_, op, res) => + if (Utils.locWithinLoc(loc, op.extent) + && Path.same(op.path, openNeedle)) { + [op, ...res]; + } else { + res; + }, + opens, + [], + ) + |> List.sort((a: SharedTypes.openTracker, b) => + b.loc.loc_start.pos_cnum - a.loc.loc_start.pos_cnum + ); - switch (matching) { - | [] => None - | [first, ..._] => Some(first) - }; + switch (matching) { + | [] => None + | [first, ..._] => Some(first) }; +}; let getTypeAtPath = (~env, path) => { switch (Query.fromCompilerPath(~env, path)) { @@ -61,16 +60,14 @@ let getTypeAtPath = (~env, path) => { | `Global(moduleName, path) => `Global((moduleName, path)) | `Not_found => `Not_found | `Exported(env, name) => - let res = - switch (Hashtbl.find_opt(env.exported.types, name)) { + let res = { + let%opt stamp = Hashtbl.find_opt(env.exported.types, name); + let declaredType = Hashtbl.find_opt(env.file.stamps.types, stamp); + switch (declaredType) { + | Some(declaredType) => Some(`Local(declaredType)) | None => None - | Some(stamp) => - let declaredType = Hashtbl.find_opt(env.file.stamps.types, stamp); - switch (declaredType) { - | Some(declaredType) => Some(`Local(declaredType)) - | None => None - }; }; + }; res |? `Not_found; | `Stamp(stamp) => let res = { @@ -94,16 +91,13 @@ module F = ) => { let extra = Collector.extra; - let maybeAddUse = (path, ident, loc, tip) => - switch (findClosestMatchingOpen(extra.opens, path, ident, loc)) { - | None => () - | Some(tracker) => - switch (Query.makeRelativePath(tracker.path, path)) { - | None => () - | Some(relpath) => - tracker.used = [(relpath, tip, loc), ...tracker.used] - } - }; + let maybeAddUse = (path, ident, loc, tip) => { + let%opt_consume tracker = + findClosestMatchingOpen(extra.opens, path, ident, loc); + let%opt_consume relpath = Query.makeRelativePath(tracker.path, path); + + tracker.used = [(relpath, tip, loc), ...tracker.used]; + }; let addLocation = (loc, ident) => extra.locations = [(loc, ident), ...extra.locations]; diff --git a/src/rescript-editor-support/Process_406.re b/src/rescript-editor-support/Process_406.re index 673000a3..f5918f79 100644 --- a/src/rescript-editor-support/Process_406.re +++ b/src/rescript-editor-support/Process_406.re @@ -1,18 +1,15 @@ open SharedTypes; -let fileForCmt = (~moduleName, ~uri, cmt, processDoc) => - switch (Shared.tryReadCmt(cmt)) { - | Error(e) => Error(e) - | Ok(infos) => Ok(ProcessCmt.forCmt(~moduleName, ~uri, processDoc, infos)) - }; +let fileForCmt = (~moduleName, ~uri, cmt, processDoc) => { + let%try infos = Shared.tryReadCmt(cmt); + Ok(ProcessCmt.forCmt(~moduleName, ~uri, processDoc, infos)); +}; -let fullForCmt = (~moduleName, ~uri, cmt, processDoc) => - switch (Shared.tryReadCmt(cmt)) { - | Error(e) => Error(e) - | Ok(infos) => - let file = ProcessCmt.forCmt(~moduleName, ~uri, processDoc, infos); - let extra = ProcessExtra.forCmt(~file, infos); - Ok({file, extra}); - }; +let fullForCmt = (~moduleName, ~uri, cmt, processDoc) => { + let%try infos = Shared.tryReadCmt(cmt); + let file = ProcessCmt.forCmt(~moduleName, ~uri, processDoc, infos); + let extra = ProcessExtra.forCmt(~file, infos); + Ok({file, extra}); +}; module PrintType = PrintType; diff --git a/src/rescript-editor-support/Protocol.re b/src/rescript-editor-support/Protocol.re index 44dc53da..3b6aae4e 100644 --- a/src/rescript-editor-support/Protocol.re +++ b/src/rescript-editor-support/Protocol.re @@ -2,32 +2,18 @@ module J = JsonShort; let rgetPosition = pos => { open RResult.InfixResult; - switch (RJson.get("line", pos) |?> RJson.number) { - | Error(e) => Error(e) - | Ok(line) => - switch (RJson.get("character", pos) |?> RJson.number) { - | Error(e) => Error(e) - | Ok(character) => Ok((int_of_float(line), int_of_float(character))) - } - } + let%try line = RJson.get("line", pos) |?> RJson.number; + let%try character = RJson.get("character", pos) |?> RJson.number; + Ok((int_of_float(line), int_of_float(character))); }; let rPositionParams = params => { open RResult.InfixResult; - switch ( - RJson.get("textDocument", params) |?> RJson.get("uri") |?> RJson.string - ) { - | Error(e) => Error(e) - | Ok(uri) => - switch (Uri2.parse(uri) |> RResult.orError("Not a uri")) { - | Error(e) => Error(e) - | Ok(uri) => - switch (RJson.get("position", params) |?> rgetPosition) { - | Error(e) => Error(e) - | Ok(pos) => Ok((uri, pos)) - } - } - } + let%try uri = + RJson.get("textDocument", params) |?> RJson.get("uri") |?> RJson.string; + let%try uri = Uri2.parse(uri) |> RResult.orError("Not a uri"); + let%try pos = RJson.get("position", params) |?> rgetPosition; + Ok((uri, pos)); }; let posOfLexing = ({Lexing.pos_lnum, pos_cnum, pos_bol}) => diff --git a/src/rescript-editor-support/Query.re b/src/rescript-editor-support/Query.re index 37b59356..3a84d043 100644 --- a/src/rescript-editor-support/Query.re +++ b/src/rescript-editor-support/Query.re @@ -80,15 +80,10 @@ let rec resolvePathInner = (~env, ~path) => { switch (path) { | Tip(name) => Some(`Local((env, name))) | Nested(subName, subPath) => - switch (Hashtbl.find_opt(env.exported.modules, subName)) { - | None => None - | Some(stamp) => - switch (Hashtbl.find_opt(env.file.stamps.modules, stamp)) { - | None => None - | Some({item: kind}) => findInModule(~env, kind, subPath) - } - } - } + let%opt stamp = Hashtbl.find_opt(env.exported.modules, subName); + let%opt {item: kind} = Hashtbl.find_opt(env.file.stamps.modules, stamp); + findInModule(~env, kind, subPath); + }; } and findInModule = (~env, kind, path) => { switch (kind) { @@ -99,10 +94,9 @@ and findInModule = (~env, kind, path) => { if (stamp == 0) { Some(`Global((moduleName, fullPath))); } else { - switch (Hashtbl.find_opt(env.file.stamps.modules, stamp)) { - | None => None - | Some({item: kind}) => findInModule(~env, kind, fullPath) - }; + let%opt {item: kind} = + Hashtbl.find_opt(env.file.stamps.modules, stamp); + findInModule(~env, kind, fullPath); }; }; }; @@ -110,18 +104,12 @@ and findInModule = (~env, kind, path) => { /* let rec findSubModule = (~env, ~getModule) */ let rec resolvePath = (~env, ~path, ~getModule) => { - switch (resolvePathInner(~env, ~path)) { - | None => None - | Some(result) => - switch (result) { - | `Local(env, name) => Some((env, name)) - | `Global(moduleName, fullPath) => - switch (getModule(moduleName)) { - | None => None - | Some(file) => - resolvePath(~env=fileEnv(file), ~path=fullPath, ~getModule) - } - } + let%opt result = resolvePathInner(~env, ~path); + switch (result) { + | `Local(env, name) => Some((env, name)) + | `Global(moduleName, fullPath) => + let%opt file = getModule(moduleName); + resolvePath(~env=fileEnv(file), ~path=fullPath, ~getModule); }; }; @@ -130,24 +118,15 @@ let resolveFromStamps = (~env, ~path, ~getModule, ~pos) => { | Tip(name) => Some((env, name)) | Nested(name, inner) => /* Log.log("Finding from stamps " ++ name); */ - switch (findInScope(pos, name, env.file.stamps.modules)) { - | None => None - | Some(declared) => - /* Log.log("found it"); */ - switch (findInModule(~env, declared.item, inner)) { - | None => None - | Some(res) => - switch (res) { - | `Local(env, name) => Some((env, name)) - | `Global(moduleName, fullPath) => - switch (getModule(moduleName)) { - | None => None - | Some(file) => - resolvePath(~env=fileEnv(file), ~path=fullPath, ~getModule) - } - } - } - } + let%opt declared = findInScope(pos, name, env.file.stamps.modules); + /* Log.log("found it"); */ + let%opt res = findInModule(~env, declared.item, inner); + switch (res) { + | `Local(env, name) => Some((env, name)) + | `Global(moduleName, fullPath) => + let%opt file = getModule(moduleName); + resolvePath(~env=fileEnv(file), ~path=fullPath, ~getModule); + }; }; }; @@ -175,45 +154,24 @@ let fromCompilerPath = (~env, path) => { let resolveModuleFromCompilerPath = (~env, ~getModule, path) => { switch (fromCompilerPath(~env, path)) { | `Global(moduleName, path) => - switch (getModule(moduleName)) { - | None => None - | Some(file) => - let env = fileEnv(file); - switch (resolvePath(~env, ~getModule, ~path)) { - | None => None - | Some((env, name)) => - switch (Hashtbl.find_opt(env.exported.modules, name)) { - | None => None - | Some(stamp) => - switch (Hashtbl.find_opt(env.file.stamps.modules, stamp)) { - | None => None - | Some(declared) => Some((env, Some(declared))) - } - } - }; - } + let%opt file = getModule(moduleName); + let env = fileEnv(file); + let%opt (env, name) = resolvePath(~env, ~getModule, ~path); + let%opt stamp = Hashtbl.find_opt(env.exported.modules, name); + let%opt declared = Hashtbl.find_opt(env.file.stamps.modules, stamp); + Some((env, Some(declared))); | `Stamp(stamp) => - switch (Hashtbl.find_opt(env.file.stamps.modules, stamp)) { - | None => None - | Some(declared) => Some((env, Some(declared))) - } + let%opt declared = Hashtbl.find_opt(env.file.stamps.modules, stamp); + Some((env, Some(declared))); | `GlobalMod(moduleName) => - switch (getModule(moduleName)) { - | None => None - | Some(file) => - let env = fileEnv(file); - Some((env, None)); - } + let%opt file = getModule(moduleName); + let env = fileEnv(file); + Some((env, None)); | `Not_found => None | `Exported(env, name) => - switch (Hashtbl.find_opt(env.exported.modules, name)) { - | None => None - | Some(stamp) => - switch (Hashtbl.find_opt(env.file.stamps.modules, stamp)) { - | None => None - | Some(declared) => Some((env, Some(declared))) - } - } + let%opt stamp = Hashtbl.find_opt(env.exported.modules, name); + let%opt declared = Hashtbl.find_opt(env.file.stamps.modules, stamp); + Some((env, Some(declared))); }; }; @@ -276,28 +234,21 @@ let declaredForTip = (~stamps, stamp, tip) => }; let getField = (file, stamp, name) => { - switch (Hashtbl.find_opt(file.stamps.types, stamp)) { - | None => None - | Some({item: {kind}}) => - switch (kind) { - | Record(fields) => fields |> List.find_opt(f => f.fname.txt == name) - | _ => None - } + let%opt {item: {kind}} = Hashtbl.find_opt(file.stamps.types, stamp); + switch (kind) { + | Record(fields) => fields |> List.find_opt(f => f.fname.txt == name) + | _ => None }; }; let getConstructor = (file, stamp, name) => { - switch (Hashtbl.find_opt(file.stamps.types, stamp)) { - | None => None - | Some({item: {kind}}) => - switch (kind) { - | Variant(constructors) => - switch (constructors |> List.find_opt(const => const.cname.txt == name)) { - | None => None - | Some(const) => Some(const) - } - | _ => None - } + let%opt {item: {kind}} = Hashtbl.find_opt(file.stamps.types, stamp); + switch (kind) { + | Variant(constructors) => + let%opt const = + constructors |> List.find_opt(const => const.cname.txt == name); + Some(const); + | _ => None }; }; diff --git a/src/rescript-editor-support/References.re b/src/rescript-editor-support/References.re index 4d520b7a..8f1204d5 100644 --- a/src/rescript-editor-support/References.re +++ b/src/rescript-editor-support/References.re @@ -72,18 +72,14 @@ let localReferencesForLoc = (~file, ~extra, loc) => | LModule(LocalReference(stamp, tip) | Definition(stamp, tip)) | Typed(_, LocalReference(stamp, tip) | Definition(stamp, tip)) => open Infix; - switch ( + let%opt localStamp = switch (tip) { | Constructor(name) => Query.getConstructor(file, stamp, name) |?>> (x => x.stamp) | Field(name) => Query.getField(file, stamp, name) |?>> (x => x.stamp) | _ => Some(stamp) - } - ) { - | None => None - | Some(localStamp) => - Hashtbl.find_opt(extra.internalReferences, localStamp) - } + }; + Hashtbl.find_opt(extra.internalReferences, localStamp); | LModule(GlobalReference(moduleName, path, tip)) | Typed(_, GlobalReference(moduleName, path, tip)) => switch (Hashtbl.find_opt(extra.externalReferences, moduleName)) { @@ -102,15 +98,11 @@ let definedForLoc = (~file, ~getModule, locKind) => { let inner = (~file, stamp, tip) => { switch (tip) { | Constructor(name) => - switch (Query.getConstructor(file, stamp, name)) { - | None => None - | Some(constructor) => Some(([], `Constructor(constructor))) - } + let%opt constructor = Query.getConstructor(file, stamp, name); + Some(([], `Constructor(constructor))); | Field(name) => - switch (Query.getField(file, stamp, name)) { - | None => None - | Some(field) => Some(([], `Field(field))) - } + let%opt field = Query.getField(file, stamp, name); + Some(([], `Field(field))); | _ => maybeLog( "Trying for declared " @@ -120,10 +112,9 @@ let definedForLoc = (~file, ~getModule, locKind) => { ++ " in file " ++ Uri2.toString(file.uri), ); - switch (Query.declaredForTip(~stamps=file.stamps, stamp, tip)) { - | None => None - | Some(declared) => Some((declared.docstring, `Declared)) - }; + let%opt declared = + Query.declaredForTip(~stamps=file.stamps, stamp, tip); + Some((declared.docstring, `Declared)); }; }; @@ -134,95 +125,62 @@ let definedForLoc = (~file, ~getModule, locKind) => { | GlobalReference(moduleName, path, tip) => { maybeLog("Getting global " ++ moduleName); - switch ( + let%try file = getModule(moduleName) - |> RResult.orError("Cannot get module " ++ moduleName) - ) { - | Error(e) => Error(e) - | Ok(file) => - let env = Query.fileEnv(file); - switch ( - Query.resolvePath(~env, ~path, ~getModule) - |> RResult.orError("Cannot resolve path " ++ pathToString(path)) - ) { - | Error(e) => Error(e) - | Ok((env, name)) => - switch ( - Query.exportedForTip(~env, name, tip) - |> RResult.orError( - "Exported not found for tip " - ++ name - ++ " > " - ++ tipToString(tip), - ) - ) { - | Error(e) => Error(e) - | Ok(stamp) => - maybeLog( - "Getting for " ++ string_of_int(stamp) ++ " in " ++ name, - ); - switch ( - inner(~file=env.file, stamp, tip) - |> RResult.orError("could not get defined") - ) { - | Error(e) => Error(e) - | Ok(res) => - maybeLog("Yes!! got it"); - Ok(res); - }; - } - }; - }; + |> RResult.orError("Cannot get module " ++ moduleName); + let env = Query.fileEnv(file); + let%try (env, name) = + Query.resolvePath(~env, ~path, ~getModule) + |> RResult.orError("Cannot resolve path " ++ pathToString(path)); + let%try stamp = + Query.exportedForTip(~env, name, tip) + |> RResult.orError( + "Exported not found for tip " + ++ name + ++ " > " + ++ tipToString(tip), + ); + maybeLog("Getting for " ++ string_of_int(stamp) ++ " in " ++ name); + let%try res = + inner(~file=env.file, stamp, tip) + |> RResult.orError("could not get defined"); + maybeLog("Yes!! got it"); + Ok(res); } |> RResult.toOptionAndLog }; }; let alternateDeclared = (~file, ~pathsForModule, ~getUri, declared, tip) => { - switch (Hashtbl.find_opt(pathsForModule, file.moduleName)) { - | None => None - | Some(paths) => - maybeLog("paths for " ++ file.moduleName); - switch (paths) { - | IntfAndImpl(_, intf, _, impl) => - maybeLog("Have both!!"); - let intfUri = Uri2.fromPath(intf); - let implUri = Uri2.fromPath(impl); - if (intfUri == file.uri) { - switch (getUri(implUri) |> RResult.toOptionAndLog) { - | None => None - | Some((file, extra)) => - switch ( - Query.declaredForExportedTip( - ~stamps=file.stamps, - ~exported=file.contents.exported, - declared.name.txt, - tip, - ) - ) { - | None => None - | Some(declared) => Some((file, extra, declared)) - } - }; - } else { - switch (getUri(intfUri) |> RResult.toOptionAndLog) { - | None => None - | Some((file, extra)) => - switch ( - Query.declaredForExportedTip( - ~stamps=file.stamps, - ~exported=file.contents.exported, - declared.name.txt, - tip, - ) - ) { - | None => None - | Some(declared) => Some((file, extra, declared)) - } - }; - }; - | _ => None + let%opt paths = Hashtbl.find_opt(pathsForModule, file.moduleName); + maybeLog("paths for " ++ file.moduleName); + switch (paths) { + | IntfAndImpl(_, intf, _, impl) => + maybeLog("Have both!!"); + let intfUri = Uri2.fromPath(intf); + let implUri = Uri2.fromPath(impl); + if (intfUri == file.uri) { + let%opt (file, extra) = getUri(implUri) |> RResult.toOptionAndLog; + let%opt declared = + Query.declaredForExportedTip( + ~stamps=file.stamps, + ~exported=file.contents.exported, + declared.name.txt, + tip, + ); + Some((file, extra, declared)); + } else { + let%opt (file, extra) = getUri(intfUri) |> RResult.toOptionAndLog; + let%opt declared = + Query.declaredForExportedTip( + ~stamps=file.stamps, + ~exported=file.contents.exported, + declared.name.txt, + tip, + ); + Some((file, extra, declared)); }; + | _ => None }; }; @@ -235,50 +193,26 @@ let resolveModuleReference = switch (Query.fromCompilerPath(~env, path)) { | `Not_found => None | `Exported(env, name) => - switch (Hashtbl.find_opt(env.exported.modules, name)) { - | None => None - | Some(stamp) => - switch (Hashtbl.find_opt(env.file.stamps.modules, stamp)) { - | None => None - | Some(md) => - Some((env.file, Some(md))) - /* Some((env.file.uri, validateLoc(md.name.loc, md.extentLoc))) */ - } - } + let%opt stamp = Hashtbl.find_opt(env.exported.modules, name); + let%opt md = Hashtbl.find_opt(env.file.stamps.modules, stamp); + Some((env.file, Some(md))); + /* Some((env.file.uri, validateLoc(md.name.loc, md.extentLoc))) */ | `Global(moduleName, path) => - switch (getModule(moduleName)) { - | None => None - | Some(file) => - let env = Query.fileEnv(file); - switch (Query.resolvePath(~env, ~getModule, ~path)) { - | None => None - | Some((env, name)) => - switch (Hashtbl.find_opt(env.exported.modules, name)) { - | None => None - | Some(stamp) => - switch (Hashtbl.find_opt(env.file.stamps.modules, stamp)) { - | None => None - | Some(md) => - Some((env.file, Some(md))) - /* Some((env.file.uri, validateLoc(md.name.loc, md.extentLoc))) */ - } - } - }; - } + let%opt file = getModule(moduleName); + let env = Query.fileEnv(file); + let%opt (env, name) = Query.resolvePath(~env, ~getModule, ~path); + let%opt stamp = Hashtbl.find_opt(env.exported.modules, name); + let%opt md = Hashtbl.find_opt(env.file.stamps.modules, stamp); + Some((env.file, Some(md))); + /* Some((env.file.uri, validateLoc(md.name.loc, md.extentLoc))) */ | `Stamp(stamp) => - switch (Hashtbl.find_opt(file.stamps.modules, stamp)) { - | None => None - | Some(md) => - Some((file, Some(md))) - /* Some((file.uri, validateLoc(md.name.loc, md.extentLoc))) */ - } + let%opt md = Hashtbl.find_opt(file.stamps.modules, stamp); + Some((file, Some(md))); + /* Some((file.uri, validateLoc(md.name.loc, md.extentLoc))) */ | `GlobalMod(name) => - switch (getModule(name)) { - | None => None - | Some(file) => - /* maybeLog("Congrats, found a global mod"); */ - Some((file, None)) - } + let%opt file = getModule(name); + /* maybeLog("Congrats, found a global mod"); */ + Some((file, None)); | _ => None }; }; @@ -298,125 +232,93 @@ let forLocalStamp = ) => { let env = Query.fileEnv(file); open Infix; - switch ( + let%opt localStamp = switch (tip) { | Constructor(name) => Query.getConstructor(file, stamp, name) |?>> (x => x.stamp) | Field(name) => Query.getField(file, stamp, name) |?>> (x => x.stamp) | _ => Some(stamp) - } - ) { - | None => None - | Some(localStamp) => - switch (Hashtbl.find_opt(extra.internalReferences, localStamp)) { - | None => None - | Some(local) => - open Infix; - let externals = - { - maybeLog("Checking externals: " ++ string_of_int(stamp)); - switch (Query.declaredForTip(~stamps=env.file.stamps, stamp, tip)) { - | None => None - | Some(declared) => - if (isVisible(declared)) { - /** - if this file has a corresponding interface or implementation file - also find the references in that file. - */ - let alternativeReferences = - ( - switch ( - alternateDeclared( - ~pathsForModule, - ~file, - ~getUri, - declared, - tip, - ) - ) { - | None => None - | Some((file, extra, {stamp})) => - switch ( - switch (tip) { - | Constructor(name) => - Query.getConstructor(file, stamp, name) |?>> (x => x.stamp) - | Field(name) => - Query.getField(file, stamp, name) |?>> (x => x.stamp) - | _ => Some(stamp) - } - ) { - | None => None - | Some(localStamp) => - switch (Hashtbl.find_opt(extra.internalReferences, localStamp)) { - | None => None - | Some(local) => Some([(file.uri, local)]) - } - } - } - ) - |? []; - switch ( - pathFromVisibility(declared.modulePath, declared.name.txt) - ) { - | None => None - | Some(path) => - maybeLog("Now checking path " ++ pathToString(path)); - let thisModuleName = file.moduleName; - let externals = - allModules - |> List.filter(name => name != file.moduleName) - |> Utils.filterMap(name => - { - switch ( - getModule(name) - |> RResult.orError( - "Could not get file for module " ++ name, - ) - ) { - | Error(e) => Error(e) - | Ok(file) => - switch ( - getExtra(name) - |> RResult.orError( - "Could not get extra for module " ++ name, - ) - ) { - | Error(e) => Error(e) - | Ok(extra) => - switch ( - Hashtbl.find_opt(extra.externalReferences, thisModuleName) - |> RResult.orError( - "No references in " - ++ name - ++ " for " - ++ thisModuleName, - ) - ) { - | Error(e) => Error(e) - | Ok(refs) => - let refs = - refs - |> Utils.filterMap(((p, t, l)) => - p == path && t == tip ? Some(l) : None - ); - Ok((file.uri, refs)); - } - } - } - } |> RResult.toOptionAndLog - ); - Some(alternativeReferences @ externals); + }; + let%opt local = Hashtbl.find_opt(extra.internalReferences, localStamp); + open Infix; + let externals = + { + maybeLog("Checking externals: " ++ string_of_int(stamp)); + let%opt declared = + Query.declaredForTip(~stamps=env.file.stamps, stamp, tip); + if (isVisible(declared)) { + /** + if this file has a corresponding interface or implementation file + also find the references in that file. + */ + let alternativeReferences = + { + let%opt (file, extra, {stamp}) = + alternateDeclared( + ~pathsForModule, + ~file, + ~getUri, + declared, + tip, + ); + let%opt localStamp = + switch (tip) { + | Constructor(name) => + Query.getConstructor(file, stamp, name) |?>> (x => x.stamp) + | Field(name) => + Query.getField(file, stamp, name) |?>> (x => x.stamp) + | _ => Some(stamp) }; - } else { - maybeLog("Not visible"); - Some([]); - } - }; - } - |? []; - Some([(file.uri, local), ...externals]); + let%opt local = + Hashtbl.find_opt(extra.internalReferences, localStamp); + Some([(file.uri, local)]); + } + |? []; + + let%opt path = + pathFromVisibility(declared.modulePath, declared.name.txt); + maybeLog("Now checking path " ++ pathToString(path)); + let thisModuleName = file.moduleName; + let externals = + allModules + |> List.filter(name => name != file.moduleName) + |> Utils.filterMap(name => + { + let%try file = + getModule(name) + |> RResult.orError( + "Could not get file for module " ++ name, + ); + let%try extra = + getExtra(name) + |> RResult.orError( + "Could not get extra for module " ++ name, + ); + let%try refs = + Hashtbl.find_opt(extra.externalReferences, thisModuleName) + |> RResult.orError( + "No references in " + ++ name + ++ " for " + ++ thisModuleName, + ); + let refs = + refs + |> Utils.filterMap(((p, t, l)) => + p == path && t == tip ? Some(l) : None + ); + Ok((file.uri, refs)); + } + |> RResult.toOptionAndLog + ); + Some(alternativeReferences @ externals); + } else { + maybeLog("Not visible"); + Some([]); + }; } - }; + |? []; + Some([(file.uri, local), ...externals]); }; let allReferencesForLoc = @@ -473,64 +375,47 @@ let allReferencesForLoc = |> RResult.orError("Could not get for local stamp"); | LModule(GlobalReference(moduleName, path, tip)) | Typed(_, GlobalReference(moduleName, path, tip)) => - switch ( + let%try file = getModule(moduleName) - |> RResult.orError("Cannot get module " ++ moduleName) - ) { - | Error(e) => Error(e) - | Ok(file) => - let env = Query.fileEnv(file); - switch ( - Query.resolvePath(~env, ~path, ~getModule) - |> RResult.orError("Cannot resolve path " ++ pathToString(path)) - ) { - | Error(e) => Error(e) - | Ok((env, name)) => - switch ( - Query.exportedForTip(~env, name, tip) - |> RResult.orError( - "Exported not found for tip " ++ name ++ " > " ++ tipToString(tip) - ) - ) { - | Error(e) => Error(e) - | Ok(stamp) => - switch (getUri(env.file.uri)) { - | Error(e) => Error(e) - | Ok((file, extra)) => - maybeLog( - "Finding references for (global) " - ++ Uri2.toString(env.file.uri) - ++ " and stamp " - ++ string_of_int(stamp) - ++ " and tip " - ++ tipToString(tip), - ); - forLocalStamp( - ~pathsForModule, - ~getUri, - ~file, - ~extra, - ~allModules, - ~getModule, - ~getExtra, - stamp, - tip, - ) - |> RResult.orError("Could not get for local stamp"); - } - } - }; - } + |> RResult.orError("Cannot get module " ++ moduleName); + let env = Query.fileEnv(file); + let%try (env, name) = + Query.resolvePath(~env, ~path, ~getModule) + |> RResult.orError("Cannot resolve path " ++ pathToString(path)); + let%try stamp = + Query.exportedForTip(~env, name, tip) + |> RResult.orError( + "Exported not found for tip " ++ name ++ " > " ++ tipToString(tip), + ); + let%try (file, extra) = getUri(env.file.uri); + maybeLog( + "Finding references for (global) " + ++ Uri2.toString(env.file.uri) + ++ " and stamp " + ++ string_of_int(stamp) + ++ " and tip " + ++ tipToString(tip), + ); + forLocalStamp( + ~pathsForModule, + ~getUri, + ~file, + ~extra, + ~allModules, + ~getModule, + ~getExtra, + stamp, + tip, + ) + |> RResult.orError("Could not get for local stamp"); }; }; let refsForPos = (~file, ~extra, pos) => { - switch (locForPos(~extra, pos)) { - | None => None - | Some((_, loc)) => - maybeLog("Got a loc for pos"); - localReferencesForLoc(~file, ~extra, loc); - } + let%opt (_, loc) = locForPos(~extra, pos); + maybeLog("Got a loc for pos"); + let%opt refs = localReferencesForLoc(~file, ~extra, loc); + Some(refs); }; let validateLoc = (loc: Location.t, backup: Location.t) => @@ -559,46 +444,32 @@ let validateLoc = (loc: Location.t, backup: Location.t) => }; let resolveModuleDefinition = (~file, ~getModule, stamp) => { - switch (Hashtbl.find_opt(file.stamps.modules, stamp)) { - | None => None - | Some(md) => - switch (resolveModuleReference(~file, ~getModule, md)) { - | None => None - | Some((file, declared)) => - let loc = - switch (declared) { - | None => Utils.topLoc(Uri2.toPath(file.uri)) - | Some(declared) => - validateLoc(declared.name.loc, declared.extentLoc) - }; - Some((file.uri, loc)); - } - }; + let%opt md = Hashtbl.find_opt(file.stamps.modules, stamp); + let%opt (file, declared) = resolveModuleReference(~file, ~getModule, md); + let loc = + switch (declared) { + | None => Utils.topLoc(Uri2.toPath(file.uri)) + | Some(declared) => validateLoc(declared.name.loc, declared.extentLoc) + }; + Some((file.uri, loc)); }; let definition = (~file, ~getModule, stamp, tip) => { switch (tip) { | Constructor(name) => - switch (Query.getConstructor(file, stamp, name)) { - | None => None - | Some(constructor) => Some((file.uri, constructor.cname.loc)) - } + let%opt constructor = Query.getConstructor(file, stamp, name); + Some((file.uri, constructor.cname.loc)); | Field(name) => - switch (Query.getField(file, stamp, name)) { - | None => None - | Some(field) => Some((file.uri, field.fname.loc)) - } + let%opt field = Query.getField(file, stamp, name); + Some((file.uri, field.fname.loc)); | Module => resolveModuleDefinition(~file, ~getModule, stamp) | _ => - switch (Query.declaredForTip(~stamps=file.stamps, stamp, tip)) { - | None => None - | Some(declared) => - let loc = validateLoc(declared.name.loc, declared.extentLoc); - let env = Query.fileEnv(file); - let uri = Query.getSourceUri(~env, ~getModule, declared.modulePath); - maybeLog("Inner uri " ++ Uri2.toString(uri)); - Some((uri, loc)); - } + let%opt declared = Query.declaredForTip(~stamps=file.stamps, stamp, tip); + let loc = validateLoc(declared.name.loc, declared.extentLoc); + let env = Query.fileEnv(file); + let uri = Query.getSourceUri(~env, ~getModule, declared.modulePath); + maybeLog("Inner uri " ++ Uri2.toString(uri)); + Some((uri, loc)); }; }; @@ -614,23 +485,16 @@ let definitionForLoc = (~pathsForModule, ~file, ~getUri, ~getModule, loc) => { switch (loc) { | Typed(_, Definition(stamp, tip)) => maybeLog("Trying to find a defintion for a definition"); - switch (Query.declaredForTip(~stamps=file.stamps, stamp, tip)) { - | None => None - | Some(declared) => - maybeLog("Declared"); - if (declared.exported) { - maybeLog("exported, looking for alternate " ++ file.moduleName); - switch ( - alternateDeclared(~pathsForModule, ~file, ~getUri, declared, tip) - ) { - | None => None - | Some((file, _extra, declared)) => - let loc = validateLoc(declared.name.loc, declared.extentLoc); - Some((file.uri, loc)); - }; - } else { - None; - }; + let%opt declared = Query.declaredForTip(~stamps=file.stamps, stamp, tip); + maybeLog("Declared"); + if (declared.exported) { + maybeLog("exported, looking for alternate " ++ file.moduleName); + let%opt (file, _extra, declared) = + alternateDeclared(~pathsForModule, ~file, ~getUri, declared, tip); + let loc = validateLoc(declared.name.loc, declared.extentLoc); + Some((file.uri, loc)); + } else { + None; }; | Explanation(_) | Typed(_, NotFound) @@ -640,15 +504,12 @@ let definitionForLoc = (~pathsForModule, ~file, ~getUri, ~getModule, loc) => { | TopLevelModule(name) => maybeLog("Toplevel " ++ name); open Infix; - switch ( + let%opt src = Hashtbl.find_opt(pathsForModule, name) |> orLog("No paths found") |?> getSrc - |> orLog("No src found") - ) { - | None => None - | Some(src) => Some((Uri2.fromPath(src), Utils.topLoc(src))) - } + |> orLog("No src found"); + Some((Uri2.fromPath(src), Utils.topLoc(src))); | LModule(LocalReference(stamp, tip)) | Typed(_, LocalReference(stamp, tip)) => maybeLog("Local defn " ++ tipToString(tip)); @@ -663,30 +524,19 @@ let definitionForLoc = (~pathsForModule, ~file, ~getUri, ~getModule, loc) => { ++ " : " ++ tipToString(tip), ); - switch (getModule(moduleName)) { - | None => None - | Some(file) => - let env = Query.fileEnv(file); - switch (Query.resolvePath(~env, ~path, ~getModule)) { - | None => None - | Some((env, name)) => - switch (Query.exportedForTip(~env, name, tip)) { - | None => None - | Some(stamp) => - /** oooh wht do I do if the stamp is inside a pseudo-file? */ - maybeLog("Got stamp " ++ string_of_int(stamp)); - definition(~file=env.file, ~getModule, stamp, tip); - } - }; - }; + let%opt file = getModule(moduleName); + let env = Query.fileEnv(file); + let%opt (env, name) = Query.resolvePath(~env, ~path, ~getModule); + let%opt stamp = Query.exportedForTip(~env, name, tip); + /** oooh wht do I do if the stamp is inside a pseudo-file? */ + maybeLog("Got stamp " ++ string_of_int(stamp)); + definition(~file=env.file, ~getModule, stamp, tip); }; }; let definitionForPos = - (~pathsForModule, ~file, ~extra, ~getUri, ~getModule, pos) => - switch (locForPos(~extra, pos)) { - | None => None - | Some((_, loc)) => - maybeLog("Got a loc for pos"); - definitionForLoc(~pathsForModule, ~file, ~getUri, ~getModule, loc); - }; + (~pathsForModule, ~file, ~extra, ~getUri, ~getModule, pos) => { + let%opt (_, loc) = locForPos(~extra, pos); + maybeLog("Got a loc for pos"); + definitionForLoc(~pathsForModule, ~file, ~getUri, ~getModule, loc); +}; diff --git a/src/rescript-editor-support/RescriptEditorSupport.re b/src/rescript-editor-support/RescriptEditorSupport.re index 60c0b2c6..fd246bfc 100644 --- a/src/rescript-editor-support/RescriptEditorSupport.re +++ b/src/rescript-editor-support/RescriptEditorSupport.re @@ -25,47 +25,44 @@ let capabilities = let getInitialState = params => { let rootUri = Json.get("rootUri", params) |?> Json.string |?> Uri2.parse; - switch (rootUri |> RResult.orError("Not a uri")) { - | Error(e) => Error(e) - | Ok(rootUri) => - let rootPath = Uri2.toPath(rootUri); - - Files.mkdirp(rootPath /+ "node_modules" /+ ".lsp"); - Log.setLocation(rootPath /+ "node_modules" /+ ".lsp" /+ "debug.log"); - Log.log("Hello - from " ++ Sys.executable_name); - - Rpc.sendNotification( - stdout, - "client/registerCapability", - J.o([ - ( - "registrations", - J.l([ - J.o([ - ("id", J.s("watching")), - ("method", J.s("workspace/didChangeWatchedFiles")), - ( - "registerOptions", - J.o([ - ( - "watchers", - J.l([ - J.o([("globPattern", J.s("**/bsconfig.json"))]), - J.o([("globPattern", J.s("**/.merlin"))]), - ]), - ), - ]), - ), - ]), + let%try rootUri = rootUri |> RResult.orError("Not a uri"); + let rootPath = Uri2.toPath(rootUri); + + Files.mkdirp(rootPath /+ "node_modules" /+ ".lsp"); + Log.setLocation(rootPath /+ "node_modules" /+ ".lsp" /+ "debug.log"); + Log.log("Hello - from " ++ Sys.executable_name); + + Rpc.sendNotification( + stdout, + "client/registerCapability", + J.o([ + ( + "registrations", + J.l([ + J.o([ + ("id", J.s("watching")), + ("method", J.s("workspace/didChangeWatchedFiles")), + ( + "registerOptions", + J.o([ + ( + "watchers", + J.l([ + J.o([("globPattern", J.s("**/bsconfig.json"))]), + J.o([("globPattern", J.s("**/.merlin"))]), + ]), + ), + ]), + ), ]), - ), - ]), - ); + ]), + ), + ]), + ); - let state = TopTypes.empty(); + let state = TopTypes.empty(); - Ok(state); - }; + Ok(state); }; let parseArgs = args => { diff --git a/src/rescript-editor-support/State.re b/src/rescript-editor-support/State.re index 88f0098a..b963716c 100644 --- a/src/rescript-editor-support/State.re +++ b/src/rescript-editor-support/State.re @@ -15,15 +15,11 @@ let converter = src => { let newDocsForCmt = (~moduleName, cmtCache, changed, cmt, src) => { let uri = Uri2.fromPath(src |? cmt); - switch ( + let%opt file = Process_406.fileForCmt(~moduleName, ~uri, cmt, converter(src)) - |> RResult.toOptionAndLog - ) { - | None => None - | Some(file) => - Hashtbl.replace(cmtCache, cmt, (changed, file)); - Some(file); - }; + |> RResult.toOptionAndLog; + Hashtbl.replace(cmtCache, cmt, (changed, file)); + Some(file); }; let docsForCmt = (~moduleName, cmt, src, state) => @@ -60,27 +56,21 @@ open Infix; let getFullFromCmt = (~state, ~uri) => { let path = Uri2.toPath(uri); - switch (Packages.getPackage(uri, state)) { - | Error(e) => Error(e) - | Ok(package) => - let moduleName = - BuildSystem.namespacedName(package.namespace, FindFiles.getName(path)); - switch (Hashtbl.find_opt(package.pathsForModule, moduleName)) { - | Some(paths) => - let cmt = - SharedTypes.getCmt(~interface=Utils.endsWith(path, "i"), paths); - switch (Process_406.fullForCmt(~moduleName, ~uri, cmt, x => [x])) { - | Error(e) => Error(e) - | Ok(full) => - Hashtbl.replace( - package.interModuleDependencies, - moduleName, - SharedTypes.hashList(full.extra.externalReferences) |> List.map(fst), - ); - Ok((package, full)); - }; - | None => Error("can't find module " ++ moduleName) - }; + let%try package = Packages.getPackage(uri, state); + let moduleName = + BuildSystem.namespacedName(package.namespace, FindFiles.getName(path)); + switch (Hashtbl.find_opt(package.pathsForModule, moduleName)) { + | Some(paths) => + let cmt = + SharedTypes.getCmt(~interface=Utils.endsWith(path, "i"), paths); + let%try full = Process_406.fullForCmt(~moduleName, ~uri, cmt, x => [x]); + Hashtbl.replace( + package.interModuleDependencies, + moduleName, + SharedTypes.hashList(full.extra.externalReferences) |> List.map(fst), + ); + Ok((package, full)); + | None => Error("can't find module " ++ moduleName) }; }; @@ -102,30 +92,23 @@ let docsForModule = (modname, state, ~package) => }; let fileForUri = (state, uri) => { - switch (getFullFromCmt(~state, ~uri)) { - | Error(e) => Error(e) - | Ok((_package, {extra, file})) => Ok((file, extra)) - } + let%try (_package, {extra, file}) = getFullFromCmt(~state, ~uri); + Ok((file, extra)); }; let fileForModule = (state, ~package, modname) => { - switch (docsForModule(modname, state, ~package)) { - | None => None - | Some((file, _)) => Some(file) - } + let%opt (file, _) = docsForModule(modname, state, ~package); + Some(file); }; let extraForModule = (state, ~package, modname) => if (Hashtbl.mem(package.pathsForModule, modname)) { let paths = Hashtbl.find(package.pathsForModule, modname); /* TODO do better? */ - switch (SharedTypes.getSrc(paths)) { - | None => None - | Some(src) => - switch (getFullFromCmt(~state, ~uri=Uri2.fromPath(src))) { - | Ok((_package, {extra})) => Some(extra) - | Error(_) => None - } + let%opt src = SharedTypes.getSrc(paths); + switch (getFullFromCmt(~state, ~uri=Uri2.fromPath(src))) { + | Ok((_package, {extra})) => Some(extra) + | Error(_) => None }; } else { None;