Refine inline transformation UX (#12939)
https://github.com/zed-industries/zed/assets/482957/1790e32e-1f59-4831-8a4c-722cf441e7e9 Release Notes: - N/A --------- Co-authored-by: Richard <richard@zed.dev> Co-authored-by: Nathan <nathan@zed.dev>
This commit is contained in:
co-authored by
Richard
Nathan
parent
9e3c5f3e12
commit
e1f4dfc068
+74
-46
@@ -116,15 +116,16 @@ use serde::{Deserialize, Serialize};
|
||||
use settings::{update_settings_file, Settings, SettingsStore};
|
||||
use smallvec::SmallVec;
|
||||
use snippet::Snippet;
|
||||
use std::ops::Not as _;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
borrow::Cow,
|
||||
cell::RefCell,
|
||||
cmp::{self, Ordering, Reverse},
|
||||
mem,
|
||||
num::NonZeroU32,
|
||||
ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
|
||||
ops::{ControlFlow, Deref, DerefMut, Not as _, Range, RangeInclusive},
|
||||
path::Path,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
@@ -377,6 +378,19 @@ impl Default for EditorStyle {
|
||||
|
||||
type CompletionId = usize;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
|
||||
struct EditorActionId(usize);
|
||||
|
||||
impl EditorActionId {
|
||||
pub fn post_inc(&mut self) -> Self {
|
||||
let answer = self.0;
|
||||
|
||||
*self = Self(answer + 1);
|
||||
|
||||
Self(answer)
|
||||
}
|
||||
}
|
||||
|
||||
// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
|
||||
// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
|
||||
|
||||
@@ -512,7 +526,8 @@ pub struct Editor {
|
||||
gutter_dimensions: GutterDimensions,
|
||||
pub vim_replace_map: HashMap<Range<usize>, String>,
|
||||
style: Option<EditorStyle>,
|
||||
editor_actions: Vec<Box<dyn Fn(&mut ViewContext<Self>)>>,
|
||||
next_editor_action_id: EditorActionId,
|
||||
editor_actions: Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut ViewContext<Self>)>>>>,
|
||||
use_autoclose: bool,
|
||||
auto_replace_emoji_shortcode: bool,
|
||||
show_git_blame_gutter: bool,
|
||||
@@ -1805,7 +1820,8 @@ impl Editor {
|
||||
style: None,
|
||||
show_cursor_names: false,
|
||||
hovered_cursors: Default::default(),
|
||||
editor_actions: Default::default(),
|
||||
next_editor_action_id: EditorActionId::default(),
|
||||
editor_actions: Rc::default(),
|
||||
vim_replace_map: Default::default(),
|
||||
show_inline_completions: mode == EditorMode::Full,
|
||||
custom_context_menu: None,
|
||||
@@ -6448,29 +6464,9 @@ impl Editor {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
|
||||
if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
|
||||
self.change_selections(None, cx, |s| {
|
||||
s.select_anchors(selections.to_vec());
|
||||
});
|
||||
}
|
||||
self.request_autoscroll(Autoscroll::fit(), cx);
|
||||
self.unmark_text(cx);
|
||||
self.refresh_inline_completion(true, cx);
|
||||
cx.emit(EditorEvent::Edited);
|
||||
cx.emit(EditorEvent::TransactionUndone {
|
||||
transaction_id: tx_id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
|
||||
if self.read_only(cx) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
|
||||
if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
|
||||
if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
|
||||
if let Some((selections, _)) =
|
||||
self.selection_history.transaction(transaction_id).cloned()
|
||||
{
|
||||
self.change_selections(None, cx, |s| {
|
||||
s.select_anchors(selections.to_vec());
|
||||
@@ -6479,7 +6475,28 @@ impl Editor {
|
||||
self.request_autoscroll(Autoscroll::fit(), cx);
|
||||
self.unmark_text(cx);
|
||||
self.refresh_inline_completion(true, cx);
|
||||
cx.emit(EditorEvent::Edited);
|
||||
cx.emit(EditorEvent::Edited { transaction_id });
|
||||
cx.emit(EditorEvent::TransactionUndone { transaction_id });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
|
||||
if self.read_only(cx) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
|
||||
if let Some((_, Some(selections))) =
|
||||
self.selection_history.transaction(transaction_id).cloned()
|
||||
{
|
||||
self.change_selections(None, cx, |s| {
|
||||
s.select_anchors(selections.to_vec());
|
||||
});
|
||||
}
|
||||
self.request_autoscroll(Autoscroll::fit(), cx);
|
||||
self.unmark_text(cx);
|
||||
self.refresh_inline_completion(true, cx);
|
||||
cx.emit(EditorEvent::Edited { transaction_id });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9590,18 +9607,20 @@ impl Editor {
|
||||
now: Instant,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<TransactionId> {
|
||||
if let Some(tx_id) = self
|
||||
if let Some(transaction_id) = self
|
||||
.buffer
|
||||
.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
|
||||
{
|
||||
if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
|
||||
if let Some((_, end_selections)) =
|
||||
self.selection_history.transaction_mut(transaction_id)
|
||||
{
|
||||
*end_selections = Some(self.selections.disjoint_anchors());
|
||||
} else {
|
||||
log::error!("unexpectedly ended a transaction that wasn't started by this editor");
|
||||
}
|
||||
|
||||
cx.emit(EditorEvent::Edited);
|
||||
Some(tx_id)
|
||||
cx.emit(EditorEvent::Edited { transaction_id });
|
||||
Some(transaction_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -11293,21 +11312,28 @@ impl Editor {
|
||||
pub fn register_action<A: Action>(
|
||||
&mut self,
|
||||
listener: impl Fn(&A, &mut WindowContext) + 'static,
|
||||
) -> &mut Self {
|
||||
) -> Subscription {
|
||||
let id = self.next_editor_action_id.post_inc();
|
||||
let listener = Arc::new(listener);
|
||||
self.editor_actions.borrow_mut().insert(
|
||||
id,
|
||||
Box::new(move |cx| {
|
||||
let _view = cx.view().clone();
|
||||
let cx = cx.window_context();
|
||||
let listener = listener.clone();
|
||||
cx.on_action(TypeId::of::<A>(), move |action, phase, cx| {
|
||||
let action = action.downcast_ref().unwrap();
|
||||
if phase == DispatchPhase::Bubble {
|
||||
listener(action, cx)
|
||||
}
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
self.editor_actions.push(Box::new(move |cx| {
|
||||
let _view = cx.view().clone();
|
||||
let cx = cx.window_context();
|
||||
let listener = listener.clone();
|
||||
cx.on_action(TypeId::of::<A>(), move |action, phase, cx| {
|
||||
let action = action.downcast_ref().unwrap();
|
||||
if phase == DispatchPhase::Bubble {
|
||||
listener(action, cx)
|
||||
}
|
||||
})
|
||||
}));
|
||||
self
|
||||
let editor_actions = self.editor_actions.clone();
|
||||
Subscription::new(move || {
|
||||
editor_actions.borrow_mut().remove(&id);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn file_header_size(&self) -> u8 {
|
||||
@@ -11764,7 +11790,9 @@ pub enum EditorEvent {
|
||||
ids: Vec<ExcerptId>,
|
||||
},
|
||||
BufferEdited,
|
||||
Edited,
|
||||
Edited {
|
||||
transaction_id: clock::Lamport,
|
||||
},
|
||||
Reparsed,
|
||||
Focused,
|
||||
Blurred,
|
||||
|
||||
Reference in New Issue
Block a user