diff options
| author | delta <darkussdelta@gmail.com> | 2023-03-04 22:04:55 +0100 |
|---|---|---|
| committer | delta <darkussdelta@gmail.com> | 2023-03-04 22:18:21 +0100 |
| commit | f0b32f45746c026d402651013b7e98315d6956a1 (patch) | |
| tree | f42609e98522da081cebdd21a674a702d1054bbc /.config/awesome/ui/fresnel | |
| parent | a0f8b5fa6acdd1c2477fb1881dd9067956bf0ae6 (diff) | |
restructure awesome config, add fresnel
Diffstat (limited to '.config/awesome/ui/fresnel')
| -rw-r--r-- | .config/awesome/ui/fresnel/init.lua | 276 | ||||
| -rw-r--r-- | .config/awesome/ui/fresnel/lenses/.gitignore | 2 | ||||
| -rw-r--r-- | .config/awesome/ui/fresnel/lenses/Cargo.toml | 18 | ||||
| -rw-r--r-- | .config/awesome/ui/fresnel/lenses/install.log | 10 | ||||
| l--------- | .config/awesome/ui/fresnel/lenses/liblenses.so | 1 | ||||
| -rw-r--r-- | .config/awesome/ui/fresnel/lenses/rustfmt.toml | 3 | ||||
| -rw-r--r-- | .config/awesome/ui/fresnel/lenses/src/application.rs | 107 | ||||
| -rw-r--r-- | .config/awesome/ui/fresnel/lenses/src/calculator.rs | 25 | ||||
| -rw-r--r-- | .config/awesome/ui/fresnel/lenses/src/entry.rs | 20 | ||||
| -rw-r--r-- | .config/awesome/ui/fresnel/lenses/src/lib.rs | 16 |
10 files changed, 478 insertions, 0 deletions
diff --git a/.config/awesome/ui/fresnel/init.lua b/.config/awesome/ui/fresnel/init.lua new file mode 100644 index 0000000..cf1357a --- /dev/null +++ b/.config/awesome/ui/fresnel/init.lua @@ -0,0 +1,276 @@ +local awful = require "awful" +local gtable = require "gears.table" +local gdebug = require "gears.debug" +local gfs = require "gears.filesystem" +local h = require "misc.helpers" +local cfg = require "misc.cfg" +local vars = require "misc.vars" +local wibox = require "wibox" +local beautiful = require "beautiful" +local rubato = require "lib.rubato" +local al_prompt = require "lib.bling.widget.app_launcher.prompt" +local btn = awful.button.names + +package.cpath = package.cpath .. ";" .. gfs.get_configuration_dir() .. "ui/fresnel/lenses/target/debug/lib?.so" + +local lenses = require "lenses" +local max_entries = 10 + +local fresnel = {} + +fresnel._toggled = false +fresnel._entries_exec = {} +fresnel._entries_offset = 0 +fresnel._entries_count = 0 +fresnel._visible_entries = 0 +fresnel._selected_index = 1 + +function fresnel:_exec_entry(entry_index) + local exec = self._entries_exec[entry_index] + if type(exec) ~= "userdata" then + awful.spawn((exec[2] and cfg.terminal .. " -e " or "") .. exec[1]) + end +end + +function fresnel:_update(query, scrolled) + query = query or "" + scrolled = scrolled or false + + if not scrolled then + self._selected_index = 1 + self._entries_offset = 0 + end + + local layout = self._widget.widget:get_children_by_id("entry_layout")[1] + local status = self._widget.widget:get_children_by_id("status")[1] + local all_providers = {} + local entries_count = 0 + + self._entries_exec = {} + layout:reset() + + for _, provider in h.opairs(lenses) do + local entries = provider(query) + + table.sort(entries, function(a, b) + return a.message < b.message + end) + + all_providers = gtable.join(all_providers, entries) + end + + self._entries_count = #all_providers + + for i, entry in ipairs(all_providers) do + if i <= self._entries_offset then + goto continue + end + if entries_count == max_entries then break end + table.insert(self._entries_exec, entry.exec) + + local entry_widget = wibox.widget { + widget = wibox.container.background, + shape = vars.shape, + { + widget = wibox.container.margin, + margins = vars.padding, + { + widget = wibox.container.constraint, + strategy = "max", + height = vars.char_height, + { + { + widget = wibox.container.background, + fg = vars.colors.dim.fg, + { + widget = wibox.widget.textbox, + text = entry.provider .. " | " + } + }, + { + widget = wibox.widget.textbox, + text = entry.message + }, + spacing = vars.padding, + layout = wibox.layout.fixed.horizontal + } + } + }, + buttons = { + awful.button { + modifiers = {}, + button = btn.LEFT, + on_press = function() + self:_exec_entry(i) + end + } + }, + _selected = false + } + + if self._selected_index + self._entries_offset == i then + entry_widget._selected = true + entry_widget.bg = vars.colors.black + end + + entry_widget:connect_signal("mouse::enter", function() + if entry_widget._selected == true then return end + entry_widget.bg = vars.colors.black + end) + + entry_widget:connect_signal("mouse::leave", function() + if entry_widget._selected == true then return end + entry_widget.bg = vars.colors.bg + end) + + layout:add(entry_widget) + + entries_count = entries_count + 1 + self._visible_entries = entries_count + ::continue:: + end + + status.text = self._entries_offset + self._selected_index .. "/" .. self._entries_count +end + +fresnel._text = "" +fresnel._prompt = al_prompt { + prompt = "", + reset_on_stop = true, + ul_cursor = "low", + bg_cursor = vars.colors.black, + changed_callback = function(text) + if fresnel._text == text then return end + if fresnel._toggled == false then return end + fresnel:_update(text) + fresnel._text = text + end, + keypressed_callback = function(mod, key) + if key == "Escape" or key == " " and mod.Mod4 then + fresnel:hide() + elseif key == "Return" then + fresnel:_exec_entry(fresnel._selected_index) + fresnel:hide() + elseif key == "Up" then + local next_index = fresnel._selected_index - 1 + if next_index < 1 and fresnel._entries_offset == 0 then + return + elseif next_index < 1 and fresnel._entries_offset > 0 then + fresnel._entries_offset = fresnel._entries_offset - 1 + else + fresnel._selected_index = next_index + end + + fresnel:_update(fresnel._text, true) + elseif key == "Down" then + local next_index = fresnel._selected_index + 1 + if next_index > fresnel._visible_entries and fresnel._entries_offset + fresnel._visible_entries == fresnel._entries_count then + return + elseif next_index > fresnel._visible_entries and fresnel._entries_offset + fresnel._visible_entries < fresnel._entries_count then + fresnel._entries_offset = fresnel._entries_offset + 1 + else + fresnel._selected_index = next_index + end + + fresnel:_update(fresnel._text, true) + end + end +} + +fresnel._widget = h.popup { + visible = false, + ontop = true, + placement = function(d) + awful.placement.top(d, { + margins = { + top = beautiful.useless_gap * 2 + } + }) + end, + minimum_width = screen[1].geometry.width / 2, + maximum_width = screen[1].geometry.width / 2, + widget = { + { + widget = wibox.container.background, + bg = vars.colors.black, + fg = vars.colors.dim.fg, + shape = vars.shape, + { + widget = wibox.container.margin, + margins = vars.padding, + { + { + widget = wibox.widget.textbox, + text = ">" + }, + { + widget = wibox.container.margin, + margins = { + left = vars.padding, + right = vars.padding + }, + { + widget = wibox.container.constraint, + strategy = "max", + height = vars.char_height, + { + widget = wibox.container.background, + fg = vars.colors.fg, + fresnel._prompt.textbox + } + } + }, + { + widget = wibox.widget.textbox, + text = "0/0", + id = "status" + }, + layout = wibox.layout.align.horizontal + } + } + }, + { + widget = wibox.container.margin, + margins = { + top = vars.padding + }, + { + spacing = vars.padding, + layout = wibox.layout.fixed.vertical, + id = "entry_layout" + } + }, + layout = wibox.layout.align.vertical + } +} +fresnel._widget.maximum_height = vars.big_padding * 2 + (vars.padding * 2 + vars.char_height) * (1 + 10) + vars.padding + vars.padding * 9 + +function fresnel:show() + self._toggled = true + self._timed.target = 1 + self:_update() + self._prompt:start() +end + +function fresnel:hide() + self._toggled = false + self._timed.target = 0 + self._prompt:stop() +end + +fresnel._timed = rubato.timed { + duration = vars.anim_duration, + intro = vars.anim_intro, + pos = 0, + subscribed = function(pos) + fresnel._widget.opacity = pos + + if pos == 0 then + fresnel._widget.visible = false + else + fresnel._widget.visible = true + end + end +} + +return fresnel diff --git a/.config/awesome/ui/fresnel/lenses/.gitignore b/.config/awesome/ui/fresnel/lenses/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.config/awesome/ui/fresnel/lenses/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/.config/awesome/ui/fresnel/lenses/Cargo.toml b/.config/awesome/ui/fresnel/lenses/Cargo.toml new file mode 100644 index 0000000..4dcb8bc --- /dev/null +++ b/.config/awesome/ui/fresnel/lenses/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "lenses" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +freedesktop_entry_parser = "1.3.0" +meval = "0.2.0" +mlua = { version = "0.8.7", features = [ "module", "lua54", "serialize" ] } +parking_lot = "0.12.1" +rayon = "1.6.1" +serde = { version = "1.0.152", features = [ "derive" ] } +url = "2.3.1" + +[lib] +crate-type = ["cdylib"] diff --git a/.config/awesome/ui/fresnel/lenses/install.log b/.config/awesome/ui/fresnel/lenses/install.log new file mode 100644 index 0000000..c0f5d63 --- /dev/null +++ b/.config/awesome/ui/fresnel/lenses/install.log @@ -0,0 +1,10 @@ +[03:45:24 2023-02-24] FETCHING Version 2.16.1 +[03:45:24 2023-02-24] CREATING /home/delta/.spicetify +[03:45:24 2023-02-24] DOWNLOADING https://github.com/spicetify/spicetify-cli/releases/download/v2.16.1/spicetify-2.16.1-linux-amd64.tar.gz +[03:45:34 2023-02-24] EXTRACTING /home/delta/.spicetify/spicetify.tar.gz +[03:45:34 2023-02-24] SETTING EXECUTABLE PERMISSIONS TO /home/delta/.spicetify/spicetify +[03:45:34 2023-02-24] REMOVING /home/delta/.spicetify/spicetify.tar.gz +[03:45:34 2023-02-24] APPENDING /home/delta/.spicetify to PATH in /home/delta/.config/fish/config.fish +[03:45:34 2023-02-24] Restart your shell to have spicetify in your PATH. +[03:45:34 2023-02-24] spicetify v2.16.1 was installed successfully to /home/delta/.spicetify +[03:45:34 2023-02-24] Run 'spicetify --help' to get started diff --git a/.config/awesome/ui/fresnel/lenses/liblenses.so b/.config/awesome/ui/fresnel/lenses/liblenses.so new file mode 120000 index 0000000..5f7fc45 --- /dev/null +++ b/.config/awesome/ui/fresnel/lenses/liblenses.so @@ -0,0 +1 @@ +target/liblenses.so
\ No newline at end of file diff --git a/.config/awesome/ui/fresnel/lenses/rustfmt.toml b/.config/awesome/ui/fresnel/lenses/rustfmt.toml new file mode 100644 index 0000000..36afbbd --- /dev/null +++ b/.config/awesome/ui/fresnel/lenses/rustfmt.toml @@ -0,0 +1,3 @@ +imports_layout = "Vertical" +unstable_features = true +group_imports = "StdExternalCrate" diff --git a/.config/awesome/ui/fresnel/lenses/src/application.rs b/.config/awesome/ui/fresnel/lenses/src/application.rs new file mode 100644 index 0000000..0cf6c1a --- /dev/null +++ b/.config/awesome/ui/fresnel/lenses/src/application.rs @@ -0,0 +1,107 @@ +use std::{ + fs::read_dir, + path::PathBuf, +}; + +use freedesktop_entry_parser as fd; +use mlua::prelude::*; +use parking_lot::Mutex; +use rayon::prelude::*; +use url::Url; + +use crate::entry::{ + entries_to_lua_table, + Entry, +}; + +fn parse_entry<'a>(entry: fd::Entry, path: PathBuf) -> Result<Entry, ()> { + let section = entry.section("Desktop Entry"); + let name = section.attr("Name").ok_or(())?.to_string(); + + if section.attr("Type").ok_or(())? != "Application" { + return Err(()); + } + + match section.attr("OnlyShowIn") { + Some(_) => return Err(()), + None => {} + } + + match section.attr("Hidden") { + Some(_) => return Err(()), + None => {} + } + + match section.attr("NoDisplay") { + Some(_) => return Err(()), + None => {} + } + + let exec = section.attr("Exec").ok_or(())?.to_string(); + let mut new_exec = exec.clone(); + for (index, _) in exec.match_indices("%") { + match exec.chars().nth(index + 1).unwrap().to_ascii_lowercase() { + 'i' => match section.attr("Icon") { + Some(icon) => new_exec.replace_range(index..index + 2, &format!("--icon {}", icon)), + None => {} + }, + 'c' => new_exec.replace_range(index..index + 2, &name), + 'k' => new_exec.replace_range(index..index + 2, Url::from_file_path(&path)?.as_str()), + + 'f' | 'u' | 'v' | 'm' | 'd' | 'n' => new_exec.replace_range(index..index + 2, ""), + _ => continue, + } + } + + Ok(Entry { + message: name, + exec: Some(( + new_exec, + section + .attr("Terminal") + .unwrap_or("false") + .parse() + .map_err(drop)?, + )), + provider: "Application".to_string(), + }) +} + +pub fn query(lua: &Lua, input: String) -> LuaResult<LuaTable> { + let applications_dir = "/usr/share/applications"; + let entries = read_dir(applications_dir)? + .map(|result| result.map(|e| e.path())) + .collect::<Result<Vec<_>, std::io::Error>>()?; + + let entries = entries + .into_iter() + .filter(|e| match e.extension() { + Some(ext) if ext == "desktop" => true, + None | _ => false, + }) + .collect::<Vec<_>>(); + + let mut parsed_entries: Mutex<Vec<Entry>> = Mutex::new(Vec::new()); + + entries.into_par_iter().for_each(|path| { + let entry = match fd::parse_entry(&path) { + Ok(entry) => entry, + Err(_) => return, + }; + + match parse_entry(entry, path) { + Ok(parsed_entry) => parsed_entries.lock().push(parsed_entry), + Err(_) => return, + } + }); + + Ok(entries_to_lua_table( + parsed_entries + .get_mut() + .iter() + .filter(|entry| entry.message.to_lowercase().contains(&input)) + .map(|entry| (*entry).clone()) + .collect(), + lua, + )) +} diff --git a/.config/awesome/ui/fresnel/lenses/src/calculator.rs b/.config/awesome/ui/fresnel/lenses/src/calculator.rs new file mode 100644 index 0000000..792985d --- /dev/null +++ b/.config/awesome/ui/fresnel/lenses/src/calculator.rs @@ -0,0 +1,25 @@ +use meval::eval_str; +use mlua::prelude::*; + +use crate::entry::{ + entries_to_lua_table, + Entry, +}; + +pub fn query(lua: &Lua, input: String) -> LuaResult<LuaTable> { + println!("{:?}", input); + let result = match eval_str(input.trim()) { + Ok(ok) => ok.to_string(), + Err(_) => return Ok(lua.create_table()?), + }; + + Ok(entries_to_lua_table( + vec![Entry { + message: result, + exec: None, + // icon: '', + provider: "Calculator".to_string(), + }], + lua, + )) +} diff --git a/.config/awesome/ui/fresnel/lenses/src/entry.rs b/.config/awesome/ui/fresnel/lenses/src/entry.rs new file mode 100644 index 0000000..d6e7467 --- /dev/null +++ b/.config/awesome/ui/fresnel/lenses/src/entry.rs @@ -0,0 +1,20 @@ +use mlua::{ + prelude::*, + LuaSerdeExt, +}; +use serde::Serialize; + +#[derive(Serialize, Clone)] +pub struct Entry { + pub message: String, + pub exec: Option<(String, bool)>, + // pub icon: char, + pub provider: String, +} + +pub fn entries_to_lua_table(entries: Vec<Entry>, lua: &Lua) -> LuaTable { + match lua.to_value(&entries).unwrap() { + LuaValue::Table(t) => t, + _ => unreachable!(), + } +} diff --git a/.config/awesome/ui/fresnel/lenses/src/lib.rs b/.config/awesome/ui/fresnel/lenses/src/lib.rs new file mode 100644 index 0000000..e4fc881 --- /dev/null +++ b/.config/awesome/ui/fresnel/lenses/src/lib.rs @@ -0,0 +1,16 @@ +mod application; +mod calculator; +mod entry; + +use mlua::prelude::*; + +#[mlua::lua_module] +fn lenses(lua: &Lua) -> LuaResult<LuaTable> { + let exports = lua.create_table()?; + // lua.create_fun + // exports.push(application::query)?; + exports.set("1", lua.create_function(calculator::query)?)?; + exports.set("2", lua.create_function(application::query)?)?; + + Ok(exports) +} |
