feat: **Updated dependencies** and updated the Rust edition to 2024

This commit is contained in:
veeso
2025-06-08 18:00:42 +02:00
parent 8715c2b6f9
commit 783da22ca2
39 changed files with 715 additions and 639 deletions

View File

@@ -4,7 +4,7 @@ on:
workflow_dispatch: workflow_dispatch:
env: env:
TERMSCP_VERSION: "0.17.0" TERMSCP_VERSION: "0.18.0"
jobs: jobs:
build-binaries: build-binaries:

View File

@@ -1,6 +1,7 @@
# Changelog # Changelog
- [Changelog](#changelog) - [Changelog](#changelog)
- [0.18.0](#0180)
- [0.17.0](#0170) - [0.17.0](#0170)
- [0.16.1](#0161) - [0.16.1](#0161)
- [0.16.0](#0160) - [0.16.0](#0160)
@@ -40,6 +41,12 @@
--- ---
## 0.18.0
Released on 31/07/2025
- **Updated dependencies** and updated the Rust edition to `2024`
## 0.17.0 ## 0.17.0
Released on 24/03/2025 Released on 24/03/2025

1144
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,8 +10,8 @@ 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.17.0" version = "0.18.0"
rust-version = "1.85.0" rust-version = "1.85.1"
[package.metadata.rpm] [package.metadata.rpm]
package = "termscp" package = "termscp"
@@ -71,16 +71,16 @@ self_update = { version = "^0.42", default-features = false, features = [
] } ] }
serde = { version = "^1", features = ["derive"] } serde = { version = "^1", features = ["derive"] }
simplelog = "^0.12" simplelog = "^0.12"
ssh2-config = "^0.4" ssh2-config = "^0.5"
tempfile = "3" tempfile = "3"
thiserror = "2" thiserror = "2"
tokio = { version = "1.44", features = ["rt"] } tokio = { version = "1.44", features = ["rt"] }
toml = "^0.8" toml = "^0.8"
tui-realm-stdlib = "2" tui-realm-stdlib = "3"
tuirealm = "2" tuirealm = "3"
unicode-width = "^0.2" unicode-width = "^0.2"
version-compare = "^0.2" version-compare = "^0.2"
whoami = "^1.5" whoami = "^1.6"
wildmatch = "^2" wildmatch = "^2"
[target."cfg(not(target_os = \"macos\"))".dependencies] [target."cfg(not(target_os = \"macos\"))".dependencies]

View File

@@ -71,7 +71,7 @@
</p> </p>
<p align="center">Developed by <a href="https://veeso.me/" target="_blank">@veeso</a></p> <p align="center">Developed by <a href="https://veeso.me/" target="_blank">@veeso</a></p>
<p align="center">Current version: 0.17.0 24/03/2025</p> <p align="center">Current version: 0.18.0 24/03/2025</p>
<p align="center"> <p align="center">
<a href="https://opensource.org/licenses/MIT" <a href="https://opensource.org/licenses/MIT"

View File

@@ -71,7 +71,7 @@
</p> </p>
<p align="center">Entwickelt von <a href="https://veeso.me/" target="_blank">@veeso</a></p> <p align="center">Entwickelt von <a href="https://veeso.me/" target="_blank">@veeso</a></p>
<p align="center">Aktuelle Version: 0.17.0 24/03/2025</p> <p align="center">Aktuelle Version: 0.18.0 24/03/2025</p>
<p align="center"> <p align="center">
<a href="https://opensource.org/licenses/MIT" <a href="https://opensource.org/licenses/MIT"

View File

@@ -71,7 +71,7 @@
</p> </p>
<p align="center">Desarrollado por <a href="https://veeso.me/" target="_blank">@veeso</a></p> <p align="center">Desarrollado por <a href="https://veeso.me/" target="_blank">@veeso</a></p>
<p align="center">Versión actual: 0.17.0 24/03/2025</p> <p align="center">Versión actual: 0.18.0 24/03/2025</p>
<p align="center"> <p align="center">
<a href="https://opensource.org/licenses/MIT" <a href="https://opensource.org/licenses/MIT"

View File

@@ -71,7 +71,7 @@
</p> </p>
<p align="center">Développé par <a href="https://veeso.me/" target="_blank">@veeso</a></p> <p align="center">Développé par <a href="https://veeso.me/" target="_blank">@veeso</a></p>
<p align="center">Version actuelle: 0.17.0 24/03/2025</p> <p align="center">Version actuelle: 0.18.0 24/03/2025</p>
<p align="center"> <p align="center">
<a href="https://opensource.org/licenses/MIT" <a href="https://opensource.org/licenses/MIT"

View File

@@ -71,7 +71,7 @@
</p> </p>
<p align="center">Sviluppato da <a href="https://veeso.me/" target="_blank">@veeso</a></p> <p align="center">Sviluppato da <a href="https://veeso.me/" target="_blank">@veeso</a></p>
<p align="center">Versione corrente: 0.17.0 24/03/2025</p> <p align="center">Versione corrente: 0.18.0 24/03/2025</p>
<p align="center"> <p align="center">
<a href="https://opensource.org/licenses/MIT" <a href="https://opensource.org/licenses/MIT"

View File

@@ -71,7 +71,7 @@
</p> </p>
<p align="center">Desenvolvido por <a href="https://veeso.me/" target="_blank">@veeso</a></p> <p align="center">Desenvolvido por <a href="https://veeso.me/" target="_blank">@veeso</a></p>
<p align="center">Versão atual: 0.17.0 24/03/2025</p> <p align="center">Versão atual: 0.18.0 24/03/2025</p>
<p align="center"> <p align="center">
<a href="https://opensource.org/licenses/MIT" <a href="https://opensource.org/licenses/MIT"

View File

@@ -71,7 +71,7 @@
</p> </p>
<p align="center"><a href="https://veeso.me/" target="_blank">@veeso</a> 开发</p> <p align="center"><a href="https://veeso.me/" target="_blank">@veeso</a> 开发</p>
<p align="center">当前版本: 0.17.0 24/03/2025</p> <p align="center">当前版本: 0.18.0 24/03/2025</p>
<p align="center"> <p align="center">
<a href="https://opensource.org/licenses/MIT" <a href="https://opensource.org/licenses/MIT"

View File

@@ -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.17.0" TERMSCP_VERSION="0.18.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_AMD64="${GITHUB_URL}/termscp_${TERMSCP_VERSION}_amd64.deb" DEB_URL_AMD64="${GITHUB_URL}/termscp_${TERMSCP_VERSION}_amd64.deb"
DEB_URL_AARCH64="${GITHUB_URL}/termscp_${TERMSCP_VERSION}_arm64.deb" DEB_URL_AARCH64="${GITHUB_URL}/termscp_${TERMSCP_VERSION}_arm64.deb"

View File

@@ -35,7 +35,7 @@
<span translate="getStarted.windows.moderation">Consider that Chocolatey moderation can take up to a few weeks <span translate="getStarted.windows.moderation">Consider that Chocolatey moderation can take up to a few weeks
since last release, so if the latest version is not available yet, since last release, so if the latest version is not available yet,
you can install it downloading the ZIP file from</span> you can install it downloading the ZIP file from</span>
<a href="https://github.com/veeso/termscp/releases/latest/download/termscp.0.17.0.nupkg" <a href="https://github.com/veeso/termscp/releases/latest/download/termscp.0.18.0.nupkg"
target="_blank">Github</a> target="_blank">Github</a>
<span translate="getStarted.windows.then">and then, from the ZIP directory, install it via</span> <span translate="getStarted.windows.then">and then, from the ZIP directory, install it via</span>
</p> </p>
@@ -74,7 +74,7 @@
On Debian based distros, you can install termscp using the Deb On Debian based distros, you can install termscp using the Deb
package via: package via:
</p> </p>
<pre><span class="function">wget</span> -O termscp.deb <span class="string">https://github.com/veeso/termscp/releases/latest/download/termscp_0.17.0_amd64.deb</span> <pre><span class="function">wget</span> -O termscp.deb <span class="string">https://github.com/veeso/termscp/releases/latest/download/termscp_0.18.0_amd64.deb</span>
sudo <span class="function">dpkg</span> -i <span class="string">termscp.deb</span></pre> sudo <span class="function">dpkg</span> -i <span class="string">termscp.deb</span></pre>
</div> </div>
<h3> <h3>

View File

@@ -12,7 +12,7 @@
</button> </button>
<div class="p-4 my-4 text-sm text-green-800 rounded-lg bg-green-50"> <div class="p-4 my-4 text-sm text-green-800 rounded-lg bg-green-50">
<p class="text-lg"> <p class="text-lg">
<span translate="intro.versionAlert">termscp 0.17.0 is NOW out! Download it from</span>&nbsp; <span translate="intro.versionAlert">termscp 0.18.0 is NOW out! Download it from</span>&nbsp;
<a href="/get-started.html" translate="intro.here">here!</a> <a href="/get-started.html" translate="intro.here">here!</a>
</p> </p>
</div> </div>

View File

@@ -12,7 +12,7 @@
"intro": { "intro": {
"caption": "A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/Kube/S3/WebDAV", "caption": "A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/Kube/S3/WebDAV",
"getStarted": "Get started →", "getStarted": "Get started →",
"versionAlert": "termscp 0.17.0 is NOW out! Download it from", "versionAlert": "termscp 0.18.0 is NOW out! Download it from",
"here": "here", "here": "here",
"features": { "features": {
"handy": { "handy": {

View File

@@ -12,7 +12,7 @@
"intro": { "intro": {
"caption": "Un explorador y transferencia de archivos de terminal rico en funciones, con apoyo para SCP/SFTP/FTP/Kube/S3/WebDAV", "caption": "Un explorador y transferencia de archivos de terminal rico en funciones, con apoyo para SCP/SFTP/FTP/Kube/S3/WebDAV",
"getStarted": "Para iniciar →", "getStarted": "Para iniciar →",
"versionAlert": "termscp 0.17.0 ya está disponible! Descárgalo desde", "versionAlert": "termscp 0.18.0 ya está disponible! Descárgalo desde",
"here": "aquì", "here": "aquì",
"features": { "features": {
"handy": { "handy": {

View File

@@ -12,7 +12,7 @@
"intro": { "intro": {
"caption": "Un file transfer et navigateur de terminal riche en fonctionnalités avec support pour SCP/SFTP/FTP/Kube/S3/WebDAV", "caption": "Un file transfer et navigateur de terminal riche en fonctionnalités avec support pour SCP/SFTP/FTP/Kube/S3/WebDAV",
"getStarted": "Pour commencer →", "getStarted": "Pour commencer →",
"versionAlert": "termscp 0.17.0 est maintenant sorti! Télécharge-le depuis", "versionAlert": "termscp 0.18.0 est maintenant sorti! Télécharge-le depuis",
"here": "ici", "here": "ici",
"features": { "features": {
"handy": { "handy": {

View File

@@ -12,7 +12,7 @@
"intro": { "intro": {
"caption": "Un file transfer ed explorer ricco di funzionalità con supporto per SFTP/SCP/FTP/S3", "caption": "Un file transfer ed explorer ricco di funzionalità con supporto per SFTP/SCP/FTP/S3",
"getStarted": "Installa termscp →", "getStarted": "Installa termscp →",
"versionAlert": "termscp 0.17.0 è ORA disponbile! Scaricalo da", "versionAlert": "termscp 0.18.0 è ORA disponbile! Scaricalo da",
"here": "qui", "here": "qui",
"features": { "features": {
"handy": { "handy": {

View File

@@ -12,7 +12,7 @@
"intro": { "intro": {
"caption": "功能丰富的终端 UI 文件传输和浏览器,支持 SCP/SFTP/FTP/Kube/S3/WebDAV", "caption": "功能丰富的终端 UI 文件传输和浏览器,支持 SCP/SFTP/FTP/Kube/S3/WebDAV",
"getStarted": "开始 →", "getStarted": "开始 →",
"versionAlert": "termscp 0.17.0 现已发布! 从下载", "versionAlert": "termscp 0.18.0 现已发布! 从下载",
"here": "这里", "here": "这里",
"features": { "features": {
"handy": { "handy": {

View File

@@ -504,10 +504,7 @@ impl Formatter {
}; };
// Match format length: group 3 // Match format length: group 3
let fmt_len: Option<usize> = match &regex_match.get(3) { let fmt_len: Option<usize> = match &regex_match.get(3) {
Some(len) => match len.as_str().parse::<usize>() { Some(len) => len.as_str().parse::<usize>().ok(),
Ok(len) => Some(len),
Err(_) => None,
},
None => None, None => None,
}; };
// Match format extra: group 2 + 1 // Match format extra: group 2 + 1

View File

@@ -79,10 +79,7 @@ fn get_config_client() -> Option<ConfigClient> {
Err(_) => None, Err(_) => None,
Ok(dir) => { Ok(dir) => {
let (cfg_path, ssh_key_dir) = environment::get_config_paths(dir.as_path()); let (cfg_path, ssh_key_dir) = environment::get_config_paths(dir.as_path());
match ConfigClient::new(cfg_path.as_path(), ssh_key_dir.as_path()) { ConfigClient::new(cfg_path.as_path(), ssh_key_dir.as_path()).ok()
Err(_) => None,
Ok(c) => Some(c),
}
} }
} }
} }

View File

@@ -153,10 +153,7 @@ impl ConfigClient {
// Convert string to `GroupDirs` // Convert string to `GroupDirs`
match &self.config.user_interface.group_dirs { match &self.config.user_interface.group_dirs {
None => None, None => None,
Some(val) => match GroupDirs::from_str(val.as_str()) { Some(val) => GroupDirs::from_str(val.as_str()).ok(),
Ok(val) => Some(val),
Err(_) => None,
},
} }
} }

View File

@@ -44,13 +44,10 @@ impl SshKeyStorage {
/// Resolve host via ssh2 configuration /// Resolve host via ssh2 configuration
fn resolve_host_in_ssh2_configuration(&self, host: &str) -> Option<PathBuf> { fn resolve_host_in_ssh2_configuration(&self, host: &str) -> Option<PathBuf> {
self.ssh_config.as_ref().and_then(|x| { self.ssh_config.as_ref().and_then(|x| {
let key = x x.query(host)
.query(host)
.identity_file .identity_file
.as_ref() .as_ref()
.and_then(|x| x.first().cloned()); .and_then(|x| x.first().cloned())
key
}) })
} }
} }

View File

@@ -197,7 +197,7 @@ impl DeleteBookmarkPopup {
.color(color) .color(color)
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.choices(&["Yes", "No"]) .choices(["Yes", "No"])
.value(1) .value(1)
.rewind(true) .rewind(true)
.foreground(color) .foreground(color)
@@ -265,7 +265,7 @@ impl DeleteRecentPopup {
.color(color) .color(color)
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.choices(&["Yes", "No"]) .choices(["Yes", "No"])
.value(1) .value(1)
.rewind(true) .rewind(true)
.foreground(color) .foreground(color)
@@ -337,7 +337,7 @@ impl BookmarkSavePassword {
.sides(BorderSides::BOTTOM | BorderSides::LEFT | BorderSides::RIGHT) .sides(BorderSides::BOTTOM | BorderSides::LEFT | BorderSides::RIGHT)
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.choices(&["Yes", "No"]) .choices(["Yes", "No"])
.value(0) .value(0)
.rewind(true) .rewind(true)
.foreground(color) .foreground(color)

View File

@@ -36,9 +36,9 @@ impl RemoteProtocolRadio {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.choices(if cfg!(smb) { .choices(if cfg!(smb) {
&["SFTP", "SCP", "FTP", "FTPS", "S3", "Kube", "WebDAV", "SMB"] vec!["SFTP", "SCP", "FTP", "FTPS", "S3", "Kube", "WebDAV", "SMB"].into_iter()
} else { } else {
&["SFTP", "SCP", "FTP", "FTPS", "S3", "Kube", "WebDAV"] vec!["SFTP", "SCP", "FTP", "FTPS", "S3", "Kube", "WebDAV"].into_iter()
}) })
.foreground(color) .foreground(color)
.rewind(true) .rewind(true)
@@ -126,7 +126,7 @@ impl HostBridgeProtocolRadio {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.choices(if cfg!(smb) { .choices(if cfg!(smb) {
&[ vec![
"Localhost", "Localhost",
"SFTP", "SFTP",
"SCP", "SCP",
@@ -137,8 +137,9 @@ impl HostBridgeProtocolRadio {
"WebDAV", "WebDAV",
"SMB", "SMB",
] ]
.into_iter()
} else { } else {
&[ vec![
"Localhost", "Localhost",
"SFTP", "SFTP",
"SCP", "SCP",
@@ -148,6 +149,7 @@ impl HostBridgeProtocolRadio {
"Kube", "Kube",
"WebDAV", "WebDAV",
] ]
.into_iter()
}) })
.foreground(color) .foreground(color)
.rewind(true) .rewind(true)
@@ -649,7 +651,7 @@ impl RadioS3NewPathStyle {
.color(color) .color(color)
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.choices(&["Yes", "No"]) .choices(["Yes", "No"])
.foreground(color) .foreground(color)
.rewind(true) .rewind(true)
.title("New path style", Alignment::Left) .title("New path style", Alignment::Left)

View File

@@ -28,7 +28,7 @@ impl ErrorPopup {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(color) .foreground(color)
.text(&[TextSpan::from(text.as_ref())]) .text([TextSpan::from(text.as_ref())])
.wrap(true), .wrap(true),
} }
} }
@@ -64,7 +64,7 @@ impl InfoPopup {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(color) .foreground(color)
.text(&[TextSpan::from(text.as_ref())]) .text([TextSpan::from(text.as_ref())])
.wrap(true), .wrap(true),
} }
} }
@@ -100,7 +100,7 @@ impl WaitPopup {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(color) .foreground(color)
.text(&[TextSpan::from(text.as_ref())]) .text([TextSpan::from(text.as_ref())])
.wrap(true), .wrap(true),
} }
} }
@@ -130,7 +130,7 @@ impl WindowSizeError {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(color) .foreground(color)
.text(&[TextSpan::from( .text([TextSpan::from(
"termscp requires at least 24 lines of height to run", "termscp requires at least 24 lines of height to run",
)]) )])
.wrap(true), .wrap(true),
@@ -163,7 +163,7 @@ impl QuitPopup {
.foreground(color) .foreground(color)
.title("Quit termscp?", Alignment::Center) .title("Quit termscp?", Alignment::Center)
.rewind(true) .rewind(true)
.choices(&["Yes", "No"]), .choices(["Yes", "No"]),
} }
} }
} }
@@ -230,7 +230,7 @@ impl InstallUpdatePopup {
.foreground(color) .foreground(color)
.title("Install update?", Alignment::Center) .title("Install update?", Alignment::Center)
.rewind(true) .rewind(true)
.choices(&["Yes", "No"]), .choices(["Yes", "No"]),
} }
} }
} }
@@ -296,13 +296,7 @@ impl ReleaseNotes {
) )
.foreground(color) .foreground(color)
.title("Release notes", Alignment::Center) .title("Release notes", Alignment::Center)
.text_rows( .text_rows(notes.lines().map(TextSpan::from)),
notes
.lines()
.map(TextSpan::from)
.collect::<Vec<TextSpan>>()
.as_slice(),
),
} }
} }
} }

View File

@@ -64,7 +64,7 @@ pub struct NewVersionDisclaimer {
impl NewVersionDisclaimer { impl NewVersionDisclaimer {
pub fn new(new_version: &str, color: Color) -> Self { pub fn new(new_version: &str, color: Color) -> Self {
Self { Self {
component: Span::default().foreground(color).spans(&[ component: Span::default().foreground(color).spans([
TextSpan::from("termscp "), TextSpan::from("termscp "),
TextSpan::new(new_version).underlined().bold(), TextSpan::new(new_version).underlined().bold(),
TextSpan::from( TextSpan::from(
@@ -91,7 +91,7 @@ pub struct HelpFooter {
impl HelpFooter { impl HelpFooter {
pub fn new(key_color: Color) -> Self { pub fn new(key_color: Color) -> Self {
Self { Self {
component: Span::default().spans(&[ component: Span::default().spans([
TextSpan::from("<F1|CTRL+H>").bold().fg(key_color), TextSpan::from("<F1|CTRL+H>").bold().fg(key_color),
TextSpan::from(" Help "), TextSpan::from(" Help "),
TextSpan::from("<CTRL+C>").bold().fg(key_color), TextSpan::from("<CTRL+C>").bold().fg(key_color),

View File

@@ -53,12 +53,20 @@ impl MockComponent for Log {
.unwrap() .unwrap()
.unwrap_table() .unwrap_table()
.iter() .iter()
.map(|row| ListItem::new(tui_realm_stdlib::utils::wrap_spans(row, width, &self.props))) .map(|row| {
let row_refs = row.iter().collect::<Vec<_>>();
ListItem::new(tui_realm_stdlib::utils::wrap_spans(
row_refs.as_slice(),
width,
&self.props,
))
})
.collect(); .collect();
let title = ("Log".to_string(), Alignment::Left);
let w = TuiList::new(list_items) let w = TuiList::new(list_items)
.block(tui_realm_stdlib::utils::get_block( .block(tui_realm_stdlib::utils::get_block(
borders, borders,
Some(("Log".to_string(), Alignment::Left)), Some(&title),
focus, focus,
None, None,
)) ))

View File

@@ -16,7 +16,7 @@ pub struct FooterBar {
impl FooterBar { impl FooterBar {
pub fn new(key_color: Color) -> Self { pub fn new(key_color: Color) -> Self {
Self { Self {
component: Span::default().spans(&[ component: Span::default().spans([
TextSpan::from("<F1|H>").bold().fg(key_color), TextSpan::from("<F1|H>").bold().fg(key_color),
TextSpan::from(" Help "), TextSpan::from(" Help "),
TextSpan::from("<TAB>").bold().fg(key_color), TextSpan::from("<TAB>").bold().fg(key_color),

View File

@@ -214,7 +214,7 @@ impl DeletePopup {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(color) .foreground(color)
.choices(&["Yes", "No"]) .choices(["Yes", "No"])
.value(1) .value(1)
.title("Delete file(s)?", Alignment::Center), .title("Delete file(s)?", Alignment::Center),
} }
@@ -279,7 +279,7 @@ impl DisconnectPopup {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(color) .foreground(color)
.choices(&["Yes", "No"]) .choices(["Yes", "No"])
.title("Are you sure you want to disconnect?", Alignment::Center), .title("Are you sure you want to disconnect?", Alignment::Center),
} }
} }
@@ -344,7 +344,7 @@ impl ErrorPopup {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(color) .foreground(color)
.text(&[TextSpan::from(text.as_ref())]) .text([TextSpan::from(text.as_ref())])
.wrap(true), .wrap(true),
} }
} }
@@ -461,7 +461,7 @@ impl FatalPopup {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(color) .foreground(color)
.text(&[TextSpan::from(text.as_ref())]) .text([TextSpan::from(text.as_ref())])
.wrap(true), .wrap(true),
} }
} }
@@ -1121,7 +1121,7 @@ impl QuitPopup {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(color) .foreground(color)
.choices(&["Yes", "No"]) .choices(["Yes", "No"])
.title("Are you sure you want to quit termscp?", Alignment::Center), .title("Are you sure you want to quit termscp?", Alignment::Center),
} }
} }
@@ -1275,7 +1275,7 @@ impl ReplacePopup {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(color) .foreground(color)
.choices(&["Yes", "No"]) .choices(["Yes", "No"])
.title(text, Alignment::Center), .title(text, Alignment::Center),
} }
} }
@@ -1502,7 +1502,7 @@ impl SortingPopup {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(color) .foreground(color)
.choices(&["Name", "Modify time", "Creation time", "Size"]) .choices(["Name", "Modify time", "Creation time", "Size"])
.title("Sort files by…", Alignment::Center) .title("Sort files by…", Alignment::Center)
.value(match value { .value(match value {
FileSorting::CreationTime => 2, FileSorting::CreationTime => 2,
@@ -1554,7 +1554,7 @@ impl StatusBarLocal {
let file_sorting = file_sorting_label(browser.host_bridge().file_sorting); let file_sorting = file_sorting_label(browser.host_bridge().file_sorting);
let hidden_files = hidden_files_label(browser.host_bridge().hidden_files_visible()); let hidden_files = hidden_files_label(browser.host_bridge().hidden_files_visible());
Self { Self {
component: Span::default().spans(&[ component: Span::default().spans([
TextSpan::new("File sorting: ").fg(sorting_color), TextSpan::new("File sorting: ").fg(sorting_color),
TextSpan::new(file_sorting).fg(sorting_color).reversed(), TextSpan::new(file_sorting).fg(sorting_color).reversed(),
TextSpan::new(" Hidden files: ").fg(hidden_color), TextSpan::new(" Hidden files: ").fg(hidden_color),
@@ -1589,7 +1589,7 @@ impl StatusBarRemote {
false => "OFF", false => "OFF",
}; };
Self { Self {
component: Span::default().spans(&[ component: Span::default().spans([
TextSpan::new("File sorting: ").fg(sorting_color), TextSpan::new("File sorting: ").fg(sorting_color),
TextSpan::new(file_sorting).fg(sorting_color).reversed(), TextSpan::new(file_sorting).fg(sorting_color).reversed(),
TextSpan::new(" Hidden files: ").fg(hidden_color), TextSpan::new(" Hidden files: ").fg(hidden_color),
@@ -1728,7 +1728,7 @@ impl SyncBrowsingMkdirPopup {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(color) .foreground(color)
.choices(&["Yes", "No"]) .choices(["Yes", "No"])
.title( .title(
format!( format!(
r#"Sync browsing: directory "{dir_name}" doesn't exist. Do you want to create it?"# r#"Sync browsing: directory "{dir_name}" doesn't exist. Do you want to create it?"#
@@ -1802,7 +1802,7 @@ impl WaitPopup {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(color) .foreground(color)
.text(&[TextSpan::from(text.as_ref())]) .text([TextSpan::from(text.as_ref())])
.wrap(true), .wrap(true),
} }
} }
@@ -1830,7 +1830,7 @@ impl WalkdirWaitPopup {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(color) .foreground(color)
.text(&[ .text([
TextSpan::from(text.as_ref()), TextSpan::from(text.as_ref()),
TextSpan::from("Press 'CTRL+C' to abort"), TextSpan::from("Press 'CTRL+C' to abort"),
]) ])
@@ -1961,7 +1961,7 @@ impl WatcherPopup {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(color) .foreground(color)
.choices(&["Yes", "No"]) .choices(["Yes", "No"])
.title(text, Alignment::Center), .title(text, Alignment::Center),
} }
} }

View File

@@ -59,21 +59,21 @@ impl ChmodPopup {
}, },
user: Checkbox::default() user: Checkbox::default()
.foreground(color) .foreground(color)
.choices(&["Read", "Write", "Execute"]) .choices(["Read", "Write", "Execute"])
.title("User", Alignment::Left) .title("User", Alignment::Left)
.borders(Borders::default().sides(BorderSides::NONE)) .borders(Borders::default().sides(BorderSides::NONE))
.values(&make_pex_values(pex.user())) .values(&make_pex_values(pex.user()))
.rewind(true), .rewind(true),
group: Checkbox::default() group: Checkbox::default()
.foreground(color) .foreground(color)
.choices(&["Read", "Write", "Execute"]) .choices(["Read", "Write", "Execute"])
.title("Group", Alignment::Left) .title("Group", Alignment::Left)
.borders(Borders::default().sides(BorderSides::NONE)) .borders(Borders::default().sides(BorderSides::NONE))
.values(&make_pex_values(pex.group())) .values(&make_pex_values(pex.group()))
.rewind(true), .rewind(true),
others: Checkbox::default() others: Checkbox::default()
.foreground(color) .foreground(color)
.choices(&["Read", "Write", "Execute"]) .choices(["Read", "Write", "Execute"])
.title("Others", Alignment::Left) .title("Others", Alignment::Left)
.borders(Borders::default().sides(BorderSides::NONE)) .borders(Borders::default().sides(BorderSides::NONE))
.values(&make_pex_values(pex.others())) .values(&make_pex_values(pex.others()))
@@ -208,9 +208,11 @@ impl MockComponent for ChmodPopup {
.get_or(Attribute::Focus, AttrValue::Flag(false)) .get_or(Attribute::Focus, AttrValue::Flag(false))
.unwrap_flag(); .unwrap_flag();
let div_title = (self.title.clone(), Alignment::Center);
let div = tui_realm_stdlib::utils::get_block( let div = tui_realm_stdlib::utils::get_block(
Borders::default().color(self.color), Borders::default().color(self.color),
Some((self.title.clone(), Alignment::Center)), Some(&div_title),
focus, focus,
None, None,
); );

View File

@@ -158,7 +158,7 @@ impl MockComponent for FileList {
.props .props
.get_or(Attribute::Focus, AttrValue::Flag(false)) .get_or(Attribute::Focus, AttrValue::Flag(false))
.unwrap_flag(); .unwrap_flag();
let div = tui_realm_stdlib::utils::get_block(borders, Some(title), focus, None); let div = tui_realm_stdlib::utils::get_block(borders, Some(&title), focus, None);
// Make list entries // Make list entries
let init_table_iter = if self.has_dot_dot() { let init_table_iter = if self.has_dot_dot() {
vec![vec![TextSpan::from("..")]] vec![vec![TextSpan::from("..")]]

View File

@@ -57,7 +57,7 @@ impl FileListWithSearch {
pub fn borders(mut self, b: Borders) -> Self { pub fn borders(mut self, b: Borders) -> Self {
self.file_list self.file_list
.attr(Attribute::Borders, AttrValue::Borders(b.clone())); .attr(Attribute::Borders, AttrValue::Borders(b));
self.search.attr(Attribute::Borders, AttrValue::Borders(b)); self.search.attr(Attribute::Borders, AttrValue::Borders(b));
self self
} }

View File

@@ -28,7 +28,7 @@ impl ExplorerFuzzy {
.foreground(fg) .foreground(fg)
.highlighted_color(hg) .highlighted_color(hg)
.title(title, Alignment::Left) .title(title, Alignment::Left)
.rows(files.iter().map(|x| vec![TextSpan::from(x)]).collect()), .rows(files.iter().map(|x| vec![TextSpan::from(*x)]).collect()),
} }
} }
@@ -236,7 +236,7 @@ impl ExplorerFind {
.foreground(fg) .foreground(fg)
.highlighted_color(hg) .highlighted_color(hg)
.title(title, Alignment::Left) .title(title, Alignment::Left)
.rows(files.iter().map(|x| vec![TextSpan::from(x)]).collect()), .rows(files.iter().map(|x| vec![TextSpan::from(*x)]).collect()),
} }
} }
} }
@@ -373,7 +373,7 @@ impl ExplorerLocal {
.foreground(fg) .foreground(fg)
.highlighted_color(hg) .highlighted_color(hg)
.title(title, Alignment::Left) .title(title, Alignment::Left)
.rows(files.iter().map(|x| vec![TextSpan::from(x)]).collect()) .rows(files.iter().map(|x| vec![TextSpan::from(*x)]).collect())
.dot_dot(true), .dot_dot(true),
} }
} }
@@ -587,7 +587,7 @@ impl ExplorerRemote {
.foreground(fg) .foreground(fg)
.highlighted_color(hg) .highlighted_color(hg)
.title(title, Alignment::Left) .title(title, Alignment::Left)
.rows(files.iter().map(|x| vec![TextSpan::from(x)]).collect()) .rows(files.iter().map(|x| vec![TextSpan::from(*x)]).collect())
.dot_dot(true), .dot_dot(true),
} }
} }

View File

@@ -286,10 +286,7 @@ impl FileTransferActivity {
log_records: VecDeque::with_capacity(256), // 256 events is enough I guess log_records: VecDeque::with_capacity(256), // 256 events is enough I guess
walkdir: WalkdirStates::default(), walkdir: WalkdirStates::default(),
transfer: TransferStates::default(), transfer: TransferStates::default(),
cache: match TempDir::new() { cache: TempDir::new().ok(),
Ok(d) => Some(d),
Err(_) => None,
},
fswatcher: if enable_fs_watcher { fswatcher: if enable_fs_watcher {
FsWatcher::init(Duration::from_secs(5)).ok() FsWatcher::init(Duration::from_secs(5)).ok()
} else { } else {

View File

@@ -26,7 +26,7 @@ impl ErrorPopup {
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.foreground(Color::Red) .foreground(Color::Red)
.text(&[TextSpan::from(text.as_ref())]) .text([TextSpan::from(text.as_ref())])
.wrap(true), .wrap(true),
} }
} }
@@ -52,7 +52,7 @@ pub struct Footer {
impl Default for Footer { impl Default for Footer {
fn default() -> Self { fn default() -> Self {
Self { Self {
component: Span::default().spans(&[ component: Span::default().spans([
TextSpan::new("<F1|CTRL+H>").bold().fg(Color::Cyan), TextSpan::new("<F1|CTRL+H>").bold().fg(Color::Cyan),
TextSpan::new(" Help "), TextSpan::new(" Help "),
TextSpan::new("<F4|CTRL+S>").bold().fg(Color::Cyan), TextSpan::new("<F4|CTRL+S>").bold().fg(Color::Cyan),
@@ -88,7 +88,7 @@ impl Header {
.color(Color::Yellow) .color(Color::Yellow)
.sides(BorderSides::BOTTOM), .sides(BorderSides::BOTTOM),
) )
.choices(&["Configuration parameters", "SSH Keys", "Theme"]) .choices(["Configuration parameters", "SSH Keys", "Theme"])
.foreground(Color::Yellow) .foreground(Color::Yellow)
.value(match layout { .value(match layout {
ViewLayout::SetupForm => 0, ViewLayout::SetupForm => 0,
@@ -217,7 +217,7 @@ impl Default for QuitPopup {
Alignment::Center, Alignment::Center,
) )
.rewind(true) .rewind(true)
.choices(&["Save", "Don't save", "Cancel"]), .choices(["Save", "Don't save", "Cancel"]),
} }
} }
} }
@@ -273,7 +273,7 @@ impl Default for SavePopup {
.foreground(Color::Yellow) .foreground(Color::Yellow)
.title("Save changes?", Alignment::Center) .title("Save changes?", Alignment::Center)
.rewind(true) .rewind(true)
.choices(&["Yes", "No"]), .choices(["Yes", "No"]),
} }
} }
} }

View File

@@ -33,7 +33,7 @@ impl CheckUpdates {
.color(Color::LightYellow) .color(Color::LightYellow)
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.choices(&["Yes", "No"]) .choices(["Yes", "No"])
.foreground(Color::LightYellow) .foreground(Color::LightYellow)
.rewind(true) .rewind(true)
.title("Check for updates?", Alignment::Left) .title("Check for updates?", Alignment::Left)
@@ -67,7 +67,7 @@ impl DefaultProtocol {
.color(Color::Cyan) .color(Color::Cyan)
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.choices(&["SFTP", "SCP", "FTP", "FTPS", "Kube", "S3", "SMB", "WebDAV"]) .choices(["SFTP", "SCP", "FTP", "FTPS", "Kube", "S3", "SMB", "WebDAV"])
.foreground(Color::Cyan) .foreground(Color::Cyan)
.rewind(true) .rewind(true)
.title("Default protocol", Alignment::Left) .title("Default protocol", Alignment::Left)
@@ -110,7 +110,7 @@ impl GroupDirs {
.color(Color::LightMagenta) .color(Color::LightMagenta)
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.choices(&["Display first", "Display last", "No"]) .choices(["Display first", "Display last", "No"])
.foreground(Color::LightMagenta) .foreground(Color::LightMagenta)
.rewind(true) .rewind(true)
.title("Group directories", Alignment::Left) .title("Group directories", Alignment::Left)
@@ -148,7 +148,7 @@ impl HiddenFiles {
.color(Color::LightRed) .color(Color::LightRed)
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.choices(&["Yes", "No"]) .choices(["Yes", "No"])
.foreground(Color::LightRed) .foreground(Color::LightRed)
.rewind(true) .rewind(true)
.title("Show hidden files? (by default)", Alignment::Left) .title("Show hidden files? (by default)", Alignment::Left)
@@ -182,7 +182,7 @@ impl NotificationsEnabled {
.color(Color::LightRed) .color(Color::LightRed)
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.choices(&["Yes", "No"]) .choices(["Yes", "No"])
.foreground(Color::LightRed) .foreground(Color::LightRed)
.rewind(true) .rewind(true)
.title("Enable notifications?", Alignment::Left) .title("Enable notifications?", Alignment::Left)
@@ -216,7 +216,7 @@ impl PromptOnFileReplace {
.color(Color::LightBlue) .color(Color::LightBlue)
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.choices(&["Yes", "No"]) .choices(["Yes", "No"])
.foreground(Color::LightBlue) .foreground(Color::LightBlue)
.rewind(true) .rewind(true)
.title("Prompt when replacing existing files?", Alignment::Left) .title("Prompt when replacing existing files?", Alignment::Left)

View File

@@ -31,7 +31,7 @@ impl Default for DelSshKeyPopup {
.color(Color::Red) .color(Color::Red)
.modifiers(BorderType::Rounded), .modifiers(BorderType::Rounded),
) )
.choices(&["Yes", "No"]) .choices(["Yes", "No"])
.foreground(Color::Red) .foreground(Color::Red)
.rewind(true) .rewind(true)
.title("Delete key?", Alignment::Center) .title("Delete key?", Alignment::Center)

View File

@@ -100,7 +100,7 @@ static REMOTE_SMB_OPT_REGEX: Lazy<Regex> =
/** /**
* Regex matches: * Regex matches:
* - group 1: Version * - group 1: Version
* E.g. termscp-0.3.2 => 0.3.2; v0.4.0 => 0.4.0 * E.g. termscp-0.3.2 => 0.3.2; v0.4.0 => 0.4.0
*/ */
static SEMVER_REGEX: Lazy<Regex> = lazy_regex!(r"v?((0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*))"); static SEMVER_REGEX: Lazy<Regex> = lazy_regex!(r"v?((0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*))");