Scrolling in the editor by following the cursor now works.
This commit is contained in:
parent
833e92c5a0
commit
74cd79745f
|
@ -61,6 +61,7 @@ impl TextBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Creates an iterator at the first character
|
||||||
pub fn root_iter<'a>(&'a self) -> TextBufferIter<'a> {
|
pub fn root_iter<'a>(&'a self) -> TextBufferIter<'a> {
|
||||||
let mut node_stack: Vec<&'a TextNode> = Vec::new();
|
let mut node_stack: Vec<&'a TextNode> = Vec::new();
|
||||||
let mut cur_node = &self.root;
|
let mut cur_node = &self.root;
|
||||||
|
@ -86,6 +87,49 @@ impl TextBuffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Creates an iterator starting at the specified character index.
|
||||||
|
/// If the index is past the end of the text, then the iterator will
|
||||||
|
/// return None on next().
|
||||||
|
pub fn iter_at_char<'a>(&'a self, index: uint) -> TextBufferIter<'a> {
|
||||||
|
let mut node_stack: Vec<&'a TextNode> = Vec::new();
|
||||||
|
let mut cur_node = &self.root;
|
||||||
|
let mut char_i = index;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match cur_node.data {
|
||||||
|
TextNodeData::Leaf(_) => {
|
||||||
|
let mut char_iter = match cur_node.data {
|
||||||
|
TextNodeData::Leaf(ref tb) => tb.as_str().chars(),
|
||||||
|
_ => panic!("This should never happen.")
|
||||||
|
};
|
||||||
|
|
||||||
|
while char_i > 0 {
|
||||||
|
char_iter.next();
|
||||||
|
char_i -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TextBufferIter {
|
||||||
|
node_stack: node_stack,
|
||||||
|
cur_block: char_iter,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
TextNodeData::Branch(ref left, ref right) => {
|
||||||
|
if left.char_count > char_i {
|
||||||
|
node_stack.push(&(**right));
|
||||||
|
cur_node = &(**left);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cur_node = &(**right);
|
||||||
|
char_i -= left.char_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Show for TextBuffer {
|
impl fmt::Show for TextBuffer {
|
||||||
|
@ -129,6 +173,30 @@ impl<'a> TextBufferIter<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Skips the iterator n characters ahead, unless it hits a newline
|
||||||
|
// character. If it hits a newline character, returns true, otherwise,
|
||||||
|
// false.
|
||||||
|
pub fn skip_non_newline_chars(&mut self, n: uint) -> bool {
|
||||||
|
// TODO: more efficient implementation, taking advantage of rope
|
||||||
|
// structure.
|
||||||
|
for _ in range(0, n) {
|
||||||
|
match self.next() {
|
||||||
|
Option::Some(c) => {
|
||||||
|
if c == '\n' {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Option::None => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,26 @@ impl Editor {
|
||||||
self.view_dim = (h, w);
|
self.view_dim = (h, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Moves the editor's view the minimum amount to show the cursor
|
||||||
|
pub fn move_view_to_cursor(&mut self) {
|
||||||
|
// Horizontal
|
||||||
|
if self.cursor.1 < self.view_pos.1 {
|
||||||
|
self.view_pos.1 = self.cursor.1;
|
||||||
|
}
|
||||||
|
else if self.cursor.1 >= (self.view_pos.1 + self.view_dim.1) {
|
||||||
|
self.view_pos.1 = 1 + self.cursor.1 - self.view_dim.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vertical
|
||||||
|
if self.cursor.0 < self.view_pos.0 {
|
||||||
|
self.view_pos.0 = self.cursor.0;
|
||||||
|
}
|
||||||
|
else if self.cursor.0 >= (self.view_pos.0 + self.view_dim.0) {
|
||||||
|
self.view_pos.0 = 1 + self.cursor.0 - self.view_dim.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn insert_text_at_cursor(&mut self, text: &str) {
|
pub fn insert_text_at_cursor(&mut self, text: &str) {
|
||||||
let pos = self.buffer.pos_2d_to_closest_1d(self.cursor);
|
let pos = self.buffer.pos_2d_to_closest_1d(self.cursor);
|
||||||
let str_len = char_count(text);
|
let str_len = char_count(text);
|
||||||
|
@ -68,6 +88,8 @@ impl Editor {
|
||||||
|
|
||||||
// Move cursor
|
// Move cursor
|
||||||
self.cursor = self.buffer.pos_1d_to_closest_2d(p + str_len);
|
self.cursor = self.buffer.pos_1d_to_closest_2d(p + str_len);
|
||||||
|
|
||||||
|
self.move_view_to_cursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_text_at_char(&mut self, text: &str, pos: uint) {
|
pub fn insert_text_at_char(&mut self, text: &str, pos: uint) {
|
||||||
|
@ -87,6 +109,8 @@ impl Editor {
|
||||||
self.buffer.remove_text(pos_a, pos_b);
|
self.buffer.remove_text(pos_a, pos_b);
|
||||||
|
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
|
|
||||||
|
self.move_view_to_cursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_left(&mut self) {
|
pub fn cursor_left(&mut self) {
|
||||||
|
@ -98,22 +122,30 @@ impl Editor {
|
||||||
else {
|
else {
|
||||||
self.cursor = self.buffer.pos_1d_to_closest_2d(0);
|
self.cursor = self.buffer.pos_1d_to_closest_2d(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.move_view_to_cursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_right(&mut self) {
|
pub fn cursor_right(&mut self) {
|
||||||
let p = self.buffer.pos_2d_to_closest_1d(self.cursor);
|
let p = self.buffer.pos_2d_to_closest_1d(self.cursor);
|
||||||
self.cursor = self.buffer.pos_1d_to_closest_2d(p + 1);
|
self.cursor = self.buffer.pos_1d_to_closest_2d(p + 1);
|
||||||
|
|
||||||
|
self.move_view_to_cursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_up(&mut self) {
|
pub fn cursor_up(&mut self) {
|
||||||
if self.cursor.0 > 0 {
|
if self.cursor.0 > 0 {
|
||||||
self.cursor.0 -= 1;
|
self.cursor.0 -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.move_view_to_cursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_down(&mut self) {
|
pub fn cursor_down(&mut self) {
|
||||||
if self.cursor.0 < self.buffer.newline_count() {
|
if self.cursor.0 < self.buffer.newline_count() {
|
||||||
self.cursor.0 += 1;
|
self.cursor.0 += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.move_view_to_cursor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ impl TermUI {
|
||||||
|
|
||||||
let mut width = self.rb.width();
|
let mut width = self.rb.width();
|
||||||
let mut height = self.rb.height();
|
let mut height = self.rb.height();
|
||||||
|
self.editor.update_dim(height, width);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Draw the editor to screen
|
// Draw the editor to screen
|
||||||
|
@ -121,6 +122,7 @@ impl TermUI {
|
||||||
Ok(rustbox::Event::ResizeEvent(w, h)) => {
|
Ok(rustbox::Event::ResizeEvent(w, h)) => {
|
||||||
width = w as uint;
|
width = w as uint;
|
||||||
height = h as uint;
|
height = h as uint;
|
||||||
|
self.editor.update_dim(height, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -140,12 +142,14 @@ impl TermUI {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_editor(&self, editor: &Editor, c1: (uint, uint), c2: (uint, uint)) {
|
pub fn draw_editor(&self, editor: &Editor, c1: (uint, uint), c2: (uint, uint)) {
|
||||||
let mut tb_iter = editor.buffer.root_iter();
|
let mut tb_iter = editor.buffer.iter_at_char(editor.buffer.pos_2d_to_closest_1d(editor.view_pos));
|
||||||
let mut line: uint = 0;
|
let mut pline = c1.0;
|
||||||
let mut column: uint = 0;
|
let mut pcol = c1.1;
|
||||||
let mut pos: uint = 0;
|
let mut line = editor.view_pos.0;
|
||||||
let height = c2.0 - c1.0;
|
let mut column = editor.view_pos.1;
|
||||||
let width = c2.1 - c1.1;
|
let mut pos = editor.buffer.pos_2d_to_closest_1d(editor.view_pos);
|
||||||
|
let max_line = line + (c2.0 - c1.0);
|
||||||
|
let max_col = column + (c2.1 - c1.1);
|
||||||
|
|
||||||
let cursor_pos = editor.buffer.pos_2d_to_closest_1d(editor.cursor);
|
let cursor_pos = editor.buffer.pos_2d_to_closest_1d(editor.cursor);
|
||||||
|
|
||||||
|
@ -153,20 +157,23 @@ impl TermUI {
|
||||||
if let Option::Some(c) = tb_iter.next() {
|
if let Option::Some(c) = tb_iter.next() {
|
||||||
if c == '\n' {
|
if c == '\n' {
|
||||||
if pos == cursor_pos {
|
if pos == cursor_pos {
|
||||||
self.rb.print(column, line, rustbox::RB_NORMAL, Color::Black, Color::White, " ".to_string().as_slice());
|
self.rb.print(pcol, pline, rustbox::RB_NORMAL, Color::Black, Color::White, " ".to_string().as_slice());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pline += 1;
|
||||||
|
pcol = c1.1;
|
||||||
line += 1;
|
line += 1;
|
||||||
column = 0;
|
column = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if pos == cursor_pos {
|
if pos == cursor_pos {
|
||||||
self.rb.print(column, line, rustbox::RB_NORMAL, Color::Black, Color::White, c.to_string().as_slice());
|
self.rb.print(pcol, pline, rustbox::RB_NORMAL, Color::Black, Color::White, c.to_string().as_slice());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self.rb.print(column, line, rustbox::RB_NORMAL, Color::White, Color::Black, c.to_string().as_slice());
|
self.rb.print(pcol, pline, rustbox::RB_NORMAL, Color::White, Color::Black, c.to_string().as_slice());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pcol += 1;
|
||||||
column += 1;
|
column += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,24 +181,57 @@ impl TermUI {
|
||||||
// Show cursor at end of document if it's past the end of
|
// Show cursor at end of document if it's past the end of
|
||||||
// the document
|
// the document
|
||||||
if cursor_pos >= pos {
|
if cursor_pos >= pos {
|
||||||
self.rb.print(column, line, rustbox::RB_NORMAL, Color::Black, Color::White, " ");
|
self.rb.print(pcol, pline, rustbox::RB_NORMAL, Color::Black, Color::White, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos += 1;
|
if line > max_line {
|
||||||
|
return;
|
||||||
if line > height {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if column > width {
|
// If we're past the edge of the display, go to the next line
|
||||||
|
if column > max_col {
|
||||||
tb_iter.next_line();
|
tb_iter.next_line();
|
||||||
|
|
||||||
|
pline += 1;
|
||||||
|
pcol = c1.1;
|
||||||
line += 1;
|
line += 1;
|
||||||
column = 0;
|
column = 0;
|
||||||
|
|
||||||
|
if line > max_line {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're before the edge of the display, move forward to get
|
||||||
|
// to it.
|
||||||
|
loop {
|
||||||
|
if column < editor.view_pos.1 {
|
||||||
|
let nl = tb_iter.skip_non_newline_chars(editor.view_pos.1);
|
||||||
|
if !nl {
|
||||||
|
column = editor.view_pos.1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pline += 1;
|
||||||
|
line += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if line > max_line {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the 1d position of the char to be printed next
|
||||||
pos = editor.buffer.pos_2d_to_closest_1d((line, column));
|
pos = editor.buffer.pos_2d_to_closest_1d((line, column));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user