Move filepath into the Buffer struct.

This commit is contained in:
Nathan Vegdahl 2020-02-24 07:35:04 +09:00
parent 4544efb299
commit e1d91ff43d
5 changed files with 60 additions and 73 deletions

View File

@ -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(())

View File

@ -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(())
} }

View File

@ -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);

View File

@ -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(),

View File

@ -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
} }