e fixed
This commit is contained in:
@@ -319,11 +319,20 @@ async fn execute_edit_action<S: CanvasState>(
|
|||||||
"move_word_end" => {
|
"move_word_end" => {
|
||||||
let current_input = state.get_current_input();
|
let current_input = state.get_current_input();
|
||||||
if !current_input.is_empty() {
|
if !current_input.is_empty() {
|
||||||
let new_pos =
|
let current_pos = state.current_cursor_pos();
|
||||||
find_word_end(current_input, state.current_cursor_pos());
|
let new_pos = find_word_end(current_input, current_pos);
|
||||||
let final_pos = new_pos.min(current_input.len());
|
|
||||||
state.set_current_cursor_pos(final_pos);
|
// If already at word end, jump to next word's end
|
||||||
*ideal_cursor_column = final_pos;
|
let final_pos = if new_pos == current_pos {
|
||||||
|
find_word_end(current_input, new_pos + 1)
|
||||||
|
} else {
|
||||||
|
new_pos
|
||||||
|
};
|
||||||
|
|
||||||
|
let max_valid_index = current_input.len().saturating_sub(1);
|
||||||
|
let clamped_pos = final_pos.min(max_valid_index);
|
||||||
|
state.set_current_cursor_pos(clamped_pos);
|
||||||
|
*ideal_cursor_column = clamped_pos;
|
||||||
}
|
}
|
||||||
Ok("".to_string())
|
Ok("".to_string())
|
||||||
}
|
}
|
||||||
@@ -400,19 +409,17 @@ fn find_word_end(text: &str, current_pos: usize) -> usize {
|
|||||||
if len == 0 {
|
if len == 0 {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if current_pos >= len {
|
|
||||||
return len;
|
let mut pos = current_pos.min(len - 1);
|
||||||
|
|
||||||
|
// If already at whitespace, find next word first
|
||||||
|
if get_char_type(chars[pos]) == CharType::Whitespace {
|
||||||
|
pos = find_next_word_start(text, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut pos = current_pos;
|
// Now find end of current/next word
|
||||||
|
if pos >= len {
|
||||||
if get_char_type(chars[pos]) == CharType::Whitespace {
|
return len.saturating_sub(1);
|
||||||
while pos < len && get_char_type(chars[pos]) == CharType::Whitespace {
|
|
||||||
pos += 1;
|
|
||||||
}
|
|
||||||
if pos == len {
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let word_type = get_char_type(chars[pos]);
|
let word_type = get_char_type(chars[pos]);
|
||||||
@@ -420,11 +427,8 @@ fn find_word_end(text: &str, current_pos: usize) -> usize {
|
|||||||
pos += 1;
|
pos += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if pos > current_pos && pos > 0 {
|
// Return last character of the word
|
||||||
pos - 1
|
pos.saturating_sub(1).min(len.saturating_sub(1))
|
||||||
} else {
|
|
||||||
current_pos.min(len.saturating_sub(1))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_prev_word_start(text: &str, current_pos: usize) -> usize {
|
fn find_prev_word_start(text: &str, current_pos: usize) -> usize {
|
||||||
|
|||||||
@@ -296,18 +296,21 @@ async fn execute_action<S: CanvasState>(
|
|||||||
"move_word_end" => {
|
"move_word_end" => {
|
||||||
let current_input = state.get_current_input();
|
let current_input = state.get_current_input();
|
||||||
if !current_input.is_empty() {
|
if !current_input.is_empty() {
|
||||||
// 1. Find the index of the last character of the target word
|
let current_pos = state.current_cursor_pos();
|
||||||
let new_pos =
|
let new_pos = find_word_end(current_input, current_pos);
|
||||||
find_word_end(current_input, state.current_cursor_pos());
|
|
||||||
|
// Only move if we're not already at the found position
|
||||||
|
let final_pos = if new_pos != current_pos {
|
||||||
|
new_pos
|
||||||
|
} else {
|
||||||
|
// If already at a word end, jump to next word's end
|
||||||
|
find_word_end(current_input, new_pos + 1)
|
||||||
|
};
|
||||||
|
|
||||||
// 2. Clamp the position for Read-Only mode
|
|
||||||
// max_valid_index is the index of the VERY LAST character in the input string
|
|
||||||
let max_valid_index = current_input.len().saturating_sub(1);
|
let max_valid_index = current_input.len().saturating_sub(1);
|
||||||
let final_pos = new_pos.min(max_valid_index);
|
let clamped_pos = final_pos.min(max_valid_index);
|
||||||
|
state.set_current_cursor_pos(clamped_pos);
|
||||||
// 3. Set the cursor
|
*ideal_cursor_column = clamped_pos;
|
||||||
state.set_current_cursor_pos(final_pos);
|
|
||||||
*ideal_cursor_column = final_pos;
|
|
||||||
}
|
}
|
||||||
Ok("".to_string())
|
Ok("".to_string())
|
||||||
}
|
}
|
||||||
@@ -394,29 +397,62 @@ fn find_next_word_start(text: &str, current_pos: usize) -> usize {
|
|||||||
pos
|
pos
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_word_end(text: &str, current_pos: usize) -> usize {
|
fn find_next_word_end(text: &str, current_pos: usize) -> usize {
|
||||||
let chars: Vec<char> = text.chars().collect();
|
let chars: Vec<char> = text.chars().collect();
|
||||||
if chars.is_empty() {
|
if chars.is_empty() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
let mut pos = current_pos.min(chars.len().saturating_sub(1));
|
|
||||||
|
|
||||||
if get_char_type(chars[pos]) == CharType::Whitespace {
|
// Find start of next word
|
||||||
while pos + 1 < chars.len() && get_char_type(chars[pos + 1]) == CharType::Whitespace {
|
let next_start = find_next_word_start(text, current_pos);
|
||||||
|
|
||||||
|
// Find end of that word
|
||||||
|
if next_start >= chars.len() {
|
||||||
|
return chars.len().saturating_sub(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut pos = next_start;
|
||||||
|
let word_type = get_char_type(chars[pos]);
|
||||||
|
|
||||||
|
while pos < chars.len() && get_char_type(chars[pos]) == word_type {
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos.saturating_sub(1).min(chars.len().saturating_sub(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_word_end(text: &str, current_pos: usize) -> usize {
|
||||||
|
let chars: Vec<char> = text.chars().collect();
|
||||||
|
let len = chars.len();
|
||||||
|
if len == 0 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut pos = current_pos.min(len - 1);
|
||||||
|
let original_pos = pos;
|
||||||
|
|
||||||
|
// First try to find end of current word
|
||||||
|
let current_type = get_char_type(chars[pos]);
|
||||||
|
if current_type != CharType::Whitespace {
|
||||||
|
// Move forward to word end
|
||||||
|
while pos < len && get_char_type(chars[pos]) == current_type {
|
||||||
pos += 1;
|
pos += 1;
|
||||||
}
|
}
|
||||||
if pos + 1 >= chars.len() || get_char_type(chars[pos + 1]) == CharType::Whitespace {
|
return pos.saturating_sub(1);
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
pos += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If in whitespace, find next word's end
|
||||||
|
pos = find_next_word_start(text, pos);
|
||||||
|
if pos >= len {
|
||||||
|
return len.saturating_sub(1);
|
||||||
|
}
|
||||||
|
|
||||||
let word_type = get_char_type(chars[pos]);
|
let word_type = get_char_type(chars[pos]);
|
||||||
while pos + 1 < chars.len() && get_char_type(chars[pos + 1]) == word_type {
|
while pos < len && get_char_type(chars[pos]) == word_type {
|
||||||
pos += 1;
|
pos += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos
|
pos.saturating_sub(1).min(len.saturating_sub(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_prev_word_start(text: &str, current_pos: usize) -> usize {
|
fn find_prev_word_start(text: &str, current_pos: usize) -> usize {
|
||||||
|
|||||||
Reference in New Issue
Block a user