feat(tui): support copying to clipboard

This commit is contained in:
Orhun Parmaksız 2022-01-15 02:30:34 +03:00
parent 0a3d9dfdc1
commit 4259786326
No known key found for this signature in database
GPG key ID: F83424824B3E4B90
8 changed files with 543 additions and 8 deletions

337
Cargo.lock generated
View file

@ -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"

View file

@ -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"

View file

@ -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 => {}
}

View file

@ -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,

View file

@ -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),

View file

@ -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()? {

View 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]
}
}

View file

@ -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>,