Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use editor tooling distributed with compiler when supported #1055

Merged
merged 4 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#### :house: Internal

- Auto-format vendored OCaml sources like in compiler repo. https://github.com/rescript-lang/rescript-vscode/pull/1053
- All OCaml sources in this repo is now considered "legacy", as the OCaml parts of the editor integration are now shipped with the compiler instead.

## 1.58.0

Expand Down
16 changes: 13 additions & 3 deletions client/src/commands/code_analysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
OutputChannel,
StatusBarItem,
} from "vscode";
import { analysisProdPath, getAnalysisBinaryPath } from "../utils";
import { findProjectRootOfFileInDir, getBinaryPath } from "../utils";

export let statusBarItem = {
setToStopText: (codeAnalysisRunningStatusBarItem: StatusBarItem) => {
Expand Down Expand Up @@ -208,9 +208,19 @@ export const runCodeAnalysisWithReanalyze = (
let currentDocument = window.activeTextEditor.document;
let cwd = targetDir ?? path.dirname(currentDocument.uri.fsPath);

let binaryPath = getAnalysisBinaryPath();
let projectRootPath: string | null = findProjectRootOfFileInDir(
currentDocument.uri.fsPath
);

// This little weird lookup is because in the legacy setup reanalyze needs to be
// run from the analysis binary, whereas in the new setup it's run from the tools
// binary.
let binaryPath =
getBinaryPath("rescript-tools.exe", projectRootPath) ??
getBinaryPath("rescript-editor-analysis.exe");

if (binaryPath === null) {
window.showErrorMessage("Binary executable not found.", analysisProdPath);
window.showErrorMessage("Binary executable not found.");
return;
}

Expand Down
12 changes: 10 additions & 2 deletions client/src/commands/dump_debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import {
ViewColumn,
window,
} from "vscode";
import { createFileInTempDir, getAnalysisBinaryPath } from "../utils";
import {
createFileInTempDir,
findProjectRootOfFileInDir,
getBinaryPath,
} from "../utils";
import * as path from "path";

// Maps to Cli.ml
Expand Down Expand Up @@ -132,7 +136,11 @@ export const dumpDebug = async (
const { line: endLine, character: endChar } = editor.selection.end;
const filePath = editor.document.uri.fsPath;

const binaryPath = getAnalysisBinaryPath();
let projectRootPath: string | null = findProjectRootOfFileInDir(filePath);
const binaryPath = getBinaryPath(
"rescript-editor-analysis.exe",
projectRootPath
);
if (binaryPath === null) {
window.showErrorMessage("Binary executable not found.");
return;
Expand Down
80 changes: 59 additions & 21 deletions client/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,50 @@
import * as path from "path";
import * as fs from "fs";
import * as os from "os";
import { DocumentUri } from "vscode-languageclient";

/*
* Much of the code in here is duplicated from the server code.
* At some point we should move the functionality powered by this
* to the server itself.
*/

type binaryName = "rescript-editor-analysis.exe" | "rescript-tools.exe";

const platformDir =
process.arch === "arm64" ? process.platform + process.arch : process.platform;

const analysisDevPath = path.join(
path.dirname(__dirname),
"..",
"analysis",
"rescript-editor-analysis.exe"
);

export const analysisProdPath = path.join(
path.dirname(__dirname),
"..",
"server",
"analysis_binaries",
platformDir,
"rescript-editor-analysis.exe"
);

export const getAnalysisBinaryPath = (): string | null => {
if (fs.existsSync(analysisDevPath)) {
return analysisDevPath;
} else if (fs.existsSync(analysisProdPath)) {
return analysisProdPath;
const getLegacyBinaryDevPath = (b: binaryName) =>
path.join(path.dirname(__dirname), "..", "analysis", b);

export const getLegacyBinaryProdPath = (b: binaryName) =>
path.join(
path.dirname(__dirname),
"..",
"server",
"analysis_binaries",
platformDir,
b
);

export const getBinaryPath = (
binaryName: "rescript-editor-analysis.exe" | "rescript-tools.exe",
projectRootPath: string | null = null
): string | null => {
const binaryFromCompilerPackage = path.join(
projectRootPath ?? "",
"node_modules",
"rescript",
platformDir,
binaryName
);

if (projectRootPath != null && fs.existsSync(binaryFromCompilerPackage)) {
return binaryFromCompilerPackage;
} else if (fs.existsSync(getLegacyBinaryDevPath(binaryName))) {
return getLegacyBinaryDevPath(binaryName);
} else if (fs.existsSync(getLegacyBinaryProdPath(binaryName))) {
return getLegacyBinaryProdPath(binaryName);
} else {
return null;
}
Expand All @@ -39,3 +58,22 @@ export const createFileInTempDir = (prefix = "", extension = "") => {
tempFileId = tempFileId + 1;
return path.join(os.tmpdir(), tempFileName);
};

export let findProjectRootOfFileInDir = (
source: DocumentUri
): null | DocumentUri => {
let dir = path.dirname(source);
if (
fs.existsSync(path.join(dir, "rescript.json")) ||
fs.existsSync(path.join(dir, "bsconfig.json"))
) {
return dir;
} else {
if (dir === source) {
// reached top
return null;
} else {
return findProjectRootOfFileInDir(dir);
}
}
};
9 changes: 5 additions & 4 deletions server/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,22 @@ export let jsonrpcVersion = "2.0";
export let platformPath = path.join("rescript", platformDir);
export let nodeModulesPlatformPath = path.join("node_modules", platformPath);
export let bscExeName = "bsc.exe";
export let editorAnalysisName = "rescript-editor-analysis.exe";
export let bscNativeReScriptPartialPath = path.join(
nodeModulesPlatformPath,
bscExeName
);

export let analysisDevPath = path.join(
export let builtinAnalysisDevPath = path.join(
path.dirname(__dirname),
"..",
"rescript-editor-analysis.exe"
editorAnalysisName
);
export let analysisProdPath = path.join(
export let builtinAnalysisProdPath = path.join(
path.dirname(__dirname),
"analysis_binaries",
platformDir,
"rescript-editor-analysis.exe"
editorAnalysisName
);

export let rescriptBinName = "rescript";
Expand Down
1 change: 1 addition & 0 deletions server/src/projectFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface projectFiles {
filesDiagnostics: filesDiagnostics;
rescriptVersion: string | undefined;
bscBinaryLocation: string | null;
editorAnalysisLocation: string | null;
namespaceName: string | null;

bsbWatcherByEditor: null | cp.ChildProcess;
Expand Down
1 change: 1 addition & 0 deletions server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ let openedFile = (fileUri: string, fileContent: string) => {
rescriptVersion: utils.findReScriptVersion(projectRootPath),
bsbWatcherByEditor: null,
bscBinaryLocation: utils.findBscExeBinary(projectRootPath),
editorAnalysisLocation: utils.findEditorAnalysisBinary(projectRootPath),
hasPromptedToStartBuild: /(\/|\\)node_modules(\/|\\)/.test(
projectRootPath
)
Expand Down
53 changes: 43 additions & 10 deletions server/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,23 +192,19 @@ export let findReScriptVersion = (
}
};

let binaryPath: string | null = null;
if (fs.existsSync(c.analysisDevPath)) {
binaryPath = c.analysisDevPath;
} else if (fs.existsSync(c.analysisProdPath)) {
binaryPath = c.analysisProdPath;
} else {
// This is the path for the _builtin_ legacy analysis, that works for versions 11 and below.
let builtinBinaryPath: string | null = null;
if (fs.existsSync(c.builtinAnalysisDevPath)) {
builtinBinaryPath = c.builtinAnalysisDevPath;
} else if (fs.existsSync(c.builtinAnalysisProdPath)) {
builtinBinaryPath = c.builtinAnalysisProdPath;
}

export let runAnalysisAfterSanityCheck = (
filePath: p.DocumentUri,
args: Array<any>,
projectRequired = false
) => {
if (binaryPath == null) {
return null;
}

let projectRootPath = findProjectRootOfFile(filePath);
if (projectRootPath == null && projectRequired) {
return null;
Expand All @@ -217,6 +213,35 @@ export let runAnalysisAfterSanityCheck = (
projectsFiles.get(projectRootPath ?? "")?.rescriptVersion ??
findReScriptVersion(filePath);

let binaryPath = builtinBinaryPath;

let project = projectRootPath ? projectsFiles.get(projectRootPath) : null;

/**
* All versions including 12.0.0-alpha.5 and above should use the analysis binary
* that now ships with the compiler. Previous versions use the legacy one we ship
* with the extension itself.
*/
let shouldUseBuiltinAnalysis =
rescriptVersion?.startsWith("9.") ||
rescriptVersion?.startsWith("10.") ||
rescriptVersion?.startsWith("11.") ||
[
"12.0.0-alpha.1",
"12.0.0-alpha.2",
"12.0.0-alpha.3",
"12.0.0-alpha.4",
].includes(rescriptVersion ?? "");

if (!shouldUseBuiltinAnalysis && project != null) {
binaryPath = project.editorAnalysisLocation;
} else if (!shouldUseBuiltinAnalysis && project == null) {
// TODO: Warn user about broken state?
return null;
} else {
binaryPath = builtinBinaryPath;
}

let options: childProcess.ExecFileSyncOptions = {
cwd: projectRootPath || undefined,
maxBuffer: Infinity,
Expand All @@ -233,6 +258,11 @@ export let runAnalysisAfterSanityCheck = (
: undefined,
},
};

if (binaryPath == null) {
return null;
}

let stdout = "";
try {
stdout = childProcess.execFileSync(binaryPath, args, options).toString();
Expand Down Expand Up @@ -737,3 +767,6 @@ let findPlatformPath = (projectRootPath: p.DocumentUri | null) => {

export let findBscExeBinary = (projectRootPath: p.DocumentUri | null) =>
findBinary(findPlatformPath(projectRootPath), c.bscExeName);

export let findEditorAnalysisBinary = (projectRootPath: p.DocumentUri | null) =>
findBinary(findPlatformPath(projectRootPath), c.editorAnalysisName);