Skip to content

Commit b17e061

Browse files
committed
Fix crash on multibyte string in commit diff
When a multibyte string was found during the scan for whitespace characters, it could cause a crash due to an invalid index.
1 parent d1c57f9 commit b17e061

2 files changed

Lines changed: 39 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file.
33

44
The format is based on [Keep a Changelog](http://keepachangelog.com/).
55

6+
## [2.2.1] - 2022-10-13
7+
### Fixed
8+
- Crash on multibyte strings in commit diff view ([#755](https://github.com/MitMaro/git-interactive-rebase-tool/pull/755))
9+
610
## [2.2.0] - 2022-04-21
711
### Added
812
- Added mew keybindings for customizing the scrolling the view. ([#647](https://github.com/MitMaro/git-interactive-rebase-tool/pull/647))
@@ -161,7 +165,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
161165
### Added
162166
- Initial project release
163167

164-
[Unreleased]: https://github.com/MitMaro/git-interactive-rebase-tool/compare/2.2.0...HEAD
168+
[Unreleased]: https://github.com/MitMaro/git-interactive-rebase-tool/compare/2.2.1...HEAD
169+
[2.2.1]: https://github.com/MitMaro/git-interactive-rebase-tool/compare/2.2.1...2.2.0
165170
[2.2.0]: https://github.com/MitMaro/git-interactive-rebase-tool/compare/2.2.0...2.1.0
166171
[2.1.0]: https://github.com/MitMaro/git-interactive-rebase-tool/compare/2.0.0...2.1.0
167172
[2.0.0]: https://github.com/MitMaro/git-interactive-rebase-tool/compare/1.2.1...2.0.0

src/core/src/modules/show_commit/util.rs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,23 +151,52 @@ pub(super) fn get_files_changed_summary(diff: &CommitDiff, is_full_width: bool)
151151

152152
pub(super) fn get_partition_index_on_whitespace_for_line(line: &str) -> (usize, usize) {
153153
let graphemes = UnicodeSegmentation::graphemes(line, true);
154-
let length = graphemes.clone().count();
154+
let length = graphemes.clone().map(|c| c.len()).sum();
155155
let mut start_partition_index = 0;
156156
let mut end_partition_index = length;
157157

158-
for (index, c) in graphemes.clone().enumerate() {
158+
let mut index = 0;
159+
for c in graphemes.clone() {
159160
if c != " " && c != "\t" && c != "\n" {
160161
start_partition_index = index;
161162
break;
162163
}
164+
index += c.len();
163165
}
164166

165-
for (index, c) in graphemes.rev().enumerate() {
167+
index = length;
168+
for c in graphemes.rev() {
166169
if c != " " && c != "\t" && c != "\n" {
167-
end_partition_index = length - index;
170+
end_partition_index = index;
168171
break;
169172
}
173+
index -= c.len();
170174
}
171175

172176
(start_partition_index, end_partition_index)
173177
}
178+
179+
#[cfg(test)]
180+
mod tests {
181+
use rstest::rstest;
182+
183+
use super::*;
184+
185+
#[rstest]
186+
#[case::empty_string("", 0, 0)]
187+
#[case::single_character("a", 0, 1)]
188+
#[case::multiple_characters("abc", 0, 3)]
189+
#[case::internal_spaces(" a b c ", 1, 6)]
190+
#[case::leading_whitespace(" a", 1, 2)]
191+
#[case::trailing_whitespace("a ", 0, 1)]
192+
#[case::leading_trailing_whitespace(" a ", 1, 2)]
193+
#[case::all_supported_whitespace_characters(" \ta \t\n", 2, 3)]
194+
#[case::multi_byte_character("…", 0, 3)]
195+
#[case::multi_byte_character_leading_whitespace(" …", 1, 4)]
196+
#[case::multi_byte_character_trailing_whitespace("… ", 0, 3)]
197+
#[case::multi_byte_character_leading_trailing_whitespace(" … ", 1, 4)]
198+
#[case::multi_byte_character_in_middle(" a…b ", 1, 6)]
199+
fn get_partition_index_on_whitespace_for_line_cases(#[case] s: &str, #[case] start: usize, #[case] end: usize) {
200+
assert_eq!(get_partition_index_on_whitespace_for_line(s), (start, end));
201+
}
202+
}

0 commit comments

Comments
 (0)