diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index eb412f3dcb..0c861a889f 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -28,8 +28,10 @@ use language::{ BracketPair, Buffer, Diagnostic, DiagnosticSeverity, Language, Point, Selection, SelectionGoal, TransactionId, }; -pub use multi_buffer::{Anchor, ExcerptId, ExcerptProperties, MultiBuffer, ToOffset, ToPoint}; -use multi_buffer::{AnchorRangeExt, MultiBufferChunks, MultiBufferSnapshot}; +pub use multi_buffer::{ + Anchor, AnchorRangeExt, ExcerptId, ExcerptProperties, MultiBuffer, ToOffset, ToPoint, +}; +use multi_buffer::{MultiBufferChunks, MultiBufferSnapshot}; use postage::watch; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 40f83e9ba0..317cff84b6 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -1917,7 +1917,11 @@ impl BufferSnapshot { }) .collect::>(); - Some(Outline::new(items)) + if items.is_empty() { + None + } else { + Some(Outline::new(items)) + } } pub fn enclosing_bracket_ranges( diff --git a/crates/outline/src/outline.rs b/crates/outline/src/outline.rs index 9b182f0cae..778b1be555 100644 --- a/crates/outline/src/outline.rs +++ b/crates/outline/src/outline.rs @@ -1,4 +1,4 @@ -use editor::{Anchor, Editor, EditorSettings}; +use editor::{Anchor, AnchorRangeExt, Editor, EditorSettings}; use fuzzy::StringMatch; use gpui::{ action, @@ -14,7 +14,10 @@ use gpui::{ use language::Outline; use ordered_float::OrderedFloat; use postage::watch; -use std::{cmp, sync::Arc}; +use std::{ + cmp::{self, Reverse}, + sync::Arc, +}; use workspace::{Settings, Workspace}; action!(Toggle); @@ -34,6 +37,7 @@ pub fn init(cx: &mut MutableAppContext) { struct OutlineView { handle: WeakViewHandle, + editor: ViewHandle, outline: Outline, selected_match_index: usize, matches: Vec, @@ -91,6 +95,7 @@ impl View for OutlineView { impl OutlineView { fn new( outline: Outline, + editor: ViewHandle, settings: watch::Receiver, cx: &mut ViewContext, ) -> Self { @@ -114,6 +119,7 @@ impl OutlineView { .detach(); let mut this = Self { handle: cx.weak_handle(), + editor, matches: Default::default(), selected_match_index: 0, outline, @@ -135,7 +141,7 @@ impl OutlineView { let buffer = editor.read(cx).buffer().read(cx).read(cx).outline(); if let Some(outline) = buffer { workspace.toggle_modal(cx, |cx, workspace| { - cx.add_view(|cx| OutlineView::new(outline, workspace.settings(), cx)) + cx.add_view(|cx| OutlineView::new(outline, editor, workspace.settings(), cx)) }) } } @@ -185,7 +191,31 @@ impl OutlineView { string: Default::default(), }) .collect(); - self.selected_match_index = 0; + + let editor = self.editor.read(cx); + let buffer = editor.buffer().read(cx).read(cx); + let cursor_offset = editor.newest_selection::(&buffer).head(); + self.selected_match_index = self + .outline + .items + .iter() + .enumerate() + .map(|(ix, item)| { + let range = item.range.to_offset(&buffer); + let distance_to_closest_endpoint = cmp::min( + (range.start as isize - cursor_offset as isize).abs() as usize, + (range.end as isize - cursor_offset as isize).abs() as usize, + ); + let depth = if range.contains(&cursor_offset) { + Some(item.depth) + } else { + None + }; + (ix, depth, distance_to_closest_endpoint) + }) + .max_by_key(|(_, depth, distance)| (*depth, Reverse(*distance))) + .unwrap() + .0; } else { self.matches = self.outline.search(&query, cx); self.selected_match_index = self