Skip to content

Commit 396c111

Browse files
Eli Belashclaude
andcommitted
Add line number click selection feature
Click on line numbers in the left margin to select entire lines: - Single click: selects the entire line - Shift+click: extends selection to clicked line - Click and drag: select multiple lines Based on PR microsoft#622 by jenia90 (microsoft#622) Also adds additional dialog logging coverage (log_dialog_open/close). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 3f95547 commit 396c111

File tree

8 files changed

+71
-1
lines changed

8 files changed

+71
-1
lines changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ OGEdit aims to deliver more features faster with less bureaucracy.
88

99
- [Key Features](#features)
1010
- [Selection Auto-Highlight](#selection-auto-highlight)
11+
- [Line Number Click Selection](#line-number-click-selection)
1112
- [Ctrl+D Duplicate Line](#ctrld-duplicate-line)
1213
- [File Watcher](#file-watcher)
1314
- [F5 Reload from Disk](#f5-reload-from-disk)
@@ -43,6 +44,18 @@ When you select text, all identical occurrences in the document are highlighted
4344

4445
**Performance:** Limited to 1000 matches to maintain responsiveness in large files.
4546

47+
### Line Number Click Selection
48+
49+
Click on line numbers in the left margin to quickly select entire lines:
50+
51+
- **Single click**: Selects the entire line
52+
- **Shift+click**: Extends selection from current position to the clicked line
53+
- **Click and drag**: Select multiple lines by dragging across line numbers
54+
55+
This feature only works when line numbers are visible (enabled by default, configurable via `line_numbers` setting).
56+
57+
*Based on [PR #622](https://github.com/microsoft/edit/pull/622) by [jenia90](https://github.com/jenia90).*
58+
4659
### Ctrl+D Duplicate Line
4760

4861
Duplicate the current line or selection with `Ctrl+D`. Also available via **Edit → Duplicate** menu (accelerator key: `D`).

src/bin/edit/draw_editor.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ pub fn draw_goto_menu(ctx: &mut Context, state: &mut State) {
488488
match validate_goto_point(&state.goto_target) {
489489
Ok(point) => {
490490
logging::log_goto(point);
491+
logging::log_dialog_close("Go to Line", &format!("Ln {}", point.y + 1));
491492
let mut buf = doc.buffer.borrow_mut();
492493
buf.cursor_move_to_logical(point);
493494
buf.make_cursor_visible();

src/bin/edit/draw_filepicker.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ pub fn draw_file_picker(ctx: &mut Context, state: &mut State) {
223223
&& let Some(path) = doit.as_deref()
224224
&& path.exists()
225225
{
226+
logging::log_dialog_open("Overwrite Warning");
226227
state.file_picker_overwrite_warning = doit.take();
227228
}
228229
}
@@ -258,6 +259,7 @@ pub fn draw_file_picker(ctx: &mut Context, state: &mut State) {
258259
ctx.inherit_focus();
259260

260261
if ctx.button("no", loc(LocId::No), ButtonStyle::default()) {
262+
logging::log_dialog_close("Overwrite Warning", "No");
261263
state.file_picker_overwrite_warning = None;
262264
}
263265
}
@@ -296,12 +298,14 @@ pub fn draw_file_picker(ctx: &mut Context, state: &mut State) {
296298
Ok(..) => {
297299
if is_open {
298300
logging::log_file_open(&path_str);
301+
logging::log_dialog_close("File Picker", "file opened");
299302
// Track in recent files
300303
state.config.add_recent_file(&path);
301304
// Start watching for external modifications
302305
state.file_watcher.watch(&path);
303306
} else {
304307
logging::log_file_save(&path_str);
308+
logging::log_dialog_close("File Picker", "file saved");
305309
// Save the parent directory as the last-used save folder for this project
306310
if let Some(parent) = path.parent() {
307311
let parent_str = parent.to_string_lossy().to_string();

src/bin/edit/draw_menubar.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub fn draw_menubar(ctx: &mut Context, state: &mut State) {
2323
draw_menu_file(ctx, state);
2424
}
2525
if !contains_focus && ctx.consume_shortcut(vk::F10) {
26+
logging::log_action("SHORTCUT: F10 -> Activate menubar");
2627
ctx.steal_focus();
2728
}
2829
if state.documents.active().is_some() {

src/bin/edit/draw_statusbar.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,23 @@ pub fn draw_statusbar(ctx: &mut Context, state: &mut State) {
6363
{
6464
if ctx.button("reopen", loc(LocId::EncodingReopen), ButtonStyle::default()) {
6565
logging::log_action("ENCODING_METHOD: Reopen");
66+
logging::log_dialog_close("Encoding Picker", "Reopen");
67+
logging::log_dialog_open("Encoding Change");
6668
state.wants_encoding_change = StateEncodingChange::Reopen;
6769
}
6870
ctx.focus_on_first_present();
6971
if ctx.button("convert", loc(LocId::EncodingConvert), ButtonStyle::default()) {
7072
logging::log_action("ENCODING_METHOD: Convert");
73+
logging::log_dialog_close("Encoding Picker", "Convert");
74+
logging::log_dialog_open("Encoding Change");
7175
state.wants_encoding_change = StateEncodingChange::Convert;
7276
}
7377
}
7478
ctx.block_end();
7579
} else {
7680
// Can't reopen a file that doesn't exist.
81+
logging::log_dialog_close("Encoding Picker", "Convert (no file)");
82+
logging::log_dialog_open("Encoding Change");
7783
state.wants_encoding_change = StateEncodingChange::Convert;
7884
}
7985

@@ -306,6 +312,7 @@ pub fn draw_dialog_encoding_change(ctx: &mut Context, state: &mut State) {
306312
if let Some(encoding) = change
307313
&& let Some(doc) = state.documents.active_mut()
308314
{
315+
logging::log_dialog_close("Encoding Change", encoding);
309316
let old_encoding = doc.buffer.borrow().encoding();
310317
logging::log_encoding_change(old_encoding, encoding);
311318

@@ -390,6 +397,7 @@ pub fn draw_go_to_file(ctx: &mut Context, state: &mut State) {
390397
let activated = ctx.styled_list_item_end(false) == ListSelection::Activated;
391398
if activated {
392399
logging::log_action(&format!("SWITCH_DOCUMENT: {}", doc.filename));
400+
logging::log_dialog_close("Go to File", "document selected");
393401
}
394402
activated
395403
}) {
@@ -421,6 +429,7 @@ pub fn draw_go_to_file(ctx: &mut Context, state: &mut State) {
421429
state.config.add_recent_file(&path);
422430
// Start watching for external modifications
423431
state.file_watcher.watch(&path);
432+
logging::log_dialog_close("Go to File", "recent file opened");
424433
state.wants_go_to_file = false;
425434
ctx.needs_rerender();
426435
}

src/bin/edit/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,23 +619,27 @@ fn draw_handle_clipboard_change(ctx: &mut Context, state: &mut State) {
619619

620620
if over_limit {
621621
if ctx.button("ok", loc(LocId::Ok), ButtonStyle::default()) {
622+
logging::log_dialog_close("Large Clipboard Warning", "Ok");
622623
done = Some(true);
623624
}
624625
ctx.inherit_focus();
625626
} else {
626627
if ctx.button("always", loc(LocId::Always), ButtonStyle::default()) {
628+
logging::log_dialog_close("Large Clipboard Warning", "Always");
627629
state.osc_clipboard_always_send = true;
628630
done = Some(true);
629631
}
630632

631633
if ctx.button("yes", loc(LocId::Yes), ButtonStyle::default()) {
634+
logging::log_dialog_close("Large Clipboard Warning", "Yes");
632635
done = Some(true);
633636
}
634637
if data_len < 10 * LARGE_CLIPBOARD_THRESHOLD {
635638
ctx.inherit_focus();
636639
}
637640

638641
if ctx.button("no", loc(LocId::No), ButtonStyle::default()) {
642+
logging::log_dialog_close("Large Clipboard Warning", "No");
639643
done = Some(false);
640644
}
641645
if data_len >= 10 * LARGE_CLIPBOARD_THRESHOLD {
@@ -646,6 +650,7 @@ fn draw_handle_clipboard_change(ctx: &mut Context, state: &mut State) {
646650
ctx.table_end();
647651
}
648652
if ctx.modal_end() {
653+
logging::log_dialog_close("Large Clipboard Warning", "Escape");
649654
done = Some(false);
650655
}
651656

src/bin/edit/state.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,8 @@ pub fn draw_add_untitled_document(ctx: &mut Context, state: &mut State) {
322322
pub fn error_log_add(ctx: &mut Context, state: &mut State, err: apperr::Error) {
323323
let msg = format!("{}", FormatApperr::from(err));
324324
if !msg.is_empty() {
325+
logging::log_error(&msg);
326+
logging::log_dialog_open("Error");
325327
state.error_log[state.error_log_index] = msg;
326328
state.error_log_index = (state.error_log_index + 1) % state.error_log.len();
327329
state.error_log_count = state.error_log.len().min(state.error_log_count + 1);
@@ -353,12 +355,14 @@ pub fn draw_error_log(ctx: &mut Context, state: &mut State) {
353355
ctx.block_end();
354356

355357
if ctx.button("ok", loc(LocId::Ok), ButtonStyle::default()) {
358+
logging::log_dialog_close("Error", "Ok");
356359
state.error_log_count = 0;
357360
}
358361
ctx.attr_position(Position::Center);
359362
ctx.inherit_focus();
360363
}
361364
if ctx.modal_end() {
365+
logging::log_dialog_close("Error", "Escape");
362366
state.error_log_count = 0;
363367
}
364368
}

src/tui.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2230,7 +2230,40 @@ impl<'a> Context<'a, '_> {
22302230
y: mouse.y - inner.top + tc.scroll_offset.y,
22312231
};
22322232

2233-
if text_rect.contains(self.tui.mouse_down_position) {
2233+
// Margin/gutter area for line number clicks
2234+
// Credit: jenia90 (https://github.com/microsoft/edit/pull/622)
2235+
let margin_rect = Rect {
2236+
left: inner.left,
2237+
top: inner.top,
2238+
right: inner.left + tb.margin_width(),
2239+
bottom: inner.bottom,
2240+
};
2241+
2242+
if margin_rect.contains(self.tui.mouse_down_position) && tb.margin_width() > 0 {
2243+
// Clicking in the margin (line numbers) selects entire lines
2244+
if self.tui.mouse_is_drag {
2245+
// Dragging across line numbers extends selection
2246+
if !tb.has_selection() {
2247+
tb.start_selection();
2248+
}
2249+
tb.selection_update_visual(Point { x: CoordType::MAX, y: pos.y });
2250+
tc.preferred_column = tb.cursor_visual_pos().x;
2251+
} else if self.tui.mouse_state == InputMouseState::Left {
2252+
// Single click on line number
2253+
if self.input_mouse_modifiers.contains(kbmod::SHIFT) {
2254+
// Shift+click extends selection to this line
2255+
tb.selection_update_visual(Point { x: CoordType::MAX, y: pos.y });
2256+
} else {
2257+
// Regular click selects the entire line
2258+
tb.cursor_move_to_visual(Point { x: 0, y: pos.y });
2259+
tb.select_line();
2260+
}
2261+
tc.preferred_column = tb.cursor_visual_pos().x;
2262+
}
2263+
make_cursor_visible = true;
2264+
self.set_input_consumed();
2265+
return make_cursor_visible;
2266+
} else if text_rect.contains(self.tui.mouse_down_position) {
22342267
if self.tui.mouse_is_drag {
22352268
tb.selection_update_visual(pos);
22362269
tc.preferred_column = tb.cursor_visual_pos().x;

0 commit comments

Comments
 (0)