mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 20:32:10 +00:00
feat: add option to control enable/disable oxc linter (#1665)
1. Closed https://github.com/oxc-project/oxc/issues/1655
This commit is contained in:
parent
d719af473c
commit
e529b38e32
3 changed files with 122 additions and 15 deletions
|
|
@ -1,4 +1,13 @@
|
||||||
import { ExtensionContext, window, commands, workspace } from "vscode";
|
import {
|
||||||
|
ExtensionContext,
|
||||||
|
window,
|
||||||
|
commands,
|
||||||
|
workspace,
|
||||||
|
StatusBarItem,
|
||||||
|
StatusBarAlignment,
|
||||||
|
ConfigurationTarget,
|
||||||
|
ThemeColor,
|
||||||
|
} from "vscode";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Executable,
|
Executable,
|
||||||
|
|
@ -19,10 +28,13 @@ const enum OxcCommands {
|
||||||
ApplyAllFixes = "oxc.applyAllFixes",
|
ApplyAllFixes = "oxc.applyAllFixes",
|
||||||
ShowOutputChannel = "oxc.showOutputChannel",
|
ShowOutputChannel = "oxc.showOutputChannel",
|
||||||
ShowTraceOutputChannel = "oxc.showTraceOutputChannel",
|
ShowTraceOutputChannel = "oxc.showTraceOutputChannel",
|
||||||
|
ToggleEnable = "oxc.toggleEnable",
|
||||||
}
|
}
|
||||||
|
|
||||||
let client: LanguageClient;
|
let client: LanguageClient;
|
||||||
|
|
||||||
|
let myStatusBarItem: StatusBarItem;
|
||||||
|
|
||||||
export async function activate(context: ExtensionContext) {
|
export async function activate(context: ExtensionContext) {
|
||||||
const restartCommand = commands.registerCommand(
|
const restartCommand = commands.registerCommand(
|
||||||
OxcCommands.RestartServer,
|
OxcCommands.RestartServer,
|
||||||
|
|
@ -60,10 +72,22 @@ export async function activate(context: ExtensionContext) {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const toggleEnable = commands.registerCommand(
|
||||||
|
OxcCommands.ToggleEnable,
|
||||||
|
() => {
|
||||||
|
let enabled = workspace.getConfiguration("oxc-client").get("enable");
|
||||||
|
let nextState = !enabled;
|
||||||
|
workspace
|
||||||
|
.getConfiguration("oxc-client")
|
||||||
|
.update("enable", nextState, ConfigurationTarget.Global);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
context.subscriptions.push(
|
context.subscriptions.push(
|
||||||
restartCommand,
|
restartCommand,
|
||||||
showOutputCommand,
|
showOutputCommand,
|
||||||
showTraceOutputCommand,
|
showTraceOutputCommand,
|
||||||
|
toggleEnable,
|
||||||
);
|
);
|
||||||
|
|
||||||
const outputChannel = window.createOutputChannel(outputChannelName);
|
const outputChannel = window.createOutputChannel(outputChannelName);
|
||||||
|
|
@ -101,7 +125,10 @@ export async function activate(context: ExtensionContext) {
|
||||||
"javascript",
|
"javascript",
|
||||||
"typescriptreact",
|
"typescriptreact",
|
||||||
"javascriptreact",
|
"javascriptreact",
|
||||||
].map((lang) => ({ language: lang, scheme: "file" })),
|
].map((lang) => ({
|
||||||
|
language: lang,
|
||||||
|
scheme: "file",
|
||||||
|
})),
|
||||||
synchronize: {
|
synchronize: {
|
||||||
// Notify the server about file changes to '.clientrc files contained in the workspace
|
// Notify the server about file changes to '.clientrc files contained in the workspace
|
||||||
fileEvents: workspace.createFileSystemWatcher("**/.clientrc"),
|
fileEvents: workspace.createFileSystemWatcher("**/.clientrc"),
|
||||||
|
|
@ -121,15 +148,34 @@ export async function activate(context: ExtensionContext) {
|
||||||
clientOptions,
|
clientOptions,
|
||||||
);
|
);
|
||||||
workspace.onDidChangeConfiguration((e) => {
|
workspace.onDidChangeConfiguration((e) => {
|
||||||
let settings: any = {};
|
let settings: any = JSON.parse(
|
||||||
if (e.affectsConfiguration("oxc-client.run")) {
|
JSON.stringify(workspace.getConfiguration("oxc-client")),
|
||||||
settings.run = workspace.getConfiguration("oxc-client").get("run");
|
);
|
||||||
}
|
updateStatsBar(settings.enable);
|
||||||
client.sendNotification("workspace/didChangeConfiguration", {
|
client.sendNotification("workspace/didChangeConfiguration", {
|
||||||
settings,
|
settings,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function updateStatsBar(enable: boolean) {
|
||||||
|
if (!myStatusBarItem) {
|
||||||
|
myStatusBarItem = window.createStatusBarItem(
|
||||||
|
StatusBarAlignment.Right,
|
||||||
|
100,
|
||||||
|
);
|
||||||
|
myStatusBarItem.command = OxcCommands.ToggleEnable;
|
||||||
|
context.subscriptions.push(myStatusBarItem);
|
||||||
|
myStatusBarItem.show();
|
||||||
|
}
|
||||||
|
let bgColor = new ThemeColor(
|
||||||
|
enable
|
||||||
|
? "statusBarItem.activeBackground"
|
||||||
|
: "statusBarItem.errorBackground",
|
||||||
|
);
|
||||||
|
myStatusBarItem.text = `oxc: ${enable ? "on" : "off"}`;
|
||||||
|
myStatusBarItem.backgroundColor = bgColor;
|
||||||
|
}
|
||||||
|
updateStatsBar(clientConfig.enable);
|
||||||
client.start();
|
client.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,11 @@
|
||||||
"title": "Restart Oxc Server",
|
"title": "Restart Oxc Server",
|
||||||
"category": "Oxc"
|
"category": "Oxc"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "oxc.toggleEnable",
|
||||||
|
"title": "toggle enable",
|
||||||
|
"category": "Oxc"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "oxc.showOutputChannel",
|
"command": "oxc.showOutputChannel",
|
||||||
"title": "Show Output Channel",
|
"title": "Show Output Channel",
|
||||||
|
|
@ -67,6 +72,11 @@
|
||||||
"default": "onType",
|
"default": "onType",
|
||||||
"description": "Run the linter on save (onSave) or on type (onType)"
|
"description": "Run the linter on save (onSave) or on type (onType)"
|
||||||
},
|
},
|
||||||
|
"oxc-client.enable": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "enable oxc linter"
|
||||||
|
},
|
||||||
"oxc-client.trace.server": {
|
"oxc-client.trace.server": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"scope": "window",
|
"scope": "window",
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
|
|
@ -17,11 +18,11 @@ use tower_lsp::jsonrpc::{Error, ErrorCode, Result};
|
||||||
use tower_lsp::lsp_types::{
|
use tower_lsp::lsp_types::{
|
||||||
CodeAction, CodeActionKind, CodeActionOptions, CodeActionOrCommand, CodeActionParams,
|
CodeAction, CodeActionKind, CodeActionOptions, CodeActionOrCommand, CodeActionParams,
|
||||||
CodeActionProviderCapability, CodeActionResponse, Diagnostic, DidChangeConfigurationParams,
|
CodeActionProviderCapability, CodeActionResponse, Diagnostic, DidChangeConfigurationParams,
|
||||||
DidChangeTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams,
|
DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams,
|
||||||
InitializeParams, InitializeResult, InitializedParams, MessageType, OneOf, Registration,
|
DidSaveTextDocumentParams, InitializeParams, InitializeResult, InitializedParams, MessageType,
|
||||||
ServerCapabilities, ServerInfo, TextDocumentSyncCapability, TextDocumentSyncKind, TextEdit,
|
OneOf, Registration, ServerCapabilities, ServerInfo, TextDocumentSyncCapability,
|
||||||
Url, WorkDoneProgressOptions, WorkspaceEdit, WorkspaceFoldersServerCapabilities,
|
TextDocumentSyncKind, TextEdit, Url, WorkDoneProgressOptions, WorkspaceEdit,
|
||||||
WorkspaceServerCapabilities,
|
WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities,
|
||||||
};
|
};
|
||||||
use tower_lsp::{Client, LanguageServer, LspService, Server};
|
use tower_lsp::{Client, LanguageServer, LspService, Server};
|
||||||
|
|
||||||
|
|
@ -43,6 +44,27 @@ enum Run {
|
||||||
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
|
||||||
struct Options {
|
struct Options {
|
||||||
run: Run,
|
run: Run,
|
||||||
|
enable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Options {
|
||||||
|
fn get_lint_level(&self) -> SyntheticRunLevel {
|
||||||
|
if self.enable {
|
||||||
|
match self.run {
|
||||||
|
Run::OnSave => SyntheticRunLevel::OnSave,
|
||||||
|
Run::OnType => SyntheticRunLevel::OnType,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SyntheticRunLevel::Disable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, PartialOrd, Clone, Copy)]
|
||||||
|
enum SyntheticRunLevel {
|
||||||
|
Disable,
|
||||||
|
OnSave,
|
||||||
|
OnType,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tower_lsp::async_trait]
|
#[tower_lsp::async_trait]
|
||||||
|
|
@ -94,6 +116,25 @@ impl LanguageServer for Backend {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
debug!("{:?}", &changed_options.get_lint_level());
|
||||||
|
if changed_options.get_lint_level() == SyntheticRunLevel::Disable {
|
||||||
|
// clear all exists diagnostics when linter is disabled
|
||||||
|
let opened_files = self.diagnostics_report_map.iter().map(|k| k.key().to_string());
|
||||||
|
let cleared_diagnostics = opened_files
|
||||||
|
.into_iter()
|
||||||
|
.map(|uri| {
|
||||||
|
(
|
||||||
|
// should convert successfully, case the key is from `params.document.uri`
|
||||||
|
Url::from_str(&uri)
|
||||||
|
.ok()
|
||||||
|
.and_then(|url| url.to_file_path().ok())
|
||||||
|
.expect("should convert to path"),
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
self.publish_all_diagnostics(&cleared_diagnostics).await;
|
||||||
|
}
|
||||||
*self.options.lock().await = changed_options;
|
*self.options.lock().await = changed_options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,8 +162,8 @@ impl LanguageServer for Backend {
|
||||||
async fn did_save(&self, params: DidSaveTextDocumentParams) {
|
async fn did_save(&self, params: DidSaveTextDocumentParams) {
|
||||||
debug!("oxc server did save");
|
debug!("oxc server did save");
|
||||||
// drop as fast as possible
|
// drop as fast as possible
|
||||||
let options = { self.options.lock().await.run };
|
let run_level = { self.options.lock().await.get_lint_level() };
|
||||||
if options < Run::OnSave {
|
if run_level < SyntheticRunLevel::OnSave {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.handle_file_update(params.text_document.uri, None).await;
|
self.handle_file_update(params.text_document.uri, None).await;
|
||||||
|
|
@ -131,8 +172,8 @@ impl LanguageServer for Backend {
|
||||||
/// When the document changed, it may not be written to disk, so we should
|
/// When the document changed, it may not be written to disk, so we should
|
||||||
/// get the file context from the language client
|
/// get the file context from the language client
|
||||||
async fn did_change(&self, params: DidChangeTextDocumentParams) {
|
async fn did_change(&self, params: DidChangeTextDocumentParams) {
|
||||||
let options = { self.options.lock().await.run };
|
let run_level = { self.options.lock().await.get_lint_level() };
|
||||||
if options < Run::OnType {
|
if run_level < SyntheticRunLevel::OnType {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let content = params.content_changes.first().map(|c| c.text.clone());
|
let content = params.content_changes.first().map(|c| c.text.clone());
|
||||||
|
|
@ -140,9 +181,18 @@ impl LanguageServer for Backend {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn did_open(&self, params: DidOpenTextDocumentParams) {
|
async fn did_open(&self, params: DidOpenTextDocumentParams) {
|
||||||
|
let run_level = { self.options.lock().await.get_lint_level() };
|
||||||
|
if run_level < SyntheticRunLevel::OnType {
|
||||||
|
return;
|
||||||
|
}
|
||||||
self.handle_file_update(params.text_document.uri, None).await;
|
self.handle_file_update(params.text_document.uri, None).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn did_close(&self, params: DidCloseTextDocumentParams) {
|
||||||
|
let uri = params.text_document.uri.to_string();
|
||||||
|
self.diagnostics_report_map.remove(&uri);
|
||||||
|
}
|
||||||
|
|
||||||
async fn code_action(&self, params: CodeActionParams) -> Result<Option<CodeActionResponse>> {
|
async fn code_action(&self, params: CodeActionParams) -> Result<Option<CodeActionResponse>> {
|
||||||
let uri = params.text_document.uri;
|
let uri = params.text_document.uri;
|
||||||
|
|
||||||
|
|
@ -199,6 +249,7 @@ impl Backend {
|
||||||
|
|
||||||
#[allow(clippy::ptr_arg)]
|
#[allow(clippy::ptr_arg)]
|
||||||
async fn publish_all_diagnostics(&self, result: &Vec<(PathBuf, Vec<Diagnostic>)>) {
|
async fn publish_all_diagnostics(&self, result: &Vec<(PathBuf, Vec<Diagnostic>)>) {
|
||||||
|
debug!("{:?}", result);
|
||||||
join_all(result.iter().map(|(path, diagnostics)| {
|
join_all(result.iter().map(|(path, diagnostics)| {
|
||||||
self.client.publish_diagnostics(
|
self.client.publish_diagnostics(
|
||||||
Url::from_file_path(path).unwrap(),
|
Url::from_file_path(path).unwrap(),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue