Skip to content

Commit bde905e

Browse files
committed
version 0.33.0
1 parent bbb87bb commit bde905e

File tree

6 files changed

+92
-56
lines changed

6 files changed

+92
-56
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
*If you're reading this because you try make sense of some new API or a breaking change, you might also be interested in coming to the chat for explanations or guidance.*
22

3+
<a name="v0.33.0"></a>
4+
### v0.33.0 - 2025-05-30
5+
- InputField: select_non_space_around, get_pos, set_cursor_pos, get_mouse_event_pos
6+
37
<a name="v0.32.0"></a>
48
### v0.32.0 - 2025-05-09
59
- update crokey to 1.2

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "termimad"
3-
version = "0.32.0"
3+
version = "0.33.0"
44
authors = ["dystroy <[email protected]>"]
55
repository = "https://github.com/Canop/termimad"
66
description = "Markdown Renderer for the Terminal"

src/views/input_field.rs

Lines changed: 61 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ impl InputField {
247247
wrap_content_fun!(move_current_line_up);
248248
wrap_content_fun!(move_current_line_down);
249249
wrap_content_fun!(select_word_around);
250+
wrap_content_fun!(select_non_space_around);
250251

251252
pub fn page_up(&mut self) -> bool {
252253
if self.content.move_lines_up(self.area.height as usize) {
@@ -372,6 +373,34 @@ impl InputField {
372373
}
373374
}
374375

376+
/// Get the position in the input field from row, column
377+
pub fn get_pos(&self, row: u16, column: u16) -> Option<Pos> {
378+
if self.area.contains(column, row) {
379+
let y = ((row - self.area.top) as usize + self.scroll.y)
380+
.min(self.content.line_count() - 1);
381+
let line = &self.content.lines()[y];
382+
let x = line
383+
.col_to_char_idx((column - self.area.left) as usize + self.scroll.x)
384+
.unwrap_or(line.chars.len());
385+
Some(Pos { x, y })
386+
} else {
387+
None
388+
}
389+
}
390+
391+
/// Set the cursor position in the input field
392+
///
393+
/// The position set may be different to ensure consistency
394+
/// (for example if it's after the end, it will be set back).
395+
pub fn set_cursor_pos(&mut self, pos: Pos) {
396+
self.content.set_cursor_pos(pos);
397+
}
398+
399+
/// Get the position in the input field from a mouse event
400+
pub fn get_mouse_event_pos(&self, mouse_event: MouseEvent) -> Option<Pos> {
401+
self.get_pos(mouse_event.row, mouse_event.column)
402+
}
403+
375404
/// Apply a mouse event
376405
pub fn apply_mouse_event(&mut self, mouse_event: MouseEvent, is_double_click: bool) -> bool {
377406
let MouseEvent {
@@ -380,50 +409,43 @@ impl InputField {
380409
row,
381410
modifiers,
382411
} = mouse_event;
383-
if self.area.contains(column, row) {
384-
if self.focused {
385-
let y = ((row - self.area.top) as usize + self.scroll.y)
386-
.min(self.content.line_count() - 1);
387-
let line = &self.content.lines()[y];
388-
let x = line
389-
.col_to_char_idx((column - self.area.left) as usize + self.scroll.x)
390-
.unwrap_or(line.chars.len());
391-
// We handle the selection click on down, so that it's set at the
392-
// start of drag.
393-
match kind {
394-
MouseEventKind::Down(MouseButton::Left) => {
395-
// FIXME Crossterm doesn't seem to send shift modifier
396-
// with up or down mouse events
397-
if modifiers == KeyModifiers::SHIFT {
398-
self.content.make_selection();
399-
} else {
400-
self.content.unselect();
401-
}
402-
self.content.set_cursor_pos(Pos { x, y });
403-
}
404-
MouseEventKind::Up(MouseButton::Left) if is_double_click => {
405-
self.content.set_cursor_pos(Pos { x, y });
406-
self.content.select_word_around();
407-
}
408-
MouseEventKind::Drag(MouseButton::Left) => {
412+
let Some(Pos { x, y }) = self.get_pos(row, column) else {
413+
return false;
414+
};
415+
if self.focused {
416+
// We handle the selection click on down, so that it's set at the
417+
// start of drag.
418+
match kind {
419+
MouseEventKind::Down(MouseButton::Left) => {
420+
// FIXME Crossterm doesn't seem to send shift modifier
421+
// with up or down mouse events
422+
if modifiers == KeyModifiers::SHIFT {
409423
self.content.make_selection();
410-
self.content.set_cursor_pos(Pos { x, y });
411-
}
412-
MouseEventKind::ScrollDown => {
413-
self.scroll_down();
414-
}
415-
MouseEventKind::ScrollUp => {
416-
self.scroll_up();
424+
} else {
425+
self.content.unselect();
417426
}
418-
_ => {}
427+
self.content.set_cursor_pos(Pos { x, y });
419428
}
420-
} else if matches!(kind, MouseEventKind::Down(MouseButton::Left)) {
421-
self.focused = true;
429+
MouseEventKind::Up(MouseButton::Left) if is_double_click => {
430+
self.content.set_cursor_pos(Pos { x, y });
431+
self.content.select_word_around();
432+
}
433+
MouseEventKind::Drag(MouseButton::Left) => {
434+
self.content.make_selection();
435+
self.content.set_cursor_pos(Pos { x, y });
436+
}
437+
MouseEventKind::ScrollDown => {
438+
self.scroll_down();
439+
}
440+
MouseEventKind::ScrollUp => {
441+
self.scroll_up();
442+
}
443+
_ => {}
422444
}
423-
true
424-
} else {
425-
false
445+
} else if matches!(kind, MouseEventKind::Down(MouseButton::Left)) {
446+
self.focused = true;
426447
}
448+
true
427449
}
428450

429451
/// apply the event to change the state (content, cursor)

src/views/input_field_content.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,25 @@ impl InputFieldContent {
373373
true
374374
}
375375

376+
/// make all the non-space characters around the current pos, if any, the current selection
377+
pub fn select_non_space_around(&mut self) -> bool {
378+
let chars = &self.lines[self.pos.y].chars;
379+
let mut start = self.pos.x;
380+
if start >= chars.len() || !is_non_space_char(chars[start]) {
381+
return false;
382+
}
383+
while start > 0 && is_non_space_char(chars[start - 1]) {
384+
start -= 1;
385+
}
386+
let mut end = self.pos.x;
387+
while end + 1 < chars.len() && is_non_space_char(chars[end + 1]) {
388+
end += 1;
389+
}
390+
self.selection_tail = Some(Pos::new(start, self.pos.y));
391+
self.pos.x = end;
392+
true
393+
}
394+
376395
/// Remove the char at cursor position, if any.
377396
///
378397
/// Cursor position is unchanged
@@ -673,6 +692,9 @@ fn test_char_iterator() {
673692
fn is_word_char(c: char) -> bool {
674693
c.is_alphanumeric() || c == '_'
675694
}
695+
fn is_non_space_char(c: char) -> bool {
696+
!c.is_whitespace()
697+
}
676698

677699
#[cfg(test)]
678700
mod input_content_edit_monoline_tests {

src/views/list_view.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -350,22 +350,14 @@ impl<'t, T> ListView<'t, T> {
350350
/// ensure the last line is visible
351351
pub fn scroll_to_bottom(&mut self) {
352352
let body_height = self.tbody_height() as usize;
353-
self.scroll = if self.displayed_rows_count > body_height {
354-
self.displayed_rows_count - body_height
355-
} else {
356-
0
357-
}
353+
self.scroll = self.displayed_rows_count.saturating_sub(body_height);
358354
}
359355
/// set the scroll amount.
360356
/// lines_count can be negative
361357
pub fn try_scroll_lines(&mut self, lines_count: i32) {
362358
if lines_count < 0 {
363359
let lines_count = -lines_count as usize;
364-
self.scroll = if lines_count >= self.scroll {
365-
0
366-
} else {
367-
self.scroll - lines_count
368-
};
360+
self.scroll = self.scroll.saturating_sub(lines_count);
369361
} else {
370362
self.scroll = (self.scroll + lines_count as usize)
371363
.min(self.displayed_rows_count - self.tbody_height() as usize + 1);
@@ -435,7 +427,7 @@ impl<'t, T> ListView<'t, T> {
435427
}
436428
if let Some(sel) = self.selection {
437429
if sel <= self.scroll {
438-
self.scroll = if sel > 2 { sel - 2 } else { 0 };
430+
self.scroll = sel.saturating_sub(2);
439431
} else if sel + 1 >= self.scroll + tbody_height {
440432
self.scroll = sel - tbody_height + 2;
441433
}

src/views/text_view.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,7 @@ impl<'a, 't> TextView<'a, 't> {
144144
pub fn try_scroll_lines(&mut self, lines_count: i32) {
145145
if lines_count < 0 {
146146
let lines_count = -lines_count as usize;
147-
self.scroll = if lines_count >= self.scroll {
148-
0
149-
} else {
150-
self.scroll - lines_count
151-
};
147+
self.scroll = self.scroll.saturating_sub(lines_count);
152148
} else {
153149
self.set_scroll(self.scroll + lines_count as usize);
154150
}

0 commit comments

Comments
 (0)