Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
kirawi committed Jan 28, 2023
1 parent 94b869b commit 31178f0
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 147 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions helix-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ regex = "1"
bitflags = "1.3"
ahash = "0.8.2"
hashbrown = { version = "0.13.1", features = ["raw"] }
walkdir = "2.3"

log = "0.4"
serde = { version = "1.0", features = ["derive"] }
Expand Down
5 changes: 4 additions & 1 deletion helix-core/src/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,14 @@ struct Revision {
timestamp: Instant,
}

const HEADER_TAG: &str = "Helix Undofile\n\n";
const HEADER_TAG: &str = "Helix Undofile";
const CURRENT_VERSION: u8 = 1;

pub fn serialize_history(file: File, history: &History) -> std::io::Result<()> {
let mut writer = std::io::BufWriter::new(file);

write_string(&mut writer, HEADER_TAG)?;
write_byte(&mut writer, CURRENT_VERSION)?;
write_usize(&mut writer, history.current)?;
write_vec(&mut writer, &history.revisions, serialize_revision)?;
Ok(())
Expand All @@ -87,6 +89,7 @@ pub fn deserialize_history(file: File) -> std::io::Result<History> {
"missing undofile header",
))
} else {
let _version = read_byte(&mut reader)?;
let timestamp = Instant::now();
let current = read_usize(&mut reader)?;
let revisions = read_vec(&mut reader, |reader| {
Expand Down
7 changes: 3 additions & 4 deletions helix-core/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,10 +431,9 @@ pub fn serialize_transaction<W: Write>(
write_vec(writer, selection.ranges(), |writer, range| {
write_usize(writer, range.anchor)?;
write_usize(writer, range.head)?;
write_bool(writer, range.horiz.is_some())?;
if let Some(horiz) = range.horiz.as_ref() {
write_u32(writer, *horiz)?;
}
write_option(writer, range.horiz.as_ref(), |writer, horiz| {
write_u32(writer, *horiz)
})?;
Ok(())
})?;

Expand Down
45 changes: 6 additions & 39 deletions helix-view/src/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::{
use anyhow::{Context, Result};
use sha1_smol::Sha1;

pub struct Session {
pub struct Workspace {
path: PathBuf,
lock: Option<FileLock>,
}
Expand All @@ -21,7 +21,7 @@ pub fn path_as_bytes(path: PathBuf) -> Vec<u8> {
return std::os::unix::ffi::OsStrExt::as_bytes(path.as_os_str()).into();
}

impl Session {
impl Workspace {
// TODO: Allow custom session names to be passed.
pub fn new(path: PathBuf) -> Result<Self> {
let bytes = path_as_bytes(path);
Expand All @@ -30,6 +30,10 @@ impl Session {
Ok(Self { path, lock: None })
}

pub fn path(&self) -> PathBuf {
self.path.clone()
}

pub fn get(&mut self, filename: &str) -> Result<File> {
if self.lock.is_none() {
let lock = FileLock::shared(self.path.join(".helix.lock"))?;
Expand Down Expand Up @@ -118,7 +122,6 @@ mod sys {
flock(file, flag)
}

#[cfg(not(target_os = "solaris"))]
fn flock(file: &File, flag: libc::c_int) -> Result<()> {
let ret = unsafe { libc::flock(file.as_raw_fd(), flag) };
if ret < 0 {
Expand All @@ -127,42 +130,6 @@ mod sys {
Ok(())
}
}

#[cfg(target_os = "solaris")]
fn flock(file: &File, flag: libc::c_int) -> Result<()> {
// Solaris lacks flock(), so try to emulate using fcntl()
let mut flock = libc::flock {
l_type: 0,
l_whence: 0,
l_start: 0,
l_len: 0,
l_sysid: 0,
l_pid: 0,
l_pad: [0, 0, 0, 0],
};
flock.l_type = if flag & libc::LOCK_UN != 0 {
libc::F_UNLCK
} else if flag & libc::LOCK_EX != 0 {
libc::F_WRLCK
} else if flag & libc::LOCK_SH != 0 {
libc::F_RDLCK
} else {
panic!("unexpected flock() operation")
};

let mut cmd = libc::F_SETLKW;
if (flag & libc::LOCK_NB) != 0 {
cmd = libc::F_SETLK;
}

let ret = unsafe { libc::fcntl(file.as_raw_fd(), cmd, &flock) };

if ret < 0 {
anyhow::bail!(Error::last_os_error())
} else {
Ok(())
}
}
}

#[cfg(windows)]
Expand Down
173 changes: 70 additions & 103 deletions helix-view/src/session/undo.rs
Original file line number Diff line number Diff line change
@@ -1,103 +1,70 @@
use std::fs::File;
use std::io::BufReader;
use std::io::BufWriter;
use std::path::PathBuf;

#[cfg(unix)]
use std::os::unix::prelude::OsStrExt;

use anyhow::Context;
use anyhow::Result;
use helix_core::history::deserialize_history;
use helix_core::history::serialize_history;
use helix_core::parse::*;

use crate::Editor;

use super::Session;

// TODO: Check if serialized files already exist, and use them.
// TODO: Maybe have a way to verify that the histories match, and overwrite if they don't.
pub fn serialize(session: &mut Session, editor: &mut Editor) -> Result<()> {
// Handle existing index file to merge.
let mut index_file = session.get_mut("undo/index")?;
let mut index = deserialize_index(&index_file).context("failed to parse undo index")?;
for path in editor.documents().filter_map(|doc| doc.path().cloned()) {
if !index.iter().any(|(_, value)| *value == path) {
let key = index.last().map(|(key, _)| key + 1).unwrap_or(0);
index.push((key, path));
}
}
serialize_index(&mut index_file, &index)?;

for (filename, doc_path) in index {
let doc = match editor
.documents_mut()
.find(|doc| doc.path() == Some(&doc_path))
{
Some(doc) => doc,
None => continue,
};
let filename = format!("undo/{filename}");
let file = session.get_mut(&filename)?;
let history = doc.history.take();
serialize_history(file, &history)?;
doc.history.set(history);
}

Ok(())
}

pub fn deserialize(session: &mut Session, editor: &mut Editor) -> Result<()> {
let index = session
.get("undo/index")
.and_then(|file| deserialize_index(&file))
.context("failed to parse index file")?;

for (filename, doc_path) in index {
let id = editor.open(&doc_path, crate::editor::Action::Load)?;
let doc = editor.document_mut(id).unwrap();
let filename = format!("undo/{filename}");
let file = session.get(&filename)?;
doc.history = std::cell::Cell::new(deserialize_history(file)?);
}

Ok(())
}

fn serialize_index(file: &mut File, documents: &[(usize, PathBuf)]) -> Result<()> {
let mut writer = BufWriter::new(file);
write_vec(&mut writer, documents, |writer, (id, path)| {
write_usize(writer, *id)?;

#[cfg(windows)]
write_string(writer, path.to_str().unwrap())?;

#[cfg(unix)]
{
let bytes = path.as_os_str().as_bytes();
write_vec(writer, bytes, |writer, byte| write_byte(writer, *byte))?;
}
Ok(())
})?;

Ok(())
}

fn deserialize_index(file: &File) -> Result<Vec<(usize, PathBuf)>> {
let mut reader = BufReader::new(file);
let res = read_vec(&mut reader, |reader| {
let id = read_usize(reader)?;

#[cfg(windows)]
let path = PathBuf::from(read_string(reader)?);

#[cfg(unix)]
let path = {
let bytes = read_vec(reader, read_byte)?;
PathBuf::from(std::ffi::OsStr::from_bytes(&bytes))
};
Ok((id, path))
})?;
Ok(res)
}
// use std::fs::File;
// use std::io::BufReader;
// use std::io::BufWriter;
// use std::path::PathBuf;

// #[cfg(unix)]
// use std::os::unix::prelude::OsStrExt;

// use anyhow::Context;
// use anyhow::Result;
// use helix_core::history::deserialize_history;
// use helix_core::history::serialize_history;
// use helix_core::parse::*;

// use crate::Editor;

// use super::Session;

// // TODO: Check if serialized files already exist, and use them.
// // TODO: Maybe have a way to verify that the histories match, and overwrite if they don't.
// pub fn serialize(session: &mut Session, editor: &mut Editor) -> Result<()> {
// let cwd = std::env::current_dir()?;
// for doc in editor.documents_mut().filter(|doc| doc.path().is_some()) {

// }
// // Handle existing index file to merge.
// let mut index_file = session.get_mut("undo/index")?;
// let mut index = deserialize_index(&index_file).context("failed to parse undo index")?;
// for path in editor.documents().filter_map(|doc| doc.path().cloned()) {
// if !index.iter().any(|(_, value)| *value == path) {
// let key = index.last().map(|(key, _)| key + 1).unwrap_or(0);
// index.push((key, path));
// }
// }
// serialize_index(&mut index_file, &index)?;

// for (filename, doc_path) in index {
// let doc = match editor
// .documents_mut()
// .find(|doc| doc.path() == Some(&doc_path))
// {
// Some(doc) => doc,
// None => continue,
// };
// let filename = format!("undo/{filename}");
// let file = session.get_mut(&filename)?;
// let history = doc.history.take();
// serialize_history(file, &history)?;
// doc.history.set(history);
// }

// Ok(())
// }

// pub fn deserialize(session: &mut Session, editor: &mut Editor) -> Result<()> {
// let index = session
// .get("undo/index")
// .and_then(|file| deserialize_index(&file))
// .context("failed to parse index file")?;

// for (filename, doc_path) in index {
// let id = editor.open(&doc_path, crate::editor::Action::Load)?;
// let doc = editor.document_mut(id).unwrap();
// let filename = format!("undo/{filename}");
// let file = session.get(&filename)?;
// doc.history = std::cell::Cell::new(deserialize_history(file)?);
// }

// Ok(())
// }

0 comments on commit 31178f0

Please sign in to comment.