git.lucas.co / cce-browser
web browser (Servo)
git clone https://git.lucas.co/cce-browser.git

commit476a3cf21f2391f7f246944abdb8091d181347be
parentc207089815
authorLucas Galante <lsgalante12@gmail.com>
date2026-10-03 04:08
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