mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Apply composer editing preferences to TUI text prompts (#39618)
## What changed - Initialize custom text prompts with the main composer's editor keybindings and Vim setting. - Support Vim mode transitions, operator sequences, cursor styles, keymap contexts, and mode-aware footer hints in these prompts. - Start Vim prompts in insert mode, use the first `Esc` to enter normal mode, and preserve `Esc` cancellation outside Vim. ## Testing - Cover remapped editor and Vim commands, mode and context transitions, paste handling, cancellation, and footer rendering at different widths. GitOrigin-RevId: 7a678310639dafb938084197df23d6d2a080a051
This commit is contained in:
1 parent
bc3545b805
commit
4bb7804a23
10 files changed
+245
-28
No files matched your search
@@ -1344,8 +1344,7 @@ impl ChatComposer {
|
|||||||
enabled
|
enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return whether Vim editing is enabled for tests that assert mode transitions.
|
/// Return whether Vim editing is enabled.
|
||||||
#[cfg(test)]
|
|
||||||
pub(crate) fn is_vim_enabled(&self) -> bool {
|
pub(crate) fn is_vim_enabled(&self) -> bool {
|
||||||
self.draft.textarea.is_vim_enabled()
|
self.draft.textarea.is_vim_enabled()
|
||||||
}
|
}
|
||||||
@@ -1362,14 +1361,7 @@ impl ChatComposer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn vim_mode_indicator_span(&self) -> Option<Span<'static>> {
|
fn vim_mode_indicator_span(&self) -> Option<Span<'static>> {
|
||||||
self.draft
|
self.draft.textarea.vim_mode_indicator_span()
|
||||||
.textarea
|
|
||||||
.vim_mode_label()
|
|
||||||
.map(|label| match label {
|
|
||||||
"Normal" => "Vim: Normal".magenta(),
|
|
||||||
"Insert" => "Vim: Insert".green(),
|
|
||||||
_ => unreachable!(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mode_indicator_line(&self, show_cycle_hint: bool) -> Option<Line<'static>> {
|
fn mode_indicator_line(&self, show_cycle_hint: bool) -> Option<Line<'static>> {
|
||||||
|
|||||||
@@ -13,14 +13,21 @@ use ratatui::widgets::Widget;
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use crate::key_hint;
|
||||||
use crate::key_hint::has_ctrl_or_alt;
|
use crate::key_hint::has_ctrl_or_alt;
|
||||||
|
use crate::keymap::KeymapContextSet;
|
||||||
|
use crate::keymap::RuntimeKeymap;
|
||||||
|
use crate::line_truncation::truncate_line_with_ellipsis_if_overflow;
|
||||||
use crate::render::renderable::Renderable;
|
use crate::render::renderable::Renderable;
|
||||||
|
|
||||||
|
use super::popup_consts::accept_cancel_hint_line;
|
||||||
use super::popup_consts::standard_popup_hint_line;
|
use super::popup_consts::standard_popup_hint_line;
|
||||||
|
|
||||||
use super::CancellationEvent;
|
use super::CancellationEvent;
|
||||||
use super::bottom_pane_view::BottomPaneView;
|
use super::bottom_pane_view::BottomPaneView;
|
||||||
use super::bottom_pane_view::ViewCompletion;
|
use super::bottom_pane_view::ViewCompletion;
|
||||||
|
use super::footer::max_left_width_for_right;
|
||||||
|
use super::footer::render_context_right;
|
||||||
use super::paste_burst::PasteBurst;
|
use super::paste_burst::PasteBurst;
|
||||||
use super::textarea::TextArea;
|
use super::textarea::TextArea;
|
||||||
use super::textarea::TextAreaState;
|
use super::textarea::TextAreaState;
|
||||||
@@ -68,19 +75,42 @@ impl CustomPromptView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Apply the same editor and Vim bindings used by the main composer.
|
||||||
|
pub(crate) fn set_keymap_bindings(&mut self, keymap: &RuntimeKeymap) {
|
||||||
|
self.textarea.set_keymap_bindings(keymap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable Vim editing while keeping the prompt ready for immediate input.
|
||||||
|
pub(crate) fn enable_vim_in_insert_mode(&mut self) {
|
||||||
|
self.textarea.set_vim_enabled(/*enabled*/ true);
|
||||||
|
self.textarea.enter_vim_insert_mode();
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_key_event_at(&mut self, key_event: KeyEvent, now: Instant) {
|
fn handle_key_event_at(&mut self, key_event: KeyEvent, now: Instant) {
|
||||||
|
if self.textarea.is_vim_operator_pending() {
|
||||||
|
self.textarea.input(key_event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
match key_event {
|
match key_event {
|
||||||
KeyEvent {
|
KeyEvent {
|
||||||
code: KeyCode::Esc, ..
|
code: KeyCode::Esc, ..
|
||||||
} => {
|
} => {
|
||||||
self.on_ctrl_c();
|
if self.textarea.should_handle_vim_insert_escape(key_event) {
|
||||||
|
self.textarea.input(key_event);
|
||||||
|
self.paste_burst.clear_after_explicit_paste();
|
||||||
|
} else {
|
||||||
|
self.on_ctrl_c();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
KeyEvent {
|
KeyEvent {
|
||||||
code: KeyCode::Enter,
|
code: KeyCode::Enter,
|
||||||
modifiers,
|
modifiers,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
if self.paste_burst.direct_insert_newline_should_insert(now) {
|
if self.textarea.allows_paste_burst()
|
||||||
|
&& self.paste_burst.direct_insert_newline_should_insert(now)
|
||||||
|
{
|
||||||
self.paste_burst.extend_window(now);
|
self.paste_burst.extend_window(now);
|
||||||
self.textarea.insert_str("\n");
|
self.textarea.insert_str("\n");
|
||||||
return;
|
return;
|
||||||
@@ -126,6 +156,10 @@ impl CustomPromptView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BottomPaneView for CustomPromptView {
|
impl BottomPaneView for CustomPromptView {
|
||||||
|
fn keymap_contexts(&self) -> KeymapContextSet {
|
||||||
|
KeymapContextSet::new(self.textarea.keymap_context())
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_key_event(&mut self, key_event: KeyEvent) {
|
fn handle_key_event(&mut self, key_event: KeyEvent) {
|
||||||
self.handle_key_event_at(key_event, Instant::now());
|
self.handle_key_event_at(key_event, Instant::now());
|
||||||
}
|
}
|
||||||
@@ -135,6 +169,10 @@ impl BottomPaneView for CustomPromptView {
|
|||||||
CancellationEvent::Handled
|
CancellationEvent::Handled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prefer_esc_to_handle_key_event(&self) -> bool {
|
||||||
|
self.textarea.uses_vim_insert_cursor() || self.textarea.is_vim_operator_pending()
|
||||||
|
}
|
||||||
|
|
||||||
fn is_complete(&self) -> bool {
|
fn is_complete(&self) -> bool {
|
||||||
self.completion.is_some()
|
self.completion.is_some()
|
||||||
}
|
}
|
||||||
@@ -253,15 +291,37 @@ impl Renderable for CustomPromptView {
|
|||||||
|
|
||||||
let hint_y = hint_blank_y.saturating_add(1);
|
let hint_y = hint_blank_y.saturating_add(1);
|
||||||
if hint_y < area.y.saturating_add(area.height) {
|
if hint_y < area.y.saturating_add(area.height) {
|
||||||
Paragraph::new(standard_popup_hint_line()).render(
|
let mut hint_line = if self.textarea.uses_vim_insert_cursor() {
|
||||||
Rect {
|
accept_cancel_hint_line(
|
||||||
x: area.x,
|
Some(key_hint::plain(KeyCode::Enter).into()),
|
||||||
y: hint_y,
|
"to confirm",
|
||||||
width: area.width,
|
Some(key_hint::plain(KeyCode::Esc).into()),
|
||||||
height: 1,
|
"to enter normal mode",
|
||||||
},
|
)
|
||||||
buf,
|
} else {
|
||||||
);
|
standard_popup_hint_line()
|
||||||
|
};
|
||||||
|
let hint_area = Rect {
|
||||||
|
x: area.x,
|
||||||
|
y: hint_y,
|
||||||
|
width: area.width,
|
||||||
|
height: 1,
|
||||||
|
};
|
||||||
|
let mut vim_mode = self.textarea.vim_mode_indicator_span().map(Line::from);
|
||||||
|
let available_hint_width = vim_mode
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|line| max_left_width_for_right(hint_area, line.width() as u16))
|
||||||
|
.filter(|width| *width > 0);
|
||||||
|
if vim_mode.is_some() && available_hint_width.is_none() {
|
||||||
|
vim_mode = None;
|
||||||
|
}
|
||||||
|
if let Some(width) = available_hint_width {
|
||||||
|
hint_line = truncate_line_with_ellipsis_if_overflow(hint_line, width as usize);
|
||||||
|
}
|
||||||
|
Paragraph::new(hint_line).render(hint_area, buf);
|
||||||
|
if let Some(line) = vim_mode {
|
||||||
|
render_context_right(hint_area, buf, &line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,6 +344,14 @@ impl Renderable for CustomPromptView {
|
|||||||
let state = *self.textarea_state.borrow();
|
let state = *self.textarea_state.borrow();
|
||||||
self.textarea.cursor_pos_with_state(textarea_rect, state)
|
self.textarea.cursor_pos_with_state(textarea_rect, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cursor_style(&self, _area: Rect) -> crossterm::cursor::SetCursorStyle {
|
||||||
|
if self.textarea.uses_vim_insert_cursor() {
|
||||||
|
crossterm::cursor::SetCursorStyle::SteadyBar
|
||||||
|
} else {
|
||||||
|
crossterm::cursor::SetCursorStyle::DefaultUserShape
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CustomPromptView {
|
impl CustomPromptView {
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::key_hint;
|
||||||
|
use crate::keymap::KeymapContext;
|
||||||
|
use crate::keymap::RuntimeKeymap;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::Receiver;
|
||||||
|
|
||||||
@@ -74,6 +77,139 @@ fn delayed_enter_after_typing_submits() {
|
|||||||
assert!(view.is_complete());
|
assert!(view.is_complete());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn vim_insert_escape_clears_paste_burst_before_enter() {
|
||||||
|
let (mut view, submitted_rx) = custom_prompt_view();
|
||||||
|
let now = Instant::now();
|
||||||
|
view.enable_vim_in_insert_mode();
|
||||||
|
|
||||||
|
for (idx, ch) in "abc".chars().enumerate() {
|
||||||
|
view.handle_key_event_at(KeyEvent::from(KeyCode::Char(ch)), now + elapsed(idx));
|
||||||
|
}
|
||||||
|
view.handle_key_event_at(KeyEvent::from(KeyCode::Esc), now + elapsed(/*ms*/ 3));
|
||||||
|
view.handle_key_event_at(KeyEvent::from(KeyCode::Enter), now + elapsed(/*ms*/ 4));
|
||||||
|
|
||||||
|
assert_eq!(submitted_rx.try_recv(), Ok("abc".to_string()));
|
||||||
|
assert_eq!(view.completion(), Some(ViewCompletion::Accepted));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn vim_prompt_hint_tracks_escape_behavior() {
|
||||||
|
let (mut view, _submitted_rx) = custom_prompt_view();
|
||||||
|
let rendered_hint = |view: &CustomPromptView, width: u16| {
|
||||||
|
let area = Rect::new(0, 0, width, 5);
|
||||||
|
let mut buf = Buffer::empty(area);
|
||||||
|
view.render(area, &mut buf);
|
||||||
|
(0..area.width)
|
||||||
|
.map(|x| buf[(x, area.height - 1)].symbol())
|
||||||
|
.collect::<String>()
|
||||||
|
.trim_end()
|
||||||
|
.to_string()
|
||||||
|
};
|
||||||
|
let vim_color = |view: &CustomPromptView| {
|
||||||
|
let area = Rect::new(0, 0, 80, 5);
|
||||||
|
let mut buf = Buffer::empty(area);
|
||||||
|
view.render(area, &mut buf);
|
||||||
|
buf[(67, 4)].style().fg
|
||||||
|
};
|
||||||
|
|
||||||
|
insta::assert_snapshot!(rendered_hint(&view, /*width*/ 80), @"Press enter to confirm or esc to go back");
|
||||||
|
view.enable_vim_in_insert_mode();
|
||||||
|
insta::assert_snapshot!(rendered_hint(&view, /*width*/ 80), @"Press enter to confirm or esc to enter normal mode Vim: Insert");
|
||||||
|
insta::assert_snapshot!(rendered_hint(&view, /*width*/ 60), @"Press enter to confirm or esc to enter norm… Vim: Insert");
|
||||||
|
insta::assert_snapshot!(rendered_hint(&view, /*width*/ 14), @"Press enter to");
|
||||||
|
assert_eq!(vim_color(&view), Some(ratatui::style::Color::Green));
|
||||||
|
|
||||||
|
view.handle_key_event(KeyEvent::from(KeyCode::Esc));
|
||||||
|
insta::assert_snapshot!(rendered_hint(&view, /*width*/ 80), @"Press enter to confirm or esc to go back Vim: Normal");
|
||||||
|
assert_eq!(vim_color(&view), Some(ratatui::style::Color::Magenta));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn vim_insert_cursor_tracks_mode_and_normal_mode_commands() {
|
||||||
|
let (mut view, _submitted_rx) = custom_prompt_view();
|
||||||
|
let area = Rect::new(0, 0, 80, 10);
|
||||||
|
view.textarea.set_text_clearing_elements("rename");
|
||||||
|
view.textarea.set_cursor("rename".len());
|
||||||
|
let mut config = codex_config::types::TuiKeymap::default();
|
||||||
|
config.editor.move_left = Some(codex_config::types::KeybindingsSpec::One(
|
||||||
|
codex_config::types::KeybindingSpec("f2".to_string()),
|
||||||
|
));
|
||||||
|
let mut keymap = RuntimeKeymap::from_config(&config).expect("valid editor remap");
|
||||||
|
keymap.vim_normal.delete_char = vec![key_hint::plain(KeyCode::F(3))];
|
||||||
|
view.set_keymap_bindings(&keymap);
|
||||||
|
view.handle_key_event(KeyEvent::from(KeyCode::F(2)));
|
||||||
|
assert_eq!(view.textarea.cursor(), "rename".len() - 1);
|
||||||
|
view.textarea.set_cursor("rename".len());
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
view.cursor_style(area),
|
||||||
|
crossterm::cursor::SetCursorStyle::DefaultUserShape
|
||||||
|
));
|
||||||
|
|
||||||
|
view.enable_vim_in_insert_mode();
|
||||||
|
assert!(view.prefer_esc_to_handle_key_event());
|
||||||
|
assert!(view.keymap_contexts().contains(KeymapContext::Editor));
|
||||||
|
assert!(matches!(
|
||||||
|
view.cursor_style(area),
|
||||||
|
crossterm::cursor::SetCursorStyle::SteadyBar
|
||||||
|
));
|
||||||
|
|
||||||
|
view.handle_key_event(KeyEvent::from(KeyCode::Esc));
|
||||||
|
assert!(!view.is_complete());
|
||||||
|
assert!(!view.prefer_esc_to_handle_key_event());
|
||||||
|
assert!(view.keymap_contexts().contains(KeymapContext::VimNormal));
|
||||||
|
assert!(matches!(
|
||||||
|
view.cursor_style(area),
|
||||||
|
crossterm::cursor::SetCursorStyle::DefaultUserShape
|
||||||
|
));
|
||||||
|
|
||||||
|
for key_code in [KeyCode::Enter, KeyCode::Esc] {
|
||||||
|
view.handle_key_event(KeyEvent::from(KeyCode::Char('d')));
|
||||||
|
assert!(view.prefer_esc_to_handle_key_event());
|
||||||
|
assert!(view.keymap_contexts().contains(KeymapContext::VimOperator));
|
||||||
|
view.handle_key_event(KeyEvent::from(key_code));
|
||||||
|
assert!(!view.is_complete());
|
||||||
|
assert!(!view.prefer_esc_to_handle_key_event());
|
||||||
|
assert_eq!(view.textarea.text(), "rename");
|
||||||
|
}
|
||||||
|
|
||||||
|
view.handle_key_event(KeyEvent::from(KeyCode::Char('d')));
|
||||||
|
view.handle_key_event(KeyEvent::from(KeyCode::Char('i')));
|
||||||
|
assert!(
|
||||||
|
view.keymap_contexts()
|
||||||
|
.contains(KeymapContext::VimTextObject)
|
||||||
|
);
|
||||||
|
view.handle_key_event(KeyEvent::from(KeyCode::Esc));
|
||||||
|
|
||||||
|
view.handle_key_event(KeyEvent::from(KeyCode::Char('h')));
|
||||||
|
view.handle_key_event(KeyEvent::from(KeyCode::F(3)));
|
||||||
|
assert_eq!(view.textarea.text(), "renae");
|
||||||
|
|
||||||
|
view.handle_key_event(KeyEvent::from(KeyCode::Char('i')));
|
||||||
|
assert!(matches!(
|
||||||
|
view.cursor_style(area),
|
||||||
|
crossterm::cursor::SetCursorStyle::SteadyBar
|
||||||
|
));
|
||||||
|
view.handle_key_event(KeyEvent::from(KeyCode::Char('m')));
|
||||||
|
assert_eq!(view.textarea.text(), "rename");
|
||||||
|
|
||||||
|
view.handle_key_event(KeyEvent::from(KeyCode::Esc));
|
||||||
|
view.handle_key_event(KeyEvent::from(KeyCode::Esc));
|
||||||
|
assert!(view.is_complete());
|
||||||
|
assert_eq!(view.completion(), Some(ViewCompletion::Cancelled));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn escape_without_vim_cancels_prompt() {
|
||||||
|
let (mut view, _submitted_rx) = custom_prompt_view();
|
||||||
|
|
||||||
|
view.handle_key_event(KeyEvent::from(KeyCode::Esc));
|
||||||
|
|
||||||
|
assert!(view.is_complete());
|
||||||
|
assert_eq!(view.completion(), Some(ViewCompletion::Cancelled));
|
||||||
|
}
|
||||||
|
|
||||||
fn custom_prompt_view() -> (CustomPromptView, Receiver<String>) {
|
fn custom_prompt_view() -> (CustomPromptView, Receiver<String>) {
|
||||||
let (submitted, submitted_rx) = std::sync::mpsc::channel();
|
let (submitted, submitted_rx) = std::sync::mpsc::channel();
|
||||||
let view = CustomPromptView::new(
|
let view = CustomPromptView::new(
|
||||||
|
|||||||
@@ -1380,7 +1380,6 @@ impl BottomPane {
|
|||||||
self.composer.is_empty()
|
self.composer.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub(crate) fn composer_is_vim_enabled(&self) -> bool {
|
pub(crate) fn composer_is_vim_enabled(&self) -> bool {
|
||||||
self.composer.is_vim_enabled()
|
self.composer.is_vim_enabled()
|
||||||
}
|
}
|
||||||
@@ -1455,6 +1454,15 @@ impl BottomPane {
|
|||||||
self.push_view(view);
|
self.push_view(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Show a text prompt with the composer's current editing preferences.
|
||||||
|
pub(crate) fn show_text_prompt(&mut self, mut view: custom_prompt_view::CustomPromptView) {
|
||||||
|
view.set_keymap_bindings(&self.keymap);
|
||||||
|
if self.composer_is_vim_enabled() {
|
||||||
|
view.enable_vim_in_insert_mode();
|
||||||
|
}
|
||||||
|
self.push_view(Box::new(view));
|
||||||
|
}
|
||||||
|
|
||||||
/// Called when the agent requests user approval.
|
/// Called when the agent requests user approval.
|
||||||
pub fn push_approval_request(&mut self, request: ApprovalRequest, features: &Features) {
|
pub fn push_approval_request(&mut self, request: ApprovalRequest, features: &Features) {
|
||||||
let request = if let Some(view) = self.view_stack.last_mut() {
|
let request = if let Some(view) = self.view_stack.last_mut() {
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ use ratatui::buffer::Buffer;
|
|||||||
use ratatui::layout::Rect;
|
use ratatui::layout::Rect;
|
||||||
use ratatui::style::Color;
|
use ratatui::style::Color;
|
||||||
use ratatui::style::Style;
|
use ratatui::style::Style;
|
||||||
|
use ratatui::style::Stylize;
|
||||||
|
use ratatui::text::Span;
|
||||||
use ratatui::widgets::StatefulWidgetRef;
|
use ratatui::widgets::StatefulWidgetRef;
|
||||||
use ratatui::widgets::WidgetRef;
|
use ratatui::widgets::WidgetRef;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
@@ -356,6 +358,7 @@ impl TextArea {
|
|||||||
/// `None` means Vim editing is disabled, so callers should omit the mode
|
/// `None` means Vim editing is disabled, so callers should omit the mode
|
||||||
/// indicator rather than rendering an insert-mode label for normal
|
/// indicator rather than rendering an insert-mode label for normal
|
||||||
/// non-modal editing.
|
/// non-modal editing.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn vim_mode_label(&self) -> Option<&'static str> {
|
pub(crate) fn vim_mode_label(&self) -> Option<&'static str> {
|
||||||
if !self.vim_enabled {
|
if !self.vim_enabled {
|
||||||
return None;
|
return None;
|
||||||
@@ -366,6 +369,17 @@ impl TextArea {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the styled footer indicator for the active Vim editing mode.
|
||||||
|
pub(crate) fn vim_mode_indicator_span(&self) -> Option<Span<'static>> {
|
||||||
|
if !self.vim_enabled {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(match self.vim_mode {
|
||||||
|
VimMode::Normal => "Vim: Normal".magenta(),
|
||||||
|
VimMode::Insert => "Vim: Insert".green(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn text(&self) -> &str {
|
pub fn text(&self) -> &str {
|
||||||
&self.text
|
&self.text
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ impl ChatWidget {
|
|||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
self.bottom_pane.show_view(Box::new(view));
|
self.bottom_pane.show_text_prompt(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn show_resume_paused_goal_prompt(
|
pub(crate) fn show_resume_paused_goal_prompt(
|
||||||
|
|||||||
@@ -357,8 +357,7 @@ impl ChatWidget {
|
|||||||
tx.set_thread_name(name);
|
tx.set_thread_name(name);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
self.bottom_pane.show_text_prompt(view);
|
||||||
self.bottom_pane.show_view(Box::new(view));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn ensure_thread_rename_allowed(&mut self) -> bool {
|
pub(super) fn ensure_thread_rename_allowed(&mut self) -> bool {
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ impl ChatWidget {
|
|||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
self.bottom_pane.show_view(Box::new(view));
|
self.bottom_pane.show_text_prompt(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn open_marketplace_add_loading_popup(&mut self, _source: &str) {
|
pub(crate) fn open_marketplace_add_loading_popup(&mut self, _source: &str) {
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ impl ChatWidget {
|
|||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
self.bottom_pane.show_view(Box::new(view));
|
self.bottom_pane.show_text_prompt(view);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ impl ChatWidget {
|
|||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
self.bottom_pane.show_view(Box::new(view));
|
self.bottom_pane.show_text_prompt(view);
|
||||||
self.request_redraw();
|
self.request_redraw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user