Updated to work with more recent library versions. Also RustFmt.

This commit is contained in:
Nathan Vegdahl 2016-03-05 02:40:01 -08:00
parent f1ffc2867a
commit 45e6125bbc
13 changed files with 1582 additions and 1137 deletions

2
.gitignore vendored
View File

@ -1,3 +1,3 @@
/target /target
/Cargo.lock *.rs.bk
.zedstate .zedstate

247
Cargo.lock generated Normal file
View File

@ -0,0 +1,247 @@
[root]
name = "Led"
version = "0.0.1"
dependencies = [
"docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
"ropey 0.3.0 (git+https://github.com/cessen/ropey.git)",
"rustbox 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "aho-corasick"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "docopt"
version = "0.6.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"regex 0.1.55 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "encoding"
version = "0.2.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"encoding-index-japanese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding-index-korean 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding-index-simpchinese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding-index-singlebyte 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding-index-tradchinese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "encoding-index-japanese"
version = "1.20141219.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "encoding-index-korean"
version = "1.20141219.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "encoding-index-simpchinese"
version = "1.20141219.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "encoding-index-singlebyte"
version = "1.20141219.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "encoding-index-tradchinese"
version = "1.20141219.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "encoding_index_tests"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gag"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libc"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.1.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ropey"
version = "0.3.0"
source = "git+https://github.com/cessen/ropey.git#aa4dcf8d39d77f295126eed77d56f4b93a069b49"
dependencies = [
"unicode-segmentation 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustbox"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gag 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
"termbox-sys 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-serialize"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc_version"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "tempfile"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termbox-sys"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-segmentation"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "utf8-ranges"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

View File

@ -18,10 +18,9 @@ git = "https://github.com/cessen/ropey.git"
#git = "https://github.com/PistonDevelopers/freetype-rs.git" #git = "https://github.com/PistonDevelopers/freetype-rs.git"
[dependencies] [dependencies]
time = "0.1.30"
rustc-serialize = "0.3.0" rustc-serialize = "0.3.0"
unicode-segmentation = "0.1.*" unicode-segmentation = "0.1"
unicode-width = "0.1.*" unicode-width = "0.1"
docopt = "0.6.*" docopt = "0.6"
encoding = "*" encoding = "0.2"
rustbox = "0.6.3" rustbox = "0.8"

View File

@ -8,7 +8,7 @@ use std::io;
use std::io::{BufReader, BufWriter, Read, Write}; use std::io::{BufReader, BufWriter, Read, Write};
use ropey::{Rope, RopeSlice, RopeGraphemeIter, RopeLineIter}; use ropey::{Rope, RopeSlice, RopeGraphemeIter, RopeLineIter};
use self::undo_stack::{UndoStack}; use self::undo_stack::UndoStack;
use self::undo_stack::Operation::*; use self::undo_stack::Operation::*;
use string_utils::grapheme_count; use string_utils::grapheme_count;
@ -124,9 +124,9 @@ impl Buffer {
// Push operation to the undo stack // Push operation to the undo stack
self.undo_stack.push(RemoveTextBefore(removed_text, cpos_b)); self.undo_stack.push(RemoveTextBefore(removed_text, cpos_b));
} } else {
else { panic!("Buffer::remove_text_before(): attempt to remove text before beginning of \
panic!("Buffer::remove_text_before(): attempt to remove text before beginning of buffer."); buffer.");
} }
} }
@ -240,20 +240,17 @@ impl Buffer {
else { else {
let a = if line_a > 0 { let a = if line_a > 0 {
self.text.line_index_to_char_index(line_a) - 1 self.text.line_index_to_char_index(line_a) - 1
} } else {
else {
0 0
}; };
let b = if line_b < self.line_count() { let b = if line_b < self.line_count() {
if line_a > 0 { if line_a > 0 {
self.text.line_index_to_char_index(line_b) - 1 self.text.line_index_to_char_index(line_b) - 1
} } else {
else {
self.text.line_index_to_char_index(line_b) self.text.line_index_to_char_index(line_b)
} }
} } else {
else {
self.text.char_count() self.text.char_count()
}; };
@ -277,28 +274,28 @@ impl Buffer {
let size = grapheme_count(&s[..]); let size = grapheme_count(&s[..]);
self._remove_text(p, p + size); self._remove_text(p, p + size);
return Some(p); return Some(p);
}, }
RemoveTextBefore(ref s, p) => { RemoveTextBefore(ref s, p) => {
let size = grapheme_count(&s[..]); let size = grapheme_count(&s[..]);
self._insert_text(&s[..], p); self._insert_text(&s[..], p);
return Some(p + size); return Some(p + size);
}, }
RemoveTextAfter(ref s, p) => { RemoveTextAfter(ref s, p) => {
self._insert_text(&s[..], p); self._insert_text(&s[..], p);
return Some(p); return Some(p);
}, }
MoveText(pa, pb, pto) => { MoveText(pa, pb, pto) => {
let size = pb - pa; let size = pb - pa;
self._move_text(pto, pto + size, pa); self._move_text(pto, pto + size, pa);
return Some(pa); return Some(pa);
}, }
_ => { _ => {
return None; return None;
}, }
} }
} }
@ -315,22 +312,22 @@ impl Buffer {
let size = grapheme_count(&s[..]); let size = grapheme_count(&s[..]);
self._insert_text(&s[..], p); self._insert_text(&s[..], p);
return Some(p + size); return Some(p + size);
}, }
RemoveTextBefore(ref s, p) | RemoveTextAfter(ref s, p) => { RemoveTextBefore(ref s, p) | RemoveTextAfter(ref s, p) => {
let size = grapheme_count(&s[..]); let size = grapheme_count(&s[..]);
self._remove_text(p, p + size); self._remove_text(p, p + size);
return Some(p); return Some(p);
}, }
MoveText(pa, pb, pto) => { MoveText(pa, pb, pto) => {
self._move_text(pa, pb, pto); self._move_text(pa, pb, pto);
return Some(pa); return Some(pa);
}, }
_ => { _ => {
return None; return None;
}, }
} }
} }
@ -352,8 +349,7 @@ impl Buffer {
// Convert to char index // Convert to char index
let cpos = if pos < self.text.grapheme_count() { let cpos = if pos < self.text.grapheme_count() {
self.text.grapheme_index_to_char_index(pos) self.text.grapheme_index_to_char_index(pos)
} } else {
else {
self.text.char_count() self.text.char_count()
}; };
@ -383,14 +379,12 @@ impl Buffer {
let l_end_pos = if pos.0 < self.text.line_ending_count() { let l_end_pos = if pos.0 < self.text.line_ending_count() {
let temp2 = self.text.line_index_to_char_index(pos.0 + 1); let temp2 = self.text.line_index_to_char_index(pos.0 + 1);
self.text.char_index_to_grapheme_index(temp2) - 1 self.text.char_index_to_grapheme_index(temp2) - 1
} } else {
else {
self.text.grapheme_count() self.text.grapheme_count()
}; };
return min(l_begin_pos + pos.1, l_end_pos); return min(l_begin_pos + pos.1, l_end_pos);
} } else {
else {
return self.text.grapheme_count(); return self.text.grapheme_count();
} }
} }
@ -403,8 +397,7 @@ impl Buffer {
pub fn get_grapheme<'a>(&'a self, index: usize) -> &'a str { pub fn get_grapheme<'a>(&'a self, index: usize) -> &'a str {
if index >= self.grapheme_count() { if index >= self.grapheme_count() {
panic!("Buffer::get_grapheme(): index past last grapheme."); panic!("Buffer::get_grapheme(): index past last grapheme.");
} } else {
else {
return self.text.grapheme_at_index(index); return self.text.grapheme_at_index(index);
} }
} }
@ -418,8 +411,7 @@ impl Buffer {
let a = self.text.line_index_to_char_index(index); let a = self.text.line_index_to_char_index(index);
let b = if (index + 1) < self.line_count() { let b = if (index + 1) < self.line_count() {
self.text.line_index_to_char_index(index + 1) self.text.line_index_to_char_index(index + 1)
} } else {
else {
self.text.char_count() self.text.char_count()
}; };
@ -432,8 +424,7 @@ impl Buffer {
// Bounds checks // Bounds checks
if pos_b < pos_a { if pos_b < pos_a {
panic!("Buffer::string_from_range(): pos_a must be less than or equal to pos_b."); panic!("Buffer::string_from_range(): pos_a must be less than or equal to pos_b.");
} } else if pos_b > self.grapheme_count() {
else if pos_b > self.grapheme_count() {
panic!("Buffer::string_from_range(): specified range is past end of buffer text."); panic!("Buffer::string_from_range(): specified range is past end of buffer text.");
} }
@ -483,8 +474,6 @@ impl Buffer {
pub fn line_iter_at_index<'a>(&'a self, index: usize) -> RopeLineIter<'a> { pub fn line_iter_at_index<'a>(&'a self, index: usize) -> RopeLineIter<'a> {
self.text.line_iter_at_index(index) self.text.line_iter_at_index(index)
} }
} }
@ -1635,4 +1624,3 @@ mod tests {
} }

View File

@ -37,8 +37,7 @@ impl UndoStack {
if let Some(op) = self.stack_a.pop_back() { if let Some(op) = self.stack_a.pop_back() {
self.stack_b.push_back(op.clone()); self.stack_b.push_back(op.clone());
return Some(op); return Some(op);
} } else {
else {
return None; return None;
} }
} }
@ -48,8 +47,7 @@ impl UndoStack {
if let Some(op) = self.stack_b.pop_back() { if let Some(op) = self.stack_b.pop_back() {
self.stack_a.push_back(op.clone()); self.stack_a.push_back(op.clone());
return Some(op); return Some(op);
} } else {
else {
return None; return None;
} }
} }

View File

@ -36,15 +36,13 @@ impl Cursor {
/// A collection of cursors, managed to always be in a consistent /// A collection of cursors, managed to always be in a consistent
/// state for multi-cursor editing. /// state for multi-cursor editing.
pub struct CursorSet { pub struct CursorSet {
cursors: Vec<Cursor> cursors: Vec<Cursor>,
} }
impl CursorSet { impl CursorSet {
pub fn new() -> CursorSet { pub fn new() -> CursorSet {
CursorSet { CursorSet { cursors: vec![Cursor::new()] }
cursors: vec!(Cursor::new()),
}
} }
pub fn add_cursor(&mut self, cursor: Cursor) { pub fn add_cursor(&mut self, cursor: Cursor) {
@ -69,11 +67,9 @@ impl CursorSet {
self.cursors.sort_by(|a, b| { self.cursors.sort_by(|a, b| {
if a.range.0 < b.range.0 { if a.range.0 < b.range.0 {
Ordering::Less Ordering::Less
} } else if a.range.0 > b.range.0 {
else if a.range.0 > b.range.0 {
Ordering::Greater Ordering::Greater
} } else {
else {
Ordering::Equal Ordering::Equal
} }
}); });
@ -84,8 +80,7 @@ impl CursorSet {
if self.cursors[i].range.1 >= self.cursors[i + 1].range.0 { if self.cursors[i].range.1 >= self.cursors[i + 1].range.0 {
self.cursors[i].range.1 = self.cursors[i + 1].range.1; self.cursors[i].range.1 = self.cursors[i + 1].range.1;
self.cursors.remove(i + 1); self.cursors.remove(i + 1);
} } else {
else {
i += 1; i += 1;
} }
} }

View File

@ -55,7 +55,7 @@ impl<T: LineFormatter> Editor<T> {
pub fn new_from_file(formatter: T, path: &Path) -> Editor<T> { pub fn new_from_file(formatter: T, path: &Path) -> Editor<T> {
let buf = match Buffer::new_from_file(path) { let buf = match Buffer::new_from_file(path) {
Ok(b) => {b}, Ok(b) => b,
// TODO: handle un-openable file better // TODO: handle un-openable file better
_ => panic!("Could not open file!"), _ => panic!("Could not open file!"),
}; };
@ -106,39 +106,37 @@ impl<T: LineFormatter> Editor<T> {
let ending = if line.grapheme_count() > 0 { let ending = if line.grapheme_count() > 0 {
let g = line.grapheme_at_index(line.grapheme_count() - 1); let g = line.grapheme_at_index(line.grapheme_count() - 1);
str_to_line_ending(g) str_to_line_ending(g)
} } else {
else {
LineEnding::None LineEnding::None
}; };
// Record which line ending it is // Record which line ending it is
match ending { match ending {
LineEnding::None => { LineEnding::None => {}
},
LineEnding::CRLF => { LineEnding::CRLF => {
line_ending_histogram[0] += 1; line_ending_histogram[0] += 1;
}, }
LineEnding::LF => { LineEnding::LF => {
line_ending_histogram[1] += 1; line_ending_histogram[1] += 1;
}, }
LineEnding::VT => { LineEnding::VT => {
line_ending_histogram[2] += 1; line_ending_histogram[2] += 1;
}, }
LineEnding::FF => { LineEnding::FF => {
line_ending_histogram[3] += 1; line_ending_histogram[3] += 1;
}, }
LineEnding::CR => { LineEnding::CR => {
line_ending_histogram[4] += 1; line_ending_histogram[4] += 1;
}, }
LineEnding::NEL => { LineEnding::NEL => {
line_ending_histogram[5] += 1; line_ending_histogram[5] += 1;
}, }
LineEnding::LS => { LineEnding::LS => {
line_ending_histogram[6] += 1; line_ending_histogram[6] += 1;
}, }
LineEnding::PS => { LineEnding::PS => {
line_ending_histogram[7] += 1; line_ending_histogram[7] += 1;
}, }
} }
// Stop after 100 lines // Stop after 100 lines
@ -193,8 +191,7 @@ impl<T: LineFormatter> Editor<T> {
for g in g_iter { for g in g_iter {
if g == "\t" { if g == "\t" {
count += 1; count += 1;
} } else {
else {
break; break;
} }
} }
@ -206,7 +203,7 @@ impl<T: LineFormatter> Editor<T> {
// Store last line info // Store last line info
last_indent = (true, count); last_indent = (true, count);
}, }
Some(" ") => { Some(" ") => {
// Count leading spaces // Count leading spaces
@ -214,8 +211,7 @@ impl<T: LineFormatter> Editor<T> {
for g in g_iter { for g in g_iter {
if g == " " { if g == " " {
count += 1; count += 1;
} } else {
else {
break; break;
} }
} }
@ -226,17 +222,16 @@ impl<T: LineFormatter> Editor<T> {
let amount = count - last_indent.1; let amount = count - last_indent.1;
if amount < 9 { if amount < 9 {
space_histogram[amount] += 1; space_histogram[amount] += 1;
} } else {
else {
space_histogram[8] += 1; space_histogram[8] += 1;
} }
} }
// Store last line info // Store last line info
last_indent = (false, count); last_indent = (false, count);
}, }
_ => {}, _ => {}
} }
// Stop after 1000 lines // Stop after 1000 lines
@ -263,8 +258,7 @@ impl<T: LineFormatter> Editor<T> {
self.soft_tabs = true; self.soft_tabs = true;
self.soft_tab_width = width as u8; self.soft_tab_width = width as u8;
} } else {
else {
self.soft_tabs = false; self.soft_tabs = false;
} }
} }
@ -283,7 +277,8 @@ impl<T: LineFormatter> Editor<T> {
let line_count_digits = digit_count(self.buffer.line_count() as u32, 10) as usize; let line_count_digits = digit_count(self.buffer.line_count() as u32, 10) as usize;
// Minus 1 vertically for the header, minus one more than the digits in // Minus 1 vertically for the header, minus one more than the digits in
// the line count for the gutter. // the line count for the gutter.
self.view_dim = (self.editor_dim.0 - 1, self.editor_dim.1 - line_count_digits - 1); self.view_dim = (self.editor_dim.0 - 1,
self.editor_dim.1 - line_count_digits - 1);
} }
@ -330,16 +325,23 @@ impl<T: LineFormatter> Editor<T> {
// the closest cursor. // the closest cursor.
// Find the first and last grapheme index visible within the editor. // Find the first and last grapheme index visible within the editor.
let g_first = self.formatter.index_set_horizontal_v2d(&self.buffer, self.view_pos.0, 0, Floor); let g_first = self.formatter
let mut g_last = self.formatter.index_offset_vertical_v2d(&self.buffer, g_first, self.view_dim.0 as isize, (Floor, Floor)); .index_set_horizontal_v2d(&self.buffer, self.view_pos.0, 0, Floor);
g_last = self.formatter.index_set_horizontal_v2d(&self.buffer, g_last, self.view_dim.1, Floor); let mut g_last = self.formatter.index_offset_vertical_v2d(&self.buffer,
g_first,
self.view_dim.0 as isize,
(Floor, Floor));
g_last = self.formatter
.index_set_horizontal_v2d(&self.buffer, g_last, self.view_dim.1, Floor);
// Adjust the view depending on where the cursor is // Adjust the view depending on where the cursor is
if self.cursors[0].range.0 < g_first { if self.cursors[0].range.0 < g_first {
self.view_pos.0 = self.cursors[0].range.0; self.view_pos.0 = self.cursors[0].range.0;
} } else if self.cursors[0].range.0 > g_last {
else if self.cursors[0].range.0 > g_last { self.view_pos.0 = self.formatter.index_offset_vertical_v2d(&self.buffer,
self.view_pos.0 = self.formatter.index_offset_vertical_v2d(&self.buffer, self.cursors[0].range.0, -(self.view_dim.0 as isize), (Floor, Floor)); self.cursors[0].range.0,
-(self.view_dim.0 as isize),
(Floor, Floor));
} }
} }
@ -383,12 +385,14 @@ impl<T: LineFormatter> Editor<T> {
// Figure out how many spaces to insert // Figure out how many spaces to insert
let vis_pos = self.formatter.index_to_horizontal_v2d(&self.buffer, c.range.0); let vis_pos = self.formatter.index_to_horizontal_v2d(&self.buffer, c.range.0);
// TODO: handle tab settings // TODO: handle tab settings
let next_tab_stop = ((vis_pos / self.soft_tab_width as usize) + 1) * self.soft_tab_width as usize; 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); let space_count = min(next_tab_stop - vis_pos, 8);
// Insert spaces // Insert spaces
let space_strs = ["", " ", " ", " ", " ", " ", " ", " ", " "]; let space_strs = ["", " ", " ", " ", " ", " ", " ", " ",
" "];
self.buffer.insert_text(space_strs[space_count], c.range.0); self.buffer.insert_text(space_strs[space_count], c.range.0);
self.dirty = true; self.dirty = true;
@ -403,8 +407,7 @@ impl<T: LineFormatter> Editor<T> {
// Adjust view // Adjust view
self.move_view_to_cursor(); self.move_view_to_cursor();
} } else {
else {
self.insert_text_at_cursor("\t"); self.insert_text_at_cursor("\t");
} }
} }
@ -418,7 +421,12 @@ impl<T: LineFormatter> Editor<T> {
pub fn insert_text_at_grapheme(&mut self, text: &str, pos: usize) { pub fn insert_text_at_grapheme(&mut self, text: &str, pos: usize) {
self.dirty = true; self.dirty = true;
let buf_len = self.buffer.grapheme_count(); let buf_len = self.buffer.grapheme_count();
self.buffer.insert_text(text, if pos < buf_len {pos} else {buf_len}); self.buffer.insert_text(text,
if pos < buf_len {
pos
} else {
buf_len
});
} }
@ -474,7 +482,11 @@ impl<T: LineFormatter> Editor<T> {
return; return;
} }
let max_len = if self.buffer.grapheme_count() > c.range.1 {self.buffer.grapheme_count() - c.range.1} else {0}; let max_len = if self.buffer.grapheme_count() > c.range.1 {
self.buffer.grapheme_count() - c.range.1
} else {
0
};
let len = min(max_len, grapheme_count); let len = min(max_len, grapheme_count);
// Remove text // Remove text
@ -556,8 +568,7 @@ impl<T: LineFormatter> Editor<T> {
for c in self.cursors.iter_mut() { for c in self.cursors.iter_mut() {
if c.range.0 >= n { if c.range.0 >= n {
c.range.0 -= n; c.range.0 -= n;
} } else {
else {
c.range.0 = 0; c.range.0 = 0;
} }
@ -590,13 +601,18 @@ impl<T: LineFormatter> Editor<T> {
pub fn cursor_up(&mut self, n: usize) { pub fn cursor_up(&mut self, n: usize) {
for c in self.cursors.iter_mut() { for c in self.cursors.iter_mut() {
let vmove = -1 * (n * self.formatter.single_line_height()) as isize; 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)); let mut temp_index = self.formatter.index_offset_vertical_v2d(&self.buffer,
c.range.0,
vmove,
(Round, Round));
if temp_index == 0 { if temp_index == 0 {
c.update_vis_start(&(self.buffer), &(self.formatter)); c.update_vis_start(&(self.buffer), &(self.formatter));
} } else {
else { temp_index = self.formatter.index_set_horizontal_v2d(&self.buffer,
temp_index = self.formatter.index_set_horizontal_v2d(&self.buffer, temp_index, c.vis_start, Round); temp_index,
c.vis_start,
Round);
} }
c.range.0 = temp_index; c.range.0 = temp_index;
@ -611,13 +627,18 @@ impl<T: LineFormatter> Editor<T> {
pub fn cursor_down(&mut self, n: usize) { pub fn cursor_down(&mut self, n: usize) {
for c in self.cursors.iter_mut() { for c in self.cursors.iter_mut() {
let vmove = (n * self.formatter.single_line_height()) as isize; 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)); let mut temp_index = self.formatter.index_offset_vertical_v2d(&self.buffer,
c.range.0,
vmove,
(Round, Round));
if temp_index == self.buffer.grapheme_count() { if temp_index == self.buffer.grapheme_count() {
c.update_vis_start(&(self.buffer), &(self.formatter)); c.update_vis_start(&(self.buffer), &(self.formatter));
} } else {
else { temp_index = self.formatter.index_set_horizontal_v2d(&self.buffer,
temp_index = self.formatter.index_set_horizontal_v2d(&self.buffer, temp_index, c.vis_start, Round); temp_index,
c.vis_start,
Round);
} }
c.range.0 = temp_index; c.range.0 = temp_index;
@ -630,8 +651,12 @@ impl<T: LineFormatter> Editor<T> {
pub fn page_up(&mut self) { pub fn page_up(&mut self) {
let move_amount = self.view_dim.0 - max((self.view_dim.0 / 8), self.formatter.single_line_height()); let move_amount = self.view_dim.0 -
self.view_pos.0 = self.formatter.index_offset_vertical_v2d(&self.buffer, self.view_pos.0, -1 * move_amount as isize, (Round, Round)); max((self.view_dim.0 / 8), self.formatter.single_line_height());
self.view_pos.0 = self.formatter.index_offset_vertical_v2d(&self.buffer,
self.view_pos.0,
-1 * move_amount as isize,
(Round, Round));
self.cursor_up(move_amount); self.cursor_up(move_amount);
@ -641,8 +666,12 @@ impl<T: LineFormatter> Editor<T> {
pub fn page_down(&mut self) { pub fn page_down(&mut self) {
let move_amount = self.view_dim.0 - max((self.view_dim.0 / 8), self.formatter.single_line_height()); let move_amount = self.view_dim.0 -
self.view_pos.0 = self.formatter.index_offset_vertical_v2d(&self.buffer, self.view_pos.0, move_amount as isize, (Round, Round)); max((self.view_dim.0 / 8), self.formatter.single_line_height());
self.view_pos.0 = self.formatter.index_offset_vertical_v2d(&self.buffer,
self.view_pos.0,
move_amount as isize,
(Round, Round));
self.cursor_down(move_amount); self.cursor_down(move_amount);
@ -654,7 +683,11 @@ impl<T: LineFormatter> Editor<T> {
pub fn jump_to_line(&mut self, n: usize) { pub fn jump_to_line(&mut self, n: usize) {
let pos = self.buffer.line_col_to_index((n, 0)); let pos = self.buffer.line_col_to_index((n, 0));
self.cursors.truncate(1); self.cursors.truncate(1);
self.cursors[0].range.0 = self.formatter.index_set_horizontal_v2d(&self.buffer, pos, self.cursors[0].vis_start, Round); self.cursors[0].range.0 = self.formatter.index_set_horizontal_v2d(&self.buffer,
pos,
self.cursors[0]
.vis_start,
Round);
self.cursors[0].range.1 = self.cursors[0].range.0; self.cursors[0].range.1 = self.cursors[0].range.0;
// Adjust view // Adjust view

View File

@ -24,8 +24,7 @@ pub trait LineFormatter {
/// Returns the 2d visual dimensions of the given text when formatted /// Returns the 2d visual dimensions of the given text when formatted
/// by the formatter. /// by the formatter.
/// The text to be formatted is passed as a grapheme iterator. /// The text to be formatted is passed as a grapheme iterator.
fn dimensions<'a, T>(&'a self, g_iter: T) -> (usize, usize) fn dimensions<'a, T>(&'a self, g_iter: T) -> (usize, usize) where T: Iterator<Item = &'a str>;
where T: Iterator<Item=&'a str>;
/// Converts a grapheme index within a text into a visual 2d position. /// Converts a grapheme index within a text into a visual 2d position.
@ -36,7 +35,11 @@ pub trait LineFormatter {
/// Converts a visual 2d position into a grapheme index within a text. /// Converts a visual 2d position into a grapheme index within a text.
/// The text to be formatted is passed as a grapheme iterator. /// The text to be formatted is passed as a grapheme iterator.
fn v2d_to_index<'a, T>(&'a self, g_iter: T, v2d: (usize, usize), rounding: (RoundingBehavior, RoundingBehavior)) -> usize fn v2d_to_index<'a, T>(&'a self,
g_iter: T,
v2d: (usize, usize),
rounding: (RoundingBehavior, RoundingBehavior))
-> usize
where T: Iterator<Item = &'a str>; where T: Iterator<Item = &'a str>;
@ -57,7 +60,12 @@ pub trait LineFormatter {
/// Takes a grapheme index and a visual vertical offset, and returns the grapheme /// Takes a grapheme index and a visual vertical offset, and returns the grapheme
/// index after that visual offset is applied. /// index after that visual offset is applied.
fn index_offset_vertical_v2d(&self, buf: &Buffer, index: usize, offset: isize, rounding: (RoundingBehavior, RoundingBehavior)) -> usize { fn index_offset_vertical_v2d(&self,
buf: &Buffer,
index: usize,
offset: isize,
rounding: (RoundingBehavior, RoundingBehavior))
-> usize {
// TODO: handle rounding modes // TODO: handle rounding modes
// TODO: do this with bidirectional line iterator // TODO: do this with bidirectional line iterator
@ -68,7 +76,12 @@ pub trait LineFormatter {
let (line_block, col_i_adjusted) = block_index_and_offset(col_i); let (line_block, col_i_adjusted) = block_index_and_offset(col_i);
let mut line = buf.get_line(line_i); let mut line = buf.get_line(line_i);
let (mut y, x) = self.index_to_v2d(line.grapheme_iter_between_indices(line_block * LINE_BLOCK_LENGTH, min(line.grapheme_count(), (line_block+1) * LINE_BLOCK_LENGTH)), col_i_adjusted); let (mut y, x) =
self.index_to_v2d(line.grapheme_iter_between_indices(line_block * LINE_BLOCK_LENGTH,
min(line.grapheme_count(),
(line_block + 1) *
LINE_BLOCK_LENGTH)),
col_i_adjusted);
// First, find the right line while keeping track of the vertical offset // First, find the right line while keeping track of the vertical offset
let mut new_y = y as isize + offset; let mut new_y = y as isize + offset;
@ -76,13 +89,17 @@ pub trait LineFormatter {
let mut block_index: usize = line_block; let mut block_index: usize = line_block;
loop { loop {
line = buf.get_line(line_i); line = buf.get_line(line_i);
let (h, _) = self.dimensions(line.grapheme_iter_between_indices(block_index * LINE_BLOCK_LENGTH, min(line.grapheme_count(), (block_index+1) * LINE_BLOCK_LENGTH))); let (h, _) =
self.dimensions(line.grapheme_iter_between_indices(block_index *
LINE_BLOCK_LENGTH,
min(line.grapheme_count(),
(block_index + 1) *
LINE_BLOCK_LENGTH)));
if new_y >= 0 && new_y < h as isize { if new_y >= 0 && new_y < h as isize {
y = new_y as usize; y = new_y as usize;
break; break;
} } else {
else {
if new_y > 0 { if new_y > 0 {
let is_last_block = block_index >= last_block_index(line.grapheme_count()); let is_last_block = block_index >= last_block_index(line.grapheme_count());
@ -94,13 +111,11 @@ pub trait LineFormatter {
if is_last_block { if is_last_block {
line_i += 1; line_i += 1;
block_index = 0; block_index = 0;
} } else {
else {
block_index += 1; block_index += 1;
} }
new_y -= h as isize; new_y -= h as isize;
} } else if new_y < 0 {
else if new_y < 0 {
// Check for off-the-end // Check for off-the-end
if block_index == 0 && line_i == 0 { if block_index == 0 && line_i == 0 {
return 0; return 0;
@ -110,14 +125,12 @@ pub trait LineFormatter {
line_i -= 1; line_i -= 1;
line = buf.get_line(line_i); line = buf.get_line(line_i);
block_index = last_block_index(line.grapheme_count()); block_index = last_block_index(line.grapheme_count());
} } else {
else {
block_index -= 1; block_index -= 1;
} }
let (h, _) = self.dimensions(line.grapheme_iter_between_indices(block_index * LINE_BLOCK_LENGTH, min(line.grapheme_count(), (block_index+1) * LINE_BLOCK_LENGTH))); let (h, _) = self.dimensions(line.grapheme_iter_between_indices(block_index * LINE_BLOCK_LENGTH, min(line.grapheme_count(), (block_index+1) * LINE_BLOCK_LENGTH)));
new_y += h as isize; new_y += h as isize;
} } else {
else {
unreachable!(); unreachable!();
} }
} }
@ -125,8 +138,11 @@ pub trait LineFormatter {
// Next, convert the resulting coordinates back into buffer-wide // Next, convert the resulting coordinates back into buffer-wide
// coordinates. // coordinates.
let block_slice = line.slice(block_index * LINE_BLOCK_LENGTH, min(line.grapheme_count(), (block_index+1) * LINE_BLOCK_LENGTH)); let block_slice = line.slice(block_index * LINE_BLOCK_LENGTH,
let block_col_i = min(self.v2d_to_index(block_slice.grapheme_iter(), (y, x), rounding), LINE_BLOCK_LENGTH - 1); min(line.grapheme_count(),
(block_index + 1) * LINE_BLOCK_LENGTH));
let block_col_i = min(self.v2d_to_index(block_slice.grapheme_iter(), (y, x), rounding),
LINE_BLOCK_LENGTH - 1);
col_i = (block_index * LINE_BLOCK_LENGTH) + block_col_i; col_i = (block_index * LINE_BLOCK_LENGTH) + block_col_i;
return buf.line_col_to_index((line_i, col_i)); return buf.line_col_to_index((line_i, col_i));
@ -136,7 +152,12 @@ pub trait LineFormatter {
/// Takes a grapheme index and a desired visual horizontal position, and /// Takes a grapheme index and a desired visual horizontal position, and
/// returns a grapheme index on the same visual line as the given index, /// returns a grapheme index on the same visual line as the given index,
/// but offset to have the desired horizontal position. /// but offset to have the desired horizontal position.
fn index_set_horizontal_v2d(&self, buf: &Buffer, index: usize, horizontal: usize, rounding: RoundingBehavior) -> usize { 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_i, col_i) = buf.index_to_line_col(index);
let line = buf.get_line(line_i); let line = buf.get_line(line_i);
@ -146,15 +167,17 @@ pub trait LineFormatter {
let end_index = min(line.grapheme_count(), start_index + LINE_BLOCK_LENGTH); let end_index = min(line.grapheme_count(), start_index + LINE_BLOCK_LENGTH);
// Calculate the horizontal position // Calculate the horizontal position
let (v, _) = self.index_to_v2d(line.grapheme_iter_between_indices(start_index, end_index), col_i_adjusted); let (v, _) = self.index_to_v2d(line.grapheme_iter_between_indices(start_index, end_index),
let block_col_i = self.v2d_to_index(line.grapheme_iter_between_indices(start_index, end_index), (v, horizontal), (RoundingBehavior::Floor, rounding)); col_i_adjusted);
let block_col_i = self.v2d_to_index(line.grapheme_iter_between_indices(start_index,
end_index),
(v, horizontal),
(RoundingBehavior::Floor, rounding));
let mut new_col_i = start_index + min(block_col_i, LINE_BLOCK_LENGTH - 1); let mut new_col_i = start_index + min(block_col_i, LINE_BLOCK_LENGTH - 1);
// Make sure we're not pushing the index off the end of the line // Make sure we're not pushing the index off the end of the line
if (line_i + 1) < buf.line_count() if (line_i + 1) < buf.line_count() && new_col_i >= line.grapheme_count() &&
&& new_col_i >= line.grapheme_count() line.grapheme_count() > 0 {
&& line.grapheme_count() > 0
{
new_col_i = line.grapheme_count() - 1; new_col_i = line.grapheme_count() - 1;
} }
@ -175,8 +198,7 @@ pub fn last_block_index(gc: usize) -> usize {
if block_count > 0 { if block_count > 0 {
return block_count - 1; return block_count - 1;
} } else {
else {
return 0; return 0;
} }
} }

View File

@ -1,6 +1,5 @@
// #![feature(test)] // #![feature(test)]
extern crate time;
// extern crate test; // extern crate test;
extern crate rustbox; extern crate rustbox;
extern crate docopt; extern crate docopt;
@ -74,13 +73,11 @@ fn main() {
// let mut ui = GUI::new_from_editor(editor); // let mut ui = GUI::new_from_editor(editor);
// ui.main_ui_loop(); // ui.main_ui_loop();
// sdl2::quit(); // sdl2::quit();
} } else {
else {
// Load file, if specified // Load file, if specified
let editor = if let Option::Some(s) = args.arg_file { let editor = if let Option::Some(s) = args.arg_file {
Editor::new_from_file(ConsoleLineFormatter::new(4), &Path::new(&s[..])) Editor::new_from_file(ConsoleLineFormatter::new(4), &Path::new(&s[..]))
} } else {
else {
Editor::new(ConsoleLineFormatter::new(4)) Editor::new(ConsoleLineFormatter::new(4))
}; };

View File

@ -7,16 +7,16 @@ use unicode_segmentation::UnicodeSegmentation;
pub fn is_line_ending(text: &str) -> bool { pub fn is_line_ending(text: &str) -> bool {
match text { match text {
"\u{000D}\u{000A}" "\u{000D}\u{000A}" |
| "\u{000A}" "\u{000A}" |
| "\u{000B}" "\u{000B}" |
| "\u{000C}" "\u{000C}" |
| "\u{000D}" "\u{000D}" |
| "\u{0085}" "\u{0085}" |
| "\u{2028}" "\u{2028}" |
| "\u{2029}" => true, "\u{2029}" => true,
_ => false _ => false,
} }
} }
@ -175,7 +175,8 @@ pub fn insert_text_at_grapheme_index(s: &mut String, text: &str, pos: usize) {
/// Removes the text between the given grapheme indices in the given string. /// Removes the text between the given grapheme indices in the given string.
pub fn remove_text_between_grapheme_indices(s: &mut String, pos_a: usize, pos_b: usize) { pub fn remove_text_between_grapheme_indices(s: &mut String, pos_a: usize, pos_b: usize) {
// Bounds checks // Bounds checks
assert!(pos_a <= pos_b, "remove_text_between_grapheme_indices(): pos_a must be less than or equal to pos_b."); assert!(pos_a <= pos_b,
"remove_text_between_grapheme_indices(): pos_a must be less than or equal to pos_b.");
if pos_a == pos_b { if pos_a == pos_b {
return; return;
@ -250,46 +251,46 @@ pub fn str_to_line_ending(g: &str) -> LineEnding {
// ============== // ==============
// Line endings // Line endings
// ============== // ==============
//
// CRLF // CRLF
"\u{000D}\u{000A}" => { "\u{000D}\u{000A}" => {
return LineEnding::CRLF; return LineEnding::CRLF;
}, }
// LF // LF
"\u{000A}" => { "\u{000A}" => {
return LineEnding::LF; return LineEnding::LF;
}, }
// VT // VT
"\u{000B}" => { "\u{000B}" => {
return LineEnding::VT; return LineEnding::VT;
}, }
// FF // FF
"\u{000C}" => { "\u{000C}" => {
return LineEnding::FF; return LineEnding::FF;
}, }
// CR // CR
"\u{000D}" => { "\u{000D}" => {
return LineEnding::CR; return LineEnding::CR;
}, }
// NEL // NEL
"\u{0085}" => { "\u{0085}" => {
return LineEnding::NEL; return LineEnding::NEL;
}, }
// LS // LS
"\u{2028}" => { "\u{2028}" => {
return LineEnding::LS; return LineEnding::LS;
}, }
// PS // PS
"\u{2029}" => { "\u{2029}" => {
return LineEnding::PS; return LineEnding::PS;
}, }
// Not a line ending // Not a line ending
_ => { _ => {
@ -312,5 +313,4 @@ pub const LINE_ENDINGS: [&'static str; 9] = ["",
"\u{000D}", "\u{000D}",
"\u{0085}", "\u{0085}",
"\u{2028}", "\u{2028}",
"\u{2029}" "\u{2029}"];
];

View File

@ -34,16 +34,15 @@ impl ConsoleLineFormatter {
pub fn set_wrap_width(&mut self, width: usize) { pub fn set_wrap_width(&mut self, width: usize) {
match self.wrap_type { match self.wrap_type {
WrapType::NoWrap => { WrapType::NoWrap => {}
},
WrapType::CharWrap(ref mut w) => { WrapType::CharWrap(ref mut w) => {
*w = width; *w = width;
}, }
WrapType::WordWrap(ref mut w) => { WrapType::WordWrap(ref mut w) => {
*w = width; *w = width;
}, }
} }
} }
@ -105,7 +104,11 @@ impl LineFormatter for ConsoleLineFormatter {
} }
fn v2d_to_index<'a, T>(&'a self, g_iter: T, v2d: (usize, usize), _: (RoundingBehavior, RoundingBehavior)) -> usize fn v2d_to_index<'a, T>(&'a self,
g_iter: T,
v2d: (usize, usize),
_: (RoundingBehavior, RoundingBehavior))
-> usize
where T: Iterator<Item = &'a str> where T: Iterator<Item = &'a str>
{ {
// TODO: handle rounding modes // TODO: handle rounding modes
@ -115,8 +118,7 @@ impl LineFormatter for ConsoleLineFormatter {
if pos.0 > v2d.0 { if pos.0 > v2d.0 {
i -= 1; i -= 1;
break; break;
} } else if pos.0 == v2d.0 && pos.1 >= v2d.1 {
else if pos.0 == v2d.0 && pos.1 >= v2d.1 {
break; break;
} }
@ -159,7 +161,10 @@ where T: Iterator<Item=&'a str>
} }
fn next_charwrap(&mut self, g: &'a str, wrap_width: usize) -> Option<(&'a str, (usize, usize), usize)> { fn next_charwrap(&mut self,
g: &'a str,
wrap_width: usize)
-> Option<(&'a str, (usize, usize), usize)> {
let width = grapheme_vis_width_at_vis_pos(g, self.pos.1, self.f.tab_width as usize); let width = grapheme_vis_width_at_vis_pos(g, self.pos.1, self.f.tab_width as usize);
if (self.pos.1 + width) > wrap_width { if (self.pos.1 + width) > wrap_width {
@ -169,22 +174,23 @@ where T: Iterator<Item=&'a str>
} }
if self.f.maintain_indent { if self.f.maintain_indent {
let pos = (self.pos.0 + self.f.single_line_height(), self.indent + self.f.wrap_additional_indent); let pos = (self.pos.0 + self.f.single_line_height(),
self.pos = (self.pos.0 + self.f.single_line_height(), self.indent + self.f.wrap_additional_indent + width); self.indent + self.f.wrap_additional_indent);
self.pos = (self.pos.0 + self.f.single_line_height(),
self.indent + self.f.wrap_additional_indent + width);
return Some((g, pos, width));
} else {
let pos = (self.pos.0 + self.f.single_line_height(),
self.f.wrap_additional_indent);
self.pos = (self.pos.0 + self.f.single_line_height(),
self.f.wrap_additional_indent + width);
return Some((g, pos, width)); return Some((g, pos, width));
} }
else { } else {
let pos = (self.pos.0 + self.f.single_line_height(), self.f.wrap_additional_indent);
self.pos = (self.pos.0 + self.f.single_line_height(), self.f.wrap_additional_indent + width);
return Some((g, pos, width));
}
}
else {
if !self.indent_found { if !self.indent_found {
if is_whitespace(g) { if is_whitespace(g) {
self.indent += width; self.indent += width;
} } else {
else {
self.indent_found = true; self.indent_found = true;
} }
} }
@ -208,20 +214,18 @@ where T: Iterator<Item=&'a str>
WrapType::NoWrap => { WrapType::NoWrap => {
if let Some(g) = self.grapheme_iter.next() { if let Some(g) = self.grapheme_iter.next() {
return self.next_nowrap(g); return self.next_nowrap(g);
} } else {
else {
return None; return None;
} }
}, }
WrapType::CharWrap(wrap_width) => { WrapType::CharWrap(wrap_width) => {
if let Some(g) = self.grapheme_iter.next() { if let Some(g) = self.grapheme_iter.next() {
return self.next_charwrap(g, wrap_width); return self.next_charwrap(g, wrap_width);
} } else {
else {
return None; return None;
} }
}, }
WrapType::WordWrap(wrap_width) => { WrapType::WordWrap(wrap_width) => {
// Get next word if necessary // Get next word if necessary
@ -230,7 +234,9 @@ where T: Iterator<Item=&'a str>
self.word_buf.truncate(0); self.word_buf.truncate(0);
while let Some(g) = self.grapheme_iter.next() { while let Some(g) = self.grapheme_iter.next() {
self.word_buf.push(g); self.word_buf.push(g);
let width = grapheme_vis_width_at_vis_pos(g, self.pos.1 + word_width, self.f.tab_width as usize); let width = grapheme_vis_width_at_vis_pos(g,
self.pos.1 + word_width,
self.f.tab_width as usize);
word_width += width; word_width += width;
if is_whitespace(g) { if is_whitespace(g) {
break; break;
@ -239,8 +245,7 @@ where T: Iterator<Item=&'a str>
if self.word_buf.len() == 0 { if self.word_buf.len() == 0 {
return None; return None;
} } else if !self.indent_found && !is_whitespace(self.word_buf[0]) {
else if !self.indent_found && !is_whitespace(self.word_buf[0]) {
self.indent_found = true; self.indent_found = true;
} }
@ -252,10 +257,11 @@ where T: Iterator<Item=&'a str>
} }
if self.f.maintain_indent { if self.f.maintain_indent {
self.pos = (self.pos.0 + self.f.single_line_height(), self.indent + self.f.wrap_additional_indent); self.pos = (self.pos.0 + self.f.single_line_height(),
} self.indent + self.f.wrap_additional_indent);
else { } else {
self.pos = (self.pos.0 + self.f.single_line_height(), self.f.wrap_additional_indent); self.pos = (self.pos.0 + self.f.single_line_height(),
self.f.wrap_additional_indent);
} }
} }
@ -266,7 +272,7 @@ where T: Iterator<Item=&'a str>
let g = self.word_buf[self.word_i]; let g = self.word_buf[self.word_i];
self.word_i += 1; self.word_i += 1;
return self.next_charwrap(g, wrap_width); return self.next_charwrap(g, wrap_width);
}, }
} }
} }
} }
@ -284,13 +290,12 @@ fn grapheme_vis_width_at_vis_pos(g: &str, pos: usize, tab_width: usize) -> usize
"\t" => { "\t" => {
let ending_pos = ((pos / tab_width) + 1) * tab_width; let ending_pos = ((pos / tab_width) + 1) * tab_width;
return ending_pos - pos; return ending_pos - pos;
}, }
_ => { _ => {
if is_line_ending(g) { if is_line_ending(g) {
return 1; return 1;
} } else {
else {
return UnicodeWidthStr::width(g); return UnicodeWidthStr::width(g);
} }
} }
@ -319,7 +324,8 @@ mod tests {
f.wrap_additional_indent = 0; f.wrap_additional_indent = 0;
f.set_wrap_width(80); f.set_wrap_width(80);
assert_eq!(f.dimensions(UnicodeSegmentation::graphemes(text, true)), (1, 22)); assert_eq!(f.dimensions(UnicodeSegmentation::graphemes(text, true)),
(1, 22));
} }
@ -333,7 +339,8 @@ mod tests {
f.wrap_additional_indent = 0; f.wrap_additional_indent = 0;
f.set_wrap_width(12); f.set_wrap_width(12);
assert_eq!(f.dimensions(UnicodeSegmentation::graphemes(text, true)), (5, 12)); assert_eq!(f.dimensions(UnicodeSegmentation::graphemes(text, true)),
(5, 12));
} }
@ -347,10 +354,14 @@ mod tests {
f.wrap_additional_indent = 0; f.wrap_additional_indent = 0;
f.set_wrap_width(80); f.set_wrap_width(80);
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 0), (0, 0)); assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 0),
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 5), (0, 5)); (0, 0));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 22), (0, 22)); assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 5),
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 23), (0, 22)); (0, 5));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 22),
(0, 22));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 23),
(0, 22));
} }
@ -364,27 +375,43 @@ mod tests {
f.wrap_additional_indent = 0; f.wrap_additional_indent = 0;
f.set_wrap_width(12); f.set_wrap_width(12);
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 0), (0, 0)); assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 0),
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 5), (0, 5)); (0, 0));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 11), (0, 11)); assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 5),
(0, 5));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 11),
(0, 11));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 12), (1, 0)); assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 12),
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 15), (1, 3)); (1, 0));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 23), (1, 11)); assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 15),
(1, 3));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 23),
(1, 11));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 24), (2, 0)); assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 24),
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 28), (2, 4)); (2, 0));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 35), (2, 11)); assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 28),
(2, 4));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 35),
(2, 11));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 36), (3, 0)); assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 36),
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 43), (3, 7)); (3, 0));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 47), (3, 11)); assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 43),
(3, 7));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 47),
(3, 11));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 48), (4, 0)); assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 48),
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 50), (4, 2)); (4, 0));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 56), (4, 8)); assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 50),
(4, 2));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 56),
(4, 8));
assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 57), (4, 8)); assert_eq!(f.index_to_v2d(UnicodeSegmentation::graphemes(text, true), 57),
(4, 8));
} }
@ -398,12 +425,30 @@ mod tests {
f.wrap_additional_indent = 0; f.wrap_additional_indent = 0;
f.set_wrap_width(80); f.set_wrap_width(80);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (0,0), (Floor, Floor)), 0); assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (0,5), (Floor, Floor)), 5); (0, 0),
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (0,22), (Floor, Floor)), 22); (Floor, Floor)),
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (0,23), (Floor, Floor)), 22); 0);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (1,0), (Floor, Floor)), 22); assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (1,1), (Floor, Floor)), 22); (0, 5),
(Floor, Floor)),
5);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
(0, 22),
(Floor, Floor)),
22);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
(0, 23),
(Floor, Floor)),
22);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
(1, 0),
(Floor, Floor)),
22);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
(1, 1),
(Floor, Floor)),
22);
} }
@ -417,26 +462,74 @@ mod tests {
f.wrap_additional_indent = 0; f.wrap_additional_indent = 0;
f.set_wrap_width(12); f.set_wrap_width(12);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (0,0), (Floor, Floor)), 0); assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (0,11), (Floor, Floor)), 11); (0, 0),
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (0,12), (Floor, Floor)), 11); (Floor, Floor)),
0);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
(0, 11),
(Floor, Floor)),
11);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
(0, 12),
(Floor, Floor)),
11);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (1,0), (Floor, Floor)), 12); assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (1,11), (Floor, Floor)), 23); (1, 0),
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (1,12), (Floor, Floor)), 23); (Floor, Floor)),
12);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
(1, 11),
(Floor, Floor)),
23);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
(1, 12),
(Floor, Floor)),
23);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (2,0), (Floor, Floor)), 24); assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (2,11), (Floor, Floor)), 35); (2, 0),
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (2,12), (Floor, Floor)), 35); (Floor, Floor)),
24);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
(2, 11),
(Floor, Floor)),
35);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
(2, 12),
(Floor, Floor)),
35);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (3,0), (Floor, Floor)), 36); assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (3,11), (Floor, Floor)), 47); (3, 0),
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (3,12), (Floor, Floor)), 47); (Floor, Floor)),
36);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
(3, 11),
(Floor, Floor)),
47);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
(3, 12),
(Floor, Floor)),
47);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (4,0), (Floor, Floor)), 48); assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (4,7), (Floor, Floor)), 55); (4, 0),
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (4,8), (Floor, Floor)), 56); (Floor, Floor)),
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true), (4,9), (Floor, Floor)), 56); 48);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
(4, 7),
(Floor, Floor)),
55);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
(4, 8),
(Floor, Floor)),
56);
assert_eq!(f.v2d_to_index(UnicodeSegmentation::graphemes(text, true),
(4, 9),
(Floor, Floor)),
56);
} }

View File

@ -3,7 +3,7 @@
use rustbox; use rustbox;
use rustbox::Color; use rustbox::Color;
use editor::Editor; use editor::Editor;
use time::Duration; use std::time::Duration;
use formatter::{LineFormatter, LINE_BLOCK_LENGTH, block_index_and_offset}; use formatter::{LineFormatter, LINE_BLOCK_LENGTH, block_index_and_offset};
use std::char; use std::char;
use std::default::Default; use std::default::Default;
@ -116,90 +116,90 @@ impl TermUI {
K_CTRL_Q => { K_CTRL_Q => {
quit = true; quit = true;
break; break;
}, }
K_CTRL_S => { K_CTRL_S => {
self.editor.save_if_dirty(); self.editor.save_if_dirty();
}, }
K_CTRL_Z => { K_CTRL_Z => {
self.editor.undo(); self.editor.undo();
}, }
K_CTRL_Y => { K_CTRL_Y => {
self.editor.redo(); self.editor.redo();
}, }
K_CTRL_L => { K_CTRL_L => {
self.go_to_line_ui_loop(); self.go_to_line_ui_loop();
}, }
K_PAGEUP => { K_PAGEUP => {
self.editor.page_up(); self.editor.page_up();
}, }
K_PAGEDOWN => { K_PAGEDOWN => {
self.editor.page_down(); self.editor.page_down();
}, }
K_UP => { K_UP => {
self.editor.cursor_up(1); self.editor.cursor_up(1);
}, }
K_DOWN => { K_DOWN => {
self.editor.cursor_down(1); self.editor.cursor_down(1);
}, }
K_LEFT => { K_LEFT => {
self.editor.cursor_left(1); self.editor.cursor_left(1);
}, }
K_RIGHT => { K_RIGHT => {
self.editor.cursor_right(1); self.editor.cursor_right(1);
}, }
K_ENTER => { K_ENTER => {
let nl = line_ending_to_str(self.editor.line_ending_type); let nl = line_ending_to_str(self.editor.line_ending_type);
self.editor.insert_text_at_cursor(nl); self.editor.insert_text_at_cursor(nl);
}, }
K_SPACE => { K_SPACE => {
self.editor.insert_text_at_cursor(" "); self.editor.insert_text_at_cursor(" ");
}, }
K_TAB => { K_TAB => {
self.editor.insert_tab_at_cursor(); self.editor.insert_tab_at_cursor();
}, }
K_BACKSPACE => { K_BACKSPACE => {
self.editor.backspace_at_cursor(); self.editor.backspace_at_cursor();
}, }
K_DELETE => { K_DELETE => {
self.editor.remove_text_in_front_of_cursor(1); self.editor.remove_text_in_front_of_cursor(1);
}, }
// Character // Character
0 => { 0 => {
if let Option::Some(c) = char::from_u32(character) { if let Option::Some(c) = char::from_u32(character) {
self.editor.insert_text_at_cursor(&c.to_string()[..]); self.editor.insert_text_at_cursor(&c.to_string()[..]);
} }
}, }
_ => {} _ => {}
} }
}, }
Ok(rustbox::Event::ResizeEvent(w, h)) => { Ok(rustbox::Event::ResizeEvent(w, h)) => {
resize = Some((h as usize, w as usize)); resize = Some((h as usize, w as usize));
}, }
_ => { _ => {
break; break;
} }
} }
e = self.rb.peek_event(Duration::milliseconds(0), true); // Get next event (if any) e = self.rb.peek_event(Duration::from_millis(0), true); // Get next event (if any)
} }
if let Some((h, w)) = resize { if let Some((h, w)) = resize {
@ -236,7 +236,12 @@ impl TermUI {
self.rb.print(i, 0, rustbox::RB_NORMAL, foreground, background, " "); self.rb.print(i, 0, rustbox::RB_NORMAL, foreground, background, " ");
} }
self.rb.print(1, 0, rustbox::RB_NORMAL, foreground, background, prefix); self.rb.print(1, 0, rustbox::RB_NORMAL, foreground, background, prefix);
self.rb.print(prefix.len() + 1, 0, rustbox::RB_NORMAL, foreground, background, &line[..]); self.rb.print(prefix.len() + 1,
0,
rustbox::RB_NORMAL,
foreground,
background,
&line[..]);
self.rb.present(); self.rb.present();
@ -252,16 +257,16 @@ impl TermUI {
K_ESC => { K_ESC => {
cancel = true; cancel = true;
break; break;
}, }
K_ENTER => { K_ENTER => {
confirm = true; confirm = true;
break; break;
}, }
K_BACKSPACE => { K_BACKSPACE => {
line.pop(); line.pop();
}, }
// Character // Character
0 => { 0 => {
@ -270,24 +275,24 @@ impl TermUI {
line.push(c); line.push(c);
} }
} }
}, }
_ => {} _ => {}
} }
}, }
Ok(rustbox::Event::ResizeEvent(w, h)) => { Ok(rustbox::Event::ResizeEvent(w, h)) => {
self.width = w as usize; self.width = w as usize;
self.height = h as usize; self.height = h as usize;
self.editor.update_dim(self.height - 1, self.width); self.editor.update_dim(self.height - 1, self.width);
}, }
_ => { _ => {
break; break;
} }
} }
e = self.rb.peek_event(Duration::milliseconds(0), true); // Get next event (if any) e = self.rb.peek_event(Duration::from_millis(0), true); // Get next event (if any)
} }
@ -302,8 +307,7 @@ impl TermUI {
let n2: usize = n; // Weird work-around: the type of n wasn't being inferred let n2: usize = n; // Weird work-around: the type of n wasn't being inferred
if n2 > 0 { if n2 > 0 {
self.editor.jump_to_line(n2 - 1); self.editor.jump_to_line(n2 - 1);
} } else {
else {
self.editor.jump_to_line(0); self.editor.jump_to_line(0);
} }
} }
@ -313,7 +317,10 @@ impl TermUI {
} }
fn draw_editor(&self, editor: &Editor<ConsoleLineFormatter>, c1: (usize, usize), c2: (usize, usize)) { fn draw_editor(&self,
editor: &Editor<ConsoleLineFormatter>,
c1: (usize, usize),
c2: (usize, usize)) {
let foreground = Color::Black; let foreground = Color::Black;
let background = Color::Cyan; let background = Color::Cyan;
@ -324,21 +331,35 @@ impl TermUI {
// Filename and dirty marker // Filename and dirty marker
let filename = editor.file_path.display(); let filename = editor.file_path.display();
let dirty_char = if editor.dirty {"*"} else {""}; let dirty_char = if editor.dirty {
"*"
} else {
""
};
let name = format!("{}{}", filename, dirty_char); let name = format!("{}{}", filename, dirty_char);
self.rb.print(c1.1 + 1, c1.0, rustbox::RB_NORMAL, foreground, background, &name[..]); self.rb.print(c1.1 + 1,
c1.0,
rustbox::RB_NORMAL,
foreground,
background,
&name[..]);
// Percentage position in document // Percentage position in document
// TODO: use view instead of cursor for calculation if there is more // TODO: use view instead of cursor for calculation if there is more
// than one cursor. // than one cursor.
let percentage: usize = if editor.buffer.grapheme_count() > 0 { let percentage: usize = if editor.buffer.grapheme_count() > 0 {
(((editor.cursors[0].range.0 as f32) / (editor.buffer.grapheme_count() as f32)) * 100.0) as usize (((editor.cursors[0].range.0 as f32) / (editor.buffer.grapheme_count() as f32)) *
} 100.0) as usize
else { } else {
100 100
}; };
let pstring = format!("{}%", percentage); let pstring = format!("{}%", percentage);
self.rb.print(c2.1 - pstring.len(), c1.0, rustbox::RB_NORMAL, foreground, background, &pstring[..]); self.rb.print(c2.1 - pstring.len(),
c1.0,
rustbox::RB_NORMAL,
foreground,
background,
&pstring[..]);
// Text encoding info and tab style // Text encoding info and tab style
let nl = match editor.line_ending_type { let nl = match editor.line_ending_type {
@ -352,21 +373,38 @@ impl TermUI {
LineEnding::LS => "LS", LineEnding::LS => "LS",
LineEnding::PS => "PS", LineEnding::PS => "PS",
}; };
let soft_tabs_str = if editor.soft_tabs {"spaces"} else {"tabs"}; let soft_tabs_str = if editor.soft_tabs {
let info_line = format!("UTF8:{} {}:{}", nl, soft_tabs_str, editor.soft_tab_width as usize); "spaces"
self.rb.print(c2.1 - 30, c1.0, rustbox::RB_NORMAL, foreground, background, &info_line[..]); } else {
"tabs"
};
let info_line = format!("UTF8:{} {}:{}",
nl,
soft_tabs_str,
editor.soft_tab_width as usize);
self.rb.print(c2.1 - 30,
c1.0,
rustbox::RB_NORMAL,
foreground,
background,
&info_line[..]);
// Draw main text editing area // Draw main text editing area
self.draw_editor_text(editor, (c1.0 + 1, c1.1), c2); self.draw_editor_text(editor, (c1.0 + 1, c1.1), c2);
} }
fn draw_editor_text(&self, editor: &Editor<ConsoleLineFormatter>, c1: (usize, usize), c2: (usize, usize)) { fn draw_editor_text(&self,
editor: &Editor<ConsoleLineFormatter>,
c1: (usize, usize),
c2: (usize, usize)) {
// Calculate all the starting info // Calculate all the starting info
let gutter_width = editor.editor_dim.1 - editor.view_dim.1; let gutter_width = editor.editor_dim.1 - editor.view_dim.1;
let (line_index, col_i) = editor.buffer.index_to_line_col(editor.view_pos.0); let (line_index, col_i) = editor.buffer.index_to_line_col(editor.view_pos.0);
let (mut line_block_index, _) = block_index_and_offset(col_i); let (mut line_block_index, _) = block_index_and_offset(col_i);
let mut grapheme_index = editor.buffer.line_col_to_index((line_index, line_block_index * LINE_BLOCK_LENGTH)); let mut grapheme_index = editor.buffer.line_col_to_index((line_index,
line_block_index *
LINE_BLOCK_LENGTH));
let temp_line = editor.buffer.get_line(line_index); let temp_line = editor.buffer.get_line(line_index);
let (vis_line_offset, _) = editor.formatter.index_to_v2d(temp_line.grapheme_iter_between_indices(line_block_index*LINE_BLOCK_LENGTH, min(temp_line.grapheme_count(), (line_block_index+1)*LINE_BLOCK_LENGTH)), editor.view_pos.0 - grapheme_index); let (vis_line_offset, _) = editor.formatter.index_to_v2d(temp_line.grapheme_iter_between_indices(line_block_index*LINE_BLOCK_LENGTH, min(temp_line.grapheme_count(), (line_block_index+1)*LINE_BLOCK_LENGTH)), editor.view_pos.0 - grapheme_index);
@ -387,7 +425,12 @@ impl TermUI {
let lnx = c1.1 + (gutter_width - 1 - digit_count(line_num as u32, 10) as usize); let lnx = c1.1 + (gutter_width - 1 - digit_count(line_num as u32, 10) as usize);
let lny = screen_line as usize; let lny = screen_line as usize;
if lny >= c1.0 && lny <= c2.0 { if lny >= c1.0 && lny <= c2.0 {
self.rb.print(lnx, lny, rustbox::RB_NORMAL, Color::White, Color::Blue, &format!("{}", line_num)[..]); self.rb.print(lnx,
lny,
rustbox::RB_NORMAL,
Color::White,
Color::Blue,
&format!("{}", line_num)[..]);
} }
} }
@ -396,7 +439,8 @@ impl TermUI {
let mut line_g_index: usize = 0; let mut line_g_index: usize = 0;
let mut last_pos_y = 0; let mut last_pos_y = 0;
let mut lines_traversed: usize = 0; let mut lines_traversed: usize = 0;
let mut g_iter = editor.formatter.iter(line.grapheme_iter_at_index(line_block_index*LINE_BLOCK_LENGTH)); let mut g_iter = editor.formatter.iter(line.grapheme_iter_at_index(line_block_index *
LINE_BLOCK_LENGTH));
loop { loop {
if let Some((g, (pos_y, pos_x), width)) = g_iter.next() { if let Some((g, (pos_y, pos_x), width)) = g_iter.next() {
@ -428,32 +472,53 @@ impl TermUI {
// Actually print the character // Actually print the character
if is_line_ending(g) { if is_line_ending(g) {
if at_cursor { if at_cursor {
self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, " "); self.rb.print(px as usize,
py as usize,
rustbox::RB_NORMAL,
Color::Black,
Color::White,
" ");
} }
} } else if g == "\t" {
else if g == "\t" {
for i in 0..width { for i in 0..width {
let tpx = px as usize + i; let tpx = px as usize + i;
if tpx <= c2.1 { if tpx <= c2.1 {
self.rb.print(tpx as usize, py as usize, rustbox::RB_NORMAL, Color::White, Color::Black, " "); self.rb.print(tpx as usize,
py as usize,
rustbox::RB_NORMAL,
Color::White,
Color::Black,
" ");
} }
} }
if at_cursor { if at_cursor {
self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, " "); self.rb.print(px as usize,
py as usize,
rustbox::RB_NORMAL,
Color::Black,
Color::White,
" ");
} }
} } else {
else {
if at_cursor { if at_cursor {
self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, g); self.rb.print(px as usize,
} py as usize,
else { rustbox::RB_NORMAL,
self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::White, Color::Black, g); Color::Black,
Color::White,
g);
} else {
self.rb.print(px as usize,
py as usize,
rustbox::RB_NORMAL,
Color::White,
Color::Black,
g);
} }
} }
} }
} } else {
else {
break; break;
} }
@ -463,7 +528,8 @@ impl TermUI {
if line_g_index >= LINE_BLOCK_LENGTH { if line_g_index >= LINE_BLOCK_LENGTH {
line_block_index += 1; line_block_index += 1;
line_g_index = 0; line_g_index = 0;
g_iter = editor.formatter.iter(line.grapheme_iter_at_index(line_block_index * LINE_BLOCK_LENGTH)); g_iter = editor.formatter.iter(line.grapheme_iter_at_index(line_block_index *
LINE_BLOCK_LENGTH));
lines_traversed += 1; lines_traversed += 1;
} }
} }
@ -488,15 +554,22 @@ impl TermUI {
if at_cursor { if at_cursor {
// Calculate the cell coordinates at which to draw the cursor // Calculate the cell coordinates at which to draw the cursor
let pos_x = editor.formatter.index_to_horizontal_v2d(&self.editor.buffer, self.editor.buffer.grapheme_count()); let pos_x = editor.formatter.index_to_horizontal_v2d(&self.editor.buffer,
self.editor
.buffer
.grapheme_count());
let px = pos_x as isize + screen_col - editor.view_pos.1 as isize; let px = pos_x as isize + screen_col - editor.view_pos.1 as isize;
let py = screen_line - 1; let py = screen_line - 1;
if (px >= c1.1 as isize) && (py >= c1.0 as isize) && (px <= c2.1 as isize) && (py <= c2.0 as isize) { if (px >= c1.1 as isize) && (py >= c1.0 as isize) && (px <= c2.1 as isize) &&
self.rb.print(px as usize, py as usize, rustbox::RB_NORMAL, Color::Black, Color::White, " "); (py <= c2.0 as isize) {
self.rb.print(px as usize,
py as usize,
rustbox::RB_NORMAL,
Color::Black,
Color::White,
" ");
} }
} }
} }
} }