mirror of
https://github.com/orhun/systeroid
synced 2024-10-02 21:53:31 +00:00
feat(tui): support copying to clipboard
This commit is contained in:
parent
0a3d9dfdc1
commit
4259786326
337
Cargo.lock
generated
337
Cargo.lock
generated
|
@ -40,6 +40,12 @@ version = "1.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "0.2.17"
|
||||
|
@ -61,12 +67,28 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clipboard-win"
|
||||
version = "3.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fdf5e01086b6be750428ba4a40619f847eb2e95756eee84b18e06e5f0b50342"
|
||||
dependencies = [
|
||||
"lazy-bytes-cast",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "2.0.0"
|
||||
|
@ -78,6 +100,32 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "copypasta"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4423d79fed83ebd9ab81ec21fa97144300a961782158287dc9bf7eddac37ff0b"
|
||||
dependencies = [
|
||||
"clipboard-win",
|
||||
"objc",
|
||||
"objc-foundation",
|
||||
"objc_id",
|
||||
"smithay-clipboard",
|
||||
"x11-clipboard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "copypasta-ext"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc2f548212db51db2dba038e6e86c98a5d4a8ab0767ab230673a28be89a45b87"
|
||||
dependencies = [
|
||||
"copypasta",
|
||||
"libc",
|
||||
"which",
|
||||
"x11-clipboard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.0"
|
||||
|
@ -152,6 +200,21 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dlib"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794"
|
||||
dependencies = [
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
|
@ -253,6 +316,12 @@ version = "0.4.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "lazy-bytes-cast"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10257499f089cd156ad82d0a9cd57d9501fa2c989068992a97eb3c27836f206b"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -265,6 +334,16 @@ version = "0.2.103"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
|
@ -274,12 +353,30 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b6c2ebff6180198788f5db08d7ce3bc1d0b617176678831a7510825973e357"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.4"
|
||||
|
@ -289,6 +386,12 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.4"
|
||||
|
@ -299,6 +402,30 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1e25ee6b412c2a1e3fcb6a4499a5c1bfe7f43e014bdce9a6b6666e5aa2d187"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
|
@ -315,12 +442,47 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
||||
|
||||
[[package]]
|
||||
name = "objc"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
|
||||
dependencies = [
|
||||
"malloc_buf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc-foundation"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
||||
dependencies = [
|
||||
"block",
|
||||
"objc",
|
||||
"objc_id",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc_id"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
||||
dependencies = [
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.29"
|
||||
|
@ -330,6 +492,15 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
|
@ -424,6 +595,12 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
|
@ -461,6 +638,40 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||
|
||||
[[package]]
|
||||
name = "smithay-client-toolkit"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1325f292209cee78d5035530932422a30aa4c8fda1a16593ac083c1de211e68a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"dlib",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"memmap2",
|
||||
"nix",
|
||||
"pkg-config",
|
||||
"wayland-client",
|
||||
"wayland-cursor",
|
||||
"wayland-protocols",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smithay-clipboard"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "610b551bd25378bfd2b8e7a0fcbd83d427e8f2f6a40c47ae0f70688e9949dd55"
|
||||
dependencies = [
|
||||
"smithay-client-toolkit",
|
||||
"wayland-client",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.78"
|
||||
|
@ -523,6 +734,7 @@ dependencies = [
|
|||
name = "systeroid-tui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"copypasta-ext",
|
||||
"getopts",
|
||||
"systeroid-core",
|
||||
"termion",
|
||||
|
@ -603,6 +815,12 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.2"
|
||||
|
@ -620,6 +838,90 @@ version = "0.10.2+wasi-snapshot-preview1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
|
||||
[[package]]
|
||||
name = "wayland-client"
|
||||
version = "0.29.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91223460e73257f697d9e23d401279123d36039a3f7a449e983f123292d4458f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"downcast-rs",
|
||||
"libc",
|
||||
"nix",
|
||||
"scoped-tls",
|
||||
"wayland-commons",
|
||||
"wayland-scanner",
|
||||
"wayland-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-commons"
|
||||
version = "0.29.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94f6e5e340d7c13490eca867898c4cec5af56c27a5ffe5c80c6fc4708e22d33e"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"once_cell",
|
||||
"smallvec",
|
||||
"wayland-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-cursor"
|
||||
version = "0.29.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c52758f13d5e7861fc83d942d3d99bf270c83269575e52ac29e5b73cb956a6bd"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"wayland-client",
|
||||
"xcursor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-protocols"
|
||||
version = "0.29.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wayland-client",
|
||||
"wayland-commons",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-scanner"
|
||||
version = "0.29.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39a1ed3143f7a143187156a2ab52742e89dac33245ba505c17224df48939f9e0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-sys"
|
||||
version = "0.29.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9341df79a8975679188e37dab3889bfa57c44ac2cb6da166f519a81cbe452d4"
|
||||
dependencies = [
|
||||
"dlib",
|
||||
"lazy_static",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9"
|
||||
dependencies = [
|
||||
"either",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
@ -650,3 +952,38 @@ name = "winapi-x86_64-pc-windows-gnu"
|
|||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "x11-clipboard"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "473068b7b80ac86a18328824f1054e5e007898c47b5bbc281bd7abe32bc3653c"
|
||||
dependencies = [
|
||||
"xcb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xcb"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "771e2b996df720cd1c6dd9ff90f62d91698fd3610cc078388d0564bdd6622a9c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"quick-xml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xcursor"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
|
||||
|
|
|
@ -9,6 +9,7 @@ termion = "1.5.6"
|
|||
unicode-width = "0.1.9"
|
||||
thiserror = "1.0.30"
|
||||
getopts = "0.2.21"
|
||||
copypasta-ext = "0.3.7"
|
||||
|
||||
[dependencies.systeroid-core]
|
||||
version = "0.1.0"
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use crate::command::Command;
|
||||
use crate::error::Result;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::options::CopyOption;
|
||||
use crate::widgets::StatefulTable;
|
||||
use copypasta_ext::prelude::ClipboardProvider;
|
||||
use std::str::FromStr;
|
||||
use std::time::Instant;
|
||||
use systeroid_core::sysctl::controller::Sysctl;
|
||||
|
@ -10,7 +12,6 @@ use systeroid_core::sysctl::parameter::Parameter;
|
|||
const MESSAGE_DURATION: u128 = 1750;
|
||||
|
||||
/// Application controller.
|
||||
#[derive(Debug)]
|
||||
pub struct App<'a> {
|
||||
/// Whether if the application is running.
|
||||
pub running: bool,
|
||||
|
@ -20,21 +21,27 @@ pub struct App<'a> {
|
|||
pub input_time: Option<Instant>,
|
||||
/// Whether if the search mode is enabled.
|
||||
pub search_mode: bool,
|
||||
/// Entries of the options menu.
|
||||
pub options: Option<StatefulTable<&'a str>>,
|
||||
/// List of sysctl parameters.
|
||||
pub parameter_list: StatefulTable<Parameter>,
|
||||
/// Clipboard context.
|
||||
clipboard: Option<Box<dyn ClipboardProvider>>,
|
||||
/// Sysctl controller.
|
||||
sysctl: &'a mut Sysctl,
|
||||
}
|
||||
|
||||
impl<'a> App<'a> {
|
||||
/// Constructs a new instance.
|
||||
pub fn new(sysctl: &'a mut Sysctl) -> Self {
|
||||
pub fn new(sysctl: &'a mut Sysctl, clipboard: Option<Box<dyn ClipboardProvider>>) -> Self {
|
||||
Self {
|
||||
running: true,
|
||||
input: None,
|
||||
input_time: None,
|
||||
search_mode: false,
|
||||
options: None,
|
||||
parameter_list: StatefulTable::with_items(sysctl.parameters.clone()),
|
||||
clipboard,
|
||||
sysctl,
|
||||
}
|
||||
}
|
||||
|
@ -64,14 +71,56 @@ impl<'a> App<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Copies the selected entry to the clipboard.
|
||||
fn copy_to_clipboard(&mut self, copy_option: CopyOption) -> Result<()> {
|
||||
self.input = Some(if let Some(clipboard) = self.clipboard.as_mut() {
|
||||
if let Some(parameter) = self.parameter_list.selected() {
|
||||
match copy_option {
|
||||
CopyOption::Name => clipboard.set_contents(parameter.name.clone()),
|
||||
CopyOption::Value => clipboard.set_contents(parameter.value.clone()),
|
||||
CopyOption::Documentation => {
|
||||
clipboard.set_contents(parameter.get_documentation().unwrap_or_default())
|
||||
}
|
||||
}
|
||||
.map_err(|e| Error::ClipboardError(e.to_string()))?;
|
||||
String::from("Copied to clipboard!")
|
||||
} else {
|
||||
String::from("No parameter is selected")
|
||||
}
|
||||
} else {
|
||||
String::from("Clipboard is not initialized")
|
||||
});
|
||||
self.input_time = Some(Instant::now());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Runs the given command and updates the application.
|
||||
pub fn run_command(&mut self, command: Command) -> Result<()> {
|
||||
match command {
|
||||
Command::Select => {
|
||||
if let Some(copy_option) = self
|
||||
.options
|
||||
.as_ref()
|
||||
.and_then(|v| v.selected())
|
||||
.and_then(|v| CopyOption::try_from(*v).ok())
|
||||
{
|
||||
self.copy_to_clipboard(copy_option)?;
|
||||
}
|
||||
self.options = None;
|
||||
}
|
||||
Command::ScrollUp => {
|
||||
self.parameter_list.previous();
|
||||
if let Some(options) = self.options.as_mut() {
|
||||
options.previous();
|
||||
} else {
|
||||
self.parameter_list.previous();
|
||||
}
|
||||
}
|
||||
Command::ScrollDown => {
|
||||
self.parameter_list.next();
|
||||
if let Some(options) = self.options.as_mut() {
|
||||
options.next();
|
||||
} else {
|
||||
self.parameter_list.next();
|
||||
}
|
||||
}
|
||||
Command::EnableSearch => {
|
||||
if self.input_time.is_some() {
|
||||
|
@ -129,6 +178,25 @@ impl<'a> App<'a> {
|
|||
self.search();
|
||||
}
|
||||
}
|
||||
Command::Copy => {
|
||||
if self.parameter_list.selected().is_some() {
|
||||
let mut copy_options = CopyOption::variants().to_vec();
|
||||
if self
|
||||
.parameter_list
|
||||
.selected()
|
||||
.and_then(|parameter| parameter.get_documentation())
|
||||
.is_none()
|
||||
{
|
||||
copy_options.retain(|v| v != &CopyOption::Documentation)
|
||||
}
|
||||
self.options = Some(StatefulTable::with_items(
|
||||
copy_options.iter().map(|v| v.as_str()).collect(),
|
||||
));
|
||||
} else {
|
||||
self.input = Some(String::from("No parameter is selected"));
|
||||
self.input_time = Some(Instant::now());
|
||||
}
|
||||
}
|
||||
Command::Refresh => {
|
||||
self.input = None;
|
||||
let parameters = Sysctl::init(self.sysctl.config.clone())?.parameters;
|
||||
|
@ -142,7 +210,11 @@ impl<'a> App<'a> {
|
|||
self.parameter_list = StatefulTable::with_items(self.sysctl.parameters.clone());
|
||||
}
|
||||
Command::Exit => {
|
||||
self.running = false;
|
||||
if self.options.is_some() {
|
||||
self.options = None;
|
||||
} else {
|
||||
self.running = false;
|
||||
}
|
||||
}
|
||||
Command::None => {}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ use termion::event::Key;
|
|||
/// Possible application commands.
|
||||
#[derive(Debug)]
|
||||
pub enum Command {
|
||||
/// Perform an action based on the selected entry.
|
||||
Select,
|
||||
/// Scroll up on the widget.
|
||||
ScrollUp,
|
||||
/// Scroll down on the widget.
|
||||
|
@ -16,6 +18,8 @@ pub enum Command {
|
|||
UpdateInput(char),
|
||||
/// Clear the input buffer.
|
||||
ClearInput(bool),
|
||||
/// Copy selected value to clipboard.
|
||||
Copy,
|
||||
/// Refresh the application.
|
||||
Refresh,
|
||||
/// Exit the application.
|
||||
|
@ -31,6 +35,7 @@ impl FromStr for Command {
|
|||
"search" => Ok(Command::EnableSearch),
|
||||
"up" => Ok(Command::ScrollUp),
|
||||
"down" => Ok(Command::ScrollDown),
|
||||
"copy" => Ok(Command::Copy),
|
||||
"refresh" => Ok(Command::Refresh),
|
||||
"exit" | "quit" | "q" | "q!" => Ok(Command::Exit),
|
||||
_ => Err(()),
|
||||
|
@ -55,6 +60,8 @@ impl Command {
|
|||
Key::Down => Command::ScrollDown,
|
||||
Key::Char(':') => Command::UpdateInput(' '),
|
||||
Key::Char('/') => Command::EnableSearch,
|
||||
Key::Char('\n') => Command::Select,
|
||||
Key::Char('c') => Command::Copy,
|
||||
Key::Char('r') => Command::Refresh,
|
||||
Key::Esc => Command::Exit,
|
||||
_ => Command::None,
|
||||
|
|
|
@ -8,7 +8,10 @@ pub enum Error {
|
|||
IoError(#[from] std::io::Error),
|
||||
/// Error that may occur while receiving messages from the channel.
|
||||
#[error("Channel receive error: `{0}`")]
|
||||
ReceiveError(#[from] std::sync::mpsc::RecvError),
|
||||
ChannelReceiveError(#[from] std::sync::mpsc::RecvError),
|
||||
/// Error that may occur while getting/setting the contents of the clipboard.
|
||||
#[error("Clipboard error: `{0}`")]
|
||||
ClipboardError(String),
|
||||
/// Error that may occur in the core library.
|
||||
#[error("{0}")]
|
||||
SysctlError(#[from] systeroid_core::error::Error),
|
||||
|
|
|
@ -12,6 +12,8 @@ pub mod command;
|
|||
pub mod error;
|
||||
/// Event handling.
|
||||
pub mod event;
|
||||
/// Application options.
|
||||
pub mod options;
|
||||
/// User interface renderer.
|
||||
pub mod ui;
|
||||
/// Custom widgets.
|
||||
|
@ -22,6 +24,7 @@ use crate::args::Args;
|
|||
use crate::command::Command;
|
||||
use crate::error::Result;
|
||||
use crate::event::{Event, EventHandler};
|
||||
use copypasta_ext::display::DisplayServer;
|
||||
use std::io::Write;
|
||||
use systeroid_core::cache::Cache;
|
||||
use systeroid_core::config::Config;
|
||||
|
@ -42,9 +45,16 @@ pub fn run<Output: Write>(args: Args, output: Output) -> Result<()> {
|
|||
terminal.hide_cursor()?;
|
||||
terminal.clear()?;
|
||||
let event_handler = EventHandler::new(args.tick_rate);
|
||||
let clipboard = match DisplayServer::select().try_context() {
|
||||
None => {
|
||||
eprintln!("failed to initialize clipboard, no suitable clipboard provider found");
|
||||
None
|
||||
}
|
||||
clipboard => clipboard,
|
||||
};
|
||||
let mut sysctl = Sysctl::init(Config::default())?;
|
||||
sysctl.update_docs_from_cache(args.kernel_docs.as_ref(), &Cache::init()?)?;
|
||||
let mut app = App::new(&mut sysctl);
|
||||
let mut app = App::new(&mut sysctl, clipboard);
|
||||
while app.running {
|
||||
terminal.draw(|frame| ui::render(frame, &mut app))?;
|
||||
match event_handler.next()? {
|
||||
|
|
39
systeroid-tui/src/options.rs
Normal file
39
systeroid-tui/src/options.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
use std::convert::TryFrom;
|
||||
|
||||
/// Available copying options.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum CopyOption {
|
||||
/// Copy the name of the parameter.
|
||||
Name,
|
||||
/// Copy the value of the parameter.
|
||||
Value,
|
||||
/// Copy the documentation of the parameter.
|
||||
Documentation,
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for CopyOption {
|
||||
type Error = ();
|
||||
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
||||
Self::variants()
|
||||
.iter()
|
||||
.find(|v| value == v.as_str())
|
||||
.copied()
|
||||
.ok_or(())
|
||||
}
|
||||
}
|
||||
|
||||
impl CopyOption {
|
||||
/// Returns the string representation of the option.
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Name => "Parameter name",
|
||||
Self::Value => "Parameter value",
|
||||
Self::Documentation => "Documentation",
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the variants.
|
||||
pub fn variants() -> &'static [Self] {
|
||||
&[Self::Name, Self::Value, Self::Documentation]
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
use crate::app::App;
|
||||
use crate::widgets::StatefulTable;
|
||||
use tui::backend::Backend;
|
||||
use tui::layout::{Alignment, Constraint, Direction, Layout, Rect};
|
||||
use tui::style::{Color, Style};
|
||||
|
@ -100,6 +101,9 @@ fn render_parameter_list<B: Backend>(frame: &mut Frame<'_, B>, rect: Rect, app:
|
|||
app.parameter_list.items.len()
|
||||
),
|
||||
);
|
||||
if let Some(options) = app.options.as_mut() {
|
||||
render_options_menu(frame, rect, options);
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders the text for displaying the selected index.
|
||||
|
@ -150,6 +154,68 @@ fn render_selection_text<B: Backend>(frame: &mut Frame<'_, B>, rect: Rect, selec
|
|||
}
|
||||
}
|
||||
|
||||
/// Renders a list as a popup for showing options.
|
||||
fn render_options_menu<B: Backend>(
|
||||
frame: &mut Frame<'_, B>,
|
||||
rect: Rect,
|
||||
options: &mut StatefulTable<&str>,
|
||||
) {
|
||||
let (length_x, length_y) = (
|
||||
25,
|
||||
u16::try_from(options.items.len()).unwrap_or_default() + 2,
|
||||
);
|
||||
let popup_layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Length((rect.height.checked_sub(length_y)).unwrap_or_default() / 2),
|
||||
Constraint::Min(length_y),
|
||||
Constraint::Length((rect.height.checked_sub(length_y)).unwrap_or_default() / 2),
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
.split(rect);
|
||||
let rect = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Length(
|
||||
(popup_layout[1].width.checked_sub(length_x)).unwrap_or_default() / 2,
|
||||
),
|
||||
Constraint::Min(length_x),
|
||||
Constraint::Length(
|
||||
(popup_layout[1].width.checked_sub(length_x)).unwrap_or_default() / 2,
|
||||
),
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
.split(popup_layout[1])[1];
|
||||
frame.render_widget(Clear, rect);
|
||||
frame.render_stateful_widget(
|
||||
Table::new(options.items.iter().map(|item| {
|
||||
Row::new(vec![Cell::from(item.to_string())])
|
||||
.height(1)
|
||||
.bottom_margin(0)
|
||||
}))
|
||||
.block(
|
||||
Block::default()
|
||||
.title(Span::styled(
|
||||
"Copy to clipboard",
|
||||
Style::default().fg(Color::White),
|
||||
))
|
||||
.title_alignment(Alignment::Center)
|
||||
.borders(Borders::all())
|
||||
.border_style(Style::default().fg(Color::White))
|
||||
.border_type(BorderType::Rounded)
|
||||
.style(Style::default().bg(Color::Black)),
|
||||
)
|
||||
.highlight_style(Style::default().bg(Color::White).fg(Color::Black))
|
||||
.widths(&[Constraint::Percentage(100)]),
|
||||
rect,
|
||||
&mut options.state,
|
||||
);
|
||||
}
|
||||
|
||||
/// Renders the documentation of the selected sysctl parameter.
|
||||
fn render_parameter_documentation<B: Backend>(
|
||||
frame: &mut Frame<'_, B>,
|
||||
|
|
Loading…
Reference in a new issue