0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 09:31:22 -05:00

feat(lsp): support the unstable setting (#8851)

This commit is contained in:
Kitson Kelly 2020-12-22 21:21:18 +11:00 committed by GitHub
parent b091c6c8c9
commit 097c3379ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 224 additions and 84 deletions

View file

@ -89,49 +89,34 @@ impl LanguageServer {
config.settings.enable
}
pub async fn update_import_map(&self) -> Result<(), AnyError> {
let (maybe_import_map, maybe_root_uri) = {
let config = self.config.read().unwrap();
(config.settings.import_map.clone(), config.root_uri.clone())
};
if let Some(import_map_str) = &maybe_import_map {
info!("update import map");
let import_map_url = if let Ok(url) = Url::from_file_path(import_map_str)
pub async fn get_line_index(
&self,
specifier: ModuleSpecifier,
) -> Result<Vec<u32>, AnyError> {
let line_index = if specifier.as_url().scheme() == "asset" {
let state_snapshot = self.snapshot();
if let Some(source) =
tsc::get_asset(&specifier, &self.ts_server, &state_snapshot).await?
{
Ok(url)
} else if let Some(root_uri) = &maybe_root_uri {
let root_path = root_uri
.to_file_path()
.map_err(|_| anyhow!("Bad root_uri: {}", root_uri))?;
let import_map_path = root_path.join(import_map_str);
Url::from_file_path(import_map_path).map_err(|_| {
anyhow!("Bad file path for import map: {:?}", import_map_str)
})
text::index_lines(&source)
} else {
Err(anyhow!(
"The path to the import map (\"{}\") is not resolvable.",
import_map_str
))
}?;
let import_map_path = import_map_url
.to_file_path()
.map_err(|_| anyhow!("Bad file path."))?;
let import_map_json =
fs::read_to_string(import_map_path).await.map_err(|err| {
anyhow!(
"Failed to load the import map at: {}. [{}]",
import_map_url,
err
)
})?;
let import_map =
ImportMap::from_json(&import_map_url.to_string(), &import_map_json)?;
*self.maybe_import_map_uri.write().unwrap() = Some(import_map_url);
*self.maybe_import_map.write().unwrap() = Some(import_map);
return Err(anyhow!("asset source missing: {}", specifier));
}
} else {
*self.maybe_import_map.write().unwrap() = None;
}
Ok(())
let file_cache = self.file_cache.read().unwrap();
if let Some(file_id) = file_cache.lookup(&specifier) {
let file_text = file_cache.get_contents(file_id)?;
text::index_lines(&file_text)
} else {
let mut sources = self.sources.write().unwrap();
if let Some(line_index) = sources.get_line_index(&specifier) {
line_index
} else {
return Err(anyhow!("source for specifier not found: {}", specifier));
}
}
};
Ok(line_index)
}
async fn prepare_diagnostics(&self) -> Result<(), AnyError> {
@ -260,34 +245,76 @@ impl LanguageServer {
}
}
pub async fn get_line_index(
&self,
specifier: ModuleSpecifier,
) -> Result<Vec<u32>, AnyError> {
let line_index = if specifier.as_url().scheme() == "asset" {
let state_snapshot = self.snapshot();
if let Some(source) =
tsc::get_asset(&specifier, &self.ts_server, &state_snapshot).await?
{
text::index_lines(&source)
} else {
return Err(anyhow!("asset source missing: {}", specifier));
}
} else {
let file_cache = self.file_cache.read().unwrap();
if let Some(file_id) = file_cache.lookup(&specifier) {
let file_text = file_cache.get_contents(file_id)?;
text::index_lines(&file_text)
} else {
let mut sources = self.sources.write().unwrap();
if let Some(line_index) = sources.get_line_index(&specifier) {
line_index
} else {
return Err(anyhow!("source for specifier not found: {}", specifier));
}
}
pub async fn update_import_map(&self) -> Result<(), AnyError> {
let (maybe_import_map, maybe_root_uri) = {
let config = self.config.read().unwrap();
(config.settings.import_map.clone(), config.root_uri.clone())
};
Ok(line_index)
if let Some(import_map_str) = &maybe_import_map {
info!("update import map");
let import_map_url = if let Ok(url) = Url::from_file_path(import_map_str)
{
Ok(url)
} else if let Some(root_uri) = &maybe_root_uri {
let root_path = root_uri
.to_file_path()
.map_err(|_| anyhow!("Bad root_uri: {}", root_uri))?;
let import_map_path = root_path.join(import_map_str);
Url::from_file_path(import_map_path).map_err(|_| {
anyhow!("Bad file path for import map: {:?}", import_map_str)
})
} else {
Err(anyhow!(
"The path to the import map (\"{}\") is not resolvable.",
import_map_str
))
}?;
let import_map_path = import_map_url
.to_file_path()
.map_err(|_| anyhow!("Bad file path."))?;
let import_map_json =
fs::read_to_string(import_map_path).await.map_err(|err| {
anyhow!(
"Failed to load the import map at: {}. [{}]",
import_map_url,
err
)
})?;
let import_map =
ImportMap::from_json(&import_map_url.to_string(), &import_map_json)?;
*self.maybe_import_map_uri.write().unwrap() = Some(import_map_url);
*self.maybe_import_map.write().unwrap() = Some(import_map);
} else {
*self.maybe_import_map.write().unwrap() = None;
}
Ok(())
}
async fn update_tsconfig(&self) -> Result<(), AnyError> {
let mut tsconfig = TsConfig::new(json!({
"allowJs": true,
"experimentalDecorators": true,
"isolatedModules": true,
"lib": ["deno.ns", "deno.window"],
"module": "esnext",
"noEmit": true,
"strict": true,
"target": "esnext",
}));
{
let config = self.config.read().unwrap();
if config.settings.unstable {
let unstable_libs = json!({
"lib": ["deno.ns", "deno.window", "deno.unstable"]
});
tsconfig.merge(&unstable_libs);
}
}
self
.ts_server
.request(self.snapshot(), tsc::RequestMethod::Configure(tsconfig))
.await?;
Ok(())
}
}
@ -331,23 +358,9 @@ impl lspower::LanguageServer for LanguageServer {
config.update_capabilities(&params.capabilities);
}
// TODO(@kitsonk) need to make this configurable, respect unstable
let ts_config = TsConfig::new(json!({
"allowJs": true,
"experimentalDecorators": true,
"isolatedModules": true,
"lib": ["deno.ns", "deno.window"],
"module": "esnext",
"noEmit": true,
"strict": true,
"target": "esnext",
}));
// TODO(lucacasonato): handle error correctly
self
.ts_server
.request(self.snapshot(), tsc::RequestMethod::Configure(ts_config))
.await
.unwrap();
if let Err(err) = self.update_tsconfig().await {
warn!("Updating tsconfig has errored: {}", err);
}
Ok(InitializeResult {
capabilities,
@ -502,6 +515,12 @@ impl lspower::LanguageServer for LanguageServer {
.show_message(MessageType::Warning, err.to_string())
.await;
}
if let Err(err) = self.update_tsconfig().await {
self
.client
.show_message(MessageType::Warning, err.to_string())
.await;
}
}
_ => error!("received empty extension settings from the client"),
}
@ -1014,4 +1033,83 @@ mod tests {
]);
harness.run().await;
}
#[tokio::test]
async fn test_hover_unstable_disabled() {
let mut harness = LspTestHarness::new(vec![
("initialize_request.json", LspResponse::RequestAny),
("initialized_notification.json", LspResponse::None),
("did_open_notification_unstable.json", LspResponse::None),
(
"hover_request.json",
LspResponse::Request(
2,
json!({
"contents": [
{
"language": "typescript",
"value": "any"
}
],
"range": {
"start": {
"line": 0,
"character": 17
},
"end": {
"line": 0,
"character": 28
}
}
}),
),
),
(
"shutdown_request.json",
LspResponse::Request(3, json!(null)),
),
("exit_notification.json", LspResponse::None),
]);
harness.run().await;
}
#[tokio::test]
async fn test_hover_unstable_enabled() {
let mut harness = LspTestHarness::new(vec![
("initialize_request_unstable.json", LspResponse::RequestAny),
("initialized_notification.json", LspResponse::None),
("did_open_notification_unstable.json", LspResponse::None),
(
"hover_request.json",
LspResponse::Request(
2,
json!({
"contents": [
{
"language": "typescript",
"value": "const Deno.permissions: Deno.Permissions"
},
"**UNSTABLE**: Under consideration to move to `navigator.permissions` to\nmatch web API. It could look like `navigator.permissions.query({ name: Deno.symbols.read })`."
],
"range": {
"start": {
"line": 0,
"character": 17
},
"end": {
"line": 0,
"character": 28
}
}
}),
),
),
(
"shutdown_request.json",
LspResponse::Request(3, json!(null)),
),
("exit_notification.json", LspResponse::None),
]);
harness.run().await;
}
}

View file

@ -0,0 +1,12 @@
{
"jsonrpc": "2.0",
"method": "textDocument/didOpen",
"params": {
"textDocument": {
"uri": "file:///a/file.ts",
"languageId": "typescript",
"version": 1,
"text": "console.log(Deno.permissions);\n"
}
}
}

View file

@ -0,0 +1,30 @@
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"processId": 0,
"clientInfo": {
"name": "test-harness",
"version": "1.0.0"
},
"rootUri": null,
"initializationOptions": {
"enable": true,
"lint": true,
"unstable": true,
"config": null,
"importMap": null
},
"capabilities": {
"textDocument": {
"synchronization": {
"dynamicRegistration": true,
"willSave": true,
"willSaveWaitUntil": true,
"didSave": true
}
}
}
}
}