Skip to content

Commit

Permalink
LS: Dynamic Indentation for Auto Open (#871)
Browse files Browse the repository at this point in the history
Changes the hardcoded indentation used for auto-open to use an
indentation based on the text found before the insertion location. This
will allow the indentation to be accurate for both the namespace
experience, and the notebook experience.
  • Loading branch information
ScottCarda-MS authored Nov 27, 2023
1 parent bcecf3a commit 24acbd3
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 43 deletions.
40 changes: 38 additions & 2 deletions language_service/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ pub(crate) fn get_completions(
};
context_finder.visit_package(user_ast_package);

let indent = match context_finder.start_of_namespace {
Some(start) => get_indent(compilation, start),
None => String::new(),
};

// The PRELUDE namespaces are always implicitly opened.
context_finder
.opens
Expand Down Expand Up @@ -74,6 +79,7 @@ pub(crate) fn get_completions(
&context_finder.opens,
context_finder.start_of_namespace,
&context_finder.current_namespace_name,
&indent,
);
}

Expand All @@ -90,6 +96,7 @@ pub(crate) fn get_completions(
&context_finder.opens,
context_finder.start_of_namespace,
&context_finder.current_namespace_name,
&indent,
);

// Item decl keywords last, unlike in a namespace
Expand All @@ -113,6 +120,7 @@ pub(crate) fn get_completions(
&context_finder.opens,
context_finder.start_of_namespace,
&context_finder.current_namespace_name,
&indent,
);

// Namespace declarations - least likely to be used, so last
Expand All @@ -126,6 +134,30 @@ pub(crate) fn get_completions(
}
}

fn get_indent(compilation: &Compilation, package_offset: u32) -> String {
let source = compilation
.user_unit()
.sources
.find_by_offset(package_offset)
.expect("source should exist in the user source map");
let source_offset = (package_offset - source.offset)
.try_into()
.expect("offset can't be converted to uszie");
let before_offset = &source.contents[..source_offset];
let mut indent = match before_offset.rfind(|c| c == '{' || c == '\n') {
Some(begin) => {
let indent = &before_offset[begin..];
indent.strip_prefix('{').unwrap_or(indent)
}
None => before_offset,
}
.to_string();
if !indent.starts_with('\n') {
indent.insert(0, '\n');
}
indent
}

struct CompletionListBuilder {
current_sort_group: u32,
items: Vec<CompletionItem>,
Expand Down Expand Up @@ -199,6 +231,7 @@ impl CompletionListBuilder {
opens: &[(Rc<str>, Option<Rc<str>>)],
start_of_namespace: Option<u32>,
current_namespace_name: &Option<Rc<str>>,
indent: &String,
) {
let core = &compilation
.package_store
Expand All @@ -222,6 +255,7 @@ impl CompletionListBuilder {
opens,
start_of_namespace,
current_namespace_name.clone(),
indent,
));
}

