Commit db82d0c4 authored by David Raifaizen's avatar David Raifaizen

Removing erroneous file copies

parent 25cd180a
use std::cmp::min;
use std::ops::{Index, IndexMut};
use std::str::Chars;
/// A line in a buffer.
pub trait Line<'a> {
/// The underlying iterator.
type Iter: Iterator<Item = char> + 'a;
/// Iterator over characters.
fn chars_iter(&'a self) -> Self::Iter;
}
impl<'a, T: AsRef<str>> Line<'a> for T {
type Iter = Chars<'a>;
fn chars_iter(&self) -> Chars {
self.as_ref().chars()
}
}
/// A buffer structure
pub trait Buffer<'a> {
/// The line type of the buffer.
type Line: 'a + Line<'a>;
/// The line iterator.
type LineIter: Iterator<Item = &'a Self::Line>;
/// Create a new empty split buffer
fn new() -> Self;
/// Convert a string to a split buffer
fn from_str(s: &str) -> Self;
/// Get the nth line in the buffer by option reference
fn get_line(&self, n: usize) -> Option<&Self::Line>;
/// Get the nth line in the buffer by optional mutable reference
fn get_line_mut(&mut self, n: usize) -> Option<&mut Self::Line>;
/// Remove the nth line and return it. Panics on out of bound.
fn remove_line(&mut self, n: usize) -> Self::Line;
/// Insert line at n. Panics on out of bound.
fn insert_line(&mut self, n: usize, line: Self::Line);
/// Convert a vector of lines to a split buffer
fn from_lines(vec: &[Self::Line]) -> SplitBuffer;
/// Give a hint on where the operations are most frequent (i.e. where the cursor is). X value.
fn focus_hint_x(&mut self, x: usize);
/// Give a hint on where the operations are most frequent (i.e. where the cursor is). Y value.
fn focus_hint_y(&mut self, y: usize);
/// Get the number of lines in the buffer.
fn len(&self) -> usize;
/// Get an iterator over the lines in the buffer.
fn lines(&'a self) -> Self::LineIter;
/// Get the leading whitespaces of the nth line. Used for autoindenting.
fn get_indent(&self, n: usize) -> &str;
}
/// The buffer data structure, that Sodium is using.
///
/// This structure consists of two "subbuffers", which are just vectors over lines (defined by
/// Strings). The split is called a center.
///
/// The nearer a given operation is to the center, the better it performs.
///
/// The second buffer is in reverse order to get the particular efficiency we want.
pub struct SplitBuffer {
before: Vec<String>,
after: Vec<String>,
#[cfg(debug)]
_hinted_since_edit: bool,
}
impl SplitBuffer {
fn up(&mut self) {
self.after.push(self.before.pop().expect("Popped last element"));
}
fn down(&mut self) {
self.before.push(self.after.pop().expect("Popped last element"));
}
fn y(&self) -> usize {
self.before.len()
}
}
// TODO remove
impl SplitBuffer {
/// Convert the buffer to a string.
pub fn to_string(&self) -> String {
self.lines().map(|x| x.to_owned() + "\n").collect()
}
}
impl<'a> Buffer<'a> for SplitBuffer {
type Line = String;
type LineIter = SplitBufIter<'a>;
fn new() -> Self {
SplitBuffer {
before: vec![String::new()],
after: Vec::new(),
}
}
fn from_str(s: &str) -> Self {
SplitBuffer {
before: s.lines().map(ToOwned::to_owned).collect(),
after: Vec::new(),
}
}
fn get_line(&self, n: usize) -> Option<&String> {
if n < self.before.len() {
Some(&self.before[n])
} else if n < self.len() {
let n = self.len() - 1 - n;
Some(&self.after[n])
} else {
None
}
}
fn get_line_mut(&mut self, n: usize) -> Option<&mut String> {
if n < self.before.len() {
Some(&mut self.before[n])
} else if n < self.len() {
let n = self.len() - 1 - n;
Some(&mut self.after[n])
} else {
None
}
}
fn remove_line(&mut self, n: usize) -> String {
if n < self.before.len() {
self.before.remove(n)
} else if n < self.len() {
let n = self.len() - 1 - n;
self.after.remove(n)
} else {
panic!("Out of bound");
}
}
fn insert_line(&mut self, n: usize, line: String) {
if n < self.before.len() {
self.before.insert(n, line);
} else if n < self.len() {
let n = self.len() - 1 - n;
self.after.insert(n, line);
} else {
panic!("Out of bound");
}
}
fn from_lines(ln: &[String]) -> SplitBuffer {
SplitBuffer {
before: ln.to_owned(),
after: Vec::new(),
}
}
fn focus_hint_y(&mut self, y: usize) {
if y < self.y() {
for _ in 0..min(self.y() - y, self.before.len()) {
self.up();
}
} else if y > self.y() {
for _ in 0..min(y - self.y(), self.after.len()) {
self.down();
}
} else if y >= self.len() {
panic!("Out of bound");
}
}
fn focus_hint_x(&mut self, _: usize) {}
fn len(&self) -> usize {
self.before.len() + self.after.len()
}
fn lines(&'a self) -> SplitBufIter<'a> {
SplitBufIter {
buffer: self,
line: 0,
}
}
fn get_indent(&self, n: usize) -> &str {
if let Some(ln) = self.get_line(n) {
let mut len = 0;
for c in ln.chars() {
match c {
'\t' | ' ' => len += 1,
_ => break,
}
}
&ln[..len]
} else {
""
}
}
}
impl Index<usize> for SplitBuffer {
type Output = String;
fn index<'a>(&'a self, index: usize) -> &'a String {
self.get_line(index).expect("Out of bound")
}
}
impl IndexMut<usize> for SplitBuffer {
fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut String {
#[cfg(debug)]
fn debug_check(b: &mut SplitBuffer) {
if b._hinted_since_edit {
b._hinted_since_edit = false;
} else {
panic!("No focus hint given since last edit!");
}
}
#[cfg(not(debug))]
fn debug_check(_: &mut SplitBuffer) {}
debug_check(&mut *self);
self.get_line_mut(index).expect("Out of bound")
}
}
/// A iterator over the lines of a split buffer
pub struct SplitBufIter<'a> {
buffer: &'a SplitBuffer,
line: usize,
}
impl<'a> Iterator for SplitBufIter<'a> {
type Item = &'a String;
fn next(&mut self) -> Option<&'a String> {
self.nth(1)
}
fn nth(&mut self, n: usize) -> Option<&'a String> {
let res = self.buffer.get_line(self.line);
self.line += n;
res
}
fn count(self) -> usize {
self.buffer.len()
}
}
impl<'a> DoubleEndedIterator for SplitBufIter<'a> {
fn next_back(&mut self) -> Option<&'a String> {
if self.line == 0 {
None
} else {
self.line -= 1;
self.buffer.get_line(self.line)
}
}
}
use editor::Editor;
use mode::{Mode, CommandMode};
#[derive(Clone)]
/// A cursor, i.e. a state defining a mode, and a position. The cursor does not define the content
/// of the current file.
pub struct Cursor {
/// The x coordinate of the cursor
pub x: usize,
/// The y coordinate of the cursor
pub y: usize,
/// The mode of the cursor
pub mode: Mode,
}
impl Cursor {
/// Create a new default cursor
pub fn new() -> Cursor {
Cursor {
x: 0,
y: 0,
mode: Mode::Command(CommandMode::Normal),
}
}
}
impl Editor {
/// 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) {
Some(c) => Some(c),
None => None,
}
}
/// Get the current cursor
#[inline]
pub fn cursor(&self) -> &Cursor {
self.cursors.get(self.current_cursor as usize).unwrap()
}
/// Get the current cursor mutably
#[inline]
pub fn cursor_mut(&mut self) -> &mut Cursor {
self.cursors.get_mut(self.current_cursor as usize).unwrap()
}
/// Go to next cursor
#[inline]
pub fn next_cursor(&mut self) {
self.current_cursor = (self.current_cursor.wrapping_add(1)) % (self.cursors.len() as u8);
}
/// Go to previous cursor
#[inline]
pub fn prev_cursor(&mut self) {
if self.current_cursor != 0 {
self.current_cursor -= 1;
}
else {
self.current_cursor = self.cursors.len() as u8;
}
}
}
/// Write to console if the debug option is set (with newline)
#[macro_export]
macro_rules! debugln {
($e:expr, $($arg:tt)*) => ({
if $e.options.debug {
println!($($arg)*);
}
});
}
/// Write to console if the debug option is set
#[macro_export]
macro_rules! debug {
($e:expr, $($arg:tt)*) => ({
if $e.options.debug {
print!($($arg)*);
}
});
}
use buffer::Buffer;
use cursor::Cursor;
use editor::Editor;
use redraw::RedrawTask;
impl Editor {
/// Delete a character.
#[inline]
pub fn delete(&mut self) {
let &Cursor{ x, y, .. } = self.cursor();
if x == self.buffer[y].len() {
if y + 1 < self.buffer.len() {
let s = self.buffer.remove_line(y + 1);
self.buffer[y].push_str(&s);
self.redraw_task = RedrawTask::Lines(y..y + 1);
}
} else if x < self.buffer[y].len() {
self.buffer[y].remove(x);
self.redraw_task = RedrawTask::LinesAfter(y);
}
self.hint();
}
/// Backspace.
#[inline]
pub fn backspace(&mut self) {
let previous = self.previous(1);
if let Some(p) = previous {
self.goto(p);
self.delete();
} else {
self.status_bar.msg = "Can't delete file start".to_owned();
}
}
}
use buffer::{Buffer, SplitBuffer};
use cursor::Cursor;
use graphics::StatusBar;
use key::{Key, Cmd};
use key_state::KeyState;
use options::Options;
use parse::Inst;
use redraw::RedrawTask;
#[cfg(feature = "orbital")]
use orbclient::Window;
use std::env::args;
/// The current state of the editor, including the file, the cursor, the scrolling info, etc.
pub struct Editor {
/// The current cursor
pub current_cursor: u8,
/// The cursors
pub cursors: Vec<Cursor>,
/// The buffer (document)
pub buffer: SplitBuffer,
/// The x coordinate of the scroll
pub scroll_x: usize,
/// The y coordinate of the scroll
pub scroll_y: usize,
/// The window
#[cfg(feature = "orbital")]
pub window: Window,
/// The status bar
pub status_bar: StatusBar,
/// The prompt
pub prompt: String,
/// The settings
pub options: Options,
/// The key state
pub key_state: KeyState,
/// Redraw
pub redraw_task: RedrawTask,
}
impl Editor {
/// Create new default state editor
pub fn init() {
#[cfg(feature = "orbital")]
let window = Window::new(-1, -1, 700, 500, &"Sodium").unwrap();
#[cfg(feature = "orbital")]
let mut editor = Editor {
current_cursor: 0,
cursors: vec![Cursor::new()],
buffer: SplitBuffer::new(),
scroll_x: 0,
scroll_y: 0,
window: *window, // ORBITAL SPECIFIC!
status_bar: StatusBar::new(),
prompt: String::new(),
options: Options::new(),
key_state: KeyState::new(),
redraw_task: RedrawTask::None,
};
#[cfg(not(feature = "orbital"))]
let mut editor = Editor {
current_cursor: 0,
cursors: vec![Cursor::new()],
buffer: SplitBuffer::new(),
scroll_x: 0,
scroll_y: 0,
status_bar: StatusBar::new(),
prompt: String::new(),
options: Options::new(),
key_state: KeyState::new(),
redraw_task: RedrawTask::Null,
};
if let Some(x) = args().skip(1).next() {
editor.open(&x);
}
debugln!(editor, "Starting Sodium");
editor.redraw();
debugln!(editor, "First redraw of the screen");
loop {
let inp = editor.get_inst();
if let Inst(_, Cmd { key: Key::Quit }) = inp {
debugln!(editor, "C'ya");
break;
}
editor.exec(inp);
editor.status_bar.mode = editor.cursor().mode.to_string();
editor.redraw();
}
}
/// Hint the buffer about the cursor position.
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 parse::{Inst, Parameter};
use mode::{Mode, CommandMode, PrimitiveMode};
use insert::{InsertOptions, InsertMode};
use redraw::RedrawTask;
use buffer::Buffer;
// TODO: Move the command definitions outta here
impl Editor {
/// Execute an instruction
pub fn exec(&mut self, Inst(para, cmd): Inst) {
use key::Key::*;
use mode::Mode::*;
use mode::PrimitiveMode::*;
use mode::CommandMode::*;
let n = para.d();
let bef = self.pos();
let mut mov = false;
match (self.cursor().mode, cmd.key) {
(Primitive(Prompt), Char(' ')) if self.key_state.shift => {
self.prompt = String::new();
self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
},
(Primitive(Insert(_)), Char(' ')) if self.key_state.shift => {
let left = self.left(1);
self.goto(left);
self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
},
(_, Char(' ')) if self.key_state.shift =>
self.cursor_mut().mode = Mode::Command(CommandMode::Normal),
(_, Char(' ')) if self.key_state.alt => self.next_cursor(),
_ if self.key_state.alt => if let Some(m) = self.to_motion(Inst(para, cmd)) {
self.goto(m);
},
(Command(Normal), Char('i')) => {
self.cursor_mut().mode =
Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
mode: InsertMode::Insert,
}));
}
(Command(Normal), Char('a')) => {
let pos = self.right(1, false);
self.goto( pos );
self.cursor_mut().mode =
Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
mode: InsertMode::Insert,
}));
}
(Command(Normal), Char('o')) => {
let y = self.y();
let ind = if self.options.autoindent {
self.buffer.get_indent(y).to_owned()
} else {
String::new()
};
let last = ind.len();
self.buffer.insert_line(y, ind.into());
self.goto((last, y + 1));
self.cursor_mut().mode =
Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
mode: InsertMode::Insert,
}));
}
(Command(Normal), Char('h')) => {
let left = self.left(n);
self.goto(left);
mov = true;
}
(Command(Normal), Char('j')) => {
let down = self.down(n);
self.goto(down);
mov = true;
}
(Command(Normal), Char('k')) => {
let up = self.up(n);
self.goto(up);
mov = true;
}
(Command(Normal), Char('l')) => {
let right = self.right(n, true);
self.goto(right);
mov = true;
}
(Command(Normal), Char('J')) => {
let down = self.down(15 * n);
self.goto(down);
mov = true;
}
(Command(Normal), Char('K')) => {
let up = self.up(15 * n);
self.goto(up);
mov = true;
}
(Command(Normal), Char('x')) => {
self.delete();
let bounded = self.bound(self.pos(), true);
self.goto(bounded);
}
(Command(Normal), Char('X')) => {
self.backspace();
let bounded = self.bound(self.pos(), true);
self.goto(bounded);
}
(Command(Normal), Char('L')) => {
let ln_end = (self.buffer[self.y()].len(), self.y());
self.goto(ln_end);
mov = true;
}
(Command(Normal), Char('H')) => {
self.cursor_mut().x = 0;
mov = true;
}
(Command(Normal), Char('r')) => {
let (x, y) = self.pos();
let c = self.get_char();
// If there is nothing in the current buffer
// ignore the command
if self.buffer[y].len() > 0 {
self.buffer[y].remove(x);
}
self.buffer[y].insert(x, c);
}
(Command(Normal), Char('R')) => {
self.cursor_mut().mode =
Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
mode: InsertMode::Replace,
}));
}
(Command(Normal), Char('d')) => {
let ins = self.get_inst();
if let Some(m) = self.to_motion_unbounded(ins) {
self.remove_rb(m);
}
}
(Command(Normal), Char('G')) => {
let last = self.buffer.len() - 1;
self.goto((0, last));
mov = true;
}
(Command(Normal), Char('g')) => {
if let Parameter::Int(n) = para {
self.goto((0, n - 1));
mov = true;
} else {
let inst = self.get_inst();
if let Some(m) = self.to_motion(inst) {
self.goto(m); // fix
mov = true;
}
}
}
(Command(Normal), Char('b')) => {
// Branch cursor
if self.cursors.len() < 255 {
let cursor = self.cursor().clone();
self.cursors.insert(self.current_cursor as usize, cursor);
self.next_cursor();
}
else {
self.status_bar.msg = format!("At max 255 cursors");
}
}
(Command(Normal), Char('B')) => {
// Delete cursor
if self.cursors.len() > 1 {
self.cursors.remove(self.current_cursor as usize);
self.prev_cursor();
}
else {
self.status_bar.msg = format!("No other cursors!");
}
}
(Command(Normal), Char('t')) => {
let ch = self.get_char();
let pos = self.next_ocur(ch, n);
if let Some(p) = pos {
let y = self.y();
self.goto((p, y));
mov = true;
}
}
(Command(Normal), Char('f')) => {
let ch = self.get_char();
let pos = self.previous_ocur(ch, n);
if let Some(p) = pos {
let y = self.y();
self.goto((p, y));
mov = true;
}
}
(Command(Normal), Char(';')) =>
self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Prompt),
(Command(Normal), Char(' ')) => self.next_cursor(),
(Command(Normal), Char('z')) => {
let Inst(param, cmd) = self.get_inst();
match param {
Parameter::Null => {
if let Some(m) = self.to_motion(Inst(param, cmd)) {
self.scroll_y = m.1;
self.goto(m);
}
}
Parameter::Int(n) => {
self.scroll_y = n;
}
}
self.redraw_task = RedrawTask::Full;
}
(Command(Normal), Char('Z')) => {
self.scroll_y = self.y() - 3;
self.redraw_task = RedrawTask::Full;
}
(Command(Normal), Char('~'))