Build Linux release artifacts as statically linked musl binaries for x86_64 and aarch64, update packaging and updater handling, and document the reduced runtime requirements.
Keep release version preparation locked without refreshing dependencies or committing Cargo.lock.
Closes#440
Support Auto, SMB1, SMB2, and SMB3 selection on Unix, bound negotiation to the selected dialect family, preserve legacy bookmarks as Auto, and document the new option. Windows keeps operating-system-managed negotiation.
Closes#439
Resolve SSH host parameters in auth forms and CLI connections while preserving explicit user, bookmark, and parsed alias values. Continue forwarding SSH config files for HostName and other SSH options, and document the precedence in English and Chinese.
Closes#441
* ci: migrate project automation to Just
Centralize build, test, release, dependency, hook, and website commands in Just recipes. Pin workflow tooling, use the repository toolchain, and run the complete validation set in CI.
* ci: codex being codex
* docs: update CLAUDE.md for just task runner migration
Reflect the switch to just recipes for build/test/clippy/fmt, note
dprint replacing raw rustfmt, and add a cross-platform code requirement.
* fix: resolve clippy warnings breaking CI on ubuntu and windows
Use clone() instead of implicit to_string() on already-owned String
values, gate the windows-only unused make_file_at import behind
cfg(posix), and fix unused mut / manual assign-op in the windows-only
localhost test.
* fix: fmt
Unanchored include patterns (LICENSE, README.md) matched at any depth
via gitignore-glob semantics, pulling 437 site/node_modules files into
the package and breaking cargo publish's dirty check.
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.
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.
build.rs uses vergen-git2 (Git2::all_git), which runs `git describe` and
reads commit metadata. The build and publish-crate jobs checked out a
shallow clone without tags, so vergen could not resolve the describe
string and libgit2 may fail on shallow repos. Add fetch-depth: 0 and
fetch-tags: true to both jobs that compile the crate.
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.
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
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
Reflect the new config directory locations (~/.config/termscp on macOS,
%USERPROFILE%\.termscp on Windows) across the English and Chinese docs,
and add a CLAUDE.md note to keep both translations in sync.
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
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.
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.
- silence SC3043 by declaring dash dialect (local is supported)
- quote unquoted vars (SC2086/SC1090)
- fix set -e aborting arch install before cargo check
- fix install_cargo removing unset $archive instead of $rustup
- make brew upgrade fallback a real if-then-else (SC2015)
- drop leftover starship BASE_URL and debug echo $1
Add Site GitHub Actions workflow running prettier format check, astro
check, tests, and build on changes under site/. Wire prettier into the
site package with config, ignore, and scripts, and format existing
sources.
Add install.ps1 mirroring install.sh for Windows: arch detection,
release zip download, binary extraction, user PATH update.
- copy install.ps1 to site public/ at build time (copy-install.mjs)
- serve /install.ps1 with text/plain Content-Type (vercel.json)
- add PowerShell one-liner to install page and README
- bump install.ps1 default version in bump_version.sh
- add CopyButton component next to every install command line
prepare job failed: git-cliff --latest crashed with 'trim_start_matches on
null' because the checkout was shallow (no tags/history) so no release existed.
- checkout prepare with fetch-depth: 0 + fetch-tags so git-cliff sees full
history and tags (also fixes an otherwise-truncated CHANGELOG)
- generate release notes with --unreleased --tag v$VERSION instead of --latest:
--latest selected the previous real tag (stale notes); --unreleased --tag
renders the version being released
The old manual dist/build/* scripts and dist/{deb,rpm}.sh are superseded by the
automated release workflow. Add the chocolatey package consumed by release.yml.
Pin every action to a commit SHA whose tag comment matches (verified via gh api),
add least-privilege permissions, set persist-credentials: false, and replace the
archived actions-rs/cargo with a plain cargo test. zizmor clean at default persona.
Single workflow_dispatch (version, dry_run) that bumps versions, regenerates
CHANGELOG via git-cliff, rebuilds site CSS, builds all targets, creates the
GitHub release, updates the Homebrew tap and publishes Chocolatey.
- dist/release/bump_version.sh: version replacer across all tracked locations (+tests)
- .github/workflows/release.yml: prepare -> build matrix -> homebrew/release -> choco
- retire build-artifacts.yml (merged into release.yml)
- Linux builds via cargo-zigbuild (old glibc) for broad compatibility
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
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.
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.
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.
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.
`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
* 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
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.
Comprehensive design for incremental refactoring of the 13k-line
FileTransferActivity god-struct using a unified Pane abstraction.
Detailed step-by-step plan covering 6 phases: split monoliths,
error handling, Pane struct, action dedup, session split, view reorg.
Extract 26 popup components from the monolithic 1,868-line popups.rs
into 20 individual files under popups/. Each file contains one or two
related components with their own imports. The popups.rs module file
now contains only module declarations and re-exports.
Replace 8 panic!() calls with error!() logging and early returns/fallthrough.
These panics documented invariants (e.g. "this tab can't do X") but would crash
the app if somehow triggered. Error logging is safer and more resilient.
Replace raw FileExplorer fields in Browser with Pane structs that bundle
the explorer and connected state. Move host_bridge_connected and
remote_connected from FileTransferActivity into the panes. Add navigation
API (fs_pane, opposite_pane, is_find_tab) for future unification tasks.
Rename private get_selected_file to get_selected_file_by_id and add three
new unified methods (get_selected_entries, get_selected_file, is_selected_one)
that dispatch based on self.browser.tab(). Old per-tab methods are kept for
now until their callers are migrated in subsequent tasks.
Collapse _local_/_remote_ action method pairs (mkdir, delete, symlink,
chmod, rename, copy) into unified methods that branch internally on
is_local_tab(). This halves the number of action methods and simplifies
the update.rs dispatch logic. Also unifies ShowFileInfoPopup and
ShowChmodPopup dispatching to use get_selected_entries().
Move `host_bridge` and `client` filesystem fields from FileTransferActivity
into the Pane struct, enabling tab-agnostic dispatch via `fs_pane()`/
`fs_pane_mut()`. This eliminates most `is_local_tab()` branching across
15+ action files.
Key changes:
- Add `fs: Box<dyn HostBridge>` to Pane, remove from FileTransferActivity
- Replace per-side method pairs with unified pane-dispatched methods
- Unify navigation (changedir, reload, scan, file_exists, has_file_changed)
- Replace 147-line popup if/else chain with data-driven priority table
- Replace assert!/panic!/unreachable! with proper error handling
- Fix typo "filetransfer_activiy" across ~29 files
- Add unit tests for Pane
Net result: -473 lines, single code path for most file operations.
* feat: Import bookmarks from ssh config with a CLI command
Use import-ssh-hosts to import all the possible hosts by the configured ssh config or the default one on your machine
closes#331
Removed error popup message if failed to check for updates.
Prevent long timeouts when checking for updates if the network is down or the DNS is not working.
closes#354
* fix: Report a message while calculating total size of files to transfer.
Currently, in case of huge transfers the app may look frozen while calculating the transfer size. We should at least report to the user we are actually doing something.
closes#361
* ci: windows runner
* feat: Replaced the `Exec` popup with a fully functional terminal emulator
closes#340
* fix: colors and fmt for terminal
* feat: Handle exit and cd on terminal
* fix: Fmt pah
I fixed the id_rsa/id_ed25519 SSH auth issue on Mac and now termscp should respect the key-based authentication, just like the regular ssh user@hostname, without the need for any ssh agents.
---
Co-authored-by: Lucas Czekaj <lukasz@czekaj.us>
the logic of selecting files has been extended!
From now on selecting file will put the files into a transfer queue, which is shown on the bottom panel.
When a file is selected the file is added to the queue with a destination path, which is the **current other explorer path at the moment of selection.
It is possible to navigate to the transfer queue by using `P` and pressing `ENTER` on a file will remove it from the transfer queue.Other commands will work as well on the transfer queue, like `COPY`, `MOVE`, `DELETE`, `RENAME`.
closes#132
* When the file is exchanged, all times attributes are set (if supported by the protocol)
* If local/remote file have the same last modification time (`mtime`), the file is not transferred
Use containers to test file transfers
Container setup
Container setup
tests with docker-compose
these tests won't work with containers
ftp tests with containers; removed crap servers; tests only lib
hostname for github
booooooh
fixed recursive remove FTP
Use containers to test file transfers
Container setup
Container setup
tests with docker-compose
these tests won't work with containers
ftp tests with containers; removed crap servers; tests only lib
hostname for github
booooooh
fixed recursive remove FTP
fixed rename
changelog
Desperate attempt
Fixed ftp tests; migrated sftp tests to containers; use env for services
github actions are just broken imo
github actions are just broken imo
Don't use services, since they just don't fuckin work...
docker compose not supported yet?
deprecated typo
Now explain this: github actions have services (which don't work) and then you find out docker-compose is already installed *BLOWMIND*
Fixed hostname for tests
scp tests
maybe
tests
wtf
Restored host tests
Changelog
Improving coverage
Improving coverage
Restored coverage task
More tests for file transfers; test ssh keys too
typo
tests; code improvements
Use tests helpers
fixed tempdir
fixed tempdir
about: Report a typo/error in a repository document
title: "[COPY] - ISSUE_TITLE"
labels: documentation
assignees: veeso
---
## Report
### DOCUMENT NAME
This sentence at row ROW_NUMBER doesn't seem right:
> Write down here the wrong sentence
and I think it should be changed to:
> Write down here the correct sentence
`Copy paste the template above for all the sentences to fix`
---
`Copy paste the template above for all the documents to fix`
## Additional information
> ❗ Report LANGUAGE checks only if it concerns the documents above
> ❗ If the documents concerns more than one language, copy paste the checks below for each check you want to report
> ❗ The PR mention regards the indicated language. If you check the box, I may add you to a PR where I need to translate a new section of the user manual/README or other documents. I promise I won't stress you anyway.
- [ ] I am C1/C2 speaker for this language: LANGUAGE
- [ ] You can mention me in a PR in case a review for translations is needed
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
List here your changes
- I made this...
- I made also that...
## Type of change
Please select relevant options.
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update
<!--
Provide a brief description of the changes you made in this pull request. If your changes are related to a specific issue, please mention the issue number (e.g., "Fixes #123").
-->
## Checklist
- [ ]My code follows the contribution guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] Any dependent changes have been merged and published in downstream modules
- [ ]I have read the [AI Policy](https://github.com/veeso/termscp/blob/main/AI_POLICY.md) and the [contributing guidelines](https://github.com/veeso/termscp/blob/main/CONTRIBUTING.md).
## AI Disclosure
<!--
Describe how you used AI tools in this contribution. If you did not use any AI tools, write "N/A".
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
termscp is a terminal file transfer client with a TUI (Terminal User Interface), supporting SFTP, SCP, FTP/FTPS, Kube, S3, GCS, SMB, and WebDAV protocols. It features a dual-pane file explorer (local + remote), bookmarks, system keyring integration, file watching/sync, an embedded terminal, and customizable themes.
- **Language**: Rust (edition 2024, MSRV 1.98.0)
- **UI Framework**: tuirealm v3 (built on crossterm)
- **File Transfer**: remotefs ecosystem
## Build & Development Commands
Task runner is `just` (modular recipes under `just/*.just`, imported by root `justfile`). Run `just --list` for the full set.
```bash
# Build
just build_crates # cargo build --workspace
just build_crates "--release"
cargo build --no-default-features # minimal build without SMB/keyring (no just recipe)
# Test (CI-equivalent)
just test"--no-default-features --features github-actions --no-fail-fast"
# Run a single test / a module (use cargo directly, just recipes don't take test names)
cargo test <test_name> -- --nocapture
cargo test --lib filetransfer::
cargo test --lib config::params::tests
# Lint
just clippy "-- -D warnings"
# Format (dprint: Markdown, TOML, YAML, and Rust via nightly rustfmt)
just fmt_check # check only
just fmt # fix
# All code checks at once (fmt_check, clippy -D warnings, doc, deny, install script lint)
just check_code
```
### System Dependencies (for building)
- **Linux**: `libdbus-1-dev`, `libsmbclient-dev`
- **macOS**: `pkg-config`, `samba` (brew, with force link)
## Feature Flags
- **`smb`** (default): SMB/Samba protocol support
- **`keyring`** (default): System keyring integration for password storage
`ActivityManager` owns a `Context` that is passed between activities. Each activity takes ownership of the Context on `on_create()` and returns it on `on_destroy()`.
Platform-specific dependencies: SSH and FTP crates use different TLS backends on Unix vs Windows. SMB support is completely gated behind the `smb` feature flag.
### File Transfer Protocols
`FileTransferProtocol` enum maps to protocol-specific parameter types (`ProtocolParams` enum) and `RemoteFsBuilder` constructs the appropriate `RemoteFs` client. Each protocol has its own params struct (e.g., `GenericProtocolParams` for SSH-based, `AwsS3Params`, `GoogleCloudStorageParams`, `KubeProtocolParams`, `SmbParams`, `WebDAVProtocolParams`).
- **Error handling**: Custom error types with `thiserror`, module-level Result aliases (e.g., `HostResult<T>`)
- **Builder pattern**: Used for `RemoteFsBuilder`, `HostBridgeBuilder`
- **Client pattern**: System services wrapped as clients (`BookmarksClient`, `ConfigClient`)
- **Tests**: Unit tests in `#[cfg(test)]` blocks within source files. Tests requiring serial execution use `#[serial]` from `serial_test`
- **Encryption**: Bookmark passwords encrypted with `magic-crypt`; keys stored in system keyring or encrypted file
## Other conventions
- Always run `just fmt` and `just clippy "-- -D warnings"` after modifying Rust code
- Always put plans to `./.claude/plans/`
- When changing behavior that is documented under `docs/` (paths, config keys, commands, flags, etc.), update BOTH `docs/en-US/` and `docs/zh-CN/` to keep the translations in sync
- All code must be cross-platform compatible (Windows, macOS, Linux) — avoid POSIX-only APIs, hardcoded path separators, or shell-specific behavior unless gated behind the `posix`/`win` cfg aliases
termscp was born because, as a terminal lover and Linux user, I wanted something like WinSCP on Linux and on terminal. At my previous job, I used SFTP/SCP practically everyday and that made me desire an application like termscp so much that eventually I started to work on it in my spare time.
I saw there was a very cool library to create terminal user interfaces (`tui-rs`, now `ratatui`), so I started to code it.
I wrote termscp as an experiment. I didn't design anything at the time. I just said,
> "Ok, there must be a FileTransfer trait somehow. I'll have more views, so I'll use something like Android activities, and there must be a module to interact with the local host."
And so in december 2020 I had the first version of termscp running and it worked, but was very simple, raw and minimal.
A lot of things have changed since them, both the features the project provides and my personal view of this project.
Today I don't see termscp as a WinSCP clone anymore. I've also thought about changing the name as the time passed by, but I liked it and it would be hard to change the name on the registries, etc.
Right now I see termscp as a **rich-featured file transfer client for terminals**. All I want is to provide all the features users need to use it correctly, I want it to be **safe and reliable** and eventually I want people to consider termscp **the first choice as a file transfer client**.
### Project goals
- Have support for all the most used file transfer protocol
- Provide all the features a file explorer requires
- Have a well designed application
- Make a reliable, safe and fast application
---
## Open an issue
Open an issue when:
- You have questions or concerns regarding the project or the application itself.
- You have a bug to report.
- You have a copy error to report. (Error in documentation; bad translation or sentence)
- You have a feature or a suggestion to improve termscp to submit.
### Questions
If you have a question open an issue using the `Question` template.
By default your question should already be labeled with the `question` label, if you need help with your installation, please also add the `help wanted` label.
Check the issue is always assigned to `veeso`.
### Bug reports
If you want to report an issue or a bug you've encountered while using termscp, open an issue using the `Bug report` template.
The `Bug` label should already be set and the issue should already be assigned to `veeso`.
Don't set other labels to your issue, not even priority.
When you open a bug try to be the most precise as possible in describing your issue. I'm not saying you should always be that precise, since sometimes it's very easy for maintainers to understand what you're talking about. Just try to be reasonable to understand sometimes we might not know what you're talking about or we just don't have the technical knowledge you might think.
Please always provide the environment you're working on and consider that we don't provide any support for older version of termscp, at least for those not classified as LTS (if we'll ever have them).
If you can, provide the log file or the snippet involving your issue. You can find in the [user manual](https://docs.termscp.rs/en-US/configuration/logging.html) the location of the log file. Please, if you can, enable the **debug mode**, before submitting the log, in order to provide us with a better overview of the problem.
Last but not least: the template I've written must be used. Full stop.
Maintainers will may add additional labels to your issue:
- **duplicate**: the issue is duplicated; the reference to the related issue will be added to your description. Your issue will be closed.
- **priority**: this must be fixed asap
- **sorcery**: it is not possible to find out what's causing your bug, nor is reproducible on our test environments.
- **wontfix**: your bug has a very high ratio between the difficulty to fix it and the probability to encounter it, or it just isn't a bug, but a feature.
### Copy error
If you want to report a copy error, create an issue using the `copy` template.
The `Documentation` label should already be set and the issue should already be assigned to `veeso`.
If you want to fix the copy by yourself you can fork the project and open a PR, otherwise I will fix it by myself.
The copy issue is accepted **also if you're not a C1/C2 speaker**, but a speaker of that level in case the language is different from Italian/English is preferred.
Please fullfil the form on the bottom of the template if you want.
### Feature requests
Whenever you have a good idea which chould improve the project, it is a good idea to submit it to the project owner.
The first thing you should do though, is not starting to write the code, but is to become concern about how termscp works, what kind
of contribution I appreciate and what kind of contribution I won't consider.
Said so, follow these steps:
- Read the contributing guidelines, entirely
- Think on whether your idea would fit in the project mission and guidelines or not
- Think about the impact your idea would have on the project
- Open an issue using the `feature request` template describing with accuracy your suggestion
- Wait for the maintainer feedback on your idea
It is very important to follow these steps, since it will prevent you from working on a feature that will be rejected and trust me, none of us wants to deal with this situation.
Always mind that your suggestion, may be rejected: I'll always provide a feedback on the reasons that brought me to reject your feature, just try not to get mad about that.
---
@@ -17,193 +109,46 @@ Please note we have a [code of conduct](./CODE_OF_CONDUCT.md), please follow it
At the moment, these kind of contributions are more appreciated and should be preferred:
- Fix for issues described in [Known Issues](./README.md#known-issues) or [issues reported by the community](https://github.com/ChristianVisintin/TermSCP/issues)
- New file transfers: for further details see [Implementing File Transfer](#implementing-file-transfers)
-Improvements to translators: any improvement to transliteration is accepted if makes sense, consider that my implementations could be not 100% correct (and probably they're not), indeed consider that I don't speak all these languages (tbh I only can speak Russian as a language with a different alphabet from latin - and I can't even speak it very well).
-Code optimizations: any optimization to the code is welcome
- Fix for issues described in [Known Issues](./README.md#known-issues-) or [issues reported by the community](https://github.com/veeso/termscp/issues)
-**New file transfers**: for further details see [Implementing File Transfer](#implementing-file-transfers). ⚠️ this is going to be deprecated SOON! We're moving the file transfers into another library. Please see [remotefs-rs](https://github.com/veeso/remotefs-rs).
-**Code optimizations**: any optimization to the code is welcome
-See also features described in [Upcoming features](./README.md##upcoming-features-). Open an issue first though.
- README/User manual **translations**: really appreciated atm. Please just add a folder into `docs/` with the language code. Language code with two characters is used in case the language is understandable by all the countries where this language is spoken (e.g. `it-CH`, `it-IT` are not really different, so I just created `it`, but there is a big difference from `zh-CN` and `zh-TW` for instance). Don't worry about flags in README, I will implement that part if it's too complicated.
For any other kind of contribution, especially for new features, please submit an issue first.
For any other kind of contribution, especially for new features, please submit a new issue first.
## Pull Request Process
Let's make it simple and clear:
1. Open an issue with an **appropriate label** (e.g. bug, enhancement, ...).
2. Write a **properly documentation** compliant with **rustdoc** standard.
3. Write tests for your code. This doesn't apply necessarily for implementation regarding the user-interface module (`ui`).
4.Report changes to the issue you opened, writing a report of what you changed and what you have introduced.
5.Update the `CHANGELOG.md` file with details of changes to the application.
6. Request maintainers to merge your changes.
1. Open a PR with an **appropriate label** (e.g. bug, enhancement, ...).
2. Write a **properly documentation** for your software compliant with **rustdoc** standard.
3. Write tests for your code. This doesn't apply necessarily for implementation regarding the user-interface module (`ui/activities`) and (if a test server is not available) for file transfers.
4.Check your code with `cargo clippy`.
5.Check if the CI for your commits reports three-green.
6. Report changes to the PR you opened, writing a report of what you changed and what you have introduced.
7. Update the `CHANGELOG.md` file with details of changes to the application. In changelog report changes under a chapter called `PR{PULL_REQUEST_NUMBER}` (e.g. PR12).
8. Assign a maintainer to the reviewers.
9. Wait for a maintainer to fullfil the acceptance tests
10. Wait for a maintainer to complete the acceptance tests
11. Request maintainers to merge your changes.
### Software guidelines
In addition to the process described for the PRs, I've also decided to introduce a list of guidelines to follow when writing the code, that should be followed:
1.**Let's stop the NPM apocalypse**: personally I'm against the abuse of dependencies we make in software projects and I think that NodeJS has opened the way to this drama (and has already gone too far). Nowadays nobody cares about adding hundreds of dependencies to their projects. Don't misunderstand me: I think that package managers are cool, but I'm totally against the abuse we're making of them. I think when we work on a project, we should try to use the minor quantity of dependencies as possible, especially because it's not hard to see how many libraries are getting abandoned right now, causing compatibility issues after a while. So please, when working on termscp, try not to add useless dependencies.
2.**No C-bindings**: personally I think that Rust still relies too much on C. And that's bad, really bad. Many libraries in Rust are just wrappers to C libraries, which is a huge problem, especially considering this is a multiplatform project. Everytime you add a C-binding to your project, you're forcing your users to install additional libraries to their systems. Sometimes these libraries are already installed on their systems (as happens for openssl in this case), but sometimes not. So if you really have to add a dependency to this project, please AVOID completely adding C-bounded libraries.
3.**Test units matter**: Whenever you implement something new to this project, always implement test units which cover the most cases as possible.
4.**Comments are useful**: Many people say that the code should be that simple to talk by itself about what it does, and comments should then be useless. I personally don't agree. I'm not saying they're wrong, but I'm just saying that this approach has, in my personal opinion, many aspects which are underrated:
1. What's obvious for me, might not be for the others.
2. Our capacity to work on a code depends mostly on **time and experience**, not on complexity: I'm not denying complexity matter, but the most decisive factor when working on code is the experience we've acquired working on it and the time we've spent. As the author of the project, I know the project like the back of my hands, but if I didn't work on it for a year, then I would probably have some problems in working on it again as the same speed as before. And do you know what's really time-saving in these cases? Comments.
## Developer contributions guide
Welcome to the contributions guide for TermSCP. This chapter DOESN'T contain the documentation for TermSCP, which can instead be found on Rust Docs at <https://docs.rs/termscp>
This chapter describes how TermSCP works and the guide lines to implement stuff such as file transfers and add features to the user interface.
### How TermSCP works
TermSCP is basically made up of 4 components:
- the **filetransfer**: the filetransfer takes care of managing the remote file system; it provides function to establish a connection with the remote, operating on the remote server file system (e.g. remove files, make directories, rename files, ...), read files and write files. The FileTransfer, as we'll see later, is actually a trait, and for each protocol a FileTransfer must be implement the trait.
- the **host**: the host module provides functions to interact with the local host file system.
- the **ui**: this module contains the implementation of the user interface, as we'll see in the next chapter, this is achieved through **activities**.
- the **activity_manager**: the activity manager takes care of managing activities, basically it runs the activities of the user interface, and chooses, based on their state, when is the moment to terminate the current activity and which activity to run after the current one.
#### Activities
Just a little paragraph about activities. Really, read the code and the documentation to have a clear idea of how the ui works.
I think there are many ways to implement a user interface; for termscp, I decided to go for a **Android-like** approach.
Android works with Activity, each activity represents a view and there is a context shared between them, and so it works here.
Just a little note about activities, activities work with a `Context`, the context is a data holder for different data, which are shared and common between the activities.
I've implemented a Trait called `Activity`, which, is a very very reduced version of the Android activity of course.
This trait provides only 3 methods:
-`on_create`: this method must initialize the activity; the context is passed to the activity, which will be the only owner of the Context, until the activity terminates.
-`on_draw`: this method must be called each time you want to perform an update of the user interface. This is basically the run method of the activity. This method also cares about handling input events. The developer shouldn't draw the interface on each call of this method (consider that this method might be called hundreds of times per second), but only when actually something has changed (for example after an input event has been raised).
-`on_destroy`: this method finalizes the activity and drops it; this method returns the Context to the caller (the activity manager).
You can view the developer guide [here](https://docs.termscp.rs/en-US/developer/developer.html).
---
### Implementing File Transfers
This chapter describes how to implement a file transfer in TermSCP. A file transfer is a module which implements the `FileTransfer` trait. The file transfer provides different modules to interact with a remote server, which in addition to the most obvious methods, used to download and upload files, provides also methods to list files, delete files, create directories etc.
In the following steps I will describe how to implement a new file transfer, in this case I will be implementing the SCP file transfer (which I'm actually implementing the moment I'm writing this lines).
1. Add the Scp protocol to the `FileTransferProtocol` enum.
Move to `src/filetransfer/mod.rs` and add `Scp` to the `FileTransferProtocol` enum
```rs
/// ## FileTransferProtocol
///
/// This enum defines the different transfer protocol available in TermSCP
In this case Scp is a "plain" enum type. If you need particular options, follow the implementation of `Ftp` which uses a boolean flag for indicating if using FTPS or FTP.
2. Implement the FileTransfer struct
Create a file at `src/filetransfer/mytransfer.rs`
Declare your file transfer struct
```rs
/// ## ScpFileTransfer
///
/// SFTP file transfer structure
pub struct ScpFileTransfer {
session: Option<Session>,
sftp: Option<Sftp>,
wrkdir: PathBuf,
}
```
3. Implement the `FileTransfer` trait for it
You'll have to implement the following methods for your file transfer:
- connect: connect to remote server
- disconnect: disconnect from remote server
- is_connected: returns whether the file transfer is connected to remote
- pwd: get working directory
- change_dir: change working directory.
- list_dir: get files and directories at a certain path
- mkdir: make a new directory. Return an error in case the directory already exists
- remove: remove a file or a directory. In case the protocol doesn't support recursive removing of directories you MUST implement this through a recursive algorithm
- rename: rename a file or a directory
- stat: returns detail for a certain path
- send_file: opens a stream to a remote path for write purposes (write a remote file)
- recv_file: opens a stream to a remote path for read purposes (write a local file)
- on_sent: finalize a stream when writing a remote file. In case it's not necessary just return `Ok(())`
- on_recv: fianlize a stream when reading a remote file. In case it's not necessary just return `Ok(())`
In case the protocol you're working on doesn't support any of this features, just return `Err(FileTransferError::new(FileTransferErrorType::UnsupportedFeature))`
4. Add your transfer to filetransfers:
Move to `src/filetransfer/mod.rs` and declare your file transfer:
```rs
// Transfers
pub mod ftp_transfer;
pub mod scp_transfer; // <-- here
pub mod sftp_transfer;
```
5. Handle FileTransfer in `FileTransferActivity::new`
Move to `src/ui/activities/filetransfer_activity/mod.rs` and add the new protocol to the client match
description="TermSCP is a SCP/SFTP/FTPS client for command line with an integrated UI to explore the remote file system. Basically WinSCP on a terminal."
- [How Password can be provided](#how-password-can-be-provided)
- [Keybindings ⌨](#keybindings-)
- [Documentation 📚](#documentation-)
- [Known issues 🧻](#known-issues-)
- [Upcoming Features 🧪](#upcoming-features-)
- [Contributions 🤙🏻](#contributions-)
- [Changelog ⏳](#changelog-)
- [Powered by 🚀](#powered-by-)
- [Gallery 🎬](#gallery-)
- [License 📃](#license-)
## About termscp 🖥
---
## About TermSCP 🖥
TermSCP is basically a porting of WinSCP to terminal. So basically is a terminal utility with an TUI to connect to a remote server to retrieve and upload files and to interact with the local file system. It works both on **Linux**, **MacOS**, **UNIX** and **Windows** and supports SFTP, SCP, FTP and FTPS.
Termscp is a feature rich terminal file transfer and explorer, with support for SCP/SFTP/FTP/Kube/S3/Google Cloud Storage (GCS)/WebDAV. So basically is a terminal utility with an TUI to connect to a remote server to retrieve and upload files and to interact with the local file system. It is **Linux**, **MacOS**, **FreeBSD**, **NetBSD** and **Windows** compatible.

---
### Why TermSCP 🤔
It happens very often to me, when using SCP at work to forget the path of a file on a remote machine, which forces me then to connect through SSH, gather the file path and finally download it through SCP. I could use WinSCP, but I use Linux and I pratically use the terminal for everything, so I wanted something like WinSCP on my terminal. Yeah, I know there midnight commander too, but actually I don't like it very much tbh (and doesn't support scp).
## Features 🎁
- Different communication protocols
- SFTP
- SCP
- FTP and FTPS
- Practical user interface to explore and operate on the remote and on the local machine file system
- Compatible with Windows, Linux, UNIX and MacOS
- Written in Rust
- Easy to extend with new file transfers protocols
- 📁 Different communication protocols
-**SFTP**
-**SCP**
-**FTP** and **FTPS**
- **Kube**
- **S3**
- **Google Cloud Storage (GCS)**
- **SMB**
- **WebDAV**
- 🖥 Explore and operate on the remote and on the local machine file system with a handy UI
- Create, remove, rename, search, view and edit files
- ⭐ Connect to your favourite hosts through built-in bookmarks and recent connections
- 📝 View and edit files with your favourite applications
- 💁 SFTP/SCP authentication with SSH keys and username/password
- 🐧 Compatible with Windows, Linux, FreeBSD, NetBSD and MacOS
- 🐚 Embedded terminal for executing commands on the system.
- 🎨 Make it yours!
- Themes
- Custom file explorer format
- Customizable text editor
- Customizable file sorting
- and many other parameters...
- 📫 Get notified via Desktop Notifications when a large file has been transferred
- 🔭 Keep file changes synchronized with the remote host
- 🔐 Save your password in your operating system key vault
- 🦀 Rust-powered
- 👀 Developed keeping an eye on performance
- 🦄 Frequent awesome updates
---
## Installation ▶
## Get started 🚀
If you're considering to install TermSCP I want to thank you 💛 ! I hope you will enjoy TermSCP!
If you want to contribute to this project, don't forget to check out our contribute guide. [Read More](CONTRIBUTING.md)
If you're considering to install termscp I want to thank you 💜 ! I hope you will enjoy termscp!\
If you want to contribute to this project, don't forget to check out our [contribute guide](CONTRIBUTING.md).
### Cargo 🦀
If you are a Linux, a FreeBSD or a MacOS user this simple shell script will install termscp on your system with a single command:
```sh
# Install termscp through cargo
cargo install termscp
curl --proto '=https' --tlsv1.2 -sSLf https://termscp.rs/install.sh | sh
```
### Deb package 📦
> ❗ MacOs installation requires [Homebrew](https://brew.sh/), otherwise the Rust compiler will be installed
Get `deb` package from [HERE](https://github.com/ChristianVisintin/TermSCP/releases/download/latest/termscp_0.1.0_amd64.deb)
or run `wget https://github.com/ChristianVisintin/TermSCP/releases/download/latest/termscp_0.1.0_amd64.deb`
if you're a Windows user, you can install termscp from PowerShell with a single command:
then install through dpkg:
```sh
dpkg -i termscp_*.deb
# Or even better with gdebi
gdebi termscp_*.deb
```ps
irmhttps://termscp.rs/install.ps1|iex
```
### RPM Package 📦
Get `rpm` package from [HERE](https://github.com/ChristianVisintin/TermSCP/releases/download/latest/termscp-0.1.0-1.x86_64.rpm)
or run `wget https://github.com/ChristianVisintin/TermSCP/releases/download/latest/termscp-0.1.0-1.x86_64.rpm`
then install through rpm:
```sh
rpm -U termscp_*.rpm
```
### Chocolatey 🍫
You can install TermSCP on Windows using [chocolatey](https://chocolatey.org/)
Start PowerShell as administrator and run
or, alternatively, with [Chocolatey](https://chocolatey.org/):
```ps
chocoinstalltermscp
```
Alternatively you can download the ZIP file from [HERE](https://github.com/ChristianVisintin/TermSCP/releases/download/latest/termscp.0.1.0.nupkg)
and then with PowerShell started with administrator previleges, run:
```ps
chocoinstalltermscp-s.
```
### Brew 🍻
You can install TermSCP on MacOS using [brew](https://brew.sh/)
From your terminal run
NetBSD users can install termscp from the official repositories.
```sh
brew tap ChristianVisintin/termscp
brew install termscp
pkgin install termscp
```
---
Arch Linux users can install termscp from the official repositories.
## Usage ❓
TermSCP can be started with the following options:
-`-P, --password <password>` if address is provided, password will be this argument
-`-v, --version` Print version info
-`-h, --help` Print help page
TermSCP can be started in two different mode, if no extra arguments is provided, TermSCP will show the authentication form, where the user will be able to provide the parameters required to connect to the remote peer.
Alternatively, the user can provide an address as argument to skip the authentication form and starting directly the connection to the remote server.
### Address argument
The address argument has the following syntax:
```txt
[protocol]://[username@]<address>[:port]
```sh
pacman -S termscp
```
Let's see some example of this particular syntax, since it's very comfortable and you'll probably going to use this instead of the other one...
For more information or other platforms, please visit [termscp.rs](https://termscp.rs/install) to view all installation methods.
- Connect using default protocol (sftp) to 192.168.1.31, port is default for this protocol (22); username is current user's name
⚠️ If you're looking on how to update termscp just run termscp from CLI with: `(sudo) termscp update` ⚠️
```sh
termscp 192.168.1.31
```
### Requirements ❗
- Connect using default protocol (sftp) to 192.168.1.31, port is default for this protocol (22); username is `root`
The official Linux binaries and `.deb` packages are statically linked against
musl and have **no runtime requirements**: they run on any distribution and
any glibc version.
```sh
termscp root@192.168.1.31
```
These are only required to build termscp from source:
- Connect using scp to 192.168.1.31, port is 4022; username is `omar`
- **Linux** users:
- libdbus-1
- pkg-config
- libsmbclient
- **FreeBSD** or, **NetBSD** users:
- dbus
- pkgconf
- libsmbclient
```sh
termscp scp://omar@192.168.1.31:4022
```
### Optional Requirements ✔️
#### How Password can be provided
These requirements are not forced required to run termscp, but to enjoy all of its features
You have probably noticed, that, when providing the address as argument, there's no way to provide the password.
Password can be basically provided through 3 ways when address argument is provided:
- `-P, --password` option: just use this CLI option providing the password. I strongly unrecommend this method, since it's very unsecure (since you might keep the password in the shell history)
- Via `sshpass`: you can provide password via `sshpass`, e.g. `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31`
- You will be prompted for it: if you don't use any of the previous methods, you will be prompted for the password, as happens with the more classics tools such as `scp`, `ssh`, etc.
- **Linux/FreeBSD** users:
- To **open** files via `V` (at least one of these)
- _xdg-open_
- _gio_
- _gnome-open_
- _kde-open_
- **Linux** users:
- A keyring manager: read more in the [User manual](https://docs.termscp.rs/en-US/configuration/password-security.html#linux-keyring)
- **WSL** users
- To **open** files via `V` (at least one of these)
| `<ESC>` | Disconnect from remote; return to authentication page |
| `<TAB>` | Switch between log tab and explorer |
| `<BACKSPACE>` | Go to previous directory in stack |
| `<RIGHT>` | Move to remote explorer tab |
| `<LEFT>` | Move to local explorer tab |
| `<UP>` | Move up in selected list |
| `<DOWN>` | Move down in selected list |
| `<PGUP>` | Move up in selected list by 8 rows |
| `<PGDOWN>` | Move down in selected list by 8 rows |
| `<ENTER>` | Enter directory |
| `<SPACE>` | Upload / download selected file |
| `<CTRL+D>` | Make directory |
| `<CTRL+G>` | Go to supplied path |
| `<CTRL+H>` | Show help |
| `<CTRL+Q>` | Quit TermSCP |
| `<CTRL+R>` | Rename file |
| `<CTRL+U>` | Go to parent directory |
| `<CANC>` | Delete file |
---
## Documentation 📚
The developer documentation can be found on Rust Docs at <https://docs.rs/termscp>
---
## Known issues 🧻
- Ftp:
- Time in explorer is `1 Jan 1970`, but shouldn't be: that's because chrono can't parse date in a different locale. So if your server has a locale different from the one on your machine, it won't be able to parse the date.
- Some servers don't work: yes, some kind of ftp server don't work correctly, sometimes it won't display any files in the directories, some other times uploading files will fail. Up to date, `vsftpd` is the only one server which I saw working correctly with TermSCP. Am I going to solve this? I'd like to, but it's not my fault at all. Unfortunately [rust-ftp](https://github.com/mattnenterprise/rust-ftp) is an abandoned project (up to 2020), indeed I had to patch many stuff by myself. I'll try to solve these issues, but it will take a long time.
- Sftp:
- sftp is much slower than scp: Okay this is an annoying issue, and again: not my fault. It seems there is an issue with [ssh2-rs](https://github.com/alexcrichton/ssh2-rs) library. If you want to stay up to date with the status of this issue, subscribe to [this issue](https://github.com/alexcrichton/ssh2-rs/issues/206)
- `NoSuchFileOrDirectory` on connect: let me guess, you're running on WSL and you've installed termscp through cargo. I know about this issue and it's a glitch of WSL I guess. Don't worry about it, just move the termscp executable into another PATH location, such as `/usr/bin`.
The user manual can be found on [termscp's documentation website](https://docs.termscp.rs).
---
## Upcoming Features 🧪
- **File viewer**: possibility to show in a popup the file content from the explorer.
See [Milestones](https://github.com/veeso/termscp/milestones)
---
## Contributions 🤙🏻
## Contributing and issues 🤝🏻
Contributions are welcome! 😉
Contributions, bug reports, new features and questions are welcome! 😉
If you have any question or concern, or you want to suggest a new feature, or you want just want to improve termscp, feel free to open an issue or a PR.
If you think you can contribute to TermSCP, please follow [TermSCP's contributions guide](CONTRIBUTING.md)
An **appreciated** contribution would be a translation of the user manual and readme in **other languages**
Licensed under the GNU GPLv3 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
<http://www.gnu.org/licenses/gpl-3.0.txt>
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
<summary>A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/Kube/WebDAV/S3</summary>
<description>
## About TermSCP
Termscp is a feature rich terminal file transfer and explorer, with support for SCP/SFTP/FTP/S3. So basically is a terminal utility with an TUI to connect to a remote server to retrieve and upload files and to interact with the local file system. It is **Linux**, **MacOS**, **BSD** and **Windows** compatible and supports SFTP, SCP, FTP and FTPS.
Features:
- 📁 Different communication protocols
- SFTP
- Kube
- WebDAV
- SCP
- FTP and FTPS
- S3
- SMB
- 🖥 Explore and operate on the remote and on the local machine file system with a handy UI
- Create, remove, rename, search, view and edit files
- ⭐ Connect to your favourite hosts through built-in bookmarks and recent connections
- 📝 View and edit text files with your favourite text editor
- 💁 SFTP/SCP authentication through SSH keys and username/password
- 🐧 Compatible with Windows, Linux, BSD and MacOS
- ✏ Customizable
- Themes
- Custom file explorer format
- Customizable text editor
- Customizable file sorting
- 🔐 Save your password in your operating system key vault
- 🦀 Rust-powered
- 🤝 Easy to extend with new file transfers protocols
| `-P <password>` | Provide the password from the CLI. Repeat the flag for multiple remotes; the order must match the address arguments. Discouraged. |
| `-q` | Disable logging. |
| `-T <ticks>` | Set the UI tick interval in milliseconds. Default is `10`. |
| `--wno-keyring` | Disable system keyring support. |
| `-v` | Print version info. |
| `--help` | Print the help page. |
The `-P` option is discouraged because the password may be kept in the shell
history. See the bookmarks and password-security chapters for safer ways to
provide credentials.
## Subcommands
termscp exposes the following subcommands.
### Import a theme
```sh
termscp theme <theme-file>
```
Import the theme defined in `<theme-file>`.
### Install the latest version
```sh
termscp update
```
Download and install the latest available version of termscp.
### Import ssh hosts
```sh
termscp import-ssh-hosts [ssh-config-file]
```
Import all the hosts from the specified ssh config file as bookmarks in
termscp. If `[ssh-config-file]` is not provided, the default location
`~/.ssh/config` is used. Identity files are imported as ssh keys in termscp too.
### Open configuration
```sh
termscp config
```
Start termscp directly in the configuration (setup) screen.
termscp lets you save your favourite hosts as bookmarks, which can then be loaded quickly from the main layout. termscp also keeps the last 16 hosts you connected to. Both features let you reload all the parameters required to connect to a remote simply by selecting an entry in the tab under the authentication form.
## Where bookmarks are stored
Bookmarks are saved, when possible, in the configuration directory:
-`$HOME/.config/termscp/` on Linux/BSD
-`$HOME/.config/termscp/` on macOS
-`%USERPROFILE%\.termscp\` on Windows
## Saving passwords
For bookmarks only, you can optionally save the password used to authenticate. This does not apply to recent hosts, which never save passwords. The password is not saved by default; you are prompted to choose whether to save it when you create a new bookmark.
If you are concerned about the security of the passwords saved for your bookmarks, see [Are my passwords safe?](../configuration/password-security.md)
## Creating a bookmark
1. Fill in the authentication form with the parameters to connect to your remote server.
2. Press `<CTRL+S>`.
3. Type the name you want to give to the bookmark.
4. Choose whether to remember the password.
5. Press `<ENTER>` to submit.
## Loading a bookmark
To use a previously saved connection, press `<TAB>` to navigate to the bookmarks list, then press `<ENTER>` to load the bookmark parameters into the form.
After you establish a connection with a remote host, termscp shows the file explorer. The explorer is made up of three panels.
- **Local explorer panel**: displayed on the left of the screen. It shows the entries of the current directory on localhost.
- **Remote explorer panel**: displayed on the right of the screen. It shows the entries of the current directory on the remote host.
- **Find results panel**: shown after you search for files. Depending on where you searched (local or remote), it replaces the local explorer panel or the remote explorer panel and lists the entries matching your search query.
## Switching between panels
Use the following keys to move between panels.
-`<LEFT>`: move to the local explorer panel.
-`<RIGHT>`: move to the remote explorer panel.
-`<TAB>`: switch the active explorer tab.
-`<ESC>`: while in the find results panel, exit it and return to the previous panel.
For the complete list of keys available in the explorer, see [Keyboard shortcuts](keyboard-shortcuts.md).
The file watcher synchronizes local paths to a remote path. When a change is detected on a watched local path, it is propagated to the configured remote path within about 5 seconds.
You can watch as many paths as you like.
## Watching a path
1. Put the cursor on the local explorer, on the file or directory you want to keep synchronized.
2. In the remote panel, navigate to the directory where the changes should be reported.
3. Press `<T>`.
4. Answer `<YES>` to the popup.
## Unwatching a path
You can stop watching a path in two ways:
- Press `<T>` on the watched local path (or any of its subfolders).
- Press `<CTRL+T>`, then press `<ENTER>` on the path you want to unwatch.
## Propagated changes
The following changes are reported to the remote host:
- New files and file changes
- Files moved or renamed
- Files removed or unlinked
The watcher works in one direction only (local to remote). Changes made on the remote host are **not** synchronized back to the local host.
termscp lets you act on several files at once. Use these controls to build a selection.
-`<M>`: mark the highlighted file for selection.
-`<CTRL+A>`: select all files in the current directory.
-`<ALT+A>`: deselect all files.
Once a file is marked for selection, it is displayed with a highlighted background.
When a selection exists, only the selected files are processed for actions; the currently highlighted item is ignored. You can also work on multiple files while in the find results panel.
## Actions on a selection
All actions are available when working with multiple files, but some behave slightly differently. With a selection, the name you enter refers to the destination directory rather than a single destination file.
- **Copy**: you are prompted for a destination. With multiple files selected, this name is the destination directory where all the files are copied.
- **Rename**: same as copy, but the files are moved to the destination directory.
- **Save as**: same as copy, but the files are written to the destination directory.
## The transfer queue
If you select a file in a directory (for example `/home`) and then change directory, the file stays selected and is shown in the **transfer queue** in the bottom panel.
When a file is selected, the remote directory active at that moment is associated with its entry. If the file is later transferred, it is transferred to the remote directory associated with it.
### Example
Suppose you select the local file `/home/a.txt` while the remote panel is at `/tmp`, then you move to `/var`, select `/var/b.txt` while the remote panel is at `/home`, and finally perform a transfer. The result is:
termscp can open files with an external application and edit text files in your configured editor. Both local and remote files are supported.
## Open and Open With
Press `<V>` to open a file with the system default application for its file type. termscp relies on your operating system's default opener (powered by the [open](https://docs.rs/crate/open/1.7.0) crate), so make sure at least one of the following is available on your system.
- **Windows**: handled automatically through the `start` command.
- **macOS**: handled automatically through `open`, which is already installed.
- **Linux**: one of `xdg-open`, `gio`, `gnome-open`, or `kde-open` must be installed.
- **WSL**: `wslview` is required. Install [wslu](https://github.com/wslutilities/wslu).
Press `<W>` to open a file with a program you specify.
## Editing text files
Press `<O>` to open a file in your configured text editor. Only text files are supported; binary files are not.
If the file is located on the remote host, it is first downloaded into your temporary file directory, and then re-uploaded to the remote host **only** if you changed it. termscp detects changes by checking the file's last modification time.
## Editing remote files
You cannot edit a remote file in place directly from the remote panel. When you open a remote file, it is downloaded into a temporary directory, but termscp cannot create a watcher to detect when the external program you used to open it has closed, so it cannot tell when you are done editing. To edit a remote file, download it to a local directory first, edit it there, and then upload it again.
Synchronized browsing keeps navigation in sync between the two explorer panels. While it is enabled, whenever you change the working directory in one panel, the same change is reproduced in the other panel.
To enable synchronized browsing, press `<Y>`. Press `<Y>` again to disable it. While it is enabled, the status bar reports the synchronized browsing state as `ON`.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.