Skip to content

Commit 0564184

Browse files
committed
fix: improve performance and bug fix
1 parent dcaff65 commit 0564184

20 files changed

Lines changed: 1020 additions & 170 deletions

.github/workflows/release.yml

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -259,14 +259,22 @@ jobs:
259259
shell: bash
260260
run: |
261261
TARGET_REPO="${CLOUDSMITH_REPO}"
262+
TARGET_DISTRIBUTION="${CLOUDSMITH_DISTRIBUTION:-}"
263+
TARGET_RELEASE="${CLOUDSMITH_RELEASE:-}"
262264
if [[ "${CLOUDSMITH_REPO}" != */*/* ]]; then
263-
if [[ -z "${CLOUDSMITH_DISTRIBUTION}" ]]; then
264-
echo "CLOUDSMITH_REPO must be OWNER/REPO/DISTRO[/RELEASE] or set CLOUDSMITH_DISTRIBUTION."
265-
exit 1
265+
if [[ -z "${TARGET_DISTRIBUTION}" ]]; then
266+
TARGET_DISTRIBUTION="ubuntu"
267+
echo "CLOUDSMITH_DISTRIBUTION is not set, defaulting to '${TARGET_DISTRIBUTION}'."
266268
fi
267-
TARGET_REPO="${CLOUDSMITH_REPO}/${CLOUDSMITH_DISTRIBUTION}"
268-
if [[ -n "${CLOUDSMITH_RELEASE}" ]]; then
269-
TARGET_REPO="${TARGET_REPO}/${CLOUDSMITH_RELEASE}"
269+
if [[ -z "${TARGET_RELEASE}" ]]; then
270+
if command -v lsb_release >/dev/null 2>&1; then
271+
TARGET_RELEASE="$(lsb_release -cs)"
272+
else
273+
TARGET_RELEASE="stable"
274+
fi
275+
echo "CLOUDSMITH_RELEASE is not set, defaulting to '${TARGET_RELEASE}'."
270276
fi
277+
TARGET_REPO="${CLOUDSMITH_REPO}/${TARGET_DISTRIBUTION}/${TARGET_RELEASE}"
271278
fi
279+
echo "Publishing to Cloudsmith repository: ${TARGET_REPO}"
272280
cloudsmith push deb "${TARGET_REPO}" dist/debian-amd64/*.deb --republish

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## [0.1.7] - 2026-03-09
4+
5+
### Changed
6+
7+
- Improved responsiveness by moving slow Git status and image preview work off the UI render path and into background workers.
8+
- Stabilized preview interaction under high-frequency input, including wheel and key reversal behavior and bounded scroll processing at pane edges.
9+
- Hardened large file behavior with explicit limits for text/image previews, diff generation, and preview caching.
10+
311
## [0.1.6] - 2026-03-08
412

513
### Added

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "fpv"
3-
version = "0.1.6"
3+
version = "0.1.7"
44
edition = "2021"
55
description = "A minimal, keyboard-first TUI file previewer with syntax highlighting"
66
license = "MIT"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
A minimal, keyboard-first TUI file previewer for browsing directories and viewing code with syntax highlighting in the terminal.
88

9-
Current release: `v0.1.6`
9+
Current release: `v0.1.7`
1010

1111
---
1212

src/app/navigation.rs

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,37 @@
11
use crate::app::navigation_result::NavigationActionResult;
22
use crate::app::state::{NodeType, SessionState, TreeNode};
33
use crate::fs::current_dir::{
4-
is_filesystem_root, list_current_directory_with_visibility, parent_path,
4+
directory_access_error_message, is_filesystem_root, list_current_directory_with_visibility,
5+
parent_path,
56
};
67
use anyhow::Result;
78
use std::path::{Path, PathBuf};
89

910
const MAX_DIR_ENTRIES: usize = 2000;
1011

12+
fn replace_directory_entries(
13+
state: &mut SessionState,
14+
nodes: &mut Vec<TreeNode>,
15+
entries: Vec<TreeNode>,
16+
preferred: Option<&PathBuf>,
17+
) {
18+
state.clear_current_dir_error();
19+
*nodes = entries;
20+
state.restore_or_default_selection(nodes, preferred);
21+
state.update_selected_path(nodes);
22+
}
23+
24+
fn set_current_directory_error(
25+
state: &mut SessionState,
26+
nodes: &mut Vec<TreeNode>,
27+
message: String,
28+
) {
29+
state.set_current_dir_error(message);
30+
nodes.clear();
31+
state.selected_index = 0;
32+
state.set_selected_path(state.current_path.clone());
33+
}
34+
1135
fn absolute_current_path(path: &Path) -> PathBuf {
1236
if path.is_absolute() {
1337
return path.to_path_buf();
@@ -75,13 +99,19 @@ pub fn enter_selected_directory(
7599

76100
let target = node.path.clone();
77101
let entries =
78-
list_current_directory_with_visibility(&target, MAX_DIR_ENTRIES, state.show_hidden)?;
102+
match list_current_directory_with_visibility(&target, MAX_DIR_ENTRIES, state.show_hidden) {
103+
Ok(entries) => entries,
104+
Err(error) => {
105+
return Ok(NavigationActionResult::blocked(
106+
"enter_directory",
107+
state.current_path.clone(),
108+
directory_access_error_message(&error),
109+
));
110+
}
111+
};
79112
state.last_child_path = Some(target.clone());
80113
state.current_path = target.clone();
81-
*nodes = entries;
82-
state.selected_index = 0;
83-
state.revalidate_selection(nodes);
84-
state.update_selected_path(nodes);
114+
replace_directory_entries(state, nodes, entries, None);
85115

86116
Ok(NavigationActionResult::changed(
87117
"enter_directory",
@@ -114,11 +144,18 @@ pub fn go_to_parent_directory(
114144

115145
let previous_child = current_path;
116146
let entries =
117-
list_current_directory_with_visibility(&parent, MAX_DIR_ENTRIES, state.show_hidden)?;
147+
match list_current_directory_with_visibility(&parent, MAX_DIR_ENTRIES, state.show_hidden) {
148+
Ok(entries) => entries,
149+
Err(error) => {
150+
return Ok(NavigationActionResult::blocked(
151+
"go_parent",
152+
state.current_path.clone(),
153+
directory_access_error_message(&error),
154+
));
155+
}
156+
};
118157
state.current_path = parent.clone();
119-
*nodes = entries;
120-
state.restore_or_default_selection(nodes, Some(&previous_child));
121-
state.update_selected_path(nodes);
158+
replace_directory_entries(state, nodes, entries, Some(&previous_child));
122159

123160
Ok(NavigationActionResult::changed(
124161
"go_parent",
@@ -132,14 +169,23 @@ pub fn refresh_current_directory(
132169
nodes: &mut Vec<TreeNode>,
133170
) -> Result<NavigationActionResult> {
134171
let previous_selected_path = nodes.get(state.selected_index).map(|n| n.path.clone());
135-
let entries = list_current_directory_with_visibility(
172+
let entries = match list_current_directory_with_visibility(
136173
&state.current_path,
137174
MAX_DIR_ENTRIES,
138175
state.show_hidden,
139-
)?;
140-
*nodes = entries;
141-
state.restore_or_default_selection(nodes, previous_selected_path.as_ref());
142-
state.update_selected_path(nodes);
176+
) {
177+
Ok(entries) => entries,
178+
Err(error) => {
179+
let message = directory_access_error_message(&error);
180+
set_current_directory_error(state, nodes, message.clone());
181+
return Ok(NavigationActionResult::blocked(
182+
"refresh_current_dir",
183+
state.current_path.clone(),
184+
message,
185+
));
186+
}
187+
};
188+
replace_directory_entries(state, nodes, entries, previous_selected_path.as_ref());
143189

144190
Ok(NavigationActionResult::changed(
145191
"refresh_current_dir",

0 commit comments

Comments
 (0)