forked from 1b-agent/opencadstudio-upstream
feat(command-line): copy/clear history + selectable log (#232)
The command-line history dropdown was display-only, so users had to screenshot and OCR the log to report output. Make it copyable: - Render the whole backlog in one read-only text_editor so a single mouse drag selects across lines and Ctrl+C copies the span. - Add Copy (whole log to clipboard) and Clear buttons to the dropdown. - Gate the Ctrl+C/X/V accelerators on event Status::Ignored so a focused text widget's copy/cut/paste wins instead of firing COPYCLIP/CUTCLIP; the drawing's clipboard shortcuts still work when it has focus. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
ada9952f06
commit
1e9de924be
6 files changed
+181
-30
No files matched your search
@@ -194,6 +194,10 @@ pub(super) struct OpenCADStudio {
|
||||
ribbon: Ribbon,
|
||||
app_menu: AppMenu,
|
||||
command_line: CommandLine,
|
||||
/// Read-only editor buffer backing the command-line history dropdown, so
|
||||
/// the log can be drag-selected across lines and copied (issue #232).
|
||||
/// Rebuilt from the history each time the dropdown is opened.
|
||||
history_content: iced::widget::text_editor::Content,
|
||||
status_bar: StatusBar,
|
||||
cursor_pos: Point,
|
||||
vp_size: (f32, f32),
|
||||
@@ -1176,6 +1180,16 @@ pub enum Message {
|
||||
CommandHistoryNext,
|
||||
/// Toggle the dropdown listing the full command-line history.
|
||||
CommandHistoryToggle,
|
||||
/// Copy the full command-line history (every line) to the system
|
||||
/// clipboard as plain text — issue #232, so output can be pasted for
|
||||
/// debugging instead of screenshotted.
|
||||
CommandHistoryCopy,
|
||||
/// Clear every line from the command-line history.
|
||||
CommandHistoryClear,
|
||||
/// Text-editor action from the read-only history dropdown. Only
|
||||
/// non-editing actions (cursor moves, selection, scroll) are applied so
|
||||
/// the log stays read-only while remaining drag-selectable and copyable.
|
||||
CommandHistoryEdit(iced::widget::text_editor::Action),
|
||||
/// User clicked an autocomplete suggestion — fill the input with
|
||||
/// the chosen command name and dispatch it.
|
||||
CommandSuggestionPick(String),
|
||||
@@ -1906,6 +1920,7 @@ impl OpenCADStudio {
|
||||
ribbon: Ribbon::new(),
|
||||
app_menu,
|
||||
command_line: CommandLine::new(),
|
||||
history_content: iced::widget::text_editor::Content::new(),
|
||||
status_bar: StatusBar::new(),
|
||||
cursor_pos: Point::ORIGIN,
|
||||
vp_size: (1280.0, 720.0),
|
||||
|
||||
@@ -774,6 +774,41 @@ impl OpenCADStudio {
|
||||
|
||||
Message::CommandHistoryToggle => {
|
||||
self.command_line.toggle_history();
|
||||
// On open, snapshot the current log into the read-only editor
|
||||
// buffer so it can be drag-selected across lines and copied.
|
||||
if self.command_line.history_open {
|
||||
use iced::widget::text_editor::{Action, Motion};
|
||||
self.history_content = iced::widget::text_editor::Content::with_text(
|
||||
&self.command_line.history_plain_text(),
|
||||
);
|
||||
// Scroll to the newest line (bottom), the most useful when
|
||||
// opening the log to grab a recent error.
|
||||
self.history_content.perform(Action::Move(Motion::DocumentEnd));
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::CommandHistoryCopy => {
|
||||
let text = self.command_line.history_plain_text();
|
||||
if text.is_empty() {
|
||||
Task::none()
|
||||
} else {
|
||||
iced::clipboard::write(text)
|
||||
}
|
||||
}
|
||||
|
||||
Message::CommandHistoryClear => {
|
||||
self.command_line.clear_history();
|
||||
self.history_content = iced::widget::text_editor::Content::new();
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::CommandHistoryEdit(action) => {
|
||||
// Read-only: drop edits, keep selection / cursor / scroll so
|
||||
// the user can still highlight and Ctrl+C the log.
|
||||
if !action.is_edit() {
|
||||
self.history_content.perform(action);
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
|
||||
+20
-4
@@ -1105,7 +1105,11 @@ impl OpenCADStudio {
|
||||
|| self.mtext_editor.as_ref().is_some_and(|e| e.show_preview)
|
||||
|| self.text_inline.is_some();
|
||||
let command_line_overlay =
|
||||
iced::widget::container(self.command_line.view(allow_autocomplete, dyn_capturing))
|
||||
iced::widget::container(self.command_line.view(
|
||||
allow_autocomplete,
|
||||
dyn_capturing,
|
||||
&self.history_content,
|
||||
))
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.align_x(iced::alignment::Horizontal::Center)
|
||||
@@ -1583,9 +1587,21 @@ impl OpenCADStudio {
|
||||
"z" if !shift => Some(Message::Undo),
|
||||
"z" if shift => Some(Message::Redo),
|
||||
"y" => Some(Message::Redo),
|
||||
"c" => Some(Message::Command("COPYCLIP".to_string())),
|
||||
"x" => Some(Message::Command("CUTCLIP".to_string())),
|
||||
"v" => Some(Message::PasteShortcut),
|
||||
// Clipboard accelerators defer to a focused
|
||||
// text widget: when the command-line history
|
||||
// editor (or any text field) captures Ctrl+C/
|
||||
// X/V it copies/cuts/pastes its own text and
|
||||
// marks the event Captured, so we must NOT also
|
||||
// fire the drawing's COPYCLIP/CUTCLIP/paste.
|
||||
// Only when nothing captured (the drawing has
|
||||
// focus, status Ignored) do these run. (#232)
|
||||
"c" if status == Status::Ignored => {
|
||||
Some(Message::Command("COPYCLIP".to_string()))
|
||||
}
|
||||
"x" if status == Status::Ignored => {
|
||||
Some(Message::Command("CUTCLIP".to_string()))
|
||||
}
|
||||
"v" if status == Status::Ignored => Some(Message::PasteShortcut),
|
||||
_ => None,
|
||||
},
|
||||
// Printable glyphs are already handled by the
|
||||
|
||||
Reference in new issue
Block a user