diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-09 23:16:24 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-09 23:16:24 +0300 |
| commit | 9f210e973834700d14c6c0283ed750ed5b038e8b (patch) | |
| tree | cd8c75755c59fdc47bf71ca6dc34e49ab0258ae6 /src | |
| parent | 3a9888cd564dc45d23a7bdd0dba29a6ff1ef48a1 (diff) | |
chore: enable clippy linting
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/mod.rs | 14 | ||||
| -rw-r--r-- | src/app/input/mod.rs | 21 | ||||
| -rw-r--r-- | src/app/input/modal.rs | 12 | ||||
| -rw-r--r-- | src/app/input/settings.rs | 24 | ||||
| -rw-r--r-- | src/app/mod.rs | 2 | ||||
| -rw-r--r-- | src/app/runtime.rs | 9 | ||||
| -rw-r--r-- | src/app/state.rs | 9 | ||||
| -rw-r--r-- | src/cli.rs | 7 | ||||
| -rw-r--r-- | src/client/mod.rs | 10 | ||||
| -rw-r--r-- | src/config/model.rs | 8 | ||||
| -rw-r--r-- | src/ghostty/mod.rs | 8 | ||||
| -rw-r--r-- | src/main.rs | 97 | ||||
| -rw-r--r-- | src/pane.rs | 2 | ||||
| -rw-r--r-- | src/pane/state.rs | 4 | ||||
| -rw-r--r-- | src/pane/terminal.rs | 4 | ||||
| -rw-r--r-- | src/raw_input.rs | 17 | ||||
| -rw-r--r-- | src/server/client_transport.rs | 3 | ||||
| -rw-r--r-- | src/server/headless.rs | 4 | ||||
| -rw-r--r-- | src/ui/mobile.rs | 6 | ||||
| -rw-r--r-- | src/ui/panes.rs | 76 | ||||
| -rw-r--r-- | src/ui/sidebar.rs | 4 | ||||
| -rw-r--r-- | src/ui/tabs.rs | 8 |
22 files changed, 167 insertions, 182 deletions
diff --git a/src/api/mod.rs b/src/api/mod.rs index f256e4a8..318a0ee7 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -368,7 +368,7 @@ fn output_match_read_source( ) -> crate::api::schema::ReadSource { match source { crate::api::schema::ReadSource::Recent => crate::api::schema::ReadSource::RecentUnwrapped, - other => other.clone(), + other => *other, } } @@ -741,14 +741,12 @@ impl ActiveSubscription { let probe = pane_read( format!("{request_id}:sub:{index}:probe"), &pane_id, - source.clone(), + source, lines, strip_ansi, api_tx, ); - if let Err(error) = probe { - return Err(error); - } + probe?; Ok(Self::OutputMatched(ActiveOutputMatchedSubscription { pane_id, @@ -765,11 +763,7 @@ impl ActiveSubscription { pane_id, agent_status, } => { - let probe = - match pane_get(format!("{request_id}:sub:{index}:probe"), &pane_id, api_tx) { - Ok(probe) => probe, - Err(error) => return Err(error), - }; + let probe = pane_get(format!("{request_id}:sub:{index}:probe"), &pane_id, api_tx)?; Ok(Self::AgentStatusChanged( ActiveAgentStatusChangedSubscription { diff --git a/src/app/input/mod.rs b/src/app/input/mod.rs index 56ad09a9..aa607c78 100644 --- a/src/app/input/mod.rs +++ b/src/app/input/mod.rs @@ -92,10 +92,13 @@ impl App { pub(crate) fn handle_onboarding_key(&mut self, key: KeyEvent) { match key.code { KeyCode::Right | KeyCode::Char('l') => self.open_settings_from_onboarding(), - _ => match modal_action_from_key(&key, ONBOARDING_WELCOME_ACTIONS) { - Some(ModalAction::Continue) => self.open_settings_from_onboarding(), - _ => {} - }, + _ => { + if let Some(ModalAction::Continue) = + modal_action_from_key(&key, ONBOARDING_WELCOME_ACTIONS) + { + self.open_settings_from_onboarding(); + } + } } } @@ -116,10 +119,12 @@ impl App { notes.scroll = max_scroll; } } - _ => match modal_action_from_key(&key, RELEASE_NOTES_ACTIONS) { - Some(ModalAction::Close) => self.dismiss_release_notes(), - _ => {} - }, + _ => { + if let Some(ModalAction::Close) = modal_action_from_key(&key, RELEASE_NOTES_ACTIONS) + { + self.dismiss_release_notes(); + } + } } } diff --git a/src/app/input/modal.rs b/src/app/input/modal.rs index 998bb69b..a76576bf 100644 --- a/src/app/input/modal.rs +++ b/src/app/input/modal.rs @@ -261,13 +261,11 @@ pub(super) fn apply_rename_action(state: &mut AppState, action: ModalAction) { state.name_input.trim().to_string() }; match state.mode { - Mode::RenameWorkspace if !state.workspaces.is_empty() => { - if !new_name.is_empty() { - let workspace_id = state.workspaces[state.selected].id.clone(); - state.workspaces[state.selected].set_custom_name(new_name); - crate::logging::workspace_renamed(&workspace_id); - state.mark_session_dirty(); - } + Mode::RenameWorkspace if !state.workspaces.is_empty() && !new_name.is_empty() => { + let workspace_id = state.workspaces[state.selected].id.clone(); + state.workspaces[state.selected].set_custom_name(new_name); + crate::logging::workspace_renamed(&workspace_id); + state.mark_session_dirty(); } Mode::RenameTab if state.creating_new_tab => { state.request_new_tab = true; diff --git a/src/app/input/settings.rs b/src/app/input/settings.rs index 2c92bc63..67144a28 100644 --- a/src/app/input/settings.rs +++ b/src/app/input/settings.rs @@ -10,6 +10,8 @@ use crate::{ }; #[derive(Debug, Clone, PartialEq, Eq)] +// The shared `Save` verb is semantic: these actions persist settings. +#[allow(clippy::enum_variant_names)] pub(super) enum SettingsAction { SaveTheme(String), SaveSound(bool), @@ -135,10 +137,13 @@ pub(super) fn update_settings_state(state: &mut AppState, key: KeyEvent) -> Opti state.settings.section = SettingsSection::Theme; state.settings.list.selected = current_theme_index(&state.theme_name); } - _ => match super::modal::modal_action_from_key(&key, super::modal::SETTINGS_ACTIONS) { - Some(super::modal::ModalAction::Close) => cancel_settings(state), - _ => {} - }, + _ => { + if let Some(super::modal::ModalAction::Close) = + super::modal::modal_action_from_key(&key, super::modal::SETTINGS_ACTIONS) + { + cancel_settings(state); + } + } }, SettingsSection::Toast => match key.code { KeyCode::Up | KeyCode::Char('k') => state.settings.list.move_prev(), @@ -155,10 +160,13 @@ pub(super) fn update_settings_state(state: &mut AppState, key: KeyEvent) -> Opti state.settings.section = SettingsSection::Theme; state.settings.list.selected = current_theme_index(&state.theme_name); } - _ => match super::modal::modal_action_from_key(&key, super::modal::SETTINGS_ACTIONS) { - Some(super::modal::ModalAction::Close) => cancel_settings(state), - _ => {} - }, + _ => { + if let Some(super::modal::ModalAction::Close) = + super::modal::modal_action_from_key(&key, super::modal::SETTINGS_ACTIONS) + { + cancel_settings(state); + } + } }, } diff --git a/src/app/mod.rs b/src/app/mod.rs index 1ea315cf..60e38f5b 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -351,7 +351,7 @@ impl App { toast_config: config.ui.toast.clone(), keybinds: config.keybinds(), spinner_tick: 0, - palette: resolve_palette(&config), + palette: resolve_palette(config), theme_name: config .theme .name diff --git a/src/app/runtime.rs b/src/app/runtime.rs index a4e93d3b..3c67c306 100644 --- a/src/app/runtime.rs +++ b/src/app/runtime.rs @@ -229,10 +229,11 @@ impl App { } pub(crate) fn start_git_status_refresh_if_due(&mut self, now: Instant) { - if !self - .git_refresh_deadline() - .is_some_and(|deadline| now >= deadline) - { + let Some(deadline) = self.git_refresh_deadline() else { + return; + }; + + if now < deadline { return; } diff --git a/src/app/state.rs b/src/app/state.rs index f7c4daa1..134d86bd 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -391,18 +391,13 @@ pub enum Mode { KeybindHelp, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum AgentPanelScope { CurrentWorkspace, + #[default] AllWorkspaces, } -impl Default for AgentPanelScope { - fn default() -> Self { - Self::AllWorkspaces - } -} - // --------------------------------------------------------------------------- // Settings UI state // --------------------------------------------------------------------------- @@ -202,7 +202,7 @@ fn compatibility_label(protocol: Option<u32>) -> &'static str { fn restart_needed_label(server: &ServerRuntimeStatus) -> &'static str { match server { ServerRuntimeStatus::Running { version, .. } => match version.as_deref() { - Some(version) if version == env!("CARGO_PKG_VERSION") => "no", + Some(env!("CARGO_PKG_VERSION")) => "no", Some(_) => "yes", None => "unknown", }, @@ -1391,10 +1391,7 @@ fn parse_session_name_and_json(args: &[String], usage: &str) -> Result<(String, } fn print_session_table(sessions: &[crate::session::SessionInfo]) { - println!( - "{:<20} {:<8} {:<48} {}", - "name", "status", "directory", "socket" - ); + println!("{:<20} {:<8} {:<48} socket", "name", "status", "directory"); for session in sessions { println!( "{:<20} {:<8} {:<48} {}", diff --git a/src/client/mod.rs b/src/client/mod.rs index 1e0beded..475a079f 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -231,9 +231,8 @@ fn do_handshake( rows, requested_encoding, }; - protocol::write_message(stream, &hello).map_err(|e| { - ClientError::ConnectionFailed(io::Error::new(io::ErrorKind::Other, e.to_string())) - })?; + protocol::write_message(stream, &hello) + .map_err(|e| ClientError::ConnectionFailed(io::Error::other(e.to_string())))?; // Read Welcome. stream @@ -339,7 +338,7 @@ pub fn run_client() -> io::Result<()> { let rt = tokio::runtime::Builder::new_current_thread() .enable_all() .build() - .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; + .map_err(io::Error::other)?; let should_quit = Arc::new(AtomicBool::new(false)); @@ -577,8 +576,7 @@ fn server_reader_thread( /// Writes a message to the server stream (blocking). fn write_to_server(stream: &mut UnixStream, msg: &ClientMessage) -> io::Result<()> { - protocol::write_message(stream, msg) - .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string())) + protocol::write_message(stream, msg).map_err(|e| io::Error::other(e.to_string())) } // --------------------------------------------------------------------------- diff --git a/src/config/model.rs b/src/config/model.rs index 7e6c7382..a11192fb 100644 --- a/src/config/model.rs +++ b/src/config/model.rs @@ -209,11 +209,11 @@ impl<'de> Deserialize<'de> for ToastConfig { } let raw = RawToastConfig::deserialize(deserializer)?; - let delivery = raw.delivery.unwrap_or_else(|| match raw.enabled { + let legacy_delivery = match raw.enabled { Some(true) => ToastDelivery::Herdr, - Some(false) => ToastDelivery::Off, - None => ToastDelivery::Off, - }); + Some(false) | None => ToastDelivery::Off, + }; + let delivery = raw.delivery.unwrap_or(legacy_delivery); Ok(Self { delivery }) } } diff --git a/src/ghostty/mod.rs b/src/ghostty/mod.rs index 27fcb6f9..02bae73f 100644 --- a/src/ghostty/mod.rs +++ b/src/ghostty/mod.rs @@ -234,8 +234,10 @@ impl CellWide { } } +type WritePtyCallback = dyn FnMut(&[u8]) + Send; + struct WritePtyCallbackState { - callback: Box<dyn FnMut(&[u8]) + Send>, + callback: Box<WritePtyCallback>, } unsafe extern "C" fn write_pty_trampoline( @@ -1469,10 +1471,10 @@ mod tests { ); render_state.update(&terminal).unwrap(); - assert_eq!(render_state.cursor_visible().unwrap(), true); + assert!(render_state.cursor_visible().unwrap()); terminal.write(b"\x1b[?25l"); render_state.update(&terminal).unwrap(); - assert_eq!(render_state.cursor_visible().unwrap(), false); + assert!(!render_state.cursor_visible().unwrap()); terminal.write(b"\x1b[?1049h\x1b[HALT"); assert_eq!(terminal.active_screen().unwrap(), ActiveScreen::Alternate); diff --git a/src/main.rs b/src/main.rs index ee2c30e4..c35a4084 100644 --- a/src/main.rs +++ b/src/main.rs @@ -243,57 +243,56 @@ fn main() -> io::Result<()> { println!(" herdr integration <subcommand> ..."); println!(); println!("Common commands:"); - println!( - " {:<32} {}", - "herdr", "Launch or attach to the persistent session" - ); - println!( - " {:<32} {}", - "herdr status [server|client]", "Show local client and running server status" - ); - println!( - " {:<32} {}", - "herdr update", "Download and install the latest version" - ); - println!( - " {:<32} {}", - "herdr server stop", "Stop the running server via the API socket" - ); - println!( - " {:<32} {}", - "herdr server reload-config", "Reload config.toml in the running server" - ); - println!( - " {:<32} {}", - "herdr workspace <subcommand>", "Workspace helpers over the socket API" - ); - println!( - " {:<32} {}", - "herdr tab <subcommand>", "Tab helpers over the socket API" - ); - println!( - " {:<32} {}", - "herdr pane <subcommand>", "Pane control helpers over the socket API" - ); - println!( - " {:<32} {}", - "herdr wait <subcommand>", "Blocking wait helpers over the socket API" - ); - println!( - " {:<32} {}", - "herdr session <subcommand>", "Manage named persistent sessions" - ); - println!( - " {:<32} {}", - "herdr integration <subcommand>", "Manage built-in agent integrations" - ); + for (command, description) in [ + ("herdr", "Launch or attach to the persistent session"), + ( + "herdr status [server|client]", + "Show local client and running server status", + ), + ("herdr update", "Download and install the latest version"), + ( + "herdr server stop", + "Stop the running server via the API socket", + ), + ( + "herdr server reload-config", + "Reload config.toml in the running server", + ), + ( + "herdr workspace <subcommand>", + "Workspace helpers over the socket API", + ), + ("herdr tab <subcommand>", "Tab helpers over the socket API"), + ( + "herdr pane <subcommand>", + "Pane control helpers over the socket API", + ), + ( + "herdr wait <subcommand>", + "Blocking wait helpers over the socket API", + ), + ( + "herdr session <subcommand>", + "Manage named persistent sessions", + ), + ( + "herdr integration <subcommand>", + "Manage built-in agent integrations", + ), + ] { + println!(" {command:<32} {description}"); + } println!(); println!("Advanced commands:"); - println!(" {:<32} {}", "herdr server", "Run as headless server"); - println!( - " {:<32} {}", - "herdr client", "Connect to a running server as a thin client" - ); + for (command, description) in [ + ("herdr server", "Run as headless server"), + ( + "herdr client", + "Connect to a running server as a thin client", + ), + ] { + println!(" {command:<32} {description}"); + } println!(); println!("Options:"); println!(" --no-session Run monolithically (no server/client, escape hatch)"); diff --git a/src/pane.rs b/src/pane.rs index c741c04d..7d4ec729 100644 --- a/src/pane.rs +++ b/src/pane.rs @@ -602,6 +602,8 @@ impl PaneRuntime { } let pid = child_pid.load(Ordering::Acquire); + // Keep the terminal restore side effect separate from render notification state. + #[allow(clippy::collapsible_if)] if pid > 0 && terminal.maybe_restore_host_terminal_theme(pane_id, pid) { if !render_dirty.swap(true, Ordering::AcqRel) { render_notify.notify_one(); diff --git a/src/pane/state.rs b/src/pane/state.rs index aac80920..590f2025 100644 --- a/src/pane/state.rs +++ b/src/pane/state.rs @@ -104,9 +104,7 @@ impl PaneState { source: &str, agent_label: &str, ) -> Option<EffectiveStateChange> { - let Some(current_agent_label) = self.effective_agent_label() else { - return None; - }; + let current_agent_label = self.effective_agent_label()?; if current_agent_label != agent_label { return None; } diff --git a/src/pane/terminal.rs b/src/pane/terminal.rs index 80f83915..ad040ba2 100644 --- a/src/pane/terminal.rs +++ b/src/pane/terminal.rs @@ -712,10 +712,12 @@ impl GhosttyPaneTerminal { } } +type VisibleHyperlinks = Vec<((u16, u16), String, String)>; + fn ghostty_visible_hyperlinks( core: &mut GhosttyPaneCore, area: Rect, -) -> Result<Vec<((u16, u16), String, String)>, crate::ghostty::Error> { +) -> Result<VisibleHyperlinks, crate::ghostty::Error> { let GhosttyPaneCore { terminal, render_state, diff --git a/src/raw_input.rs b/src/raw_input.rs index 6640ec29..0cf9d84b 100644 --- a/src/raw_input.rs +++ b/src/raw_input.rs @@ -39,10 +39,7 @@ pub fn parse_raw_input_bytes_with_ranges(data: &[u8]) -> Vec<RawInputEventWithRa let mut events = Vec::new(); let mut offset = 0usize; - loop { - let Some((event, consumed)) = extract_one_event(&buffer) else { - break; - }; + while let Some((event, consumed)) = extract_one_event(&buffer) { buffer.drain(..consumed); events.push(RawInputEventWithRange { event, @@ -85,10 +82,7 @@ pub fn parse_raw_input_bytes_sync(data: &[u8]) -> Vec<RawInputEvent> { let mut buffer = data.to_vec(); let mut events = Vec::new(); - loop { - let Some((event, consumed)) = extract_one_event(&buffer) else { - break; - }; + while let Some((event, consumed)) = extract_one_event(&buffer) { buffer.drain(..consumed); events.push(event); } @@ -175,10 +169,7 @@ fn drain_buffer(buffer: &mut Vec<u8>, tx: &mpsc::Sender<RawInputEvent>) { pub(crate) fn drain_complete_input_bytes(buffer: &mut Vec<u8>) -> Vec<Vec<u8>> { let mut chunks = Vec::new(); - loop { - let Some((_event, consumed)) = extract_one_event(buffer) else { - break; - }; + while let Some((_event, consumed)) = extract_one_event(buffer) { chunks.push(buffer[..consumed].to_vec()); buffer.drain(..consumed); } @@ -244,7 +235,7 @@ fn stdin_read_ready<R: AsRawFd>(_reader: &R, _timeout_ms: i32) -> Option<bool> { #[cfg(unix)] { let fd = _reader.as_raw_fd(); - return poll_read_ready(fd, _timeout_ms); + poll_read_ready(fd, _timeout_ms) } } diff --git a/src/server/client_transport.rs b/src/server/client_transport.rs index 9f5183d9..ec1adf0b 100644 --- a/src/server/client_transport.rs +++ b/src/server/client_transport.rs @@ -158,8 +158,7 @@ pub(crate) fn handle_client_handshake( encoding: render_encoding, error: None, }; - protocol::write_message(&mut stream, &welcome) - .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?; + protocol::write_message(&mut stream, &welcome).map_err(|e| io::Error::other(e.to_string()))?; // Clear read timeout for normal operation. stream.set_read_timeout(None)?; diff --git a/src/server/headless.rs b/src/server/headless.rs index ffcb6bbb..7bd8638a 100644 --- a/src/server/headless.rs +++ b/src/server/headless.rs @@ -612,7 +612,7 @@ impl HeadlessServer { crate::raw_input::RawInputEvent::OuterFocusLost => Some(false), _ => None, }) - .last(); + .next_back(); let Some(next_focus) = next_focus else { return; @@ -1708,7 +1708,7 @@ pub fn run_server() -> io::Result<()> { let rt = tokio::runtime::Builder::new_multi_thread() .enable_all() .build() - .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; + .map_err(io::Error::other)?; let result = rt.block_on(async { // Create the App (with AppState, event channels, etc.). diff --git a/src/ui/mobile.rs b/src/ui/mobile.rs index 50cbed0c..41f29f89 100644 --- a/src/ui/mobile.rs +++ b/src/ui/mobile.rs @@ -745,11 +745,7 @@ fn render_left_scrollbar( .max(1) .min(track.height as usize) as u16; let travel = track.height.saturating_sub(thumb_len); - let thumb_top = if max_scroll == 0 { - track.y - } else { - track.y + ((travel as usize * scroll.min(max_scroll)) / max_scroll) as u16 - }; + let thumb_top = track.y + ((travel as usize * scroll.min(max_scroll)) / max_scroll) as u16; for y in track.y..track.y + track.height { let is_thumb = y >= thumb_top && y < thumb_top + thumb_len; diff --git a/src/ui/panes.rs b/src/ui/panes.rs index 82be8bf1..c4ba0c54 100644 --- a/src/ui/panes.rs +++ b/src/ui/panes.rs @@ -219,6 +219,44 @@ fn render_selection_highlight( } } +fn render_empty(app: &AppState, frame: &mut Frame, area: Rect) { + let p = &app.palette; + let lines = vec![ + Line::from(""), + Line::from(""), + Line::from(Span::styled( + " No workspaces yet", + Style::default().fg(p.overlay0), + )), + Line::from(""), + Line::from(Span::styled( + " A workspace is one project context.", + Style::default().fg(p.overlay1), + )), + Line::from(Span::styled( + " Its root pane (top-left) sets the default repo or folder name.", + Style::default().fg(p.overlay1), + )), + Line::from(""), + Line::from(vec![ + Span::styled(" Press ", Style::default().fg(p.overlay0)), + Span::styled( + app.keybinds.new_workspace_label.to_string(), + Style::default().fg(p.accent).add_modifier(Modifier::BOLD), + ), + Span::styled(" to create one", Style::default().fg(p.overlay0)), + ]), + ]; + frame.render_widget( + Paragraph::new(lines).block( + Block::default() + .borders(Borders::ALL) + .border_style(Style::default().fg(p.surface_dim)), + ), + area, + ); +} + #[cfg(test)] mod tests { use super::*; @@ -315,41 +353,3 @@ mod tests { assert_eq!(info.inner_rect, Rect::new(10, 3, 39, 8)); } } - -fn render_empty(app: &AppState, frame: &mut Frame, area: Rect) { - let p = &app.palette; - let lines = vec![ - Line::from(""), - Line::from(""), - Line::from(Span::styled( - " No workspaces yet", - Style::default().fg(p.overlay0), - )), - Line::from(""), - Line::from(Span::styled( - " A workspace is one project context.", - Style::default().fg(p.overlay1), - )), - Line::from(Span::styled( - " Its root pane (top-left) sets the default repo or folder name.", - Style::default().fg(p.overlay1), - )), - Line::from(""), - Line::from(vec![ - Span::styled(" Press ", Style::default().fg(p.overlay0)), - Span::styled( - format!("{}", app.keybinds.new_workspace_label), - Style::default().fg(p.accent).add_modifier(Modifier::BOLD), - ), - Span::styled(" to create one", Style::default().fg(p.overlay0)), - ]), - ]; - frame.render_widget( - Paragraph::new(lines).block( - Block::default() - .borders(Borders::ALL) - .border_style(Style::default().fg(p.surface_dim)), - ), - area, - ); -} diff --git a/src/ui/sidebar.rs b/src/ui/sidebar.rs index 04a3acd9..83ceebe0 100644 --- a/src/ui/sidebar.rs +++ b/src/ui/sidebar.rs @@ -32,7 +32,7 @@ fn sidebar_section_heights(total_h: u16, split_ratio: f32) -> (u16, u16) { } if total_h < 6 { - let ws_h = (total_h + 1) / 2; + let ws_h = total_h.div_ceil(2); return (ws_h, total_h.saturating_sub(ws_h)); } @@ -385,7 +385,7 @@ pub(crate) fn collapsed_sidebar_sections(area: Rect) -> (Rect, Option<u16>, Rect } let total_h = content.height as usize; - let ws_h = (total_h + 1) / 2; + let ws_h = total_h.div_ceil(2); let detail_h = total_h.saturating_sub(ws_h + 1); if ws_h == 0 || detail_h == 0 { return (content, None, Rect::default()); diff --git a/src/ui/tabs.rs b/src/ui/tabs.rs index 400ee65f..a6ce0e68 100644 --- a/src/ui/tabs.rs +++ b/src/ui/tabs.rs @@ -33,14 +33,14 @@ fn layout_tab_hit_areas(ws: &crate::workspace::Workspace, area: Rect, scroll: us let mut x = area.x; let right = area.x + area.width; - for idx in scroll..ws.tabs.len() { + for (idx, rect) in rects.iter_mut().enumerate().skip(scroll) { if x >= right { break; } let desired = tab_width(&ws.tabs[idx]); let remaining = right.saturating_sub(x); let width = desired.min(remaining).max(1); - rects[idx] = Rect::new(x, area.y, width, 1); + *rect = Rect::new(x, area.y, width, 1); x = x.saturating_add(width + 1); } rects @@ -178,14 +178,14 @@ fn tab_drop_indicator_x( ws: &crate::workspace::Workspace, insert_idx: usize, ) -> Option<u16> { - let visible_tabs = app + let mut visible_tabs = app .view .tab_hit_areas .iter() .enumerate() .filter(|(_, rect)| rect.width > 0); let first_visible = visible_tabs.clone().next()?; - let last_visible = visible_tabs.last().unwrap_or(first_visible); + let last_visible = visible_tabs.next_back().unwrap_or(first_visible); if insert_idx == 0 { return Some(if first_visible.0 == 0 { |
