fix stray curly

This commit is contained in:
Aleksey Kladov 2018-08-26 09:12:18 +03:00
parent a48964c64d
commit a450142aca
13 changed files with 144 additions and 29 deletions

View File

@ -32,7 +32,7 @@ use libsyntax2::{
ast::{self, AstNode, NameOwner},
SyntaxKind::*,
};
use libeditor::{LineIndex, FileSymbol, find_node};
use libeditor::{LineIndex, FileSymbol, find_node_at_offset};
use self::{
symbol_index::FileSymbols,
@ -183,10 +183,10 @@ impl World {
) -> Result<Vec<(FileId, FileSymbol)>> {
let file = self.file_syntax(id)?;
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));
}
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 module.has_semi() {
let file_ids = self.resolve_module(id, module);

View File

@ -3,7 +3,7 @@ use std::{
};
use libsyntax2::{
File,
File, TextUnit,
ast::{self, AstNode, AttrsOwner, TypeParamsOwner, NameOwner},
SyntaxKind::COMMA,
SyntaxNodeRef,
@ -13,7 +13,7 @@ use libsyntax2::{
},
};
use {TextUnit, EditBuilder, Edit};
use {EditBuilder, Edit, find_node_at_offset};
#[derive(Debug)]
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> {
let nominal = find_node::<ast::NominalDef>(file.syntax(), offset)?;
let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?;
Some(move || {
let derive_attr = nominal
.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> {
let nominal = find_node::<ast::NominalDef>(file.syntax(), offset)?;
let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?;
let name = nominal.name()?;
Some(move || {
@ -105,16 +105,6 @@ fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<Synta
.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>) {
buf.push_str(bra);
let mut first = true;

View 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()
}]
}

View File

@ -8,11 +8,12 @@ mod line_index;
mod edit;
mod code_actions;
mod typing;
mod completion;
use libsyntax2::{
File, TextUnit, TextRange,
File, TextUnit, TextRange, SyntaxNodeRef,
ast::{AstNode, NameOwner},
algo::{walk, find_leaf_at_offset},
algo::{walk, find_leaf_at_offset, ancestors},
SyntaxKind::{self, *},
};
pub use libsyntax2::AtomEdit;
@ -22,10 +23,11 @@ pub use self::{
symbols::{StructureNode, file_structure, FileSymbol, file_symbols},
edit::{EditBuilder, Edit},
code_actions::{
ActionResult, find_node,
ActionResult,
flip_comma, add_derive, add_impl,
},
typing::join_lines,
completion::scope_completion,
};
#[derive(Debug)]
@ -138,3 +140,16 @@ pub fn runnables(file: &File) -> Vec<Runnable> {
})
.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()
}

View File

@ -9,7 +9,7 @@ use libeditor::{
ActionResult,
highlight, runnables, extend_selection, file_structure,
flip_comma, add_derive, add_impl, matching_brace,
join_lines,
join_lines, scope_completion,
};
#[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 {
File::parse(text)
}

View File

@ -43,7 +43,12 @@ pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemF
m.abandon(p);
if p.at(L_CURLY) {
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");
} else {
p.error("expected an item");

View File

@ -127,12 +127,12 @@ fn validate_block_structure(root: SyntaxNodeRef) {
assert_eq!(
node.parent(),
pair.parent(),
"unpaired curleys:\n{}",
"\nunpaired curleys:\n{}",
utils::dump_tree(root),
);
assert!(
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,
root.text(),
node.text(),

View File

@ -141,7 +141,9 @@ impl<'t> Parser<'t> {
pub(crate) fn err_and_bump(&mut self, message: &str) {
let m = self.start();
self.error(message);
self.bump();
if !self.at(SyntaxKind::L_CURLY) && !self.at(SyntaxKind::R_CURLY) {
self.bump();
}
m.complete(self, ERROR);
}
}

View File

@ -1,7 +1,7 @@
ROOT@[0; 31)
ERROR@[0; 1)
R_CURLY@[0; 1)
err: `expected an item`
err: `unmatched `}``
WHITESPACE@[1; 3)
STRUCT_DEF@[3; 12)
STRUCT_KW@[3; 9)
@ -10,7 +10,7 @@ ROOT@[0; 31)
IDENT@[10; 11) "S"
SEMI@[11; 12)
WHITESPACE@[12; 14)
err: `expected an item`
err: `unmatched `}``
ERROR@[14; 15)
R_CURLY@[14; 15)
WHITESPACE@[15; 17)
@ -26,7 +26,7 @@ ROOT@[0; 31)
L_CURLY@[25; 26)
R_CURLY@[26; 27)
WHITESPACE@[27; 29)
err: `expected an item`
err: `unmatched `}``
ERROR@[29; 30)
R_CURLY@[29; 30)
WHITESPACE@[30; 31)

View File

@ -9,7 +9,7 @@ ROOT@[0; 14)
err: `expected value parameter`
err: `expected R_PAREN`
err: `expected a block`
err: `expected an item`
err: `unmatched `}``
ERROR@[7; 8)
R_CURLY@[7; 8)
err: `expected an item`

View File

@ -0,0 +1,4 @@
fn foo(foo: i32) {
let bar = 92;
1 +
}

View File

@ -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)

View File

@ -26,6 +26,7 @@ fn lexer_tests() {
#[test]
fn parser_tests() {
dir_tests(&["parser/inline", "parser/ok", "parser/err"], |text| {
eprintln!("\n{}\n", text);
let file = File::parse(text);
dump_tree(file.syntax())
})