diff --git a/CHANGELOG.md b/CHANGELOG.md index d9abd8dc..41bfe004 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - clearer help headers ([#131](https://github.com/extrawurst/gitui/issues/131)) +- diisplay non-utf8 commit messages at least partially ([#150](https://github.com/extrawurst/gitui/issues/150)) ## [0.7.0] - 2020-06-15 diff --git a/Cargo.lock b/Cargo.lock index bf1b7731..dab09e77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,6 +45,7 @@ version = "0.7.0" dependencies = [ "crossbeam-channel", "git2", + "invalidstring", "log", "rayon-core", "scopetime", @@ -367,6 +368,10 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "invalidstring" +version = "0.1.0" + [[package]] name = "iovec" version = "0.1.4" diff --git a/asyncgit/Cargo.toml b/asyncgit/Cargo.toml index deca102e..6d91f144 100644 --- a/asyncgit/Cargo.toml +++ b/asyncgit/Cargo.toml @@ -12,12 +12,13 @@ categories = ["concurrency","asynchronous"] keywords = ["git"] [dependencies] +scopetime = { path = "../scopetime", version = "0.1" } git2 = { version = "0.13.6", default-features = false } rayon-core = "1.7" crossbeam-channel = "0.4" log = "0.4" -scopetime = { path = "../scopetime", version = "0.1" } thiserror = "1.0" [dev-dependencies] -tempfile = "3.1" \ No newline at end of file +tempfile = "3.1" +invalidstring = { path = "../invalidstring", version = "0.1" } \ No newline at end of file diff --git a/asyncgit/src/sync/commits_info.rs b/asyncgit/src/sync/commits_info.rs index 7bd78485..39256352 100644 --- a/asyncgit/src/sync/commits_info.rs +++ b/asyncgit/src/sync/commits_info.rs @@ -2,6 +2,7 @@ use super::utils::repo; use crate::error::Result; use git2::{Commit, Error, Oid}; use scopetime::scope_time; +use std::borrow::Cow; /// identifies a single commit #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -81,14 +82,13 @@ pub fn get_commits_info( } fn get_message(c: &Commit, message_length_limit: usize) -> String { - if let Some(msg) = c.message() { - limit_str(msg, message_length_limit) - } else { - String::from("") - } + limit_str( + String::from_utf8_lossy(c.message_bytes()), + message_length_limit, + ) } -fn limit_str(s: &str, limit: usize) -> String { +fn limit_str(s: Cow<'_, str>, limit: usize) -> String { if let Some(first) = s.lines().next() { first.chars().take(limit).collect::() } else { @@ -103,6 +103,7 @@ mod tests { use crate::error::Result; use crate::sync::{ commit, stage_add_file, tests::repo_init_empty, + utils::get_head_repo, }; use std::{fs::File, io::Write, path::Path}; @@ -130,4 +131,31 @@ mod tests { Ok(()) } + + #[test] + fn test_invalid_utf8() -> Result<()> { + let file_path = Path::new("foo"); + let (_td, repo) = repo_init_empty().unwrap(); + let root = repo.path().parent().unwrap(); + let repo_path = root.as_os_str().to_str().unwrap(); + + File::create(&root.join(file_path))?.write_all(b"a")?; + stage_add_file(repo_path, file_path).unwrap(); + + let msg = invalidstring::invalid_utf8("test msg"); + commit(repo_path, msg.as_str()).unwrap(); + + let res = get_commits_info( + repo_path, + &vec![get_head_repo(&repo).unwrap().into()], + 50, + ) + .unwrap(); + + assert_eq!(res.len(), 1); + dbg!(&res[0].message); + assert_eq!(res[0].message.starts_with("test msg"), true); + + Ok(()) + } } diff --git a/invalidstring/Cargo.toml b/invalidstring/Cargo.toml new file mode 100644 index 00000000..c122d2f7 --- /dev/null +++ b/invalidstring/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "invalidstring" +version = "0.1.0" +authors = ["Stephan Dilly "] +edition = "2018" +description = "just for testing invalid string data" +homepage = "https://github.com/extrawurst/gitui" +repository = "https://github.com/extrawurst/gitui" +readme = "README.md" +license = "MIT" +categories = ["testing","utf8"] +keywords = ["string"] + +[dependencies] diff --git a/invalidstring/README.md b/invalidstring/README.md new file mode 100644 index 00000000..eea0615c --- /dev/null +++ b/invalidstring/README.md @@ -0,0 +1,5 @@ +# invalidstring + +*just for testing invalid string data* + +This crate is part of the [gitui](http://gitui.org) project. We need this to be a seperate crate so that `asyncgit` can remain forbidding `unsafe`. \ No newline at end of file diff --git a/invalidstring/src/lib.rs b/invalidstring/src/lib.rs new file mode 100644 index 00000000..be241417 --- /dev/null +++ b/invalidstring/src/lib.rs @@ -0,0 +1,8 @@ +/// uses unsafe to postfix the string with invalid utf8 data +pub fn invalid_utf8(prefix: &str) -> String { + let bytes = b"\xc3\x73"; + + unsafe { + format!("{}{}", prefix, std::str::from_utf8_unchecked(bytes)) + } +}