Source from dynamic sources

This commit is contained in:
Armin Friedl 2021-09-12 16:33:52 +02:00
parent 15fe9bc1d5
commit 5938bad12f
5 changed files with 513 additions and 10 deletions

249
Cargo.lock generated
View file

@ -2,6 +2,32 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
version = "1.3.2"
@ -14,6 +40,12 @@ version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cmake"
version = "0.1.45"
@ -24,10 +56,73 @@ dependencies = [
]
[[package]]
name = "fltk"
version = "1.1.11"
name = "crossbeam-channel"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "471fefc1fc3e019d314d542637f5bf48bd72a678f5e9052167b9ac7bea7b0a38"
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
dependencies = [
"cfg-if",
"crossbeam-utils",
"lazy_static",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
dependencies = [
"cfg-if",
"lazy_static",
]
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "env_logger"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "fltk"
version = "1.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bf356f493316a45a5b90b8d5db97c0fd9850b87ab19cc7f88b53ca5d01fd710"
dependencies = [
"bitflags",
"fltk-derive",
@ -39,9 +134,9 @@ dependencies = [
[[package]]
name = "fltk-derive"
version = "1.1.11"
version = "1.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712f09c29760a17e14a2f0d08a36b78bab82d5fbb3b2c3e17f3420f239351364"
checksum = "57ddbb2cb93484b56da41b80c1466bca2620b68b61847d5e7f999bda0782ab78"
dependencies = [
"quote",
"syn",
@ -49,14 +144,29 @@ dependencies = [
[[package]]
name = "fltk-sys"
version = "1.1.11"
version = "1.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc5eabad4839df806d102049c44586233743cf6607e2d2829155bb9fe45775e"
checksum = "ebe424d107ab6ef0a4b756295c259bb8cec6e610548d55481457309884d526d4"
dependencies = [
"cmake",
"libc",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -69,6 +179,15 @@ version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5"
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "malloc_buf"
version = "0.0.6"
@ -78,6 +197,31 @@ dependencies = [
"libc",
]
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "memoffset"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "objc"
version = "0.2.7"
@ -114,13 +258,64 @@ dependencies = [
"libc",
]
[[package]]
name = "rayon"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
dependencies = [
"autocfg",
"crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"lazy_static",
"num_cpus",
]
[[package]]
name = "regex"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "roftl"
version = "0.1.0"
dependencies = [
"env_logger",
"fltk",
"log",
"rayon",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "syn"
version = "1.0.75"
@ -132,8 +327,48 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "termcolor"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
dependencies = [
"winapi-util",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[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-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View file

@ -6,4 +6,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
fltk = "^1.1"
fltk = "1.1"
log = "0.4"
env_logger = "0.9.0"
rayon = "1.5.1"

View file

@ -1,3 +1,95 @@
fn main() {
println!("Hello, world!");
use log::{debug, info, trace, warn};
use std::error::Error;
mod roftl;
mod ui;
use roftl::{Action, Entry, Source};
struct TestSource {
name: String,
entries: Vec<Entry>,
}
impl TestSource {
fn new(s: &str) -> Box<TestSource> {
let mut ts = Box::new(TestSource {
name: "Testsource".into(),
entries: vec![],
});
(1..1000).for_each(|i| {
ts.add_entry(
format! {"Test {} {}", i, s},
format! {"Test {} description", i},
);
});
ts
}
fn add_entry(&mut self, name: String, description: String) {
let id = self.entries.len();
self.entries.push(Entry {
name,
description,
source: self,
id: id as u32,
});
}
}
impl Source for TestSource {
fn name(&self) -> &str {
&self.name
}
fn entries(&self) -> Vec<Entry> {
self.entries.clone()
}
fn action(&self, entry: &Entry, action: Action) {
println!("Doing action {:?} for entry {}", action, entry.name)
}
}
fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
let mut roftl = roftl::Roftl::new();
roftl
.add_source(TestSource::new("ts1"))
.add_source(TestSource::new("ts2"));
roftl.source();
let mut app = ui::draw()?;
roftl
.narrow("")
.iter()
.for_each(|e| app.add_candidate((*e).clone()));
while app.wait() {
match app.events.recv() {
Some(ui::Event::CandidateSelect(entry)) => {
trace! {"Selected: {}", entry.name}
roftl.action(&entry, Action::Primary)
}
Some(ui::Event::InputUpdate) => {
trace! {"Input: {}", &app.get_input()}
app.clear_candidates();
roftl
.narrow(&app.get_input())
.iter()
.for_each(|e| app.add_candidate((*e).clone()));
}
_ => {}
}
}
Ok(())
}

63
src/roftl.rs Normal file
View file

@ -0,0 +1,63 @@
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
#[derive(Clone)]
pub struct Entry {
pub name: String,
pub description: String,
pub source: *const dyn Source,
pub id: u32
}
unsafe impl Sync for Entry {}
unsafe impl Send for Entry {}
#[derive(Debug)]
pub enum Action {
Primary,
}
pub trait Source: Send + Sync {
fn name(&self) -> &str;
fn entries(&self) -> Vec<Entry>;
fn action(&self, entry: &Entry, action: Action);
}
pub struct Roftl {
sources: Vec<Box<dyn Source>>,
entries: Vec<Entry>,
}
impl Roftl {
pub fn new() -> Roftl {
Roftl {
sources: vec![],
entries: vec![],
}
}
pub fn add_source(&mut self, source: Box<dyn Source>) -> &mut Roftl {
self.sources.push(source);
self
}
pub fn source(&mut self) {
self.entries = self
.sources
.par_iter()
.flat_map_iter(|s| s.entries())
.collect();
}
pub fn narrow(&self, input: &str) -> Vec<&Entry> {
self.entries.par_iter()
.filter(|e| e.name.starts_with(input))
.collect()
}
pub fn action(&self, entry: &Entry, action: Action) {
unsafe {
Source::action(&*entry.source, entry, action);
}
}
}

110
src/ui.rs Normal file
View file

@ -0,0 +1,110 @@
use std::ops::Deref;
use fltk::enums::{CallbackTrigger, Font, FrameType};
use fltk::group::{PackType, ScrollType};
use fltk::output;
use fltk::prelude::*;
use fltk::{app, window, input, group};
use super::roftl::Entry;
#[derive(Clone)]
pub enum Event {
InputUpdate,
CandidateSelect(Entry)
}
pub struct RoftlApp {
pub app: app::App,
pub events: app::Receiver::<Event>,
send: app::Sender<Event>,
input: input::Input,
candidates: group::Pack,
scroll: group::Scroll
}
impl RoftlApp {
pub fn add_candidate(&mut self, entry: Entry) {
let mut output = output::Output::default();
output.set_value(&entry.name);
output.set_frame(FrameType::FlatBox);
output.set_size(380,30);
let s = self.send.clone();
output.handle(move |_widget, ev: fltk::enums::Event| {
match ev {
fltk::enums::Event::Focus => {
s.send(Event::CandidateSelect(entry.clone()));
true
},
_ => false
}
});
self.candidates.add(&output);
self.scroll.redraw();
}
pub fn clear_candidates(&mut self) {
for i in 0..self.candidates.children() {
self.candidates.child(i).and_then(|c| {Some(WidgetBase::delete(c))});
}
self.scroll.redraw();
}
pub fn get_input(&self) -> String {
self.input.value().clone()
}
}
impl Deref for RoftlApp {
type Target = app::App;
fn deref(&self) -> &Self::Target {
&self.app
}
}
pub fn draw() -> Result<RoftlApp, FltkError> {
app::set_font(Font::Screen);
let app = app::App::default();
let mut window = window::Window::default()
.with_size(400, 300)
.center_screen();
window.set_border(false);
let pack = group::Pack::default()
.with_type(PackType::Vertical)
.with_size(400,40);
let mut input = input::Input::default()
.with_size(0,40);
input.set_trigger(CallbackTrigger::Changed);
let scroll = group::Scroll::default()
.with_size(400, 300-40)
.with_type(ScrollType::AlwaysOn);
let candidates = group::Pack::default()
.with_size(380, 300-40)
.center_of(&scroll);
candidates.end();
scroll.end();
pack.end();
window.end();
window.show();
let (s, r) = app::channel::<Event>();
input.emit(s.clone(), Event::InputUpdate);
Ok(RoftlApp{app, events: r, send: s, input, candidates, scroll})
}