Skip to content

Initial SendLogNotification #1066

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -105,6 +105,7 @@ You'll find all ReScript specific settings under the scope `rescript.settings`.
| Inlay Hints (experimental) | This allows an editor to place annotations inline with text to display type hints. Enable using `rescript.settings.inlayHints.enable: true` |
| Code Lens (experimental) | This tells the editor to add code lenses to function definitions, showing its full type above the definition. Enable using `rescript.settings.codeLens: true` |
| Signature Help | This tells the editor to show signature help when you're writing function calls. Enable using `rescript.settings.signatureHelp.enabled: true` |
| Log level | This tells the editor which log messages to show in the Output window. The options are `"error"`, `"warning"`, `"info"`, `"log"` with default `"info"`. Set via `"rescript.settings.logLevel"`. |

**Default settings:**

@@ -126,6 +127,9 @@ You'll find all ReScript specific settings under the scope `rescript.settings`.

// Enable (experimental) code lens for function definitions.
"rescript.settings.codeLens": true

// Set log level ("error", "warning", "info", "log").
"rescript.settings.logLevel": "info"
```

## 🚀 Code Analyzer
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -206,6 +206,12 @@
],
"default": null,
"description": "Path to the directory where platform-specific ReScript binaries are. You can use it if you haven't or don't want to use the installed ReScript from node_modules in your project."
},
"rescript.settings.logLevel": {
"type": "string",
"enum": ["error", "warning", "info", "log"],
"default": "info",
"description": "Controls the log level of the language server. Logs below this level will be filtered out."
}
}
},
2 changes: 2 additions & 0 deletions server/src/config.ts
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ export interface extensionConfiguration {
enable?: boolean;
};
};
logLevel: "error" | "warning" | "info" | "log"
}

// All values here are temporary, and will be overridden as the server is
@@ -53,6 +54,7 @@ let config: { extensionConfiguration: extensionConfiguration } = {
enable: true,
},
},
logLevel: "info"
},
};

69 changes: 54 additions & 15 deletions server/src/server.ts
Original file line number Diff line number Diff line change
@@ -28,6 +28,38 @@ import * as ic from "./incrementalCompilation";
import config, { extensionConfiguration } from "./config";
import { projectsFiles } from "./projectFiles";

const notificationLevelMap = new Map([
["error", p.MessageType.Error],
["warning", p.MessageType.Warning],
["info", p.MessageType.Info],
["log", p.MessageType.Log]
])

/**
* Sends an LSP log notification that will appear in the ReScript Language Server Output window in VSCode.
* Other LSP clients will also receive this notification,
* as we utilize LanguageClient in the VSCode extension, providing this functionality at no extra cost.
*/
function sendLogNotification(level: p.MessageType, message: string) {
const currentLogLevel = notificationLevelMap.get(config.extensionConfiguration.logLevel) || p.MessageType.Info;

if (currentLogLevel >= level) {
const logMessageParams: p.LogMessageParams = {
type: level,
message
}
const notificationMessage: p.NotificationMessage = {
method: "window/logMessage",
jsonrpc: c.jsonrpcVersion,
params: logMessageParams
}

if (send) {
send(notificationMessage);
}
}
}

// This holds client capabilities specific to our extension, and not necessarily
// related to the LS protocol. It's for enabling/disabling features that might
// work in one client, like VSCode, but perhaps not in others, like vim.
@@ -54,18 +86,18 @@ let stupidFileContentCache: Map<string, string> = new Map();
let codeActionsFromDiagnostics: codeActions.filesCodeActions = {};

// will be properly defined later depending on the mode (stdio/node-rpc)
let send: (msg: p.Message) => void = (_) => {};
let send: (msg: p.Message) => void = (_) => { };

let findRescriptBinary = (projectRootPath: p.DocumentUri | null) =>
config.extensionConfiguration.binaryPath == null
? lookup.findFilePathFromProjectRoot(
projectRootPath,
path.join(c.nodeModulesBinDir, c.rescriptBinName)
)
projectRootPath,
path.join(c.nodeModulesBinDir, c.rescriptBinName)
)
: utils.findBinary(
config.extensionConfiguration.binaryPath,
c.rescriptBinName
);
config.extensionConfiguration.binaryPath,
c.rescriptBinName
);

let createInterfaceRequest = new v.RequestType<
p.TextDocumentIdentifier,
@@ -332,9 +364,9 @@ let openedFile = (fileUri: string, fileContent: string) => {
message:
config.extensionConfiguration.binaryPath == null
? `Can't find ReScript binary in ${path.join(
projectRootPath,
c.nodeModulesBinDir
)} or parent directories. Did you install it? It's required to use "rescript" > 9.1`
projectRootPath,
c.nodeModulesBinDir
)} or parent directories. Did you install it? It's required to use "rescript" > 9.1`
: `Can't find ReScript binary in the directory ${config.extensionConfiguration.binaryPath}`,
},
};
@@ -418,6 +450,7 @@ export default function listen(useStdio = false) {
send = (msg: p.Message) => process.send!(msg);
process.on("message", onMessage);
}
utils.setSendLogNotification(sendLogNotification);
}

