Skip to content

Commit a1e1163

Browse files
authored
fix: fix the issue of inaccurate automatic column width adjustment via PR #8 from fuhan666/bugfix/col-width
2 parents 353cdc9 + d5cd1c4 commit a1e1163

9 files changed

Lines changed: 289 additions & 356 deletions

File tree

Cargo.lock

Lines changed: 25 additions & 195 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ categories = ["command-line-utilities", "development-tools", "data-structures",
1010
exclude = ["/.github", "CHANGELOG.md", ".gitignore"]
1111

1212
[dependencies]
13-
ratatui = "0.29.0"
13+
ratatui = "0.24.0"
1414
crossterm = "0.27.0"
1515
calamine = "0.22.1"
1616
anyhow = "1.0.79"
@@ -20,7 +20,7 @@ serde = { version = "1.0", features = ["derive"] }
2020
serde_json = "1.0"
2121
chrono = "0.4"
2222
indexmap = { version = "2.0", features = ["serde"] }
23-
tui-textarea = "0.7.0"
23+
tui-textarea = "0.4.0"
2424

2525
[profile.release]
2626
opt-level = 3

src/app/edit.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::app::AppState;
33
use crate::app::InputMode;
44
use crate::app::{Transition, VimMode, VimState};
55
use anyhow::Result;
6+
use ratatui::style::{Modifier, Style};
67
use tui_textarea::Input;
78

89
impl AppState<'_> {
@@ -11,10 +12,14 @@ impl AppState<'_> {
1112
let content = self.get_cell_content(self.selected_cell.0, self.selected_cell.1);
1213
self.input_buffer = content.clone();
1314

14-
self.text_area = tui_textarea::TextArea::default();
15-
self.text_area.insert_str(&content);
16-
self.text_area.set_tab_length(4);
15+
// Initialize TextArea with content and settings
16+
let mut text_area = tui_textarea::TextArea::default();
17+
text_area.insert_str(&content);
18+
text_area.set_tab_length(4);
19+
text_area.set_cursor_line_style(Style::default());
20+
text_area.set_cursor_style(Style::default().add_modifier(Modifier::REVERSED));
1721

22+
self.text_area = text_area;
1823
self.vim_state = Some(VimState::new(VimMode::Normal));
1924
}
2025

src/app/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod state;
66
mod ui;
77
mod undo_manager;
88
mod vim;
9+
mod word;
910

1011
pub use state::*;
1112
pub use vim::*;

src/app/search.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,32 @@
11
use crate::app::AppState;
22
use crate::app::InputMode;
3+
use ratatui::style::{Modifier, Style};
34

45
impl AppState<'_> {
56
pub fn start_search_forward(&mut self) {
67
self.input_mode = InputMode::SearchForward;
78
self.input_buffer = String::new();
8-
self.text_area = tui_textarea::TextArea::default();
9+
10+
// Initialize TextArea
11+
let mut text_area = tui_textarea::TextArea::default();
12+
text_area.set_cursor_line_style(Style::default());
13+
text_area.set_cursor_style(Style::default().add_modifier(Modifier::REVERSED));
14+
self.text_area = text_area;
15+
916
self.add_notification("Search forward mode".to_string());
1017
self.highlight_enabled = true;
1118
}
1219

1320
pub fn start_search_backward(&mut self) {
1421
self.input_mode = InputMode::SearchBackward;
1522
self.input_buffer = String::new();
16-
self.text_area = tui_textarea::TextArea::default();
23+
24+
// Initialize TextArea
25+
let mut text_area = tui_textarea::TextArea::default();
26+
text_area.set_cursor_line_style(Style::default());
27+
text_area.set_cursor_style(Style::default().add_modifier(Modifier::REVERSED));
28+
self.text_area = text_area;
29+
1730
self.add_notification("Search backward mode".to_string());
1831
self.highlight_enabled = true;
1932
}

src/app/sheet.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -611,8 +611,7 @@ impl AppState<'_> {
611611

612612
max_width = max_width.max(display_width);
613613
}
614-
let padding = (max_width / 5).max(2);
615-
max_width + padding
614+
max_width
616615
}
617616

