Implement TableValue component (#17)

* use table value component

* add todo

* add linux target_os

* add default features for copypasta

* fix clippy warnings

* update gobang.gif
pull/19/head
Takayuki Maeda 3 years ago committed by GitHub
parent 0be60b5039
commit 0ebb39f3cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

267
Cargo.lock generated

@ -89,6 +89,12 @@ dependencies = [
"wyz",
]
[[package]]
name = "block"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "block-buffer"
version = "0.9.0"
@ -181,6 +187,30 @@ dependencies = [
"winapi 0.3.9",
]
[[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 0.3.9",
]
[[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 = "cpufeatures"
version = "0.1.5"
@ -298,12 +328,27 @@ dependencies = [
"generic-array",
]
[[package]]
name = "dlib"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794"
dependencies = [
"libloading",
]
[[package]]
name = "dotenv"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]]
name = "downcast-rs"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]]
name = "easy-cast"
version = "0.4.4"
@ -486,6 +531,7 @@ version = "0.1.0-alpha.0"
dependencies = [
"anyhow",
"chrono",
"copypasta",
"crossterm 0.19.0",
"database-tree",
"easy-cast",
@ -598,6 +644,12 @@ dependencies = [
"winapi-build",
]
[[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"
@ -626,6 +678,16 @@ version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
[[package]]
name = "libloading"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a"
dependencies = [
"cfg-if 1.0.0",
"winapi 0.3.9",
]
[[package]]
name = "libm"
version = "0.2.1"
@ -650,6 +712,15 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
dependencies = [
"libc",
]
[[package]]
name = "maplit"
version = "1.0.2"
@ -668,6 +739,15 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "memmap2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4"
dependencies = [
"libc",
]
[[package]]
name = "mio"
version = "0.6.23"
@ -755,6 +835,18 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "nix"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a"
dependencies = [
"bitflags",
"cc",
"cfg-if 1.0.0",
"libc",
]
[[package]]
name = "nom"
version = "6.1.2"
@ -858,6 +950,35 @@ dependencies = [
"libc",
]
[[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"
@ -939,6 +1060,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
[[package]]
name = "ppv-lite86"
version = "0.2.10"
@ -1104,6 +1231,12 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[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"
@ -1239,6 +1372,33 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "smithay-client-toolkit"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec783683499a2cfc85b6df3d04f83b1907b5cbd98a1aed44667dbdf1eac4e64c"
dependencies = [
"bitflags",
"dlib",
"lazy_static",
"log",
"memmap2",
"nix",
"wayland-client",
"wayland-cursor",
"wayland-protocols",
]
[[package]]
name = "smithay-clipboard"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "986c5b4a7bd4f50d4c51f81f844745535cb488360f9cf63293780b109b9295f3"
dependencies = [
"smithay-client-toolkit",
"wayland-client",
]
[[package]]
name = "spin"
version = "0.5.2"
@ -1676,6 +1836,79 @@ version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
[[package]]
name = "wayland-client"
version = "0.28.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ab332350e502f159382201394a78e3cc12d0f04db863429260164ea40e0355"
dependencies = [
"bitflags",
"downcast-rs",
"libc",
"nix",
"scoped-tls",
"wayland-commons",
"wayland-scanner",
"wayland-sys",
]
[[package]]
name = "wayland-commons"
version = "0.28.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a21817947c7011bbd0a27e11b17b337bfd022e8544b071a2641232047966fbda"
dependencies = [
"nix",
"once_cell",
"smallvec",
"wayland-sys",
]
[[package]]
name = "wayland-cursor"
version = "0.28.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be610084edd1586d45e7bdd275fe345c7c1873598caa464c4fb835dee70fa65a"
dependencies = [
"nix",
"wayland-client",
"xcursor",
]
[[package]]
name = "wayland-protocols"
version = "0.28.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "286620ea4d803bacf61fa087a4242ee316693099ee5a140796aaba02b29f861f"
dependencies = [
"bitflags",
"wayland-client",
"wayland-commons",
"wayland-scanner",
]
[[package]]
name = "wayland-scanner"
version = "0.28.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce923eb2deb61de332d1f356ec7b6bf37094dc5573952e1c8936db03b54c03f1"
dependencies = [
"proc-macro2",
"quote",
"xml-rs",
]
[[package]]
name = "wayland-sys"
version = "0.28.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d841fca9aed7febf9bed2e9796c49bf58d4152ceda8ac949ebe00868d8f0feb8"
dependencies = [
"dlib",
"lazy_static",
"pkg-config",
]
[[package]]
name = "web-sys"
version = "0.3.51"
@ -1765,6 +1998,40 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
[[package]]
name = "x11-clipboard"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b397ace6e980510de59a4fe3d4c758dffab231d6d747ce9fa1aba6b6035d5f32"
dependencies = [
"xcb",
]
[[package]]
name = "xcb"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62056f63138b39116f82a540c983cc11f1c90cd70b3d492a70c25eaa50bd22a6"
dependencies = [
"libc",
"log",
]
[[package]]
name = "xcursor"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a9a231574ae78801646617cefd13bfe94be907c0e4fa979cfd8b770aa3c5d08"
dependencies = [
"nom",
]
[[package]]
name = "xml-rs"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"
[[package]]
name = "zeroize"
version = "1.3.0"

@ -26,6 +26,7 @@ strum = "0.21"
strum_macros = "0.21"
database-tree = { path = "./database-tree", version = "0.1" }
easy-cast = "0.4"
copypasta = { version = "0.7.0" }
[workspace]
members=[

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 MiB

After

Width:  |  Height:  |  Size: 4.1 MiB

@ -1,3 +1,4 @@
use crate::clipboard::Clipboard;
use crate::components::DrawableComponent as _;
use crate::{
components::tab::Tab,
@ -33,6 +34,7 @@ pub struct App {
pub databases: DatabasesComponent,
pub connections: ConnectionsComponent,
pub table_status: TableStatusComponent,
pub clipboard: Clipboard,
pub pool: Option<MySqlPool>,
pub error: Option<String>,
}
@ -50,6 +52,7 @@ impl Default for App {
databases: DatabasesComponent::new(),
connections: ConnectionsComponent::default(),
table_status: TableStatusComponent::default(),
clipboard: Clipboard::new(),
pool: None,
error: None,
}

@ -0,0 +1,75 @@
#[cfg(any(test, not(any(target_os = "linux", target_os = "macos", windows))))]
use copypasta::nop_clipboard::NopClipboardContext;
#[cfg(target_os = "linux")]
use copypasta::x11_clipboard::{Primary as X11SelectionClipboard, X11ClipboardContext};
#[cfg(any(target_os = "linux", target_os = "macos", windows))]
use copypasta::ClipboardContext;
use copypasta::ClipboardProvider;
pub struct Clipboard {
clipboard: Box<dyn ClipboardProvider>,
selection: Option<Box<dyn ClipboardProvider>>,
}
impl Clipboard {
#[cfg(any(target_os = "linux", target_os = "macos", windows))]
pub fn new() -> Self {
Self::default()
}
#[cfg(any(test, not(any(target_os = "linux", target_os = "macos", windows))))]
pub fn new_nop() -> Self {
Self {
clipboard: Box::new(NopClipboardContext::new().unwrap()),
selection: None,
}
}
}
impl Default for Clipboard {
fn default() -> Self {
#[cfg(any(target_os = "macos", windows))]
return Self {
clipboard: Box::new(ClipboardContext::new().unwrap()),
selection: None,
};
#[cfg(target_os = "linux")]
return Self {
clipboard: Box::new(ClipboardContext::new().unwrap()),
selection: Some(Box::new(
X11ClipboardContext::<X11SelectionClipboard>::new().unwrap(),
)),
};
#[cfg(not(any(target_os = "linux", target_os = "macos", windows)))]
return Self::new_nop();
}
}
impl Clipboard {
pub fn store(&mut self, text: impl Into<String>) {
let clipboard = match &mut self.selection {
Some(provider) => provider,
None => &mut self.clipboard,
};
clipboard.set_contents(text.into()).unwrap_or_else(|err| {
panic!("Unable to store text in clipboard: {}", err);
});
}
pub fn _load(&mut self) -> String {
let clipboard = match &mut self.selection {
Some(provider) => provider,
None => &mut self.clipboard,
};
match clipboard.get_contents() {
Err(err) => {
panic!("Unable to load text from clipboard: {}", err);
}
Ok(text) => text,
}
}
}

@ -5,6 +5,7 @@ pub mod query;
pub mod tab;
pub mod table;
pub mod table_status;
pub mod table_value;
pub mod utils;
pub use command::{CommandInfo, CommandText};
@ -14,6 +15,7 @@ pub use query::QueryComponent;
pub use tab::TabComponent;
pub use table::TableComponent;
pub use table_status::TableStatusComponent;
pub use table_value::TableValueComponent;
use anyhow::Result;
use tui::{backend::Backend, layout::Rect, Frame};

@ -1,10 +1,12 @@
use super::{utils::scroll_vertical::VerticalScroll, Component, DrawableComponent};
use super::{
utils::scroll_vertical::VerticalScroll, Component, DrawableComponent, TableValueComponent,
};
use crate::event::Key;
use anyhow::Result;
use std::convert::From;
use tui::{
backend::Backend,
layout::{Constraint, Rect},
layout::{Constraint, Direction, Layout, Rect},
style::{Color, Style},
widgets::{Block, Borders, Cell, Row, Table, TableState},
Frame,
@ -95,7 +97,7 @@ impl TableComponent {
if self.rows.is_empty() {
return;
}
if self.column_index == self.headers.len() - 1 {
if self.column_index == self.headers.len() {
return;
}
if self.column_index == 9 {
@ -130,6 +132,20 @@ impl TableComponent {
}
}
pub fn is_selected_cell(&self, row_index: usize, column_index: usize) -> bool {
if column_index != self.column_index {
return false;
}
matches!(self.state.selected(), Some(selected_row_index) if row_index == selected_row_index)
}
pub fn selected_cell(&self) -> Option<String> {
self.rows
.get(self.state.selected()?)?
.get(self.column_index.saturating_sub(1) + self.column_page)
.map(|cell| cell.to_string())
}
pub fn headers(&self) -> Vec<String> {
let mut headers = self.headers[self.column_page..].to_vec();
headers.insert(0, "".to_string());
@ -161,6 +177,11 @@ impl TableComponent {
impl DrawableComponent for TableComponent {
fn draw<B: Backend>(&mut self, f: &mut Frame<B>, area: Rect, focused: bool) -> Result<()> {
let layout = Layout::default()
.direction(Direction::Vertical)
.constraints(vec![Constraint::Length(3), Constraint::Length(5)])
.split(area);
self.state.selected().map_or_else(
|| {
self.scroll.reset();
@ -169,11 +190,14 @@ impl DrawableComponent for TableComponent {
self.scroll.update(
selection,
self.rows.len(),
area.height.saturating_sub(2) as usize,
layout[1].height.saturating_sub(2) as usize,
);
},
);
TableValueComponent::new(self.selected_cell().unwrap_or_default())
.draw(f, layout[0], focused)?;
let headers = self.headers();
let header_cells = headers
.iter()
@ -187,18 +211,9 @@ impl DrawableComponent for TableComponent {
.max()
.unwrap_or(0)
+ 1;
let cells = item.iter().enumerate().map(|(column_page, c)| {
Cell::from(c.to_string()).style(if column_page == self.column_index {
match self.state.selected() {
Some(selected_row) => {
if row_index == selected_row {
Style::default().bg(Color::Blue)
} else {
Style::default()
}
}
None => Style::default(),
}
let cells = item.iter().enumerate().map(|(column_index, c)| {
Cell::from(c.to_string()).style(if self.is_selected_cell(row_index, column_index) {
Style::default().bg(Color::Blue)
} else {
Style::default()
})
@ -208,7 +223,7 @@ impl DrawableComponent for TableComponent {
let widths = (0..10)
.map(|_| Constraint::Percentage(10))
.collect::<Vec<Constraint>>();
let t = Table::new(rows)
let table = Table::new(rows)
.header(header)
.block(Block::default().borders(Borders::ALL).title("Records"))
.highlight_style(if self.select_entire_row {
@ -222,9 +237,9 @@ impl DrawableComponent for TableComponent {
Style::default().fg(Color::DarkGray)
})
.widths(&widths);
f.render_stateful_widget(t, area, &mut self.state);
f.render_stateful_widget(table, layout[1], &mut self.state);
self.scroll.draw(f, area);
self.scroll.draw(f, layout[1]);
Ok(())
}
}

@ -0,0 +1,51 @@
use super::{Component, DrawableComponent};
use crate::event::Key;
use anyhow::Result;
use tui::{
backend::Backend,
layout::{Alignment, Rect},
style::{Color, Modifier, Style},
text::Span,
widgets::{Block, Borders, Paragraph, Wrap},
Frame,
};
pub struct TableValueComponent {
pub value: String,
}
impl TableValueComponent {
pub fn new(value: String) -> Self {
Self { value }
}
}
impl DrawableComponent for TableValueComponent {
fn draw<B: Backend>(&mut self, f: &mut Frame<B>, area: Rect, focused: bool) -> Result<()> {
let paragraph = Paragraph::new(self.value.clone())
.block(
Block::default()
.borders(Borders::ALL)
.style(Style::default())
.title(Span::styled(
"Value",
Style::default().add_modifier(Modifier::BOLD),
)),
)
.style(if focused {
Style::default()
} else {
Style::default().fg(Color::DarkGray)
})
.alignment(Alignment::Left)
.wrap(Wrap { trim: true });
f.render_widget(paragraph, area);
Ok(())
}
}
impl Component for TableValueComponent {
fn event(&mut self, _key: Key) -> Result<()> {
todo!("scroll");
}
}

@ -6,6 +6,11 @@ pub async fn handler(key: Key, app: &mut App) -> anyhow::Result<()> {
match key {
Key::Left => app.focus_block = FocusBlock::DabataseList,
Key::Char('c') => app.focus_block = FocusBlock::ConnectionList,
Key::Char('y') => {
if let Some(text) = app.record_table.selected_cell() {
app.clipboard.store(text)
}
}
key => app.record_table.event(key)?,
}
Ok(())

@ -6,6 +6,11 @@ pub async fn handler(key: Key, app: &mut App) -> anyhow::Result<()> {
match key {
Key::Left => app.focus_block = FocusBlock::DabataseList,
Key::Char('c') => app.focus_block = FocusBlock::ConnectionList,
Key::Char('y') => {
if let Some(text) = app.structure_table.selected_cell() {
app.clipboard.store(text)
}
}
key => app.structure_table.event(key)?,
}
Ok(())

@ -1,4 +1,5 @@
mod app;
mod clipboard;
mod components;
mod event;
mod handlers;
@ -33,7 +34,6 @@ async fn main() -> anyhow::Result<()> {
let stdout = stdout();
setup_terminal()?;
set_panic_handlers()?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;

Loading…
Cancel
Save