diff --git a/README.md b/README.md index 18d811474..c7479c425 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,7 @@ Custom endpoints are using (for messages body) `PlainNotification` type and stri * `fsproj/addFile` - accepts `DotnetFileRequest`, create the file if needed and add it to the project if not already present * `fsproj/addExistingFile` - accepts `DotnetFileRequest`, add existing file to a project if not already present * `fsproj/removeFile` - accepts `DotnetFileRequest`, remove the file from the project +* `fsproj/renameFile` - accepts `DotnetRenameFileRequest`, rename the file from the project ### Supported LSP notifications diff --git a/src/FsAutoComplete.Core/Commands.fs b/src/FsAutoComplete.Core/Commands.fs index d6e2c8e6d..e894cfee4 100644 --- a/src/FsAutoComplete.Core/Commands.fs +++ b/src/FsAutoComplete.Core/Commands.fs @@ -167,6 +167,26 @@ module Commands = return CoreResponse.ErrorRes ex.Message } + let renameFile (fsprojPath: string) (oldFileVirtualPath: string) (newFileName: string) = + async { + try + let dir = Path.GetDirectoryName fsprojPath + let oldFilePath = Path.Combine(dir, oldFileVirtualPath) + let oldFileInfo = FileInfo(oldFilePath) + + let newFilePath = Path.Combine(oldFileInfo.Directory.FullName, newFileName) + + File.Move(oldFilePath, newFilePath) + + let newVirtPath = + Path.Combine(Path.GetDirectoryName oldFileVirtualPath, newFileName) + + FsProjEditor.renameFile fsprojPath oldFileVirtualPath newVirtPath + return CoreResponse.Res() + with ex -> + return CoreResponse.ErrorRes ex.Message + } + let removeFile fsprojPath fileVirtPath = async { FsProjEditor.removeFile fsprojPath fileVirtPath @@ -1503,6 +1523,29 @@ type Commands(checker: FSharpCompilerServiceChecker, state: State, hasAnalyzers: return CoreResponse.ErrorRes ex.Message } + member _.FsProjRenameFile (fsprojPath: string) (oldFileVirtualPath: string) (newFileName: string) = + async { + try + let dir = Path.GetDirectoryName fsprojPath + let oldFilePath = Path.Combine(dir, oldFileVirtualPath) + let oldFileInfo = FileInfo(oldFilePath) + + let newFilePath = Path.Combine(oldFileInfo.Directory.FullName, newFileName) + + File.Move(oldFilePath, newFilePath) + + let newVirtPath = + Path.Combine(Path.GetDirectoryName oldFileVirtualPath, newFileName) + + FsProjEditor.renameFile fsprojPath oldFileVirtualPath newVirtPath + + // Clear diagnostics for the old file + state.RemoveProjectOptions(normalizePath oldFilePath) + return CoreResponse.Res() + with ex -> + return CoreResponse.ErrorRes ex.Message + } + member _.FsProjAddFile (fsprojPath: string) (fileVirtPath: string) = async { try diff --git a/src/FsAutoComplete.Core/FsprojEdit.fs b/src/FsAutoComplete.Core/FsprojEdit.fs index 2864faa2e..ace6ce959 100644 --- a/src/FsAutoComplete.Core/FsprojEdit.fs +++ b/src/FsAutoComplete.Core/FsprojEdit.fs @@ -110,6 +110,14 @@ module FsProjEditor = xdoc.Save fsprojPath Ok() + let renameFile (fsprojPath: string) (oldFileName: string) (newFileName: string) = + let xdoc = System.Xml.XmlDocument() + xdoc.Load fsprojPath + let xpath = sprintf "//Compile[@Include='%s']" oldFileName + let node = xdoc.SelectSingleNode(xpath) + node.Attributes["Include"].InnerText <- newFileName + xdoc.Save fsprojPath + let addFile (fsprojPath: string) (newFileName: string) = let xdoc = System.Xml.XmlDocument() xdoc.Load fsprojPath diff --git a/src/FsAutoComplete/LspHelpers.fs b/src/FsAutoComplete/LspHelpers.fs index 69a6b945c..b6524b761 100644 --- a/src/FsAutoComplete/LspHelpers.fs +++ b/src/FsAutoComplete/LspHelpers.fs @@ -581,6 +581,11 @@ type DotnetFile2Request = FileVirtualPath: string NewFile: string } +type DotnetRenameFileRequest = + { FsProj: string + OldFileVirtualPath: string + NewFileName: string } + type FSharpLiterateRequest = { TextDocument: TextDocumentIdentifier } diff --git a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs index 252966fbe..18339f539 100644 --- a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs +++ b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs @@ -4530,6 +4530,36 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return! LspResult.internalError (string e) } + override __.FsProjRenameFile(p: DotnetRenameFileRequest) = + asyncResult { + let tags = [ "DotnetRenameFileRequest", box p ] + use trace = fsacActivitySource.StartActivityForType(thisType, tags = tags) + + try + logger.info ( + Log.setMessage "FsProjRenameFile Request: {parms}" + >> Log.addContextDestructured "parms" p + ) + + do! + Commands.renameFile p.FsProj p.OldFileVirtualPath p.NewFileName + |> AsyncResult.ofCoreResponse + |> AsyncResult.map ignore + + forceLoadProjects () |> ignore + return None + with e -> + trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + + logger.error ( + Log.setMessage "FsProjRenameFile Request Errored {p}" + >> Log.addContextDestructured "p" p + >> Log.addExn e + ) + + return! LspResult.internalError (string e) + } + override __.FsProjAddFile(p: DotnetFileRequest) = asyncResult { @@ -4709,6 +4739,7 @@ module AdaptiveFSharpLspServer = |> Map.add "fsproj/addFileBelow" (serverRequestHandling (fun s p -> s.FsProjAddFileBelow(p))) |> Map.add "fsproj/addFile" (serverRequestHandling (fun s p -> s.FsProjAddFile(p))) |> Map.add "fsproj/addExistingFile" (serverRequestHandling (fun s p -> s.FsProjAddExistingFile(p))) + |> Map.add "fsproj/renameFile" (serverRequestHandling (fun s p -> s.FsProjRenameFile(p))) |> Map.add "fsproj/removeFile" (serverRequestHandling (fun s p -> s.FsProjRemoveFile(p))) let adaptiveServer lspClient = diff --git a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs index 5e2d2ebb4..4ce1cea59 100644 --- a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs +++ b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs @@ -2527,6 +2527,24 @@ type FSharpLspServer(state: State, lspClient: FSharpLspClient) = return res } + override __.FsProjRenameFile(p: DotnetRenameFileRequest) = + async { + logger.info ( + Log.setMessage "FsProjRenameFile Request: {parms}" + >> Log.addContextDestructured "parms" p + ) + + let! res = commands.FsProjRenameFile p.FsProj p.OldFileVirtualPath p.NewFileName + + let res = + match res with + | CoreResponse.InfoRes msg -> success None + | CoreResponse.ErrorRes msg -> LspResult.internalError msg + | CoreResponse.Res(_) -> success None + + return res + } + override __.FsProjAddFile(p: DotnetFileRequest) = async { logger.info ( @@ -2902,6 +2920,7 @@ module FSharpLspServer = |> Map.add "fsproj/addFileBelow" (serverRequestHandling (fun s p -> s.FsProjAddFileBelow(p))) |> Map.add "fsproj/addFile" (serverRequestHandling (fun s p -> s.FsProjAddFile(p))) |> Map.add "fsproj/addExistingFile" (serverRequestHandling (fun s p -> s.FsProjAddExistingFile(p))) + |> Map.add "fsproj/renameFile" (serverRequestHandling (fun s p -> s.FsProjRenameFile(p))) |> Map.add "fsproj/removeFile" (serverRequestHandling (fun s p -> s.FsProjRemoveFile(p))) let regularServer lspClient = diff --git a/src/FsAutoComplete/LspServers/IFSharpLspServer.fs b/src/FsAutoComplete/LspServers/IFSharpLspServer.fs index 0870ef3a1..a48045c77 100644 --- a/src/FsAutoComplete/LspServers/IFSharpLspServer.fs +++ b/src/FsAutoComplete/LspServers/IFSharpLspServer.fs @@ -42,6 +42,7 @@ type IFSharpLspServer = abstract FsProjMoveFileDown: DotnetFileRequest -> Async> abstract FsProjAddFileAbove: DotnetFile2Request -> Async> abstract FsProjAddFileBelow: DotnetFile2Request -> Async> + abstract FsProjRenameFile: DotnetRenameFileRequest -> Async> abstract FsProjAddFile: DotnetFileRequest -> Async> abstract FsProjRemoveFile: DotnetFileRequest -> Async> abstract FsProjAddExistingFile: DotnetFileRequest -> Async>