Draw rest of the owl

This commit is contained in:
Piotr Osiewicz 2023-11-07 00:10:59 +01:00
parent 750f901f9c
commit 72e42a0d89
13 changed files with 99 additions and 57 deletions

4
Cargo.lock generated
View file

@ -329,6 +329,7 @@ dependencies = [
"collections",
"ctor",
"editor",
"editor_extensions",
"env_logger 0.9.3",
"fs",
"futures 0.3.28",
@ -1726,6 +1727,7 @@ dependencies = [
"db",
"drag_and_drop",
"editor",
"editor_extensions",
"feature_flags",
"feedback",
"futures 0.3.28",
@ -2941,6 +2943,7 @@ dependencies = [
"anyhow",
"client",
"editor",
"editor_extensions",
"futures 0.3.28",
"gpui",
"human_bytes",
@ -11148,6 +11151,7 @@ dependencies = [
"db",
"diagnostics",
"editor",
"editor_extensions",
"env_logger 0.9.3",
"feature_flags",
"feedback",

View file

@ -13,6 +13,7 @@ ai = { path = "../ai" }
client = { path = "../client" }
collections = { path = "../collections"}
editor = { path = "../editor" }
editor_extensions = { path = "../editor_extensions" }
fs = { path = "../fs" }
gpui = { path = "../gpui" }
language = { path = "../language" }

View file

@ -24,6 +24,7 @@ use editor::{
scroll::autoscroll::{Autoscroll, AutoscrollStrategy},
Anchor, Editor, MoveDown, MoveUp, MultiBufferSnapshot, ToOffset, ToPoint,
};
use editor_extensions::FollowableEditor;
use fs::Fs;
use futures::StreamExt;
use gpui::{
@ -2196,7 +2197,7 @@ struct ConversationEditor {
conversation: ModelHandle<Conversation>,
fs: Arc<dyn Fs>,
workspace: WeakViewHandle<Workspace>,
editor: ViewHandle<Editor>,
editor: ViewHandle<FollowableEditor>,
blocks: HashSet<BlockId>,
scroll_position: Option<ScrollPosition>,
_subscriptions: Vec<Subscription>,
@ -2222,10 +2223,11 @@ impl ConversationEditor {
cx: &mut ViewContext<Self>,
) -> Self {
let editor = cx.add_view(|cx| {
let mut editor = Editor::for_buffer(conversation.read(cx).buffer.clone(), None, cx);
editor.set_soft_wrap_mode(SoftWrap::EditorWidth, cx);
editor.set_show_gutter(false, cx);
editor.set_show_wrap_guides(false, cx);
let mut editor = FollowableEditor::for_raw_buffer(conversation.read(cx).buffer.clone(), cx);
editor.0.update(cx, |this, cx| {this.set_soft_wrap_mode(SoftWrap::EditorWidth, cx);
this.set_show_gutter(false, cx);
this.set_show_wrap_guides(false, cx);
});
editor
});
@ -2277,11 +2279,11 @@ impl ConversationEditor {
.collect::<Vec<_>>();
if !new_selections.is_empty() {
self.editor.update(cx, |editor, cx| {
editor.change_selections(
editor.0.update(cx, |this, cx| this.change_selections(
Some(Autoscroll::Strategy(AutoscrollStrategy::Fit)),
cx,
|selections| selections.select_ranges(new_selections),
);
));
});
// Avoid scrolling to the new cursor position so the assistant's output is stable.
cx.defer(|this, _| this.scroll_position = None);
@ -2310,7 +2312,7 @@ impl ConversationEditor {
}
fn cursors(&self, cx: &AppContext) -> Vec<usize> {
let selections = self.editor.read(cx).selections.all::<usize>(cx);
let selections = self.editor.read(cx).0.read(cx).selections.all::<usize>(cx);
selections
.into_iter()
.map(|selection| selection.head())
@ -2339,14 +2341,14 @@ impl ConversationEditor {
ConversationEvent::StreamedCompletion => {
self.editor.update(cx, |editor, cx| {
if let Some(scroll_position) = self.scroll_position {
let snapshot = editor.snapshot(cx);
let snapshot = editor.0.update(cx, |this, cx| this.snapshot(cx));
let cursor_point = scroll_position.cursor.to_display_point(&snapshot);
let scroll_top =
cursor_point.row() as f32 - scroll_position.offset_before_cursor.y();
editor.set_scroll_position(
editor.0.update(cx, |this, cx| this.set_scroll_position(
vec2f(scroll_position.offset_before_cursor.x(), scroll_top),
cx,
);
));
}
});
}
@ -2355,7 +2357,7 @@ impl ConversationEditor {
fn handle_editor_event(
&mut self,
_: ViewHandle<Editor>,
_: ViewHandle<FollowableEditor>,
event: &editor::Event,
cx: &mut ViewContext<Self>,
) {
@ -2377,15 +2379,15 @@ impl ConversationEditor {
fn cursor_scroll_position(&self, cx: &mut ViewContext<Self>) -> Option<ScrollPosition> {
self.editor.update(cx, |editor, cx| {
let snapshot = editor.snapshot(cx);
let cursor = editor.selections.newest_anchor().head();
let snapshot = editor.0.update(cx, |this, cx| this.snapshot(cx));
let cursor = editor.0.read(cx).selections.newest_anchor().head();
let cursor_row = cursor.to_display_point(&snapshot.display_snapshot).row() as f32;
let scroll_position = editor
let scroll_position = editor.0.read(cx)
.scroll_manager
.anchor()
.scroll_position(&snapshot.display_snapshot);
let scroll_bottom = scroll_position.y() + editor.visible_line_count().unwrap_or(0.);
let scroll_bottom = scroll_position.y() + editor.0.read(cx).visible_line_count().unwrap_or(0.);
if (scroll_position.y()..scroll_bottom).contains(&cursor_row) {
Some(ScrollPosition {
cursor,
@ -2402,7 +2404,7 @@ impl ConversationEditor {
fn update_message_headers(&mut self, cx: &mut ViewContext<Self>) {
self.editor.update(cx, |editor, cx| {
let buffer = editor.buffer().read(cx).snapshot(cx);
let buffer = editor.0.read(cx).buffer().read(cx).snapshot(cx);
let excerpt_id = *buffer.as_singleton().unwrap().0;
let old_blocks = std::mem::take(&mut self.blocks);
let new_blocks = self
@ -2505,8 +2507,10 @@ impl ConversationEditor {
})
.collect::<Vec<_>>();
editor.remove_blocks(old_blocks, None, cx);
let ids = editor.insert_blocks(new_blocks, None, cx);
let ids = editor.0.update(cx, |this, cx| {
this.remove_blocks(old_blocks, None, cx);
this.insert_blocks(new_blocks, None, cx)
});
self.blocks = HashSet::from_iter(ids);
});
}
@ -2568,14 +2572,14 @@ impl ConversationEditor {
conversation.update(cx, |conversation, cx| {
conversation
.editor
.update(cx, |editor, cx| editor.insert(&text, cx))
.update(cx, |editor, cx| editor.0.update(cx, |this, cx| this.insert(&text, cx)))
});
});
}
}
fn copy(&mut self, _: &editor::Copy, cx: &mut ViewContext<Self>) {
let editor = self.editor.read(cx);
let editor = self.editor.read(cx).0.read(cx);
let conversation = self.conversation.read(cx);
if editor.selections.count() == 1 {
let selection = editor.selections.newest::<usize>(cx);
@ -2610,9 +2614,9 @@ impl ConversationEditor {
fn split(&mut self, _: &Split, cx: &mut ViewContext<Self>) {
self.conversation.update(cx, |conversation, cx| {
let selections = self.editor.read(cx).selections.disjoint_anchors();
let selections = self.editor.read(cx).0.read(cx).selections.disjoint_anchors();
for selection in selections.into_iter() {
let buffer = self.editor.read(cx).buffer().read(cx).snapshot(cx);
let buffer = self.editor.read(cx).0.read(cx).buffer().read(cx).snapshot(cx);
let range = selection
.map(|endpoint| endpoint.to_offset(&buffer))
.range();

View file

@ -32,6 +32,7 @@ collections = { path = "../collections" }
context_menu = { path = "../context_menu" }
drag_and_drop = { path = "../drag_and_drop" }
editor = { path = "../editor" }
editor_extensions = { path = "../editor_extensions" }
feedback = { path = "../feedback" }
fuzzy = { path = "../fuzzy" }
gpui = { path = "../gpui" }

View file

@ -7,6 +7,7 @@ use client::{
};
use collections::HashMap;
use editor::{CollaborationHub, Editor};
use editor_extensions::FollowableEditor;
use gpui::{
actions,
elements::{ChildView, Label},
@ -35,7 +36,7 @@ pub fn init(cx: &mut AppContext) {
}
pub struct ChannelView {
pub editor: ViewHandle<Editor>,
pub editor: ViewHandle<FollowableEditor>,
project: ModelHandle<Project>,
channel_store: ModelHandle<ChannelStore>,
channel_buffer: ModelHandle<ChannelBuffer>,
@ -137,16 +138,18 @@ impl ChannelView {
) -> Self {
let buffer = channel_buffer.read(cx).buffer();
let editor = cx.add_view(|cx| {
let mut editor = Editor::for_buffer(buffer, None, cx);
editor.set_collaboration_hub(Box::new(ChannelBufferCollaborationHub(
let mut editor = FollowableEditor::for_raw_buffer(buffer, cx);
editor.0.update(cx, |this, cx| {
this.set_collaboration_hub(Box::new(ChannelBufferCollaborationHub(
channel_buffer.clone(),
)));
editor.set_read_only(
this.set_read_only(
!channel_buffer
.read(cx)
.channel(cx)
.is_some_and(|c| c.can_edit_notes()),
);
);
});
editor
});
let _editor_event_subscription = cx.subscribe(&editor, |_, _, e, cx| cx.emit(e.clone()));
@ -176,12 +179,12 @@ impl ChannelView {
) {
match event {
ChannelBufferEvent::Disconnected => self.editor.update(cx, |editor, cx| {
editor.set_read_only(true);
editor.0.update(cx, |this, cx| this.set_read_only(true));
cx.notify();
}),
ChannelBufferEvent::ChannelChanged => {
self.editor.update(cx, |editor, cx| {
editor.set_read_only(!self.channel(cx).is_some_and(|c| c.can_edit_notes()));
editor.0.update(cx, |this, cx| this.set_read_only(!self.channel(cx).is_some_and(|c| c.can_edit_notes())));
cx.emit(editor::Event::TitleChanged);
cx.notify()
});
@ -320,7 +323,7 @@ impl Item for ChannelView {
}
fn to_item_events(event: &Self::Event) -> SmallVec<[ItemEvent; 2]> {
editor::Editor::to_item_events(event)
FollowableEditor::to_item_events(event)
}
}
@ -430,7 +433,7 @@ impl FollowableItem for ChannelView {
}
fn should_unfollow_on_event(event: &Self::Event, cx: &AppContext) -> bool {
Editor::should_unfollow_on_event(event, cx)
FollowableEditor::should_unfollow_on_event(event, cx)
}
fn is_project_item(&self, _cx: &AppContext) -> bool {

View file

@ -20,6 +20,7 @@ use context_menu::{ContextMenu, ContextMenuItem};
use db::kvp::KEY_VALUE_STORE;
use drag_and_drop::{DragAndDrop, Draggable};
use editor::{Cancel, Editor};
use editor_extensions::FollowableEditor;
use feature_flags::{ChannelsAlpha, FeatureFlagAppExt, FeatureFlagViewExt};
use futures::StreamExt;
use fuzzy::{match_strings, StringMatchCandidate};
@ -274,7 +275,7 @@ pub struct CollabPanel {
pending_serialization: Task<Option<()>>,
context_menu: ViewHandle<ContextMenu>,
filter_editor: ViewHandle<Editor>,
channel_name_editor: ViewHandle<Editor>,
channel_name_editor: ViewHandle<FollowableEditor>,
channel_editing_state: Option<ChannelEditingState>,
entries: Vec<ListEntry>,
selection: Option<usize>,
@ -409,7 +410,7 @@ impl CollabPanel {
.detach();
let channel_name_editor = cx.add_view(|cx| {
Editor::single_line(
FollowableEditor::single_line(
Some(Arc::new(|theme| {
theme.collab_panel.user_query_editor.clone()
})),
@ -1433,7 +1434,7 @@ impl CollabPanel {
fn take_editing_state(&mut self, cx: &mut ViewContext<Self>) -> bool {
if let Some(_) = self.channel_editing_state.take() {
self.channel_name_editor.update(cx, |editor, cx| {
editor.set_text("", cx);
editor.0.update(cx, |this, cx| this.set_text("", cx));
});
true
} else {
@ -2822,7 +2823,7 @@ impl CollabPanel {
fn insert_space(&mut self, _: &InsertSpace, cx: &mut ViewContext<Self>) {
if self.channel_editing_state.is_some() {
self.channel_name_editor.update(cx, |editor, cx| {
editor.insert(" ", cx);
editor.0.update(cx, |this, cx| this.insert(" ", cx));
});
}
}
@ -2838,7 +2839,7 @@ impl CollabPanel {
if pending_name.is_some() {
return false;
}
let channel_name = self.channel_name_editor.read(cx).text(cx);
let channel_name = self.channel_name_editor.read(cx).0.read(cx).text(cx);
*pending_name = Some(channel_name.clone());
@ -2856,7 +2857,7 @@ impl CollabPanel {
if pending_name.is_some() {
return false;
}
let channel_name = self.channel_name_editor.read(cx).text(cx);
let channel_name = self.channel_name_editor.read(cx).0.read(cx).text(cx);
*pending_name = Some(channel_name.clone());
self.channel_store
@ -3025,8 +3026,11 @@ impl CollabPanel {
pending_name: None,
});
self.channel_name_editor.update(cx, |editor, cx| {
editor.set_text(channel.name.clone(), cx);
editor.select_all(&Default::default(), cx);
editor.0.update(cx, |this, cx| {
this.set_text(channel.name.clone(), cx);
this.select_all(&Default::default(), cx);
})
});
cx.focus(self.channel_name_editor.as_any());
self.update_entries(false, cx);

View file

@ -617,7 +617,7 @@ pub const MAX_TAB_TITLE_LEN: usize = 24;
type CompletionId = usize;
type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
pub type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
type BackgroundHighlight = (fn(&Theme) -> Color, Vec<Range<Anchor>>);

View file

@ -453,6 +453,27 @@ impl FollowableEditor {
}),
)
}
pub fn for_raw_buffer(
buffer: ModelHandle<Buffer>,
cx: &mut ViewContext<Self>,
) -> Self {
Self(
cx.add_view(|cx| {
Editor::for_buffer(buffer, None, cx)
}),
)
}
pub fn single_line(
field_editor_style: Option<Arc<editor::GetFieldEditorTheme>>,
cx: &mut ViewContext<Self>,
) -> Self {
Self(
cx.add_view(|cx| {
Editor::single_line(field_editor_style, cx)
}),
)
}
}
impl gpui::View for FollowableEditor {

View file

@ -13,6 +13,7 @@ test-support = []
[dependencies]
client = { path = "../client" }
editor = { path = "../editor" }
editor_extensions = { path = "../editor_extensions" }
language = { path = "../language" }
gpui = { path = "../gpui" }
project = { path = "../project" }

View file

@ -2,6 +2,7 @@ use crate::system_specs::SystemSpecs;
use anyhow::bail;
use client::{Client, ZED_SECRET_CLIENT_TOKEN, ZED_SERVER_URL};
use editor::{Anchor, Editor};
use editor_extensions::FollowableEditor;
use futures::AsyncReadExt;
use gpui::{
actions,
@ -58,7 +59,7 @@ struct FeedbackRequestBody<'a> {
#[derive(Clone)]
pub(crate) struct FeedbackEditor {
system_specs: SystemSpecs,
editor: ViewHandle<Editor>,
editor: ViewHandle<FollowableEditor>,
project: ModelHandle<Project>,
pub allow_submission: bool,
}
@ -71,8 +72,8 @@ impl FeedbackEditor {
cx: &mut ViewContext<Self>,
) -> Self {
let editor = cx.add_view(|cx| {
let mut editor = Editor::for_buffer(buffer, Some(Arc::new(project.clone())), cx);
editor.set_vertical_scroll_margin(5, cx);
let mut editor = FollowableEditor::for_buffer(buffer, project.clone(), cx);
editor.0.update(cx, |this, cx| this.set_vertical_scroll_margin(5, cx));
editor
});
@ -92,7 +93,7 @@ impl FeedbackEditor {
return Task::ready(Ok(()));
}
let feedback_text = self.editor.read(cx).text(cx);
let feedback_text = self.editor.read(cx).0.read(cx).text(cx);
let feedback_char_count = feedback_text.chars().count();
let feedback_text = feedback_text.trim().to_string();
@ -339,7 +340,7 @@ impl Item for FeedbackEditor {
{
let buffer = self
.editor
.read(cx)
.read(cx).0.read(cx)
.buffer()
.read(cx)
.as_singleton()
@ -373,7 +374,7 @@ impl Item for FeedbackEditor {
}
fn to_item_events(event: &Self::Event) -> SmallVec<[ItemEvent; 2]> {
Editor::to_item_events(event)
FollowableEditor::to_item_events(event)
}
}

View file

@ -38,6 +38,7 @@ copilot_button = { path = "../copilot_button" }
diagnostics = { path = "../diagnostics" }
db = { path = "../db" }
editor = { path = "../editor" }
editor_extensions = { path = "../editor_extensions" }
feedback = { path = "../feedback" }
file_finder = { path = "../file_finder" }
search = { path = "../search" }

View file

@ -93,7 +93,7 @@ fn main() {
if cx.has_global::<Weak<AppState>>() {
if let Some(app_state) = cx.global::<Weak<AppState>>().upgrade() {
workspace::open_new(&app_state, cx, |workspace, cx| {
Editor::new_file(workspace, &Default::default(), cx)
editor_extensions::new_file(workspace, &Default::default(), cx)
})
.detach();
}
@ -343,7 +343,7 @@ async fn restore_or_create_workspace(app_state: &Arc<AppState>, mut cx: AsyncApp
} else {
cx.update(|cx| {
workspace::open_new(app_state, cx, |workspace, cx| {
Editor::new_file(workspace, &Default::default(), cx)
editor_extensions::new_file(workspace, &Default::default(), cx)
})
.detach();
});

View file

@ -15,6 +15,7 @@ use collab_ui::CollabTitlebarItem; // TODO: Add back toggle collab ui shortcut
use collections::VecDeque;
pub use editor;
use editor::{Editor, MultiBuffer};
use editor_extensions::FollowableEditor;
use anyhow::anyhow;
use feedback::{
@ -195,9 +196,9 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::AppContext) {
});
workspace.add_item(
Box::new(cx.add_view(|cx| {
Editor::for_multibuffer(
FollowableEditor::for_multibuffer(
buffer,
Some(Arc::new(project.clone())),
project.clone(),
cx,
)
})),
@ -250,7 +251,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::AppContext) {
move |_: &NewWindow, cx: &mut AppContext| {
if let Some(app_state) = app_state.upgrade() {
open_new(&app_state, cx, |workspace, cx| {
Editor::new_file(workspace, &Default::default(), cx)
editor_extensions::new_file(workspace, &Default::default(), cx)
})
.detach();
}
@ -261,7 +262,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::AppContext) {
move |_: &NewFile, cx: &mut AppContext| {
if let Some(app_state) = app_state.upgrade() {
open_new(&app_state, cx, |workspace, cx| {
Editor::new_file(workspace, &Default::default(), cx)
editor_extensions::new_file(workspace, &Default::default(), cx)
})
.detach();
}
@ -336,7 +337,7 @@ pub fn initialize_workspace(
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.add_view(|_| editor_extensions::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);
@ -540,7 +541,7 @@ fn open_log_file(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
});
workspace.add_item(
Box::new(cx.add_view(|cx| {
Editor::for_multibuffer(buffer, Some(Arc::new(project)), cx)
FollowableEditor::for_multibuffer(buffer, project, cx)
})),
cx,
);
@ -708,7 +709,7 @@ fn open_telemetry_log_file(workspace: &mut Workspace, cx: &mut ViewContext<Works
MultiBuffer::singleton(buffer, cx).with_title("Telemetry Log".into())
});
workspace.add_item(
Box::new(cx.add_view(|cx| Editor::for_multibuffer(buffer, Some(Arc::new(project)), cx))),
Box::new(cx.add_view(|cx| FollowableEditor::for_multibuffer(buffer, project, cx))),
cx,
);
}).log_err()?;
@ -743,7 +744,7 @@ fn open_bundled_file(
});
workspace.add_item(
Box::new(cx.add_view(|cx| {
Editor::for_multibuffer(buffer, Some(Arc::new(project.clone())), cx)
FollowableEditor::for_multibuffer(buffer, project.clone(), cx)
})),
cx,
);