618617
pub fn get_column_width(&self, col: usize) -> usize {

src/app/vim.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ use ratatui::widgets::Block;
33
use std::fmt;
44
use tui_textarea::{CursorMove, Input, Key, TextArea};
55

6+
use crate::app::word::move_cursor_to_word_end;
7+
68
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79
pub enum VimMode {
810
Normal,
@@ -109,9 +111,39 @@ impl VimState {
109111
ctrl: false,
110112
..
111113
} => {
112-
textarea.move_cursor(CursorMove::WordEnd);
114+
// Use custom WordEnd implementation
115+
let lines = textarea.lines();
116+
let (row, col) = textarea.cursor();
117+
let (new_row, new_col) = move_cursor_to_word_end(lines, row, col);
118+
119+
// Set the cursor to the new position
120+
if row != new_row {
121+
// If need to move to a different row
122+
while textarea.cursor().0 < new_row {
123+
textarea.move_cursor(CursorMove::Down);
124+
}
125+
textarea.move_cursor(CursorMove::Head);
126+
while textarea.cursor().1 < new_col {
127+
textarea.move_cursor(CursorMove::Forward);
128+
}
129+
} else {
130+
// If staying on the same row
131+
if col < new_col {
132+
// Move forward
133+
while textarea.cursor().1 < new_col {
134+
textarea.move_cursor(CursorMove::Forward);
135+
}
136+
} else {
137+
// Move backward
138+
while textarea.cursor().1 > new_col {
139+
textarea.move_cursor(CursorMove::Back);
140+
}
141+
}
142+
}
143+
144+
// For operator mode, include the character under the cursor
113145
if matches!(self.mode, VimMode::Operator(_)) {
114-
textarea.move_cursor(CursorMove::Forward); // Include the text under the cursor
146+
textarea.move_cursor(CursorMove::Forward);
115147
}
116148
}
117149
Input {

src/app/word.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Custom implementation of word navigation functions from tui-textarea v0.5.2+
2+
3+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4+
enum CharKind {
5+
Space,
6+
Punctuation,
7+
Other,
8+
}
9+
10+
impl CharKind {
11+
fn new(c: char) -> Self {
12+
if c.is_whitespace() {
13+
Self::Space
14+
} else if c.is_ascii_punctuation() {
15+
Self::Punctuation
16+
} else {
17+
Self::Other
18+
}
19+
}
20+
}
21+
22+
/// Find the end of the next word
23+
/// This is a custom implementation of the `find_word_end_next` function from tui-textarea v0.5.2+
24+
pub fn find_word_end_next(line: &str, start_col: usize) -> Option<usize> {
25+
let mut it = line.chars().enumerate().skip(start_col);
26+
let (mut cur_col, cur_char) = it.next()?;
27+
let mut cur = CharKind::new(cur_char);
28+
29+
for (next_col, c) in it {
30+
let next = CharKind::new(c);
31+
// if cursor started at the end of a word, don't stop
32+
if next_col.saturating_sub(start_col) > 1 && cur != CharKind::Space && next != cur {
33+
return Some(next_col.saturating_sub(1));
34+
}
35+
cur = next;
36+
cur_col = next_col;
37+
}
38+
39+
// if end of line is whitespace, don't stop the cursor
40+
if cur != CharKind::Space && cur_col.saturating_sub(start_col) >= 1 {
41+
return Some(cur_col);
42+
}
43+
44+
None
45+
}
46+
47+
/// Move cursor to the end of the next word
48+
pub fn move_cursor_to_word_end(text: &[String], row: usize, col: usize) -> (usize, usize) {
49+
if row >= text.len() {
50+
return (row, col);
51+
}
52+
53+
let line = &text[row];
54+
55+
if let Some(new_col) = find_word_end_next(line, col) {
56+
return (row, new_col);
57+
} else if row + 1 < text.len() {
58+
// Try to find word end in the next line
59+
if let Some(new_col) = find_word_end_next(&text[row + 1], 0) {
60+
return (row + 1, new_col);
61+
} else if !text[row + 1].is_empty() {
62+
// If no word end found but line is not empty, go to the end of the line
63+
return (row + 1, text[row + 1].chars().count().saturating_sub(1));
64+
}
65+
}
66+
67+
// Can't find a word end, stay at the current position
68+
(row, col)
69+
}

0 commit comments

Comments
 (0)