Extract the selected text using a callback that returns the full line content for a given row number.
(&self, get_line: F)
| 110 | /// Extract the selected text using a callback that returns the full line |
| 111 | /// content for a given row number. |
| 112 | pub fn get_selected_text<F>(&self, get_line: F) -> String |
| 113 | where |
| 114 | F: Fn(u16) -> Option<String>, |
| 115 | { |
| 116 | let ((r0, c0), (r1, c1)) = match self.range() { |
| 117 | Some(r) => r, |
| 118 | None => return String::new(), |
| 119 | }; |
| 120 | |
| 121 | let mut result = String::new(); |
| 122 | |
| 123 | for row in r0..=r1 { |
| 124 | let line = match get_line(row) { |
| 125 | Some(l) => l, |
| 126 | None => continue, |
| 127 | }; |
| 128 | |
| 129 | let selected = if r0 == r1 { |
| 130 | // Single line: clip both ends |
| 131 | slice_by_columns(&line, c0 as usize, c1.saturating_add(1) as usize) |
| 132 | } else if row == r0 { |
| 133 | // First row: from col to end |
| 134 | slice_from_column(&line, c0 as usize) |
| 135 | } else if row == r1 { |
| 136 | // Last row: from start to col |
| 137 | slice_to_column(&line, c1.saturating_add(1) as usize) |
| 138 | } else { |
| 139 | // Middle row: full line |
| 140 | line |
| 141 | }; |
| 142 | |
| 143 | if !result.is_empty() { |
| 144 | result.push('\n'); |
| 145 | } |
| 146 | result.push_str(selected.trim_end()); |
| 147 | } |
| 148 | |
| 149 | result |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | fn slice_by_columns(line: &str, start_col: usize, end_col_exclusive: usize) -> String { |