From 57518153147ad53639f16cc940d219dc582c550a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 27 Aug 2018 22:03:19 +0300 Subject: Add runnables --- crates/libeditor/src/scope.rs | 14 ++++++++- crates/libeditor/tests/test.rs | 8 ++++++ crates/libsyntax2/src/ast/generated.rs | 8 ++++++ crates/libsyntax2/src/grammar.ron | 6 +++- crates/server/src/main_loop/handlers.rs | 50 +++++++++++++++++++++++++++++++++ crates/server/src/main_loop/mod.rs | 4 +++ crates/server/src/req.rs | 27 ++++++++++++++++++ 7 files changed, 115 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/libeditor/src/scope.rs b/crates/libeditor/src/scope.rs index 76104b2cf..3d398a74c 100644 --- a/crates/libeditor/src/scope.rs +++ b/crates/libeditor/src/scope.rs @@ -61,7 +61,19 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { compute_block_scopes(block, scopes, scope); } } - // ForExpr(e) => TODO, + ast::Expr::ForExpr(e) => { + if let Some(expr) = e.iterable() { + compute_expr_scopes(expr, scopes, scope); + } + let mut scope = scope; + if let Some(pat) = e.pat() { + scope = scopes.new_scope(scope); + scopes.add_bindings(scope, pat); + } + if let Some(block) = e.body() { + compute_block_scopes(block, scopes, scope); + } + }, _ => { expr.syntax().children() .filter_map(ast::Expr::cast) diff --git a/crates/libeditor/tests/test.rs b/crates/libeditor/tests/test.rs index d051980b0..d8c24610d 100644 --- a/crates/libeditor/tests/test.rs +++ b/crates/libeditor/tests/test.rs @@ -286,6 +286,14 @@ fn quux() { } ", r#"[CompletionItem { name: "b" }, CompletionItem { name: "a" }]"#); + + do_check(r" +fn quux() { + for x in &[1, 2, 3] { + <|> + } +} +", r#"[CompletionItem { name: "x" }]"#); } fn file(text: &str) -> File { diff --git a/crates/libsyntax2/src/ast/generated.rs b/crates/libsyntax2/src/ast/generated.rs index 6891e857c..f99d1274a 100644 --- a/crates/libsyntax2/src/ast/generated.rs +++ b/crates/libsyntax2/src/ast/generated.rs @@ -539,6 +539,14 @@ impl<'a> AstNode<'a> for ForExpr<'a> { } impl<'a> ForExpr<'a> { + pub fn pat(self) -> Option> { + super::child_opt(self) + } + + pub fn iterable(self) -> Option> { + super::child_opt(self) + } + pub fn body(self) -> Option> { super::child_opt(self) } diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron index c9e128462..a98e9e2fd 100644 --- a/crates/libsyntax2/src/grammar.ron +++ b/crates/libsyntax2/src/grammar.ron @@ -344,7 +344,11 @@ Grammar( options: [ ["body", "Block"] ] ), "ForExpr": ( - options: [ ["body", "Block"] ] + options: [ + ["pat", "Pat"], + ["iterable", "Expr"], + ["body", "Block"] , + ] ), "WhileExpr": ( options: [ diff --git a/crates/server/src/main_loop/handlers.rs b/crates/server/src/main_loop/handlers.rs index 350eda7df..583af0900 100644 --- a/crates/server/src/main_loop/handlers.rs +++ b/crates/server/src/main_loop/handlers.rs @@ -204,6 +204,56 @@ pub fn handle_code_action( return Ok(Some(res)); } +pub fn handle_runnables( + world: ServerWorld, + params: req::RunnablesParams, +) -> Result> { + let file_id = params.text_document.try_conv_with(&world)?; + let file = world.analysis().file_syntax(file_id)?; + let line_index = world.analysis().file_line_index(file_id)?; + let offset = params.position.map(|it| it.conv_with(&line_index)); + let mut res = Vec::new(); + for runnable in libeditor::runnables(&file) { + if let Some(offset) = offset { + if !contains_offset_nonstrict(runnable.range, offset) { + continue; + } + } + + let r = req::Runnable { + range: runnable.range.conv_with(&line_index), + label: match &runnable.kind { + libeditor::RunnableKind::Test { name } => + format!("test {}", name), + libeditor::RunnableKind::Bin => + "run binary".to_string(), + }, + bin: "cargo".to_string(), + args: match runnable.kind { + libeditor::RunnableKind::Test { name } => { + vec![ + "test".to_string(), + "--".to_string(), + name, + "--nocapture".to_string(), + ] + } + libeditor::RunnableKind::Bin => vec!["run".to_string()] + }, + env: { + let mut m = HashMap::new(); + m.insert( + "RUST_BACKTRACE".to_string(), + "short".to_string(), + ); + m + } + }; + res.push(r); + } + return Ok(res); +} + pub fn handle_workspace_symbol( world: ServerWorld, params: req::WorkspaceSymbolParams, diff --git a/crates/server/src/main_loop/mod.rs b/crates/server/src/main_loop/mod.rs index 5213ecc04..6d6ca6ae9 100644 --- a/crates/server/src/main_loop/mod.rs +++ b/crates/server/src/main_loop/mod.rs @@ -29,6 +29,7 @@ use { handle_parent_module, handle_join_lines, handle_completion, + handle_runnables, }, }; @@ -138,6 +139,9 @@ fn on_request( handle_request_on_threadpool::( &mut req, pool, world, sender, handle_code_action, )?; + handle_request_on_threadpool::( + &mut req, pool, world, sender, handle_runnables, + )?; handle_request_on_threadpool::( &mut req, pool, world, sender, handle_workspace_symbol, )?; diff --git a/crates/server/src/req.rs b/crates/server/src/req.rs index 6d3466b66..e4138abba 100644 --- a/crates/server/src/req.rs +++ b/crates/server/src/req.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use serde::{ser::Serialize, de::DeserializeOwned}; use languageserver_types::{TextDocumentIdentifier, Range, Url, Position, Location}; use url_serde; @@ -134,3 +136,28 @@ pub struct JoinLinesParams { pub text_document: TextDocumentIdentifier, pub range: Range, } + +pub enum Runnables {} + +impl Request for Runnables { + type Params = RunnablesParams; + type Result = Vec; + const METHOD: &'static str = "m/joinLines"; +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct RunnablesParams { + pub text_document: TextDocumentIdentifier, + pub position: Option, +} + +#[derive(Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Runnable { + pub range: Range, + pub label: String, + pub bin: String, + pub args: Vec, + pub env: HashMap, +} -- cgit v1.2.3