Skip to content

Commit

Permalink
Upgrade web demo and tower-lsp (#411)
Browse files Browse the repository at this point in the history
* Use latest tower-lsp community fork from git

* Rewrite web demo to use an up-to-date monaco/vscode wrapper

* Use workspace dependency for tower-lsp

* Add explanation on deprecated root_uri field

* Remove two console.log calls

* [chore] include tower-lsp in nix outputHashes

* Fix formatting

---------

Co-authored-by: mangoiv <[email protected]>
  • Loading branch information
timsueberkrueb and MangoIV authored Dec 9, 2024
1 parent 25dfde6 commit 3a47c0e
Show file tree
Hide file tree
Showing 24 changed files with 2,663 additions and 1,012 deletions.
1,128 changes: 597 additions & 531 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ categories = ["compilers"]
# fancy error messages
miette = { version = "7" }
thiserror = { version = "1" }
# lsp server
tower-lsp = { git = "https://github.com/tower-lsp/tower-lsp", rev = "19f5a87810ff4b643d2bc394e438450bd9c74365", default-features = false, features = [
"runtime-agnostic",
] }
# source code locations
codespan = { git = "https://github.com/polarity-lang/codespan.git", rev = "542320ab177fd38fff3a398a97b3f0352e065149" }
# ignoring fields when deriving traits (e.g. Eq, Hash)
Expand Down
2 changes: 1 addition & 1 deletion app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ log = { workspace = true }
tokio = { version = "1", features = ["rt-multi-thread"] }
futures = "0.3"
async-std = "1"
tower-lsp = { version = "0.17", default-features = false, features = ["runtime-agnostic"] }
tower-lsp = { workspace = true }
# workspace members
driver = { path = "../lang/driver" }
elaborator = { path = "../lang/elaborator" }
Expand Down
1 change: 1 addition & 0 deletions contrib/nix/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ rustPlatform.buildRustPackage rec {
lockFile = "${src}/Cargo.lock";
outputHashes = {
"codespan-0.11.1" = "sha256-Wq99v77bqSGIOK/iyv+x/EG1563XSeaTDW5K2X3kSXU=";
"tower-lsp-0.20.0" = "sha256-f3S2CyFFX6yylaxMoXhB1/bfizVsLfNldLM+dXl5Y8k=";
};
};

Expand Down
5 changes: 1 addition & 4 deletions lang/lsp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ categories.workspace = true

[dependencies]
# lsp
lsp = { version = "0.93", package = "lsp-types" }
tower-lsp = { version = "0.17", default-features = false, features = [
"runtime-agnostic",
] }
tower-lsp = { workspace = true }
# asynchronous locks
async-lock = "2"
# source code spans
Expand Down
16 changes: 8 additions & 8 deletions lang/lsp/src/capabilities.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
use tower_lsp::lsp_types::*;

pub fn capabilities() -> lsp::ServerCapabilities {
pub fn capabilities() -> ServerCapabilities {
let text_document_sync = {
let options = lsp::TextDocumentSyncOptions {
let options = TextDocumentSyncOptions {
open_close: Some(true),
change: Some(lsp::TextDocumentSyncKind::FULL),
change: Some(TextDocumentSyncKind::FULL),
..Default::default()
};
Some(lsp::TextDocumentSyncCapability::Options(options))
Some(TextDocumentSyncCapability::Options(options))
};

let hover_provider = Some(HoverProviderCapability::Simple(true));

let code_action_provider = Some(lsp::CodeActionProviderCapability::Simple(true));
let code_action_provider = Some(CodeActionProviderCapability::Simple(true));

let document_formatting_provider = Some(lsp::OneOf::Left(true));
let document_formatting_provider = Some(OneOf::Left(true));

let definition_provider = Some(lsp::OneOf::Left(true));
let definition_provider = Some(OneOf::Left(true));

lsp::ServerCapabilities {
ServerCapabilities {
text_document_sync,
hover_provider,
code_action_provider,
Expand Down
25 changes: 18 additions & 7 deletions lang/lsp/src/codeactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,40 @@ pub async fn code_action(

server
.client
.log_message(MessageType::INFO, format!("Code action request: {}", text_document.uri))
.log_message(
MessageType::INFO,
format!("Code action request: {}", text_document.uri.as_str()),
)
.await;

let mut db = server.database.write().await;
let span_start = db.location_to_index(&text_document.uri, range.start.from_lsp());
let span_end = db.location_to_index(&text_document.uri, range.end.from_lsp());
let span_start = db.location_to_index(&text_document.uri.from_lsp(), range.start.from_lsp());
let span_end = db.location_to_index(&text_document.uri.from_lsp(), range.end.from_lsp());
let span = span_start.and_then(|start| span_end.map(|end| codespan::Span::new(start, end)));
let item =
if let Some(span) = span { db.item_at_span(&text_document.uri, span).await } else { None };
let item = if let Some(span) = span {
db.item_at_span(&text_document.uri.from_lsp(), span).await
} else {
None
};

if let Some(item) = item {
let Ok(Xfunc { title, edits }) = db.xfunc(&text_document.uri, item.type_name()).await
let Ok(Xfunc { title, edits }) =
db.xfunc(&text_document.uri.from_lsp(), item.type_name()).await
else {
return Ok(None);
};
let edits = edits
.into_iter()
.map(|edit| TextEdit {
range: db.span_to_locations(&text_document.uri, edit.span).unwrap().to_lsp(),
range: db
.span_to_locations(&text_document.uri.from_lsp(), edit.span)
.unwrap()
.to_lsp(),
new_text: edit.text,
})
.collect();

#[allow(clippy::mutable_key_type)]
let mut changes = HashMap::new();
changes.insert(text_document.uri, edits);

Expand Down
3 changes: 2 additions & 1 deletion lang/lsp/src/conversion/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use lsp::DiagnosticSeverity;
use miette::Severity;
use tower_lsp::lsp_types::DiagnosticSeverity;

mod spans;
mod uri_to_url;

pub trait FromLsp {
type Target;
Expand Down
21 changes: 21 additions & 0 deletions lang/lsp/src/conversion/uri_to_url.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use std::str::FromStr;

use tower_lsp::lsp_types::Uri;

use super::{FromLsp, ToLsp};

impl FromLsp for &Uri {
type Target = url::Url;

fn from_lsp(self) -> Self::Target {
url::Url::parse(self.as_str()).expect("Failed to parse URI")
}
}

impl ToLsp for &url::Url {
type Target = Uri;

fn to_lsp(self) -> Self::Target {
Uri::from_str(self.as_str()).expect("Failed to parse URL")
}
}
9 changes: 7 additions & 2 deletions lang/lsp/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use tower_lsp::jsonrpc::Result;
use tower_lsp::lsp_types::*;

use crate::conversion::FromLsp;

use super::server::*;
use printer::{Print, PrintCfg};

Expand All @@ -13,12 +15,15 @@ pub async fn formatting(

server
.client
.log_message(MessageType::INFO, format!("Formatting request: {}", text_document.uri))
.log_message(
MessageType::INFO,
format!("Formatting request: {}", text_document.uri.from_lsp()),
)
.await;

let mut db = server.database.write().await;

let prg = match db.ust(&text_document.uri).await {
let prg = match db.ust(&text_document.uri.from_lsp()).await {
Ok(prg) => prg,
Err(_) => return Ok(None),
};
Expand Down
33 changes: 18 additions & 15 deletions lang/lsp/src/gotodefinition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@ pub async fn goto_definition(

server
.client
.log_message(MessageType::INFO, format!("GotoDefinition request: {}", text_document.uri))
.log_message(
MessageType::INFO,
format!("GotoDefinition request: {}", text_document.uri.from_lsp()),
)
.await;

let pos = pos_params.position;
let mut db = server.database.write().await;
let info = db.location_to_index(&text_document.uri, pos.from_lsp());
let info = db.location_to_index(&text_document.uri.from_lsp(), pos.from_lsp());
let info = match info {
Some(idx) => db.hoverinfo_at_index(&text_document.uri, idx).await,
Some(idx) => db.hoverinfo_at_index(&text_document.uri.from_lsp(), idx).await,
None => None,
};
let res = info.and_then(|info| info_to_jump(&db, info));
Expand All @@ -36,17 +39,17 @@ fn info_to_jump(db: &Database, info: Info) -> Option<GotoDefinitionResponse> {
Some(GotoDefinitionResponse::Scalar(jump_location))
}

fn span_to_location(span: &Span, uri: &Url, db: &Database) -> Option<Location> {
let range = db.span_to_locations(uri, *span).map(ToLsp::to_lsp)?;
fn span_to_location(span: &Span, uri: &Uri, db: &Database) -> Option<Location> {
let range = db.span_to_locations(&uri.from_lsp(), *span).map(ToLsp::to_lsp)?;
Some(Location { uri: uri.clone(), range })
}

trait ToJumpTarget {
fn to_jump_target(&self) -> Option<(Url, Span)>;
fn to_jump_target(&self) -> Option<(Uri, Span)>;
}

impl ToJumpTarget for InfoContent {
fn to_jump_target(&self) -> Option<(Url, Span)> {
fn to_jump_target(&self) -> Option<(Uri, Span)> {
match self {
InfoContent::TypeCtorInfo(i) => i.to_jump_target(),
InfoContent::CallInfo(i) => i.to_jump_target(),
Expand All @@ -58,28 +61,28 @@ impl ToJumpTarget for InfoContent {
}

impl ToJumpTarget for UseInfo {
fn to_jump_target(&self) -> Option<(Url, Span)> {
Some((self.uri.clone(), Span::default()))
fn to_jump_target(&self) -> Option<(Uri, Span)> {
Some((self.uri.to_lsp(), Span::default()))
}
}

impl ToJumpTarget for TypeCtorInfo {
fn to_jump_target(&self) -> Option<(Url, Span)> {
fn to_jump_target(&self) -> Option<(Uri, Span)> {
let TypeCtorInfo { definition_site, .. } = self;
definition_site.clone()
definition_site.clone().map(|(url, span)| (url.to_lsp(), span))
}
}

impl ToJumpTarget for CallInfo {
fn to_jump_target(&self) -> Option<(Url, Span)> {
fn to_jump_target(&self) -> Option<(Uri, Span)> {
let CallInfo { definition_site, .. } = self;
definition_site.clone()
definition_site.clone().map(|(url, span)| (url.to_lsp(), span))
}
}

impl ToJumpTarget for DotCallInfo {
fn to_jump_target(&self) -> Option<(Url, Span)> {
fn to_jump_target(&self) -> Option<(Uri, Span)> {
let DotCallInfo { definition_site, .. } = self;
definition_site.clone()
definition_site.clone().map(|(url, span)| (url.to_lsp(), span))
}
}
10 changes: 5 additions & 5 deletions lang/lsp/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,24 @@ pub async fn hover(server: &Server, params: HoverParams) -> jsonrpc::Result<Opti

server
.client
.log_message(MessageType::INFO, format!("Hover request: {}", text_document.uri))
.log_message(MessageType::INFO, format!("Hover request: {}", text_document.uri.from_lsp()))
.await;

let pos = pos_params.position;
let mut db = server.database.write().await;
let info = db.location_to_index(&text_document.uri, pos.from_lsp());
let info = db.location_to_index(&text_document.uri.from_lsp(), pos.from_lsp());

let info = match info {
Some(idx) => db.hoverinfo_at_index(&text_document.uri, idx).await,
Some(idx) => db.hoverinfo_at_index(&text_document.uri.from_lsp(), idx).await,
None => None,
};

let res = info.map(|info| info_to_hover(&db, &text_document.uri, info));
Ok(res)
}

fn info_to_hover(db: &Database, uri: &Url, info: Info) -> Hover {
let range = db.span_to_locations(uri, info.span).map(ToLsp::to_lsp);
fn info_to_hover(db: &Database, uri: &Uri, info: Info) -> Hover {
let range = db.span_to_locations(&uri.from_lsp(), info.span).map(ToLsp::to_lsp);
let contents = info.content.to_hover_content();
Hover { contents, range }
}
Expand Down
44 changes: 28 additions & 16 deletions lang/lsp/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use driver::Database;
#[cfg(not(target_arch = "wasm32"))]
use driver::{FileSource, FileSystemSource, InMemorySource};

use crate::conversion::FromLsp;

use super::capabilities::*;
use super::diagnostics::*;

Expand All @@ -30,9 +32,13 @@ impl LanguageServer for Server {
async fn initialize(&self, params: InitializeParams) -> jsonrpc::Result<InitializeResult> {
let capabilities = capabilities();
#[cfg(not(target_arch = "wasm32"))]
// FIXME: Use `workspace_folders` instead of `root_uri`.
// `root_uri` is deprecated in in favor of `workspace_folders`, see:
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize
#[allow(deprecated)]
if let Some(root_uri) = params.root_uri {
let root_path =
root_uri.to_file_path().map_err(|_| jsonrpc::Error::internal_error())?;
root_uri.from_lsp().to_file_path().map_err(|_| jsonrpc::Error::internal_error())?;
let source = InMemorySource::new().fallback_to(FileSystemSource::new(root_path));
let mut database = self.database.write().await;
let source_mut = database.file_source_mut();
Expand All @@ -52,46 +58,52 @@ impl LanguageServer for Server {
Ok(())
}

async fn did_open(&self, params: lsp::DidOpenTextDocumentParams) {
async fn did_open(&self, params: DidOpenTextDocumentParams) {
let text_document = params.text_document;
let mut db = self.database.write().await;

self.client
.log_message(MessageType::INFO, format!("Opened file: {}", text_document.uri))
.log_message(
MessageType::INFO,
format!("Opened file: {}", text_document.uri.from_lsp()),
)
.await;

let source_mut = db.file_source_mut();
assert!(source_mut.manage(&text_document.uri));
source_mut.write_string(&text_document.uri, &text_document.text).await.unwrap();
assert!(source_mut.manage(&text_document.uri.from_lsp()));
source_mut.write_string(&text_document.uri.from_lsp(), &text_document.text).await.unwrap();

let res = db.ast(&text_document.uri).await.map(|_| ());
let diags = db.diagnostics(&text_document.uri, res);
let res = db.ast(&text_document.uri.from_lsp()).await.map(|_| ());
let diags = db.diagnostics(&text_document.uri.from_lsp(), res);
self.send_diagnostics(text_document.uri, diags).await;
}

async fn did_change(&self, params: lsp::DidChangeTextDocumentParams) {
async fn did_change(&self, params: DidChangeTextDocumentParams) {
let text_document = params.text_document;
let mut content_changes = params.content_changes;

self.client
.log_message(MessageType::INFO, format!("Changed file: {}", text_document.uri))
.log_message(
MessageType::INFO,
format!("Changed file: {}", text_document.uri.from_lsp()),
)
.await;

let mut db = self.database.write().await;
let text = content_changes.drain(0..).next().unwrap().text;

let source_mut = db.file_source_mut();
assert!(source_mut.manage(&text_document.uri));
source_mut.write_string(&text_document.uri, &text).await.unwrap();
assert!(source_mut.manage(&text_document.uri.from_lsp()));
source_mut.write_string(&text_document.uri.from_lsp(), &text).await.unwrap();

let res = db.invalidate(&text_document.uri).await;
let res = db.invalidate(&text_document.uri.from_lsp()).await;

let res = match res {
Ok(()) => db.ast(&text_document.uri).await.map(|_| ()),
Ok(()) => db.ast(&text_document.uri.from_lsp()).await.map(|_| ()),
Err(_) => Ok(()),
};

let diags = db.diagnostics(&text_document.uri, res);
let diags = db.diagnostics(&text_document.uri.from_lsp(), res);
self.send_diagnostics(text_document.uri, diags).await;
}

Expand Down Expand Up @@ -119,7 +131,7 @@ impl LanguageServer for Server {
}

impl Server {
pub(crate) async fn send_diagnostics(&self, url: Url, diags: Vec<Diagnostic>) {
self.client.publish_diagnostics(url, diags, None).await;
pub(crate) async fn send_diagnostics(&self, uri: Uri, diags: Vec<Diagnostic>) {
self.client.publish_diagnostics(uri, diags, None).await;
}
}
2 changes: 1 addition & 1 deletion web/crates/browser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ crate-type = ["cdylib", "rlib"]
# async
async-trait = "0.1"
futures = "0.3"
tower-lsp = { version = "0.17", default-features = false }
tower-lsp = { workspace = true }
# web platform
console_error_panic_hook = "0.1"
js-sys = "0.3"
Expand Down
Loading

0 comments on commit 3a47c0e

Please sign in to comment.