Show cursor position in status bar (#3464)

Passes the compiler so it must work!

(though it doesn't show up until we fix pane focus)

Release Notes:

- N/A
This commit is contained in:
Conrad Irwin
2023-11-30 16:40:42 -07:00
committed by GitHub
4 changed files with 86 additions and 95 deletions
+72 -76
View File
@@ -8,9 +8,9 @@ use anyhow::{anyhow, Context, Result};
use collections::HashSet;
use futures::future::try_join_all;
use gpui::{
div, point, AnyElement, AppContext, AsyncAppContext, Entity, EntityId, EventEmitter,
FocusHandle, Model, ParentElement, Pixels, SharedString, Styled, Subscription, Task, View,
ViewContext, VisualContext, WeakView, WindowContext,
div, point, AnyElement, AppContext, AsyncAppContext, Div, Entity, EntityId, EventEmitter,
FocusHandle, IntoElement, Model, ParentElement, Pixels, Render, SharedString, Styled,
Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
};
use language::{
proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, OffsetRangeExt,
@@ -20,6 +20,7 @@ use project::{search::SearchQuery, FormatTrigger, Item as _, Project, ProjectPat
use rpc::proto::{self, update_view, PeerId};
use settings::Settings;
use smallvec::SmallVec;
use std::fmt::Write;
use std::{
borrow::Cow,
cmp::{self, Ordering},
@@ -31,8 +32,11 @@ use std::{
use text::Selection;
use theme::{ActiveTheme, Theme};
use ui::{Color, Label};
use util::{paths::PathExt, ResultExt, TryFutureExt};
use workspace::item::{BreadcrumbText, FollowEvent, FollowableEvents, FollowableItemHandle};
use util::{paths::PathExt, paths::FILE_ROW_COLUMN_DELIMITER, ResultExt, TryFutureExt};
use workspace::{
item::{BreadcrumbText, FollowEvent, FollowableEvents, FollowableItemHandle},
StatusItemView,
};
use workspace::{
item::{FollowableItem, Item, ItemEvent, ItemHandle, ProjectItem},
searchable::{Direction, SearchEvent, SearchableItem, SearchableItemHandle},
@@ -1119,86 +1123,78 @@ pub struct CursorPosition {
_observe_active_editor: Option<Subscription>,
}
// impl Default for CursorPosition {
// fn default() -> Self {
// Self::new()
// }
// }
impl Default for CursorPosition {
fn default() -> Self {
Self::new()
}
}
// impl CursorPosition {
// pub fn new() -> Self {
// Self {
// position: None,
// selected_count: 0,
// _observe_active_editor: None,
// }
// }
impl CursorPosition {
pub fn new() -> Self {
Self {
position: None,
selected_count: 0,
_observe_active_editor: None,
}
}
// fn update_position(&mut self, editor: View<Editor>, cx: &mut ViewContext<Self>) {
// let editor = editor.read(cx);
// let buffer = editor.buffer().read(cx).snapshot(cx);
fn update_position(&mut self, editor: View<Editor>, cx: &mut ViewContext<Self>) {
let editor = editor.read(cx);
let buffer = editor.buffer().read(cx).snapshot(cx);
// self.selected_count = 0;
// let mut last_selection: Option<Selection<usize>> = None;
// for selection in editor.selections.all::<usize>(cx) {
// self.selected_count += selection.end - selection.start;
// if last_selection
// .as_ref()
// .map_or(true, |last_selection| selection.id > last_selection.id)
// {
// last_selection = Some(selection);
// }
// }
// self.position = last_selection.map(|s| s.head().to_point(&buffer));
self.selected_count = 0;
let mut last_selection: Option<Selection<usize>> = None;
for selection in editor.selections.all::<usize>(cx) {
self.selected_count += selection.end - selection.start;
if last_selection
.as_ref()
.map_or(true, |last_selection| selection.id > last_selection.id)
{
last_selection = Some(selection);
}
}
self.position = last_selection.map(|s| s.head().to_point(&buffer));
// cx.notify();
// }
// }
cx.notify();
}
}
// impl Entity for CursorPosition {
// type Event = ();
// }
impl Render for CursorPosition {
type Element = Div;
// impl View for CursorPosition {
// fn ui_name() -> &'static str {
// "CursorPosition"
// }
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
div().when_some(self.position, |el, position| {
let mut text = format!(
"{}{FILE_ROW_COLUMN_DELIMITER}{}",
position.row + 1,
position.column + 1
);
if self.selected_count > 0 {
write!(text, " ({} selected)", self.selected_count).unwrap();
}
// fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
// if let Some(position) = self.position {
// let theme = &theme::current(cx).workspace.status_bar;
// let mut text = format!(
// "{}{FILE_ROW_COLUMN_DELIMITER}{}",
// position.row + 1,
// position.column + 1
// );
// if self.selected_count > 0 {
// write!(text, " ({} selected)", self.selected_count).unwrap();
// }
// Label::new(text, theme.cursor_position.clone()).into_any()
// } else {
// Empty::new().into_any()
// }
// }
// }
el.child(Label::new(text))
})
}
}
// impl StatusItemView for CursorPosition {
// fn set_active_pane_item(
// &mut self,
// active_pane_item: Option<&dyn ItemHandle>,
// cx: &mut ViewContext<Self>,
// ) {
// if let Some(editor) = active_pane_item.and_then(|item| item.act_as::<Editor>(cx)) {
// self._observe_active_editor = Some(cx.observe(&editor, Self::update_position));
// self.update_position(editor, cx);
// } else {
// self.position = None;
// self._observe_active_editor = None;
// }
impl StatusItemView for CursorPosition {
fn set_active_pane_item(
&mut self,
active_pane_item: Option<&dyn ItemHandle>,
cx: &mut ViewContext<Self>,
) {
if let Some(editor) = active_pane_item.and_then(|item| item.act_as::<Editor>(cx)) {
self._observe_active_editor = Some(cx.observe(&editor, Self::update_position));
self.update_position(editor, cx);
} else {
self.position = None;
self._observe_active_editor = None;
}
// cx.notify();
// }
// }
cx.notify();
}
}
fn path_for_buffer<'a>(
buffer: &Model<MultiBuffer>,
+4
View File
@@ -240,6 +240,10 @@ impl Element for AnyView {
}
fn paint(self, _: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
debug_assert!(
state.is_some(),
"state is None. Did you include an AnyView twice in the tree?"
);
(self.paint)(&self, state.take().unwrap(), cx)
}
}
+8 -17
View File
@@ -52,22 +52,13 @@ impl Render for StatusBar {
h_stack()
.gap_4()
.child(
h_stack()
.gap_1()
.child(
// TODO: Line / column numbers
div()
.border()
.border_color(gpui::red())
.child(Button::new("status_line_column_numbers", "15:22")),
)
.child(
// TODO: Language picker
div()
.border()
.border_color(gpui::red())
.child(Button::new("status_buffer_language", "Rust")),
),
h_stack().gap_1().child(
// TODO: Language picker
div()
.border()
.border_color(gpui::red())
.child(Button::new("status_buffer_language", "Rust")),
),
)
.child(
h_stack()
@@ -133,7 +124,7 @@ impl StatusBar {
h_stack()
.items_center()
.gap_2()
.children(self.right_items.iter().map(|item| item.to_any()))
.children(self.right_items.iter().rev().map(|item| item.to_any()))
}
}
+2 -2
View File
@@ -147,7 +147,7 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
// let feedback_button = cx.add_view(|_| {
// feedback::deploy_feedback_button::DeployFeedbackButton::new(workspace)
// });
// let cursor_position = cx.add_view(|_| editor::items::CursorPosition::new());
let cursor_position = cx.build_view(|_| editor::items::CursorPosition::new());
workspace.status_bar().update(cx, |status_bar, cx| {
status_bar.add_left_item(diagnostic_summary, cx);
status_bar.add_left_item(activity_indicator, cx);
@@ -156,7 +156,7 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
// status_bar.add_right_item(copilot, cx);
// status_bar.add_right_item(active_buffer_language, cx);
// status_bar.add_right_item(vim_mode_indicator, cx);
// status_bar.add_right_item(cursor_position, cx);
status_bar.add_right_item(cursor_position, cx);
});
auto_update::notify_of_any_new_update(cx);