@@ -2452,7 +2452,7 @@ fn find_matching_bracket_text_based(
.find_map(|(ch, char_offset)| get_bracket_pair(ch).map(|info| (info, char_offset)));
if bracket_info.is_none() {
- return find_matching_c_preprocessor_directive(map, line_range);
+ return find_matching_c_preprocessor_directive(map, line_range, offset);
}
let (open, close, is_opening) = bracket_info?.0;
@@ -2489,18 +2489,20 @@ fn find_matching_bracket_text_based(
fn find_matching_c_preprocessor_directive(
map: &DisplaySnapshot,
line_range: Range<MultiBufferOffset>,
+ offset: MultiBufferOffset,
) -> Option<MultiBufferOffset> {
let line_start = map
.buffer_chars_at(line_range.start)
.skip_while(|(c, _)| *c == ' ' || *c == '\t')
+ .take_while(|(c, char_offset)| *char_offset < line_range.end && !c.is_whitespace())
.map(|(c, _)| c)
- .take(6)
.collect::<String>();
- if line_start.starts_with("#if")
- || line_start.starts_with("#else")
- || line_start.starts_with("#elif")
- {
+ if line_range.start + line_start.len() < offset {
+ return None;
+ }
+
+ if line_start.starts_with("#if") || line_start.starts_with("#el") {
let mut depth = 0i32;
for (ch, char_offset) in map.buffer_chars_at(line_range.end) {
if ch != '\n' {
@@ -2618,8 +2620,30 @@ fn matching(
// Ensure the range is contained by the current line.
let mut line_end = map.next_line_boundary(point).0;
- if line_end == point {
- line_end = map.max_point().to_point(map);
+ let max_point = map.max_point().to_point(map);
+
+ // Only widen to EOF when the cursor is actually at EOF.
+ // This avoids expanding a blank current line into start..EOF.
+ if line_end == point && point == max_point {
+ line_end = max_point;
+ }
+
+ let line_range = map.prev_line_boundary(point).0..line_end;
+ let line_range = line_range.start.to_offset(&map.buffer_snapshot())
+ ..line_range.end.to_offset(&map.buffer_snapshot());
+
+ if let Some(preproc_range) = find_matching_c_preprocessor_directive(map, line_range, offset) {
+ return preproc_range.to_display_point(map);
+ }
+
+ if let Some((open_range, close_range)) = comment_delimiter_pair(map, offset) {
+ if open_range.contains(&offset) {
+ return close_range.start.to_display_point(map);
+ }
+
+ if close_range.contains(&offset) {
+ return open_range.start.to_display_point(map);
+ }
}
let is_quote_char = |ch: char| matches!(ch, '\'' | '"' | '`');
@@ -2729,32 +2753,6 @@ fn matching(
continue;
}
- if let Some((open_range, close_range)) = comment_delimiter_pair(map, offset) {
- if open_range.contains(&offset) {
- return close_range.start.to_display_point(map);
- }
-
- if close_range.contains(&offset) {
- return open_range.start.to_display_point(map);
- }
-
- let open_candidate = (open_range.start >= offset
- && line_range.contains(&open_range.start))
- .then_some((open_range.start.saturating_sub(offset), close_range.start));
-
- let close_candidate = (close_range.start >= offset
- && line_range.contains(&close_range.start))
- .then_some((close_range.start.saturating_sub(offset), open_range.start));
-
- if let Some((_, destination)) = [open_candidate, close_candidate]
- .into_iter()
- .flatten()
- .min_by_key(|(distance, _)| *distance)
- {
- return destination.to_display_point(map);
- }
- }
-
closest_pair_destination
.map(|destination| destination.to_display_point(map))
.unwrap_or_else(|| {
@@ -3663,6 +3661,10 @@ mod test {
cx.shared_state().await.assert_eq(indoc! {r"/*
this is a comment
ˇ*/"});
+ cx.simulate_shared_keystrokes("k %").await;
+ cx.shared_state().await.assert_eq(indoc! {r"/*
+ ˇ this is a comment
+ */"});
cx.set_shared_state("ˇ// comment").await;
cx.simulate_shared_keystrokes("%").await;
@@ -3673,48 +3675,53 @@ mod test {
async fn test_matching_preprocessor_directives(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await;
- cx.set_shared_state(indoc! {r"#ˇif
+ cx.set_shared_state(indoc! {r"
+ #ˇif
- #else
+ #else
- #endif
- "})
+ #endif
+ "})
.await;
cx.simulate_shared_keystrokes("%").await;
- cx.shared_state().await.assert_eq(indoc! {r"#if
+ cx.shared_state().await.assert_eq(indoc! {r"
+ #if
ˇ#else
#endif
- "});
+ "});
cx.simulate_shared_keystrokes("%").await;
- cx.shared_state().await.assert_eq(indoc! {r"#if
+ cx.shared_state().await.assert_eq(indoc! {r"
+ #if
#else
ˇ#endif
- "});
+ "});
cx.simulate_shared_keystrokes("%").await;
- cx.shared_state().await.assert_eq(indoc! {r"ˇ#if
+ cx.shared_state().await.assert_eq(indoc! {r"
+ ˇ#if
#else
#endif
- "});
+ "});
cx.set_shared_state(indoc! {r"
- #ˇif
- #if
-
- #else
-
- #endif
+ #ˇif
+ #if
#else
+
#endif
- "})
+
+ #else
+
+ #endif
+ "})
.await;
cx.simulate_shared_keystrokes("%").await;
@@ -3727,8 +3734,9 @@ mod test {
#endif
ˇ#else
+
#endif
- "});
+ "});
cx.simulate_shared_keystrokes("% %").await;
cx.shared_state().await.assert_eq(indoc! {r"
@@ -3740,8 +3748,9 @@ mod test {
#endif
#else
+
#endif
- "});
+ "});
cx.simulate_shared_keystrokes("j % % %").await;
cx.shared_state().await.assert_eq(indoc! {r"
#if
@@ -3752,8 +3761,28 @@ mod test {
#endif
#else
+
#endif
- "});
+ "});
+
+ cx.set_shared_state(indoc! {r"
+ #if definedˇ(something)
+
+ #endif
+ "})
+ .await;
+ cx.simulate_shared_keystrokes("%").await;
+ cx.shared_state().await.assert_eq(indoc! {r"
+ #if defined(somethingˇ)
+
+ #endif
+ "});
+ cx.simulate_shared_keystrokes("0 %").await;
+ cx.shared_state().await.assert_eq(indoc! {r"
+ #if defined(something)
+
+ ˇ#endif
+ "});
}
#[gpui::test]
@@ -5,6 +5,9 @@
{"Get":{"state":"ˇ/*\n this is a comment\n*/","mode":"Normal"}}
{"Key":"%"}
{"Get":{"state":"/*\n this is a comment\nˇ*/","mode":"Normal"}}
+{"Key":"k"}
+{"Key":"%"}
+{"Get":{"state":"/*\nˇ this is a comment\n*/","mode":"Normal"}}
{"Put":{"state":"ˇ// comment"}}
{"Key":"%"}
{"Get":{"state":"ˇ// comment","mode":"Normal"}}
@@ -5,14 +5,20 @@
{"Get":{"state":"#if\n\n#else\n\nˇ#endif\n","mode":"Normal"}}
{"Key":"%"}
{"Get":{"state":"ˇ#if\n\n#else\n\n#endif\n","mode":"Normal"}}
-{"Put":{"state":"#ˇif\n #if\n\n #else\n\n #endif\n\n#else\n#endif\n"}}
+{"Put":{"state":"#ˇif\n #if\n\n #else\n\n #endif\n\n#else\n\n#endif\n"}}
{"Key":"%"}
-{"Get":{"state":"#if\n #if\n\n #else\n\n #endif\n\nˇ#else\n#endif\n","mode":"Normal"}}
+{"Get":{"state":"#if\n #if\n\n #else\n\n #endif\n\nˇ#else\n\n#endif\n","mode":"Normal"}}
{"Key":"%"}
{"Key":"%"}
-{"Get":{"state":"ˇ#if\n #if\n\n #else\n\n #endif\n\n#else\n#endif\n","mode":"Normal"}}
+{"Get":{"state":"ˇ#if\n #if\n\n #else\n\n #endif\n\n#else\n\n#endif\n","mode":"Normal"}}
{"Key":"j"}
{"Key":"%"}
{"Key":"%"}
{"Key":"%"}
-{"Get":{"state":"#if\n ˇ#if\n\n #else\n\n #endif\n\n#else\n#endif\n","mode":"Normal"}}
+{"Get":{"state":"#if\n ˇ#if\n\n #else\n\n #endif\n\n#else\n\n#endif\n","mode":"Normal"}}
+{"Put":{"state":"#if definedˇ(something)\n\n#endif\n"}}
+{"Key":"%"}
+{"Get":{"state":"#if defined(somethingˇ)\n\n#endif\n","mode":"Normal"}}
+{"Key":"0"}
+{"Key":"%"}
+{"Get":{"state":"#if defined(something)\n\nˇ#endif\n","mode":"Normal"}}