Skip to content
This repository was archived by the owner on Mar 12, 2025. It is now read-only.

feat(lsp): Dump type on hover #1007

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
@@ -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};

@@ -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)]
@@ -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);
@@ -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,
@@ -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>;
}
@@ -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))
}