mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-27 04:15:08 +00:00
fix stray curly
This commit is contained in:
parent
a48964c64d
commit
a450142aca
13 changed files with 144 additions and 29 deletions
|
@ -32,7 +32,7 @@ use libsyntax2::{
|
||||||
ast::{self, AstNode, NameOwner},
|
ast::{self, AstNode, NameOwner},
|
||||||
SyntaxKind::*,
|
SyntaxKind::*,
|
||||||
};
|
};
|
||||||
use libeditor::{LineIndex, FileSymbol, find_node};
|
use libeditor::{LineIndex, FileSymbol, find_node_at_offset};
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
symbol_index::FileSymbols,
|
symbol_index::FileSymbols,
|
||||||
|
@ -183,10 +183,10 @@ impl World {
|
||||||
) -> Result<Vec<(FileId, FileSymbol)>> {
|
) -> Result<Vec<(FileId, FileSymbol)>> {
|
||||||
let file = self.file_syntax(id)?;
|
let file = self.file_syntax(id)?;
|
||||||
let syntax = file.syntax();
|
let syntax = file.syntax();
|
||||||
if let Some(name_ref) = find_node::<ast::NameRef>(syntax, offset) {
|
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) {
|
||||||
return Ok(self.index_resolve(name_ref));
|
return Ok(self.index_resolve(name_ref));
|
||||||
}
|
}
|
||||||
if let Some(name) = find_node::<ast::Name>(syntax, offset) {
|
if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) {
|
||||||
if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
|
if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
|
||||||
if module.has_semi() {
|
if module.has_semi() {
|
||||||
let file_ids = self.resolve_module(id, module);
|
let file_ids = self.resolve_module(id, module);
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use libsyntax2::{
|
use libsyntax2::{
|
||||||
File,
|
File, TextUnit,
|
||||||
ast::{self, AstNode, AttrsOwner, TypeParamsOwner, NameOwner},
|
ast::{self, AstNode, AttrsOwner, TypeParamsOwner, NameOwner},
|
||||||
SyntaxKind::COMMA,
|
SyntaxKind::COMMA,
|
||||||
SyntaxNodeRef,
|
SyntaxNodeRef,
|
||||||
|
@ -13,7 +13,7 @@ use libsyntax2::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use {TextUnit, EditBuilder, Edit};
|
use {EditBuilder, Edit, find_node_at_offset};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ActionResult {
|
pub struct ActionResult {
|
||||||
|
@ -39,7 +39,7 @@ pub fn flip_comma<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_derive<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> ActionResult + 'a> {
|
pub fn add_derive<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> ActionResult + 'a> {
|
||||||
let nominal = find_node::<ast::NominalDef>(file.syntax(), offset)?;
|
let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?;
|
||||||
Some(move || {
|
Some(move || {
|
||||||
let derive_attr = nominal
|
let derive_attr = nominal
|
||||||
.attrs()
|
.attrs()
|
||||||
|
@ -66,7 +66,7 @@ pub fn add_derive<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> ActionResult + 'a> {
|
pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> ActionResult + 'a> {
|
||||||
let nominal = find_node::<ast::NominalDef>(file.syntax(), offset)?;
|
let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?;
|
||||||
let name = nominal.name()?;
|
let name = nominal.name()?;
|
||||||
|
|
||||||
Some(move || {
|
Some(move || {
|
||||||
|
@ -105,16 +105,6 @@ fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<Synta
|
||||||
.find(|node| !node.kind().is_trivia())
|
.find(|node| !node.kind().is_trivia())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_node<'a, N: AstNode<'a>>(syntax: SyntaxNodeRef<'a>, offset: TextUnit) -> Option<N> {
|
|
||||||
let leaves = find_leaf_at_offset(syntax, offset);
|
|
||||||
let leaf = leaves.clone()
|
|
||||||
.find(|leaf| !leaf.kind().is_trivia())
|
|
||||||
.or_else(|| leaves.right_biased())?;
|
|
||||||
ancestors(leaf)
|
|
||||||
.filter_map(N::cast)
|
|
||||||
.next()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn comma_list(buf: &mut String, bra: &str, ket: &str, items: impl Iterator<Item=impl fmt::Display>) {
|
fn comma_list(buf: &mut String, bra: &str, ket: &str, items: impl Iterator<Item=impl fmt::Display>) {
|
||||||
buf.push_str(bra);
|
buf.push_str(bra);
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
|
|
31
crates/libeditor/src/completion.rs
Normal file
31
crates/libeditor/src/completion.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
use libsyntax2::{
|
||||||
|
File, TextUnit,
|
||||||
|
ast,
|
||||||
|
algo::find_leaf_at_offset,
|
||||||
|
};
|
||||||
|
|
||||||
|
use {
|
||||||
|
AtomEdit, find_node_at_offset,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CompletionItem {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionItem>> {
|
||||||
|
// Insert a fake ident to get a valid parse tree
|
||||||
|
let file = {
|
||||||
|
let edit = AtomEdit::insert(offset, "intellijRulezz".to_string());
|
||||||
|
// Don't bother with completion if incremental reparse fails
|
||||||
|
file.incremental_reparse(&edit)?
|
||||||
|
};
|
||||||
|
let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), offset)?;
|
||||||
|
Some(complete(name_ref))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete(name_ref: ast::NameRef) -> Vec<CompletionItem> {
|
||||||
|
vec![CompletionItem {
|
||||||
|
name: "foo".to_string()
|
||||||
|
}]
|
||||||
|
}
|
|
@ -8,11 +8,12 @@ mod line_index;
|
||||||
mod edit;
|
mod edit;
|
||||||
mod code_actions;
|
mod code_actions;
|
||||||
mod typing;
|
mod typing;
|
||||||
|
mod completion;
|
||||||
|
|
||||||
use libsyntax2::{
|
use libsyntax2::{
|
||||||
File, TextUnit, TextRange,
|
File, TextUnit, TextRange, SyntaxNodeRef,
|
||||||
ast::{AstNode, NameOwner},
|
ast::{AstNode, NameOwner},
|
||||||
algo::{walk, find_leaf_at_offset},
|
algo::{walk, find_leaf_at_offset, ancestors},
|
||||||
SyntaxKind::{self, *},
|
SyntaxKind::{self, *},
|
||||||
};
|
};
|
||||||
pub use libsyntax2::AtomEdit;
|
pub use libsyntax2::AtomEdit;
|
||||||
|
@ -22,10 +23,11 @@ pub use self::{
|
||||||
symbols::{StructureNode, file_structure, FileSymbol, file_symbols},
|
symbols::{StructureNode, file_structure, FileSymbol, file_symbols},
|
||||||
edit::{EditBuilder, Edit},
|
edit::{EditBuilder, Edit},
|
||||||
code_actions::{
|
code_actions::{
|
||||||
ActionResult, find_node,
|
ActionResult,
|
||||||
flip_comma, add_derive, add_impl,
|
flip_comma, add_derive, add_impl,
|
||||||
},
|
},
|
||||||
typing::join_lines,
|
typing::join_lines,
|
||||||
|
completion::scope_completion,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -138,3 +140,16 @@ pub fn runnables(file: &File) -> Vec<Runnable> {
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn find_node_at_offset<'a, N: AstNode<'a>>(
|
||||||
|
syntax: SyntaxNodeRef<'a>,
|
||||||
|
offset: TextUnit,
|
||||||
|
) -> Option<N> {
|
||||||
|
let leaves = find_leaf_at_offset(syntax, offset);
|
||||||
|
let leaf = leaves.clone()
|
||||||
|
.find(|leaf| !leaf.kind().is_trivia())
|
||||||
|
.or_else(|| leaves.right_biased())?;
|
||||||
|
ancestors(leaf)
|
||||||
|
.filter_map(N::cast)
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use libeditor::{
|
||||||
ActionResult,
|
ActionResult,
|
||||||
highlight, runnables, extend_selection, file_structure,
|
highlight, runnables, extend_selection, file_structure,
|
||||||
flip_comma, add_derive, add_impl, matching_brace,
|
flip_comma, add_derive, add_impl, matching_brace,
|
||||||
join_lines,
|
join_lines, scope_completion,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -244,6 +244,26 @@ struct Foo { f: u32 }
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_completion() {
|
||||||
|
// fn do_check(code: &str, expected_completions: &str) {
|
||||||
|
// let (off, code) = extract_offset(&code);
|
||||||
|
// let file = file(&code);
|
||||||
|
// let completions = scope_completion(&file, off).unwrap();
|
||||||
|
// assert_eq_dbg(expected_completions, &completions);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// do_check(r"
|
||||||
|
// fn foo(foo: i32) {
|
||||||
|
// let bar = 92;
|
||||||
|
// 1 + <|>
|
||||||
|
// }
|
||||||
|
// ", r#"
|
||||||
|
// CompletionItem { name: "bar" },
|
||||||
|
// CompletionItem { name: "foo" },
|
||||||
|
// "#);
|
||||||
|
// }
|
||||||
|
|
||||||
fn file(text: &str) -> File {
|
fn file(text: &str) -> File {
|
||||||
File::parse(text)
|
File::parse(text)
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,12 @@ pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemF
|
||||||
m.abandon(p);
|
m.abandon(p);
|
||||||
if p.at(L_CURLY) {
|
if p.at(L_CURLY) {
|
||||||
error_block(p, "expected an item");
|
error_block(p, "expected an item");
|
||||||
} else if !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) {
|
} else if p.at(R_CURLY) && !stop_on_r_curly {
|
||||||
|
let e = p.start();
|
||||||
|
p.error("unmatched `}`");
|
||||||
|
p.bump();
|
||||||
|
e.complete(p, ERROR);
|
||||||
|
} else if !p.at(EOF) && !p.at(R_CURLY) {
|
||||||
p.err_and_bump("expected an item");
|
p.err_and_bump("expected an item");
|
||||||
} else {
|
} else {
|
||||||
p.error("expected an item");
|
p.error("expected an item");
|
||||||
|
|
|
@ -127,12 +127,12 @@ fn validate_block_structure(root: SyntaxNodeRef) {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
node.parent(),
|
node.parent(),
|
||||||
pair.parent(),
|
pair.parent(),
|
||||||
"unpaired curleys:\n{}",
|
"\nunpaired curleys:\n{}",
|
||||||
utils::dump_tree(root),
|
utils::dump_tree(root),
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
node.next_sibling().is_none() && pair.prev_sibling().is_none(),
|
node.next_sibling().is_none() && pair.prev_sibling().is_none(),
|
||||||
"floating curlys at {:?}\nfile:\n{}\nerror:\n{}\n",
|
"\nfloating curlys at {:?}\nfile:\n{}\nerror:\n{}\n",
|
||||||
node,
|
node,
|
||||||
root.text(),
|
root.text(),
|
||||||
node.text(),
|
node.text(),
|
||||||
|
|
|
@ -141,7 +141,9 @@ impl<'t> Parser<'t> {
|
||||||
pub(crate) fn err_and_bump(&mut self, message: &str) {
|
pub(crate) fn err_and_bump(&mut self, message: &str) {
|
||||||
let m = self.start();
|
let m = self.start();
|
||||||
self.error(message);
|
self.error(message);
|
||||||
self.bump();
|
if !self.at(SyntaxKind::L_CURLY) && !self.at(SyntaxKind::R_CURLY) {
|
||||||
|
self.bump();
|
||||||
|
}
|
||||||
m.complete(self, ERROR);
|
m.complete(self, ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
ROOT@[0; 31)
|
ROOT@[0; 31)
|
||||||
ERROR@[0; 1)
|
ERROR@[0; 1)
|
||||||
R_CURLY@[0; 1)
|
R_CURLY@[0; 1)
|
||||||
err: `expected an item`
|
err: `unmatched `}``
|
||||||
WHITESPACE@[1; 3)
|
WHITESPACE@[1; 3)
|
||||||
STRUCT_DEF@[3; 12)
|
STRUCT_DEF@[3; 12)
|
||||||
STRUCT_KW@[3; 9)
|
STRUCT_KW@[3; 9)
|
||||||
|
@ -10,7 +10,7 @@ ROOT@[0; 31)
|
||||||
IDENT@[10; 11) "S"
|
IDENT@[10; 11) "S"
|
||||||
SEMI@[11; 12)
|
SEMI@[11; 12)
|
||||||
WHITESPACE@[12; 14)
|
WHITESPACE@[12; 14)
|
||||||
err: `expected an item`
|
err: `unmatched `}``
|
||||||
ERROR@[14; 15)
|
ERROR@[14; 15)
|
||||||
R_CURLY@[14; 15)
|
R_CURLY@[14; 15)
|
||||||
WHITESPACE@[15; 17)
|
WHITESPACE@[15; 17)
|
||||||
|
@ -26,7 +26,7 @@ ROOT@[0; 31)
|
||||||
L_CURLY@[25; 26)
|
L_CURLY@[25; 26)
|
||||||
R_CURLY@[26; 27)
|
R_CURLY@[26; 27)
|
||||||
WHITESPACE@[27; 29)
|
WHITESPACE@[27; 29)
|
||||||
err: `expected an item`
|
err: `unmatched `}``
|
||||||
ERROR@[29; 30)
|
ERROR@[29; 30)
|
||||||
R_CURLY@[29; 30)
|
R_CURLY@[29; 30)
|
||||||
WHITESPACE@[30; 31)
|
WHITESPACE@[30; 31)
|
||||||
|
|
|
@ -9,7 +9,7 @@ ROOT@[0; 14)
|
||||||
err: `expected value parameter`
|
err: `expected value parameter`
|
||||||
err: `expected R_PAREN`
|
err: `expected R_PAREN`
|
||||||
err: `expected a block`
|
err: `expected a block`
|
||||||
err: `expected an item`
|
err: `unmatched `}``
|
||||||
ERROR@[7; 8)
|
ERROR@[7; 8)
|
||||||
R_CURLY@[7; 8)
|
R_CURLY@[7; 8)
|
||||||
err: `expected an item`
|
err: `expected an item`
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
fn foo(foo: i32) {
|
||||||
|
let bar = 92;
|
||||||
|
1 +
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
ROOT@[0; 47)
|
||||||
|
FN_DEF@[0; 46)
|
||||||
|
FN_KW@[0; 2)
|
||||||
|
WHITESPACE@[2; 3)
|
||||||
|
NAME@[3; 6)
|
||||||
|
IDENT@[3; 6) "foo"
|
||||||
|
PARAM_LIST@[6; 16)
|
||||||
|
L_PAREN@[6; 7)
|
||||||
|
PARAM@[7; 15)
|
||||||
|
BIND_PAT@[7; 10)
|
||||||
|
NAME@[7; 10)
|
||||||
|
IDENT@[7; 10) "foo"
|
||||||
|
COLON@[10; 11)
|
||||||
|
WHITESPACE@[11; 12)
|
||||||
|
PATH_TYPE@[12; 15)
|
||||||
|
PATH@[12; 15)
|
||||||
|
PATH_SEGMENT@[12; 15)
|
||||||
|
NAME_REF@[12; 15)
|
||||||
|
IDENT@[12; 15) "i32"
|
||||||
|
R_PAREN@[15; 16)
|
||||||
|
WHITESPACE@[16; 17)
|
||||||
|
BLOCK@[17; 46)
|
||||||
|
L_CURLY@[17; 18)
|
||||||
|
WHITESPACE@[18; 23)
|
||||||
|
LET_STMT@[23; 36)
|
||||||
|
LET_KW@[23; 26)
|
||||||
|
WHITESPACE@[26; 27)
|
||||||
|
BIND_PAT@[27; 30)
|
||||||
|
NAME@[27; 30)
|
||||||
|
IDENT@[27; 30) "bar"
|
||||||
|
WHITESPACE@[30; 31)
|
||||||
|
EQ@[31; 32)
|
||||||
|
WHITESPACE@[32; 33)
|
||||||
|
LITERAL@[33; 35)
|
||||||
|
INT_NUMBER@[33; 35) "92"
|
||||||
|
SEMI@[35; 36)
|
||||||
|
WHITESPACE@[36; 41)
|
||||||
|
BIN_EXPR@[41; 45)
|
||||||
|
LITERAL@[41; 42)
|
||||||
|
INT_NUMBER@[41; 42) "1"
|
||||||
|
WHITESPACE@[42; 43)
|
||||||
|
PLUS@[43; 44)
|
||||||
|
WHITESPACE@[44; 45)
|
||||||
|
err: `expected expression`
|
||||||
|
ERROR@[45; 45)
|
||||||
|
R_CURLY@[45; 46)
|
||||||
|
WHITESPACE@[46; 47)
|
|
@ -26,6 +26,7 @@ fn lexer_tests() {
|
||||||
#[test]
|
#[test]
|
||||||
fn parser_tests() {
|
fn parser_tests() {
|
||||||
dir_tests(&["parser/inline", "parser/ok", "parser/err"], |text| {
|
dir_tests(&["parser/inline", "parser/ok", "parser/err"], |text| {
|
||||||
|
eprintln!("\n{}\n", text);
|
||||||
let file = File::parse(text);
|
let file = File::parse(text);
|
||||||
dump_tree(file.syntax())
|
dump_tree(file.syntax())
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue