Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose selection_start #81

Merged
merged 3 commits into from
Aug 8, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 31 additions & 3 deletions src/textarea.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1402,7 +1402,7 @@ impl<'a> TextArea<'a> {
self.select_style
}

fn selection_range(&self) -> Option<(Pos, Pos)> {
fn selection_range_(&self) -> Option<(Pos, Pos)> {
let (sr, sc) = self.selection_start?;
let (er, ec) = self.cursor;
let (so, eo) = (self.line_offset(sr, sc), self.line_offset(er, ec));
Expand All @@ -1416,7 +1416,7 @@ impl<'a> TextArea<'a> {
}

fn take_selection_range(&mut self) -> Option<(Pos, Pos)> {
let range = self.selection_range();
let range = self.selection_range_();
self.cancel_selection();
range
}
Expand Down Expand Up @@ -1580,7 +1580,7 @@ impl<'a> TextArea<'a> {
hl.search(matches, self.search.style);
}

if let Some((start, end)) = self.selection_range() {
if let Some((start, end)) = self.selection_range_() {
hl.selection(row, start.row, start.offset, end.row, end.offset);
}

Expand Down Expand Up @@ -2003,6 +2003,34 @@ impl<'a> TextArea<'a> {
self.cursor
}

/// Get the current selection range. A tuple (selection_start, cursor) of 0-base character-wise (row, col)
/// positions. The selection start position will always come first, even when it is ahead of
/// the cursor.
/// ```
/// use tui_textarea::TextArea;
/// use tui_textarea::CursorMove;
///
/// let mut textarea = TextArea::from(["abc"]);
/// assert_eq!(textarea.selection_range(), None);
///
/// textarea.start_selection();
/// assert_eq!(textarea.selection_range(), Some(((0, 0), (0, 0))));
///
/// textarea.move_cursor(CursorMove::Forward);
/// assert_eq!(textarea.selection_range(), Some(((0, 0), (0, 1))));
///
/// textarea.cancel_selection();
/// assert_eq!(textarea.selection_range(), None);
///
/// textarea.start_selection();
/// textarea.move_cursor(CursorMove::Back);
/// assert_eq!(textarea.selection_range(), Some(((0, 1), (0, 0))));
/// ```
pub fn selection_range(&self) -> Option<((usize, usize), (usize, usize))> {
self.selection_start
.map(|selection_start| (selection_start, self.cursor))
}
Copy link
Owner

@rhysd rhysd Aug 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel the following method is a better interface because the word start is a bit confusing when the cursor is before the start position. I think that users want to obtain the range of the selected text rather than a single (row, col) position.

pub fn selection_range(&self) -> Option<((usize, usize), (usize, usize))> {
    // Return (row, col) pair of selection range
}

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that makes sense!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, @rhysd selection_range() conflicts with the private fn which has a different behavior:

tui-textarea/src/textarea.rs

Lines 1433 to 1444 in 93cfabd

fn selection_range(&self) -> Option<(Pos, Pos)> {
let (sr, sc) = self.selection_start?;
let (er, ec) = self.cursor;
let (so, eo) = (self.line_offset(sr, sc), self.line_offset(er, ec));
let s = Pos::new(sr, sc, so);
let e = Pos::new(er, ec, eo);
match (sr, so).cmp(&(er, eo)) {
Ordering::Less => Some((s, e)),
Ordering::Equal => None,
Ordering::Greater => Some((e, s)),
}
}

i guess we could call the public fn something like unordered_selection_range() or selection_range_raw()? although those are a bit unwieldy

Copy link
Owner

@rhysd rhysd Aug 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, please just rename the private method to selection_range_ (or selection_range_impl if clippy gets unhappy). Then I will rename it to more proper name after merging this PR.


/// Set text alignment. When [`Alignment::Center`] or [`Alignment::Right`] is set, line number is automatically
/// disabled because those alignments don't work well with line numbers.
/// ```
Expand Down