Expand Down Expand Up @@ -298,6 +332,7 @@ impl CompletionListBuilder {
opens: &'a [(Rc<str>, Option<Rc<str>>)],
start_of_namespace: Option<u32>,
current_namespace_name: Option<Rc<str>>,
indent: &'a String,
) -> impl Iterator<Item = (CompletionItem, u32)> + 'a {
let package = &compilation
.package_store
Expand Down Expand Up @@ -343,8 +378,9 @@ impl CompletionListBuilder {
additional_edits.push((
protocol::Span { start, end: start },
format!(
"open {};\n ",
namespace.name.clone()
"open {};{}",
namespace.name.clone(),
indent,
),
));
None
Expand Down
83 changes: 42 additions & 41 deletions language_service/src/completion/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::test_utils::{
compile_notebook_with_fake_stdlib_and_markers, compile_with_fake_stdlib,
get_source_and_marker_offsets,
};
use indoc::indoc;

fn check(source_with_cursor: &str, completions_to_check: &[&str], expect: &Expect) {
let (source, cursor_offset, _) = get_source_and_marker_offsets(source_with_cursor);
Expand Down Expand Up @@ -50,12 +51,12 @@ fn check_notebook(
#[test]
fn in_block_contains_std_functions() {
check(
r#"
indoc! {r#"
namespace Test {
operation Test() : Unit {
}
}"#,
}"#},
&["Fake", "FakeWithParam", "FakeCtlAdj"],
&expect![[r#"
[
Expand All @@ -73,8 +74,8 @@ fn in_block_contains_std_functions() {
[
(
Span {
start: 30,
end: 30,
start: 21,
end: 21,
},
"open FakeStdLib;\n ",
),
Expand All @@ -96,8 +97,8 @@ fn in_block_contains_std_functions() {
[
(
Span {
start: 30,
end: 30,
start: 21,
end: 21,
},
"open FakeStdLib;\n ",
),
Expand All @@ -119,8 +120,8 @@ fn in_block_contains_std_functions() {
[
(
Span {
start: 30,
end: 30,
start: 21,
end: 21,
},
"open FakeStdLib;\n ",
),
Expand All @@ -136,13 +137,13 @@ fn in_block_contains_std_functions() {
#[test]
fn in_block_no_auto_open() {
check(
r#"
indoc! {r#"
namespace Test {
open FakeStdLib;
operation Test() : Unit {
}
}"#,
}"#},
&["Fake"],
&expect![[r#"
[
Expand All @@ -167,13 +168,13 @@ fn in_block_no_auto_open() {
#[test]
fn in_block_with_alias() {
check(
r#"
indoc! {r#"
namespace Test {
open FakeStdLib as Alias;
operation Test() : Unit {
}
}"#,
}"#},
&["Alias.Fake"],
&expect![[r#"
[
Expand All @@ -198,15 +199,15 @@ fn in_block_with_alias() {
#[test]
fn in_block_from_other_namespace() {
check(
r#"
indoc! {r#"
namespace Test {
operation Test() : Unit {
}
}
namespace Other {
operation Foo() : Unit {}
}"#,
}"#},
&["Foo"],
&expect![[r#"
[
Expand All @@ -224,8 +225,8 @@ fn in_block_from_other_namespace() {
[
(
Span {
start: 30,
end: 30,
start: 21,
end: 21,
},
"open Other;\n ",
),
Expand All @@ -242,13 +243,13 @@ fn in_block_from_other_namespace() {
#[test]
fn in_block_nested_op() {
check(
r#"
indoc! {r#"
namespace Test {
operation Test() : Unit {
operation Foo() : Unit {}
}
}"#,
}"#},
&["Foo"],
&expect![[r#"
[
Expand All @@ -273,15 +274,15 @@ fn in_block_nested_op() {
#[test]
fn in_block_hidden_nested_op() {
check(
r#"
indoc! {r#"
namespace Test {
operation Test() : Unit {
}
operation Foo() : Unit {
operation Bar() : Unit {}
}
}"#,
}"#},
&["Bar"],
&expect![[r#"
[
Expand All @@ -294,12 +295,12 @@ fn in_block_hidden_nested_op() {
#[test]
fn in_namespace_contains_open() {
check(
r#"
indoc! {r#"
namespace Test {
operation Test() : Unit {
}
}"#,
}"#},
&["open"],
&expect![[r#"
[
Expand All @@ -322,10 +323,10 @@ fn in_namespace_contains_open() {
#[test]
fn top_level_contains_namespace() {
check(
r#"
indoc! {r#"
namespace Test {}
"#,
"#},
&["namespace"],
&expect![[r#"
[
Expand All @@ -348,11 +349,11 @@ fn top_level_contains_namespace() {
#[test]
fn attributes() {
check(
r#"
indoc! {r#"
namespace Test {
}
"#,
"#},
&["@EntryPoint()"],
&expect![[r#"
[
Expand All @@ -375,12 +376,12 @@ fn attributes() {
#[test]
fn stdlib_udt() {
check(
r#"
indoc! {r#"
namespace Test {
operation Test() : Unit {
}
"#,
"#},
&["TakesUdt"],
&expect![[r#"
[
Expand All @@ -398,8 +399,8 @@ fn stdlib_udt() {
[
(
Span {
start: 38,
end: 38,
start: 21,
end: 21,
},
"open FakeStdLib;\n ",
),
Expand All @@ -417,9 +418,9 @@ fn notebook_top_level() {
check_notebook(
&[(
"cell1",
r#"operation Foo() : Unit {}
indoc! {r#"operation Foo() : Unit {}
"#,
"#},
)],
&["operation", "namespace", "let", "Fake"],
&expect![[r#"
Expand Down Expand Up @@ -474,7 +475,7 @@ fn notebook_top_level() {
start: 0,
end: 0,
},
"open FakeStdLib;\n ",
"open FakeStdLib;\n",
),
],
),
Expand All @@ -490,9 +491,9 @@ fn notebook_top_level_global() {
check_notebook(
&[(
"cell1",
r#"operation Foo() : Unit {}
indoc! {r#"operation Foo() : Unit {}
"#,
"#},
)],
&["Fake"],
&expect![[r#"
Expand All @@ -514,7 +515,7 @@ fn notebook_top_level_global() {
start: 0,
end: 0,
},
"open FakeStdLib;\n ",
"open FakeStdLib;\n",
),
],
),
Expand All @@ -530,11 +531,11 @@ fn notebook_top_level_namespace_already_open_for_global() {
check_notebook(
&[(
"cell1",
r#"
indoc! {r#"
open FakeStdLib;
operation Foo() : Unit {}
"#,
"#},
)],
&["Fake"],
&expect![[r#"
Expand Down Expand Up @@ -562,10 +563,10 @@ fn notebook_block() {
check_notebook(
&[(
"cell1",
r#"operation Foo() : Unit {
indoc! {r#"operation Foo() : Unit {
}
"#,
"#},
)],
&["Fake", "let"],
&expect![[r#"
Expand All @@ -587,7 +588,7 @@ fn notebook_block() {
start: 0,
end: 0,
},
"open FakeStdLib;\n ",
"open FakeStdLib;\n",
),
],
),
Expand Down

0 comments on commit 24acbd3

Please sign in to comment.