Skip to content

Commit d595d93

Browse files
committed
draft(oxlnt/lsp): support jsPlugins
1 parent d713d38 commit d595d93

File tree

14 files changed

+194
-72
lines changed

14 files changed

+194
-72
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
2+
"oxc.path.oxlint": "./apps/oxlint/dist/cli.js",
23
"oxc.typeAware": true,
3-
"oxc.configPath": "oxlintrc.json",
4+
// "oxc.configPath": "oxlintrc.json",
45
"oxc.unusedDisableDirectives": "deny",
56
"oxc.fmt.experimental": true,
67
"oxc.fmt.configPath": "oxfmtrc.jsonc",

apps/oxlint/src/js_plugins/external_linter.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::sync::{atomic::Ordering, mpsc::channel};
1+
use std::sync::{Arc, atomic::Ordering, mpsc::channel};
22

33
use napi::{
44
Status,
@@ -45,7 +45,7 @@ pub fn create_external_linter(
4545
///
4646
/// The returned function will panic if called outside of a Tokio runtime.
4747
fn wrap_load_plugin(cb: JsLoadPluginCb) -> ExternalLinterLoadPluginCb {
48-
Box::new(move |workspace_dir, plugin_url, package_name| {
48+
Arc::new(Box::new(move |workspace_dir, plugin_url, package_name| {
4949
let cb = &cb;
5050
tokio::task::block_in_place(|| {
5151
tokio::runtime::Handle::current().block_on(async move {
@@ -58,7 +58,7 @@ fn wrap_load_plugin(cb: JsLoadPluginCb) -> ExternalLinterLoadPluginCb {
5858
Ok(plugin_load_result)
5959
})
6060
})
61-
})
61+
}))
6262
}
6363

6464
/// Result returned by `lintFile` JS callback.
@@ -71,17 +71,17 @@ pub enum LintFileReturnValue {
7171
/// Wrap `createWorkspace` JS callback as a normal Rust function.
7272
///
7373
fn wrap_create_workspace(cb: JsCreateWorkspaceCb) -> oxc_linter::ExternalLinterCreateWorkspaceCb {
74-
Box::new(move |root_dir: String| {
74+
Arc::new(Box::new(move |root_dir: String| {
7575
let _ = cb.call(FnArgs::from((root_dir,)), ThreadsafeFunctionCallMode::Blocking);
76-
})
76+
}))
7777
}
7878

7979
fn wrap_destroy_workspace(
8080
cb: JsDestroyWorkspaceCb,
8181
) -> oxc_linter::ExternalLinterDestroyWorkspaceCb {
82-
Box::new(move |root_dir: String| {
82+
Arc::new(Box::new(move |root_dir: String| {
8383
let _ = cb.call(FnArgs::from((root_dir,)), ThreadsafeFunctionCallMode::Blocking);
84-
})
84+
}))
8585
}
8686

8787
/// Wrap `lintFile` JS callback as a normal Rust function.
@@ -94,7 +94,7 @@ fn wrap_destroy_workspace(
9494
/// Use an `mpsc::channel` to wait for the result from JS side, and block current thread until `lintFile`
9595
/// completes execution.
9696
fn wrap_lint_file(cb: JsLintFileCb) -> ExternalLinterLintFileCb {
97-
Box::new(
97+
Arc::new(Box::new(
9898
move |workspace_dir: String,
9999
file_path: String,
100100
rule_ids: Vec<u32>,
@@ -148,7 +148,7 @@ fn wrap_lint_file(cb: JsLintFileCb) -> ExternalLinterLintFileCb {
148148
Err(err) => panic!("Callback did not respond: {err}"),
149149
}
150150
},
151-
)
151+
))
152152
}
153153

154154
/// Get buffer ID of the `Allocator` and, if it hasn't already been sent to JS,

apps/oxlint/src/lsp.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
/// Run the language server
2-
pub async fn run_lsp() {
3-
oxc_language_server::run_server(vec![Box::new(oxc_language_server::ServerLinterBuilder)]).await;
2+
pub async fn run_lsp(external_linter: Option<oxc_linter::ExternalLinter>) {
3+
oxc_language_server::run_server(vec![Box::new(oxc_language_server::ServerLinterBuilder::new(
4+
external_linter,
5+
))])
6+
.await;
47
}

apps/oxlint/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ async fn main() -> CliRunResult {
99

1010
// If --lsp flag is set, run the language server
1111
if command.lsp {
12-
run_lsp().await;
12+
run_lsp(None).await;
1313
return CliRunResult::LintSucceeded;
1414
}
1515

apps/oxlint/src/run.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -133,17 +133,6 @@ async fn lint_impl(
133133
}
134134
};
135135

136-
// If --lsp flag is set, run the language server
137-
if command.lsp {
138-
crate::lsp::run_lsp().await;
139-
return CliRunResult::LintSucceeded;
140-
}
141-
142-
init_tracing();
143-
init_miette();
144-
145-
command.handle_threads();
146-
147136
// JS plugins are only supported on 64-bit little-endian platforms at present
148137
#[cfg(all(target_pointer_width = "64", target_endian = "little"))]
149138
let external_linter = Some(super::js_plugins::create_external_linter(
@@ -158,6 +147,17 @@ async fn lint_impl(
158147
None
159148
};
160149

150+
// If --lsp flag is set, run the language server
151+
if command.lsp {
152+
crate::lsp::run_lsp(external_linter).await;
153+
return CliRunResult::LintSucceeded;
154+
}
155+
156+
init_tracing();
157+
init_miette();
158+
159+
command.handle_threads();
160+
161161
// stdio is blocked by LineWriter, use a BufWriter to reduce syscalls.
162162
// See `https://github.com/rust-lang/rust/issues/60673`.
163163
let mut stdout = BufWriter::new(std::io::stdout());

crates/oxc_language_server/src/linter/isolated_lint_handler.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ use tower_lsp_server::{UriExt, lsp_types::Uri};
1010

1111
use oxc_allocator::Allocator;
1212
use oxc_linter::{
13-
AllowWarnDeny, ConfigStore, DisableDirectives, Fix, FixKind, LINTABLE_EXTENSIONS, LintOptions,
14-
LintRunner, LintRunnerBuilder, LintServiceOptions, Linter, Message, PossibleFixes,
15-
RuleCommentType, RuntimeFileSystem, read_to_arena_str, read_to_string,
13+
AllowWarnDeny, ConfigStore, DisableDirectives, ExternalLinter, Fix, FixKind,
14+
LINTABLE_EXTENSIONS, LintOptions, LintRunner, LintRunnerBuilder, LintServiceOptions, Linter,
15+
Message, PossibleFixes, RuleCommentType, RuntimeFileSystem, read_to_arena_str, read_to_string,
1616
};
1717

1818
use super::error_with_position::{
@@ -68,12 +68,13 @@ impl IsolatedLintHandler {
6868
cwd: &Path,
6969
lint_options: LintOptions,
7070
config_store: ConfigStore,
71+
external_linter: Option<ExternalLinter>,
7172
options: &IsolatedLintHandlerOptions,
7273
) -> Self {
7374
let config_store_clone = config_store.clone();
7475
let cwd = cwd.to_string_lossy().to_string();
7576

76-
let linter = Linter::new(cwd.clone(), lint_options, config_store, None);
77+
let linter = Linter::new(cwd.clone(), lint_options, config_store, external_linter);
7778
let mut lint_service_options = LintServiceOptions::new(options.root_path.clone())
7879
.with_cross_module(options.use_cross_module);
7980

@@ -123,6 +124,7 @@ impl IsolatedLintHandler {
123124
debug!("lint {}", path.display());
124125
let rope = &Rope::from_str(source_text);
125126

127+
// ToDO: with external linter, we need a new FS (raw) system
126128
let fs = IsolatedLintHandlerFileSystem::new(path.to_path_buf(), Arc::from(source_text));
127129

128130
let mut messages: Vec<DiagnosticReport> = self

0 commit comments

Comments
 (0)