diff --git a/analysis/bin/main.ml b/analysis/bin/main.ml index 7df0d0c6c..cdc8c0b29 100644 --- a/analysis/bin/main.ml +++ b/analysis/bin/main.ml @@ -111,10 +111,22 @@ let main () = in match args with | [_; "cache-project"; rootPath] -> ( + Cfg.useProjectConfigCache := false; let uri = Uri.fromPath rootPath in match Packages.getPackage ~uri with | Some package -> Cache.cacheProject package - | None -> ()) + | None -> print_endline "\"ERR\"") + | [_; "cache-delete"; rootPath] -> ( + Cfg.useProjectConfigCache := false; + let uri = Uri.fromPath rootPath in + match Packages.findRoot ~uri (Hashtbl.create 0) with + | Some (`Bs rootPath) -> ( + match BuildSystem.getLibBs rootPath with + | None -> print_endline "\"ERR\"" + | Some libBs -> + Cache.deleteCache (Cache.targetFileFromLibBs libBs); + print_endline "\"OK\"") + | _ -> print_endline "\"ERR: Did not find root \"") | [_; "completion"; path; line; col; currentFile] -> printHeaderInfo path line col; Commands.completion ~debug ~path diff --git a/analysis/src/Cache.ml b/analysis/src/Cache.ml index 62dd8b921..90463408e 100644 --- a/analysis/src/Cache.ml +++ b/analysis/src/Cache.ml @@ -21,6 +21,8 @@ let readCache filename = with _ -> None else None +let deleteCache filename = try Sys.remove filename with _ -> () + let targetFileFromLibBs libBs = Filename.concat libBs ".project-files-cache" let cacheProject (package : package) = @@ -32,8 +34,8 @@ let cacheProject (package : package) = } in match BuildSystem.getLibBs package.rootPath with - | None -> () + | None -> print_endline "\"ERR\"" | Some libBs -> let targetFile = targetFileFromLibBs libBs in writeCache targetFile cached; - print_endline "OK" + print_endline "\"OK\"" diff --git a/analysis/src/Packages.ml b/analysis/src/Packages.ml index cd2d3b528..59021ce9e 100644 --- a/analysis/src/Packages.ml +++ b/analysis/src/Packages.ml @@ -231,7 +231,7 @@ let findRoot ~uri packagesByRoot = let parent = Filename.dirname path in if parent = path then (* reached root *) None else loop parent in - loop (Filename.dirname path) + loop (if Sys.is_directory path then path else Filename.dirname path) let getPackage ~uri = let open SharedTypes in diff --git a/client/src/extension.ts b/client/src/extension.ts index 08bcfd1fa..350d88718 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -341,7 +341,8 @@ export function activate(context: ExtensionContext) { affectsConfiguration("rescript.settings.inlayHints") || affectsConfiguration("rescript.settings.codeLens") || affectsConfiguration("rescript.settings.signatureHelp") || - affectsConfiguration("rescript.settings.incrementalTypechecking") + affectsConfiguration("rescript.settings.incrementalTypechecking") || + affectsConfiguration("rescript.settings.cache") ) { commands.executeCommand("rescript-vscode.restart_language_server"); } else { diff --git a/package.json b/package.json index 82356a3b0..507f8d773 100644 --- a/package.json +++ b/package.json @@ -192,6 +192,11 @@ "default": false, "description": "(debug) Enable debug logging (ends up in the extension output)." }, + "rescript.settings.cache.projectConfig.enabled": { + "type": "boolean", + "default": false, + "description": "(beta/experimental) Enable project config caching. Can speed up latency dramatically." + }, "rescript.settings.binaryPath": { "type": [ "string", diff --git a/server/src/config.ts b/server/src/config.ts index 9949d6bde..567f05585 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -21,6 +21,11 @@ export interface extensionConfiguration { acrossFiles?: boolean; debugLogging?: boolean; }; + cache?: { + projectConfig?: { + enabled?: boolean; + }; + }; } // All values here are temporary, and will be overridden as the server is @@ -43,7 +48,12 @@ let config: { extensionConfiguration: extensionConfiguration } = { incrementalTypechecking: { enabled: false, acrossFiles: false, - debugLogging: true, + debugLogging: false, + }, + cache: { + projectConfig: { + enabled: false, + }, }, }, }; diff --git a/server/src/constants.ts b/server/src/constants.ts index fd6e29472..a08525523 100644 --- a/server/src/constants.ts +++ b/server/src/constants.ts @@ -44,6 +44,7 @@ export let bsconfigPartialPath = "bsconfig.json"; export let rescriptJsonPartialPath = "rescript.json"; export let compilerDirPartialPath = path.join("lib", "bs"); export let compilerLogPartialPath = path.join("lib", "bs", ".compiler.log"); +export let buildNinjaPartialPath = path.join("lib", "bs", "build.ninja"); export let resExt = ".res"; export let resiExt = ".resi"; export let cmiExt = ".cmi"; diff --git a/server/src/server.ts b/server/src/server.ts index cfef4f572..42e09f42c 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -205,20 +205,49 @@ let sendCompilationFinishedMessage = () => { send(notification); }; +let debug = false; + +let syncProjectConfigCache = (rootPath: string) => { + try { + if (debug) console.log("syncing project config cache for " + rootPath); + utils.runAnalysisAfterSanityCheck(rootPath, ["cache-project", rootPath]); + if (debug) console.log("OK - synced project config cache for " + rootPath); + } catch (e) { + if (debug) console.error(e); + } +}; + +let deleteProjectConfigCache = (rootPath: string) => { + try { + if (debug) console.log("deleting project config cache for " + rootPath); + utils.runAnalysisAfterSanityCheck(rootPath, ["cache-delete", rootPath]); + if (debug) console.log("OK - deleted project config cache for " + rootPath); + } catch (e) { + if (debug) console.error(e); + } +}; + let compilerLogsWatcher = chokidar .watch([], { awaitWriteFinish: { stabilityThreshold: 1, }, }) - .on("all", (_e, _changedPath) => { - sendUpdatedDiagnostics(); - sendCompilationFinishedMessage(); - if (config.extensionConfiguration.inlayHints?.enable === true) { - sendInlayHintsRefresh(); - } - if (config.extensionConfiguration.codeLens === true) { - sendCodeLensRefresh(); + .on("all", (_e, changedPath) => { + if (changedPath.includes("build.ninja")) { + let projectRoot = utils.findProjectRootOfFile(changedPath); + if (projectRoot != null) { + syncProjectConfigCache(projectRoot); + } + } else { + sendUpdatedDiagnostics(); + sendCompilationFinishedMessage(); + if (config.extensionConfiguration.inlayHints?.enable === true) { + sendInlayHintsRefresh(); + } + if (config.extensionConfiguration.codeLens === true) { + sendCodeLensRefresh(); + } } }); let stopWatchingCompilerLog = () => { @@ -257,6 +286,14 @@ let openedFile = (fileUri: string, fileContent: string) => { compilerLogsWatcher.add( path.join(projectRootPath, c.compilerLogPartialPath) ); + if ( + config.extensionConfiguration.cache?.projectConfig?.enabled === true + ) { + compilerLogsWatcher.add( + path.join(projectRootPath, c.buildNinjaPartialPath) + ); + syncProjectConfigCache(projectRootPath); + } } let root = projectsFiles.get(projectRootPath)!; root.openFiles.add(filePath); @@ -335,6 +372,10 @@ let closedFile = (fileUri: string) => { compilerLogsWatcher.unwatch( path.join(projectRootPath, c.compilerLogPartialPath) ); + compilerLogsWatcher.unwatch( + path.join(projectRootPath, c.buildNinjaPartialPath) + ); + deleteProjectConfigCache(projectRootPath); deleteProjectDiagnostics(projectRootPath); if (root.bsbWatcherByEditor !== null) { root.bsbWatcherByEditor.kill(); diff --git a/server/src/utils.ts b/server/src/utils.ts index 8f952ffff..0fbe42a9c 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -190,6 +190,10 @@ export let runAnalysisAfterSanityCheck = ( config.extensionConfiguration.incrementalTypechecking?.enabled === true ? "true" : undefined, + RESCRIPT_PROJECT_CONFIG_CACHE: + config.extensionConfiguration.cache?.projectConfig?.enabled === true + ? "true" + : undefined, }, }; let stdout = "";