Skip to content

Commit

Permalink
Add indent action and tab width
Browse files Browse the repository at this point in the history
  • Loading branch information
jackpot51 committed Nov 1, 2023
1 parent d53932b commit 7855dce
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 3 deletions.
173 changes: 173 additions & 0 deletions src/edit/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub struct Editor {
cursor_x_opt: Option<i32>,
select_opt: Option<Cursor>,
cursor_moved: bool,
tab_width: usize,
}

impl Editor {
Expand All @@ -34,6 +35,7 @@ impl Editor {
cursor_x_opt: None,
select_opt: None,
cursor_moved: false,
tab_width: 4,
}
}

Expand Down Expand Up @@ -104,6 +106,21 @@ impl Edit for Editor {
}
}

fn tab_width(&self) -> usize {
self.tab_width
}

fn set_tab_width(&mut self, tab_width: usize) {
// A tab width of 0 is not allowed
if tab_width == 0 {
return;
}
if self.tab_width != tab_width {
self.tab_width = tab_width;
self.buffer.set_redraw(true);
}
}

fn shape_as_needed(&mut self, font_system: &mut FontSystem) {
if self.cursor_moved {
self.buffer.shape_until_cursor(font_system, self.cursor);
Expand Down Expand Up @@ -576,6 +593,162 @@ impl Edit for Editor {
self.buffer.lines[self.cursor.line].append(old_line);
}
}
Action::Indent => {
// Get start and end of selection
let (start, end) = match self.select_opt {
Some(select) => match select.line.cmp(&self.cursor.line) {
cmp::Ordering::Greater => (self.cursor, select),
cmp::Ordering::Less => (select, self.cursor),
cmp::Ordering::Equal => {
/* select.line == self.cursor.line */
if select.index < self.cursor.index {
(select, self.cursor)
} else {
/* select.index >= self.cursor.index */
(self.cursor, select)
}
}
},
None => (self.cursor, self.cursor),
};

// For every line in selection
for line_i in start.line..=end.line {
let line = &mut self.buffer.lines[line_i];

// Determine indexes of last indent and first character after whitespace
let mut after_whitespace = 0;
let mut required_indent = 0;
{
let text = line.text();
for (count, (index, c)) in text.char_indices().enumerate() {
if !c.is_whitespace() {
after_whitespace = index;
required_indent = self.tab_width - (count % self.tab_width);
break;
}
}
}

// No indent required (not possible?)
if required_indent == 0 {
continue;
}

// Save line after last whitespace
let after = line.split_off(after_whitespace);

// Add required indent
line.append(BufferLine::new(
" ".repeat(required_indent),
AttrsList::new(line.attrs_list().defaults()),
Shaping::Advanced,
));

// Re-add line after last whitespace
line.append(after);

// Adjust cursor
if self.cursor.line == line_i {
if self.cursor.index >= after_whitespace {
self.cursor.index += required_indent;
self.cursor_moved = true;
}
}

Check warning on line 657 in src/edit/editor.rs

View workflow job for this annotation

GitHub Actions / clippy

this `if` statement can be collapsed

warning: this `if` statement can be collapsed --> src/edit/editor.rs:652:21 | 652 | / if self.cursor.line == line_i { 653 | | if self.cursor.index >= after_whitespace { 654 | | self.cursor.index += required_indent; 655 | | self.cursor_moved = true; 656 | | } 657 | | } | |_____________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if = note: `#[warn(clippy::collapsible_if)]` on by default help: collapse nested if block | 652 ~ if self.cursor.line == line_i && self.cursor.index >= after_whitespace { 653 + self.cursor.index += required_indent; 654 + self.cursor_moved = true; 655 + } |

// Adjust selection
match self.select_opt {
Some(ref mut select) => {
if select.line == line_i {
if select.index >= after_whitespace {
select.index += required_indent;
}
}

Check warning on line 666 in src/edit/editor.rs

View workflow job for this annotation

GitHub Actions / clippy

this `if` statement can be collapsed

warning: this `if` statement can be collapsed --> src/edit/editor.rs:662:29 | 662 | / ... if select.line == line_i { 663 | | ... if select.index >= after_whitespace { 664 | | ... select.index += required_indent; 665 | | ... } 666 | | ... } | |_______________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if help: collapse nested if block | 662 ~ if select.line == line_i && select.index >= after_whitespace { 663 + select.index += required_indent; 664 + } |
}
None => {}
}

Check warning on line 669 in src/edit/editor.rs

View workflow job for this annotation

GitHub Actions / clippy

you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`

warning: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> src/edit/editor.rs:660:21 | 660 | / match self.select_opt { 661 | | Some(ref mut select) => { 662 | | if select.line == line_i { 663 | | if select.index >= after_whitespace { ... | 668 | | None => {} 669 | | } | |_____________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_match = note: `#[warn(clippy::single_match)]` on by default help: try | 660 ~ if let Some(ref mut select) = self.select_opt { 661 + if select.line == line_i { 662 + if select.index >= after_whitespace { 663 + select.index += required_indent; 664 + } 665 + } 666 + } |

// Request redraw
self.buffer.set_redraw(true);
}
}
Action::Unindent => {
// Get start and end of selection
let (start, end) = match self.select_opt {
Some(select) => match select.line.cmp(&self.cursor.line) {
cmp::Ordering::Greater => (self.cursor, select),
cmp::Ordering::Less => (select, self.cursor),
cmp::Ordering::Equal => {
/* select.line == self.cursor.line */
if select.index < self.cursor.index {
(select, self.cursor)
} else {
/* select.index >= self.cursor.index */
(self.cursor, select)
}
}
},
None => (self.cursor, self.cursor),
};

// For every line in selection
for line_i in start.line..=end.line {
let line = &mut self.buffer.lines[line_i];

// Determine indexes of last indent and first character after whitespace
let mut last_indent = 0;
let mut after_whitespace = 0;
{
let text = line.text();
for (count, (index, c)) in text.char_indices().enumerate() {
if !c.is_whitespace() {
after_whitespace = index;
break;
}
if count % self.tab_width == 0 {
last_indent = index;
}
}
}

// No de-indent required
if last_indent == after_whitespace {
continue;
}

// Save line after last whitespace
let after = line.split_off(after_whitespace);

// Drop part of line after last indent
line.split_off(last_indent);

// Re-add line after last whitespace
line.append(after);

// Adjust cursor
if self.cursor.line == line_i {
if self.cursor.index > last_indent {
self.cursor.index -= after_whitespace - last_indent;
self.cursor_moved = true;
}
}

Check warning on line 734 in src/edit/editor.rs

View workflow job for this annotation

GitHub Actions / clippy

this `if` statement can be collapsed

warning: this `if` statement can be collapsed --> src/edit/editor.rs:729:21 | 729 | / if self.cursor.line == line_i { 730 | | if self.cursor.index > last_indent { 731 | | self.cursor.index -= after_whitespace - last_indent; 732 | | self.cursor_moved = true; 733 | | } 734 | | } | |_____________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if help: collapse nested if block | 729 ~ if self.cursor.line == line_i && self.cursor.index > last_indent { 730 + self.cursor.index -= after_whitespace - last_indent; 731 + self.cursor_moved = true; 732 + } |

// Adjust selection
match self.select_opt {
Some(ref mut select) => {
if select.line == line_i {
if select.index > last_indent {
select.index -= after_whitespace - last_indent;
}
}

Check warning on line 743 in src/edit/editor.rs

View workflow job for this annotation

GitHub Actions / clippy

this `if` statement can be collapsed

warning: this `if` statement can be collapsed --> src/edit/editor.rs:739:29 | 739 | / ... if select.line == line_i { 740 | | ... if select.index > last_indent { 741 | | ... select.index -= after_whitespace - last_indent; 742 | | ... } 743 | | ... } | |_______________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if help: collapse nested if block | 739 ~ if select.line == line_i && select.index > last_indent { 740 + select.index -= after_whitespace - last_indent; 741 + } |
}
None => {}
}

Check warning on line 746 in src/edit/editor.rs

View workflow job for this annotation

GitHub Actions / clippy

you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`

warning: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> src/edit/editor.rs:737:21 | 737 | / match self.select_opt { 738 | | Some(ref mut select) => { 739 | | if select.line == line_i { 740 | | if select.index > last_indent { ... | 745 | | None => {} 746 | | } | |_____________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_match help: try | 737 ~ if let Some(ref mut select) = self.select_opt { 738 + if select.line == line_i { 739 + if select.index > last_indent { 740 + select.index -= after_whitespace - last_indent; 741 + } 742 + } 743 + } |

// Request redraw
self.buffer.set_redraw(true);
}
}
Action::Click { x, y } => {
self.select_opt = None;

Expand Down
24 changes: 21 additions & 3 deletions src/edit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,24 @@ pub enum Action {
Backspace,
/// Delete text in front of cursor
Delete,
// Indent text (typically Tab)
Indent,
// Unindent text (typically Shift+Tab)
Unindent,
/// Mouse click at specified position
Click { x: i32, y: i32 },
Click {
x: i32,
y: i32,
},
/// Mouse drag to specified position
Drag { x: i32, y: i32 },
Drag {
x: i32,
y: i32,
},
/// Scroll specified number of lines
Scroll { lines: i32 },
Scroll {
lines: i32,
},
/// Move cursor to previous word boundary
PreviousWord,
/// Move cursor to next word boundary
Expand Down Expand Up @@ -113,6 +125,12 @@ pub trait Edit {
/// Set the current selection position
fn set_select_opt(&mut self, select_opt: Option<Cursor>);

/// Get the current tab width
fn tab_width(&self) -> usize;

/// Set the current tab width. A tab_width of 0 is not allowed, and will be ignored

Check warning on line 131 in src/edit/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

item in documentation is missing backticks

warning: item in documentation is missing backticks --> src/edit/mod.rs:131:38 | 131 | /// Set the current tab width. A tab_width of 0 is not allowed, and will be ignored | ^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown note: the lint level is defined here --> src/lib.rs:84:9 | 84 | #![warn(clippy::doc_markdown)] | ^^^^^^^^^^^^^^^^^^^^ help: try | 131 | /// Set the current tab width. A `tab_width` of 0 is not allowed, and will be ignored | ~~~~~~~~~~~
fn set_tab_width(&mut self, tab_width: usize);

/// Shape lines until scroll, after adjusting scroll if the cursor moved
fn shape_as_needed(&mut self, font_system: &mut FontSystem);

Expand Down
8 changes: 8 additions & 0 deletions src/edit/syntect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ impl<'a> Edit for SyntaxEditor<'a> {
self.editor.set_select_opt(select_opt);
}

fn tab_width(&self) -> usize {
self.editor.tab_width()
}

fn set_tab_width(&mut self, tab_width: usize) {
self.editor.set_tab_width(tab_width);
}

fn shape_as_needed(&mut self, font_system: &mut FontSystem) {
#[cfg(feature = "std")]
let now = std::time::Instant::now();
Expand Down
8 changes: 8 additions & 0 deletions src/edit/vi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,14 @@ impl<'a> Edit for ViEditor<'a> {
self.editor.set_select_opt(select_opt);
}

fn tab_width(&self) -> usize {
self.editor.tab_width()
}

fn set_tab_width(&mut self, tab_width: usize) {
self.editor.set_tab_width(tab_width);
}

fn shape_as_needed(&mut self, font_system: &mut FontSystem) {
self.editor.shape_as_needed(font_system);
}
Expand Down

0 comments on commit 7855dce

Please sign in to comment.