## 再現手順
1. [[git-igitt]]を起動
2. 一番下のコミットまで移動
3. 1つ上のコミットに移動
## エラーログ
```error
thread 'main' panicked at 'assertion failed: min <= max', /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be\library\core\src\cmp.rs:840:9
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library\std\src\panicking.rs:593
1: core::panicking::panic_fmt
at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library\core\src\panicking.rs:67
2: core::panicking::panic
at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library\core\src\panicking.rs:117
3: __ImageBase
4: __ImageBase
5: __ImageBase
6: __ImageBase
7: __ImageBase
8: main
9: invoke_main
at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
10: __scrt_common_main_seh
at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
11: BaseThreadInitThunk
12: RtlUserThreadStart
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
```
## 調査
落ちている場所は分からないので検討をつけにいってみる。
コマンド(ホットキー)に関する処理は`main.rs`に記載されているので眺めてみる。以下のようにコメントアウトしてみた。
```rust
KeyCode::Up | KeyCode::Char('k') => {
let (rd, rf) = app.on_up(
false, // XXX
event.modifiers.contains(KeyModifiers::CONTROL),
)?;
// reload_diffs = rd;
// reload_file = rf;
}
```
この場合も再現する。つまり問題は`app.on_up`で起こっている。
`graph_view.rs`の以下が実行される。
```rust
impl GraphViewState {
pub fn move_selection(&mut self, steps: usize, down: bool) -> bool {
// steps: 1, down: false
stdout().execute(cursor::MoveTo(150, 20));
stdout().execute(crossterm::style::Print(format!(
"steps: {:8}",
self.selected.unwrap()
)));
let changed = if let Some(sel) = self.selected {
let new_idx = if down {
std::cmp::min(sel.saturating_add(steps), self.indices.len() - 1)
} else {
std::cmp::max(sel.saturating_sub(steps), 0)
};
self.selected = Some(new_idx);
new_idx != sel
} else if !self.graph_lines.is_empty() {
self.selected = Some(0);
true
} else {
false
};
if changed {
self.secondary_changed = false;
}
changed
}
```
- 1番上が0
- 1つ下が1
- 1番下だと落ちるからわからん..
`123`までは表示されたのでそこ。
```
124番目
125番目
126番目
```
- 124 -> 125が落ちる
- 126 -> 125も落ちる
もしかして125への移動がダメ?
126に移動してその後に移動しても落ちない...。ムムム。
`-n 15`でやっても最後から2つ目で落ちる。コミットグラフの内容の問題ではない気がする。
`clamp`で落ちていることは分かった。
```rust
#[must_use]
#[stable(feature = "clamp", since = "1.50.0")]
fn clamp(self, min: Self, max: Self) -> Self
where
Self: Sized,
Self: PartialOrd,
{
assert!(min <= max);
if self < min {
min
} else if self > max {
max
} else {
self
}
}
```
`graph_view.rs`の以下2箇所が怪しい。
```rust
let move_to_end = if selected_index >= state.indices.len() - 1 {
state.graph_lines.len() - 1
} else {
(state.indices[selected_index + 1] - 1).clamp(
move_to_selected + SCROLL_MARGIN,
state.graph_lines.len() - 1,
)
};
```
```rust
let scroll_start = list_area.top() as usize
+ (((list_height * start) as f32 / state.graph_lines.len() as f32).ceil() as usize)
.min(list_height - 1);
let scroll_height = (((list_height * list_height) as f32 / state.graph_lines.len() as f32)
.floor() as usize)
.clamp(1, list_height);
```
前者の`clamp`をコメントアウトしたら落ちなくなった。
```rust
let move_to_end = if selected_index >= state.indices.len() - 1 {
state.graph_lines.len() - 1
} else {
state.indices[selected_index + 1] - 1
// (state.indices[selected_index + 1] - 1).clamp(
// move_to_selected + SCROLL_MARGIN,
// state.graph_lines.len() - 1,
// )
};
let move_to_start = move_to_selected.saturating_sub(SCROLL_MARGIN);
```
この処理がなぜ必要なのかを考慮する必要がある。
## 改めて確認
| パラメータ | 意味 |
| ----------------------- | ----------------------------------------------------- |
| move_to_selected | ターミナルのN+1行目 (0から。空行も1カウント) |
| state.graph_lines.len() | コミットグラフのターミナル最大行数 |
| selected_index | 上からN+1番目のコミット (0から。空行はカウントしない) |
| state.indices.len() | コミット行の総数 |
| SCROLL_MARGIN | ??? (3で固定?) |
- `move_to_selected + SCROLL_MARGIN` が `state.graph_lines.len()` を2上回っている
- これが直接的な原因