Implement up/down and home/end
This commit is contained in:
parent
b433f22592
commit
ac83f5846b
1 changed files with 126 additions and 15 deletions
141
src/buffer.rs
141
src/buffer.rs
|
|
@ -60,6 +60,18 @@ impl TextCursor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct LayoutCursor {
|
||||||
|
line: TextLineIndex,
|
||||||
|
layout: usize,
|
||||||
|
glyph: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LayoutCursor {
|
||||||
|
fn new(line: TextLineIndex, layout: usize, glyph: usize) -> Self {
|
||||||
|
Self { line, layout, glyph }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Index of a text line
|
/// Index of a text line
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
pub struct TextLineIndex(usize);
|
pub struct TextLineIndex(usize);
|
||||||
|
|
@ -303,6 +315,81 @@ impl<'a> TextBuffer<'a> {
|
||||||
log::debug!("relayout: {:?}", duration);
|
log::debug!("relayout: {:?}", duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn layout_cursor(&self, cursor: &TextCursor) -> LayoutCursor {
|
||||||
|
let line = &self.lines[cursor.line.get()];
|
||||||
|
|
||||||
|
let layout = line.layout_opt.as_ref().unwrap(); //TODO: ensure layout is done?
|
||||||
|
for (layout_i, layout_line) in layout.iter().enumerate() {
|
||||||
|
for (glyph_i, glyph) in layout_line.glyphs.iter().enumerate() {
|
||||||
|
if cursor.index == glyph.start {
|
||||||
|
return LayoutCursor::new(
|
||||||
|
cursor.line,
|
||||||
|
layout_i,
|
||||||
|
glyph_i
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match layout_line.glyphs.last() {
|
||||||
|
Some(glyph) => {
|
||||||
|
if cursor.index == glyph.end {
|
||||||
|
return LayoutCursor::new(
|
||||||
|
cursor.line,
|
||||||
|
layout_i,
|
||||||
|
layout_line.glyphs.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
return LayoutCursor::new(
|
||||||
|
cursor.line,
|
||||||
|
layout_i,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to start of line
|
||||||
|
//TODO: should this be the end of the line?
|
||||||
|
LayoutCursor::new(
|
||||||
|
cursor.line,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_layout_cursor(&mut self, cursor: LayoutCursor) {
|
||||||
|
let line = &mut self.lines[cursor.line.get()];
|
||||||
|
let layout = line.layout(
|
||||||
|
&mut self.font_matches,
|
||||||
|
self.metrics.font_size,
|
||||||
|
self.width
|
||||||
|
);
|
||||||
|
|
||||||
|
let layout_line = match layout.get(cursor.layout) {
|
||||||
|
Some(some) => some,
|
||||||
|
None => match layout.last() {
|
||||||
|
Some(some) => some,
|
||||||
|
None => todo!("layout cursor in line with no layouts"),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_index = match layout_line.glyphs.get(cursor.glyph) {
|
||||||
|
Some(glyph) => glyph.start,
|
||||||
|
None => match layout_line.glyphs.last() {
|
||||||
|
Some(glyph) => glyph.end,
|
||||||
|
//TODO: is this correct?
|
||||||
|
None => 0,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.cursor.line != cursor.line || self.cursor.index != new_index {
|
||||||
|
self.cursor.line = cursor.line;
|
||||||
|
self.cursor.index = new_index;
|
||||||
|
self.redraw = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the current cursor position
|
/// Get the current cursor position
|
||||||
pub fn cursor(&self) -> TextCursor {
|
pub fn cursor(&self) -> TextCursor {
|
||||||
self.cursor
|
self.cursor
|
||||||
|
|
@ -437,26 +524,45 @@ impl<'a> TextBuffer<'a> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TextAction::Up => {
|
TextAction::Up => {
|
||||||
//TODO: make this move by layout lines and preserve X as best as possible!
|
//TODO: make this preserve X as best as possible!
|
||||||
if self.cursor.line.get() > 0 {
|
let mut cursor = self.layout_cursor(&self.cursor);
|
||||||
self.cursor.line = TextLineIndex::new(self.cursor.line.get() - 1);
|
if cursor.layout > 0 {
|
||||||
self.cursor.index = 0;
|
cursor.layout -= 1;
|
||||||
self.redraw = true;
|
} else if cursor.line.get() > 0 {
|
||||||
|
cursor.line = TextLineIndex::new(cursor.line.get() - 1);
|
||||||
|
cursor.layout = usize::max_value();
|
||||||
}
|
}
|
||||||
|
self.set_layout_cursor(cursor);
|
||||||
},
|
},
|
||||||
TextAction::Down => {
|
TextAction::Down => {
|
||||||
//TODO: make this move by layout lines and preserve X as best as possible!
|
//TODO: make this preserve X as best as possible!
|
||||||
if self.cursor.line.get() + 1 < self.lines.len() {
|
let mut cursor = self.layout_cursor(&self.cursor);
|
||||||
self.cursor.line = TextLineIndex::new(self.cursor.line.get() + 1);
|
let layout_len = {
|
||||||
self.cursor.index = 0;
|
let line = &mut self.lines[cursor.line.get()];
|
||||||
self.redraw = true;
|
let layout = line.layout(
|
||||||
|
&mut self.font_matches,
|
||||||
|
self.metrics.font_size,
|
||||||
|
self.width
|
||||||
|
);
|
||||||
|
layout.len()
|
||||||
|
};
|
||||||
|
if cursor.layout + 1 < layout_len {
|
||||||
|
cursor.layout += 1;
|
||||||
|
} else if cursor.line.get() + 1 < self.lines.len() {
|
||||||
|
cursor.line = TextLineIndex::new(cursor.line.get() + 1);
|
||||||
|
cursor.layout = 0;
|
||||||
}
|
}
|
||||||
|
self.set_layout_cursor(cursor);
|
||||||
},
|
},
|
||||||
TextAction::Home => {
|
TextAction::Home => {
|
||||||
todo!("home");
|
let mut cursor = self.layout_cursor(&self.cursor);
|
||||||
|
cursor.glyph = 0;
|
||||||
|
self.set_layout_cursor(cursor);
|
||||||
},
|
},
|
||||||
TextAction::End => {
|
TextAction::End => {
|
||||||
todo!("end");
|
let mut cursor = self.layout_cursor(&self.cursor);
|
||||||
|
cursor.glyph = usize::max_value();
|
||||||
|
self.set_layout_cursor(cursor);
|
||||||
}
|
}
|
||||||
TextAction::PageUp => {
|
TextAction::PageUp => {
|
||||||
//TODO: move cursor
|
//TODO: move cursor
|
||||||
|
|
@ -664,6 +770,12 @@ impl<'a> TextBuffer<'a> {
|
||||||
{
|
{
|
||||||
let font_size = self.metrics.font_size;
|
let font_size = self.metrics.font_size;
|
||||||
let line_height = self.metrics.line_height;
|
let line_height = self.metrics.line_height;
|
||||||
|
/*TODO
|
||||||
|
let layout_cursor = self.layout_cursor(&self.cursor);
|
||||||
|
let layout_select_opt = self.select_opt.as_ref().map(|cursor| {
|
||||||
|
self.layout_cursor(cursor)
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
let mut line_y = font_size;
|
let mut line_y = font_size;
|
||||||
let mut layout_i = 0;
|
let mut layout_i = 0;
|
||||||
|
|
@ -675,9 +787,7 @@ impl<'a> TextBuffer<'a> {
|
||||||
|
|
||||||
let layout = match line.layout_opt.as_ref() {
|
let layout = match line.layout_opt.as_ref() {
|
||||||
Some(some) => some,
|
Some(some) => some,
|
||||||
None => {
|
None => break,
|
||||||
return
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for layout_line in layout {
|
for layout_line in layout {
|
||||||
|
|
@ -808,6 +918,7 @@ impl<'a> TextBuffer<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw cursor
|
// Draw cursor
|
||||||
|
//TODO: draw at end of line but not start of next line
|
||||||
if let Some(cursor_glyph) = cursor_glyph_opt(&self.cursor) {
|
if let Some(cursor_glyph) = cursor_glyph_opt(&self.cursor) {
|
||||||
let x = match layout_line.glyphs.get(cursor_glyph) {
|
let x = match layout_line.glyphs.get(cursor_glyph) {
|
||||||
Some(glyph) => {
|
Some(glyph) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue