1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
|
diff --git xsrc/plusminus_header_highlighter.rs xsrc/plusminus_header_highlighter.rs
index 5bb5056..c354931 100644
--- xsrc/plusminus_header_highlighter.rs
+++ xsrc/plusminus_header_highlighter.rs
@@ -6,7 +6,7 @@ use crate::lines_highlighter::{LinesHighlighter, Response};
use crate::refiner::to_highlighted_tokens;
use crate::string_future::StringFuture;
use crate::token_collector::{
- lowlight_timestamp, render, unhighlight_git_prefix, LINE_STYLE_NEW_FILENAME,
+ align_tabs, lowlight_timestamp, render, unhighlight_git_prefix, LINE_STYLE_NEW_FILENAME,
LINE_STYLE_OLD_FILENAME,
};
@@ -92,8 +92,11 @@ impl PlusMinusHeaderHighlighter {
to_highlighted_tokens(&self.old_name, &self.new_name);
lowlight_timestamp(&mut old_tokens);
- unhighlight_git_prefix(&mut old_tokens);
lowlight_timestamp(&mut new_tokens);
+
+ align_tabs(&mut old_tokens, &mut new_tokens);
+
+ unhighlight_git_prefix(&mut old_tokens);
unhighlight_git_prefix(&mut new_tokens);
let old_filename = render(&LINE_STYLE_OLD_FILENAME, "--- ", &old_tokens);
@@ -108,3 +111,34 @@ impl PlusMinusHeaderHighlighter {
return highlighted;
}
}
+
+#[cfg(test)]
+mod tests {
+ use crate::ansi::remove_ansi_escape_codes;
+
+ use super::*;
+
+ #[test]
+ fn test_align_timestamps() {
+ let mut test_me =
+ PlusMinusHeaderHighlighter::from_line("--- x.txt\t2023-12-15 15:43:29").unwrap();
+ let mut response = test_me
+ .consume_line(
+ "+++ /Users/johan/src/riff/README.md\t2024-01-29 14:56:40",
+ &ThreadPool::new(1),
+ )
+ .unwrap();
+ assert_eq!(LineAcceptance::AcceptedDone, response.line_accepted);
+ assert_eq!(1, response.highlighted.len());
+
+ let mut highlighted = response.highlighted[0].get().to_string().into_bytes();
+ remove_ansi_escape_codes(&mut highlighted);
+ let plain = String::from_utf8(highlighted).unwrap();
+
+ assert_eq!(
+ "--- x.txt 2023-12-15 15:43:29\n\
+ +++ /Users/johan/src/riff/README.md 2024-01-29 14:56:40\n",
+ plain.as_str()
+ );
+ }
+}
diff --git xsrc/token_collector.rs xsrc/token_collector.rs
index b58c50f..e4d4152 100644
--- xsrc/token_collector.rs
+++ xsrc/token_collector.rs
@@ -1,3 +1,5 @@
+use std::cmp;
+
use crate::ansi::AnsiStyle;
use crate::ansi::Color::Default;
use crate::ansi::Color::Green;
@@ -311,6 +313,38 @@ pub fn highlight_nonleading_tabs(tokens: &mut [StyledToken]) {
}
}
+pub(crate) fn align_tabs(old: &mut [StyledToken], new: &mut [StyledToken]) {
+ let old_tab_index_token = old.iter().position(|token| token.token == "\t");
+ if old_tab_index_token.is_none() {
+ return;
+ }
+ let old_tab_index_token = old_tab_index_token.unwrap();
+ let old_tab_index_char = old
+ .iter()
+ .take(old_tab_index_token)
+ .map(|token| token.token.chars().count())
+ .sum::<usize>();
+
+ let new_tab_index_token = new.iter().position(|token| token.token == "\t");
+ if new_tab_index_token.is_none() {
+ return;
+ }
+ let new_tab_index_token = new_tab_index_token.unwrap();
+ let new_tab_index_char = new
+ .iter()
+ .take(new_tab_index_token)
+ .map(|token| token.token.chars().count())
+ .sum::<usize>();
+
+ let old_spaces =
+ " ".repeat(2 + cmp::max(old_tab_index_char, new_tab_index_char) - old_tab_index_char);
+ let new_spaces =
+ " ".repeat(2 + cmp::max(old_tab_index_char, new_tab_index_char) - new_tab_index_char);
+
+ old[old_tab_index_token].token = old_spaces;
+ new[new_tab_index_token].token = new_spaces;
+}
+
/// Highlight single space between two highlighted tokens
pub fn bridge_consecutive_highlighted_tokens(tokens: &mut [StyledToken]) {
enum FoundState {
|