diff options
author | delta <darkussdelta@gmail.com> | 2024-03-05 14:48:59 +0100 |
---|---|---|
committer | delta <darkussdelta@gmail.com> | 2024-03-05 14:48:59 +0100 |
commit | 510ef8e178929cf5e0c7fd5a5120fecf5f1b79f2 (patch) | |
tree | 3582e5cd7d000335ca94f2a009f3aed57bd86919 /.config/awesome/quarrel/native | |
parent | 95ba8030f722a616cff06c122dcfb2f63e25cf45 (diff) |
idk anymore
Diffstat (limited to '.config/awesome/quarrel/native')
-rw-r--r-- | .config/awesome/quarrel/native/Cargo.toml | 7 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/init.lua | 37 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/lenses/application.rs | 2 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/lenses/calculator.rs | 2 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/lib.rs | 22 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/mpd.rs | 142 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/net/mod.rs | 5 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/time.rs | 75 | ||||
-rw-r--r-- | .config/awesome/quarrel/native/src/util.rs | 101 |
9 files changed, 309 insertions, 84 deletions
diff --git a/.config/awesome/quarrel/native/Cargo.toml b/.config/awesome/quarrel/native/Cargo.toml index 9cff8fc..8d56c9f 100644 --- a/.config/awesome/quarrel/native/Cargo.toml +++ b/.config/awesome/quarrel/native/Cargo.toml @@ -17,6 +17,13 @@ nix = "0.26.2" chrono = "0.4.24" itertools = "0.10.5" 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" +once_cell = "1.18.0" + [lib] crate-type = ["cdylib"] diff --git a/.config/awesome/quarrel/native/init.lua b/.config/awesome/quarrel/native/init.lua index 14c66e5..e5d5aab 100644 --- a/.config/awesome/quarrel/native/init.lua +++ b/.config/awesome/quarrel/native/init.lua @@ -1,6 +1,43 @@ +---@meta + local old_cpath = package.cpath local cfg = require("gears.filesystem").get_configuration_dir() package.cpath = package.cpath .. ";" .. cfg .. "quarrel/native/lib?.so" + +---@class Entry +---@field message string +---@field exec { [1]: string, [2]: boolean }? + +---@alias query fun(input: string): Entry[] + +---@class Lenses +---@field [1] query Calculator lense +---@field [2] query Application lense + +---@alias ReadMode "l" | "n" | string + +---@class FileHandle +---@field read fun(self, mode: ReadMode): string | number +---@field write fun(self, content: string): number +---@field lines fun(self): string[] +---@field rewind fun(self) + +---@class Util +---@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" + package.cpath = old_cpath return qnative diff --git a/.config/awesome/quarrel/native/src/lenses/application.rs b/.config/awesome/quarrel/native/src/lenses/application.rs index 0857802..72aba8d 100644 --- a/.config/awesome/quarrel/native/src/lenses/application.rs +++ b/.config/awesome/quarrel/native/src/lenses/application.rs @@ -73,7 +73,7 @@ pub fn query(lua: &Lua, input: String) -> LuaResult<LuaTable> { return None }; - return parse_entry(&entry, &path).ok(); + parse_entry(&entry, &path).ok() }) .collect(); diff --git a/.config/awesome/quarrel/native/src/lenses/calculator.rs b/.config/awesome/quarrel/native/src/lenses/calculator.rs index c79dd42..07f1ee2 100644 --- a/.config/awesome/quarrel/native/src/lenses/calculator.rs +++ b/.config/awesome/quarrel/native/src/lenses/calculator.rs @@ -10,7 +10,7 @@ use crate::lenses::entry::{ Entry, }; -pub fn query<'a>(lua: &Lua, input: String) -> LuaResult<LuaTable> { +pub fn query(lua: &Lua, input: String) -> LuaResult<LuaTable> { let result = match eval(input.trim(), true, Unit::Celsius, false) { Ok(result) => { format!("{result}") diff --git a/.config/awesome/quarrel/native/src/lib.rs b/.config/awesome/quarrel/native/src/lib.rs index d89b610..472313e 100644 --- a/.config/awesome/quarrel/native/src/lib.rs +++ b/.config/awesome/quarrel/native/src/lib.rs @@ -1,8 +1,9 @@ mod lenses; +mod mpd; mod net; +mod util; use mlua::prelude::*; -use html_escape::decode_html_entities_to_string; #[mlua::lua_module] fn qnative(lua: &Lua) -> LuaResult<LuaTable> { @@ -10,14 +11,21 @@ fn qnative(lua: &Lua) -> LuaResult<LuaTable> { lenses.set("1", lua.create_function(lenses::calculator::query)?)?; lenses.set("2", lua.create_function(lenses::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("get_essid", lua.create_function(net::get_first_essid)?)?; - exports.set("decode_html", lua.create_function(|_: &Lua, string: String| { - let mut output = String::new(); - decode_html_entities_to_string(string, &mut output); - Ok(output) - })?)?; + exports.set("mpd", mpd)?; + exports.set("net", net)?; + exports.set("util", util)?; Ok(exports) } diff --git a/.config/awesome/quarrel/native/src/mpd.rs b/.config/awesome/quarrel/native/src/mpd.rs new file mode 100644 index 0000000..08c9e42 --- /dev/null +++ b/.config/awesome/quarrel/native/src/mpd.rs @@ -0,0 +1,142 @@ +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 71eaeea..96c853e 100644 --- a/.config/awesome/quarrel/native/src/net/mod.rs +++ b/.config/awesome/quarrel/native/src/net/mod.rs @@ -39,7 +39,12 @@ use wireless::{ ioctl_read_bad!(ioctl_get_interfaces, SIOCGIFCONF, IfConf); ioctl_read_bad!(ioctl_get_essid, SIOCGIWESSID, IwReq); +#[allow(clippy::unnecessary_wraps)] pub fn get_first_essid(_: &Lua, _: ()) -> LuaResult<String> { + Ok(get_first_essid_error().unwrap_or(String::new())) +} + +fn get_first_essid_error() -> LuaResult<String> { type Buffer = [c_char; 1024]; let mut buffer: Buffer = [0; 1024]; diff --git a/.config/awesome/quarrel/native/src/time.rs b/.config/awesome/quarrel/native/src/time.rs deleted file mode 100644 index 9850822..0000000 --- a/.config/awesome/quarrel/native/src/time.rs +++ /dev/null @@ -1,75 +0,0 @@ -use chrono::prelude::*; -use mlua::{ - prelude::*, - LuaSerdeExt, -}; - -// Taken from https://github.com/chronotope/chrono/issues/69#issuecomment-1510506428 -trait NaiveDateExt { - fn days_in_month(&self) -> u32; - fn days_in_year(&self) -> u32; - fn is_leap_year(&self) -> bool; -} - -impl NaiveDateExt for NaiveDate { - fn days_in_month(&self) -> u32 { - let month = self.month(); - match month { - 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, - 4 | 6 | 9 | 11 => 30, - 2 => { - if self.is_leap_year() { - 29 - } else { - 28 - } - } - _ => panic!("Invalid month: {}", month), - } - } - - fn days_in_year(&self) -> u32 { - if self.is_leap_year() { - 366 - } else { - 365 - } - } - - fn is_leap_year(&self) -> bool { - let year = self.year(); - return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); - } -} - -struct Day { - day: u32, - ce: bool, - weekday: Weekday, -} - -pub fn get_calendar_table(lua: &Lua, (year, month, day): (i32, u32, u32)) -> LuaResult<LuaTable> { - let date = - NaiveDate::from_ymd_opt(year, month, day).ok_or(LuaError::external("invalid date"))?; - let days: Vec<Day> = (1..=date.days_in_month()) - .map(|day| NaiveDate::from_ymd_opt(date.year(), date.month(), day).unwrap()) - .map(|date| { - let (ce, year) = date.year_ce(); - Day { - day: date.day(), - ce, - weekday: date.weekday(), - } - }) - .collect(); - - let calendar: Vec<Vec<Day>> = vec![vec![], vec![], vec![], vec![], vec![], vec![], vec![]]; - - if days[1].weekday != Weekday::Mon { - get_calendar_table(lua) - } - - if days.last().unwrap().weekday != Weekday::Sun {} - - Ok(lua.create_table()?) -} diff --git a/.config/awesome/quarrel/native/src/util.rs b/.config/awesome/quarrel/native/src/util.rs new file mode 100644 index 0000000..85a2574 --- /dev/null +++ b/.config/awesome/quarrel/native/src/util.rs @@ -0,0 +1,101 @@ +use std::{ + cell::RefCell, + fs::File, + fs::OpenOptions, + io::{ + Read, + Seek, + Write + }, + rc::Rc, + str::FromStr, +}; + +use html_escape::decode_html_entities_to_string; +use mlua::prelude::*; +use serde::Serialize; + +pub fn decode_html(_: &Lua, string: String) -> LuaResult<String> { + let mut output = String::new(); + decode_html_entities_to_string(string, &mut output); + Ok(output) +} + +enum ReadMode { + Line, + Number, + All, +} + +impl FromStr for ReadMode { + type Err = (); + + fn from_str(value: &str) -> Result<Self, Self::Err> { + Ok(match value { + "l" => Self::Line, + "n" => Self::Number, + _ => Self::All, + }) + } +} + +#[derive(Serialize)] +#[serde(untagged)] +enum StringOrNumber { + String(String), + Number(u64), +} + +pub struct FileHandle(Rc<RefCell<File>>); + +impl LuaUserData for FileHandle { + fn add_methods<'lua, M: LuaUserDataMethods<'lua, 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() { + ReadMode::Line => StringOrNumber::String( + content + .lines() + .next() + .map_or_else(String::new, |slice| slice.trim().to_owned()), + ), + ReadMode::Number => StringOrNumber::Number( + content.trim().parse::<u64>().map_err(LuaError::external)?, + ), + ReadMode::All => StringOrNumber::String(content), + })) + }); + methods.add_method("write", |_, this: &FileHandle, content: String| { + this.write(content.as_bytes()) + }); + methods.add_method("lines", |_, this: &FileHandle, (): ()| { + Ok(this + .read()? + .lines() + .map(ToOwned::to_owned) + .collect::<Vec<String>>()) + }); + methods.add_method("rewind", |_, this: &FileHandle, (): ()| this.rewind()); + } +} + +impl FileHandle { + pub fn new(_: &Lua, path: String) -> LuaResult<Self> { + Ok(Self(Rc::new(RefCell::new(File::open(path)?)))) + // Ok(Self(Rc::new(RefCell::new(OpenOptions::new().write(true).read(true).open(path)?)))) + } + + fn read(&self) -> LuaResult<String> { + let mut content = String::new(); + self.0.borrow_mut().read_to_string(&mut content)?; + Ok(content) + } + + fn rewind(&self) -> LuaResult<()> { + self.0.borrow_mut().rewind().map_err(LuaError::external) + } + + fn write(&self, buf: &[u8]) -> LuaResult<usize> { + self.0.borrow_mut().write(buf).map_err(LuaError::external) + } +} |