@@ -1173,12 +1173,19 @@ impl ConversationView {
&mut self,
index: usize,
inserted_text: Option<&str>,
+ cursor_offset: Option<usize>,
window: &mut Window,
cx: &mut Context<Self>,
) {
if let Some(active) = self.active_thread() {
active.update(cx, |active, cx| {
- active.move_queued_message_to_main_editor(index, inserted_text, window, cx);
+ active.move_queued_message_to_main_editor(
+ index,
+ inserted_text,
+ cursor_offset,
+ window,
+ cx,
+ );
});
}
}
@@ -2192,8 +2199,16 @@ impl ConversationView {
&editor,
window,
move |this, _editor, event, window, cx| match event {
- MessageEditorEvent::InputAttempted(text) => this
- .move_queued_message_to_main_editor(index, Some(text.as_ref()), window, cx),
+ MessageEditorEvent::InputAttempted {
+ text,
+ cursor_offset,
+ } => this.move_queued_message_to_main_editor(
+ index,
+ Some(text.as_ref()),
+ Some(*cursor_offset),
+ window,
+ cx,
+ ),
MessageEditorEvent::LostFocus => {
this.save_queued_message_at_index(index, cx);
}
@@ -6480,7 +6495,7 @@ pub(crate) mod tests {
// Main editor must be empty for this path — it is by default, but
// assert to make the precondition explicit.
assert!(thread.message_editor.read(cx).is_empty(cx));
- thread.move_queued_message_to_main_editor(0, None, window, cx);
+ thread.move_queued_message_to_main_editor(0, None, None, window, cx);
});
cx.run_until_parked();
@@ -6525,7 +6540,7 @@ pub(crate) mod tests {
vec![],
cx,
);
- thread.move_queued_message_to_main_editor(0, None, window, cx);
+ thread.move_queued_message_to_main_editor(0, None, None, window, cx);
});
cx.run_until_parked();
@@ -585,7 +585,7 @@ impl ThreadView {
self.cancel_editing(&Default::default(), window, cx);
}
MessageEditorEvent::LostFocus => {}
- MessageEditorEvent::InputAttempted(_) => {}
+ MessageEditorEvent::InputAttempted { .. } => {}
}
}
@@ -722,7 +722,7 @@ impl ThreadView {
ViewEvent::MessageEditorEvent(_editor, MessageEditorEvent::Cancel) => {
self.cancel_editing(&Default::default(), window, cx);
}
- ViewEvent::MessageEditorEvent(_editor, MessageEditorEvent::InputAttempted(_)) => {}
+ ViewEvent::MessageEditorEvent(_editor, MessageEditorEvent::InputAttempted { .. }) => {}
ViewEvent::OpenDiffLocation {
path,
position,
@@ -1440,6 +1440,7 @@ impl ThreadView {
&mut self,
index: usize,
inserted_text: Option<&str>,
+ cursor_offset: Option<usize>,
window: &mut Window,
cx: &mut Context<Self>,
) -> bool {
@@ -1455,6 +1456,9 @@ impl ThreadView {
if message_editor.read(cx).is_empty(cx) {
message_editor.update(cx, |editor, cx| {
editor.set_message(queued_content, window, cx);
+ if let Some(offset) = cursor_offset {
+ editor.set_cursor_offset(offset, window, cx);
+ }
if let Some(inserted_text) = inserted_text.as_deref() {
editor.insert_text(inserted_text, window, cx);
}
@@ -1463,8 +1467,16 @@ impl ThreadView {
return true;
}
+ // Adjust cursor offset accounting for existing content
+ let existing_len = message_editor.read(cx).text(cx).len();
+ let separator = "\n\n";
+
message_editor.update(cx, |editor, cx| {
- editor.append_message(queued_content, Some("\n\n"), window, cx);
+ editor.append_message(queued_content, Some(separator), window, cx);
+ if let Some(offset) = cursor_offset {
+ let adjusted_offset = existing_len + separator.len() + offset;
+ editor.set_cursor_offset(adjusted_offset, window, cx);
+ }
if let Some(inserted_text) = inserted_text.as_deref() {
editor.insert_text(inserted_text, window, cx);
}
@@ -3038,7 +3050,7 @@ impl ThreadView {
})
.on_click(cx.listener(move |this, _, window, cx| {
this.move_queued_message_to_main_editor(
- index, None, window, cx,
+ index, None, None, window, cx,
);
})),
)
@@ -3112,7 +3124,7 @@ impl ThreadView {
})
.on_click(cx.listener(move |this, _, window, cx| {
this.move_queued_message_to_main_editor(
- index, None, window, cx,
+ index, None, None, window, cx,
);
})),
)
@@ -8169,7 +8181,7 @@ impl Render for ThreadView {
cx.notify();
}))
.on_action(cx.listener(|this, _: &EditFirstQueuedMessage, window, cx| {
- this.move_queued_message_to_main_editor(0, None, window, cx);
+ this.move_queued_message_to_main_editor(0, None, None, window, cx);
}))
.on_action(cx.listener(|this, _: &ClearMessageQueue, _, cx| {
this.local_queued_messages.clear();
@@ -151,7 +151,10 @@ pub enum MessageEditorEvent {
Cancel,
Focus,
LostFocus,
- InputAttempted(Arc<str>),
+ InputAttempted {
+ text: Arc<str>,
+ cursor_offset: usize,
+ },
}
impl EventEmitter<MessageEditorEvent> for MessageEditor {}
@@ -257,7 +260,15 @@ impl MessageEditor {
&& editor.read(cx).read_only(cx)
&& !text.is_empty()
{
- cx.emit(MessageEditorEvent::InputAttempted(text.clone()));
+ let editor = editor.read(cx);
+ let cursor_anchor = editor.selections.newest_anchor().head();
+ let cursor_offset = cursor_anchor
+ .to_offset(&editor.buffer().read(cx).snapshot(cx))
+ .0;
+ cx.emit(MessageEditorEvent::InputAttempted {
+ text: text.clone(),
+ cursor_offset,
+ });
}
if let EditorEvent::Edited { .. } = event
@@ -1580,6 +1591,21 @@ impl MessageEditor {
self.editor.read(cx).text(cx)
}
+ pub fn set_cursor_offset(
+ &mut self,
+ offset: usize,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ self.editor.update(cx, |editor, cx| {
+ let snapshot = editor.buffer().read(cx).snapshot(cx);
+ let offset = snapshot.clip_offset(MultiBufferOffset(offset), text::Bias::Left);
+ editor.change_selections(Default::default(), window, cx, |selections| {
+ selections.select_ranges([offset..offset]);
+ });
+ });
+ }
+
pub fn insert_text(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
if text.is_empty() {
return;