added clicking (working!)
This commit is contained in:
parent
1960123e3f
commit
9471d47ade
|
@ -8,12 +8,39 @@ version = "1.0.68"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kkdisp"
|
||||
version = "0.1.0"
|
||||
|
@ -29,6 +56,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"kkdisp",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -37,12 +65,88 @@ version = "0.2.139"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "numtoa"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.50"
|
||||
|
@ -79,6 +183,12 @@ dependencies = [
|
|||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.152"
|
||||
|
@ -99,6 +209,31 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.107"
|
||||
|
@ -122,8 +257,124 @@ dependencies = [
|
|||
"redox_termios",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
"libc",
|
||||
"memchr",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
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 = "windows-sys"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
||||
|
|
|
@ -9,6 +9,7 @@ use std::io::{Stdout, Write};
|
|||
#[derive(Eq, Clone, Debug)]
|
||||
pub enum Component {
|
||||
NextLine,
|
||||
Link(String, usize),
|
||||
X(usize),
|
||||
String(String),
|
||||
Fg(Color),
|
||||
|
@ -27,46 +28,27 @@ impl Component {
|
|||
Component::Bg(c) => format!("BG({:#?})", c)
|
||||
.replace('\n', "")
|
||||
.replace(' ', ""),
|
||||
Component::Link(name, ln) => {
|
||||
format!("Clickable[{}:{}]", name, ln)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Cursed {
|
||||
fn scene(
|
||||
&mut self,
|
||||
comp: Vec<Component>,
|
||||
) -> Result<(), anyhow::Error>;
|
||||
pub struct LineArea {
|
||||
pos: (u16, u16),
|
||||
length: u16,
|
||||
}
|
||||
|
||||
impl Cursed for RawTerminal<Stdout> {
|
||||
fn scene(
|
||||
&mut self,
|
||||
comp: Vec<Component>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let mut line = 1;
|
||||
let screen_str = comp
|
||||
.into_iter()
|
||||
.map(|c| match c {
|
||||
Component::NextLine => {
|
||||
line += 1;
|
||||
String::from("\r\n")
|
||||
impl LineArea {
|
||||
pub fn new(pos: (u16, u16), length: u16) -> Self {
|
||||
Self { pos, length }
|
||||
}
|
||||
Component::X(x) => {
|
||||
termion::cursor::Goto((x + 1) as u16, line).into()
|
||||
}
|
||||
Component::String(s) => s,
|
||||
Component::Fg(c) => c.fg(),
|
||||
Component::Bg(c) => c.bg(),
|
||||
})
|
||||
.collect::<String>();
|
||||
write!(
|
||||
self,
|
||||
"{clear}{start}{scene}",
|
||||
clear = termion::clear::All,
|
||||
start = termion::cursor::Goto(1, 1),
|
||||
scene = screen_str,
|
||||
)?;
|
||||
Ok(())
|
||||
|
||||
pub fn matches(&self, pos: (u16, u16)) -> bool {
|
||||
self.pos.1 == pos.1
|
||||
&& pos.0 >= self.pos.0
|
||||
&& pos.0 <= (self.pos.0 + self.length - 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,6 +75,12 @@ impl PartialEq for Component {
|
|||
Self::NextLine => true,
|
||||
_ => false,
|
||||
},
|
||||
Self::Link(name, length) => match other {
|
||||
Self::Link(other_name, other_length) => {
|
||||
name == other_name && length == other_length
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,200 @@
|
|||
use crate::component::Cursed;
|
||||
use component::{Plan, Widget};
|
||||
use component::{Component, LineArea, Plan, Widget};
|
||||
use std::{
|
||||
io::{Stdout, Write},
|
||||
time::Duration,
|
||||
};
|
||||
use termion::raw::{IntoRawMode, RawTerminal};
|
||||
use termion::{
|
||||
clear, cursor,
|
||||
input::{MouseTerminal, TermRead},
|
||||
raw::{IntoRawMode, RawTerminal},
|
||||
screen::{AlternateScreen, IntoAlternateScreen},
|
||||
AsyncReader,
|
||||
};
|
||||
use theme::{Color, ColorSet};
|
||||
use token::Token;
|
||||
use view::Event;
|
||||
|
||||
type Result<T> = std::result::Result<T, anyhow::Error>;
|
||||
type Screen = MouseTerminal<RawTerminal<AlternateScreen<Stdout>>>;
|
||||
|
||||
extern crate termion;
|
||||
mod component;
|
||||
mod theme;
|
||||
mod token;
|
||||
pub mod component;
|
||||
pub mod theme;
|
||||
pub mod token;
|
||||
pub mod view;
|
||||
|
||||
pub struct Display {
|
||||
// needs to hold the termion display
|
||||
screen: RawTerminal<Stdout>,
|
||||
pub async fn run<V>(view: V) -> Result<()>
|
||||
where
|
||||
V: View,
|
||||
{
|
||||
let mut view = view;
|
||||
let mut screen: Screen = MouseTerminal::from(
|
||||
std::io::stdout().into_alternate_screen()?.into_raw_mode()?,
|
||||
);
|
||||
let mut events_iter = termion::async_stdin().events();
|
||||
let mut plans = view.init()?;
|
||||
let (term_w, term_h) = termion::terminal_size()?;
|
||||
let mut layers = make_layers(
|
||||
plans,
|
||||
ColorSet {
|
||||
fg: Color::WHITE,
|
||||
bg: Color::BLACK,
|
||||
},
|
||||
(term_w as usize, term_h as usize),
|
||||
);
|
||||
render_layers(&layers, &mut screen)?;
|
||||
screen.flush()?;
|
||||
loop {
|
||||
let event = match events_iter.next() {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
std::thread::sleep(Duration::from_millis(50));
|
||||
continue;
|
||||
}
|
||||
}?;
|
||||
|
||||
let event = match event {
|
||||
termion::event::Event::Mouse(mus) => match mus {
|
||||
termion::event::MouseEvent::Press(_, x, y) => {
|
||||
// TODO: scrolling later
|
||||
match match_click(&layers, (x, y)) {
|
||||
Some(yay) => Event::Link(yay),
|
||||
None => continue,
|
||||
}
|
||||
}
|
||||
_ => Event::Input(event),
|
||||
},
|
||||
_ => Event::Input(event),
|
||||
};
|
||||
|
||||
plans = view.update(event)?;
|
||||
let (term_w, term_h) = termion::terminal_size()?;
|
||||
layers = make_layers(
|
||||
plans,
|
||||
ColorSet {
|
||||
fg: Color::WHITE,
|
||||
bg: Color::BLACK,
|
||||
},
|
||||
(term_w as usize, term_h as usize),
|
||||
);
|
||||
write!(screen, "{}", clear::All)?;
|
||||
render_layers(&layers, &mut screen)?;
|
||||
screen.flush()?;
|
||||
}
|
||||
}
|
||||
|
||||
impl Display {
|
||||
pub fn new() -> Result<Self, anyhow::Error> {
|
||||
Ok(Self {
|
||||
screen: std::io::stdout().into_raw_mode()?,
|
||||
fn match_click(
|
||||
layers: &Vec<Layer>,
|
||||
click: (u16, u16),
|
||||
) -> Option<String> {
|
||||
for layer in layers.into_iter().rev() {
|
||||
for link in &layer.links {
|
||||
if link.1.matches(click) {
|
||||
return Some(link.0.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn make_layers(
|
||||
plans: PlanLayers,
|
||||
base_colorset: ColorSet,
|
||||
term_dimensions: (usize, usize),
|
||||
) -> Vec<Layer> {
|
||||
plans
|
||||
.into_iter()
|
||||
.map(|plan| Layer::make(plan, base_colorset, term_dimensions))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn render_layers(
|
||||
layered: &Vec<Layer>,
|
||||
scr: &mut Screen,
|
||||
) -> Result<()> {
|
||||
for layer in layered.into_iter().map(|layer| {
|
||||
let mut line = 1;
|
||||
(&layer.components)
|
||||
.into_iter()
|
||||
.map(|component| match component {
|
||||
Component::NextLine => {
|
||||
line += 1;
|
||||
"\n\r".into()
|
||||
}
|
||||
Component::Link(_, _) => panic!(
|
||||
"links should be filtered out at the layer"
|
||||
),
|
||||
Component::X(x) => {
|
||||
cursor::Goto((x + 1) as u16, line).into()
|
||||
}
|
||||
Component::String(s) => s.clone(),
|
||||
Component::Fg(c) => c.fg(),
|
||||
Component::Bg(c) => c.bg(),
|
||||
})
|
||||
.collect::<String>()
|
||||
}) {
|
||||
write!(scr, "{}", layer)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct Layer {
|
||||
links: Vec<(String, LineArea)>,
|
||||
components: Vec<Component>,
|
||||
}
|
||||
|
||||
impl Layer {
|
||||
pub fn make(
|
||||
plan: Plan,
|
||||
base_colorset: ColorSet,
|
||||
term_dimensions: (usize, usize),
|
||||
) -> Self {
|
||||
let mut line = 1;
|
||||
let mut line_offset = 1;
|
||||
let mut links = Vec::new();
|
||||
let components = plan
|
||||
.make(base_colorset, term_dimensions)
|
||||
.into_iter()
|
||||
.filter(|comp| match comp {
|
||||
Component::NextLine => {
|
||||
line += 1;
|
||||
line_offset = 1;
|
||||
true
|
||||
}
|
||||
Component::X(x) => {
|
||||
line_offset = (x + 1) as u16;
|
||||
true
|
||||
}
|
||||
Component::String(s) => {
|
||||
line_offset += s.len() as u16;
|
||||
true
|
||||
}
|
||||
Component::Link(name, length) => {
|
||||
links.push((
|
||||
name.clone(),
|
||||
LineArea::new(
|
||||
(line_offset, line),
|
||||
*length as u16,
|
||||
),
|
||||
));
|
||||
false
|
||||
}
|
||||
_ => true,
|
||||
})
|
||||
.collect();
|
||||
Self { links, components }
|
||||
}
|
||||
}
|
||||
// Simple type alias to be clear that the plans are going to
|
||||
// be layered on top of eachother
|
||||
pub type PlanLayers = Vec<Plan>;
|
||||
|
||||
pub trait View {
|
||||
fn init(
|
||||
&mut self,
|
||||
) -> std::result::Result<PlanLayers, anyhow::Error>;
|
||||
fn update(
|
||||
&mut self,
|
||||
event: Event,
|
||||
) -> std::result::Result<PlanLayers, anyhow::Error>;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ pub enum Token {
|
|||
CharPad(Box<Token>, char, usize),
|
||||
Fg(Box<Token>, Color),
|
||||
Bg(Box<Token>, Color),
|
||||
Link(Box<Token>, String),
|
||||
String(Box<Token>, String),
|
||||
End,
|
||||
}
|
||||
|
@ -55,6 +56,7 @@ impl Token {
|
|||
Token::String(t, s) => s.len() + t.str_len(),
|
||||
Token::Fg(t, _) => t.str_len(),
|
||||
Token::Bg(t, _) => t.str_len(),
|
||||
Token::Link(t, _) => t.str_len(),
|
||||
Token::Centered(t) => t.str_len(),
|
||||
Token::Limited(t, lim) => (*lim).min(t.str_len()),
|
||||
Token::CharPad(t, _, pad_to) => {
|
||||
|
@ -64,6 +66,13 @@ impl Token {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn link<S>(self, name: S) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
Self::Link(Box::new(self), name.into())
|
||||
}
|
||||
|
||||
pub fn pad_char(self, c: char, pad_to: usize) -> Self {
|
||||
Self::CharPad(Box::new(self), c, pad_to)
|
||||
}
|
||||
|
@ -82,6 +91,12 @@ impl Token {
|
|||
.into_iter()
|
||||
.chain(t.with_width(width))
|
||||
.collect(),
|
||||
Token::Link(t, name) => {
|
||||
vec![Component::Link(name, t.str_len())]
|
||||
.into_iter()
|
||||
.chain(t.with_width(width))
|
||||
.collect()
|
||||
}
|
||||
Token::Centered(cnt) => {
|
||||
let mut str_len = cnt.str_len();
|
||||
let components = if str_len > width {
|
||||
|
@ -234,6 +249,17 @@ mod tests {
|
|||
Component::String("end".into()),
|
||||
],
|
||||
),
|
||||
(
|
||||
"contains a link",
|
||||
Token::text("learn more")
|
||||
.centered()
|
||||
.link("string_link"),
|
||||
vec![
|
||||
Component::Link("string_link".into(), 10),
|
||||
Component::X((WIDTH - 10) / 2),
|
||||
Component::String("learn more".into()),
|
||||
],
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.for_each(|(name, token, expected)| {
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
use crate::{
|
||||
component::{Component, LineArea, Plan},
|
||||
theme::ColorSet,
|
||||
};
|
||||
|
||||
pub enum Event {
|
||||
Link(String),
|
||||
Input(termion::event::Event),
|
||||
}
|
|
@ -8,3 +8,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
anyhow = "1.0.68"
|
||||
kkdisp = { version = "0.1.0", path = "../kkdisp" }
|
||||
|
||||
[dependencies.tokio]
|
||||
version = "1.24.2"
|
||||
features = ["full"]
|
||||
|
|
|
@ -1,7 +1,78 @@
|
|||
use kkdisp::Display;
|
||||
use kkdisp::{
|
||||
component::{Plan, Widget},
|
||||
theme::Color,
|
||||
token::Token,
|
||||
view::Event,
|
||||
View,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
// let disp = Display::new();
|
||||
// let widget_idk = Widget::new()
|
||||
Display::test();
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
kkdisp::run(App::default()).await.unwrap()
|
||||
}
|
||||
|
||||
pub struct App {
|
||||
states: Vec<Plan>,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl Default for App {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
index: 0,
|
||||
states: vec![
|
||||
Plan::start().fill(vec![]).fixed(
|
||||
4,
|
||||
vec![Widget::new(
|
||||
kkdisp::component::SectionWidth::Full,
|
||||
vec![
|
||||
Token::End,
|
||||
Token::text("click me")
|
||||
.bg(Color::BLUE)
|
||||
.link("click"),
|
||||
],
|
||||
)],
|
||||
),
|
||||
Plan::start().fill(vec![]).fixed(
|
||||
4,
|
||||
vec![Widget::new(
|
||||
kkdisp::component::SectionWidth::Full,
|
||||
vec![
|
||||
Token::End,
|
||||
Token::text(
|
||||
"you did it! now undo it u fuck",
|
||||
)
|
||||
.bg(Color::RED)
|
||||
.link("click"),
|
||||
],
|
||||
)],
|
||||
),
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl View for App {
|
||||
fn init(
|
||||
&mut self,
|
||||
) -> std::result::Result<kkdisp::PlanLayers, anyhow::Error> {
|
||||
Ok(vec![self.states[self.index].clone()])
|
||||
}
|
||||
|
||||
fn update(
|
||||
&mut self,
|
||||
event: Event,
|
||||
) -> std::result::Result<kkdisp::PlanLayers, anyhow::Error> {
|
||||
match event {
|
||||
Event::Link(lnk) => {
|
||||
if lnk == "click" {
|
||||
self.index ^= 1;
|
||||
Ok(vec![self.states[self.index].clone()])
|
||||
} else {
|
||||
panic!("bad link");
|
||||
}
|
||||
}
|
||||
_ => Ok(vec![self.states[self.index].clone()]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue