...
 
Commits (16)
This diff is collapsed.
use editor::Editor;
use mode::{Mode, CommandMode, PrimitiveMode};
use buffer::{Buffer, Line};
#[derive(Clone)]
/// A cursor, i.e. a state defining a mode, and a position. The cursor does not define the content
......@@ -24,12 +25,12 @@ impl Cursor {
}
}
impl Editor {
impl<'a, B: Buffer<'a>> Editor<B> {
/// Get the character under the cursor
#[inline]
pub fn current(&self) -> Option<char> {
let (x, y) = self.pos();
match self.buffer[y].chars().nth(x) {
match self.buffer.get_line(y).chars().nth(x) {
Some(c) => Some(c),
None => None,
}
......
use editor::Editor;
use redraw::RedrawTask;
use buffer::Buffer;
use buffer::{Buffer, Line};
use cursor::Cursor;
impl Editor {
impl<'a, B: Buffer<'a>> Editor<B> {
/// Delete a character
#[inline]
pub fn delete(&mut self) {
let &Cursor{ x, y, ..} = self.cursor();
if x == self.buffer[y].len() {
if x == self.buffer.get_line(y).len() {
if y + 1 < self.buffer.len() {
let s = self.buffer.remove_line(y + 1);
self.buffer[y].push_str(&s);
let s = self.buffer.remove_line(y);
self.buffer.get_line_mut(y - 1).push_slice(s.as_slice());
let len = self.buffer.get_line(y - 1).len();
self.goto((len, y - 1));
self.redraw_task = RedrawTask::Lines(y..y + 1);
}
} else if x < self.buffer[y].len() {
self.buffer[y].remove(x);
} else if x < self.buffer.get_line(y).len() {
self.buffer.get_line_mut(y).remove(x);
self.redraw_task = RedrawTask::LinesAfter(y);
}
......
......@@ -11,13 +11,13 @@ use parse::Inst;
use orbclient::Window;
/// The current state of the editor, including the file, the cursor, the scrolling info, etc.
pub struct Editor {
pub struct Editor<B> {
/// The current cursor
pub current_cursor: u8,
/// The cursors
pub cursors: Vec<Cursor>,
/// The buffer (document)
pub buffer: SplitBuffer,
pub buffer: B,
/// The x coordinate of the scroll
pub scroll_x: usize,
/// The y coordinate of the scroll
......@@ -37,18 +37,18 @@ pub struct Editor {
pub redraw_task: RedrawTask,
}
impl Editor {
/// Create new default state editor
pub fn init() {
impl<'a, B: Buffer<'a>> Editor<B> {
/// Create a new default `Editor`
pub fn new() -> Self {
#[cfg(feature = "orbital")]
let window = Window::new(-1, -1, 700, 500, &"Sodium").unwrap();
#[cfg(feature = "orbital")]
let mut editor = Editor {
let e = Editor {
current_cursor: 0,
cursors: vec![Cursor::new()],
buffer: SplitBuffer::new(),
buffer: B::new(),
scroll_x: 0,
scroll_y: 0,
window: *window, // ORBITAL SPECIFIC!
......@@ -60,10 +60,10 @@ impl Editor {
};
#[cfg(not(feature = "orbital"))]
let mut editor = Editor {
let e = Editor {
current_cursor: 0,
cursors: vec![Cursor::new()],
buffer: SplitBuffer::new(),
buffer: B::new(),
scroll_x: 0,
scroll_y: 0,
status_bar: StatusBar::new(),
......@@ -73,6 +73,14 @@ impl Editor {
redraw_task: RedrawTask::Null,
};
e
}
/// Create new default state editor
pub fn init() {
let mut editor = Self::new();
debugln!(editor, "Starting Sodium");
editor.redraw();
......@@ -90,12 +98,4 @@ impl Editor {
editor.status_bar.mode = editor.cursor().mode.to_string();
}
}
pub fn hint(&mut self) {
let x = self.cursor().x;
let y = self.cursor().y;
self.buffer.focus_hint_y(y);
self.buffer.focus_hint_x(x);
}
}
......@@ -4,14 +4,14 @@ use key::Key;
use mode::{Mode, CommandMode, PrimitiveMode};
use insert::{InsertOptions, InsertMode};
use redraw::RedrawTask;
use buffer::Buffer;
use buffer::{Buffer, Line, Slice};
use std::iter::FromIterator;
// TODO: Move the command definitions outta here
impl Editor {
impl<'a, B: Buffer<'a>> Editor<B> {
/// Execute an instruction
pub fn exec(&mut self, Inst(para, cmd): Inst) {
pub fn exec<'b: 'a>(&'b mut self, Inst(para, cmd): Inst) {
use key::Key::*;
use mode::Mode::*;
use mode::PrimitiveMode::*;
......@@ -30,8 +30,8 @@ impl Editor {
Primitive(Insert(_)) => {
let left = self.left(1);
self.goto(left);
}
_ => {}
},
_ => {},
}
self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
......@@ -68,7 +68,7 @@ impl Editor {
mode: InsertMode::Insert,
}));
}
},
Char('a') => {
let pos = self.right(1, false);
self.goto( pos );
......@@ -76,95 +76,94 @@ impl Editor {
Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
mode: InsertMode::Insert,
}));
}
},
Char('o') => {
let y = self.y();
let y = self.y();
let ln = self.buffer.get_line(y);
let ind = if self.options.autoindent {
self.buffer.get_indent(y).to_owned()
ln.get_indent()
} else {
String::new()
<B::Line as Line>::Slice::new_empty()
};
let last = ind.len();
self.buffer.insert_line(y, ind.into());
self.buffer.insert_line(y, ind);
self.goto((last, y + 1));
self.cursor_mut().mode =
Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
mode: InsertMode::Insert,
}));
}
},
Char('h') => {
let left = self.left(n);
self.goto(left);
mov = true;
}
},
Char('j') => {
let down = self.down(n);
self.goto(down);
mov = true;
}
},
Char('k') => {
let up = self.up(n);
self.goto(up);
mov = true;
}
},
Char('l') => {
let right = self.right(n, true);
self.goto(right);
mov = true;
}
},
Char('J') => {
let down = self.down(15 * n);
self.goto(down);
mov = true;
}
},
Char('K') => {
let up = self.up(15 * n);
self.goto(up);
mov = true;
}
},
Char('x') => {
self.delete();
let bounded = self.bound(self.pos(), true);
self.goto(bounded);
}
},
Char('X') => {
self.backspace();
let bounded = self.bound(self.pos(), true);
self.goto(bounded);
}
},
Char('L') => {
let ln_end = (self.buffer[self.y()].len(), self.y());
let ln_end = (self.buffer.get_line(self.y()).len(), self.y());
self.goto(ln_end);
mov = true;
}
},
Char('H') => {
self.cursor_mut().x = 0;
mov = true;
}
},
Char('r') => {
let (x, y) = self.pos();
let c = self.get_char();
self.buffer[y].remove(x);
self.buffer[y].insert(x, c);
}
self.buffer.get_line_mut(y).set_char(x, c);
},
Char('R') => {
self.cursor_mut().mode =
Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
mode: InsertMode::Replace,
}));
}
},
Char('d') => {
let ins = self.get_inst();
if let Some(m) = self.to_motion_unbounded(ins) {
self.remove_rb(m);
}
}
},
Char('G') => {
let last = self.buffer.len() - 1;
self.goto((0, last));
mov = true;
}
},
Char('g') => {
if let Parameter::Int(n) = para {
self.goto((0, n - 1));
......@@ -177,7 +176,7 @@ impl Editor {
}
}
}
},
Char('b') => {
// Branch cursor
if self.cursors.len() < 255 {
......@@ -188,7 +187,7 @@ impl Editor {
else {
self.status_bar.msg = format!("At max 255 cursors");
}
}
},
Char('B') => {
// Delete cursor
if self.cursors.len() > 1 {
......@@ -198,7 +197,7 @@ impl Editor {
else {
self.status_bar.msg = format!("No other cursors!");
}
}
},
Char('t') => {
let ch = self.get_char();
......@@ -208,7 +207,7 @@ impl Editor {
self.goto((p, y));
mov = true;
}
}
},
Char('f') => {
let ch = self.get_char();
......@@ -218,13 +217,13 @@ impl Editor {
self.goto((p, y));
mov = true;
}
}
},
Char(';') => {
self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Prompt);
}
},
Char(' ') => {
self.next_cursor();
}
},
Char('z') => {
let Inst(param, cmd) = self.get_inst();
match param {
......@@ -239,26 +238,26 @@ impl Editor {
}
}
self.redraw_task = RedrawTask::Full;
}
},
Char('Z') => {
self.scroll_y = self.y() - 3;
self.redraw_task = RedrawTask::Full;
}
},
Char('~') => {
self.invert_chars(n);
}
},
Char(c) => {
self.status_bar.msg = format!("Unknown command: {}", c);
self.redraw_task = RedrawTask::StatusBar;
}
},
_ => {
self.status_bar.msg = format!("Unknown command");
self.redraw_task = RedrawTask::StatusBar;
}
},
},
Primitive(Insert(opt)) => {
self.insert(cmd.key, opt);
}
},
Primitive(Prompt) => {
match cmd.key {
Char('\n') => {
......@@ -267,15 +266,15 @@ impl Editor {
self.invoke(cmd);
self.prompt = String::new();
}
},
Backspace => {
self.prompt.pop();
}
},
Char(c) => self.prompt.push(c),
_ => {}
_ => {},
}
self.redraw_task = RedrawTask::StatusBar;
}
},
}
}
if mov {
......
......@@ -3,7 +3,7 @@ use redraw::RedrawTask;
use mode::Mode;
use mode::PrimitiveMode;
use mode::CommandMode;
use buffer::Buffer;
use buffer::{Buffer, Line};
#[cfg(feature = "orbital")]
use orbclient::Color;
......@@ -157,20 +157,31 @@ mod terminal {
}
#[cfg(feature = "orbital")]
impl Editor {
impl<'a, B: Buffer<'a>> Editor<B> {
/// Redraw the window
pub fn redraw(&mut self) {
// TODO: Only draw when relevant for the window
pub fn redraw<'b: 'a>(&'b mut self) {
// I was here -- bug
let (mut pos_x, pos_y) = self.pos();
// Redraw window
self.window.set(Color::rgb(25, 25, 25));
let w = self.window.width();
{ // TODO Unnecessary?
// TODO: Only draw when relevant for the window
// Redraw window
self.window.set(Color::rgb(25, 25, 25));
let w = self.window.width();
if self.options.line_marker {
self.window.rect(0,
(pos_y - self.scroll_y) as i32 * 16,
w,
16,
Color::rgb(45, 45, 45));
}
if self.options.line_marker {
self.window.rect(0,
(pos_y - self.scroll_y) as i32 * 16,
w,
self.window.rect(8 * (pos_x - self.scroll_x) as i32,
16 * (pos_y - self.scroll_y) as i32,
8,
16,
Color::rgb(45, 45, 45));
}
......@@ -192,24 +203,24 @@ impl Editor {
'\'' | '"' => {
string = !string;
(226, 225, 167) //(167, 222, 156)
}
},
_ if string => (226, 225, 167), //(167, 222, 156)
'!' |
'@' |
'#' |
'$' |
'%' |
'^' |
'&' |
'|' |
'*' |
'+' |
'-' |
'/' |
':' |
'=' |
'<' |
'>' => (198, 83, 83), //(228, 190, 175), //(194, 106, 71),
'@' |
'#' |
'$' |
'%' |
'^' |
'&' |
'|' |
'*' |
'+' |
'-' |
'/' |
':' |
'=' |
'<' |
'>' => (198, 83, 83), //(228, 190, 175), //(194, 106, 71),
'.' | ',' => (241, 213, 226),
'(' | ')' | '[' | ']' | '{' | '}' => (164, 212, 125), //(195, 139, 75),
'0' ... '9' => (209, 209, 177),
......@@ -227,14 +238,14 @@ impl Editor {
if pos_x == x && pos_y == y {
self.window.char(8 * (x - self.scroll_x) as i32,
16 * (y - self.scroll_y) as i32,
c,
Color::rgb(color.0 / 3, color.1 / 3, color.2 / 3));
16 * (y - self.scroll_y) as i32,
c,
Color::rgb(color.0 / 3, color.1 / 3, color.2 / 3));
} else {
self.window.char(8 * (x - self.scroll_x) as i32,
16 * (y - self.scroll_y) as i32,
c,
Color::rgb(color.0, color.1, color.2));
16 * (y - self.scroll_y) as i32,
c,
Color::rgb(color.0, color.1, color.2));
}
}
}
......@@ -282,7 +293,7 @@ impl Editor {
}
#[cfg(feature = "orbital")]
fn status_bar(editor: &mut Editor, text: String, a: u32, b: u32) {
fn status_bar<'a, B: Buffer<'a>>(editor: &mut Editor<B>, text: String, a: u32, b: u32) {
let h = editor.window.height();
let w = editor.window.width();
......
......@@ -2,7 +2,7 @@ use editor::Editor;
use mode::{Mode, PrimitiveMode, CommandMode};
use redraw::RedrawTask;
use key::Key;
use buffer::Buffer;
use buffer::{Buffer, Line};
use std::collections::VecDeque;
use std::iter::FromIterator;
......@@ -24,45 +24,33 @@ pub struct InsertOptions {
pub mode: InsertMode,
}
impl Editor {
impl<'a, 'b: 'a, B: Buffer<'a>> Editor<B> {
/// Insert text under the current cursor.
pub fn insert(&mut self, k: Key, InsertOptions { mode }: InsertOptions) {
pub fn insert(&'b mut self, k: Key, InsertOptions { mode }: InsertOptions) {
let (mut x, mut y) = self.pos();
match mode {
InsertMode::Insert => {
match k {
Key::Char('\n') => {
let first_part = self.buffer[y][..x].to_owned();
let second_part = self.buffer[y][x..].to_owned();
self.buffer[y] = first_part;
let nl = if self.options.autoindent {
self.buffer.get_indent(y).to_owned()
} else {
String::new()
};
let begin = nl.len();
self.buffer.insert_line(y, nl + &second_part);
let begin = self.buffer.insert_newline(x, y, self.options.autoindent);
self.redraw_task = RedrawTask::LinesAfter(y);
self.goto((begin, y + 1));
}
},
Key::Backspace => self.backspace(),
Key::Char(c) => {
self.buffer[y].insert(x, c);
self.buffer.get_line_mut(y).insert(x, c);
self.redraw_task = RedrawTask::Lines(y..y + 1);
let right = self.right(1, false);
self.goto(right);
}
_ => {}
},
_ => {},
}
}
},
InsertMode::Replace => match k {
Key::Char(c) => {
if x == self.buffer[y].len() {
if x == self.buffer.get_line(y).len() {
let next = self.next(1);
if let Some(p) = next {
self.goto(p);
......@@ -72,14 +60,14 @@ impl Editor {
}
if self.buffer.len() != y {
if self.buffer[y].len() == x {
if self.buffer.get_line(y).len() == x {
let next = self.next(1);
if let Some(p) = next {
self.goto(p);
}
} else {
self.buffer[y].remove(x);
self.buffer[y].insert(x, c);
self.buffer.get_line_mut(y).remove(x);
self.buffer.get_line_mut(y).insert(x, c);
}
}
let next = self.next(1);
......@@ -87,8 +75,8 @@ impl Editor {
self.goto(p);
}
self.redraw_task = RedrawTask::Lines(y..y + 1);
}
_ => {}
},
_ => {},
},
}
......@@ -96,7 +84,7 @@ impl Editor {
}
/// Insert a string
pub fn insert_str(&mut self, txt: String, opt: InsertOptions) {
pub fn insert_str(&'b mut self, txt: String, opt: InsertOptions) {
for c in txt.chars() {
self.insert(Key::Char(c), opt);
}
......
use editor::Editor;
use buffer::{Buffer, Line};
impl Editor {
impl<'a, B: Buffer<'a>> Editor<B> {
pub fn invert_chars(&mut self, n: usize) {
for _ in 0..n {
let (x, y) = self.pos();
let current = self.current();
if let Some(cur) = current {
self.buffer[y].remove(x);
self.buffer[y].insert(x, invert(cur));
self.buffer.get_line_mut(y).remove(x);
self.buffer.get_line_mut(y).insert(x, invert(cur));
}
if let Some(m) = self.next(1) {
self.goto(m);
......
......@@ -43,40 +43,16 @@ impl KeyState {
K_LEFT_SHIFT | K_RIGHT_SHIFT => self.shift = k.pressed,
_ if k.pressed => {
return Some(Key::from_event(k));
}
_ => {}
},
_ => {},
}
}
_ if k.pressed => {
return Some(Key::from_event(k));
}
_ => {}
}
None
}
#[cfg(feature = "ansi")]
pub fn feed(&mut self, stdin: &mut Stdin) -> Option<Key> {
match c {
'\0' => {
// "I once lived here" - bug
match k.scancode {
K_ALT => self.alt = k.pressed,
K_CTRL => self.ctrl = k.pressed,
K_LEFT_SHIFT | K_RIGHT_SHIFT => self.shift = k.pressed,
_ if k.pressed => {
return Some(Key::from_event(k));
}
_ => {}
}
}
None
},
_ if k.pressed => {
return Some(Key::from_event(k));
}
_ => {}
Some(Key::from_event(k))
},
_ => None,
}
None
}
}
......@@ -17,3 +17,15 @@ macro_rules! debug {
}
});
}
/// If a Option is Some(x) then yield x, else return None
#[macro_export]
macro_rules! try_opt {
($e:expr) => ({
if let Some(x) = $e {
x
} else {
return None;
}
});
}
#![feature(stmt_expr_attributes)]
#![feature(collections_range)]
#![feature(type_ascription)]
#[cfg(feature = "orbital")]
extern crate orbclient;
extern crate collections;
#[macro_use]
pub mod debug;
pub mod macros;
pub mod editor;
pub mod buffer;
......@@ -27,6 +31,9 @@ pub mod delete;
pub mod exec;
pub mod invert;
fn main() {
editor::Editor::init();
pub fn main() {
use editor::Editor;
use buffer::SplitBuffer;
Editor::<SplitBuffer>::init();
}
use editor::Editor;
use parse::Inst;
use position::to_signed_pos;
use buffer::Buffer;
use buffer::{Buffer, Line};
impl Editor {
impl<'a, B: Buffer<'a>> Editor<B> {
/// Convert an instruction to a motion (new coordinate). Returns None if the instructions given
/// either is invalid or has no movement.
///
......@@ -24,10 +24,9 @@ impl Editor {
Char('k') => Some(self.up(n.d())),
Char('g') => Some((0, n.or(1) - 1)),
Char('G') => Some((0, self.buffer.len() - 1)),
Char('L') => Some((self.buffer[y].len() - 1, y)),
Char('L') => Some((self.buffer.get_line(y).len() - 1, y)),
Char('H') => Some((0, y)),
Char('t') => {
let ch = self.get_char();
if let Some(o) = self.next_ocur(ch, n.d()) {
......@@ -35,9 +34,8 @@ impl Editor {
} else {
None
}
}
},
Char('f') => {
let ch = self.get_char();
if let Some(o) = self.previous_ocur(ch, n.d()) {
......@@ -45,16 +43,16 @@ impl Editor {
} else {
None
}
}
},
Char(c) => {
self.status_bar.msg = format!("Motion not defined: '{}'", c);
self.redraw_status_bar();
None
}
},
_ => {
self.status_bar.msg = format!("Motion not defined");
None
}
},
}
}
/// Like to_motion() but does not bound to the text. Therefore it returns an isize, and in some
......@@ -73,7 +71,7 @@ impl Editor {
Char('k') => Some(self.up_unbounded(n.d())),
Char('g') => Some((0, n.or(1) as isize - 1)),
Char('G') => Some((0, self.buffer.len() as isize - 1)),
Char('L') => Some(to_signed_pos((x, self.buffer[y].len()))),
Char('L') => Some(to_signed_pos((x, self.buffer.get_line(y).len()))),
Char('H') => Some((0, y as isize)),
Char('t') => {
......@@ -84,7 +82,7 @@ impl Editor {
} else {
None
}
}
},
Char('f') => {
let ch = self.get_char();
......@@ -94,7 +92,7 @@ impl Editor {
} else {
None
}
}
},
_ => None,
}
}
......
use editor::Editor;
use buffer::Buffer;
use buffer::{Buffer, Line};
impl Editor {
impl<'a, B: Buffer<'a>> Editor<B> {
/// Goto a given position. Does not automatically bound.
#[inline]
pub fn goto(&mut self, (x, y): (usize, usize)) {
......@@ -26,22 +26,22 @@ impl Editor {
pub fn after(&self, n: usize, (x, y): (usize, usize)) -> Option<(usize, usize)> {
// TODO: Make this more idiomatic {
if x + n < self.buffer[y].len() {
if x + n < self.buffer.get_line(y).len() {
Some((x + n, y))
} else {
if y + 1 >= self.buffer.len() {
None
} else {
let mut mv = n + x - self.buffer[y].len();
let mut mv = n + x - self.buffer.get_line(y).len();
let mut ry = y + 1;
loop {
if mv < self.buffer[ry].len() {
if mv < self.buffer.get_line(ry).len() {
return Some((mv, ry));
} else {
if ry + 1 < self.buffer.len() {
mv -= self.buffer[ry].len();
mv -= self.buffer.get_line(ry).len();
ry += 1;
} else {
return None;
......@@ -68,11 +68,11 @@ impl Editor {
let mut ry = y - 1;
loop {
if mv <= self.buffer[ry].len() {
return Some((self.buffer[ry].len() - mv, ry));
if mv <= self.buffer.get_line(ry).len() {
return Some((self.buffer.get_line(ry).len() - mv, ry));
} else {
if ry > 0 && mv >= self.buffer[ry].len() {
mv -= self.buffer[ry].len();
if ry > 0 && mv >= self.buffer.get_line(ry).len() {
mv -= self.buffer.get_line(ry).len();
ry -= 1;
} else if ry == 0 {
return None;
......@@ -142,7 +142,7 @@ impl Editor {
let mut dn = 0;
let mut x = self.x();
for ch in self.buffer[self.y()].chars().skip(x) {
for ch in self.buffer.get_line(self.y()).chars().skip(x) {
if dn == n {
if ch == c {
dn += 1;
......@@ -162,7 +162,7 @@ impl Editor {
let mut x = self.x();
let y = self.y();
for ch in self.buffer[y].chars().rev().skip(self.buffer[y].len() - x) {
for ch in self.buffer.get_line(y).chars().rev().skip(self.buffer.get_line(y).len() - x) {
if dn == n {
if ch == c {
dn += 1;
......
......@@ -8,7 +8,7 @@ pub enum OpenStatus {
NotFound,
}
impl Editor {
impl<'a, B: Buffer<'a>> Editor<B> {
/// Open a file
pub fn open(&mut self, path: &str) -> OpenStatus {
self.status_bar.file = path.to_string();
......@@ -16,7 +16,7 @@ impl Editor {
let mut con = String::new();
file.read_to_string(&mut con);
self.buffer = SplitBuffer::from_str(&con);
self.buffer = B::from_str(&con);
self.hint();
OpenStatus::Ok
} else {
......
......@@ -12,7 +12,7 @@ impl Options {
highlight: true,
autoindent: true,
line_marker: true,
debug: true, // TODO: Let this be `true` only in debug compilation cfg
debug: false,
}
}
......@@ -44,7 +44,7 @@ impl Options {
Some(x) => {
*x = true;
Ok(())
}
},
None => Err(()),
}
}
......@@ -54,7 +54,7 @@ impl Options {
Some(x) => {
*x = false;
Ok(())
}
},
None => Err(()),
}
}
......@@ -64,9 +64,8 @@ impl Options {
Some(x) => {
*x = !*x;
Ok(())
}
},
None => Err(()),
}
}
}
......@@ -2,6 +2,7 @@ use key::{Cmd, Key};
use editor::Editor;
use redraw::RedrawTask;
use mode::Mode;
use buffer::Buffer;
#[cfg(feature = "orbital")]
use orbclient::{EventOption, Event};
......@@ -36,7 +37,7 @@ impl Parameter {
}
}
impl Editor {
impl<'a, B: Buffer<'a>> Editor<B> {
/// Get the next character input. Useful for commands taking a character as post-parameter,
/// such as r (replace).
pub fn get_char(&mut self) -> char {
......@@ -82,7 +83,7 @@ impl Editor {
match self.cursor().mode {
Mode::Primitive(_) => {
key = k;
}
},
Mode::Command(_) => {
n = match c {
'0' ... '9' => {
......@@ -95,8 +96,7 @@ impl Editor {
n
}
};
}
},
}
}
match key {
......
use editor::Editor;
use buffer::Buffer;
use buffer::{Buffer, Line};
/// Convert a usize tuple to isize
pub fn to_signed_pos((x, y): (usize, usize)) -> (isize, isize) {
(x as isize, y as isize)
}
impl Editor {
impl<'a, B: Buffer<'a>> Editor<B> {
/// Get the position of the current cursor, bounded
#[inline]
pub fn pos(&self) -> (usize, usize) {
......@@ -29,15 +29,18 @@ impl Editor {
/// Convert a position value to a bounded position value
#[inline]
pub fn bound(&self, (x, mut y): (usize, usize), tight: bool) -> (usize, usize) {
y = if y >= self.buffer.len() {
self.buffer.len() - 1
} else {
y
};
let ln = self.buffer[y].len() + if tight {0} else {1};
let ln = self.buffer.get_line(y).len() + if tight {
0
} else {
1
};
if x >= ln {
if ln == 0 {
(0, y)
......@@ -69,4 +72,14 @@ impl Editor {
(x, y)
}
/// Give a hint about the cursor position to the buffer, used for setting the center/focus in
/// which operations are most efficient.
pub fn hint(&mut self) {
let x = self.cursor().x;
let y = self.cursor().y;
self.buffer.focus_hint_y(y);
self.buffer.focus_hint_x(x);
}
}
use editor::Editor;
use open::OpenStatus;
use buffer::Buffer;
impl Editor {
impl<'a, B: Buffer<'a>> Editor<B> {
/// Invoke a command in the prompt
pub fn invoke(&mut self, cmd: String) {
let mut split = cmd.split(' ');
......@@ -14,38 +15,38 @@ impl Editor {
Ok(()) => format!("Option set: {}", sec_cmd),
Err(()) => format!("Option does not exist: {}", sec_cmd),
}
}
},
"unset" => {
self.status_bar.msg = match self.options.unset(sec_cmd) {
Ok(()) => format!("Option unset: {}", sec_cmd),
Err(()) => format!("Option does not exist: {}", sec_cmd),
}
}
},
"toggle" | "tog" => {
self.status_bar.msg = match self.options.toggle(sec_cmd) {
Ok(()) => format!("Option toggled: {}", sec_cmd),
Err(()) => format!("Option does not exist: {}", sec_cmd),
}
}
},
"get" => {
self.status_bar.msg = match self.options.get(sec_cmd) {
Some(true) => format!("Option set: {}", sec_cmd),
Some(false) => format!("Option unset: {}", sec_cmd),
None => format!("Option does not exist: {}", sec_cmd),
}
}
},
"o" | "open" => {
self.status_bar.msg = match self.open(sec_cmd) {
OpenStatus::NotFound => format!("File {} could not be opened", sec_cmd),
OpenStatus::Ok => format!("File {} opened", sec_cmd),
}
}
},
"help" => {
self.open("/apps/sodium/help.txt");
}
},
c => {
self.status_bar.msg = format!("Unknown command: {}", c);
}
},
}
self.hint();
......
use editor::Editor;
use buffer::Buffer;
use buffer::{Buffer, Line};
use std::collections::VecDeque;
impl Editor {
impl<'a, B: Buffer<'a>> Editor<B> {
/// Remove from a given motion (row based), i.e. if the motion given is to another line, all
/// the lines from the current one to the one defined by the motion are removed. If the motion
/// defines a position on the same line, only the characters from the current position to the
/// motion's position are removed.
pub fn remove_rb<'a>(&mut self, (x, y): (isize, isize)) {
pub fn remove_rb<'b: 'a>(&'b mut self, (x, y): (isize, isize)) {
if y == self.y() as isize {
let (x, y) = self.bound((x as usize, y as usize), true);
// Single line mode
......@@ -16,7 +16,7 @@ impl Editor {
} else {
(self.x(), x)
};
for _ in self.buffer[y].drain(a..b) {}
for _ in self.buffer.get_line_mut(y).drain(a..b) {}
} else {
let (_, y) = self.bound((x as usize, y as usize), true);
// Full line mode
......@@ -31,7 +31,7 @@ impl Editor {
if self.buffer.len() > 1 {
self.buffer.remove_line(a);
} else {
self.buffer[0] = String::new();
self.buffer.get_line_mut(0).clear();
}
}
}
......