Commit Graph

876 Commits

Author SHA1 Message Date
Christian Visintin 4a9da89642 fix(build): drop vergen-git2 build dependency
vergen-git2 reads git metadata at build time, but the crates.io source
tarball ships no .git, so the published 1.1.0 fails on `cargo install`.
crates.io versions are immutable (no overwrite) and Chocolatey's
moderation queue blocks a fast re-push, so a clean 1.1.1 without vergen
is the only fix.
2026-06-08 20:53:55 +02:00
Christian Visintin 70bd7d7330 fix(transfer): enqueue full destination path instead of directory
Queued transfers stored only the destination directory as the target
path. Downstream upload logic treats the queued destination as the full
file path and passes it straight to create_file, so transfers failed
with a Failure error when the remote target resolved to a directory.

Append each entry's file name to the destination directory at enqueue
time in both enqueue_file and enqueue_all, matching the single-file
transfer path which already builds the full target path.
2026-06-08 20:17:02 +02:00
Christian Visintin b1601fb17e chore(deps): migrate keyring from 3 to 4
keyring v4 is no longer a library crate; the API moved to keyring-core
plus per-platform credential store crates. Replace the keyring dependency
with keyring-core and the native store crates, and register the default
store at runtime (lazily, once) since v4 no longer selects it at compile
time via Cargo features.
2026-06-08 20:17:02 +02:00
Christian Visintin bca261b7b2 chore(deps): bump aes, cbc, md-5, rand and vergen-git2
Migrate to the new RustCrypto cipher 0.5 traits (aes 0.9, cbc 0.2),
rand 0.10 and vergen-git2 10, whose APIs changed:

- vergen-git2: builders renamed (BuildBuilder -> Build, etc.) and the
  all_* constructors no longer return a Result
- aes/cbc: BlockDecryptMut -> BlockModeDecrypt and
  decrypt_padded_vec_mut -> decrypt_padded_vec
