gardesk/garterm / cc8f526

Browse files

feat: triple-click selects entire logical line including wrapped continuations

Authored by espadonne
SHA
cc8f526d1dcdde6f2906a4f16f0679a04f9bfe1f
Parents
2b684a0
Tree
ad00290

2 changed files

StatusFile+-
M garterm/src/app.rs 1 1
M garterm/src/input/selection.rs 39 4
garterm/src/app.rsmodified
@@ -1518,7 +1518,7 @@ impl App {
15181518
                             self.selection.select_word(abs_row, col, pane.terminal.grid(), pane.terminal.cols());
15191519
                         }
15201520
                         _ => {
1521
-                            self.selection.select_line(abs_row, pane.terminal.cols());
1521
+                            self.selection.select_line(abs_row, pane.terminal.cols(), pane.terminal.grid());
15221522
                         }
15231523
                     }
15241524
                 }
garterm/src/input/selection.rsmodified
@@ -259,10 +259,45 @@ impl Selection {
259259
         self.active = false;
260260
     }
261261
 
262
-    /// Select entire line
263
-    pub fn select_line(&mut self, row: usize, cols: usize) {
264
-        self.start = Some(SelectionPoint::new(row, 0));
265
-        self.end = Some(SelectionPoint::new(row, cols - 1));
262
+    /// Select entire logical line (including wrapped continuations)
263
+    /// Row is absolute (scrollback + active)
264
+    pub fn select_line(&mut self, row: usize, cols: usize, grid: &Grid) {
265
+        // Find the start of the logical line by searching backwards
266
+        // A line is a continuation if the PREVIOUS line has wrapped=true
267
+        let mut start_row = row;
268
+        while start_row > 0 {
269
+            if let Some(prev_line) = grid.line_absolute(start_row - 1) {
270
+                if prev_line.wrapped {
271
+                    // Previous line wraps into this one, keep going back
272
+                    start_row -= 1;
273
+                } else {
274
+                    // Previous line doesn't wrap, we found the start
275
+                    break;
276
+                }
277
+            } else {
278
+                break;
279
+            }
280
+        }
281
+
282
+        // Find the end of the logical line by searching forwards
283
+        // Keep going while the current line has wrapped=true
284
+        let mut end_row = row;
285
+        loop {
286
+            if let Some(line) = grid.line_absolute(end_row) {
287
+                if line.wrapped {
288
+                    // This line wraps to the next, keep going
289
+                    end_row += 1;
290
+                } else {
291
+                    // This line doesn't wrap, we found the end
292
+                    break;
293
+                }
294
+            } else {
295
+                break;
296
+            }
297
+        }
298
+
299
+        self.start = Some(SelectionPoint::new(start_row, 0));
300
+        self.end = Some(SelectionPoint::new(end_row, cols - 1));
266301
         self.mode = SelectionMode::Line;
267302
         self.active = false;
268303
     }