@@ -27,7 +27,8 @@ fn indent_level_for_line(line: RopeSlice) -> usize {
2727fn get_highest_syntax_node_at_bytepos(syntax: &Syntax, pos: usize) -> Option<Node> {
2828 let tree = syntax.root_layer.tree.as_ref().unwrap();
2929
30− let mut node = match tree.root_node().named_descendant_for_byte_range(pos, pos) {
30+ // named_descendant
31+ let mut node = match tree.root_node().descendant_for_byte_range(pos, pos) {
3132 Some(node) => node,
3233 None => return None,
3334 };
@@ -43,91 +44,149 @@ fn get_highest_syntax_node_at_bytepos(syntax: &Syntax, pos: usize) -> Option<Nod
4344 Some(node)
4445}
4546
46−fn walk(node: Option<Node>) -> usize {
47− let node = match node {
48− Some(node) => node,
49− None => return 0,
50− };
51−
52− let parent = match node.parent() {
53− Some(node) => node,
54− None => return 0,
55− };
56−
47+fn walk(node: Option<Node>, newline: bool) -> usize {
5748 let mut increment = 0;
5849
5950 // Hardcoded for rust for now
6051 let indent_scopes = &[
61− "block",
62− "function_item",
63− "closure_expression",
52+ // indent except first or block?
6453 "while_expression",
6554 "for_expression",
6655 "loop_expression",
6756 "if_expression",
6857 "if_let_expression",
69− "binary_expression",
7058 "match_expression",
7159 "match_arm",
72− //
73− "struct_item",
74− "enum_item",
75− "impl_item",
76− //
77− "mod_item",
7860 ];
7961
80− // let indent_except_first_scopes = &[];
62+ // this is for multiline things, such as:
63+ // self.method()
64+ // .chain()
65+ // .chain()
66+ // where the first line isn't indented
67+ let indent_except_first_scopes = &[
68+ "block",
69+ "arguments",
70+ "declaration_list",
71+ "field_declaration_list",
72+ "enum_variant_list",
73+ // "function_item",
74+ // "call_expression",
75+ // "closure_expression",
76+ "binary_expression",
77+ "field_expression",
78+ //
79+ "where_predicate", // where_clause instead?
80+ ];
8181
82− let not_first_sibling = node.next_sibling().is_some();
83− let not_last_sibling = node.prev_sibling().is_some();
84− let not_first_or_last_sibling = not_first_sibling && not_last_sibling;
82+ let outdent = &["}", "]", ")"];
8583
86− let parent_kind = parent.kind();
87− let is_scope = indent_scopes.iter().any(|scope| scope == &parent_kind);
84+ let mut node = match node {
85+ Some(node) => node,
86+ None => return 0,
87+ };
8888
89− // && not_first_or_last_sibling
90− if is_scope {
91− increment += 1
89+ // if we're calculating indentation for a brand new line then the current node will become the
90+ // parent node. We need to take it's indentation level into account too.
91+ let node_kind = node.kind();
92+ if newline
93+ && (indent_scopes.contains(&node_kind) || indent_except_first_scopes.contains(&node_kind))
94+ {
95+ increment += 1;
9296 }
9397
94− // if last_scope && increment > 0 && ...{ ignore }
98+ while let Some(parent) = node.parent() {
99+ let not_first_sibling = node.prev_sibling().is_some();
100+ let not_last_sibling = node.next_sibling().is_some();
101+ let not_first_or_last_sibling = not_first_sibling && not_last_sibling;
102+
103+ let parent_kind = parent.kind();
104+
105+ // println!(
106+ // "name: {}\tparent: {}\trange:\t{} {}\tfirst={:?}\tlast={:?}",
107+ // node.kind(),
108+ // parent.kind(),
109+ // node.range().start_point,
110+ // node.range().end_point,
111+ // node.prev_sibling().is_none(),
112+ // node.next_sibling().is_none(),
113+ // );
114+
115+ if outdent.contains(&node.kind()) {
116+ // we outdent by skipping the rules for the current level and jumping up
117+ node = parent;
118+ continue;
119+ }
120+
121+ let is_scope = indent_scopes.contains(&parent_kind);
122+
123+ // && not_first_or_last_sibling
124+ if is_scope && not_first_or_last_sibling {
125+ // println!("is_scope {}", parent_kind);
126+ increment += 1
127+ }
128+
129+ let is_scope = indent_except_first_scopes.contains(&parent_kind);
130+
131+ // && not_first_sibling
132+ if is_scope && not_first_sibling {
133+ // println!("is_scope_except_first {}", parent_kind);
134+ increment += 1
135+ }
136+
137+ // if last_scope && increment > 0 && ...{ ignore }
138+
139+ node = parent;
140+ }
95141
96− walk(Some(parent)) + increment
142+ increment
97143}
98144
99−fn find_first_non_whitespace_char(state: &State, line_num: usize) -> usize {
145+fn find_first_non_whitespace_char(state: &State, line_num: usize) -> Option<usize> {
100146 let line = state.doc.line(line_num);
101147 let mut start = state.doc.line_to_char(line_num);
102148
103149 // find first non-whitespace char
104150 for ch in line.chars() {
105151 // TODO: could use memchr with chunks?
106− if ch != ' ' && ch != '\t' {
107− break;
152+ if ch != ' ' && ch != '\t' && ch != '\n' {
153+ return Some(start);
108154 }
109155 start += 1;
110156 }
111− start
157+
158+ None
112159}
113160
114161fn suggested_indent_for_line(syntax: Option<&Syntax>, state: &State, line_num: usize) -> usize {
115162 let line = state.doc.line(line_num);
116163 let current = indent_level_for_line(line);
117164
118− let start = find_first_non_whitespace_char(state, line_num);
165+ if let Some(start) = find_first_non_whitespace_char(state, line_num) {
166+ return suggested_indent_for_pos(syntax, state, start, false);
167+ };
119168
120− suggested_indent_for_pos(syntax, state, start)
169+ // if the line is blank, indent should be zero
170+ 0
121171}
122172
123−pub fn suggested_indent_for_pos(syntax: Option<&Syntax>, state: &State, pos: usize) -> usize {
173+// TODO: two usecases: if we are triggering this for a new, blank line:
174+// - it should return 0 when mass indenting stuff
175+// - it should look up the wrapper node and count it too when we press o/O
176+pub fn suggested_indent_for_pos(
177+ syntax: Option<&Syntax>,
178+ state: &State,
179+ pos: usize,
180+ new_line: bool,
181+) -> usize {
124182 if let Some(syntax) = syntax {
125183 let byte_start = state.doc.char_to_byte(pos);
126184 let node = get_highest_syntax_node_at_bytepos(syntax, byte_start);
127185
128− let indentation = walk(node);
186+ let indentation = walk(node, new_line);
129187 // special case for comments
130188
189+ // println!("------------");
131190 // if preserve_leading_whitespace
132191
133192 indentation
@@ -155,11 +214,52 @@ mod test {
155214 #[test]
156215 fn test_suggested_indent_for_line() {
157216 let doc = Rope::from(
158− "mod test {
217+ "
218+mod test {
159219 fn hello_world() {
160− 1 + 1
220+ 1 + 1;
221+
222+ let does_indentation_work = 1;
223+
224+ let test_function = function_with_param(this_param,
225+ that_param
226+ );
227+
228+ let test_function = function_with_param(
229+ this_param,
230+ that_param
231+ );
232+
233+ let test_function = function_with_proper_indent(param1,
234+ param2,
235+ );
236+
237+ let selection = Selection::new(
238+ changes
239+ .clone()
240+ .map(|(start, end, text): (usize, usize, Option<Tendril>)| {
241+ let len = text.map(|text| text.len()).unwrap() - 1; // minus newline
242+ let pos = start + len;
243+ Range::new(pos, pos)
244+ })
245+ .collect(),
246+ 0,
247+ );
248+
249+ return;
161250 }
162251}
252+
253+impl<A, D> MyTrait<A, D> for YourType
254+where
255+ A: TraitB + TraitC,
256+ D: TraitE + TraitF,
257+{
258+
259+}
260+#[test]
261+//
262+
163263",
164264 );
165265
@@ -171,10 +271,49 @@ mod test {
171271 let highlight_config = language_config.highlight_config(&[]).unwrap().unwrap();
172272 let syntax = Syntax::new(&state.doc, highlight_config.clone());
173273
174− assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 0), 0); // mod
175− assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 1), 1); // fn
176− assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 2), 2); // 1 + 1
177− assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 4), 1); // }
178− assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 5), 0); // }
274+ // {
275+ // {
276+ // 1 + 1
277+ // }
278+ // }
279+ // assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 1), 0); // {
280+ // assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 2), 1); // {
281+ // assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 3), 2); //
282+ // assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 4), 1); // }
283+ // assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 5), 0); // }
284+
285+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 1), 0); // mod
286+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 2), 1); // fn
287+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 3), 2); // 1 + 1
288+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 4), 0); //
289+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 5), 2); // does_indentation_work
290+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 7), 2); // let test_function
291+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 8), 3); // that_param
292+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 9), 2); // );
293+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 10), 0); //
294+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 11), 2); // let test_function
295+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 12), 3); // this_param
296+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 13), 3); // that_param
297+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 14), 2); // );
298+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 15), 0); //
299+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 16), 2); // let test_function
300+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 17), 3); // param2
301+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 18), 2); // );
302+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 20), 2); // let selection
303+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 21), 3); // changes
304+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 22), 4); // clone()
305+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 23), 4); // map()
306+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 24), 5); // let len
307+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 25), 5); // let pos
308+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 26), 5); // Range
309+
310+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 27), 4); // })
311+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 28), 4); // .collect(),
312+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 29), 3); // 0,
313+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 30), 2); // })
314+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 31), 0); //
315+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 32), 2); // return;
316+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 33), 1); // }
317+ assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 34), 0); // }
179318 }
180319}