- rand: sample API moved
2026-06-08 20:17:02 +02:00
Christian Visintin 904befaea8 fix(copy): prevent emptying file when copy destination is empty (#421)
Install.sh / build (macos-latest) (push) Has been cancelled
Install.sh / build (ubuntu-latest) (push) Has been cancelled
CI / build-(macos-latest) (push) Has been cancelled
CI / build-(ubuntu-latest) (push) Has been cancelled
CI / build-(windows-latest) (push) Has been cancelled
codeberg-mirror / mirror (push) Has been cancelled
Deploy docs to GitHub Pages / deploy (push) Has been cancelled
Site / build-site (push) Has been cancelled
An empty copy destination resolved to the source file's own path, so
std::fs::copy truncated the original file to 0 bytes.

- localhost::copy now refuses to copy a file onto itself, returning an
  error instead of truncating it (root cause).
- action_copy treats an empty/whitespace destination as a cancel.

Closes #421
2026-06-08 17:12:52 +02:00
Christian Visintin 837592e48a feat(config): move config dir to ~/.config/termscp on macOS and %USERPROFILE%\.termscp on Windows
Resolve the config directory through a single per-platform config_dir()
function instead of relying on dirs::config_dir everywhere:

- macOS: ~/.config/termscp (was ~/Library/Application Support/termscp)
- Windows: %USERPROFILE%\.termscp (was roaming %APPDATA%\termscp)
- Linux/other: /termscp (unchanged)

Existing users are migrated automatically on first run: when the new
directory is absent and the legacy location exists, the whole config
directory is moved to the new path. The cache directory stays at the
platform-native location.

Closes #431
2026-06-08 16:39:24 +02:00
Christian Visintin f3085161e6 fix(progress): equalize dual progress bar heights
The bottom (partial) bar carried a block title (the current filename),
which forces a 1-row top inset in ratatui's `Block::inner` even though
its top border is dropped to join the seam with the full bar. That left
the partial bar with one inner row while the full bar kept two, so the
two gauges rendered at unequal heights.

- Move the filename from the partial bar's title into its gauge label.
- Skip setting an empty title so no phantom top-positioned title triggers
  the inset.
- Put the panel title on the top (full) bar for multi-file transfers.
- Bump the two-bar popup height to fit the joined panel.

Also bump Cargo.lock and adapt the embedded terminal to the new vt100
`screen_mut()` API.
2026-06-08 16:02:27 +02:00
Christian Visintin 1dafc76850 fix(progress): rework transfer progress panel (#424)
Migrate the transfer progress UI to tuirealm 4, where the stdlib
`ProgressBar` widget was dropped, by rebuilding the dual-bar panel on
top of `Gauge`.

- Restore the unified two-bar look: the full bar (top) and partial bar
  (bottom) draw joined borders so they read as a single panel; a single
  file shows one fully-bordered bar.
- Redraw on every file boundary in the send/recv queue loops so the
  full bar's (N/total) counter advances even for small files that finish
  within one in-loop redraw interval.
- Track progress with a single `TransferProgress` (exact file count from
  the pre-scan, lazy partial/full computation) and consolidate the theme
  progress-bar fields.
2026-06-08 16:02:27 +02:00
Christian Visintin 82141e7f2b chore: remove ko-fi 2026-06-08 10:16:00 +02:00
Christian Visintin bc59df494b fix: filter self-references and dot entries from remote directory listings
Some non-compliant FTP servers (e.g. LiteSpeed) include a self-reference
to the listed directory in the LIST response, causing the current folder
to appear as a duplicate entry in the explorer.

Closes #410
2026-04-19 01:54:46 +05:30
Christian Visintin 6252df2959 build: migrate to tui-realm 4.0
Upgrade tuirealm (3.x -> 4.0.0), tui-realm-stdlib (3 -> 4), tui-term
(0.2 -> 0.3). Apply all breaking changes from the 4.0 migration guide
across the termscp UI.

Key changes:

- Root-level re-exports removed; imports moved to module-qualified
  paths (`tuirealm::application`, `::component`, `::event`, `::props`,
  `::state`, `::subscription`, `::listener`, `::ratatui`). Same for
  stdlib component types (`tui_realm_stdlib::components::*`).
- `MockComponent` trait renamed to `Component`; old `Component` trait
  renamed to `AppComponent`. `#[derive(MockComponent)]` is now
  `#[derive(Component)]`. `Component::on` now takes `&Event<_>`.
- `TextSpan` replaced with `SpanStatic`/`LineStatic`/`TextStatic`
  (ratatui-based); tuple `(String, Alignment)` titles replaced with
  the new `Title` builder; `Alignment` split into
  `HorizontalAlignment`/`VerticalAlignment`; stdlib components use
  `.alignment_horizontal` instead of `.alignment`.
- `State::One`/`PropPayload::One` -> `Single`. `CmdResult::None`
  -> `NoChange`. `Props::get_or` removed; `Props::get` now returns a
  borrowed `Option<&AttrValue>` (call sites switched to
  `.and_then(AttrValue::as_*)`). `Component::query` returns
  `Option<QueryResult<'a>>`.
- `Attribute::HighlightedColor` -> `HighlightStyle` (a full `Style`).
  `.highlighted_*` helpers renamed to `.highlight_*`.
- `PollStrategy::UpTo(n)` now requires a `Duration`; tick timeout moved
  from `EventListenerCfg::poll_timeout` into `PollStrategy`.
- `TerminalBridge` removed; `Context` now holds
  `CrosstermTerminalAdapter` directly and enables raw mode + alternate
  screen explicitly. The `TerminalAdapter` trait is imported where its
  methods are used.
- `Update` trait removed; activity `update` methods are plain inherent
  functions.
- `ProgressBar` replaced by stdlib `Gauge`. Paragraph `.wrap` renamed
  to `.wrap_trim`; `.text` now takes an `Into<Text>`. Stdlib `List` row
  items are now individual lines (`Vec<Span>` per row) rather than a
  `Table` of spans; custom `FileList`/`Log` convert between the two
  models.
- Radio builders drop `.foreground(color)` so unselected items render
  with the terminal default foreground, and set
  `highlight_style(Style::default().fg(color).add_modifier(REVERSED))`
  so the selected entry is visibly highlighted only with the theme
  color.
- Custom `FileList` keeps the selected row highlighted with the full
  highlight style when focused and falls back to a foreground-only
  style when unfocused.
- Theme loading is now backwards compatible: `Theme` uses a custom
  `Deserialize` through an intermediate `ThemeFile` with optional
  fields, so missing keys, unknown values or legacy aliases
  (`transfer_progress_bar_full`/`_partial`) fall back to defaults on a
  per-field basis instead of failing the whole load.
2026-04-19 01:54:46 +05:30
Christian Visintin 6ceaf048b5 fix: render progress bar immediately after mounting
Call self.view() right after mount_progress_bar() at all 6 call sites
so the bar is visible on screen before the transfer loop begins.
2026-04-19 01:54:46 +05:30
Christian Visintin 534c16427e fix: use time-based redraw interval instead of progress-delta threshold
The old 1% progress threshold caused the UI to appear frozen on large
files (e.g. 1GB) because many read/write iterations passed between
redraws. Switching to a 100ms time-based interval ensures consistent
UI responsiveness regardless of file size.
2026-04-19 01:54:46 +05:30
Christian Visintin 9b19240925 feat: consolidate theme progress bar fields into single transfer_progress_bar 2026-04-19 01:54:46 +05:30
Christian Visintin 0ddbf3b104 feat: update transfer loop to use unified TransferProgress 2026-04-19 01:54:46 +05:30
Christian Visintin 126e58503f feat: update progress bar display for new unified data model 2026-04-19 01:54:46 +05:30
Christian Visintin 0be8b60c7d feat: simplify progress bar layout to single component 2026-04-19 01:54:46 +05:30
Christian Visintin 4ed6b118ca feat: replace dual progress bar components with single TransferProgressBar 2026-04-19 01:54:46 +05:30
Christian Visintin a48b226d9b feat: rework TransferProgress to track bytes with lazy estimation 2026-04-19 01:54:46 +05:30
Christian Visintin e11af03fdd chore: enable safe clippy pedantic lints 2026-04-19 01:54:46 +05:30
Christian Visintin f044e6ace2 docs: document ssh key storage API 2026-04-19 01:54:46 +05:30
Christian Visintin e056afbd28 test: extend system regression coverage 2026-04-19 01:54:46 +05:30
Christian Visintin 9442e3b150 fix: normalize localhost relative path checks 2026-04-19 01:54:46 +05:30
Christian Visintin 9c00b9a86c test: extend config and explorer regression coverage 2026-04-19 01:54:46 +05:30
Christian Visintin 622cfe260a test: add parser and bookmark regression coverage 2026-04-19 01:54:46 +05:30
Christian Visintin 0c3ced012e refactor: split auth view helpers by responsibility 2026-04-19 01:54:46 +05:30
Christian Visintin d60c5007f9 docs: complete remaining core module docs 2026-04-19 01:54:46 +05:30
Christian Visintin 7e10b8e68b docs: document parser and file transfer params 2026-04-19 01:54:46 +05:30
Christian Visintin 08509caf1b docs: document core host and ssh modules 2026-04-19 01:54:46 +05:30
Christian Visintin 89de2d2dfa docs: add core module and API documentation 2026-04-19 01:54:46 +05:30
Christian Visintin abc80b93ad refactor: split auth update handlers by context 2026-04-19 01:54:46 +05:30
Christian Visintin 1b79a6fc91 refactor: split auth form components by protocol 2026-04-19 01:54:46 +05:30
Christian Visintin 5a3aa64fba refactor: split parser internals into focused modules 2026-04-19 01:54:46 +05:30
Christian Visintin bc4b096077 fix: stabilize core error handling
Remove production panic and unwrap paths from core modules.

Propagate bookmark encryption failures, harden file watcher and temp mapped file handling, and clean up dead code in shared utilities.
2026-04-19 01:54:46 +05:30
Christian Visintin 0025b87b0f fix: sync browsing when entering a directory from filtered/fuzzy view
Closes #382
2026-04-19 01:54:46 +05:30
Christian Visintin bd0843d3da build: replace version-compare crate with semver
closes #399
2026-04-19 01:54:46 +05:30
Christian Visintin 97e1ca789a chore: add fmt+clippy convention to CLAUDE.md and apply nightly fmt 2026-04-19 01:54:46 +05:30
Christian Visintin 2df13fac10 fix: pass full command string to exec, not just the first word
The `Exec` arm of `Command::from_str` only captured the first
whitespace-delimited token, silently dropping all arguments.
Now passes the entire input string so e.g. `ls -la /tmp` works.
2026-04-19 01:54:46 +05:30
Christian Visintin 186313f57c fix: resolve . and .. in terminal cd and prevent panic in path elide
`absolutize` now lexically normalizes paths so `cd ..` navigates to the
parent directory instead of appending `..` literally. Also guard against
`file_name()` returning `None` in `fmt_path_elide_ex`, which caused a
panic on paths containing unresolved `..` components.

Closes #402
2026-04-19 01:54:46 +05:30
Christian Visintin c81cf39fe9 build: replaced libssh with russh for remotefs-ssh 2026-04-19 01:54:46 +05:30
Christian Visintin 9cfef867a9 fix: return after empty terminal prompt 2026-04-19 01:54:46 +05:30
Christian Visintin 18314e6a2e chore: 1.0.0 version into manifests 2026-04-19 01:54:46 +05:30
Christian Visintin 9f3df1a79a style: linter 2026-04-19 01:54:46 +05:30
Christian Visintin fe424107e9 build: removed hostname, use whoami instead
whoami provides `hostname` function, so we don't need the hostname dependency, since whoami is also being used for getting the username

closes #398
2026-04-19 01:54:46 +05:30
Christian Visintin d97535894c fix: replace recursive byte-counting with entry-based transfer progress (#395)
* fix: replace recursive byte-counting with entry-based transfer progress

Replace the expensive recursive `get_total_transfer_size` pre-calculation
with a lightweight entry-based counter (`TransferProgress`) for the
overall progress bar. This avoids deep `list_dir` traversals before
transfers begin, which could cause FTP idle-timeout disconnections on
large directory trees.

The per-file byte-level progress bar (`ProgressStates`) remains
unchanged. Bytes are still tracked via `TransferStates::add_bytes` for
notification threshold logic.

Closes #384
2026-04-19 01:54:46 +05:30
Christian Visintin 4d65e48b3c fix: replace magic-crypt with aes-gcm for bookmark encryption
magic-crypt has known vulnerabilities. Replace it with aes-gcm for new
encryption (authenticated, with random nonces) while keeping a legacy
AES-128-CBC decryption path to transparently handle existing bookmarks.
2026-04-19 01:54:46 +05:30
Christian Visintin 0d24662b3d refactor: migrate from mod.rs to named module files 2026-04-19 01:54:46 +05:30
Christian Visintin d32c588f15 refactor: replace lazy_static with std::sync::LazyLock 2026-04-19 01:54:46 +05:30
Christian Visintin 60e86aff2a perf: use sort_by_cached_key to avoid repeated lowercase allocations in file sorting 2026-04-19 01:54:46 +05:30
Christian Visintin 5f83a1468c fix: correct typos in BadSytax and theme_provider log messages 2026-04-19 01:54:46 +05:30