diff options
author | delta <darkussdelta@gmail.com> | 2025-07-04 00:38:29 +0200 |
---|---|---|
committer | delta <darkussdelta@gmail.com> | 2025-07-04 00:38:29 +0200 |
commit | b3530d7c4a102935fa26498a160ee1dc6c1e9c03 (patch) | |
tree | d7751206a694bc5de2d6b34b0c077cfcd1855798 /.config/awesome/quarrel/native | |
parent | df75ec5ed5e3848c497f0439acb43ec9246ad3e7 (diff) |
:3
Diffstat (limited to '.config/awesome/quarrel/native')
-rw-r--r-- | .config/awesome/quarrel/native/Cargo.toml | 19 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/init.lua | 4 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/http.rs | 22 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/lenses/application.rs | 85 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/lenses/calculator.rs | 47 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/lenses/entry.rs | 19 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/lenses/mod.rs | 78 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/lib.rs | 14 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/moondrop.rs | 3 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/mpd.rs | 142 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/net/mod.rs | 4 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/util.rs | 3 |
12 files changed, 199 insertions, 241 deletions
diff --git a/.config/awesome/quarrel/native/Cargo.toml b/.config/awesome/quarrel/native/Cargo.toml index 8d56c9f..2551507 100644 --- a/.config/awesome/quarrel/native/Cargo.toml +++ b/.config/awesome/quarrel/native/Cargo.toml @@ -8,22 +8,21 @@ edition = "2021" [dependencies] freedesktop_entry_parser = "1.3.0" cpc = "1.9.1" -mlua = { version = "0.8.7", features = [ "module", "lua54", "serialize" ] } +mlua = { version = "0.10.3", features = [ "module", "lua54", "serialize" ] } rayon = "1.6.1" serde = { version = "1.0.152", features = [ "derive" ] } url = "2.3.1" -rodio = "0.17.1" -nix = "0.26.2" +rodio = "0.20.1" +nix = { version = "0.29.0", features = [ "ioctl", "socket" ] } chrono = "0.4.24" -itertools = "0.10.5" +itertools = "0.14.0" html-escape = "0.2.13" -mpd = { git = "https://github.com/kstep/rust-mpd", features = [ "serde" ], version = "0.1.0" } -cairo-rs = { git = "https://github.com/gtk-rs/gtk-rs-core.git", version = "0.18.0" } -gdk-pixbuf = { git = "https://github.com/gtk-rs/gtk-rs-core.git", version = "0.18.0" } -symphonia = "0.5.3" -dirs = "5.0.1" +dirs = "6.0.0" once_cell = "1.18.0" - +ureq = "3.0.9" +anyhow = { version = "1.0.97", features = ["backtrace"] } +mdrop = { git = "https://github.com/frahz/mdrop" } +sysinfo = "0.35.0" [lib] crate-type = ["cdylib"] diff --git a/.config/awesome/quarrel/native/init.lua b/.config/awesome/quarrel/native/init.lua index e5d5aab..6a823ba 100644 --- a/.config/awesome/quarrel/native/init.lua +++ b/.config/awesome/quarrel/native/init.lua @@ -26,16 +26,12 @@ package.cpath = package.cpath .. ";" .. cfg .. "quarrel/native/lib?.so" ---@field decode_html fun(input: string): string ---@field open_file fun(path: string): FileHandle ----@class Mpd ----@field init - ---@class Net ---@field get_essid fun(): string ---@class QuarrelNative ---@field lenses Lenses ---@field util Util ----@field mpd Mpd ---@field net Net local qnative = require "qnative" diff --git a/.config/awesome/quarrel/native/src/http.rs b/.config/awesome/quarrel/native/src/http.rs new file mode 100644 index 0000000..e995556 --- /dev/null +++ b/.config/awesome/quarrel/native/src/http.rs @@ -0,0 +1,22 @@ +use ureq::{Agent, agent}; +use std::{sync::LazyLock, thread}; +use mlua::prelude::*; + +static AGENT: LazyLock<Agent> = LazyLock::new(|| agent()); + +struct Stream(ureq::Body); + +pub fn get(_: &Lua, url: String, callback: LuaFunction, err_callback: LuaFunction) -> LuaResult<()> { + thread::spawn(|| { + match AGENT.get(url).call() { + Ok(body) => { + + }, + Err(err) => { + err_callback.call(err.to_string()); + } + } + // callback.call::<>() + }); + Ok(()) +} diff --git a/.config/awesome/quarrel/native/src/lenses/application.rs b/.config/awesome/quarrel/native/src/lenses/application.rs index 72aba8d..89b7bb4 100644 --- a/.config/awesome/quarrel/native/src/lenses/application.rs +++ b/.config/awesome/quarrel/native/src/lenses/application.rs @@ -1,6 +1,5 @@ use std::{ - fs::read_dir, - path::PathBuf, + fs::read_dir, path::PathBuf }; use freedesktop_entry_parser as fd; @@ -8,12 +7,54 @@ use mlua::prelude::*; use rayon::prelude::*; use url::Url; -use crate::lenses::entry::{ - entries_to_lua_table, +use crate::lenses::{ Entry, + Lense, + Cache }; -fn parse_entry(entry: &fd::Entry, path: &PathBuf) -> Result<Entry, ()> { +#[derive(Default)] +pub struct Application(pub Cache); + +impl Lense for Application { + const NAME: &str = "Application"; + + fn get_cache(&self) -> &Cache { + &self.0 + } + + fn set_cache(&mut self, cache: Cache) { + self.0 = cache; + } + + fn query(_: &Lua, input: String) -> Result<Vec<Entry>, anyhow::Error> { + 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 parsed_entries: Vec<Entry> = entries + .into_par_iter() + .filter(|path| path.extension().is_some_and(|ext| ext == "desktop")) + .filter_map(|path| { + parse_entry(path).ok().flatten() + }) + .collect(); + + Ok( + parsed_entries + .into_iter() + .filter(|entry| entry.message.to_lowercase().contains(&input.to_lowercase())) + .collect(), + ) + } +} + +fn parse_entry(path: PathBuf) -> Result<Option<Entry>, ()> { + let Ok(entry) = fd::parse_entry(&path) else { + return Err(()) + }; + let section = entry.section("Desktop Entry"); let name = section.attr("Name").ok_or(())?.to_string(); @@ -38,14 +79,14 @@ fn parse_entry(entry: &fd::Entry, path: &PathBuf) -> Result<Entry, ()> { } } 'c' => new_exec.replace_range(index..index + 2, &name), - 'k' => new_exec.replace_range(index..index + 2, Url::from_file_path(path)?.as_str()), + '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 { + Ok(Some(Entry { message: name, exec: Some(( new_exec, @@ -55,33 +96,5 @@ fn parse_entry(entry: &fd::Entry, path: &PathBuf) -> Result<Entry, ()> { .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 parsed_entries: Vec<Entry> = entries - .into_par_iter() - .filter(|path| matches!(path.extension(), Some(ext) if ext == "desktop")) - .filter_map(|path| { - let Ok(entry) = fd::parse_entry(&path) else { - return None - }; - - parse_entry(&entry, &path).ok() - }) - .collect(); - - Ok(entries_to_lua_table( - parsed_entries - .into_iter() - .filter(|entry| entry.message.to_lowercase().contains(&input.to_lowercase())) - .collect(), - lua, - )) + })) } diff --git a/.config/awesome/quarrel/native/src/lenses/calculator.rs b/.config/awesome/quarrel/native/src/lenses/calculator.rs index 07f1ee2..640bdeb 100644 --- a/.config/awesome/quarrel/native/src/lenses/calculator.rs +++ b/.config/awesome/quarrel/native/src/lenses/calculator.rs @@ -5,25 +5,36 @@ use cpc::{ }; use mlua::prelude::*; -use crate::lenses::entry::{ - entries_to_lua_table, +use crate::lenses::{ Entry, + Cache, + Lense }; -pub fn query(lua: &Lua, input: String) -> LuaResult<LuaTable> { - let result = match eval(input.trim(), true, Unit::Celsius, false) { - Ok(result) => { - format!("{result}") - } - Err(_) => return lua.create_table(), - }; - - Ok(entries_to_lua_table( - vec![Entry { - message: result, - exec: None, - provider: "Calculator".to_string(), - }], - lua, - )) +pub struct Calculator; + +impl Lense for Calculator { + const NAME: &str = "Calculator"; + + fn get_cache(&self) -> &Cache { + &Cache::Stale + } + + fn set_cache(&mut self, _: Cache) {} + + fn query(_: &Lua, input: String) -> Result<Vec<Entry>, anyhow::Error> { + let result = match eval(input.trim(), true, Unit::Celsius, false) { + Ok(result) => { + format!("{result}") + } + Err(err) => { return Err(anyhow::anyhow!(err)); }, + }; + + Ok(vec![Entry { + message: result, + exec: None, + }; 1] + ) + } } + diff --git a/.config/awesome/quarrel/native/src/lenses/entry.rs b/.config/awesome/quarrel/native/src/lenses/entry.rs deleted file mode 100644 index c7ac09e..0000000 --- a/.config/awesome/quarrel/native/src/lenses/entry.rs +++ /dev/null @@ -1,19 +0,0 @@ -use mlua::{ - prelude::*, - LuaSerdeExt, -}; -use serde::Serialize; - -#[derive(Serialize, Clone)] -pub struct Entry { - pub message: String, - pub exec: Option<(String, bool)>, - 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/quarrel/native/src/lenses/mod.rs b/.config/awesome/quarrel/native/src/lenses/mod.rs index d0db6f7..6eb5b58 100644 --- a/.config/awesome/quarrel/native/src/lenses/mod.rs +++ b/.config/awesome/quarrel/native/src/lenses/mod.rs @@ -1,3 +1,79 @@ pub mod application; pub mod calculator; -pub mod entry; + +use mlua::{ + prelude::*, + LuaSerdeExt, +}; +use serde::{Serialize, Deserialize}; + +#[derive(Deserialize, Serialize, Clone)] +pub struct Entry { + pub message: String, + pub exec: Option<(String, bool)>, +} + +impl IntoLua for Entry { + fn into_lua(self, lua: &Lua) -> LuaResult<LuaValue> { + return lua.to_value(&self) + } +} + +impl FromLua for Entry { + fn from_lua(value: LuaValue, lua: &Lua) -> LuaResult<Self> { + return lua.from_value(value); + } +} + +#[derive(Default)] +pub enum Cache { + Valid(Vec<Entry>), + #[default] + Stale +} + +pub struct _Lense<T: Lense>(pub T); + +pub trait Lense { + const NAME: &'static str; + + fn set_cache(&mut self, cache: Cache); + fn get_cache(&self) -> &Cache; + + fn query(lua: &Lua, input: String) -> Result<Vec<Entry>, anyhow::Error>; +} + +impl<T: Lense + 'static> LuaUserData for _Lense<T> { + fn add_fields<F: LuaUserDataFields<Self>>(fields: &mut F) { + // fields.add_field_method_get("cache", |lua, this| { + // let cache = this.0.get_cache(); + // match cache { + // Cache::Valid(cache) => Ok(cache.clone().into_lua(lua)?), + // Cache::Stale => Ok(LuaNil) + // } + // }); + + // fields.add_field_method_set("cache", |_, this, cache: Vec<Entry>| { + // Ok(this.0.set_cache(Cache::Valid(cache))) + // }); + + fields.add_field_method_get("stale", |_, this| Ok(matches!(this.0.get_cache(), Cache::Stale))); + + fields.add_field("name", T::NAME); + } + + fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) { + methods.add_method_mut("query", |lua, this, input: String| { + return Ok(match this.0.get_cache() { + Cache::Valid(entries) => entries.clone(), + Cache::Stale => { + let entries = T::query(lua, input).map_err(LuaError::external)?; + this.0.set_cache(Cache::Valid(entries.clone())); + entries + } + }); + }); + + methods.add_method_mut("mark_stale", |_, this, _: ()| Ok(this.0.set_cache(Cache::Stale)) ); + } +} diff --git a/.config/awesome/quarrel/native/src/lib.rs b/.config/awesome/quarrel/native/src/lib.rs index 472313e..4f1780d 100644 --- a/.config/awesome/quarrel/native/src/lib.rs +++ b/.config/awesome/quarrel/native/src/lib.rs @@ -1,29 +1,29 @@ mod lenses; -mod mpd; mod net; +// mod http; mod util; +mod moondrop; use mlua::prelude::*; +use lenses::{ _Lense }; #[mlua::lua_module] fn qnative(lua: &Lua) -> LuaResult<LuaTable> { let lenses = lua.create_table()?; - lenses.set("1", lua.create_function(lenses::calculator::query)?)?; - lenses.set("2", lua.create_function(lenses::application::query)?)?; + lenses.push(_Lense(lenses::calculator::Calculator))?; + lenses.push(_Lense(lenses::application::Application::default()))?; + // lenses.set("1", lua.create_function(lenses::calculator::Application::query)?)?; + // lenses.set("2", lua.create_function(lenses::application::Application::query)?)?; let util = lua.create_table()?; util.set("decode_html", lua.create_function(util::decode_html)?)?; util.set("open_file", lua.create_function(util::FileHandle::new)?)?; - let mpd = lua.create_table()?; - mpd.set("init", lua.create_function(mpd::init)?)?; - let net = lua.create_table()?; net.set("get_essid", lua.create_function(net::get_first_essid)?)?; let exports = lua.create_table()?; exports.set("lenses", lenses)?; - exports.set("mpd", mpd)?; exports.set("net", net)?; exports.set("util", util)?; diff --git a/.config/awesome/quarrel/native/src/moondrop.rs b/.config/awesome/quarrel/native/src/moondrop.rs new file mode 100644 index 0000000..d416ef6 --- /dev/null +++ b/.config/awesome/quarrel/native/src/moondrop.rs @@ -0,0 +1,3 @@ +use mdrop::Moondrop; + + diff --git a/.config/awesome/quarrel/native/src/mpd.rs b/.config/awesome/quarrel/native/src/mpd.rs deleted file mode 100644 index 08c9e42..0000000 --- a/.config/awesome/quarrel/native/src/mpd.rs +++ /dev/null @@ -1,142 +0,0 @@ -use std::{ - ffi::c_void, - fs::File, - net::TcpStream, - path::PathBuf, - sync::mpsc::channel, -}; - -use dirs::home_dir; -use gdk_pixbuf::{ - ffi::GdkPixbuf, - glib::translate::IntoGlibPtr, - traits::PixbufLoaderExt, - Pixbuf, - PixbufLoader, -}; -use mlua::{ - prelude::*, - LuaSerdeExt, -}; -use mpd::Client; -use once_cell::sync::Lazy; -use symphonia::{ - core::{ - formats::FormatOptions, - io::{ - MediaSourceStream, - MediaSourceStreamOptions, - }, - meta::MetadataOptions, - probe::Hint, - }, - default::get_probe, -}; - -static MPD_MUSIC_PATH: Lazy<PathBuf> = Lazy::new(|| { - [ - home_dir().expect("home directory should be set"), - "Music".into(), - ] - .iter() - .collect() -}); - -static COVER_FORMATS: [&str; 2] = ["png", "jpg"]; - -pub struct Connection(Client<TcpStream>); - -impl LuaUserData for Connection { - fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_method_mut("status", |lua, this: &mut Connection, (): ()| { - lua.to_value(&this.0.status().map_err(LuaError::external)?) - }); - - methods.add_method_mut("song", |lua, this: &mut Connection, (): ()| { - Ok( - if let Some(song) = this.0.currentsong().map_err(LuaError::external)? { - lua.to_value(&song)? - } else { - LuaNil - }, - ) - }); - - methods.add_method( - "get_cover_pixbuf", - |_, _: &Connection, file: String| { - let song_path = MPD_MUSIC_PATH.join(file); - let mut has_external_cover = false; - let mut cover_path = PathBuf::new(); - - for format in COVER_FORMATS { - let cover = song_path - .parent() - .unwrap() - .to_owned() - .join(format!("cover.{}", format)); - if cover.exists() { - has_external_cover = cover.exists(); - cover_path = cover; - break; - } - } - - let mss = MediaSourceStream::new( - Box::new(File::open(song_path)?), - MediaSourceStreamOptions::default(), - ); - - let mut probed = get_probe() - .format( - &Hint::default(), - mss, - &FormatOptions::default(), - &MetadataOptions::default(), - ) - .map_err(LuaError::external)?; - - let visuals; - - if let Some(metadata) = probed.format.metadata().skip_to_latest() { - visuals = metadata.visuals(); - if visuals.is_empty() && has_external_cover { - let pixbuf = Pixbuf::from_file(cover_path).map_err(LuaError::external)?; - - return Ok(( - Some(LuaLightUserData(unsafe { - <Pixbuf as IntoGlibPtr<*mut GdkPixbuf>>::into_glib_ptr(pixbuf) - .cast::<c_void>() - })), - Some(true), - )); - } - - let loader = PixbufLoader::new(); - loader - .write(visuals.first().unwrap().data.as_ref()) - .map_err(LuaError::external)?; - loader.close().map_err(LuaError::external)?; - - return Ok(( - Some(LuaLightUserData(unsafe { - <Pixbuf as IntoGlibPtr<*mut GdkPixbuf>>::into_glib_ptr( - loader.pixbuf().expect("Pixbuf should be initialized"), - ) - .cast::<c_void>() - })), - Some(false), - )); - } - - Ok((None, None)) - }, - ); - } -} - -pub fn init(_: &Lua, _: ()) -> LuaResult<Connection> { - Ok(Connection( - Client::connect("localhost:6600").map_err(LuaError::external)?, - )) -} diff --git a/.config/awesome/quarrel/native/src/net/mod.rs b/.config/awesome/quarrel/native/src/net/mod.rs index 96c853e..dbd87b9 100644 --- a/.config/awesome/quarrel/native/src/net/mod.rs +++ b/.config/awesome/quarrel/native/src/net/mod.rs @@ -9,7 +9,7 @@ use std::{ c_void, }, mem::size_of, - os::fd::RawFd, + os::fd::{IntoRawFd, RawFd}, }; use mlua::prelude::*; @@ -108,7 +108,7 @@ fn get_first_socket() -> LuaResult<RawFd> { for family in families { if let Ok(socket) = open_socket(family, SockType::Datagram, SockFlag::empty(), None) { - return Ok(socket); + return Ok(socket.into_raw_fd()); } } diff --git a/.config/awesome/quarrel/native/src/util.rs b/.config/awesome/quarrel/native/src/util.rs index 85a2574..41096d8 100644 --- a/.config/awesome/quarrel/native/src/util.rs +++ b/.config/awesome/quarrel/native/src/util.rs @@ -1,7 +1,6 @@ use std::{ cell::RefCell, fs::File, - fs::OpenOptions, io::{ Read, Seek, @@ -49,7 +48,7 @@ enum StringOrNumber { pub struct FileHandle(Rc<RefCell<File>>); impl LuaUserData for FileHandle { - fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + fn add_methods<'lua, M: LuaUserDataMethods<Self>>(methods: &mut M) { methods.add_method("read", |lua, this: &FileHandle, mode: String| { let content = this.read()?; Ok(lua.to_value(&match ReadMode::from_str(&mode).unwrap() { |