mirror of
https://github.com/denoland/deno.git
synced 2025-01-03 12:58:54 -05:00
parent
d6f6e157bd
commit
3b3be024fa
10 changed files with 749 additions and 19 deletions
|
@ -24,6 +24,7 @@ There are several settings that the language server supports for a workspace:
|
|||
- `deno.codeLens.implementations`
|
||||
- `deno.codeLens.references`
|
||||
- `deno.codeLens.referencesAllFunctions`
|
||||
- `deno.codeLens.test`
|
||||
- `deno.suggest.completeFunctionCalls`
|
||||
- `deno.suggest.names`
|
||||
- `deno.suggest.paths`
|
||||
|
@ -33,10 +34,11 @@ There are several settings that the language server supports for a workspace:
|
|||
- `deno.lint`
|
||||
- `deno.unstable`
|
||||
|
||||
There are settings that are support on a per resource basis by the language
|
||||
There are settings that are supported on a per resource basis by the language
|
||||
server:
|
||||
|
||||
- `deno.enable`
|
||||
- `deno.codeLens.test`
|
||||
|
||||
There are several points in the process where Deno analyzes these settings.
|
||||
First, when the `initialize` request from the client, the
|
||||
|
@ -68,7 +70,24 @@ settings.
|
|||
If the client does not have the `workspaceConfiguration` capability, the
|
||||
language server will assume the workspace setting applies to all resources.
|
||||
|
||||
## Custom requests
|
||||
## Commands
|
||||
|
||||
There are several commands that might be issued by the language server to the
|
||||
client, which the client is expected to implement:
|
||||
|
||||
- `deno.cache` - This is sent as a resolution code action when there is an
|
||||
un-cached module specifier that is being imported into a module. It will be
|
||||
sent with and argument that contains the resolved specifier as a string to be
|
||||
cached.
|
||||
- `deno.showReferences` - This is sent as the command on some code lenses to
|
||||
show locations of references. The arguments contain the specifier that is the
|
||||
subject of the command, the start position of the target and the locations of
|
||||
the references to show.
|
||||
- `deno.test` - This is sent as part of a test code lens to, of which the client
|
||||
is expected to run a test based on the arguments, which are the specifier the
|
||||
test is contained in and the name of the test to filter the tests on.
|
||||
|
||||
## Requests
|
||||
|
||||
The LSP currently supports the following custom requests. A client should
|
||||
implement these in order to have a fully functioning client that integrates well
|
||||
|
@ -115,9 +134,9 @@ with Deno:
|
|||
}
|
||||
```
|
||||
|
||||
## Custom notifications
|
||||
## Notifications
|
||||
|
||||
There is currently one custom notification that is send from the server to the
|
||||
There is currently one custom notification that is sent from the server to the
|
||||
client:
|
||||
|
||||
- `deno/registryStatus` - when `deno.suggest.imports.autoDiscover` is `true` and
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use super::analysis;
|
||||
use super::language_server;
|
||||
use super::tsc;
|
||||
|
||||
|
@ -14,7 +15,14 @@ use deno_core::ModuleSpecifier;
|
|||
use lspower::lsp;
|
||||
use regex::Regex;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashSet;
|
||||
use std::rc::Rc;
|
||||
use swc_common::SourceMap;
|
||||
use swc_common::Span;
|
||||
use swc_ecmascript::ast;
|
||||
use swc_ecmascript::visit::Node;
|
||||
use swc_ecmascript::visit::Visit;
|
||||
use swc_ecmascript::visit::VisitWith;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref ABSTRACT_MODIFIER: Regex = Regex::new(r"\babstract\b").unwrap();
|
||||
|
@ -36,6 +44,174 @@ pub struct CodeLensData {
|
|||
pub specifier: ModuleSpecifier,
|
||||
}
|
||||
|
||||
fn span_to_range(span: &Span, source_map: Rc<SourceMap>) -> lsp::Range {
|
||||
let start = source_map.lookup_char_pos(span.lo);
|
||||
let end = source_map.lookup_char_pos(span.hi);
|
||||
lsp::Range {
|
||||
start: lsp::Position {
|
||||
line: (start.line - 1) as u32,
|
||||
character: start.col_display as u32,
|
||||
},
|
||||
end: lsp::Position {
|
||||
line: (end.line - 1) as u32,
|
||||
character: end.col_display as u32,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
struct DenoTestCollector {
|
||||
code_lenses: Vec<lsp::CodeLens>,
|
||||
source_map: Rc<SourceMap>,
|
||||
specifier: ModuleSpecifier,
|
||||
test_vars: HashSet<String>,
|
||||
}
|
||||
|
||||
impl DenoTestCollector {
|
||||
pub fn new(specifier: ModuleSpecifier, source_map: Rc<SourceMap>) -> Self {
|
||||
Self {
|
||||
code_lenses: Vec::new(),
|
||||
source_map,
|
||||
specifier,
|
||||
test_vars: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_code_lens<N: AsRef<str>>(&mut self, name: N, span: &Span) {
|
||||
let range = span_to_range(span, self.source_map.clone());
|
||||
self.code_lenses.push(lsp::CodeLens {
|
||||
range,
|
||||
command: Some(lsp::Command {
|
||||
title: "▶\u{fe0e} Run Test".to_string(),
|
||||
command: "deno.test".to_string(),
|
||||
arguments: Some(vec![json!(self.specifier), json!(name.as_ref())]),
|
||||
}),
|
||||
data: None,
|
||||
});
|
||||
}
|
||||
|
||||
fn check_call_expr(&mut self, node: &ast::CallExpr, span: &Span) {
|
||||
if let Some(expr) = node.args.get(0).map(|es| es.expr.as_ref()) {
|
||||
match expr {
|
||||
ast::Expr::Object(obj_lit) => {
|
||||
for prop in &obj_lit.props {
|
||||
if let ast::PropOrSpread::Prop(prop) = prop {
|
||||
if let ast::Prop::KeyValue(key_value_prop) = prop.as_ref() {
|
||||
if let ast::PropName::Ident(ident) = &key_value_prop.key {
|
||||
if ident.sym.to_string() == "name" {
|
||||
if let ast::Expr::Lit(ast::Lit::Str(lit_str)) =
|
||||
key_value_prop.value.as_ref()
|
||||
{
|
||||
let name = lit_str.value.to_string();
|
||||
self.add_code_lens(name, &span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Expr::Lit(ast::Lit::Str(lit_str)) => {
|
||||
let name = lit_str.value.to_string();
|
||||
self.add_code_lens(name, &span);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Move out the code lenses from the collector.
|
||||
fn take(self) -> Vec<lsp::CodeLens> {
|
||||
self.code_lenses
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for DenoTestCollector {
|
||||
fn visit_call_expr(&mut self, node: &ast::CallExpr, _parent: &dyn Node) {
|
||||
if let ast::ExprOrSuper::Expr(callee_expr) = &node.callee {
|
||||
match callee_expr.as_ref() {
|
||||
ast::Expr::Ident(ident) => {
|
||||
if self.test_vars.contains(&ident.sym.to_string()) {
|
||||
self.check_call_expr(node, &ident.span);
|
||||
}
|
||||
}
|
||||
ast::Expr::Member(member_expr) => {
|
||||
if let ast::Expr::Ident(ns_prop_ident) = member_expr.prop.as_ref() {
|
||||
if ns_prop_ident.sym.to_string() == "test" {
|
||||
if let ast::ExprOrSuper::Expr(obj_expr) = &member_expr.obj {
|
||||
if let ast::Expr::Ident(ident) = obj_expr.as_ref() {
|
||||
if ident.sym.to_string() == "Deno" {
|
||||
self.check_call_expr(node, &ns_prop_ident.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_var_decl(&mut self, node: &ast::VarDecl, _parent: &dyn Node) {
|
||||
for decl in &node.decls {
|
||||
if let Some(init) = &decl.init {
|
||||
match init.as_ref() {
|
||||
// Identify destructured assignments of `test` from `Deno`
|
||||
ast::Expr::Ident(ident) => {
|
||||
if ident.sym.to_string() == "Deno" {
|
||||
if let ast::Pat::Object(object_pat) = &decl.name {
|
||||
for prop in &object_pat.props {
|
||||
match prop {
|
||||
ast::ObjectPatProp::Assign(prop) => {
|
||||
let name = prop.key.sym.to_string();
|
||||
if name == "test" {
|
||||
self.test_vars.insert(name);
|
||||
}
|
||||
}
|
||||
ast::ObjectPatProp::KeyValue(prop) => {
|
||||
if let ast::PropName::Ident(key_ident) = &prop.key {
|
||||
if key_ident.sym.to_string() == "test" {
|
||||
if let ast::Pat::Ident(value_ident) =
|
||||
&prop.value.as_ref()
|
||||
{
|
||||
self
|
||||
.test_vars
|
||||
.insert(value_ident.id.sym.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Identify variable assignments where the init is `Deno.test`
|
||||
ast::Expr::Member(member_expr) => {
|
||||
if let ast::ExprOrSuper::Expr(expr) = &member_expr.obj {
|
||||
if let ast::Expr::Ident(obj_ident) = expr.as_ref() {
|
||||
if obj_ident.sym.to_string() == "Deno" {
|
||||
if let ast::Expr::Ident(prop_ident) =
|
||||
&member_expr.prop.as_ref()
|
||||
{
|
||||
if prop_ident.sym.to_string() == "test" {
|
||||
if let ast::Pat::Ident(binding_ident) = &decl.name {
|
||||
self.test_vars.insert(binding_ident.id.sym.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn resolve_implementation_code_lens(
|
||||
code_lens: lsp::CodeLens,
|
||||
data: CodeLensData,
|
||||
|
@ -189,8 +365,51 @@ pub(crate) async fn resolve_code_lens(
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn collect(
|
||||
specifier: &ModuleSpecifier,
|
||||
language_server: &mut language_server::Inner,
|
||||
) -> Result<Vec<lsp::CodeLens>, AnyError> {
|
||||
let mut code_lenses = collect_test(specifier, language_server)?;
|
||||
code_lenses.extend(collect_tsc(specifier, language_server).await?);
|
||||
|
||||
Ok(code_lenses)
|
||||
}
|
||||
|
||||
fn collect_test(
|
||||
specifier: &ModuleSpecifier,
|
||||
language_server: &mut language_server::Inner,
|
||||
) -> Result<Vec<lsp::CodeLens>, AnyError> {
|
||||
if language_server.config.specifier_code_lens_test(specifier) {
|
||||
let source = language_server
|
||||
.get_text_content(specifier)
|
||||
.ok_or_else(|| anyhow!("Missing text content: {}", specifier))?;
|
||||
let media_type = language_server
|
||||
.get_media_type(specifier)
|
||||
.ok_or_else(|| anyhow!("Missing media type: {}", specifier))?;
|
||||
// we swallow parsed errors, as they are meaningless here.
|
||||
// TODO(@kitsonk) consider caching previous code_lens results to return if
|
||||
// there is a parse error to avoid issues of lenses popping in and out
|
||||
if let Ok(parsed_module) =
|
||||
analysis::parse_module(specifier, &source, &media_type)
|
||||
{
|
||||
let mut collector = DenoTestCollector::new(
|
||||
specifier.clone(),
|
||||
parsed_module.source_map.clone(),
|
||||
);
|
||||
parsed_module.module.visit_with(
|
||||
&ast::Invalid {
|
||||
span: swc_common::DUMMY_SP,
|
||||
},
|
||||
&mut collector,
|
||||
);
|
||||
return Ok(collector.take());
|
||||
}
|
||||
}
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
/// Return tsc navigation tree code lenses.
|
||||
pub(crate) async fn tsc_code_lenses(
|
||||
async fn collect_tsc(
|
||||
specifier: &ModuleSpecifier,
|
||||
language_server: &mut language_server::Inner,
|
||||
) -> Result<Vec<lsp::CodeLens>, AnyError> {
|
||||
|
@ -282,3 +501,80 @@ pub(crate) async fn tsc_code_lenses(
|
|||
});
|
||||
Ok(Rc::try_unwrap(code_lenses).unwrap().into_inner())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::media_type::MediaType;
|
||||
|
||||
#[test]
|
||||
fn test_deno_test_collector() {
|
||||
let specifier = resolve_url("https://deno.land/x/mod.ts").unwrap();
|
||||
let source = r#"
|
||||
Deno.test({
|
||||
name: "test a",
|
||||
fn() {}
|
||||
});
|
||||
|
||||
Deno.test("test b", function anotherTest() {});
|
||||
"#;
|
||||
let parsed_module =
|
||||
analysis::parse_module(&specifier, source, &MediaType::TypeScript)
|
||||
.unwrap();
|
||||
let mut collector =
|
||||
DenoTestCollector::new(specifier, parsed_module.source_map.clone());
|
||||
parsed_module.module.visit_with(
|
||||
&ast::Invalid {
|
||||
span: swc_common::DUMMY_SP,
|
||||
},
|
||||
&mut collector,
|
||||
);
|
||||
assert_eq!(
|
||||
collector.take(),
|
||||
vec![
|
||||
lsp::CodeLens {
|
||||
range: lsp::Range {
|
||||
start: lsp::Position {
|
||||
line: 1,
|
||||
character: 11
|
||||
},
|
||||
end: lsp::Position {
|
||||
line: 1,
|
||||
character: 15
|
||||
}
|
||||
},
|
||||
command: Some(lsp::Command {
|
||||
title: "▶\u{fe0e} Run Test".to_string(),
|
||||
command: "deno.test".to_string(),
|
||||
arguments: Some(vec![
|
||||
json!("https://deno.land/x/mod.ts"),
|
||||
json!("test a"),
|
||||
])
|
||||
}),
|
||||
data: None,
|
||||
},
|
||||
lsp::CodeLens {
|
||||
range: lsp::Range {
|
||||
start: lsp::Position {
|
||||
line: 6,
|
||||
character: 11
|
||||
},
|
||||
end: lsp::Position {
|
||||
line: 6,
|
||||
character: 15
|
||||
}
|
||||
},
|
||||
command: Some(lsp::Command {
|
||||
title: "▶\u{fe0e} Run Test".to_string(),
|
||||
command: "deno.test".to_string(),
|
||||
arguments: Some(vec![
|
||||
json!("https://deno.land/x/mod.ts"),
|
||||
json!("test b"),
|
||||
])
|
||||
}),
|
||||
data: None,
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,10 @@ pub struct ClientCapabilities {
|
|||
pub line_folding_only: bool,
|
||||
}
|
||||
|
||||
fn is_true() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeLensSettings {
|
||||
|
@ -41,6 +45,10 @@ pub struct CodeLensSettings {
|
|||
/// an impact, the `references` flag needs to be `true`.
|
||||
#[serde(default)]
|
||||
pub references_all_functions: bool,
|
||||
/// Flag for providing test code lens on `Deno.test` statements. There is
|
||||
/// also the `test_args` setting, but this is not used by the server.
|
||||
#[serde(default = "is_true")]
|
||||
pub test: bool,
|
||||
}
|
||||
|
||||
impl Default for CodeLensSettings {
|
||||
|
@ -49,12 +57,24 @@ impl Default for CodeLensSettings {
|
|||
implementations: false,
|
||||
references: false,
|
||||
references_all_functions: false,
|
||||
test: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_true() -> bool {
|
||||
true
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CodeLensSpecifierSettings {
|
||||
/// Flag for providing test code lens on `Deno.test` statements. There is
|
||||
/// also the `test_args` setting, but this is not used by the server.
|
||||
#[serde(default = "is_true")]
|
||||
pub test: bool,
|
||||
}
|
||||
|
||||
impl Default for CodeLensSpecifierSettings {
|
||||
fn default() -> Self {
|
||||
Self { test: true }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
|
||||
|
@ -109,9 +129,13 @@ impl Default for ImportCompletionSettings {
|
|||
/// Deno language server specific settings that can be applied uniquely to a
|
||||
/// specifier.
|
||||
#[derive(Debug, Default, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SpecifierSettings {
|
||||
/// A flag that indicates if Deno is enabled for this specifier or not.
|
||||
pub enable: bool,
|
||||
/// Code lens specific settings for the resource.
|
||||
#[serde(default)]
|
||||
pub code_lens: CodeLensSpecifierSettings,
|
||||
}
|
||||
|
||||
/// Deno language server specific settings that are applied to a workspace.
|
||||
|
@ -324,11 +348,21 @@ impl Config {
|
|||
|
||||
pub fn specifier_enabled(&self, specifier: &ModuleSpecifier) -> bool {
|
||||
let settings = self.settings.read().unwrap();
|
||||
if let Some(specifier_settings) = settings.specifiers.get(specifier) {
|
||||
specifier_settings.1.enable
|
||||
} else {
|
||||
settings.workspace.enable
|
||||
settings
|
||||
.specifiers
|
||||
.get(specifier)
|
||||
.map(|(_, s)| s.enable)
|
||||
.unwrap_or_else(|| settings.workspace.enable)
|
||||
}
|
||||
|
||||
pub fn specifier_code_lens_test(&self, specifier: &ModuleSpecifier) -> bool {
|
||||
let settings = self.settings.read().unwrap();
|
||||
let value = settings
|
||||
.specifiers
|
||||
.get(specifier)
|
||||
.map(|(_, s)| s.code_lens.test)
|
||||
.unwrap_or_else(|| settings.workspace.code_lens.test);
|
||||
value
|
||||
}
|
||||
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
|
@ -449,6 +483,7 @@ mod tests {
|
|||
implementations: false,
|
||||
references: false,
|
||||
references_all_functions: false,
|
||||
test: true,
|
||||
},
|
||||
internal_debug: false,
|
||||
lint: false,
|
||||
|
|
|
@ -243,7 +243,10 @@ impl Inner {
|
|||
// moment
|
||||
/// Searches already cached assets and documents and returns its text
|
||||
/// content. If not found, `None` is returned.
|
||||
fn get_text_content(&self, specifier: &ModuleSpecifier) -> Option<String> {
|
||||
pub(crate) fn get_text_content(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Option<String> {
|
||||
if specifier.scheme() == "asset" {
|
||||
self
|
||||
.assets
|
||||
|
@ -256,6 +259,17 @@ impl Inner {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_media_type(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Option<MediaType> {
|
||||
if specifier.scheme() == "asset" || self.documents.contains_key(specifier) {
|
||||
Some(MediaType::from(specifier))
|
||||
} else {
|
||||
self.sources.get_media_type(specifier)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn get_navigation_tree(
|
||||
&mut self,
|
||||
specifier: &ModuleSpecifier,
|
||||
|
@ -1099,15 +1113,15 @@ impl Inner {
|
|||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
|| !self.config.get_workspace_settings().enabled_code_lens()
|
||||
|| !(self.config.get_workspace_settings().enabled_code_lens()
|
||||
|| self.config.specifier_code_lens_test(&specifier))
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mark = self.performance.mark("code_lens", Some(¶ms));
|
||||
let code_lenses = code_lens::tsc_code_lenses(&specifier, self)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
let code_lenses =
|
||||
code_lens::collect(&specifier, self).await.map_err(|err| {
|
||||
error!("Error getting code lenses for \"{}\": {}", specifier, err);
|
||||
LspError::internal_error()
|
||||
})?;
|
||||
|
|
|
@ -45,7 +45,15 @@ where
|
|||
let (id, method, _) = client.read_request::<Value>().unwrap();
|
||||
assert_eq!(method, "workspace/configuration");
|
||||
client
|
||||
.write_response(id, json!({ "enable": true }))
|
||||
.write_response(
|
||||
id,
|
||||
json!({
|
||||
"enable": true,
|
||||
"codeLens": {
|
||||
"test": true
|
||||
}
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut diagnostics = vec![];
|
||||
|
@ -1229,6 +1237,76 @@ fn lsp_code_lens_impl() {
|
|||
shutdown(&mut client);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_code_lens_test() {
|
||||
let mut client = init("initialize_params_code_lens_test.json");
|
||||
did_open(
|
||||
&mut client,
|
||||
load_fixture("did_open_params_test_code_lens.json"),
|
||||
);
|
||||
let (maybe_res, maybe_err) = client
|
||||
.write_request(
|
||||
"textDocument/codeLens",
|
||||
json!({
|
||||
"textDocument": {
|
||||
"uri": "file:///a/file.ts"
|
||||
}
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(maybe_err.is_none());
|
||||
assert_eq!(
|
||||
maybe_res,
|
||||
Some(load_fixture("code_lens_response_test.json"))
|
||||
);
|
||||
shutdown(&mut client);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_code_lens_test_disabled() {
|
||||
let mut client = init("initialize_params_code_lens_test_disabled.json");
|
||||
client
|
||||
.write_notification(
|
||||
"textDocument/didOpen",
|
||||
load_fixture("did_open_params_test_code_lens.json"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (id, method, _) = client.read_request::<Value>().unwrap();
|
||||
assert_eq!(method, "workspace/configuration");
|
||||
client
|
||||
.write_response(
|
||||
id,
|
||||
json!({
|
||||
"enable": true,
|
||||
"codeLens": {
|
||||
"test": false
|
||||
}
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (method, _) = client.read_notification::<Value>().unwrap();
|
||||
assert_eq!(method, "textDocument/publishDiagnostics");
|
||||
let (method, _) = client.read_notification::<Value>().unwrap();
|
||||
assert_eq!(method, "textDocument/publishDiagnostics");
|
||||
let (method, _) = client.read_notification::<Value>().unwrap();
|
||||
assert_eq!(method, "textDocument/publishDiagnostics");
|
||||
let (maybe_res, maybe_err) = client
|
||||
.write_request(
|
||||
"textDocument/codeLens",
|
||||
json!({
|
||||
"textDocument": {
|
||||
"uri": "file:///a/file.ts"
|
||||
}
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(maybe_err.is_none());
|
||||
assert_eq!(maybe_res, Some(json!([])));
|
||||
shutdown(&mut client);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_code_lens_non_doc_nav_tree() {
|
||||
let mut client = init("initialize_params.json");
|
||||
|
|
162
cli/tests/lsp/code_lens_response_test.json
Normal file
162
cli/tests/lsp/code_lens_response_test.json
Normal file
|
@ -0,0 +1,162 @@
|
|||
[
|
||||
{
|
||||
"range": {
|
||||
"start": {
|
||||
"line": 4,
|
||||
"character": 5
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"character": 9
|
||||
}
|
||||
},
|
||||
"command": {
|
||||
"title": "▶︎ Run Test",
|
||||
"command": "deno.test",
|
||||
"arguments": [
|
||||
"file:///a/file.ts",
|
||||
"test a"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"range": {
|
||||
"start": {
|
||||
"line": 5,
|
||||
"character": 5
|
||||
},
|
||||
"end": {
|
||||
"line": 5,
|
||||
"character": 9
|
||||
}
|
||||
},
|
||||
"command": {
|
||||
"title": "▶︎ Run Test",
|
||||
"command": "deno.test",
|
||||
"arguments": [
|
||||
"file:///a/file.ts",
|
||||
"test b"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"range": {
|
||||
"start": {
|
||||
"line": 9,
|
||||
"character": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 9,
|
||||
"character": 4
|
||||
}
|
||||
},
|
||||
"command": {
|
||||
"title": "▶︎ Run Test",
|
||||
"command": "deno.test",
|
||||
"arguments": [
|
||||
"file:///a/file.ts",
|
||||
"test c"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"range": {
|
||||
"start": {
|
||||
"line": 13,
|
||||
"character": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 13,
|
||||
"character": 4
|
||||
}
|
||||
},
|
||||
"command": {
|
||||
"title": "▶︎ Run Test",
|
||||
"command": "deno.test",
|
||||
"arguments": [
|
||||
"file:///a/file.ts",
|
||||
"test d"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"range": {
|
||||
"start": {
|
||||
"line": 14,
|
||||
"character": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 14,
|
||||
"character": 5
|
||||
}
|
||||
},
|
||||
"command": {
|
||||
"title": "▶︎ Run Test",
|
||||
"command": "deno.test",
|
||||
"arguments": [
|
||||
"file:///a/file.ts",
|
||||
"test e"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"range": {
|
||||
"start": {
|
||||
"line": 18,
|
||||
"character": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 18,
|
||||
"character": 5
|
||||
}
|
||||
},
|
||||
"command": {
|
||||
"title": "▶︎ Run Test",
|
||||
"command": "deno.test",
|
||||
"arguments": [
|
||||
"file:///a/file.ts",
|
||||
"test f"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"range": {
|
||||
"start": {
|
||||
"line": 19,
|
||||
"character": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 19,
|
||||
"character": 5
|
||||
}
|
||||
},
|
||||
"command": {
|
||||
"title": "▶︎ Run Test",
|
||||
"command": "deno.test",
|
||||
"arguments": [
|
||||
"file:///a/file.ts",
|
||||
"test g"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"range": {
|
||||
"start": {
|
||||
"line": 23,
|
||||
"character": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 23,
|
||||
"character": 5
|
||||
}
|
||||
},
|
||||
"command": {
|
||||
"title": "▶︎ Run Test",
|
||||
"command": "deno.test",
|
||||
"arguments": [
|
||||
"file:///a/file.ts",
|
||||
"test h"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
8
cli/tests/lsp/did_open_params_test_code_lens.json
Normal file
8
cli/tests/lsp/did_open_params_test_code_lens.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"textDocument": {
|
||||
"uri": "file:///a/file.ts",
|
||||
"languageId": "typescript",
|
||||
"version": 1,
|
||||
"text": "const { test } = Deno;\nconst { test: test2 } = Deno;\nconst test3 = Deno.test;\n\nDeno.test(\"test a\", () => {});\nDeno.test({\n name: \"test b\",\n fn() {},\n});\ntest({\n name: \"test c\",\n fn() {},\n});\ntest(\"test d\", () => {});\ntest2({\n name: \"test e\",\n fn() {},\n});\ntest2(\"test f\", () => {});\ntest3({\n name: \"test g\",\n fn() {},\n});\ntest3(\"test h\", () => {});\n"
|
||||
}
|
||||
}
|
|
@ -9,7 +9,8 @@
|
|||
"enable": true,
|
||||
"codeLens": {
|
||||
"implementations": true,
|
||||
"references": true
|
||||
"references": true,
|
||||
"test": true
|
||||
},
|
||||
"importMap": null,
|
||||
"lint": true,
|
||||
|
|
56
cli/tests/lsp/initialize_params_code_lens_test.json
Normal file
56
cli/tests/lsp/initialize_params_code_lens_test.json
Normal file
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"processId": 0,
|
||||
"clientInfo": {
|
||||
"name": "test-harness",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"rootUri": null,
|
||||
"initializationOptions": {
|
||||
"enable": true,
|
||||
"importMap": null,
|
||||
"lint": true,
|
||||
"suggest": {
|
||||
"autoImports": true,
|
||||
"completeFunctionCalls": false,
|
||||
"names": true,
|
||||
"paths": true,
|
||||
"imports": {
|
||||
"hosts": {}
|
||||
}
|
||||
},
|
||||
"unstable": false
|
||||
},
|
||||
"capabilities": {
|
||||
"textDocument": {
|
||||
"codeAction": {
|
||||
"codeActionLiteralSupport": {
|
||||
"codeActionKind": {
|
||||
"valueSet": [
|
||||
"quickfix"
|
||||
]
|
||||
}
|
||||
},
|
||||
"isPreferredSupport": true,
|
||||
"dataSupport": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"edit"
|
||||
]
|
||||
}
|
||||
},
|
||||
"foldingRange": {
|
||||
"lineFoldingOnly": true
|
||||
},
|
||||
"synchronization": {
|
||||
"dynamicRegistration": true,
|
||||
"willSave": true,
|
||||
"willSaveWaitUntil": true,
|
||||
"didSave": true
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"configuration": true,
|
||||
"workspaceFolders": true
|
||||
}
|
||||
}
|
||||
}
|
61
cli/tests/lsp/initialize_params_code_lens_test_disabled.json
Normal file
61
cli/tests/lsp/initialize_params_code_lens_test_disabled.json
Normal file
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"processId": 0,
|
||||
"clientInfo": {
|
||||
"name": "test-harness",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"rootUri": null,
|
||||
"initializationOptions": {
|
||||
"enable": true,
|
||||
"codeLens": {
|
||||
"implementations": true,
|
||||
"references": true,
|
||||
"test": false
|
||||
},
|
||||
"importMap": null,
|
||||
"lint": true,
|
||||
"suggest": {
|
||||
"autoImports": true,
|
||||
"completeFunctionCalls": false,
|
||||
"names": true,
|
||||
"paths": true,
|
||||
"imports": {
|
||||
"hosts": {}
|
||||
}
|
||||
},
|
||||
"unstable": false
|
||||
},
|
||||
"capabilities": {
|
||||
"textDocument": {
|
||||
"codeAction": {
|
||||
"codeActionLiteralSupport": {
|
||||
"codeActionKind": {
|
||||
"valueSet": [
|
||||
"quickfix"
|
||||
]
|
||||
}
|
||||
},
|
||||
"isPreferredSupport": true,
|
||||
"dataSupport": true,
|
||||
"resolveSupport": {
|
||||
"properties": [
|
||||
"edit"
|
||||
]
|
||||
}
|
||||
},
|
||||
"foldingRange": {
|
||||
"lineFoldingOnly": true
|
||||
},
|
||||
"synchronization": {
|
||||
"dynamicRegistration": true,
|
||||
"willSave": true,
|
||||
"willSaveWaitUntil": true,
|
||||
"didSave": true
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"configuration": true,
|
||||
"workspaceFolders": true
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue