Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vim-like Persistent Undo #9154

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions book/src/generated/typable-cmd.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,5 @@
| `:redraw` | Clear and re-render the whole UI |
| `:move` | Move the current buffer and its corresponding file to a different path |
| `:yank-diagnostic` | Yank diagnostic(s) under primary cursor to register, or clipboard by default |
| `:history-reload` | Prepends undofile history to current history. |
| `:delete-undofile` | Delete undofile associated with the currently focused document |
5 changes: 5 additions & 0 deletions helix-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ ahash = "0.8.11"
hashbrown = { version = "0.14.3", features = ["raw"] }
dunce = "1.0"

blake3 = "1.5"
anyhow = "1"

log = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
Expand All @@ -57,3 +60,5 @@ globset = "0.4.14"
[dev-dependencies]
quickcheck = { version = "1", default-features = false }
indoc = "2.0.5"
tempfile = "3.9"
rand = { version = "0.8", default-features = false, features = ["getrandom", "small_rng"] }
130 changes: 130 additions & 0 deletions helix-core/src/combinators.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
use std::io::Error;
use std::io::ErrorKind;
use std::io::Read;
use std::io::Result;
use std::io::Write;

pub fn write_byte<W: Write>(writer: &mut W, byte: u8) -> Result<()> {
writer.write_all(&[byte])
}

pub fn write_bool<W: Write>(writer: &mut W, state: bool) -> Result<()> {
write_byte(writer, state as u8)
}

pub fn write_u32<W: Write>(writer: &mut W, n: u32) -> Result<()> {
writer.write_all(&n.to_ne_bytes())
}

pub fn write_u64<W: Write>(writer: &mut W, n: u64) -> Result<()> {
writer.write_all(&n.to_ne_bytes())
}

pub fn write_usize<W: Write>(writer: &mut W, n: usize) -> Result<()> {
writer.write_all(&n.to_ne_bytes())
}

pub fn write_string<W: Write>(writer: &mut W, s: &str) -> Result<()> {
write_usize(writer, s.len())?;
writer.write_all(s.as_bytes())
}

pub fn write_vec<W: Write, T>(
writer: &mut W,
slice: &[T],
f: impl Fn(&mut W, &T) -> Result<()>,
) -> Result<()> {
write_usize(writer, slice.len())?;
for element in slice {
f(writer, element)?;
}
Ok(())
}

pub fn write_option<W: Write, T>(
writer: &mut W,
value: Option<T>,
f: impl Fn(&mut W, T) -> Result<()>,
) -> Result<()> {
write_bool(writer, value.is_some())?;
if let Some(value) = value {
f(writer, value)?;
}
Ok(())
}

pub fn read_byte<R: Read>(reader: &mut R) -> Result<u8> {
match reader.bytes().next() {
Some(s) => s,
None => Err(Error::from(ErrorKind::UnexpectedEof)),
}
}

pub fn read_bool<R: Read>(reader: &mut R) -> Result<bool> {
let res = match read_byte(reader)? {
0 => false,
1 => true,
_ => {
return Err(Error::new(
ErrorKind::Other,
"invalid byte to bool conversion",
))
}
};
Ok(res)
}

pub fn read_u32<R: Read>(reader: &mut R) -> Result<u32> {
let mut buf = [0u8; 4];
reader.read_exact(&mut buf)?;
Ok(u32::from_ne_bytes(buf))
}

pub fn read_u64<R: Read>(reader: &mut R) -> Result<u64> {
let mut buf = [0u8; 8];
reader.read_exact(&mut buf)?;
Ok(u64::from_ne_bytes(buf))
}

pub fn read_usize<R: Read>(reader: &mut R) -> Result<usize> {
let mut buf = [0u8; std::mem::size_of::<usize>()];
reader.read_exact(&mut buf)?;
Ok(usize::from_ne_bytes(buf))
}

/// SAFETY: Only use if it is guaranteed to be a string
pub fn read_string<R: Read>(reader: &mut R) -> Result<String> {
let len = read_usize(reader)?;
let mut buf = vec![0; len];
reader.read_exact(&mut buf)?;

let res = String::from_utf8(buf).map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
Ok(res)
}

pub fn read_vec<R: Read, T>(reader: &mut R, f: impl Fn(&mut R) -> Result<T>) -> Result<Vec<T>> {
let len = read_usize(reader)?;
let mut res = Vec::with_capacity(len);
for _ in 0..len {
res.push(f(reader)?);
}
Ok(res)
}

pub fn read_option<R: Read, T>(
reader: &mut R,
f: impl Fn(&mut R) -> Result<T>,
) -> Result<Option<T>> {
let res = if read_bool(reader)? {
Some(f(reader)?)
} else {
None
};
Ok(res)
}

pub fn read_many_bytes<R: Read, const N: usize>(reader: &mut R) -> Result<[u8; N]> {
let mut buf = [0u8; N];
reader.read_exact(&mut buf)?;
Ok(buf)
}
Loading
Loading