Skip to main content

git_tailor/views/
main_view.rs

1// Copyright 2026 Thomas Johannesson
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use ratatui::{
16    layout::Rect,
17    style::{Color, Style},
18    text::{Line, Span},
19    widgets::Paragraph,
20};
21
22use crate::app::AppState;
23use crate::repo::GitRepo;
24use crate::views;
25
26/// Render the main view with split screen (commit list on left, detail on right).
27pub fn render(git_repo: &impl GitRepo, app: &mut AppState, frame: &mut ratatui::Frame) {
28    let area = frame.area();
29    const BASE_SPLIT_X: i32 = 72; // SHA(10) + gap(1) + title(60) + gap(1)
30    // MIN_LEFT: scrollbar(1) + SHA(10) + col-gap(1) + min-title(10) + panel-sep(1) = 23
31    // This matches CommitList mode's minimum separator position so both modes
32    // stop at the same column, and SHA is never obscured by the panel separator.
33    const MIN_LEFT: i32 = 23;
34    const MIN_RIGHT: i32 = 20;
35    let max_offset = (area.width as i32 - BASE_SPLIT_X - MIN_RIGHT).max(0);
36    let min_offset = (MIN_LEFT - BASE_SPLIT_X).min(0);
37    let clamped_offset = (app.separator_offset as i32).clamp(min_offset, max_offset);
38    app.separator_offset = clamped_offset as i16;
39    let separator_x = ((BASE_SPLIT_X + clamped_offset) as u16).min(area.width);
40    let left_width = separator_x.min(area.width);
41    let right_width = area.width.saturating_sub(left_width);
42
43    if right_width > 0 {
44        let left_area = Rect {
45            x: area.x,
46            y: area.y,
47            width: left_width.saturating_sub(1), // exclude the separator column itself
48            height: area.height,
49        };
50        let right_area = Rect {
51            x: area.x + left_width,
52            y: area.y,
53            width: right_width,
54            height: area.height,
55        };
56
57        // Suppress fragmap columns in the narrow left panel but keep the fragmap
58        // for row coloring.  Also restore separator_offset: compute_layout writes
59        // it back based on sub-panel width, which would clobber the value we
60        // already clamped to the panel-boundary range.
61        let saved_offset = app.separator_offset;
62        views::commit_list::render_in_area_without_fragmap_cols(app, frame, left_area);
63        app.separator_offset = saved_offset;
64
65        // Render separator between left and right
66        let sep_height = area.height.saturating_sub(1); // exclude footer row
67        let separator_spans: Vec<Line> = (0..sep_height)
68            .map(|_| {
69                Line::from(Span::styled(
70                    "│",
71                    Style::new().fg(Color::White).bg(Color::Blue),
72                ))
73            })
74            .collect();
75        let sep_area = Rect {
76            x: left_area.x + left_width - 1,
77            y: area.y,
78            width: 1,
79            height: sep_height,
80        };
81        frame.render_widget(Paragraph::new(separator_spans), sep_area);
82
83        views::commit_detail::render(git_repo, frame, app, right_area);
84
85        // Render footer at full terminal width so it isn't capped to the left panel.
86        let footer_area = Rect {
87            x: area.x,
88            y: area.y + area.height.saturating_sub(1),
89            width: area.width,
90            height: 1,
91        };
92        views::commit_list::render_footer(frame, app, footer_area);
93    } else {
94        // Screen too narrow, just show commit list
95        views::commit_list::render(app, frame);
96    }
97}