WOrking on getting cursor movement working again.
This commit is contained in:
parent
e9c06615f9
commit
26965417f3
|
@ -1,7 +1,7 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use std::mem;
|
||||
use std::path::Path;
|
||||
use std::old_path::Path;
|
||||
use std::old_io::fs::File;
|
||||
use std::old_io::{IoResult, BufferedReader};
|
||||
|
||||
|
@ -485,22 +485,22 @@ impl<'a> BufferGraphemeIter<'a> {
|
|||
self.gi.skip_graphemes(n)
|
||||
}
|
||||
|
||||
pub fn skip_non_newline_graphemes(&mut self, n: usize) -> bool {
|
||||
let mut i: usize = 0;
|
||||
|
||||
for g in self.gi {
|
||||
if is_line_ending(g) {
|
||||
return true;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
if i >= n {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
//pub fn skip_non_newline_graphemes(&mut self, n: usize) -> bool {
|
||||
// let mut i: usize = 0;
|
||||
//
|
||||
// for g in self.gi {
|
||||
// if is_line_ending(g) {
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// i += 1;
|
||||
// if i >= n {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -27,10 +27,8 @@ impl Cursor {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn update_vis_start<'a, T: LineFormatter<'a>>(&mut self, buf: &Buffer, f: &T) {
|
||||
// TODO
|
||||
//let (_, h) = buf.index_to_v2d(self.range.0);
|
||||
//self.vis_start = h;
|
||||
pub fn update_vis_start<T: LineFormatter>(&mut self, buf: &Buffer, f: &T) {
|
||||
self.vis_start = f.index_to_horizontal_v2d(buf, self.range.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ use buffer::Buffer;
|
|||
use buffer::line::LineEnding;
|
||||
use formatter::LineFormatter;
|
||||
use formatter::RoundingBehavior::*;
|
||||
use std::path::Path;
|
||||
use std::old_path::Path;
|
||||
use std::cmp::{min, max};
|
||||
use files::{save_buffer_to_file};
|
||||
use string_utils::grapheme_count;
|
||||
|
@ -13,7 +13,7 @@ use self::cursor::CursorSet;
|
|||
mod cursor;
|
||||
|
||||
|
||||
pub struct Editor<'a, T: LineFormatter<'a>> {
|
||||
pub struct Editor<T: LineFormatter> {
|
||||
pub buffer: Buffer,
|
||||
pub formatter: T,
|
||||
pub file_path: Path,
|
||||
|
@ -31,9 +31,9 @@ pub struct Editor<'a, T: LineFormatter<'a>> {
|
|||
}
|
||||
|
||||
|
||||
impl<'a, T: LineFormatter<'a>> Editor<'a, T> {
|
||||
impl<T: LineFormatter> Editor<T> {
|
||||
/// Create a new blank editor
|
||||
pub fn new(formatter: T) -> Editor<'a, T> {
|
||||
pub fn new(formatter: T) -> Editor<T> {
|
||||
Editor {
|
||||
buffer: Buffer::new(),
|
||||
formatter: formatter,
|
||||
|
@ -300,10 +300,10 @@ impl<'a, T: LineFormatter<'a>> Editor<'a, T> {
|
|||
// there are no cursors currently in view, and should jump to
|
||||
// the closest cursor.
|
||||
|
||||
let gi = self.cursors[0].range.0;
|
||||
//let gi = self.cursors[0].range.0;
|
||||
//let vho = self.cursors[0].vis_start;
|
||||
|
||||
self.view_pos.0 = gi;
|
||||
//self.view_pos.0 = gi;
|
||||
|
||||
// TODO: horizontal offset
|
||||
//self.view_pos.1 = vho;
|
||||
|
@ -336,45 +336,43 @@ impl<'a, T: LineFormatter<'a>> Editor<'a, T> {
|
|||
|
||||
|
||||
pub fn insert_tab_at_cursor(&mut self) {
|
||||
// TODO: update to new formatting code
|
||||
self.cursors.make_consistent();
|
||||
|
||||
//self.cursors.make_consistent();
|
||||
//
|
||||
//if self.soft_tabs {
|
||||
// let mut offset = 0;
|
||||
//
|
||||
// for c in self.cursors.iter_mut() {
|
||||
// // Update cursor with offset
|
||||
// c.range.0 += offset;
|
||||
// c.range.1 += offset;
|
||||
//
|
||||
// // Figure out how many spaces to insert
|
||||
// let (_, vis_pos) = self.buffer.index_to_v2d(c.range.0);
|
||||
// // TODO: handle tab settings
|
||||
// let next_tab_stop = ((vis_pos / self.soft_tab_width as usize) + 1) * self.soft_tab_width as usize;
|
||||
// let space_count = min(next_tab_stop - vis_pos, 8);
|
||||
//
|
||||
//
|
||||
// // Insert spaces
|
||||
// let space_strs = ["", " ", " ", " ", " ", " ", " ", " ", " "];
|
||||
// self.buffer.insert_text(space_strs[space_count], c.range.0);
|
||||
// self.dirty = true;
|
||||
//
|
||||
// // Move cursor
|
||||
// c.range.0 += space_count;
|
||||
// c.range.1 += space_count;
|
||||
// c.update_vis_start(&(self.buffer), &(self.formatter));
|
||||
//
|
||||
// // Update offset
|
||||
// offset += space_count;
|
||||
// }
|
||||
//
|
||||
// // Adjust view
|
||||
// self.move_view_to_cursor();
|
||||
//}
|
||||
//else {
|
||||
// self.insert_text_at_cursor("\t");
|
||||
//}
|
||||
if self.soft_tabs {
|
||||
let mut offset = 0;
|
||||
|
||||
for c in self.cursors.iter_mut() {
|
||||
// Update cursor with offset
|
||||
c.range.0 += offset;
|
||||
c.range.1 += offset;
|
||||
|
||||
// Figure out how many spaces to insert
|
||||
let vis_pos = self.formatter.index_to_horizontal_v2d(&self.buffer, c.range.0);
|
||||
// TODO: handle tab settings
|
||||
let next_tab_stop = ((vis_pos / self.soft_tab_width as usize) + 1) * self.soft_tab_width as usize;
|
||||
let space_count = min(next_tab_stop - vis_pos, 8);
|
||||
|
||||
|
||||
// Insert spaces
|
||||
let space_strs = ["", " ", " ", " ", " ", " ", " ", " ", " "];
|
||||
self.buffer.insert_text(space_strs[space_count], c.range.0);
|
||||
self.dirty = true;
|
||||
|
||||
// Move cursor
|
||||
c.range.0 += space_count;
|
||||
c.range.1 += space_count;
|
||||
c.update_vis_start(&(self.buffer), &(self.formatter));
|
||||
|
||||
// Update offset
|
||||
offset += space_count;
|
||||
}
|
||||
|
||||
// Adjust view
|
||||
self.move_view_to_cursor();
|
||||
}
|
||||
else {
|
||||
self.insert_text_at_cursor("\t");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -556,48 +554,44 @@ impl<'a, T: LineFormatter<'a>> Editor<'a, T> {
|
|||
|
||||
|
||||
pub fn cursor_up(&mut self, n: usize) {
|
||||
// TODO: update to new formatting code
|
||||
for c in self.cursors.iter_mut() {
|
||||
let vmove = -1 * (n * self.formatter.single_line_height()) as isize;
|
||||
let mut temp_index = self.formatter.index_offset_vertical_v2d(&self.buffer, c.range.0, vmove, (Round, Round));
|
||||
|
||||
//for c in self.cursors.iter_mut() {
|
||||
// let vmove = n * self.buffer.formatter.single_line_height();
|
||||
// let (v, _) = self.buffer.index_to_v2d(c.range.0);
|
||||
//
|
||||
// if vmove <= v {
|
||||
// c.range.0 = self.buffer.v2d_to_index((v - vmove, c.vis_start), (Floor, Floor));
|
||||
// c.range.1 = c.range.0;
|
||||
// }
|
||||
// else {
|
||||
// c.range = (0, 0);
|
||||
// c.update_vis_start(&(self.buffer), &(self.formatter));
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//// Adjust view
|
||||
//self.move_view_to_cursor();
|
||||
if temp_index == 0 {
|
||||
c.update_vis_start(&(self.buffer), &(self.formatter));
|
||||
}
|
||||
else {
|
||||
temp_index = self.formatter.index_set_horizontal_v2d(&self.buffer, temp_index, c.vis_start, Round);
|
||||
}
|
||||
|
||||
c.range.0 = temp_index;
|
||||
c.range.1 = temp_index;
|
||||
}
|
||||
|
||||
// Adjust view
|
||||
self.move_view_to_cursor();
|
||||
}
|
||||
|
||||
|
||||
pub fn cursor_down(&mut self, n: usize) {
|
||||
// TODO: update to new formatting code
|
||||
for c in self.cursors.iter_mut() {
|
||||
let vmove = (n * self.formatter.single_line_height()) as isize;
|
||||
let mut temp_index = self.formatter.index_offset_vertical_v2d(&self.buffer, c.range.0, vmove, (Round, Round));
|
||||
|
||||
//for c in self.cursors.iter_mut() {
|
||||
// let vmove = n * self.buffer.formatter.single_line_height();
|
||||
// let (v, _) = self.buffer.index_to_v2d(c.range.0);
|
||||
// let (h, _) = self.buffer.dimensions();
|
||||
//
|
||||
// if vmove < (h - v) {
|
||||
// c.range.0 = self.buffer.v2d_to_index((v + vmove, c.vis_start), (Floor, Floor));
|
||||
// c.range.1 = c.range.0;
|
||||
// }
|
||||
// else {
|
||||
// let end = self.buffer.grapheme_count();
|
||||
// c.range = (end, end);
|
||||
// c.update_vis_start(&(self.buffer), &(self.formatter));
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//// Adjust view
|
||||
//self.move_view_to_cursor();
|
||||
if temp_index == self.buffer.grapheme_count() {
|
||||
c.update_vis_start(&(self.buffer), &(self.formatter));
|
||||
}
|
||||
else {
|
||||
temp_index = self.formatter.index_set_horizontal_v2d(&self.buffer, temp_index, c.vis_start, Round);
|
||||
}
|
||||
|
||||
c.range.0 = temp_index;
|
||||
c.range.1 = temp_index;
|
||||
}
|
||||
|
||||
// Adjust view
|
||||
self.move_view_to_cursor();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::old_io::{IoResult, BufferedWriter};
|
||||
use std::old_io::fs::File;
|
||||
use std::path::Path;
|
||||
use std::old_path::Path;
|
||||
|
||||
use buffer::line::{line_ending_to_str};
|
||||
use buffer::Buffer as TextBuffer;
|
||||
|
|
277
src/formatter.rs
277
src/formatter.rs
|
@ -1,6 +1,7 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use buffer::line::{Line, LineGraphemeIter};
|
||||
use buffer::line::Line;
|
||||
use buffer::Buffer;
|
||||
use std::cmp::max;
|
||||
|
||||
#[derive(Copy, PartialEq)]
|
||||
|
@ -11,160 +12,178 @@ pub enum RoundingBehavior {
|
|||
}
|
||||
|
||||
|
||||
pub trait LineFormatter<'a> {
|
||||
// The iterator yields the grapheme, the 2d position of the grapheme, and the grapheme's width
|
||||
type Iter: Iterator<Item=(&'a str, (usize, usize), usize)> + 'a;
|
||||
|
||||
pub trait LineFormatter {
|
||||
fn single_line_height(&self) -> usize;
|
||||
|
||||
fn iter(&'a self, line: &'a Line) -> Self::Iter;
|
||||
|
||||
|
||||
/// Returns the 2d visual dimensions of the given line when formatted
|
||||
/// by the formatter.
|
||||
fn dimensions(&'a self, line: &'a Line) -> (usize, usize) {
|
||||
let mut dim: (usize, usize) = (0, 0);
|
||||
|
||||
for (_, pos, width) in self.iter(line) {
|
||||
dim = (max(dim.0, pos.0), max(dim.1, pos.1 + width));
|
||||
}
|
||||
|
||||
dim.0 += self.single_line_height();
|
||||
|
||||
return dim;
|
||||
}
|
||||
fn dimensions(&self, line: &Line) -> (usize, usize);
|
||||
|
||||
|
||||
/// Converts a grapheme index within a line into a visual 2d position.
|
||||
fn index_to_v2d(&'a self, line: &'a Line, index: usize) -> (usize, usize) {
|
||||
let mut pos = (0, 0);
|
||||
let mut i = 0;
|
||||
let mut last_width = 0;
|
||||
|
||||
for (_, _pos, width) in self.iter(line) {
|
||||
pos = _pos;
|
||||
last_width = width;
|
||||
i += 1;
|
||||
|
||||
if i > index {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
return (pos.0, pos.1 + last_width);
|
||||
}
|
||||
fn index_to_v2d(&self, line: &Line, index: usize) -> (usize, usize);
|
||||
|
||||
|
||||
/// Converts a visual 2d position into a grapheme index within a line.
|
||||
fn v2d_to_index(&'a self, line: &'a Line, v2d: (usize, usize), rounding: (RoundingBehavior, RoundingBehavior)) -> usize {
|
||||
fn v2d_to_index(&self, line: &Line, v2d: (usize, usize), rounding: (RoundingBehavior, RoundingBehavior)) -> usize;
|
||||
|
||||
|
||||
fn index_to_horizontal_v2d(&self, buf: &Buffer, index: usize) -> usize {
|
||||
let (line_i, col_i) = buf.index_to_line_col(index);
|
||||
let line = buf.get_line(line_i);
|
||||
return self.index_to_v2d(line, col_i).1;
|
||||
}
|
||||
|
||||
|
||||
/// Takes a grapheme index and a visual vertical offset, and returns the grapheme
|
||||
/// index after that visual offset is applied.
|
||||
fn index_offset_vertical_v2d(&self, buf: &Buffer, index: usize, offset: isize, rounding: (RoundingBehavior, RoundingBehavior)) -> usize {
|
||||
// TODO: handle rounding modes
|
||||
let mut i = 0;
|
||||
// TODO: do this with bidirectional line iterator
|
||||
let (mut line_i, mut col_i) = buf.index_to_line_col(index);
|
||||
let (mut y, x) = self.index_to_v2d(buf.get_line(line_i), col_i);
|
||||
let mut new_y = y as isize + offset;
|
||||
|
||||
for (_, pos, _) in self.iter(line) {
|
||||
if pos.0 > v2d.0 {
|
||||
// First, find the right line while keeping track of the vertical offset
|
||||
let mut line;
|
||||
loop {
|
||||
line = buf.get_line(line_i);
|
||||
let (mut h, _) = self.dimensions(line);
|
||||
|
||||
if new_y >= 0 && new_y < h as isize {
|
||||
y = new_y as usize;
|
||||
break;
|
||||
}
|
||||
else if pos.0 == v2d.0 && pos.1 >= v2d.1 {
|
||||
break;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================================================================
|
||||
// A simple implementation of LineFormatter, and LineFormatIter
|
||||
// for testing purposes.
|
||||
//================================================================
|
||||
|
||||
pub struct TestLineFormatIter<'a> {
|
||||
grapheme_iter: LineGraphemeIter<'a>,
|
||||
f: &'a TestLineFormatter,
|
||||
pos: (usize, usize),
|
||||
}
|
||||
|
||||
impl<'a> Iterator for TestLineFormatIter<'a> {
|
||||
type Item = (&'a str, (usize, usize), usize);
|
||||
|
||||
fn next(&mut self) -> Option<(&'a str, (usize, usize), usize)> {
|
||||
if let Some(g) = self.grapheme_iter.next() {
|
||||
let pos = self.pos;
|
||||
self.pos = (pos.0, pos.1 + 1);
|
||||
return Some((g, pos, 1));
|
||||
}
|
||||
else {
|
||||
return None;
|
||||
if new_y < 0 {
|
||||
// Check for off-the-end
|
||||
if (line_i + 1) >= buf.line_count() {
|
||||
return buf.grapheme_count();
|
||||
}
|
||||
|
||||
line_i += 1;
|
||||
new_y -= h as isize;
|
||||
}
|
||||
else if new_y > 0 {
|
||||
// Check for off-the-end
|
||||
if line_i == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
line_i -= 1;
|
||||
new_y -= h as isize;
|
||||
}
|
||||
else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct TestLineFormatter {
|
||||
tab_width: u8
|
||||
// Next, convert the resulting coordinates back into buffer-wide
|
||||
// coordinates.
|
||||
let col_i = self.v2d_to_index(line, (y, x), rounding);
|
||||
return buf.line_col_to_index((line_i, col_i));
|
||||
}
|
||||
|
||||
impl TestLineFormatter {
|
||||
pub fn new() -> TestLineFormatter {
|
||||
TestLineFormatter {
|
||||
tab_width: 4,
|
||||
}
|
||||
}
|
||||
|
||||
fn index_set_horizontal_v2d(&self, buf: &Buffer, index: usize, horizontal: usize, rounding: RoundingBehavior) -> usize {
|
||||
let (line_i, col_i) = buf.index_to_line_col(index);
|
||||
let line = buf.get_line(line_i);
|
||||
|
||||
let (v, h) = self.index_to_v2d(line, col_i);
|
||||
let new_col_i = self.v2d_to_index(line, (v, horizontal), (RoundingBehavior::Floor, rounding));
|
||||
|
||||
return (index + new_col_i) - col_i;
|
||||
}
|
||||
|
||||
impl<'a> LineFormatter<'a> for TestLineFormatter {
|
||||
type Iter = TestLineFormatIter<'a>;
|
||||
|
||||
fn single_line_height(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn iter(&'a self, line: &'a Line) -> TestLineFormatIter<'a> {
|
||||
TestLineFormatIter {
|
||||
grapheme_iter: line.grapheme_iter(),
|
||||
f: self,
|
||||
pos: (0, 0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
mod tests {
|
||||
#![allow(unused_imports)]
|
||||
use super::{TestLineFormatter, TestLineFormatIter};
|
||||
use buffer::line::Line;
|
||||
//====================================================================
|
||||
// UNIT TESTS
|
||||
//====================================================================
|
||||
|
||||
#[test]
|
||||
fn simple_iterator() {
|
||||
let line = Line::new_from_str("Hello!");
|
||||
let mut f = TestLineFormatter::new();
|
||||
let mut iter = f.iter(&line);
|
||||
|
||||
let (a,_,_) = iter.next().unwrap();
|
||||
assert_eq!(a, "H");
|
||||
|
||||
let (a,_,_) = iter.next().unwrap();
|
||||
assert_eq!(a, "e");
|
||||
|
||||
let (a,_,_) = iter.next().unwrap();
|
||||
assert_eq!(a, "l");
|
||||
|
||||
let (a,_,_) = iter.next().unwrap();
|
||||
assert_eq!(a, "l");
|
||||
|
||||
let (a,_,_) = iter.next().unwrap();
|
||||
assert_eq!(a, "o");
|
||||
|
||||
let (a,_,_) = iter.next().unwrap();
|
||||
assert_eq!(a, "!");
|
||||
|
||||
let a = iter.next();
|
||||
assert_eq!(a, None);
|
||||
}
|
||||
}
|
||||
//#[cfg(test)]
|
||||
//mod tests {
|
||||
// #![allow(unused_imports)]
|
||||
// use buffer::line::{Line, LineGraphemeIter};
|
||||
// use super::LineFormatter;
|
||||
//
|
||||
// pub struct TestLineFormatIter<'a> {
|
||||
// grapheme_iter: LineGraphemeIter<'a>,
|
||||
// f: &'a TestLineFormatter,
|
||||
// pos: (usize, usize),
|
||||
// }
|
||||
//
|
||||
// impl<'a> Iterator for TestLineFormatIter<'a> {
|
||||
// type Item = (&'a str, (usize, usize), usize);
|
||||
//
|
||||
// fn next(&mut self) -> Option<(&'a str, (usize, usize), usize)> {
|
||||
// if let Some(g) = self.grapheme_iter.next() {
|
||||
// let pos = self.pos;
|
||||
// self.pos = (pos.0, pos.1 + 1);
|
||||
// return Some((g, pos, 1));
|
||||
// }
|
||||
// else {
|
||||
// return None;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub struct TestLineFormatter {
|
||||
// tab_width: u8
|
||||
// }
|
||||
//
|
||||
// impl TestLineFormatter {
|
||||
// pub fn new() -> TestLineFormatter {
|
||||
// TestLineFormatter {
|
||||
// tab_width: 4,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl<'a> LineFormatter<'a, TestLineFormatIter<'a>> for TestLineFormatter {
|
||||
// fn single_line_height(&self) -> usize {
|
||||
// 1
|
||||
// }
|
||||
//
|
||||
// fn iter(&'a self, line: &'a Line) -> TestLineFormatIter<'a> {
|
||||
// TestLineFormatIter {
|
||||
// grapheme_iter: line.grapheme_iter(),
|
||||
// f: self,
|
||||
// pos: (0, 0),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// #[test]
|
||||
// fn simple_iterator() {
|
||||
// let line = Line::new_from_str("Hello!");
|
||||
// let mut f = TestLineFormatter::new();
|
||||
// let mut iter = f.iter(&line);
|
||||
//
|
||||
// let (a,_,_) = iter.next().unwrap();
|
||||
// assert_eq!(a, "H");
|
||||
//
|
||||
// let (a,_,_) = iter.next().unwrap();
|
||||
// assert_eq!(a, "e");
|
||||
//
|
||||
// let (a,_,_) = iter.next().unwrap();
|
||||
// assert_eq!(a, "l");
|
||||
//
|
||||
// let (a,_,_) = iter.next().unwrap();
|
||||
// assert_eq!(a, "l");
|
||||
//
|
||||
// let (a,_,_) = iter.next().unwrap();
|
||||
// assert_eq!(a, "o");
|
||||
//
|
||||
// let (a,_,_) = iter.next().unwrap();
|
||||
// assert_eq!(a, "!");
|
||||
//
|
||||
// let a = iter.next();
|
||||
// assert_eq!(a, None);
|
||||
// }
|
||||
//}//
|
|
@ -10,7 +10,7 @@ extern crate "rustc-serialize" as rustc_serialize;
|
|||
//extern crate freetype;
|
||||
//extern crate sdl2;
|
||||
|
||||
use std::path::Path;
|
||||
use std::old_path::Path;
|
||||
use docopt::Docopt;
|
||||
use editor::Editor;
|
||||
use term_ui::TermUI;
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::cmp::max;
|
|||
|
||||
use string_utils::{is_line_ending};
|
||||
use buffer::line::{Line, LineGraphemeIter};
|
||||
use formatter::LineFormatter;
|
||||
use formatter::{LineFormatter, RoundingBehavior};
|
||||
|
||||
//===================================================================
|
||||
// LineFormatter implementation for terminals/consoles.
|
||||
|
@ -21,17 +21,8 @@ impl ConsoleLineFormatter {
|
|||
wrap_width: 40,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a> LineFormatter<'a> for ConsoleLineFormatter {
|
||||
type Iter = ConsoleLineFormatterVisIter<'a>;
|
||||
|
||||
fn single_line_height(&self) -> usize {
|
||||
return 1;
|
||||
}
|
||||
|
||||
fn iter(&'a self, line: &'a Line) -> ConsoleLineFormatterVisIter<'a> {
|
||||
pub fn iter<'a>(&'a self, line: &'a Line) -> ConsoleLineFormatterVisIter<'a> {
|
||||
ConsoleLineFormatterVisIter {
|
||||
grapheme_iter: line.grapheme_iter(),
|
||||
f: self,
|
||||
|
@ -41,6 +32,66 @@ impl<'a> LineFormatter<'a> for ConsoleLineFormatter {
|
|||
}
|
||||
|
||||
|
||||
impl LineFormatter for ConsoleLineFormatter {
|
||||
fn single_line_height(&self) -> usize {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
fn dimensions(&self, line: &Line) -> (usize, usize) {
|
||||
let mut dim: (usize, usize) = (0, 0);
|
||||
|
||||
for (_, pos, width) in self.iter(line) {
|
||||
dim = (max(dim.0, pos.0), max(dim.1, pos.1 + width));
|
||||
}
|
||||
|
||||
dim.0 += self.single_line_height();
|
||||
|
||||
return dim;
|
||||
}
|
||||
|
||||
|
||||
fn index_to_v2d(&self, line: &Line, index: usize) -> (usize, usize) {
|
||||
let mut pos = (0, 0);
|
||||
let mut i = 0;
|
||||
let mut last_width = 0;
|
||||
|
||||
for (_, _pos, width) in self.iter(line) {
|
||||
pos = _pos;
|
||||
last_width = width;
|
||||
i += 1;
|
||||
|
||||
if i > index {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
return (pos.0, pos.1 + last_width);
|
||||
}
|
||||
|
||||
|
||||
fn v2d_to_index(&self, line: &Line, v2d: (usize, usize), rounding: (RoundingBehavior, RoundingBehavior)) -> usize {
|
||||
// TODO: handle rounding modes
|
||||
let mut i = 0;
|
||||
let mut pos = (0, 0);
|
||||
|
||||
for (_, _pos, _) in self.iter(line) {
|
||||
pos = _pos;
|
||||
if pos.0 > v2d.0 {
|
||||
break;
|
||||
}
|
||||
else if pos.0 == v2d.0 && pos.1 >= v2d.1 {
|
||||
break;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// An iterator that iterates over the graphemes in a line in a
|
||||
// manner consistent with the ConsoleFormatter.
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::char;
|
|||
use std::time::duration::Duration;
|
||||
use string_utils::{is_line_ending};
|
||||
use buffer::line::{line_ending_to_str, LineEnding};
|
||||
use self::formatter::ConsoleLineFormatter;
|
||||
use self::formatter::{ConsoleLineFormatter, ConsoleLineFormatterVisIter};
|
||||
|
||||
pub mod formatter;
|
||||
|
||||
|
@ -33,16 +33,16 @@ const K_CTRL_Y: u16 = 25;
|
|||
const K_CTRL_Z: u16 = 26;
|
||||
|
||||
|
||||
pub struct TermUI<'a> {
|
||||
pub struct TermUI {
|
||||
rb: rustbox::RustBox,
|
||||
editor: Editor<'a, ConsoleLineFormatter>,
|
||||
editor: Editor<ConsoleLineFormatter>,
|
||||
width: usize,
|
||||
height: usize,
|
||||
}
|
||||
|
||||
|
||||
impl<'a> TermUI<'a> {
|
||||
pub fn new() -> TermUI<'a> {
|
||||
impl TermUI {
|
||||
pub fn new() -> TermUI {
|
||||
let rb = match rustbox::RustBox::init(&[Some(rustbox::InitOption::BufferStderr)]) {
|
||||
Ok(rbox) => rbox,
|
||||
Err(_) => panic!("Could not create Rustbox instance."),
|
||||
|
@ -288,7 +288,7 @@ impl<'a> TermUI<'a> {
|
|||
|
||||
// Jump to line!
|
||||
if confirm {
|
||||
if let Some(n) = line.parse() {
|
||||
if let Ok(n) = line.parse() {
|
||||
let n2: usize = n; // Weird work-around: the type of n wasn't being inferred
|
||||
if n2 > 0 {
|
||||
self.editor.jump_to_line(n2-1);
|
||||
|
|
Loading…
Reference in New Issue
Block a user