From 0827ef5afd4a8353ec80af19375d12b9c6846fb8 Mon Sep 17 00:00:00 2001 From: robert Date: Sat, 13 Jun 2026 01:10:49 -0400 Subject: [PATCH 1/3] Highlight multiple words when double clicking in mcedit. This is an improvement to double clicking in the editor, allowing the user to select multiple words by dragging the mouse. Previously, the user could only select one word at a time by double clicking. Signed-off-by: Robert P. McDowell --- lib/tty/key.c | 1 + src/editor/edit.c | 102 +++++++++++++++++++++++++--------------- src/editor/editwidget.c | 19 +++----- src/editor/editwidget.h | 1 + 4 files changed, 73 insertions(+), 50 deletions(-) diff --git a/lib/tty/key.c b/lib/tty/key.c index 68cae9bd90..d605b76f6b 100644 --- a/lib/tty/key.c +++ b/lib/tty/key.c @@ -876,6 +876,7 @@ xmouse_get_event (Gpm_Event *ev, gboolean extended) ev->buttons = 0; break; } + ev->type |= (GPM_SINGLE << clicks); last_btn = ev->buttons; } } diff --git a/src/editor/edit.c b/src/editor/edit.c index 360c347476..37835a61bd 100644 --- a/src/editor/edit.c +++ b/src/editor/edit.c @@ -932,6 +932,41 @@ my_type_of (int c) return r; } +/* --------------------------------------------------------------------------------------------- */ +/** get word at cursor for marking */ + +static void +edit_get_current_word_extents (WEdit *edit, off_t *start, off_t *end) +{ + long pos; + + for (pos = edit->buffer.curs1; pos < edit->buffer.size; pos++) + { + const int check_char = edit_buffer_get_byte (&edit->buffer, pos); + + if (is_break_char (check_char)) + { + if (pos == edit->buffer.curs1) // always select at least one character. + { + *start = pos; + *end = pos+1; + return; + } + break; + } + } + *end = pos; + + for (; pos != 0; pos--) + { + const int check_char = edit_buffer_get_byte (&edit->buffer, pos - 1); + + if (is_break_char (check_char)) + break; + } + *start = pos; +} + /* --------------------------------------------------------------------------------------------- */ static void @@ -3078,8 +3113,8 @@ edit_set_markers (WEdit *edit, off_t m1, off_t m2, long c1, long c2) /* --------------------------------------------------------------------------------------------- */ /** - if mark2 is -1 then marking is from mark1 to the cursor. - Otherwise its between the markers. This handles this. + if mark2 is -1 then marking is from mark1 to end_mark_curs (the cursor). + This also handles the logic for word/line highlighting. Returns FALSE if no text is marked. */ @@ -3107,8 +3142,20 @@ eval_marks (WEdit *edit, off_t *start_mark, off_t *end_mark) } else { - *start_mark = MIN (edit->mark1, end_mark_curs); - *end_mark = MAX (edit->mark1, end_mark_curs); + if (edit->word_highlight) + { + off_t word_start; + off_t word_end; + + edit_get_current_word_extents (edit, &word_start, &word_end); + *start_mark = MIN (edit->mark1, word_start); + *end_mark = MAX (end_mark_curs, word_end); + } + else + { + *start_mark = MIN (edit->mark1, end_mark_curs); + *end_mark = MAX (edit->mark1, end_mark_curs); + } edit->column2 = edit->curs_col + edit->over_col; } @@ -3154,18 +3201,25 @@ edit_mark_cmd (WEdit *edit, gboolean unmark) edit_set_markers (edit, 0, 0, 0, 0); edit->force |= REDRAW_PAGE; } - else if (edit->mark2 >= 0) + else if (edit->mark2 >= 0) // mark highlighting just started. { + off_t m1 = edit->buffer.curs1; + edit->end_mark_curs = -1; - edit_set_markers (edit, edit->buffer.curs1, -1, edit->curs_col + edit->over_col, + if (edit->word_highlight) + edit_get_current_word_extents (edit, &m1, &edit->end_mark_curs); + edit_set_markers (edit, m1, -1, edit->curs_col + edit->over_col, edit->curs_col + edit->over_col); edit->force |= REDRAW_PAGE; } - else + else // mark highlighting just ended. { - edit->end_mark_curs = edit->buffer.curs1; - edit_set_markers (edit, edit->mark1, edit->buffer.curs1, edit->column1, - edit->curs_col + edit->over_col); + off_t m1; + off_t m2; + + eval_marks (edit, &m1, &m2); + edit->end_mark_curs = m2; + edit_set_markers (edit, m1, m2, edit->column1, edit->curs_col + edit->over_col); } } @@ -3175,33 +3229,7 @@ edit_mark_cmd (WEdit *edit, gboolean unmark) void edit_mark_current_word_cmd (WEdit *edit) { - long pos; - - for (pos = edit->buffer.curs1; pos != 0; pos--) - { - int c1, c2; - - c1 = edit_buffer_get_byte (&edit->buffer, pos); - c2 = edit_buffer_get_byte (&edit->buffer, pos - 1); - if (!isspace (c1) && isspace (c2)) - break; - if ((my_type_of (c1) & my_type_of (c2)) == 0) - break; - } - edit->mark1 = pos; - - for (; pos < edit->buffer.size; pos++) - { - int c1, c2; - - c1 = edit_buffer_get_byte (&edit->buffer, pos); - c2 = edit_buffer_get_byte (&edit->buffer, pos + 1); - if (!isspace (c1) && isspace (c2)) - break; - if ((my_type_of (c1) & my_type_of (c2)) == 0) - break; - } - edit->mark2 = MIN (pos + 1, edit->buffer.size); + edit_get_current_word_extents (edit, &edit->mark1, &edit->mark2); edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR; } diff --git a/src/editor/editwidget.c b/src/editor/editwidget.c index e905f0f447..9bb0005798 100644 --- a/src/editor/editwidget.c +++ b/src/editor/editwidget.c @@ -1103,6 +1103,8 @@ edit_mouse_callback (Widget *w, mouse_msg_t msg, mouse_event_t *event) widget_select (w); edit_update_curs_row (edit); edit_update_curs_col (edit); + if (event->count == GPM_DOUBLE) + edit->word_highlight = TRUE; if (edit->fullscreen == 0) { @@ -1131,11 +1133,14 @@ edit_mouse_callback (Widget *w, mouse_msg_t msg, mouse_event_t *event) } } - MC_FALLTHROUGH; // to start/stop text selection + edit_update_cursor (edit, event); + edit_total_update (edit); + break; case MSG_MOUSE_UP: edit_update_cursor (edit, event); edit_total_update (edit); + edit->word_highlight = FALSE; break; case MSG_MOUSE_CLICK: @@ -1149,18 +1154,6 @@ edit_mouse_callback (Widget *w, mouse_msg_t msg, mouse_event_t *event) // double click on top line (toggle fullscreen) edit_toggle_fullscreen (edit); } - else if (event->count == GPM_DOUBLE) - { - // double click - edit_mark_current_word_cmd (edit); - edit_total_update (edit); - } - else if (event->count == GPM_TRIPLE) - { - // triple click: works in GPM only, not in xterm - edit_mark_current_line_cmd (edit); - edit_total_update (edit); - } break; case MSG_MOUSE_DRAG: diff --git a/src/editor/editwidget.h b/src/editor/editwidget.h index c8569cfb35..23eefbcbbd 100644 --- a/src/editor/editwidget.h +++ b/src/editor/editwidget.h @@ -99,6 +99,7 @@ struct WEdit unsigned int delete_file : 1; // New file, needs to be deleted unless modified unsigned int highlight : 1; // There is a selected block unsigned int column_highlight : 1; + unsigned int word_highlight : 1; unsigned int fullscreen : 1; // Is window fullscreen or not long prev_col; /* recent column position of the cursor - used when moving up or down past lines that are shorter than the current line */ From d2e52bac0ffd2780bdcdc48f8c5d4aa61d67e2b5 Mon Sep 17 00:00:00 2001 From: robert Date: Sun, 14 Jun 2026 05:53:28 -0400 Subject: [PATCH 2/3] Highlight multiple lines when triple clicking in mcedit. Improves triple clicking in the editor, allowing the user to select multiple lines after a triple-click by dragging the mouse. Previously, the user could only select one line at a time after triple clicking. Signed-off-by: Robert P. McDowell --- lib/tty/key.c | 1 - src/editor/edit.c | 10 ++++++++++ src/editor/editwidget.c | 4 ++++ src/editor/editwidget.h | 11 ++++++----- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/tty/key.c b/lib/tty/key.c index d605b76f6b..dccfd16d44 100644 --- a/lib/tty/key.c +++ b/lib/tty/key.c @@ -822,7 +822,6 @@ xmouse_get_event (Gpm_Event *ev, gboolean extended) } ev->buttons = 0; last_btn = 0; - clicks = 0; } else { diff --git a/src/editor/edit.c b/src/editor/edit.c index 37835a61bd..87583d6866 100644 --- a/src/editor/edit.c +++ b/src/editor/edit.c @@ -3151,6 +3151,11 @@ eval_marks (WEdit *edit, off_t *start_mark, off_t *end_mark) *start_mark = MIN (edit->mark1, word_start); *end_mark = MAX (end_mark_curs, word_end); } + else if (edit->line_highlight) + { + *start_mark = MIN (edit->mark1, edit_buffer_get_current_bol (&edit->buffer)); + *end_mark = MAX (end_mark_curs, edit_buffer_get_current_eol (&edit->buffer)); + } else { *start_mark = MIN (edit->mark1, end_mark_curs); @@ -3208,6 +3213,11 @@ edit_mark_cmd (WEdit *edit, gboolean unmark) edit->end_mark_curs = -1; if (edit->word_highlight) edit_get_current_word_extents (edit, &m1, &edit->end_mark_curs); + else if (edit->line_highlight) + { + m1 = edit_buffer_get_current_bol (&edit->buffer); + edit->end_mark_curs = edit_buffer_get_current_eol (&edit->buffer); + } edit_set_markers (edit, m1, -1, edit->curs_col + edit->over_col, edit->curs_col + edit->over_col); edit->force |= REDRAW_PAGE; diff --git a/src/editor/editwidget.c b/src/editor/editwidget.c index 9bb0005798..18fcd3e326 100644 --- a/src/editor/editwidget.c +++ b/src/editor/editwidget.c @@ -1103,8 +1103,11 @@ edit_mouse_callback (Widget *w, mouse_msg_t msg, mouse_event_t *event) widget_select (w); edit_update_curs_row (edit); edit_update_curs_col (edit); + if (event->count == GPM_DOUBLE) edit->word_highlight = TRUE; + else if (event->count == GPM_TRIPLE) + edit->line_highlight = TRUE; if (edit->fullscreen == 0) { @@ -1141,6 +1144,7 @@ edit_mouse_callback (Widget *w, mouse_msg_t msg, mouse_event_t *event) edit_update_cursor (edit, event); edit_total_update (edit); edit->word_highlight = FALSE; + edit->line_highlight = FALSE; break; case MSG_MOUSE_CLICK: diff --git a/src/editor/editwidget.h b/src/editor/editwidget.h index 23eefbcbbd..38c948aee5 100644 --- a/src/editor/editwidget.h +++ b/src/editor/editwidget.h @@ -99,11 +99,12 @@ struct WEdit unsigned int delete_file : 1; // New file, needs to be deleted unless modified unsigned int highlight : 1; // There is a selected block unsigned int column_highlight : 1; - unsigned int word_highlight : 1; - unsigned int fullscreen : 1; // Is window fullscreen or not - long prev_col; /* recent column position of the cursor - used when moving - up or down past lines that are shorter than the current line */ - long start_line; // line number of the top of the page + unsigned int word_highlight : 1; // Highlight each word the cursor crosses + unsigned int line_highlight : 1; // Highlight each line the cursor crosses + unsigned int fullscreen : 1; // Is window fullscreen or not + long prev_col; /* recent column position of the cursor - used when moving + up or down past lines that are shorter than the current line */ + long start_line; // line number of the top of the page // file info off_t mark1; // position of highlight start From 857c485ffd22f08b5b1c8b64c15b8864028ca2a9 Mon Sep 17 00:00:00 2001 From: "Robert P. McDowell" Date: Sun, 14 Jun 2026 14:05:40 -0400 Subject: [PATCH 3/3] Multi click timer starts on button down, instead of up. This is to compliment the last two commits. Before if the user dragged their mouse and tried to immediately click, they might unintentionally initiate a double click; after triple clicking was re-implemented it was a noticabely bigger issue, with accidental triple clicks. Fix it by starting the click timer on an earlier input. Signed-off-by: Robert P. McDowell --- lib/tty/key.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/tty/key.c b/lib/tty/key.c index dccfd16d44..0c679f6024 100644 --- a/lib/tty/key.c +++ b/lib/tty/key.c @@ -818,7 +818,6 @@ xmouse_get_event (Gpm_Event *ev, gboolean extended) else { ev->type = GPM_UP | (GPM_SINGLE << clicks); - tv1 = g_get_monotonic_time (); } ev->buttons = 0; last_btn = 0; @@ -833,14 +832,6 @@ xmouse_get_event (Gpm_Event *ev, gboolean extended) { gint64 tv2; - if (btn >= 32 && btn <= 34) - { - btn -= 32; - ev->type = GPM_DRAG; - } - else - ev->type = GPM_DOWN; - tv2 = g_get_monotonic_time (); if (tv1 != 0 && tv2 - tv1 < (gint64) double_click_speed * MC_USEC_PER_MSEC) { @@ -850,6 +841,17 @@ xmouse_get_event (Gpm_Event *ev, gboolean extended) else clicks = 0; + if (btn >= 32 && btn <= 34) + { + btn -= 32; + ev->type = GPM_DRAG; + } + else + { + ev->type = GPM_DOWN; + tv1 = g_get_monotonic_time (); + } + switch (btn) { case 0: