feat: finished up application added database support
This commit is contained in:
parent
1323736724
commit
e8c315f3b8
92
Cargo.lock
generated
92
Cargo.lock
generated
@ -404,6 +404,15 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs"
|
||||||
|
version = "6.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||||
|
dependencies = [
|
||||||
|
"dirs-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs-next"
|
name = "dirs-next"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@ -414,6 +423,18 @@ dependencies = [
|
|||||||
"dirs-sys-next",
|
"dirs-sys-next",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs-sys"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"option-ext",
|
||||||
|
"redox_users 0.5.0",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs-sys-next"
|
name = "dirs-sys-next"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@ -421,7 +442,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"redox_users",
|
"redox_users 0.4.6",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -589,6 +610,12 @@ version = "1.70.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jiff"
|
name = "jiff"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
@ -720,6 +747,9 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
|
"dirs",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"skim",
|
"skim",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -772,6 +802,12 @@ version = "1.70.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "option-ext"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "overload"
|
name = "overload"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -938,7 +974,18 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.16",
|
"getrandom 0.2.16",
|
||||||
"libredox",
|
"libredox",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_users"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.16",
|
||||||
|
"libredox",
|
||||||
|
"thiserror 2.0.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1010,6 +1057,12 @@ version = "1.0.21"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
|
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@ -1036,6 +1089,19 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.140"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"itoa",
|
||||||
|
"memchr",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sharded-slab"
|
name = "sharded-slab"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
@ -1179,7 +1245,16 @@ version = "1.0.69"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl 1.0.69",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl 2.0.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1193,6 +1268,17 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "1.1.9"
|
version = "1.1.9"
|
||||||
|
@ -6,6 +6,9 @@ edition = "2024"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.98"
|
anyhow = "1.0.98"
|
||||||
clap = { version = "4.5.40", features = ["derive", "env"] }
|
clap = { version = "4.5.40", features = ["derive", "env"] }
|
||||||
|
dirs = "6.0.0"
|
||||||
|
serde = { version = "1.0.219", features = ["derive"] }
|
||||||
|
serde_json = { version = "1.0.140", features = ["preserve_order"] }
|
||||||
skim = "0.20.2"
|
skim = "0.20.2"
|
||||||
tokio = { version = "1.46.1", features = ["full"] }
|
tokio = { version = "1.46.1", features = ["full"] }
|
||||||
tracing = { version = "0.1.41", features = ["log"] }
|
tracing = { version = "0.1.41", features = ["log"] }
|
||||||
|
@ -1,44 +1 @@
|
|||||||
pub mod interactive {
|
pub mod interactive;
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use anyhow::Context;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
ssh_command::SshCommandState, ssh_config::SshConfigServiceState, state::State,
|
|
||||||
user_fuzzy_find::UserFuzzyFindState,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(clap::Parser, Default)]
|
|
||||||
pub struct InteractiveCommand {}
|
|
||||||
|
|
||||||
impl InteractiveCommand {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn execute(&self, state: &State, ssh_config_path: &Path) -> anyhow::Result<()> {
|
|
||||||
// 1. Get a list of items in ~/.ssh/config
|
|
||||||
let items = state
|
|
||||||
.ssh_config_service()
|
|
||||||
.get_ssh_items(ssh_config_path)
|
|
||||||
.await
|
|
||||||
.context("failed to get ssh items")?;
|
|
||||||
tracing::trace!("found ssh items: {:#?}", items);
|
|
||||||
|
|
||||||
// 2. Present the list, and allow the user to choose an item
|
|
||||||
let item = state
|
|
||||||
.user_fuzzy_find()
|
|
||||||
.get_ssh_item_from_user(&items)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
tracing::debug!("found ssh item: '{}'", item);
|
|
||||||
|
|
||||||
// 3. Perform ssh
|
|
||||||
// call the cmdline parse in all pipes, with the hostname as the destination
|
|
||||||
// ssh something
|
|
||||||
state.ssh_command().start_ssh_session(item).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
46
src/commands/interactive.rs
Normal file
46
src/commands/interactive.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ssh_command::SshCommandState, ssh_command_database::SshCommandDatabaseState,
|
||||||
|
ssh_config::SshConfigServiceState, state::State, user_fuzzy_find::UserFuzzyFindState,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(clap::Parser, Default)]
|
||||||
|
pub struct InteractiveCommand {}
|
||||||
|
|
||||||
|
impl InteractiveCommand {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn execute(&self, state: &State, ssh_config_path: &Path) -> anyhow::Result<()> {
|
||||||
|
// 1. Get a list of items in ~/.ssh/config
|
||||||
|
let mut items = state
|
||||||
|
.ssh_config_service()
|
||||||
|
.get_ssh_items(ssh_config_path)
|
||||||
|
.await
|
||||||
|
.context("failed to get ssh items")?;
|
||||||
|
|
||||||
|
let mut database_items = state.ssh_command_database().get_items().await?;
|
||||||
|
items.append(&mut database_items);
|
||||||
|
|
||||||
|
tracing::trace!("found ssh items: {:#?}", items);
|
||||||
|
|
||||||
|
// 2. Present the list, and allow the user to choose an item
|
||||||
|
let item = state
|
||||||
|
.user_fuzzy_find()
|
||||||
|
.get_ssh_item_from_user(&items)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
tracing::debug!("found ssh item: '{}'", item);
|
||||||
|
|
||||||
|
// 3. Perform ssh
|
||||||
|
// call the cmdline parse in all pipes, with the hostname as the destination
|
||||||
|
// ssh something
|
||||||
|
state.ssh_command().start_ssh_session(item).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -5,12 +5,14 @@ use clap::Parser;
|
|||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commands::interactive::InteractiveCommand, ssh_command::SshCommandState, state::State,
|
commands::interactive::InteractiveCommand, ssh_command::SshCommandState,
|
||||||
|
ssh_command_database::SshCommandDatabaseState, state::State,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
|
|
||||||
mod ssh_command;
|
mod ssh_command;
|
||||||
|
mod ssh_command_database;
|
||||||
mod ssh_config;
|
mod ssh_config;
|
||||||
mod state;
|
mod state;
|
||||||
mod user_fuzzy_find;
|
mod user_fuzzy_find;
|
||||||
@ -72,13 +74,16 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
cmd.execute(&state, &ssh_config_path).await?;
|
cmd.execute(&state, &ssh_config_path).await?;
|
||||||
}
|
}
|
||||||
Subcommands::External(items) => {
|
Subcommands::External(items) => {
|
||||||
|
let items_ref: Vec<&str> = items.iter().map(|i| i.as_str()).collect();
|
||||||
|
|
||||||
// Send to ssh
|
// Send to ssh
|
||||||
state
|
state
|
||||||
.ssh_command()
|
.ssh_command()
|
||||||
.start_ssh_session_from_raw(items.iter().map(|i| i.as_str()).collect())
|
.start_ssh_session_from_raw(&items_ref)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Remember result
|
// Remember result
|
||||||
|
state.ssh_command_database().add_item(&items_ref).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ impl SshCommand {
|
|||||||
|
|
||||||
// ssh something
|
// ssh something
|
||||||
let mut cmd = tokio::process::Command::new("ssh");
|
let mut cmd = tokio::process::Command::new("ssh");
|
||||||
cmd.arg(host);
|
cmd.args(host);
|
||||||
|
|
||||||
let mut process = cmd.spawn()?;
|
let mut process = cmd.spawn()?;
|
||||||
let res = process.wait().await.context("ssh call failed");
|
let res = process.wait().await.context("ssh call failed");
|
||||||
@ -23,7 +23,7 @@ impl SshCommand {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start_ssh_session_from_raw(&self, raw: Vec<&str>) -> anyhow::Result<()> {
|
pub async fn start_ssh_session_from_raw(&self, raw: &[&str]) -> anyhow::Result<()> {
|
||||||
let pretty_raw = raw.join(" ");
|
let pretty_raw = raw.join(" ");
|
||||||
tracing::info!("starting ssh session at: {}", pretty_raw);
|
tracing::info!("starting ssh session at: {}", pretty_raw);
|
||||||
|
|
||||||
|
146
src/ssh_command_database.rs
Normal file
146
src/ssh_command_database.rs
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
use std::{collections::BTreeMap, path::PathBuf};
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tokio::io::AsyncWriteExt;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ssh_config::{SshItem, SshItems},
|
||||||
|
state::State,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct SshCommandDatabase {}
|
||||||
|
|
||||||
|
impl SshCommandDatabase {
|
||||||
|
pub async fn get_items(&self) -> anyhow::Result<SshItems> {
|
||||||
|
let database_path = self.ensure_get_database_file_path().await?;
|
||||||
|
let database = if database_path.exists() {
|
||||||
|
let content = tokio::fs::read(&database_path)
|
||||||
|
.await
|
||||||
|
.context("failed to read nossh database file")?;
|
||||||
|
|
||||||
|
let database: Database = serde_json::from_slice(&content)?;
|
||||||
|
|
||||||
|
database
|
||||||
|
} else {
|
||||||
|
Database::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let entries = database.get_entries();
|
||||||
|
|
||||||
|
let ssh_items = entries
|
||||||
|
.into_iter()
|
||||||
|
.map(|e| {
|
||||||
|
(
|
||||||
|
e.join(" "),
|
||||||
|
SshItem::Raw {
|
||||||
|
contents: e.clone(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(SshItems { items: ssh_items })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self), level = "trace")]
|
||||||
|
pub async fn add_item(&self, raw_session: &[&str]) -> anyhow::Result<()> {
|
||||||
|
tracing::debug!("adding item to database");
|
||||||
|
let database_path = self.ensure_get_database_file_path().await?;
|
||||||
|
|
||||||
|
let mut database = if database_path.exists() {
|
||||||
|
let content = tokio::fs::read(&database_path)
|
||||||
|
.await
|
||||||
|
.context("failed to read nossh database file")?;
|
||||||
|
|
||||||
|
let database: Database = serde_json::from_slice(&content)?;
|
||||||
|
|
||||||
|
database
|
||||||
|
} else {
|
||||||
|
Database::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
database.add_raw(raw_session);
|
||||||
|
|
||||||
|
let mut database_file = tokio::fs::File::create(database_path)
|
||||||
|
.await
|
||||||
|
.context("failed to create nossh database file")?;
|
||||||
|
|
||||||
|
let database_file_content = serde_json::to_vec_pretty(&database)?;
|
||||||
|
|
||||||
|
database_file
|
||||||
|
.write_all(&database_file_content)
|
||||||
|
.await
|
||||||
|
.context("failed to write data to database file")?;
|
||||||
|
database_file
|
||||||
|
.flush()
|
||||||
|
.await
|
||||||
|
.context("failed to flush nossh database file")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_database_file_path(&self) -> PathBuf {
|
||||||
|
dirs::data_local_dir()
|
||||||
|
.expect("requires having a data dir, if using nossh")
|
||||||
|
.join("nossh")
|
||||||
|
.join("nossh.database.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn ensure_get_database_file_path(&self) -> anyhow::Result<PathBuf> {
|
||||||
|
let file_dir = self.get_database_file_path();
|
||||||
|
|
||||||
|
if let Some(parent) = file_dir.parent() {
|
||||||
|
tokio::fs::create_dir_all(parent)
|
||||||
|
.await
|
||||||
|
.context("failed to create data dir for nossh")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(file_dir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Serialize, Deserialize)]
|
||||||
|
struct Database {
|
||||||
|
entries: BTreeMap<String, DatabaseEntry>,
|
||||||
|
}
|
||||||
|
impl Database {
|
||||||
|
fn add_raw(&mut self, raw_session: &[&str]) {
|
||||||
|
self.entries.insert(
|
||||||
|
raw_session.join(" "),
|
||||||
|
DatabaseEntry::Raw {
|
||||||
|
contents: raw_session.iter().map(|r| r.to_string()).collect(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_entries(&self) -> Vec<&Vec<String>> {
|
||||||
|
let mut items = Vec::new();
|
||||||
|
|
||||||
|
for v in self.entries.values() {
|
||||||
|
match v {
|
||||||
|
DatabaseEntry::Raw { contents } => {
|
||||||
|
items.push(contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(tag = "entry_type")]
|
||||||
|
enum DatabaseEntry {
|
||||||
|
Raw { contents: Vec<String> },
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SshCommandDatabaseState {
|
||||||
|
fn ssh_command_database(&self) -> SshCommandDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SshCommandDatabaseState for State {
|
||||||
|
fn ssh_command_database(&self) -> SshCommandDatabase {
|
||||||
|
SshCommandDatabase {}
|
||||||
|
}
|
||||||
|
}
|
@ -44,25 +44,34 @@ impl SshConfigService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SshItem {
|
pub enum SshItem {
|
||||||
host: String,
|
Own(String),
|
||||||
|
Raw { contents: Vec<String> },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SshItem {
|
impl SshItem {
|
||||||
pub fn to_host(&self) -> &str {
|
pub fn to_host(&self) -> Vec<&str> {
|
||||||
&self.host
|
match self {
|
||||||
|
SshItem::Own(own) => vec![own],
|
||||||
|
SshItem::Raw { contents } => contents.iter().map(|c| c.as_str()).collect(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for SshItem {
|
impl Display for SshItem {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_str(&self.host)
|
let host = match self {
|
||||||
|
SshItem::Own(o) => o.to_string(),
|
||||||
|
SshItem::Raw { contents } => contents.join(" "),
|
||||||
|
};
|
||||||
|
|
||||||
|
f.write_str(&host)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SshItems {
|
pub struct SshItems {
|
||||||
items: BTreeMap<String, SshItem>,
|
pub items: BTreeMap<String, SshItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SshItems {
|
impl SshItems {
|
||||||
@ -73,13 +82,15 @@ impl SshItems {
|
|||||||
pub fn get_choice(&self, choice: &str) -> Option<&SshItem> {
|
pub fn get_choice(&self, choice: &str) -> Option<&SshItem> {
|
||||||
self.items.get(choice)
|
self.items.get(choice)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn append(&mut self, other: &mut SshItems) {
|
||||||
|
self.items.append(&mut other.items);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for SshItem {
|
impl From<&str> for SshItem {
|
||||||
fn from(value: &str) -> Self {
|
fn from(value: &str) -> Self {
|
||||||
Self {
|
Self::Own(value.to_string())
|
||||||
host: value.to_string(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ impl UserFuzzyFindState for State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SkimItem for SshItem {
|
impl SkimItem for SshItem {
|
||||||
fn text(&self) -> std::borrow::Cow<str> {
|
fn text(&'_ self) -> std::borrow::Cow<'_, str> {
|
||||||
format!("{self}").into()
|
format!("{self}").into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user