Compare commits
11 commits
Author | SHA1 | Date | |
---|---|---|---|
17a4efe80d | |||
18c30e5814 | |||
d9c01c55e8 | |||
d9abb5545e | |||
9b9786bfbf | |||
9a56ebaa57 | |||
4f5d8c9224 | |||
c7971378b2 | |||
6f2b469a01 | |||
7fefea5e5f | |||
5f53c654de |
1
.github/actions-rs/grcov.yml
vendored
1
.github/actions-rs/grcov.yml
vendored
|
@ -7,7 +7,6 @@ ignore:
|
||||||
- "C:/*"
|
- "C:/*"
|
||||||
- "../*"
|
- "../*"
|
||||||
- src/main.rs
|
- src/main.rs
|
||||||
- src/lib.rs
|
|
||||||
- src/activity_manager.rs
|
- src/activity_manager.rs
|
||||||
- src/filetransfer/transfer/s3/mod.rs
|
- src/filetransfer/transfer/s3/mod.rs
|
||||||
- src/support.rs
|
- src/support.rs
|
||||||
|
|
2
.github/workflows/coverage.yml
vendored
2
.github/workflows/coverage.yml
vendored
|
@ -24,7 +24,7 @@ jobs:
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
args: --lib --no-default-features --features github-actions --features with-containers --no-fail-fast
|
args: --no-default-features --features github-actions --features with-containers --no-fail-fast
|
||||||
env:
|
env:
|
||||||
CARGO_INCREMENTAL: "0"
|
CARGO_INCREMENTAL: "0"
|
||||||
RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests"
|
RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests"
|
||||||
|
|
2
.github/workflows/freebsd.yml
vendored
2
.github/workflows/freebsd.yml
vendored
|
@ -19,4 +19,4 @@ jobs:
|
||||||
/tmp/rustup.sh -y
|
/tmp/rustup.sh -y
|
||||||
. $HOME/.cargo/env
|
. $HOME/.cargo/env
|
||||||
cargo build --no-default-features
|
cargo build --no-default-features
|
||||||
cargo test --no-default-features --verbose --lib --features github-actions -- --test-threads 1
|
cargo test --no-default-features --verbose --features github-actions
|
||||||
|
|
2
.github/workflows/linux.yml
vendored
2
.github/workflows/linux.yml
vendored
|
@ -24,7 +24,7 @@ jobs:
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
args: --lib --no-default-features --features github-actions --features with-containers --no-fail-fast
|
args: --no-default-features --features github-actions --features with-containers --no-fail-fast
|
||||||
- name: Format
|
- name: Format
|
||||||
run: cargo fmt --all -- --check
|
run: cargo fmt --all -- --check
|
||||||
- name: Clippy
|
- name: Clippy
|
||||||
|
|
4
.github/workflows/macos.yml
vendored
4
.github/workflows/macos.yml
vendored
|
@ -14,6 +14,6 @@ jobs:
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build
|
run: cargo build
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test --verbose --lib --features github-actions -- --test-threads 1
|
run: cargo test --verbose --features github-actions
|
||||||
- name: Clippy
|
- name: Clippy
|
||||||
run: cargo clippy
|
run: cargo clippy -- -Dwarnings
|
||||||
|
|
4
.github/workflows/windows.yml
vendored
4
.github/workflows/windows.yml
vendored
|
@ -14,6 +14,6 @@ jobs:
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build
|
run: cargo build
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test --verbose --lib --features github-actions -- --test-threads 1
|
run: cargo test --verbose --features github-actions
|
||||||
- name: Clippy
|
- name: Clippy
|
||||||
run: cargo clippy
|
run: cargo clippy -- -Dwarnings
|
||||||
|
|
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,6 +1,7 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
- [Changelog](#changelog)
|
- [Changelog](#changelog)
|
||||||
|
- [0.8.0](#080)
|
||||||
- [0.7.0](#070)
|
- [0.7.0](#070)
|
||||||
- [0.6.1](#061)
|
- [0.6.1](#061)
|
||||||
- [0.6.0](#060)
|
- [0.6.0](#060)
|
||||||
|
@ -21,6 +22,20 @@
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 0.8.0
|
||||||
|
|
||||||
|
Released on FIXME:
|
||||||
|
|
||||||
|
> ❄️ Winter update 2022 ⛄
|
||||||
|
|
||||||
|
- **Enhancements**:
|
||||||
|
- **Find** feature:
|
||||||
|
- A "wait popup" will now be displayed while searching files
|
||||||
|
- If find command doesn't return any result show an info dialog and not an empty explorer
|
||||||
|
- It is now possible to keep navigating on the other explorer while "found tab" is open
|
||||||
|
- ❗ It is not possible though to have the "found tab" on both explorers (otherwise you wouldn't be able to tell whether you're transferring files)
|
||||||
|
- Files found from search are now displayed with their relative path from working directory
|
||||||
|
|
||||||
## 0.7.0
|
## 0.7.0
|
||||||
|
|
||||||
Released on 12/10/2021
|
Released on 12/10/2021
|
||||||
|
|
25
Cargo.lock
generated
25
Cargo.lock
generated
|
@ -1970,6 +1970,28 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial_test"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"parking_lot 0.11.2",
|
||||||
|
"serial_test_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial_test_derive"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote 1.0.9",
|
||||||
|
"syn 1.0.76",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.9.8"
|
version = "0.9.8"
|
||||||
|
@ -2176,7 +2198,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termscp"
|
name = "termscp"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"argh",
|
"argh",
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
|
@ -2201,6 +2223,7 @@ dependencies = [
|
||||||
"rust-s3",
|
"rust-s3",
|
||||||
"self_update",
|
"self_update",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serial_test",
|
||||||
"simplelog",
|
"simplelog",
|
||||||
"ssh2",
|
"ssh2",
|
||||||
"suppaftp",
|
"suppaftp",
|
||||||
|
|
|
@ -3,7 +3,7 @@ authors = ["Christian Visintin"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
description = "termscp is a feature rich terminal file transfer and explorer with support for SCP/SFTP/FTP/S3"
|
description = "termscp is a feature rich terminal file transfer and explorer with support for SCP/SFTP/FTP/S3"
|
||||||
documentation = "https://docs.rs/termscp"
|
documentation = "https://docs.rs/termscp"
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
homepage = "https://veeso.github.io/termscp/"
|
homepage = "https://veeso.github.io/termscp/"
|
||||||
include = ["src/**/*", "LICENSE", "README.md", "CHANGELOG.md"]
|
include = ["src/**/*", "LICENSE", "README.md", "CHANGELOG.md"]
|
||||||
keywords = ["scp-client", "sftp-client", "ftp-client", "winscp", "command-line-utility"]
|
keywords = ["scp-client", "sftp-client", "ftp-client", "winscp", "command-line-utility"]
|
||||||
|
@ -11,7 +11,7 @@ license = "MIT"
|
||||||
name = "termscp"
|
name = "termscp"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/veeso/termscp"
|
repository = "https://github.com/veeso/termscp"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
|
|
||||||
[package.metadata.rpm]
|
[package.metadata.rpm]
|
||||||
package = "termscp"
|
package = "termscp"
|
||||||
|
@ -67,6 +67,7 @@ wildmatch = "2.0.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "0.7.2"
|
pretty_assertions = "0.7.2"
|
||||||
|
serial_test = "^0.5.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "with-keyring" ]
|
default = [ "with-keyring" ]
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">Developed by <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
|
<p align="center">Developed by <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
|
||||||
<p align="center">Current version: 0.7.0 (12/10/2021)</p>
|
<p align="center">Current version: 0.8.0 (12/10/2021)</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://opensource.org/licenses/MIT"
|
<a href="https://opensource.org/licenses/MIT"
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">Entwickelt von <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
|
<p align="center">Entwickelt von <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
|
||||||
<p align="center">Aktuelle Version: 0.7.0 (12/10/2021)</p>
|
<p align="center">Aktuelle Version: 0.8.0 (12/10/2021)</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://opensource.org/licenses/MIT"
|
<a href="https://opensource.org/licenses/MIT"
|
||||||
|
|
|
@ -339,6 +339,7 @@ These are the keys supported by the formatter:
|
||||||
- `GROUP`: Owner group
|
- `GROUP`: Owner group
|
||||||
- `MTIME`: Last change time (with syntax `%b %d %Y %H:%M`); Extra might be provided as the time syntax (e.g. `{MTIME:8:%H:%M}`)
|
- `MTIME`: Last change time (with syntax `%b %d %Y %H:%M`); Extra might be provided as the time syntax (e.g. `{MTIME:8:%H:%M}`)
|
||||||
- `NAME`: File name (Elided if longer than LENGTH)
|
- `NAME`: File name (Elided if longer than LENGTH)
|
||||||
|
- `PATH`: File absolute path (Elided if longer than LENGHT)
|
||||||
- `PEX`: File permissions (UNIX format)
|
- `PEX`: File permissions (UNIX format)
|
||||||
- `SIZE`: File size (omitted for directories)
|
- `SIZE`: File size (omitted for directories)
|
||||||
- `SYMLINK`: Symlink (if any `-> {FILE_PATH}`)
|
- `SYMLINK`: Symlink (if any `-> {FILE_PATH}`)
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">Desarrollado por <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
|
<p align="center">Desarrollado por <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
|
||||||
<p align="center">Versión actual: 0.7.0 (12/10/2021)</p>
|
<p align="center">Versión actual: 0.8.0 (12/10/2021)</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://opensource.org/licenses/MIT"
|
<a href="https://opensource.org/licenses/MIT"
|
||||||
|
|
|
@ -337,7 +337,8 @@ Estas son las claves admitidas por el formateador:
|
||||||
- `CTIME`: Hora de creación (con sintaxis`%b %d %Y %H:%M`); Se puede proporcionar un extra como sintaxis de tiempo (p. Ej., `{CTIME:8:%H:%M}`)
|
- `CTIME`: Hora de creación (con sintaxis`%b %d %Y %H:%M`); Se puede proporcionar un extra como sintaxis de tiempo (p. Ej., `{CTIME:8:%H:%M}`)
|
||||||
- `GROUP`: Grupo propietario
|
- `GROUP`: Grupo propietario
|
||||||
- `MTIME`: Hora del último cambio (con sintaxis`%b %d %Y %H:%M`); Se puede proporcionar extra como sintaxis de tiempo (p. Ej., `{MTIME: 8:% H:% M}`)
|
- `MTIME`: Hora del último cambio (con sintaxis`%b %d %Y %H:%M`); Se puede proporcionar extra como sintaxis de tiempo (p. Ej., `{MTIME: 8:% H:% M}`)
|
||||||
- `NAME`: nombre de archivo (se omite si es más largo que LENGTH)
|
- `NAME`: nombre de archivo (Las carpetas entre la raíz y los primeros antepasados se eliminan si es más largo que LENGTH)
|
||||||
|
- `PATH`: Percorso completo de archivo (Las carpetas entre la raíz y los primeros antepasados se eliminan si es màs largo que LENGHT)
|
||||||
- `PEX`: permisos de archivo (formato UNIX)
|
- `PEX`: permisos de archivo (formato UNIX)
|
||||||
- `SIZE`: Tamaño del archivo (se omite para directorios)
|
- `SIZE`: Tamaño del archivo (se omite para directorios)
|
||||||
- `SYMLINK`: Symlink (si existe` -> {FILE_PATH} `)
|
- `SYMLINK`: Symlink (si existe` -> {FILE_PATH} `)
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">Développé par <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
|
<p align="center">Développé par <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
|
||||||
<p align="center">Version actuelle: 0.7.0 (12/10/2021)</p>
|
<p align="center">Version actuelle: 0.8.0 (12/10/2021)</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://opensource.org/licenses/MIT"
|
<a href="https://opensource.org/licenses/MIT"
|
||||||
|
|
|
@ -336,6 +336,7 @@ Voici les clés prises en charge par le formateur :
|
||||||
- `GROUP`: Groupe de propriétaires
|
- `GROUP`: Groupe de propriétaires
|
||||||
- `MTIME`: Heure du dernier changement (avec la syntaxe `%b %d %Y %H:%M`); Un supplément peut être fourni comme syntaxe de l'heure (par exemple, `{MTIME:8:%H:%M}`)
|
- `MTIME`: Heure du dernier changement (avec la syntaxe `%b %d %Y %H:%M`); Un supplément peut être fourni comme syntaxe de l'heure (par exemple, `{MTIME:8:%H:%M}`)
|
||||||
- `NAME`: Nom du fichier (élidé si plus long que LENGTH)
|
- `NAME`: Nom du fichier (élidé si plus long que LENGTH)
|
||||||
|
- `PATH`: Chemin absolu du fichier (les dossiers entre la racine et les premiers ancêtres sont éludés s'ils sont plus longs que LENGTH)
|
||||||
- `PEX`: Autorisations de fichiers (format UNIX)
|
- `PEX`: Autorisations de fichiers (format UNIX)
|
||||||
- `SIZE`: Taille du fichier (omis pour les répertoires)
|
- `SIZE`: Taille du fichier (omis pour les répertoires)
|
||||||
- `SYMLINK`: Lien symbolique (le cas échéant `-> {FILE_PATH}`)
|
- `SYMLINK`: Lien symbolique (le cas échéant `-> {FILE_PATH}`)
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">Sviluppato da <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
|
<p align="center">Sviluppato da <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
|
||||||
<p align="center">Versione corrente: 0.7.0 (12/10/2021)</p>
|
<p align="center">Versione corrente: 0.8.0 (12/10/2021)</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://opensource.org/licenses/MIT"
|
<a href="https://opensource.org/licenses/MIT"
|
||||||
|
|
|
@ -333,7 +333,8 @@ These are the keys supported by the formatter:
|
||||||
- `CTIME`: Creation time (con sintassi di default `%b %d %Y %H:%M`); Extra definisce il formato data (e.g. `{CTIME:8:%H:%M}`)
|
- `CTIME`: Creation time (con sintassi di default `%b %d %Y %H:%M`); Extra definisce il formato data (e.g. `{CTIME:8:%H:%M}`)
|
||||||
- `GROUP`: Owner group
|
- `GROUP`: Owner group
|
||||||
- `MTIME`: Last change time (con sintassi di default `%b %d %Y %H:%M`); Extra definisce il formato data (e.g. `{MTIME:8:%H:%M}`)
|
- `MTIME`: Last change time (con sintassi di default `%b %d %Y %H:%M`); Extra definisce il formato data (e.g. `{MTIME:8:%H:%M}`)
|
||||||
- `NAME`: Nome file (Elided if longer than LENGTH)
|
- `NAME`: Nome file (Le cartelle comprese tra la root ed il genitore del file sono omessi se la lunghezza è maggiore di LENGTH)
|
||||||
|
- `PATH`: Percorso assoluto del file (Le cartelle comprese tra la root ed il genitore del file sono omessi se la lunghezza è maggiore di LENGHT)
|
||||||
- `PEX`: Permessi utente (formato UNIX)
|
- `PEX`: Permessi utente (formato UNIX)
|
||||||
- `SIZE`: Dimensione file (omesso per le directory)
|
- `SIZE`: Dimensione file (omesso per le directory)
|
||||||
- `SYMLINK`: Link simbolico (se presente `-> {FILE_PATH}`)
|
- `SYMLINK`: Link simbolico (se presente `-> {FILE_PATH}`)
|
||||||
|
|
|
@ -336,7 +336,8 @@ These are the keys supported by the formatter:
|
||||||
- `CTIME`: Creation time (with syntax `%b %d %Y %H:%M`); Extra might be provided as the time syntax (e.g. `{CTIME:8:%H:%M}`)
|
- `CTIME`: Creation time (with syntax `%b %d %Y %H:%M`); Extra might be provided as the time syntax (e.g. `{CTIME:8:%H:%M}`)
|
||||||
- `GROUP`: Owner group
|
- `GROUP`: Owner group
|
||||||
- `MTIME`: Last change time (with syntax `%b %d %Y %H:%M`); Extra might be provided as the time syntax (e.g. `{MTIME:8:%H:%M}`)
|
- `MTIME`: Last change time (with syntax `%b %d %Y %H:%M`); Extra might be provided as the time syntax (e.g. `{MTIME:8:%H:%M}`)
|
||||||
- `NAME`: File name (Elided if longer than LENGTH)
|
- `NAME`: File name (Folders between root and first ancestors are elided if longer than LENGTH)
|
||||||
|
- `PATH`: File absolute path (Folders between root and first ancestors are elided if longer than LENGHT)
|
||||||
- `PEX`: File permissions (UNIX format)
|
- `PEX`: File permissions (UNIX format)
|
||||||
- `SIZE`: File size (omitted for directories)
|
- `SIZE`: File size (omitted for directories)
|
||||||
- `SYMLINK`: Symlink (if any `-> {FILE_PATH}`)
|
- `SYMLINK`: Symlink (if any `-> {FILE_PATH}`)
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">由 <a href="https://veeso.github.io/" target="_blank">@veeso</a> 开发</p>
|
<p align="center">由 <a href="https://veeso.github.io/" target="_blank">@veeso</a> 开发</p>
|
||||||
<p align="center">当前版本: 0.7.0 (12/10/2021)</p>
|
<p align="center">当前版本: 0.8.0 (12/10/2021)</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://opensource.org/licenses/MIT"
|
<a href="https://opensource.org/licenses/MIT"
|
||||||
|
|
|
@ -330,6 +330,7 @@ termscp和书签一样,只需要保证这些路径是可访问的:
|
||||||
- `GROUP`: 所属组
|
- `GROUP`: 所属组
|
||||||
- `MTIME`: 最后修改时间(语法为`%b %d %Y %H:%M`);Extra参数可以指定时间显示语法(例如:`{MTIME:8:%H:%M}`)
|
- `MTIME`: 最后修改时间(语法为`%b %d %Y %H:%M`);Extra参数可以指定时间显示语法(例如:`{MTIME:8:%H:%M}`)
|
||||||
- `NAME`: 文件名(超过 LENGTH 个字符的部分会被省略)
|
- `NAME`: 文件名(超过 LENGTH 个字符的部分会被省略)
|
||||||
|
- `PATH`:文件绝对路径(如果长于 LENGTH,则根目录和第一个祖先之间的文件夹将被排除)
|
||||||
- `PEX`: 文件权限(UNIX格式)
|
- `PEX`: 文件权限(UNIX格式)
|
||||||
- `SIZE`: 文件大小(目录不显示)
|
- `SIZE`: 文件大小(目录不显示)
|
||||||
- `SYMLINK`: 超链接(如果存在的话`-> {FILE_PATH}`)。
|
- `SYMLINK`: 超链接(如果存在的话`-> {FILE_PATH}`)。
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
# -f, -y, --force, --yes
|
# -f, -y, --force, --yes
|
||||||
# Skip the confirmation prompt during installation
|
# Skip the confirmation prompt during installation
|
||||||
|
|
||||||
TERMSCP_VERSION="0.7.0"
|
TERMSCP_VERSION="0.8.0"
|
||||||
GITHUB_URL="https://github.com/veeso/termscp/releases/download/v${TERMSCP_VERSION}"
|
GITHUB_URL="https://github.com/veeso/termscp/releases/download/v${TERMSCP_VERSION}"
|
||||||
DEB_URL="${GITHUB_URL}/termscp_${TERMSCP_VERSION}_amd64.deb"
|
DEB_URL="${GITHUB_URL}/termscp_${TERMSCP_VERSION}_amd64.deb"
|
||||||
RPM_URL="${GITHUB_URL}/termscp-${TERMSCP_VERSION}-1.x86_64.rpm"
|
RPM_URL="${GITHUB_URL}/termscp-${TERMSCP_VERSION}-1.x86_64.rpm"
|
||||||
|
|
|
@ -28,9 +28,11 @@
|
||||||
// Locals
|
// Locals
|
||||||
use super::FsEntry;
|
use super::FsEntry;
|
||||||
use crate::utils::fmt::{fmt_path_elide, fmt_pex, fmt_time};
|
use crate::utils::fmt::{fmt_path_elide, fmt_pex, fmt_time};
|
||||||
|
use crate::utils::path::diff_paths;
|
||||||
// Ext
|
// Ext
|
||||||
use bytesize::ByteSize;
|
use bytesize::ByteSize;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use std::path::PathBuf;
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
use users::{get_group_by_gid, get_user_by_uid};
|
use users::{get_group_by_gid, get_user_by_uid};
|
||||||
// Types
|
// Types
|
||||||
|
@ -43,6 +45,7 @@ const FMT_KEY_CTIME: &str = "CTIME";
|
||||||
const FMT_KEY_GROUP: &str = "GROUP";
|
const FMT_KEY_GROUP: &str = "GROUP";
|
||||||
const FMT_KEY_MTIME: &str = "MTIME";
|
const FMT_KEY_MTIME: &str = "MTIME";
|
||||||
const FMT_KEY_NAME: &str = "NAME";
|
const FMT_KEY_NAME: &str = "NAME";
|
||||||
|
const FMT_KEY_PATH: &str = "PATH";
|
||||||
const FMT_KEY_PEX: &str = "PEX";
|
const FMT_KEY_PEX: &str = "PEX";
|
||||||
const FMT_KEY_SIZE: &str = "SIZE";
|
const FMT_KEY_SIZE: &str = "SIZE";
|
||||||
const FMT_KEY_SYMLINK: &str = "SYMLINK";
|
const FMT_KEY_SYMLINK: &str = "SYMLINK";
|
||||||
|
@ -68,10 +71,15 @@ lazy_static! {
|
||||||
/// a chain of function is made using the Formatters method.
|
/// a chain of function is made using the Formatters method.
|
||||||
/// This method provides an extremely fast way to format fs entries
|
/// This method provides an extremely fast way to format fs entries
|
||||||
struct CallChainBlock {
|
struct CallChainBlock {
|
||||||
|
/// The function to call to format current item
|
||||||
func: FmtCallback,
|
func: FmtCallback,
|
||||||
|
/// All the content which is between two `{KEY}` items
|
||||||
prefix: String,
|
prefix: String,
|
||||||
|
/// The fmt len, specied for key as `{KEY:LEN}`
|
||||||
fmt_len: Option<usize>,
|
fmt_len: Option<usize>,
|
||||||
|
/// The extra argument for formatting, specified for key as `{KEY:LEN:EXTRA}`
|
||||||
fmt_extra: Option<String>,
|
fmt_extra: Option<String>,
|
||||||
|
/// The next block to format
|
||||||
next_block: Option<Box<CallChainBlock>>,
|
next_block: Option<Box<CallChainBlock>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,6 +339,36 @@ impl Formatter {
|
||||||
format!("{}{}{:0width$}", cur_str, prefix, name, width = file_len)
|
format!("{}{}{:0width$}", cur_str, prefix, name, width = file_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ### fmt_path
|
||||||
|
///
|
||||||
|
/// Format path
|
||||||
|
fn fmt_path(
|
||||||
|
&self,
|
||||||
|
fsentry: &FsEntry,
|
||||||
|
cur_str: &str,
|
||||||
|
prefix: &str,
|
||||||
|
fmt_len: Option<&usize>,
|
||||||
|
fmt_extra: Option<&String>,
|
||||||
|
) -> String {
|
||||||
|
let p = match fmt_extra {
|
||||||
|
None => fsentry.get_abs_path(),
|
||||||
|
Some(rel) => diff_paths(
|
||||||
|
fsentry.get_abs_path().as_path(),
|
||||||
|
PathBuf::from(rel.as_str()).as_path(),
|
||||||
|
)
|
||||||
|
.unwrap_or_else(|| fsentry.get_abs_path()),
|
||||||
|
};
|
||||||
|
format!(
|
||||||
|
"{}{}{}",
|
||||||
|
cur_str,
|
||||||
|
prefix,
|
||||||
|
match fmt_len {
|
||||||
|
None => p.display().to_string(),
|
||||||
|
Some(len) => fmt_path_elide(p.as_path(), *len),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// ### fmt_pex
|
/// ### fmt_pex
|
||||||
///
|
///
|
||||||
/// Format file permissions
|
/// Format file permissions
|
||||||
|
@ -490,6 +528,7 @@ impl Formatter {
|
||||||
FMT_KEY_GROUP => Self::fmt_group,
|
FMT_KEY_GROUP => Self::fmt_group,
|
||||||
FMT_KEY_MTIME => Self::fmt_mtime,
|
FMT_KEY_MTIME => Self::fmt_mtime,
|
||||||
FMT_KEY_NAME => Self::fmt_name,
|
FMT_KEY_NAME => Self::fmt_name,
|
||||||
|
FMT_KEY_PATH => Self::fmt_path,
|
||||||
FMT_KEY_PEX => Self::fmt_pex,
|
FMT_KEY_PEX => Self::fmt_pex,
|
||||||
FMT_KEY_SIZE => Self::fmt_size,
|
FMT_KEY_SIZE => Self::fmt_size,
|
||||||
FMT_KEY_SYMLINK => Self::fmt_symlink,
|
FMT_KEY_SYMLINK => Self::fmt_symlink,
|
||||||
|
@ -880,6 +919,36 @@ mod tests {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_fmt_path() {
|
||||||
|
let t: SystemTime = SystemTime::now();
|
||||||
|
let entry: FsEntry = FsEntry::File(FsFile {
|
||||||
|
name: String::from("bar.txt"),
|
||||||
|
abs_path: PathBuf::from("/tmp/a/b/c/bar.txt"),
|
||||||
|
last_change_time: t,
|
||||||
|
last_access_time: t,
|
||||||
|
creation_time: t,
|
||||||
|
size: 8192,
|
||||||
|
ftype: Some(String::from("txt")),
|
||||||
|
symlink: None, // UNIX only
|
||||||
|
user: None, // UNIX only
|
||||||
|
group: None, // UNIX only
|
||||||
|
unix_pex: Some((UnixPex::from(6), UnixPex::from(4), UnixPex::from(4))), // UNIX only
|
||||||
|
});
|
||||||
|
let formatter: Formatter = Formatter::new("File path: {PATH}");
|
||||||
|
assert_eq!(
|
||||||
|
formatter.fmt(&entry).as_str(),
|
||||||
|
"File path: /tmp/a/b/c/bar.txt"
|
||||||
|
);
|
||||||
|
let formatter: Formatter = Formatter::new("File path: {PATH:8}");
|
||||||
|
assert_eq!(
|
||||||
|
formatter.fmt(&entry).as_str(),
|
||||||
|
"File path: /tmp/…/c/bar.txt"
|
||||||
|
);
|
||||||
|
let formatter: Formatter = Formatter::new("File path: {PATH:128:/tmp/a/b}");
|
||||||
|
assert_eq!(formatter.fmt(&entry).as_str(), "File path: c/bar.txt");
|
||||||
|
}
|
||||||
|
|
||||||
/// ### dummy_fmt
|
/// ### dummy_fmt
|
||||||
///
|
///
|
||||||
/// Dummy formatter, just yelds an 'A' at the end of the current string
|
/// Dummy formatter, just yelds an 'A' at the end of the current string
|
||||||
|
|
|
@ -543,10 +543,9 @@ impl Localhost {
|
||||||
}),
|
}),
|
||||||
false => {
|
false => {
|
||||||
// Is File
|
// Is File
|
||||||
let extension: Option<String> = match path.extension() {
|
let extension: Option<String> = path
|
||||||
Some(s) => Some(String::from(s.to_str().unwrap_or(""))),
|
.extension()
|
||||||
None => None,
|
.map(|s| String::from(s.to_str().unwrap_or("")));
|
||||||
};
|
|
||||||
FsEntry::File(FsFile {
|
FsEntry::File(FsFile {
|
||||||
name: file_name,
|
name: file_name,
|
||||||
abs_path: path.clone(),
|
abs_path: path.clone(),
|
||||||
|
|
77
src/lib.rs
77
src/lib.rs
|
@ -1,77 +0,0 @@
|
||||||
#![doc(html_playground_url = "https://play.rust-lang.org")]
|
|
||||||
#![doc(
|
|
||||||
html_favicon_url = "https://raw.githubusercontent.com/veeso/termscp/main/assets/images/termscp-128.png"
|
|
||||||
)]
|
|
||||||
#![doc(
|
|
||||||
html_logo_url = "https://raw.githubusercontent.com/veeso/termscp/main/assets/images/termscp-512.png"
|
|
||||||
)]
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* termscp - Copyright (c) 2021 Christian Visintin
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate bitflags;
|
|
||||||
extern crate bytesize;
|
|
||||||
extern crate chrono;
|
|
||||||
extern crate content_inspector;
|
|
||||||
extern crate crossterm;
|
|
||||||
extern crate dirs;
|
|
||||||
extern crate edit;
|
|
||||||
extern crate hostname;
|
|
||||||
#[cfg(feature = "with-keyring")]
|
|
||||||
extern crate keyring;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate log;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate magic_crypt;
|
|
||||||
extern crate notify_rust;
|
|
||||||
extern crate open;
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
extern crate path_slash;
|
|
||||||
extern crate rand;
|
|
||||||
extern crate regex;
|
|
||||||
extern crate s3;
|
|
||||||
extern crate self_update;
|
|
||||||
extern crate ssh2;
|
|
||||||
extern crate suppaftp;
|
|
||||||
extern crate tempfile;
|
|
||||||
extern crate textwrap;
|
|
||||||
extern crate tui_realm_stdlib;
|
|
||||||
extern crate tuirealm;
|
|
||||||
#[cfg(target_family = "unix")]
|
|
||||||
extern crate users;
|
|
||||||
extern crate whoami;
|
|
||||||
extern crate wildmatch;
|
|
||||||
|
|
||||||
pub mod activity_manager;
|
|
||||||
pub mod config;
|
|
||||||
pub mod filetransfer;
|
|
||||||
pub mod fs;
|
|
||||||
pub mod host;
|
|
||||||
pub mod support;
|
|
||||||
pub mod system;
|
|
||||||
pub mod ui;
|
|
||||||
pub mod utils;
|
|
|
@ -35,7 +35,6 @@ extern crate lazy_static;
|
||||||
extern crate log;
|
extern crate log;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate magic_crypt;
|
extern crate magic_crypt;
|
||||||
extern crate rpassword;
|
|
||||||
|
|
||||||
// External libs
|
// External libs
|
||||||
use argh::FromArgs;
|
use argh::FromArgs;
|
||||||
|
|
|
@ -110,10 +110,12 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
use serial_test::serial;
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_system_environment_get_config_dir() {
|
fn test_system_environment_get_config_dir() {
|
||||||
// Create and get conf_dir
|
// Create and get conf_dir
|
||||||
let conf_dir: PathBuf = init_config_dir().ok().unwrap().unwrap();
|
let conf_dir: PathBuf = init_config_dir().ok().unwrap().unwrap();
|
||||||
|
@ -122,6 +124,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_system_environment_get_config_dir_err() {
|
fn test_system_environment_get_config_dir_err() {
|
||||||
let mut conf_dir: PathBuf = std::env::temp_dir();
|
let mut conf_dir: PathBuf = std::env::temp_dir();
|
||||||
conf_dir.push("termscp");
|
conf_dir.push("termscp");
|
||||||
|
@ -143,6 +146,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_system_environment_get_bookmarks_paths() {
|
fn test_system_environment_get_bookmarks_paths() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
get_bookmarks_paths(&Path::new("/home/omar/.config/termscp/")),
|
get_bookmarks_paths(&Path::new("/home/omar/.config/termscp/")),
|
||||||
|
@ -151,6 +155,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_system_environment_get_config_paths() {
|
fn test_system_environment_get_config_paths() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
get_config_paths(&Path::new("/home/omar/.config/termscp/")),
|
get_config_paths(&Path::new("/home/omar/.config/termscp/")),
|
||||||
|
@ -162,6 +167,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_system_environment_get_log_paths() {
|
fn test_system_environment_get_log_paths() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
get_log_paths(&Path::new("/home/omar/.config/termscp/")),
|
get_log_paths(&Path::new("/home/omar/.config/termscp/")),
|
||||||
|
@ -170,6 +176,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[serial]
|
||||||
fn test_system_environment_get_theme_path() {
|
fn test_system_environment_get_theme_path() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
get_theme_path(&Path::new("/home/omar/.config/termscp/")),
|
get_theme_path(&Path::new("/home/omar/.config/termscp/")),
|
||||||
|
|
|
@ -97,7 +97,6 @@ impl FileTransferActivity {
|
||||||
LogLevel::Error,
|
LogLevel::Error,
|
||||||
format!("Could not upload file: {}", err),
|
format!("Could not upload file: {}", err),
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FileExplorerTab::FindRemote | FileExplorerTab::Remote => {
|
FileExplorerTab::FindRemote | FileExplorerTab::Remote => {
|
||||||
|
@ -119,7 +118,6 @@ impl FileTransferActivity {
|
||||||
LogLevel::Error,
|
LogLevel::Error,
|
||||||
format!("Could not download file: {}", err),
|
format!("Could not download file: {}", err),
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -162,7 +160,6 @@ impl FileTransferActivity {
|
||||||
LogLevel::Error,
|
LogLevel::Error,
|
||||||
format!("Could not upload file: {}", err),
|
format!("Could not upload file: {}", err),
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,7 +193,6 @@ impl FileTransferActivity {
|
||||||
LogLevel::Error,
|
LogLevel::Error,
|
||||||
format!("Could not download file: {}", err),
|
format!("Could not download file: {}", err),
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,6 @@ impl FileTransferActivity {
|
||||||
LogLevel::Error,
|
LogLevel::Error,
|
||||||
format!("Could not upload file: {}", err),
|
format!("Could not upload file: {}", err),
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,7 +153,6 @@ impl FileTransferActivity {
|
||||||
LogLevel::Error,
|
LogLevel::Error,
|
||||||
format!("Could not upload file: {}", err),
|
format!("Could not upload file: {}", err),
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,7 +183,6 @@ impl FileTransferActivity {
|
||||||
LogLevel::Error,
|
LogLevel::Error,
|
||||||
format!("Could not download file: {}", err),
|
format!("Could not download file: {}", err),
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,7 +223,6 @@ impl FileTransferActivity {
|
||||||
LogLevel::Error,
|
LogLevel::Error,
|
||||||
format!("Could not download file: {}", err),
|
format!("Could not download file: {}", err),
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,8 @@ use crate::fs::explorer::{builder::FileExplorerBuilder, FileExplorer, FileSortin
|
||||||
use crate::fs::FsEntry;
|
use crate::fs::FsEntry;
|
||||||
use crate::system::config_client::ConfigClient;
|
use crate::system::config_client::ConfigClient;
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
/// ## FileExplorerTab
|
/// ## FileExplorerTab
|
||||||
///
|
///
|
||||||
/// File explorer tab
|
/// File explorer tab
|
||||||
|
@ -40,14 +42,23 @@ pub enum FileExplorerTab {
|
||||||
FindRemote, // Find result tab
|
FindRemote, // Find result tab
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ## FoundExplorerTab
|
||||||
|
///
|
||||||
|
/// Describes the explorer tab type
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum FoundExplorerTab {
|
||||||
|
Local,
|
||||||
|
Remote,
|
||||||
|
}
|
||||||
|
|
||||||
/// ## Browser
|
/// ## Browser
|
||||||
///
|
///
|
||||||
/// Browser contains the browser options
|
/// Browser contains the browser options
|
||||||
pub struct Browser {
|
pub struct Browser {
|
||||||
local: FileExplorer, // Local File explorer state
|
local: FileExplorer, // Local File explorer state
|
||||||
remote: FileExplorer, // Remote File explorer state
|
remote: FileExplorer, // Remote File explorer state
|
||||||
found: Option<FileExplorer>, // File explorer for find result
|
found: Option<(FoundExplorerTab, FileExplorer)>, // File explorer for find result
|
||||||
tab: FileExplorerTab, // Current selected tab
|
tab: FileExplorerTab, // Current selected tab
|
||||||
pub sync_browsing: bool,
|
pub sync_browsing: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,23 +93,30 @@ impl Browser {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn found(&self) -> Option<&FileExplorer> {
|
pub fn found(&self) -> Option<&FileExplorer> {
|
||||||
self.found.as_ref()
|
self.found.as_ref().map(|x| &x.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn found_mut(&mut self) -> Option<&mut FileExplorer> {
|
pub fn found_mut(&mut self) -> Option<&mut FileExplorer> {
|
||||||
self.found.as_mut()
|
self.found.as_mut().map(|x| &mut x.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_found(&mut self, files: Vec<FsEntry>) {
|
pub fn set_found(&mut self, tab: FoundExplorerTab, files: Vec<FsEntry>, wrkdir: &Path) {
|
||||||
let mut explorer = Self::build_found_explorer();
|
let mut explorer = Self::build_found_explorer(wrkdir);
|
||||||
explorer.set_files(files);
|
explorer.set_files(files);
|
||||||
self.found = Some(explorer);
|
self.found = Some((tab, explorer));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn del_found(&mut self) {
|
pub fn del_found(&mut self) {
|
||||||
self.found = None;
|
self.found = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ### found_tab
|
||||||
|
///
|
||||||
|
/// Returns found tab if any
|
||||||
|
pub fn found_tab(&self) -> Option<FoundExplorerTab> {
|
||||||
|
self.found.as_ref().map(|x| x.0)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn tab(&self) -> FileExplorerTab {
|
pub fn tab(&self) -> FileExplorerTab {
|
||||||
self.tab
|
self.tab
|
||||||
}
|
}
|
||||||
|
@ -152,13 +170,15 @@ impl Browser {
|
||||||
/// ### build_found_explorer
|
/// ### build_found_explorer
|
||||||
///
|
///
|
||||||
/// Build explorer reading from `ConfigClient`, for found result (has some differences)
|
/// Build explorer reading from `ConfigClient`, for found result (has some differences)
|
||||||
fn build_found_explorer() -> FileExplorer {
|
fn build_found_explorer(wrkdir: &Path) -> FileExplorer {
|
||||||
FileExplorerBuilder::new()
|
FileExplorerBuilder::new()
|
||||||
.with_file_sorting(FileSorting::Name)
|
.with_file_sorting(FileSorting::Name)
|
||||||
.with_group_dirs(Some(GroupDirs::First))
|
.with_group_dirs(Some(GroupDirs::First))
|
||||||
.with_hidden_files(true)
|
.with_hidden_files(true)
|
||||||
.with_stack_size(0)
|
.with_stack_size(0)
|
||||||
.with_formatter(Some("{NAME:32} {SYMLINK}"))
|
.with_formatter(Some(
|
||||||
|
format!("{{PATH:36:{}}} {{SYMLINK}}", wrkdir.display()).as_str(),
|
||||||
|
))
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,15 +27,17 @@
|
||||||
*/
|
*/
|
||||||
// locals
|
// locals
|
||||||
use super::{
|
use super::{
|
||||||
actions::SelectedEntry, browser::FileExplorerTab, FileTransferActivity, LogLevel, TransferOpts,
|
actions::SelectedEntry,
|
||||||
COMPONENT_EXPLORER_FIND, COMPONENT_EXPLORER_LOCAL, COMPONENT_EXPLORER_REMOTE,
|
browser::{FileExplorerTab, FoundExplorerTab},
|
||||||
COMPONENT_INPUT_COPY, COMPONENT_INPUT_EXEC, COMPONENT_INPUT_FIND, COMPONENT_INPUT_GOTO,
|
FileTransferActivity, LogLevel, TransferOpts, COMPONENT_EXPLORER_FIND,
|
||||||
COMPONENT_INPUT_MKDIR, COMPONENT_INPUT_NEWFILE, COMPONENT_INPUT_OPEN_WITH,
|
COMPONENT_EXPLORER_LOCAL, COMPONENT_EXPLORER_REMOTE, COMPONENT_INPUT_COPY,
|
||||||
COMPONENT_INPUT_RENAME, COMPONENT_INPUT_SAVEAS, COMPONENT_LIST_FILEINFO,
|
COMPONENT_INPUT_EXEC, COMPONENT_INPUT_FIND, COMPONENT_INPUT_GOTO, COMPONENT_INPUT_MKDIR,
|
||||||
COMPONENT_LIST_REPLACING_FILES, COMPONENT_LOG_BOX, COMPONENT_PROGRESS_BAR_FULL,
|
COMPONENT_INPUT_NEWFILE, COMPONENT_INPUT_OPEN_WITH, COMPONENT_INPUT_RENAME,
|
||||||
COMPONENT_PROGRESS_BAR_PARTIAL, COMPONENT_RADIO_DELETE, COMPONENT_RADIO_DISCONNECT,
|
COMPONENT_INPUT_SAVEAS, COMPONENT_LIST_FILEINFO, COMPONENT_LIST_REPLACING_FILES,
|
||||||
COMPONENT_RADIO_QUIT, COMPONENT_RADIO_REPLACE, COMPONENT_RADIO_SORTING, COMPONENT_TEXT_ERROR,
|
COMPONENT_LOG_BOX, COMPONENT_PROGRESS_BAR_FULL, COMPONENT_PROGRESS_BAR_PARTIAL,
|
||||||
COMPONENT_TEXT_FATAL, COMPONENT_TEXT_HELP,
|
COMPONENT_RADIO_DELETE, COMPONENT_RADIO_DISCONNECT, COMPONENT_RADIO_QUIT,
|
||||||
|
COMPONENT_RADIO_REPLACE, COMPONENT_RADIO_SORTING, COMPONENT_TEXT_ERROR, COMPONENT_TEXT_FATAL,
|
||||||
|
COMPONENT_TEXT_HELP,
|
||||||
};
|
};
|
||||||
use crate::fs::explorer::FileSorting;
|
use crate::fs::explorer::FileSorting;
|
||||||
use crate::fs::FsEntry;
|
use crate::fs::FsEntry;
|
||||||
|
@ -64,6 +66,15 @@ impl Update for FileTransferActivity {
|
||||||
None => None, // Exit after None
|
None => None, // Exit after None
|
||||||
Some(msg) => match msg {
|
Some(msg) => match msg {
|
||||||
// -- local tab
|
// -- local tab
|
||||||
|
(COMPONENT_EXPLORER_LOCAL, key)
|
||||||
|
if key == &MSG_KEY_RIGHT
|
||||||
|
&& matches!(self.browser.found_tab(), Some(FoundExplorerTab::Remote)) =>
|
||||||
|
{
|
||||||
|
// Go to find explorer
|
||||||
|
self.view.active(COMPONENT_EXPLORER_FIND);
|
||||||
|
self.browser.change_tab(FileExplorerTab::FindRemote);
|
||||||
|
None
|
||||||
|
}
|
||||||
(COMPONENT_EXPLORER_LOCAL, key) if key == &MSG_KEY_RIGHT => {
|
(COMPONENT_EXPLORER_LOCAL, key) if key == &MSG_KEY_RIGHT => {
|
||||||
// Change tab
|
// Change tab
|
||||||
self.view.active(COMPONENT_EXPLORER_REMOTE);
|
self.view.active(COMPONENT_EXPLORER_REMOTE);
|
||||||
|
@ -137,6 +148,15 @@ impl Update for FileTransferActivity {
|
||||||
self.update_local_filelist()
|
self.update_local_filelist()
|
||||||
}
|
}
|
||||||
// -- remote tab
|
// -- remote tab
|
||||||
|
(COMPONENT_EXPLORER_REMOTE, key)
|
||||||
|
if key == &MSG_KEY_LEFT
|
||||||
|
&& matches!(self.browser.found_tab(), Some(FoundExplorerTab::Local)) =>
|
||||||
|
{
|
||||||
|
// Go to find explorer
|
||||||
|
self.view.active(COMPONENT_EXPLORER_FIND);
|
||||||
|
self.browser.change_tab(FileExplorerTab::FindLocal);
|
||||||
|
None
|
||||||
|
}
|
||||||
(COMPONENT_EXPLORER_REMOTE, key) if key == &MSG_KEY_LEFT => {
|
(COMPONENT_EXPLORER_REMOTE, key) if key == &MSG_KEY_LEFT => {
|
||||||
// Change tab
|
// Change tab
|
||||||
self.view.active(COMPONENT_EXPLORER_LOCAL);
|
self.view.active(COMPONENT_EXPLORER_LOCAL);
|
||||||
|
@ -336,6 +356,24 @@ impl Update for FileTransferActivity {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
// -- find result explorer
|
// -- find result explorer
|
||||||
|
(COMPONENT_EXPLORER_FIND, key)
|
||||||
|
if key == &MSG_KEY_RIGHT
|
||||||
|
&& matches!(self.browser.tab(), FileExplorerTab::FindLocal) =>
|
||||||
|
{
|
||||||
|
// Active remote explorer
|
||||||
|
self.view.active(COMPONENT_EXPLORER_REMOTE);
|
||||||
|
self.browser.change_tab(FileExplorerTab::Remote);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
(COMPONENT_EXPLORER_FIND, key)
|
||||||
|
if key == &MSG_KEY_LEFT
|
||||||
|
&& matches!(self.browser.tab(), FileExplorerTab::FindRemote) =>
|
||||||
|
{
|
||||||
|
// Active local explorer
|
||||||
|
self.view.active(COMPONENT_EXPLORER_LOCAL);
|
||||||
|
self.browser.change_tab(FileExplorerTab::Local);
|
||||||
|
None
|
||||||
|
}
|
||||||
(COMPONENT_EXPLORER_FIND, key) if key == &MSG_KEY_ESC => {
|
(COMPONENT_EXPLORER_FIND, key) if key == &MSG_KEY_ESC => {
|
||||||
// Umount find
|
// Umount find
|
||||||
self.umount_find();
|
self.umount_find();
|
||||||
|
@ -433,21 +471,43 @@ impl Update for FileTransferActivity {
|
||||||
}
|
}
|
||||||
(COMPONENT_INPUT_FIND, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
(COMPONENT_INPUT_FIND, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
||||||
self.umount_find_input();
|
self.umount_find_input();
|
||||||
|
// Mount wait
|
||||||
|
self.mount_blocking_wait(format!(r#"Searching for "{}"…"#, input).as_str());
|
||||||
// Find
|
// Find
|
||||||
let res: Result<Vec<FsEntry>, String> = match self.browser.tab() {
|
let res: Result<Vec<FsEntry>, String> = match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.action_local_find(input.to_string()),
|
FileExplorerTab::Local => self.action_local_find(input.to_string()),
|
||||||
FileExplorerTab::Remote => self.action_remote_find(input.to_string()),
|
FileExplorerTab::Remote => self.action_remote_find(input.to_string()),
|
||||||
_ => panic!("Trying to search for files, while already in a find result"),
|
_ => panic!("Trying to search for files, while already in a find result"),
|
||||||
};
|
};
|
||||||
|
// Umount wait
|
||||||
|
self.umount_wait();
|
||||||
// Match result
|
// Match result
|
||||||
match res {
|
match res {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// Mount error
|
// Mount error
|
||||||
self.mount_error(err.as_str());
|
self.mount_error(err.as_str());
|
||||||
}
|
}
|
||||||
|
Ok(files) if files.is_empty() => {
|
||||||
|
// If no file has been found notify user
|
||||||
|
self.mount_info(
|
||||||
|
format!(r#"Could not find any file matching "{}""#, input).as_str(),
|
||||||
|
);
|
||||||
|
}
|
||||||
Ok(files) => {
|
Ok(files) => {
|
||||||
|
// Get wrkdir
|
||||||
|
let wrkdir = match self.browser.tab() {
|
||||||
|
FileExplorerTab::Local => self.local().wrkdir.clone(),
|
||||||
|
_ => self.remote().wrkdir.clone(),
|
||||||
|
};
|
||||||
// Create explorer and load files
|
// Create explorer and load files
|
||||||
self.browser.set_found(files);
|
self.browser.set_found(
|
||||||
|
match self.browser.tab() {
|
||||||
|
FileExplorerTab::Local => FoundExplorerTab::Local,
|
||||||
|
_ => FoundExplorerTab::Remote,
|
||||||
|
},
|
||||||
|
files,
|
||||||
|
wrkdir.as_path(),
|
||||||
|
);
|
||||||
// Mount result widget
|
// Mount result widget
|
||||||
self.mount_find(input);
|
self.mount_find(input);
|
||||||
self.update_find_list();
|
self.update_find_list();
|
||||||
|
|
|
@ -26,7 +26,10 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
// locals
|
// locals
|
||||||
use super::{browser::FileExplorerTab, Context, FileTransferActivity};
|
use super::{
|
||||||
|
browser::{FileExplorerTab, FoundExplorerTab},
|
||||||
|
Context, FileTransferActivity,
|
||||||
|
};
|
||||||
use crate::fs::explorer::FileSorting;
|
use crate::fs::explorer::FileSorting;
|
||||||
use crate::fs::FsEntry;
|
use crate::fs::FsEntry;
|
||||||
use crate::ui::components::{
|
use crate::ui::components::{
|
||||||
|
@ -165,24 +168,20 @@ impl FileTransferActivity {
|
||||||
}
|
}
|
||||||
// Draw explorers
|
// Draw explorers
|
||||||
// @! Local explorer (Find or default)
|
// @! Local explorer (Find or default)
|
||||||
match self.browser.tab() {
|
if matches!(self.browser.found_tab(), Some(FoundExplorerTab::Local)) {
|
||||||
FileExplorerTab::FindLocal => {
|
self.view
|
||||||
self.view
|
.render(super::COMPONENT_EXPLORER_FIND, f, tabs_chunks[0]);
|
||||||
.render(super::COMPONENT_EXPLORER_FIND, f, tabs_chunks[0])
|
} else {
|
||||||
}
|
self.view
|
||||||
_ => self
|
.render(super::COMPONENT_EXPLORER_LOCAL, f, tabs_chunks[0]);
|
||||||
.view
|
|
||||||
.render(super::COMPONENT_EXPLORER_LOCAL, f, tabs_chunks[0]),
|
|
||||||
}
|
}
|
||||||
// @! Remote explorer (Find or default)
|
// @! Remote explorer (Find or default)
|
||||||
match self.browser.tab() {
|
if matches!(self.browser.found_tab(), Some(FoundExplorerTab::Remote)) {
|
||||||
FileExplorerTab::FindRemote => {
|
self.view
|
||||||
self.view
|
.render(super::COMPONENT_EXPLORER_FIND, f, tabs_chunks[1]);
|
||||||
.render(super::COMPONENT_EXPLORER_FIND, f, tabs_chunks[1])
|
} else {
|
||||||
}
|
self.view
|
||||||
_ => self
|
.render(super::COMPONENT_EXPLORER_REMOTE, f, tabs_chunks[1]);
|
||||||
.view
|
|
||||||
.render(super::COMPONENT_EXPLORER_REMOTE, f, tabs_chunks[1]),
|
|
||||||
}
|
}
|
||||||
// Draw log box
|
// Draw log box
|
||||||
self.view
|
self.view
|
||||||
|
@ -400,6 +399,15 @@ impl FileTransferActivity {
|
||||||
|
|
||||||
// -- partials
|
// -- partials
|
||||||
|
|
||||||
|
/// ### mount_info
|
||||||
|
///
|
||||||
|
/// Mount info box
|
||||||
|
pub(super) fn mount_info(&mut self, text: &str) {
|
||||||
|
// Mount
|
||||||
|
let info_color = self.theme().misc_info_dialog;
|
||||||
|
self.mount_text_dialog(super::COMPONENT_TEXT_ERROR, text, info_color);
|
||||||
|
}
|
||||||
|
|
||||||
/// ### mount_error
|
/// ### mount_error
|
||||||
///
|
///
|
||||||
/// Mount error box
|
/// Mount error box
|
||||||
|
|
Loading…
Reference in a new issue