Lua host, mark match indices in results
This commit is contained in:
parent
1cade695c8
commit
48879aadd8
12 changed files with 295 additions and 29 deletions
52
Cargo.lock
generated
52
Cargo.lock
generated
|
@ -64,6 +64,15 @@ version = "0.1.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.7.1"
|
||||
|
@ -640,6 +649,24 @@ dependencies = [
|
|||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lua-src"
|
||||
version = "543.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b72914332bf1ef0e1185b229135d639f11a4a8ccfd32852db8e52419c04c0247"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "luajit-src"
|
||||
version = "210.2.0+resty5f13855"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f85722ea9e022305a077b916c9271011a195ee8dc9b2b764fc78b0378e3b72"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
|
@ -701,6 +728,21 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mlua"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4235d7e740d73d7429df6f176c81b248f05c39d67264d45a7d8cecb67c227f6f"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"cc",
|
||||
"lua-src",
|
||||
"luajit-src",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.3.0"
|
||||
|
@ -792,6 +834,15 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
|
@ -1025,6 +1076,7 @@ dependencies = [
|
|||
"freedesktop_entry_parser",
|
||||
"fuzzy-matcher",
|
||||
"log",
|
||||
"mlua",
|
||||
"rayon",
|
||||
"walkdir",
|
||||
"winit",
|
||||
|
|
|
@ -20,3 +20,4 @@ fuzzy-matcher = "0.3.7"
|
|||
|
||||
walkdir = "2.3.2"
|
||||
freedesktop_entry_parser = "1.2.0"
|
||||
mlua = { version = "0.6", features = ["lua54", "vendored"] }
|
13
lua/date.lua
Normal file
13
lua/date.lua
Normal file
|
@ -0,0 +1,13 @@
|
|||
local date = require "date"
|
||||
-- prints all FRIDAY the 13TH dates between year 2000 and 2010
|
||||
for i = 2000, 2010 do
|
||||
-- year jan 1
|
||||
x = date(i, 1, 1)
|
||||
-- from january to december
|
||||
for j = 1, 12 do
|
||||
-- set date to 13, check if friday
|
||||
if x:setmonth(j, 13):getweekday() == 6 then
|
||||
print(x:fmt("%A, %B %d %Y"))
|
||||
end
|
||||
end
|
||||
end
|
1
lua/hello.lua
Normal file
1
lua/hello.lua
Normal file
|
@ -0,0 +1 @@
|
|||
print("Hello World")
|
69
lua/ui.lua
Normal file
69
lua/ui.lua
Normal file
|
@ -0,0 +1,69 @@
|
|||
local lwtk = require("lwtk")
|
||||
|
||||
local Application = lwtk.Application
|
||||
local Column = lwtk.Column
|
||||
local Row = lwtk.Row
|
||||
local PushButton = lwtk.PushButton
|
||||
local TextInput = lwtk.TextInput
|
||||
local TitleText = lwtk.TitleText
|
||||
local Space = lwtk.Space
|
||||
|
||||
local app = Application("example01.lua")
|
||||
|
||||
local function quit()
|
||||
app:close()
|
||||
end
|
||||
|
||||
local win = app:newWindow {
|
||||
title = "example01",
|
||||
Column {
|
||||
id = "c1",
|
||||
TitleText { text = "What's your name?" },
|
||||
TextInput { id = "i1", focus = true, style = { Columns = 40 } },
|
||||
Row {
|
||||
Space {},
|
||||
PushButton { id = "b1", text = "&OK", disabled = true,
|
||||
default = true },
|
||||
|
||||
PushButton { id = "b2", text = "&Quit", onClicked = quit },
|
||||
Space {}
|
||||
}
|
||||
},
|
||||
Column {
|
||||
id = "c2",
|
||||
visible = false,
|
||||
Space {},
|
||||
TitleText { id = "t2", style = { TextAlign = "center" } },
|
||||
Space {},
|
||||
Row {
|
||||
Space {},
|
||||
PushButton { id = "b3", text = "&Again" },
|
||||
|
||||
PushButton { id = "b4", text = "&Quit", default = true,
|
||||
onClicked = quit },
|
||||
Space {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
win:childById("c1"):setOnInputChanged(function(widget, input)
|
||||
widget:childById("b1"):setDisabled(input.text == "")
|
||||
end)
|
||||
|
||||
win:childById("b1"):setOnClicked(function(widget)
|
||||
win:childById("t2"):setText("Hello "..win:childById("i1").text.."!")
|
||||
win:childById("c1"):setVisible(false)
|
||||
win:childById("c2"):setVisible(true)
|
||||
end)
|
||||
|
||||
win:childById("b3"):setOnClicked(function(widget)
|
||||
win:childById("i1"):setText("")
|
||||
win:childById("i1"):setFocus()
|
||||
win:childById("t2"):setText("")
|
||||
win:childById("c1"):setVisible(true)
|
||||
win:childById("c2"):setVisible(false)
|
||||
end)
|
||||
|
||||
win:show()
|
||||
|
||||
app:runEventLoop()
|
|
@ -23,6 +23,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.add_source(sources::TestSource::new("ts1"))
|
||||
.add_source(sources::Window::new())
|
||||
.add_source(sources::Apps::new())
|
||||
.add_source(sources::LuaHost::new())
|
||||
.with_matcher(SkimMatcher::new());
|
||||
|
||||
debug!{"Source roftl sources"}
|
||||
|
|
|
@ -73,7 +73,7 @@ impl Roftl {
|
|||
debug!("Entries {:?}", self.entries);
|
||||
}
|
||||
|
||||
pub fn narrow(&self, input: &str) -> Vec<&Entry> {
|
||||
pub fn narrow(&self, input: &str) -> Vec<(&Entry, Vec<usize>)> {
|
||||
let count = Arc::new(AtomicUsize::new(0));
|
||||
self.narrow_map.lock().unwrap().clear();
|
||||
|
||||
|
@ -97,12 +97,12 @@ impl Roftl {
|
|||
|
||||
scored_entries
|
||||
.par_iter()
|
||||
.map(|se| se.2)
|
||||
.map(|se| (se.2, se.3.clone()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn action(&self, entry_id: usize, action: Action) {
|
||||
println!("NarrowMap {:?}", self.narrow_map.lock().unwrap());
|
||||
debug!{"NarrowMap {:?}", self.narrow_map.lock().unwrap()};
|
||||
|
||||
let real_id = *self.narrow_map.lock().unwrap().get(&entry_id).unwrap();
|
||||
let entry = self.entries.get(real_id).unwrap();
|
||||
|
|
|
@ -4,12 +4,55 @@ use walkdir::WalkDir;
|
|||
|
||||
use crate::roftl::{Action, Entry, Source};
|
||||
|
||||
pub struct Apps {}
|
||||
#[derive(Debug)]
|
||||
struct App {
|
||||
name: String,
|
||||
command: String,
|
||||
}
|
||||
|
||||
impl From<&App> for Entry
|
||||
{
|
||||
fn from(app: &App) -> Self {
|
||||
Entry {
|
||||
name: app.name.clone(),
|
||||
description: "".into(),
|
||||
source: "apps",
|
||||
identifier: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct AppBuilder<'a> {
|
||||
name: Option<&'a str>,
|
||||
exec: Option<&'a str>,
|
||||
hidden: Option<&'a str>
|
||||
}
|
||||
|
||||
impl<'a> AppBuilder<'a>
|
||||
{
|
||||
fn build(&self) -> Option<App>
|
||||
{
|
||||
if self.name.is_none() { return None }
|
||||
if self.exec.is_none() { return None }
|
||||
if self.hidden.is_some() { return None }
|
||||
|
||||
Some (
|
||||
App {
|
||||
name: self.name.unwrap().into(),
|
||||
command: self.exec.unwrap().into()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Apps {
|
||||
entries: Vec<App>
|
||||
}
|
||||
|
||||
impl Apps {
|
||||
pub fn new() -> Box<Apps>
|
||||
{
|
||||
Box::new(Apps{})
|
||||
Box::new(Apps{entries: vec![]})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,26 +78,43 @@ impl Source for Apps {
|
|||
.collect();
|
||||
|
||||
let mut entries: Vec<Entry> = vec![];
|
||||
let mut idx: u64 = 0;
|
||||
for entry in desktop_entries {
|
||||
match entry.section("Desktop Entry").attr("Name")
|
||||
{
|
||||
Some(name) => entries.push(
|
||||
Entry{name: name.clone().into(),
|
||||
description: "".into(),
|
||||
source: self.name(),
|
||||
identifier: 0}
|
||||
),
|
||||
let mut app_builder = AppBuilder::default();
|
||||
let section = entry.section("Desktop Entry");
|
||||
|
||||
None => continue
|
||||
for attr in section.attrs()
|
||||
{
|
||||
match attr.name
|
||||
{
|
||||
"Name" => app_builder.name = attr.value,
|
||||
"Exec" => app_builder.exec = attr.value,
|
||||
"Hidden" => app_builder.hidden = attr.value,
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(app) = app_builder.build()
|
||||
{
|
||||
let mut entry: Entry = (&app).into();
|
||||
entry.identifier = idx;
|
||||
idx += 1;
|
||||
entries.push(entry);
|
||||
self.entries.push(app);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
debug!{"Got desktop entries: {:?}", entries}
|
||||
|
||||
entries
|
||||
}
|
||||
|
||||
fn action(&self, entry: &Entry, action: Action) {
|
||||
todo!()
|
||||
debug!{"Got desktop entry {:?} for action", entry}
|
||||
debug!{"Desktop entry has id {}", entry.identifier}
|
||||
debug!{"Apps has entries {:?}", self.entries}
|
||||
let app = self.entries.get(entry.identifier as usize).unwrap();
|
||||
debug!{"Doing primary action {} for {}", app.name, app.command}
|
||||
}
|
||||
}
|
||||
|
|
56
src/sources/luahost.rs
Normal file
56
src/sources/luahost.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
use std::path::PathBuf;
|
||||
use mlua::prelude::*;
|
||||
|
||||
use log::debug;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use crate::roftl::{Entry, Source, Action};
|
||||
|
||||
pub struct LuaHost {
|
||||
scripts: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl LuaHost {
|
||||
pub fn new() -> Box<LuaHost> {
|
||||
Box::new(LuaHost{ scripts: vec![] })
|
||||
}
|
||||
}
|
||||
|
||||
impl Source for LuaHost {
|
||||
fn name(&self) -> &'static str {
|
||||
"lua"
|
||||
}
|
||||
|
||||
fn entries(&mut self) -> Vec<Entry> {
|
||||
// TODO read from config
|
||||
let script_path = "/home/armin/dev/incubator/roftl/lua";
|
||||
|
||||
let scripts: Vec<PathBuf> = WalkDir::new(script_path).into_iter()
|
||||
.map(|e| e.unwrap().path().to_path_buf())
|
||||
.collect();
|
||||
|
||||
let mut entries: Vec<Entry> = vec![];
|
||||
for (idx, script) in scripts.iter().enumerate() {
|
||||
entries.push(
|
||||
Entry {
|
||||
source: self.name(),
|
||||
name: script.file_stem().unwrap().to_str().unwrap().into(),
|
||||
description: "".into(),
|
||||
identifier: idx as u64
|
||||
});
|
||||
}
|
||||
self.scripts = scripts;
|
||||
entries
|
||||
}
|
||||
|
||||
fn action(&self, entry: &Entry, action: Action) {
|
||||
let script = self.scripts.get(entry.identifier as usize).unwrap();
|
||||
debug!{"Got script {:?}", script};
|
||||
|
||||
let script_content = std::fs::read_to_string(script).unwrap();
|
||||
let lua = Lua::new();
|
||||
lua.load(&script_content).exec().unwrap();
|
||||
|
||||
debug!{"Executed {:?}", script};
|
||||
}
|
||||
}
|
|
@ -6,3 +6,6 @@ pub use windows::Window;
|
|||
|
||||
mod apps;
|
||||
pub use apps::Apps;
|
||||
|
||||
mod luahost;
|
||||
pub use luahost::LuaHost;
|
||||
|
|
|
@ -103,7 +103,7 @@ impl<'a> Painter<'a> {
|
|||
ctx.show_text(input).unwrap();
|
||||
}
|
||||
|
||||
pub fn result_box<T>(&self, x: T, y: T, result: &'a str, selected: bool)
|
||||
pub fn result_box<T>(&self, x: T, y: T, result: &'a str, indices: &[usize], selected: bool)
|
||||
where T: Into<f64>
|
||||
{
|
||||
let ctx = self.context;
|
||||
|
@ -117,14 +117,22 @@ impl<'a> Painter<'a> {
|
|||
ctx.fill().unwrap();
|
||||
|
||||
// draw text
|
||||
ctx.select_font_face ("serif", cairo::FontSlant::Normal, cairo::FontWeight::Normal);
|
||||
let font_size = self.device_to_user(self.theme.result_font_size);
|
||||
ctx.set_font_size(font_size);
|
||||
let (r,g,b,a) = if selected { self.theme.result_font_selected }
|
||||
else { self.theme.result_font_color };
|
||||
ctx.set_source_rgba(r,g,b,a);
|
||||
ctx.move_to (x+0.2, y+0.8);
|
||||
ctx.show_text(result).unwrap();
|
||||
|
||||
for i in 0..result.len() {
|
||||
if indices.contains(&i) {
|
||||
ctx.select_font_face ("serif", cairo::FontSlant::Normal, cairo::FontWeight::Bold);
|
||||
ctx.show_text(&result[i..i+1]).unwrap();
|
||||
} else {
|
||||
ctx.select_font_face ("serif", cairo::FontSlant::Normal, cairo::FontWeight::Normal);
|
||||
ctx.show_text(&result[i..i+1]).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn divider<T>(&self, x: T, y: T)
|
||||
|
|
22
src/ui/ui.rs
22
src/ui/ui.rs
|
@ -71,7 +71,7 @@ fn make_context(window: &Window) -> cairo::Context
|
|||
cairo::Context::new(&surface).expect("Could not create drawing context")
|
||||
}
|
||||
|
||||
pub fn draw(window: &Window, input: &str, result: Vec<&Entry>, selection: usize)
|
||||
pub fn draw(window: &Window, input: &str, result: Vec<(&Entry, Vec<usize>)>, selection: usize)
|
||||
{
|
||||
let context = make_context(&window);
|
||||
|
||||
|
@ -84,12 +84,13 @@ pub fn draw(window: &Window, input: &str, result: Vec<&Entry>, selection: usize)
|
|||
painter.divider(0, 1);
|
||||
|
||||
result.iter().enumerate()
|
||||
.for_each(|(i, e)| {
|
||||
painter.result_box(0, 1+(i as u32), &e.name, selection==i);
|
||||
.for_each(|(i, r)| {
|
||||
let e = r.0;
|
||||
painter.result_box(0, 1+(i as u32), &e.name, &r.1, selection==i);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn redraw_quick(window: &Window, result: Vec<&Entry>, selection: usize) {
|
||||
pub fn redraw_quick(window: &Window, result: Vec<(&Entry, Vec<usize>)>, selection: usize) {
|
||||
let context = make_context(&window);
|
||||
|
||||
context.scale(30.0, 30.0);
|
||||
|
@ -97,16 +98,17 @@ pub fn redraw_quick(window: &Window, result: Vec<&Entry>, selection: usize) {
|
|||
let painter = painter::Painter::new(&context);
|
||||
|
||||
result.iter().enumerate()
|
||||
.for_each(|(i, e)| {
|
||||
.for_each(|(i, r)| {
|
||||
let e = r.0;
|
||||
// clear first and last as these may produce artifacts otherwise
|
||||
if i == 0 { painter.result_box(0, 1+(i as u32), &e.name, false) }
|
||||
if i == result.len()-1 { painter.result_box(0, 1+(i as u32), &e.name, false) }
|
||||
if i == 0 { painter.result_box(0, 1+(i as u32), &e.name, &r.1, false) }
|
||||
if i == result.len()-1 { painter.result_box(0, 1+(i as u32), &e.name, &r.1, false) }
|
||||
|
||||
// clear boxes around selection as these could be the old selection
|
||||
if selection > 0 && i == (selection-1) { painter.result_box(0, 1+(i as u32), &e.name, false) }
|
||||
if i == (selection+1) { painter.result_box(0, 1+(i as u32), &e.name, false) }
|
||||
if selection > 0 && i == (selection-1) { painter.result_box(0, 1+(i as u32), &e.name, &r.1, false) }
|
||||
if i == (selection+1) { painter.result_box(0, 1+(i as u32), &e.name, &r.1, false) }
|
||||
|
||||
// mark selection, note that this negates any unmarking above in case they are the same
|
||||
if i == selection { painter.result_box(0, 1+(i as u32), &e.name, true) }
|
||||
if i == selection { painter.result_box(0, 1+(i as u32), &e.name, &r.1, true) }
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue