Add indent action and tab width
This commit is contained in:
parent
d53932bd7c
commit
7855dce09d
4 changed files with 210 additions and 3 deletions
|
|
@ -23,6 +23,7 @@ pub struct Editor {
|
||||||
cursor_x_opt: Option<i32>,
|
cursor_x_opt: Option<i32>,
|
||||||
select_opt: Option<Cursor>,
|
select_opt: Option<Cursor>,
|
||||||
cursor_moved: bool,
|
cursor_moved: bool,
|
||||||
|
tab_width: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Editor {
|
impl Editor {
|
||||||
|
|
@ -34,6 +35,7 @@ impl Editor {
|
||||||
cursor_x_opt: None,
|
cursor_x_opt: None,
|
||||||
select_opt: None,
|
select_opt: None,
|
||||||
cursor_moved: false,
|
cursor_moved: false,
|
||||||
|
tab_width: 4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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) {
|
fn shape_as_needed(&mut self, font_system: &mut FontSystem) {
|
||||||
if self.cursor_moved {
|
if self.cursor_moved {
|
||||||
self.buffer.shape_until_cursor(font_system, self.cursor);
|
self.buffer.shape_until_cursor(font_system, self.cursor);
|
||||||
|
|
@ -576,6 +593,162 @@ impl Edit for Editor {
|
||||||
self.buffer.lines[self.cursor.line].append(old_line);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust selection
|
||||||
|
match self.select_opt {
|
||||||
|
Some(ref mut select) => {
|
||||||
|
if select.line == line_i {
|
||||||
|
if select.index >= after_whitespace {
|
||||||
|
select.index += required_indent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request redraw
|
||||||
|
self.buffer.set_redraw(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
Action::Click { x, y } => {
|
Action::Click { x, y } => {
|
||||||
self.select_opt = None;
|
self.select_opt = None;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,12 +59,24 @@ pub enum Action {
|
||||||
Backspace,
|
Backspace,
|
||||||
/// Delete text in front of cursor
|
/// Delete text in front of cursor
|
||||||
Delete,
|
Delete,
|
||||||
|
// Indent text (typically Tab)
|
||||||
|
Indent,
|
||||||
|
// Unindent text (typically Shift+Tab)
|
||||||
|
Unindent,
|
||||||
/// Mouse click at specified position
|
/// Mouse click at specified position
|
||||||
Click { x: i32, y: i32 },
|
Click {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
},
|
||||||
/// Mouse drag to specified position
|
/// Mouse drag to specified position
|
||||||
Drag { x: i32, y: i32 },
|
Drag {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
},
|
||||||
/// Scroll specified number of lines
|
/// Scroll specified number of lines
|
||||||
Scroll { lines: i32 },
|
Scroll {
|
||||||
|
lines: i32,
|
||||||
|
},
|
||||||
/// Move cursor to previous word boundary
|
/// Move cursor to previous word boundary
|
||||||
PreviousWord,
|
PreviousWord,
|
||||||
/// Move cursor to next word boundary
|
/// Move cursor to next word boundary
|
||||||
|
|
@ -113,6 +125,12 @@ pub trait Edit {
|
||||||
/// Set the current selection position
|
/// Set the current selection position
|
||||||
fn set_select_opt(&mut self, select_opt: Option<Cursor>);
|
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
|
||||||
|
fn set_tab_width(&mut self, tab_width: usize);
|
||||||
|
|
||||||
/// Shape lines until scroll, after adjusting scroll if the cursor moved
|
/// Shape lines until scroll, after adjusting scroll if the cursor moved
|
||||||
fn shape_as_needed(&mut self, font_system: &mut FontSystem);
|
fn shape_as_needed(&mut self, font_system: &mut FontSystem);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,14 @@ impl<'a> Edit for SyntaxEditor<'a> {
|
||||||
self.editor.set_select_opt(select_opt);
|
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) {
|
fn shape_as_needed(&mut self, font_system: &mut FontSystem) {
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
let now = std::time::Instant::now();
|
let now = std::time::Instant::now();
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,14 @@ impl<'a> Edit for ViEditor<'a> {
|
||||||
self.editor.set_select_opt(select_opt);
|
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) {
|
fn shape_as_needed(&mut self, font_system: &mut FontSystem) {
|
||||||
self.editor.shape_as_needed(font_system);
|
self.editor.shape_as_needed(font_system);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue