Implementation of "insert char" command

This commit is contained in:
daa 2018-03-23 00:36:43 +03:00
parent 4cd6cf46dd
commit 783eb1a8ad
3 changed files with 80 additions and 38 deletions

View File

@ -28,13 +28,13 @@ impl Level {
//TODO: im
pub fn insert(&mut self, c: &str, shift: bool, render_state: &shell::RenderState) {
self.model_layout.insert(c, shift);
self.model_layout.insert_char(c, shift);
self.update_preferred_size(render_state);
}
pub fn replace_from_ctx(&mut self, ctx: &CmdLineContext, render_state: &shell::RenderState) {
let content = ctx.get_lines();
self.replace_line(&content.lines, false);
self.replace_line(content.lines, false);
self.prompt_offset = content.prompt_offset;
self.model_layout
.set_cursor(self.prompt_offset + ctx.pos as usize);
@ -43,7 +43,7 @@ impl Level {
pub fn from_ctx(ctx: &CmdLineContext, render_state: &shell::RenderState) -> Self {
let content = ctx.get_lines();
let mut level = Level::from_lines(&content.lines, ctx.max_width, render_state);
let mut level = Level::from_lines(content.lines, ctx.max_width, render_state);
level.prompt_offset = content.prompt_offset;
level
@ -54,7 +54,7 @@ impl Level {
level
}
fn replace_line(&mut self, lines: &Vec<Vec<(Option<Attrs>, Vec<char>)>>, append: bool) {
fn replace_line(&mut self, lines: Vec<Vec<(Option<Attrs>, Vec<char>)>>, append: bool) {
if append {
self.model_layout.layout_append(lines);
} else {
@ -96,14 +96,14 @@ impl Level {
render_state: &shell::RenderState,
) -> Self {
Level::from_lines(
&Level::to_attributed_content(content),
Level::to_attributed_content(content),
max_width,
render_state,
)
}
pub fn from_lines(
lines: &Vec<Vec<(Option<Attrs>, Vec<char>)>>,
lines: Vec<Vec<(Option<Attrs>, Vec<char>)>>,
max_width: i32,
render_state: &shell::RenderState,
) -> Self {
@ -382,7 +382,7 @@ impl CmdLine {
.collect();
let block = state.block.as_mut().unwrap();
block.replace_line(&vec![attr_content], true);
block.replace_line(vec![attr_content], true);
block.update_preferred_size(&*render_state.borrow());
block.update_cache(&*render_state.borrow());
}

View File

@ -174,15 +174,6 @@ impl UiModel {
ModelRect::new(top as usize, bot as usize, left, right)
}
/// Move down all lines except first one
pub fn move_down(&mut self) {
let right = self.columns + 1;
for row in (1..self.rows + 1).rev() {
self.copy_row(row as i64, 1, 0, right);
}
}
pub fn clear(&mut self) {
let (rows, columns) = (self.rows, self.columns);
self.clear_region(0, rows - 1, 0, columns - 1);

View File

@ -6,6 +6,7 @@ pub struct ModelLayout {
pub model: UiModel,
rows_filled: usize,
cols_filled: usize,
lines: Vec<Vec<(Option<Attrs>, Vec<char>)>>,
}
impl ModelLayout {
@ -16,16 +17,22 @@ impl ModelLayout {
model: UiModel::new(ModelLayout::ROWS_STEP as u64, columns),
rows_filled: 0,
cols_filled: 0,
lines: Vec::new(),
}
}
pub fn layout_append(&mut self, lines: &Vec<Vec<(Option<Attrs>, Vec<char>)>>) {
pub fn layout_append(&mut self, mut lines: Vec<Vec<(Option<Attrs>, Vec<char>)>>) {
let rows_filled = self.rows_filled;
self.layout_replace(rows_filled, lines);
let take_from = self.lines.len();
self.lines.append(&mut lines);
self.layout_replace(rows_filled, take_from);
}
pub fn layout(&mut self, lines: &Vec<Vec<(Option<Attrs>, Vec<char>)>>) {
self.layout_replace(0, lines);
pub fn layout(&mut self, lines: Vec<Vec<(Option<Attrs>, Vec<char>)>>) {
self.lines = lines;
self.layout_replace(0, 0);
}
pub fn set_cursor(&mut self, col: usize) {
@ -58,35 +65,51 @@ impl ModelLayout {
}
}
pub fn insert(&mut self, c: &str, shift: bool) {
pub fn insert_char(&mut self, c: &str, shift: bool) {
if c.is_empty() {
return;
}
let ch = c.chars().next().unwrap();
let (row, col) = self.model.get_cursor();
if shift {
//TODO: insert special char
if self.cols_filled + 1 >= self.model.columns {
let rows_filled = self.rows_filled + 1;
self.check_model_size(rows_filled);
self.model.move_down();
self.rows_filled = rows_filled;
}
self.insert_into_lines(ch);
self.layout_replace(0, 0);
} else {
self.model.put(c.chars().next().unwrap(), false, None);
self.model.put(ch, false, None);
}
self.model.set_cursor(row, col);
}
fn insert_into_lines(&mut self, ch: char) {
let line = &mut self.lines[0];
let cur_col = self.model.cur_col;
let mut col_idx = 0;
for &mut (_, ref mut chars) in line {
if cur_col < col_idx + chars.len() {
let col_sub_idx = cur_col - col_idx;
chars.insert(col_sub_idx, ch);
} else {
col_idx += chars.len();
}
}
}
/// Wrap all lines into model
///
/// returns actual width
fn layout_replace(&mut self, row_offset: usize, lines: &Vec<Vec<(Option<Attrs>, Vec<char>)>>) {
let rows = ModelLayout::count_lines(&lines, self.model.columns);
fn layout_replace(&mut self, row_offset: usize, take_from: usize) {
let rows = ModelLayout::count_lines(&self.lines[take_from..], self.model.columns);
self.check_model_size(rows + row_offset);
self.rows_filled = rows + row_offset;
let lines = &self.lines[take_from..];
let mut max_col_idx = 0;
let mut col_idx = 0;
let mut row_idx = row_offset;
@ -122,7 +145,7 @@ impl ModelLayout {
}
}
fn count_lines(lines: &Vec<Vec<(Option<Attrs>, Vec<char>)>>, max_columns: usize) -> usize {
fn count_lines(lines: &[Vec<(Option<Attrs>, Vec<char>)>], max_columns: usize) -> usize {
let mut row_count = 0;
for line in lines {
@ -151,12 +174,12 @@ mod tests {
let lines = vec![vec![(None, vec!['a'; 5])]; ModelLayout::ROWS_STEP];
let mut model = ModelLayout::new(5);
model.layout(&lines);
model.layout(lines.clone());
let (cols, rows) = model.size();
assert_eq!(5, cols);
assert_eq!(ModelLayout::ROWS_STEP, rows);
model.layout_append(&lines);
model.layout_append(lines);
let (cols, rows) = model.size();
assert_eq!(5, cols);
assert_eq!(ModelLayout::ROWS_STEP * 2, rows);
@ -168,14 +191,42 @@ mod tests {
let lines = vec![vec![(None, vec!['a'; 3])]; 1];
let mut model = ModelLayout::new(5);
model.layout(&lines);
model.layout(lines);
let (cols, _) = model.size();
assert_eq!(4, cols); // size is 3 and 4 - is with cursor position
let lines = vec![vec![(None, vec!['a'; 2])]; 1];
model.layout_append(&lines);
model.layout_append(lines);
let (cols, _) = model.size();
assert_eq!(3, cols);
}
#[test]
fn test_insert_shift() {
let lines = vec![vec![(None, vec!['a'; 3])]; 1];
let mut model = ModelLayout::new(5);
model.layout(lines);
model.set_cursor(1);
model.insert_char("b", true);
let (cols, _) = model.size();
assert_eq!(4, cols);
assert_eq!('b', model.model.model()[0].line[1].ch);
}
#[test]
fn test_insert_no_shift() {
let lines = vec![vec![(None, vec!['a'; 3])]; 1];
let mut model = ModelLayout::new(5);
model.layout(lines);
model.set_cursor(1);
model.insert_char("b", false);
let (cols, _) = model.size();
assert_eq!(3, cols);
assert_eq!('b', model.model.model()[0].line[1].ch);
}
}