function hover(msg: p.RequestMessage) {
@@ -1158,15 +1191,15 @@ function onMessage(msg: p.Message) {
inlayHintProvider: config.extensionConfiguration.inlayHints?.enable,
codeLensProvider: config.extensionConfiguration.codeLens
? {
workDoneProgress: false,
}
workDoneProgress: false,
}
: undefined,
signatureHelpProvider: config.extensionConfiguration.signatureHelp
?.enabled
? {
triggerCharacters: ["("],
retriggerCharacters: ["=", ","],
}
triggerCharacters: ["("],
retriggerCharacters: ["=", ","],
}
: undefined,
},
};
@@ -1177,6 +1210,12 @@ function onMessage(msg: p.Message) {
};
initialized = true;

let rescriptVersion = undefined;
if (initParams.workspaceFolders && initParams.workspaceFolders.length > 0) {
rescriptVersion = utils.findReScriptVersion(initParams.workspaceFolders[0].uri);
}
sendLogNotification(p.MessageType.Info, `LSP Server started! Rescript Version ${rescriptVersion}`);

// Periodically pull configuration from the client.
pullConfigurationPeriodically = setInterval(() => {
askForAllCurrentConfiguration();
30 changes: 22 additions & 8 deletions server/src/utils.ts
Original file line number Diff line number Diff line change
@@ -16,6 +16,13 @@ import { reportError } from "./errorReporter";
import config from "./config";
import { filesDiagnostics, projectsFiles } from "./projectFiles";

// This is a bit dirty but avoids passing down this function each time.
export type SendLogNotification = (level: p.MessageType, message: string) => void
let sendLogNotification: SendLogNotification = () => { };
export function setSendLogNotification(send: SendLogNotification) {
sendLogNotification = send;
}

let tempFilePrefix = "rescript_format_file_" + process.pid + "_";
let tempFileId = 0;

@@ -92,15 +99,19 @@ export let findBinary = (

type execResult =
| {
kind: "success";
result: string;
}
kind: "success";
result: string;
}
| {
kind: "error";
error: string;
};
kind: "error";
error: string;
};

type formatCodeResult = execResult;
type formatCodeResult =
| execResult
| {
kind: "blocked-using-built-in-formatter";
};

export let formatCode = (
bscPath: p.DocumentUri | null,
@@ -238,6 +249,9 @@ export let runAnalysisAfterSanityCheck = (

let stdout = "";
try {
if(args.includes("completion")){
sendLogNotification(p.MessageType.Log, `Running completion: ${binaryPath} ${args.join(" ")}`);
}
stdout = childProcess.execFileSync(binaryPath, args, options).toString();
return JSON.parse(stdout);
} catch (e) {
@@ -666,7 +680,7 @@ export let parseCompilerLogOutput = (
diagnostic,
diagnosticMessage,
file,
range,
range
});

result[file].push(diagnostic);