From 5d5c9db64c045e860a0b499ecf8379463d91a42e Mon Sep 17 00:00:00 2001 From: Amirali Esmaeili Date: Mon, 7 Jun 2021 03:43:14 +0430 Subject: [PATCH 1/5] Add prepare rename provider --- server/src/server.ts | 46 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/server/src/server.ts b/server/src/server.ts index 2da47a107..40f519b2e 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -282,6 +282,48 @@ function references(msg: p.RequestMessage) { return response; } +function prepareRename(msg: p.RequestMessage) { + // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_prepareRename + let params = msg.params as p.PrepareRenameParams; + let filePath = fileURLToPath(params.textDocument.uri); + let locations: null | p.Location[] = utils.getReferencesForPosition( + filePath, + params.position + ); + + let result: p.Range | null = null; + + if (locations !== null && locations.length > 0) { + let targetLoc = locations.find(loc => { + if ( + path.normalize(fileURLToPath(loc.uri)) === + path.normalize(fileURLToPath(params.textDocument.uri)) + ) { + let { start, end } = loc.range; + let pos = params.position; + + return ( + start.character <= pos.character && + start.line <= pos.line && + end.character >= pos.character && + end.line >= pos.line + ); + } + }); + + if (targetLoc != null) { + result = targetLoc.range; + } + } + + let response: m.ResponseMessage = { + jsonrpc: c.jsonrpcVersion, + id: msg.id, + result + }; + return response; +} + function rename(msg: p.RequestMessage) { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename let params = msg.params as p.RenameParams; @@ -591,7 +633,7 @@ function onMessage(msg: m.Message) { hoverProvider: true, definitionProvider: true, referencesProvider: true, - renameProvider: true, + renameProvider: { prepareProvider: true }, documentSymbolProvider: false, completionProvider: { triggerCharacters: [".", ">", "@", "~"] }, }, @@ -642,6 +684,8 @@ function onMessage(msg: m.Message) { send(definition(msg)); } else if (msg.method === p.ReferencesRequest.method) { send(references(msg)); + } else if (msg.method === p.PrepareRenameRequest.method) { + send(prepareRename(msg)); } else if (msg.method === p.RenameRequest.method) { send(rename(msg)); } else if (msg.method === p.DocumentSymbolRequest.method) { From 30da51e6540d6a5d7576d08a7d8cf29b74a4c540 Mon Sep 17 00:00:00 2001 From: Amirali Esmaeili Date: Mon, 7 Jun 2021 03:49:44 +0430 Subject: [PATCH 2/5] return false explicitly --- server/src/server.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/src/server.ts b/server/src/server.ts index 40f519b2e..f3ed7653a 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -309,6 +309,8 @@ function prepareRename(msg: p.RequestMessage) { end.line >= pos.line ); } + + return false; }); if (targetLoc != null) { From d163d2940e37dfeb6bec7b337714ba1d40b05f1a Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Mon, 7 Jun 2021 02:06:09 +0200 Subject: [PATCH 3/5] refactor completion --- analysis/src/Commands.ml | 72 +++++++++++++++++++--------------- analysis/src/NewCompletions.ml | 49 ++++++++++++----------- 2 files changed, 65 insertions(+), 56 deletions(-) diff --git a/analysis/src/Commands.ml b/analysis/src/Commands.ml index 66a2e0316..211e06228 100644 --- a/analysis/src/Commands.ml +++ b/analysis/src/Commands.ml @@ -33,9 +33,16 @@ let dump files = let completion ~path ~line ~col ~currentFile = let uri = Uri2.fromPath path in + let pos = (line, col) in let result = let textOpt = Files.readFile currentFile in - NewCompletions.computeCompletions ~uri ~textOpt ~pos:(line, col) + let completionItems = + match NewCompletions.getCompletable ~textOpt ~pos with + | None -> [] + | Some (completable, rawOpens) -> + NewCompletions.computeCompletions ~completable ~pos ~rawOpens ~uri + in + completionItems |> List.map Protocol.stringifyCompletionItem |> Protocol.array in @@ -143,38 +150,41 @@ let references ~path ~line ~col = let documentSymbol ~path = let uri = Uri2.fromPath path in - match ProcessCmt.getFullFromCmt ~uri with - | None -> print_endline Protocol.null - | Some {file} -> - let open SharedTypes in - let rec getItems {topLevel} = - let rec getItem = function - | MValue v -> (v |> SharedTypes.variableKind, []) - | MType (t, _) -> (t.decl |> SharedTypes.declarationKind, []) - | Module (Structure contents) -> (Module, getItems contents) - | Module (Constraint (_, modTypeItem)) -> getItem (Module modTypeItem) - | Module (Ident _) -> (Module, []) + let result = + match ProcessCmt.getFullFromCmt ~uri with + | None -> Protocol.null + | Some {file} -> + let open SharedTypes in + let rec getItems {topLevel} = + let rec getItem = function + | MValue v -> (v |> SharedTypes.variableKind, []) + | MType (t, _) -> (t.decl |> SharedTypes.declarationKind, []) + | Module (Structure contents) -> (Module, getItems contents) + | Module (Constraint (_, modTypeItem)) -> getItem (Module modTypeItem) + | Module (Ident _) -> (Module, []) + in + let fn {name = {txt}; extentLoc; item} = + let item, siblings = getItem item in + if extentLoc.loc_ghost then siblings + else (txt, extentLoc, item) :: siblings + in + let x = topLevel |> List.map fn |> List.concat in + x in - let fn {name = {txt}; extentLoc; item} = - let item, siblings = getItem item in - if extentLoc.loc_ghost then siblings - else (txt, extentLoc, item) :: siblings + let allSymbols = + getItems file.contents + |> List.map (fun (name, loc, kind) -> + Protocol.stringifyDocumentSymbolItem + { + name; + location = + {uri = Uri2.toString uri; range = Utils.cmtLocToRange loc}; + kind = SharedTypes.symbolKind kind; + }) in - let x = topLevel |> List.map fn |> List.concat in - x - in - let allSymbols = - getItems file.contents - |> List.map (fun (name, loc, kind) -> - Protocol.stringifyDocumentSymbolItem - { - name; - location = - {uri = Uri2.toString uri; range = Utils.cmtLocToRange loc}; - kind = SharedTypes.symbolKind kind; - }) - in - print_endline ("[\n" ^ (allSymbols |> String.concat ",\n") ^ "\n]") + "[\n" ^ (allSymbols |> String.concat ",\n") ^ "\n]" + in + print_endline result let rename ~path ~line ~col ~newName = let uri = Uri2.fromPath path in diff --git a/analysis/src/NewCompletions.ml b/analysis/src/NewCompletions.ml index 97e81b5ed..a114e6aa4 100644 --- a/analysis/src/NewCompletions.ml +++ b/analysis/src/NewCompletions.ml @@ -1133,33 +1133,32 @@ let processCompletable ~findItems ~full ~package ~rawOpens Utils.startsWith name prefix && not (List.mem name identsSeen)) |> List.map mkLabel -let computeCompletions ~uri ~textOpt ~pos = +let getCompletable ~textOpt ~pos = match textOpt with - | None -> [] + | None -> None | Some text -> ( match PartialParser.positionToOffset text pos with - | None -> [] + | None -> None | Some offset -> ( match PartialParser.findCompletable text offset with - | None -> [] - | Some completable -> ( - match ProcessCmt.getFullFromCmt ~uri with - | None -> [] - | Some full -> - let rawOpens = PartialParser.findOpens text offset in - let package = full.package in - let allFiles = - FileSet.union package.projectFiles package.dependenciesFiles - in - let findItems ~exact parts = - let items = - getItems ~full ~package ~rawOpens ~allFiles ~pos ~parts - in - match parts |> List.rev with - | last :: _ when exact -> - items - |> List.filter (fun {SharedTypes.name = {txt}} -> txt = last) - | _ -> items - in - completable |> processCompletable ~findItems ~full ~package ~rawOpens) - )) + | None -> None + | Some completable -> + let rawOpens = PartialParser.findOpens text offset in + Some (completable, rawOpens))) + +let computeCompletions ~completable ~pos ~rawOpens ~uri = + match ProcessCmt.getFullFromCmt ~uri with + | None -> [] + | Some full -> + let package = full.package in + let allFiles = + FileSet.union package.projectFiles package.dependenciesFiles + in + let findItems ~exact parts = + let items = getItems ~full ~package ~rawOpens ~allFiles ~pos ~parts in + match parts |> List.rev with + | last :: _ when exact -> + items |> List.filter (fun {SharedTypes.name = {txt}} -> txt = last) + | _ -> items + in + completable |> processCompletable ~findItems ~full ~package ~rawOpens From f412eb729541b6a191c5d09f182d675a99994cfe Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Mon, 7 Jun 2021 03:13:09 +0200 Subject: [PATCH 4/5] Revert "refactor completion" This reverts commit d163d2940e37dfeb6bec7b337714ba1d40b05f1a. --- analysis/src/Commands.ml | 72 +++++++++++++++------------------- analysis/src/NewCompletions.ml | 49 +++++++++++------------ 2 files changed, 56 insertions(+), 65 deletions(-) diff --git a/analysis/src/Commands.ml b/analysis/src/Commands.ml index 211e06228..66a2e0316 100644 --- a/analysis/src/Commands.ml +++ b/analysis/src/Commands.ml @@ -33,16 +33,9 @@ let dump files = let completion ~path ~line ~col ~currentFile = let uri = Uri2.fromPath path in - let pos = (line, col) in let result = let textOpt = Files.readFile currentFile in - let completionItems = - match NewCompletions.getCompletable ~textOpt ~pos with - | None -> [] - | Some (completable, rawOpens) -> - NewCompletions.computeCompletions ~completable ~pos ~rawOpens ~uri - in - completionItems + NewCompletions.computeCompletions ~uri ~textOpt ~pos:(line, col) |> List.map Protocol.stringifyCompletionItem |> Protocol.array in @@ -150,41 +143,38 @@ let references ~path ~line ~col = let documentSymbol ~path = let uri = Uri2.fromPath path in - let result = - match ProcessCmt.getFullFromCmt ~uri with - | None -> Protocol.null - | Some {file} -> - let open SharedTypes in - let rec getItems {topLevel} = - let rec getItem = function - | MValue v -> (v |> SharedTypes.variableKind, []) - | MType (t, _) -> (t.decl |> SharedTypes.declarationKind, []) - | Module (Structure contents) -> (Module, getItems contents) - | Module (Constraint (_, modTypeItem)) -> getItem (Module modTypeItem) - | Module (Ident _) -> (Module, []) - in - let fn {name = {txt}; extentLoc; item} = - let item, siblings = getItem item in - if extentLoc.loc_ghost then siblings - else (txt, extentLoc, item) :: siblings - in - let x = topLevel |> List.map fn |> List.concat in - x + match ProcessCmt.getFullFromCmt ~uri with + | None -> print_endline Protocol.null + | Some {file} -> + let open SharedTypes in + let rec getItems {topLevel} = + let rec getItem = function + | MValue v -> (v |> SharedTypes.variableKind, []) + | MType (t, _) -> (t.decl |> SharedTypes.declarationKind, []) + | Module (Structure contents) -> (Module, getItems contents) + | Module (Constraint (_, modTypeItem)) -> getItem (Module modTypeItem) + | Module (Ident _) -> (Module, []) in - let allSymbols = - getItems file.contents - |> List.map (fun (name, loc, kind) -> - Protocol.stringifyDocumentSymbolItem - { - name; - location = - {uri = Uri2.toString uri; range = Utils.cmtLocToRange loc}; - kind = SharedTypes.symbolKind kind; - }) + let fn {name = {txt}; extentLoc; item} = + let item, siblings = getItem item in + if extentLoc.loc_ghost then siblings + else (txt, extentLoc, item) :: siblings in - "[\n" ^ (allSymbols |> String.concat ",\n") ^ "\n]" - in - print_endline result + let x = topLevel |> List.map fn |> List.concat in + x + in + let allSymbols = + getItems file.contents + |> List.map (fun (name, loc, kind) -> + Protocol.stringifyDocumentSymbolItem + { + name; + location = + {uri = Uri2.toString uri; range = Utils.cmtLocToRange loc}; + kind = SharedTypes.symbolKind kind; + }) + in + print_endline ("[\n" ^ (allSymbols |> String.concat ",\n") ^ "\n]") let rename ~path ~line ~col ~newName = let uri = Uri2.fromPath path in diff --git a/analysis/src/NewCompletions.ml b/analysis/src/NewCompletions.ml index a114e6aa4..97e81b5ed 100644 --- a/analysis/src/NewCompletions.ml +++ b/analysis/src/NewCompletions.ml @@ -1133,32 +1133,33 @@ let processCompletable ~findItems ~full ~package ~rawOpens Utils.startsWith name prefix && not (List.mem name identsSeen)) |> List.map mkLabel -let getCompletable ~textOpt ~pos = +let computeCompletions ~uri ~textOpt ~pos = match textOpt with - | None -> None + | None -> [] | Some text -> ( match PartialParser.positionToOffset text pos with - | None -> None + | None -> [] | Some offset -> ( match PartialParser.findCompletable text offset with - | None -> None - | Some completable -> - let rawOpens = PartialParser.findOpens text offset in - Some (completable, rawOpens))) - -let computeCompletions ~completable ~pos ~rawOpens ~uri = - match ProcessCmt.getFullFromCmt ~uri with - | None -> [] - | Some full -> - let package = full.package in - let allFiles = - FileSet.union package.projectFiles package.dependenciesFiles - in - let findItems ~exact parts = - let items = getItems ~full ~package ~rawOpens ~allFiles ~pos ~parts in - match parts |> List.rev with - | last :: _ when exact -> - items |> List.filter (fun {SharedTypes.name = {txt}} -> txt = last) - | _ -> items - in - completable |> processCompletable ~findItems ~full ~package ~rawOpens + | None -> [] + | Some completable -> ( + match ProcessCmt.getFullFromCmt ~uri with + | None -> [] + | Some full -> + let rawOpens = PartialParser.findOpens text offset in + let package = full.package in + let allFiles = + FileSet.union package.projectFiles package.dependenciesFiles + in + let findItems ~exact parts = + let items = + getItems ~full ~package ~rawOpens ~allFiles ~pos ~parts + in + match parts |> List.rev with + | last :: _ when exact -> + items + |> List.filter (fun {SharedTypes.name = {txt}} -> txt = last) + | _ -> items + in + completable |> processCompletable ~findItems ~full ~package ~rawOpens) + )) From 08682f5d690fc5ede5b7a2834bb296bd8cb2d37c Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Mon, 7 Jun 2021 03:54:47 +0200 Subject: [PATCH 5/5] Don't return a boolean directly, but use result instead. --- server/src/server.ts | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index f3ed7653a..dbc8ecca9 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -38,7 +38,7 @@ let projectsFiles: Map< // ^ caching AND states AND distributed system. Why does LSP has to be stupid like this // will be properly defined later depending on the mode (stdio/node-rpc) -let send: (msg: m.Message) => void = (_) => {}; +let send: (msg: m.Message) => void = (_) => { }; interface CreateInterfaceRequestParams { uri: string; @@ -282,7 +282,7 @@ function references(msg: p.RequestMessage) { return response; } -function prepareRename(msg: p.RequestMessage) { +function prepareRename(msg: p.RequestMessage): m.ResponseMessage { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_prepareRename let params = msg.params as p.PrepareRenameParams; let filePath = fileURLToPath(params.textDocument.uri); @@ -293,29 +293,24 @@ function prepareRename(msg: p.RequestMessage) { let result: p.Range | null = null; - if (locations !== null && locations.length > 0) { - let targetLoc = locations.find(loc => { + if (locations !== null) { + locations.forEach(loc => { if ( path.normalize(fileURLToPath(loc.uri)) === path.normalize(fileURLToPath(params.textDocument.uri)) ) { let { start, end } = loc.range; let pos = params.position; - - return ( + if ( start.character <= pos.character && start.line <= pos.line && end.character >= pos.character && end.line >= pos.line - ); + ) { + result = loc.range; + }; } - - return false; }); - - if (targetLoc != null) { - result = targetLoc.range; - } } let response: m.ResponseMessage = { @@ -333,12 +328,12 @@ function rename(msg: p.RequestMessage) { let documentChanges: | (p.RenameFile | p.TextDocumentEdit)[] | null = utils.runAnalysisAfterSanityCheck(filePath, [ - "rename", - filePath, - params.position.line, - params.position.character, - params.newName - ]); + "rename", + filePath, + params.position.line, + params.position.character, + params.newName + ]); let result: WorkspaceEdit | null = null;