Move filepath into the Buffer struct.
This commit is contained in:
parent
4544efb299
commit
e1d91ff43d
|
@ -4,13 +4,13 @@ use std::{
|
||||||
cmp::{max, min},
|
cmp::{max, min},
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{self, BufReader, BufWriter, Write},
|
io::{self, BufWriter, Write},
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use ropey::Rope;
|
use backend::{
|
||||||
|
buffer::{Buffer, BufferPath},
|
||||||
use backend::{buffer::Buffer, marks::Mark};
|
marks::Mark,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
formatter::LineFormatter,
|
formatter::LineFormatter,
|
||||||
|
@ -24,7 +24,6 @@ use crate::{
|
||||||
pub struct Editor {
|
pub struct Editor {
|
||||||
pub buffer: Buffer,
|
pub buffer: Buffer,
|
||||||
pub formatter: LineFormatter,
|
pub formatter: LineFormatter,
|
||||||
pub file_path: PathBuf,
|
|
||||||
pub line_ending_type: LineEnding,
|
pub line_ending_type: LineEnding,
|
||||||
pub soft_tabs: bool,
|
pub soft_tabs: bool,
|
||||||
pub soft_tab_width: u8,
|
pub soft_tab_width: u8,
|
||||||
|
@ -43,48 +42,18 @@ pub struct Editor {
|
||||||
|
|
||||||
impl Editor {
|
impl Editor {
|
||||||
/// Create a new blank editor
|
/// Create a new blank editor
|
||||||
pub fn new(formatter: LineFormatter) -> Editor {
|
pub fn new(buffer: Buffer, formatter: LineFormatter) -> Editor {
|
||||||
let (buffer, v_msi, c_msi) = {
|
let mut buffer = buffer;
|
||||||
let mut buffer = Buffer::new("".into());
|
|
||||||
let view_idx = buffer.add_mark_set();
|
|
||||||
let cursors_idx = buffer.add_mark_set();
|
|
||||||
|
|
||||||
buffer.mark_sets[view_idx].add_mark(Mark::new(0, 0));
|
// Create appropriate mark sets for view positions and cursors.
|
||||||
buffer.mark_sets[cursors_idx].add_mark(Mark::new(0, 0));
|
let v_msi = buffer.add_mark_set();
|
||||||
|
let c_msi = buffer.add_mark_set();
|
||||||
(buffer, view_idx, cursors_idx)
|
buffer.mark_sets[v_msi].add_mark(Mark::new(0, 0));
|
||||||
};
|
buffer.mark_sets[c_msi].add_mark(Mark::new(0, 0));
|
||||||
|
|
||||||
Editor {
|
|
||||||
buffer: buffer,
|
|
||||||
formatter: formatter,
|
|
||||||
file_path: PathBuf::new(),
|
|
||||||
line_ending_type: LineEnding::LF,
|
|
||||||
soft_tabs: false,
|
|
||||||
soft_tab_width: 4,
|
|
||||||
editor_dim: (0, 0),
|
|
||||||
view_dim: (0, 0),
|
|
||||||
v_msi: v_msi,
|
|
||||||
c_msi: c_msi,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_from_file(formatter: LineFormatter, path: &Path) -> io::Result<Editor> {
|
|
||||||
let (buffer, v_msi, c_msi) = {
|
|
||||||
let mut buffer = Buffer::new(Rope::from_reader(BufReader::new(File::open(path)?))?);
|
|
||||||
let view_idx = buffer.add_mark_set();
|
|
||||||
let cursors_idx = buffer.add_mark_set();
|
|
||||||
|
|
||||||
buffer.mark_sets[view_idx].add_mark(Mark::new(0, 0));
|
|
||||||
buffer.mark_sets[cursors_idx].add_mark(Mark::new(0, 0));
|
|
||||||
|
|
||||||
(buffer, view_idx, cursors_idx)
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut ed = Editor {
|
let mut ed = Editor {
|
||||||
buffer: buffer,
|
buffer: buffer,
|
||||||
formatter: formatter,
|
formatter: formatter,
|
||||||
file_path: path.to_path_buf(),
|
|
||||||
line_ending_type: LineEnding::LF,
|
line_ending_type: LineEnding::LF,
|
||||||
soft_tabs: false,
|
soft_tabs: false,
|
||||||
soft_tab_width: 4,
|
soft_tab_width: 4,
|
||||||
|
@ -97,18 +66,20 @@ impl Editor {
|
||||||
ed.auto_detect_line_ending();
|
ed.auto_detect_line_ending();
|
||||||
ed.auto_detect_indentation_style();
|
ed.auto_detect_indentation_style();
|
||||||
|
|
||||||
Ok(ed)
|
ed
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_if_dirty(&mut self) -> io::Result<()> {
|
pub fn save_if_dirty(&mut self) -> io::Result<()> {
|
||||||
if self.buffer.is_dirty && self.file_path != PathBuf::new() {
|
if let BufferPath::File(ref file_path) = self.buffer.path {
|
||||||
let mut f = BufWriter::new(File::create(&self.file_path)?);
|
if self.buffer.is_dirty {
|
||||||
|
let mut f = BufWriter::new(File::create(file_path)?);
|
||||||
|
|
||||||
for c in self.buffer.text.chunks() {
|
for c in self.buffer.text.chunks() {
|
||||||
f.write(c.as_bytes())?;
|
f.write(c.as_bytes())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.buffer.is_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.buffer.is_dirty = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
23
src/main.rs
23
src/main.rs
|
@ -1,8 +1,13 @@
|
||||||
use std::{io::Write, path::Path};
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::{BufReader, Write},
|
||||||
|
};
|
||||||
|
|
||||||
|
use backend::buffer::{Buffer, BufferPath};
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use editor::Editor;
|
use editor::Editor;
|
||||||
use formatter::LineFormatter;
|
use formatter::LineFormatter;
|
||||||
|
use ropey::Rope;
|
||||||
use term_ui::TermUI;
|
use term_ui::TermUI;
|
||||||
|
|
||||||
mod editor;
|
mod editor;
|
||||||
|
@ -14,7 +19,7 @@ mod utils;
|
||||||
|
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
fn main() {
|
fn main() -> std::io::Result<()> {
|
||||||
// Parse command line arguments.
|
// Parse command line arguments.
|
||||||
let args = App::new("Led")
|
let args = App::new("Led")
|
||||||
.version(VERSION)
|
.version(VERSION)
|
||||||
|
@ -28,13 +33,17 @@ fn main() {
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
// Load file, if specified
|
// Load file, if specified
|
||||||
let editor = if let Some(filepath) = args.value_of("file") {
|
let buffer = if let Some(filepath) = args.value_of("file") {
|
||||||
Editor::new_from_file(LineFormatter::new(4), &Path::new(&filepath[..]))
|
Buffer::new(
|
||||||
.expect(&format!("Couldn't open file '{}'.", filepath))
|
Rope::from_reader(BufReader::new(File::open(filepath)?))?,
|
||||||
|
BufferPath::File(filepath.into()),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
Editor::new(LineFormatter::new(4))
|
Buffer::new("".into(), BufferPath::Temp(0))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let editor = Editor::new(buffer, LineFormatter::new(4));
|
||||||
|
|
||||||
// Holds stderr output in an internal buffer, and prints it when dropped.
|
// Holds stderr output in an internal buffer, and prints it when dropped.
|
||||||
// This keeps stderr from being swallowed by the TUI.
|
// This keeps stderr from being swallowed by the TUI.
|
||||||
let stderr_hold = gag::Hold::stderr().unwrap();
|
let stderr_hold = gag::Hold::stderr().unwrap();
|
||||||
|
@ -58,4 +67,6 @@ fn main() {
|
||||||
// Resume panic unwind.
|
// Resume panic unwind.
|
||||||
std::panic::resume_unwind(e);
|
std::panic::resume_unwind(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,10 @@ use crossterm::{
|
||||||
style::Color,
|
style::Color,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use backend::buffer::BufferPath;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
editor::Editor,
|
editor::Editor,
|
||||||
formatter::LineFormatter,
|
|
||||||
string_utils::{char_count, is_line_ending, line_ending_to_str, LineEnding},
|
string_utils::{char_count, is_line_ending, line_ending_to_str, LineEnding},
|
||||||
utils::{digit_count, Timer},
|
utils::{digit_count, Timer},
|
||||||
};
|
};
|
||||||
|
@ -187,10 +188,6 @@ enum LoopStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TermUI {
|
impl TermUI {
|
||||||
pub fn new() -> TermUI {
|
|
||||||
TermUI::new_from_editor(Editor::new(LineFormatter::new(4)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_from_editor(ed: Editor) -> TermUI {
|
pub fn new_from_editor(ed: Editor) -> TermUI {
|
||||||
let (w, h) = crossterm::terminal::size().unwrap();
|
let (w, h) = crossterm::terminal::size().unwrap();
|
||||||
let mut editor = ed;
|
let mut editor = ed;
|
||||||
|
@ -463,7 +460,10 @@ impl TermUI {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filename and dirty marker
|
// Filename and dirty marker
|
||||||
let filename = editor.file_path.display();
|
let filename = match editor.buffer.path {
|
||||||
|
BufferPath::File(ref p) => format!("{}", p.display()),
|
||||||
|
BufferPath::Temp(i) => format!("Scratch #{}", i + 1),
|
||||||
|
};
|
||||||
let dirty_char = if editor.buffer.is_dirty { "*" } else { "" };
|
let dirty_char = if editor.buffer.is_dirty { "*" } else { "" };
|
||||||
let name = format!("{}{}", filename, dirty_char);
|
let name = format!("{}{}", filename, dirty_char);
|
||||||
self.screen.draw(c1.1 + 1, c1.0, &name[..], STYLE_INFO);
|
self.screen.draw(c1.1 + 1, c1.0, &name[..], STYLE_INFO);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use ropey::Rope;
|
use ropey::Rope;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -5,9 +7,20 @@ use crate::{
|
||||||
marks::MarkSet,
|
marks::MarkSet,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A path for an open text buffer.
|
||||||
|
///
|
||||||
|
/// This indicates where the text data of the buffer came from, and
|
||||||
|
/// where it should be saved to.
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub enum BufferPath {
|
||||||
|
File(PathBuf), // A buffer for a normal file on disk.
|
||||||
|
Temp(usize), // A temporary buffer, with a number ID.
|
||||||
|
}
|
||||||
|
|
||||||
/// An open text buffer, currently being edited.
|
/// An open text buffer, currently being edited.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Buffer {
|
pub struct Buffer {
|
||||||
|
pub path: BufferPath,
|
||||||
pub is_dirty: bool, // Is this buffer currently out of sync with disk.
|
pub is_dirty: bool, // Is this buffer currently out of sync with disk.
|
||||||
pub text: Rope, // The actual text content.
|
pub text: Rope, // The actual text content.
|
||||||
pub mark_sets: Vec<MarkSet>, // MarkSets for cursors, view positions, etc.
|
pub mark_sets: Vec<MarkSet>, // MarkSets for cursors, view positions, etc.
|
||||||
|
@ -15,8 +28,9 @@ pub struct Buffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Buffer {
|
impl Buffer {
|
||||||
pub fn new(text: Rope) -> Buffer {
|
pub fn new(text: Rope, path: BufferPath) -> Buffer {
|
||||||
Buffer {
|
Buffer {
|
||||||
|
path: path,
|
||||||
is_dirty: false,
|
is_dirty: false,
|
||||||
text: text,
|
text: text,
|
||||||
mark_sets: Vec::new(),
|
mark_sets: Vec::new(),
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use crate::buffer::Buffer;
|
use crate::buffer::Buffer;
|
||||||
|
|
||||||
/// A struct holding the current editor state.
|
/// A struct holding the current editor state.
|
||||||
|
@ -7,12 +5,5 @@ use crate::buffer::Buffer;
|
||||||
/// The Editor represents all currently open buffers available for editing.
|
/// The Editor represents all currently open buffers available for editing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Editor {
|
pub struct Editor {
|
||||||
open_buffers: Vec<(BufferID, Buffer)>,
|
open_buffers: Vec<Buffer>,
|
||||||
}
|
|
||||||
|
|
||||||
/// An ID for an open text buffer.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum BufferID {
|
|
||||||
File(PathBuf), // A buffer for a normal file on disk, using the full on-disk path as the ID
|
|
||||||
Temp(usize), // A temporary buffer, with a number ID
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user