Skip to content
This repository was archived by the owner on Mar 12, 2025. It is now read-only.
Draft
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
83 changes: 13 additions & 70 deletions crates/stc_ts_lang_server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ use stc_ts_utils::StcComments;
use swc_common::{BytePos, FileName, Globals, SourceMap, GLOBALS};
use tokio::task::{spawn_blocking, JoinHandle};
use tower_lsp::{
async_trait,
jsonrpc::{self},
lsp_types::{notification::PublishDiagnostics, *},
Client, LanguageServer, LspService, Server,
Client, LspService, Server,
};
use tracing::{error, info};

Expand All @@ -23,6 +21,7 @@ pub mod config;
pub mod ir;
pub mod module_loader;
pub mod parser;
mod server_impl;
pub mod type_checker;

#[derive(Debug, Args)]
Expand Down Expand Up @@ -117,6 +116,13 @@ impl Project {

Request::ValidateFile { filename } => {
let file = db.read_file(&filename);
let file = match file {
Some(v) => v,
None => {
error!("file not found: {:?}", filename);
return;
}
};

let input = crate::type_checker::prepare_input(&db, file);
let _module_type = crate::type_checker::check_type(&db, input);
Expand Down Expand Up @@ -187,61 +193,6 @@ enum Request {
ValidateFile { filename: Arc<FileName> },
}

#[async_trait]
impl LanguageServer for StcLangServer {
async fn initialize(&self, _params: InitializeParams) -> jsonrpc::Result<InitializeResult> {
Ok(InitializeResult {
capabilities: ServerCapabilities {
text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions {
open_close: Some(true),
change: None,
..Default::default()
})),
workspace: Some(WorkspaceServerCapabilities {
workspace_folders: Some(WorkspaceFoldersServerCapabilities {
supported: Some(true),
..Default::default()
}),
..Default::default()
}),

..Default::default()
},
server_info: Some(ServerInfo {
name: "stc-ts-lsp".to_string(),
version: Some(env!("CARGO_PKG_VERSION").to_string()),
}),
})
}

async fn shutdown(&self) -> jsonrpc::Result<()> {
Ok(())
}

async fn did_open(&self, params: DidOpenTextDocumentParams) {
self.project
.sender
.lock()
.await
.send(Request::ValidateFile {
filename: to_filename(params.text_document.uri),
})
.expect("failed to send request");
}

async fn did_change(&self, params: DidChangeTextDocumentParams) {
self.project
.sender
.lock()
.await
.send(Request::SetFileContent {
filename: to_filename(params.text_document.uri),
content: params.content_changes[0].text.clone(),
})
.expect("failed to send request");
}
}

#[salsa::jar(db = Db)]
pub struct Jar(
crate::config::ParsedTsConfig,
Expand All @@ -262,7 +213,7 @@ pub struct Jar(
);

pub trait Db: salsa::DbWithJar<Jar> {
fn read_file(&self, path: &Arc<FileName>) -> SourceFile;
fn read_file(&self, path: &Arc<FileName>) -> Option<SourceFile>;

fn shared(&self) -> &Arc<Shared>;
}
Expand All @@ -281,23 +232,15 @@ impl Db for Database {
&self.shared
}

fn read_file(&self, path: &Arc<FileName>) -> SourceFile {
fn read_file(&self, path: &Arc<FileName>) -> Option<SourceFile> {
match self.files.get(path) {
Some(file) => *file,
Some(file) => Some(*file),
None => {
error!("File not found: {:?}", path);
// TODO: Error
SourceFile::new(self, path.clone(), "".to_string())
None
}
}
}
}

impl salsa::Database for Database {}

fn to_filename(uri: Url) -> Arc<FileName> {
if let Ok(v) = uri.to_file_path() {
return Arc::new(FileName::Real(v));
}
Arc::new(FileName::Url(uri))
}
91 changes: 91 additions & 0 deletions crates/stc_ts_lang_server/src/server_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use std::sync::Arc;

use swc_common::FileName;
use tower_lsp::{
async_trait,
jsonrpc::{self},
lsp_types::{InitializeResult, *},
LanguageServer,
};

use crate::{Request, StcLangServer};

#[async_trait]
impl LanguageServer for StcLangServer {
async fn initialize(&self, _params: InitializeParams) -> jsonrpc::Result<InitializeResult> {
Ok(InitializeResult {
capabilities: ServerCapabilities {
text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions {
open_close: Some(true),
change: None,
..Default::default()
})),
hover_provider: Some(HoverProviderCapability::Options(HoverOptions {
work_done_progress_options: WorkDoneProgressOptions {
work_done_progress: Some(false),
},
})),
workspace: Some(WorkspaceServerCapabilities {
workspace_folders: Some(WorkspaceFoldersServerCapabilities {
supported: Some(true),
..Default::default()
}),
..Default::default()
}),

..Default::default()
},
server_info: Some(ServerInfo {
name: "stc-ts-lsp".to_string(),
version: Some(env!("CARGO_PKG_VERSION").to_string()),
}),
})
}

async fn shutdown(&self) -> jsonrpc::Result<()> {
Ok(())
}

// async fn hover(&self, params: HoverParams) -> jsonrpc::Result<Option<Hover>>
// {}

async fn did_open(&self, params: DidOpenTextDocumentParams) {
let filename = to_filename(params.text_document.uri);

self.project
.sender
.lock()
.await
.send(Request::SetFileContent {
filename: filename.clone(),
content: params.text_document.text,
})
.expect("failed to send request");

self.project
.sender
.lock()
.await
.send(Request::ValidateFile { filename })
.expect("failed to send request");
}

async fn did_change(&self, params: DidChangeTextDocumentParams) {
self.project
.sender
.lock()
.await
.send(Request::SetFileContent {
filename: to_filename(params.text_document.uri),
content: params.content_changes[0].text.clone(),
})
.expect("failed to send request");
}
}

fn to_filename(uri: Url) -> Arc<FileName> {
if let Ok(v) = uri.to_file_path() {
return Arc::new(FileName::Real(v));
}
Arc::new(FileName::Url(uri))
}