web browser (Servo)
git clone https://git.lucas.co/cce-browser.git
feat: undo and redo in the URL bar and dialog fields
Application::undo/redo, which the runner offers the DE's undo/redo
chords (input.kdl; Ctrl+Z / Ctrl+Shift+Z by default) before they become
keys, now step LineEdit's history (cce-ui 823af6f) in whichever field has
the keyboard: a dialog's focused field while one is up, else the URL bar
while focused. With neither, or nothing to undo, they decline, and the
chord goes on as a key -- which is how Ctrl+Z still reaches a page's own
editor.
Checked in a shadow session: "abc def" typed over the URL undoes as
"abc ", "abc", "a", and redoes back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
src/main.rs | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/src/main.rs b/src/main.rs
index f0c1b2d..380fd7c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2444,6 +2444,18 @@ impl BrowserApp {
self.url.select_all();
}
+ /// The line field that has the keyboard, if any: a dialog's focused field
+ /// while one is up (it blocks everything else), else the URL bar while
+ /// it is focused. Undo and redo act on this.
+ fn focused_edit(&mut self) -> Option<&mut cce_ui::widget::LineEdit> {
+ #[cfg(feature = "wpe")]
+ if let Some(m) = self.modal.as_mut() {
+ let i = m.focused;
+ return m.fields.get_mut(i).map(|(_, e)| e);
+ }
+ self.url_focused.then_some(&mut self.url)
+ }
+
/// URL-bar keys. Editing is the shared [`cce_ui::widget::LineEdit`]; only what
@@ -2778,6 +2790,24 @@ impl Application for BrowserApp {
}
}
+ /// The DE's undo chord (`input.kdl`, Ctrl+Z by default), offered here by
+ /// the runner before it becomes a key: it undoes typing in whichever
+ /// field has the keyboard — a dialog's focused field, else the URL bar.
+ /// With neither, or nothing to undo, false lets the chord go on as a key,
+ /// which is how Ctrl+Z still reaches a web page's own editor.
+ fn undo(&mut self, needs_rebuild: &mut bool) -> bool {
+ let done = self.focused_edit().is_some_and(|e| e.undo());
+ *needs_rebuild |= done;
+ done
+ }
+
+ /// Redo — see [`undo`](Self::undo).
+ fn redo(&mut self, needs_rebuild: &mut bool) -> bool {
+ let done = self.focused_edit().is_some_and(|e| e.redo());
+ *needs_rebuild |= done;
+ done
+ }
+
fn tick(&mut self, dt: f32, needs_rebuild: &mut bool) {
// The page's wheel glide, one frame's worth. It feeds the engine, so
// the frame it produces is what actually redraws; asking for a