Implementation of "insert char" command
This commit is contained in:
parent
4cd6cf46dd
commit
783eb1a8ad
@ -28,13 +28,13 @@ impl Level {
|
|||||||
//TODO: im
|
//TODO: im
|
||||||
|
|
||||||
pub fn insert(&mut self, c: &str, shift: bool, render_state: &shell::RenderState) {
|
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);
|
self.update_preferred_size(render_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace_from_ctx(&mut self, ctx: &CmdLineContext, render_state: &shell::RenderState) {
|
pub fn replace_from_ctx(&mut self, ctx: &CmdLineContext, render_state: &shell::RenderState) {
|
||||||
let content = ctx.get_lines();
|
let content = ctx.get_lines();
|
||||||
self.replace_line(&content.lines, false);
|
self.replace_line(content.lines, false);
|
||||||
self.prompt_offset = content.prompt_offset;
|
self.prompt_offset = content.prompt_offset;
|
||||||
self.model_layout
|
self.model_layout
|
||||||
.set_cursor(self.prompt_offset + ctx.pos as usize);
|
.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 {
|
pub fn from_ctx(ctx: &CmdLineContext, render_state: &shell::RenderState) -> Self {
|
||||||
let content = ctx.get_lines();
|
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.prompt_offset = content.prompt_offset;
|
||||||
level
|
level
|
||||||
@ -54,7 +54,7 @@ impl Level {
|
|||||||
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 {
|
if append {
|
||||||
self.model_layout.layout_append(lines);
|
self.model_layout.layout_append(lines);
|
||||||
} else {
|
} else {
|
||||||
@ -96,14 +96,14 @@ impl Level {
|
|||||||
render_state: &shell::RenderState,
|
render_state: &shell::RenderState,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Level::from_lines(
|
Level::from_lines(
|
||||||
&Level::to_attributed_content(content),
|
Level::to_attributed_content(content),
|
||||||
max_width,
|
max_width,
|
||||||
render_state,
|
render_state,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_lines(
|
pub fn from_lines(
|
||||||
lines: &Vec<Vec<(Option<Attrs>, Vec<char>)>>,
|
lines: Vec<Vec<(Option<Attrs>, Vec<char>)>>,
|
||||||
max_width: i32,
|
max_width: i32,
|
||||||
render_state: &shell::RenderState,
|
render_state: &shell::RenderState,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -382,7 +382,7 @@ impl CmdLine {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let block = state.block.as_mut().unwrap();
|
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_preferred_size(&*render_state.borrow());
|
||||||
block.update_cache(&*render_state.borrow());
|
block.update_cache(&*render_state.borrow());
|
||||||
}
|
}
|
||||||
|
@ -174,15 +174,6 @@ impl UiModel {
|
|||||||
ModelRect::new(top as usize, bot as usize, left, right)
|
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) {
|
pub fn clear(&mut self) {
|
||||||
let (rows, columns) = (self.rows, self.columns);
|
let (rows, columns) = (self.rows, self.columns);
|
||||||
self.clear_region(0, rows - 1, 0, columns - 1);
|
self.clear_region(0, rows - 1, 0, columns - 1);
|
||||||
|
@ -6,6 +6,7 @@ pub struct ModelLayout {
|
|||||||
pub model: UiModel,
|
pub model: UiModel,
|
||||||
rows_filled: usize,
|
rows_filled: usize,
|
||||||
cols_filled: usize,
|
cols_filled: usize,
|
||||||
|
lines: Vec<Vec<(Option<Attrs>, Vec<char>)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModelLayout {
|
impl ModelLayout {
|
||||||
@ -16,16 +17,22 @@ impl ModelLayout {
|
|||||||
model: UiModel::new(ModelLayout::ROWS_STEP as u64, columns),
|
model: UiModel::new(ModelLayout::ROWS_STEP as u64, columns),
|
||||||
rows_filled: 0,
|
rows_filled: 0,
|
||||||
cols_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;
|
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>)>>) {
|
pub fn layout(&mut self, lines: Vec<Vec<(Option<Attrs>, Vec<char>)>>) {
|
||||||
self.layout_replace(0, lines);
|
self.lines = lines;
|
||||||
|
self.layout_replace(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_cursor(&mut self, col: usize) {
|
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() {
|
if c.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ch = c.chars().next().unwrap();
|
||||||
|
let (row, col) = self.model.get_cursor();
|
||||||
|
|
||||||
if shift {
|
if shift {
|
||||||
//TODO: insert special char
|
self.insert_into_lines(ch);
|
||||||
if self.cols_filled + 1 >= self.model.columns {
|
self.layout_replace(0, 0);
|
||||||
let rows_filled = self.rows_filled + 1;
|
|
||||||
|
|
||||||
self.check_model_size(rows_filled);
|
|
||||||
self.model.move_down();
|
|
||||||
|
|
||||||
self.rows_filled = rows_filled;
|
|
||||||
}
|
|
||||||
} else {
|
} 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
|
/// Wrap all lines into model
|
||||||
///
|
///
|
||||||
/// returns actual width
|
/// returns actual width
|
||||||
fn layout_replace(&mut self, row_offset: usize, lines: &Vec<Vec<(Option<Attrs>, Vec<char>)>>) {
|
fn layout_replace(&mut self, row_offset: usize, take_from: usize) {
|
||||||
let rows = ModelLayout::count_lines(&lines, self.model.columns);
|
let rows = ModelLayout::count_lines(&self.lines[take_from..], self.model.columns);
|
||||||
|
|
||||||
self.check_model_size(rows + row_offset);
|
self.check_model_size(rows + row_offset);
|
||||||
self.rows_filled = rows + row_offset;
|
self.rows_filled = rows + row_offset;
|
||||||
|
|
||||||
|
let lines = &self.lines[take_from..];
|
||||||
|
|
||||||
let mut max_col_idx = 0;
|
let mut max_col_idx = 0;
|
||||||
let mut col_idx = 0;
|
let mut col_idx = 0;
|
||||||
let mut row_idx = row_offset;
|
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;
|
let mut row_count = 0;
|
||||||
|
|
||||||
for line in lines {
|
for line in lines {
|
||||||
@ -151,12 +174,12 @@ mod tests {
|
|||||||
let lines = vec![vec![(None, vec!['a'; 5])]; ModelLayout::ROWS_STEP];
|
let lines = vec![vec![(None, vec!['a'; 5])]; ModelLayout::ROWS_STEP];
|
||||||
let mut model = ModelLayout::new(5);
|
let mut model = ModelLayout::new(5);
|
||||||
|
|
||||||
model.layout(&lines);
|
model.layout(lines.clone());
|
||||||
let (cols, rows) = model.size();
|
let (cols, rows) = model.size();
|
||||||
assert_eq!(5, cols);
|
assert_eq!(5, cols);
|
||||||
assert_eq!(ModelLayout::ROWS_STEP, rows);
|
assert_eq!(ModelLayout::ROWS_STEP, rows);
|
||||||
|
|
||||||
model.layout_append(&lines);
|
model.layout_append(lines);
|
||||||
let (cols, rows) = model.size();
|
let (cols, rows) = model.size();
|
||||||
assert_eq!(5, cols);
|
assert_eq!(5, cols);
|
||||||
assert_eq!(ModelLayout::ROWS_STEP * 2, rows);
|
assert_eq!(ModelLayout::ROWS_STEP * 2, rows);
|
||||||
@ -168,14 +191,42 @@ mod tests {
|
|||||||
let lines = vec![vec![(None, vec!['a'; 3])]; 1];
|
let lines = vec![vec![(None, vec!['a'; 3])]; 1];
|
||||||
let mut model = ModelLayout::new(5);
|
let mut model = ModelLayout::new(5);
|
||||||
|
|
||||||
model.layout(&lines);
|
model.layout(lines);
|
||||||
let (cols, _) = model.size();
|
let (cols, _) = model.size();
|
||||||
assert_eq!(4, cols); // size is 3 and 4 - is with cursor position
|
assert_eq!(4, cols); // size is 3 and 4 - is with cursor position
|
||||||
|
|
||||||
let lines = vec![vec![(None, vec!['a'; 2])]; 1];
|
let lines = vec![vec![(None, vec!['a'; 2])]; 1];
|
||||||
|
|
||||||
model.layout_append(&lines);
|
model.layout_append(lines);
|
||||||
let (cols, _) = model.size();
|
let (cols, _) = model.size();
|
||||||
assert_eq!(3, cols);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user