General refactors

This commit is contained in:
elkowar 2021-08-01 19:22:45 +02:00
parent 27ce9e798a
commit 2a7255c3d5
No known key found for this signature in database
GPG key ID: E321AD71B1D1F27F
9 changed files with 97 additions and 76 deletions

View file

@ -1,4 +1,4 @@
use crate::{config, display_backend, error_handling_ctx, eww_state, script_var_handler::*, EwwPaths};
use crate::{EwwPaths, config, daemon_response::DaemonResponseSender, display_backend, error_handling_ctx, eww_state, script_var_handler::*};
use anyhow::*;
use debug_stub_derive::*;
use eww_shared_util::VarName;
@ -13,27 +13,6 @@ use yuck::{
value::Coords,
};
/// Response that the app may send as a response to a event.
/// This is used in `DaemonCommand`s that contain a response sender.
#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, derive_more::Display)]
pub enum DaemonResponse {
Success(String),
Failure(String),
}
impl DaemonResponse {
pub fn is_success(&self) -> bool {
matches!(self, DaemonResponse::Success(_))
}
pub fn is_failure(&self) -> bool {
!self.is_success()
}
}
pub type DaemonResponseSender = tokio::sync::mpsc::UnboundedSender<DaemonResponse>;
pub type DaemonResponseReceiver = tokio::sync::mpsc::UnboundedReceiver<DaemonResponse>;
#[derive(Debug)]
pub enum DaemonCommand {
NoOp,
@ -111,11 +90,7 @@ impl App {
DaemonCommand::ReloadConfigAndCss(sender) => {
let mut errors = Vec::new();
error_handling_ctx::clear_files();
let config_result = config::EwwConfig::read_from_file(
&mut error_handling_ctx::ERROR_HANDLING_CTX.lock().unwrap(),
&self.paths.get_yuck_path(),
);
let config_result = config::read_from_file(&self.paths.get_yuck_path());
match config_result.and_then(|new_config| self.load_config(new_config)) {
Ok(()) => {}
Err(e) => errors.push(e),
@ -129,9 +104,9 @@ impl App {
let errors = errors.into_iter().map(|e| error_handling_ctx::format_error(&e)).join("\n");
if errors.is_empty() {
sender.send(DaemonResponse::Success(String::new()))?;
sender.send_success(String::new())?;
} else {
sender.send(DaemonResponse::Failure(errors))?;
sender.send_failure(errors)?;
}
}
DaemonCommand::UpdateConfig(config) => {
@ -176,7 +151,7 @@ impl App {
.map(|(key, value)| format!("{}: {}", key, value))
.join("\n")
};
sender.send(DaemonResponse::Success(output)).context("sending response from main thread")?
sender.send_success(output)?
}
DaemonCommand::PrintWindows(sender) => {
let output = self
@ -188,11 +163,11 @@ impl App {
format!("{}{}", if is_open { "*" } else { "" }, window_name)
})
.join("\n");
sender.send(DaemonResponse::Success(output)).context("sending response from main thread")?
sender.send_success(output)?
}
DaemonCommand::PrintDebug(sender) => {
let output = format!("state: {:#?}\n\nconfig: {:#?}", &self.eww_state, &self.eww_config);
sender.send(DaemonResponse::Success(output)).context("sending response from main thread")?
sender.send_success(output)?
}
}
};
@ -387,8 +362,8 @@ fn get_monitor_geometry(n: i32) -> gdk::Rectangle {
/// In case of an Err, send the error message to a sender.
fn respond_with_error<T>(sender: DaemonResponseSender, result: Result<T>) -> Result<()> {
match result {
Ok(_) => sender.send(DaemonResponse::Success(String::new())),
Err(e) => sender.send(DaemonResponse::Failure(error_handling_ctx::format_error(&e))),
Ok(_) => sender.send_success(String::new()),
Err(e) => sender.send_failure(error_handling_ctx::format_error(&e)),
}
.context("sending response from main thread")
}

View file

@ -1,7 +1,7 @@
use std::process::Stdio;
use crate::{
app,
daemon_response::DaemonResponse,
opts::{self, ActionClientOnly},
EwwPaths,
};
@ -24,7 +24,7 @@ pub fn handle_client_only_action(paths: &EwwPaths, action: ActionClientOnly) ->
Ok(())
}
pub fn do_server_call(stream: &mut UnixStream, action: &opts::ActionWithServer) -> Result<Option<app::DaemonResponse>> {
pub fn do_server_call(stream: &mut UnixStream, action: &opts::ActionWithServer) -> Result<Option<DaemonResponse>> {
log::info!("Forwarding options to server");
stream.set_nonblocking(false).context("Failed to set stream to non-blocking")?;

View file

@ -7,8 +7,16 @@ use yuck::config::{
use simplexpr::dynval::DynVal;
use crate::error_handling_ctx;
use super::{script_var, EwwWindowDefinition};
/// Load an [EwwConfig] from a given file, resetting and applying the global YuckFiles object in [error_handling_ctx].
pub fn read_from_file(path: impl AsRef<Path>) -> Result<EwwConfig> {
error_handling_ctx::clear_files();
EwwConfig::read_from_file(&mut error_handling_ctx::YUCK_FILES.write().unwrap(), path)
}
/// Eww configuration structure.
#[derive(Debug, Clone)]
pub struct EwwConfig {

View file

@ -0,0 +1,39 @@
use anyhow::*;
/// Response that the app may send as a response to a event.
/// This is used in `DaemonCommand`s that contain a response sender.
#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, derive_more::Display)]
pub enum DaemonResponse {
Success(String),
Failure(String),
}
impl DaemonResponse {
pub fn is_success(&self) -> bool {
matches!(self, DaemonResponse::Success(_))
}
pub fn is_failure(&self) -> bool {
!self.is_success()
}
}
#[derive(Debug)]
pub struct DaemonResponseSender(tokio::sync::mpsc::UnboundedSender<DaemonResponse>);
pub fn create_pair() -> (DaemonResponseSender, tokio::sync::mpsc::UnboundedReceiver<DaemonResponse>) {
let (sender, recv) = tokio::sync::mpsc::unbounded_channel();
(DaemonResponseSender(sender), recv)
}
impl DaemonResponseSender {
pub fn send_success(&self, s: String) -> Result<()> {
self.0.send(DaemonResponse::Success(s)).context("Failed to send success response from application thread")
}
pub fn send_failure(&self, s: String) -> Result<()> {
self.0.send(DaemonResponse::Failure(s)).context("Failed to send failure response from application thread")
}
}
pub type DaemonResponseReceiver = tokio::sync::mpsc::UnboundedReceiver<DaemonResponse>;

View file

@ -1,4 +1,7 @@
use std::sync::{Arc, Mutex};
//! Disgusting global state.
//! I hate this, but [buffet](https://github.com/buffet) told me that this is what I should do for peak maintainability!
use std::sync::{Arc, RwLock};
use codespan_reporting::{
diagnostic::Diagnostic,
@ -11,24 +14,10 @@ use yuck::{config::file_provider::YuckFiles, error::AstError, format_diagnostic:
use crate::error::DiagError;
pub static ERROR_HANDLING_CTX: Lazy<Arc<Mutex<YuckFiles>>> = Lazy::new(|| Arc::new(Mutex::new(YuckFiles::new())));
pub static YUCK_FILES: Lazy<Arc<RwLock<YuckFiles>>> = Lazy::new(|| Arc::new(RwLock::new(YuckFiles::new())));
pub fn clear_files() {
*ERROR_HANDLING_CTX.lock().unwrap() = YuckFiles::new();
}
pub fn anyhow_err_to_diagnostic(err: &anyhow::Error) -> Diagnostic<usize> {
if let Some(err) = err.downcast_ref::<DiagError>() {
err.diag.clone()
} else if let Some(err) = err.downcast_ref::<AstError>() {
err.to_diagnostic()
} else if let Some(err) = err.downcast_ref::<ConversionError>() {
err.to_diagnostic()
} else if let Some(err) = err.downcast_ref::<EvalError>() {
err.to_diagnostic()
} else {
gen_diagnostic!(err)
}
*YUCK_FILES.write().unwrap() = YuckFiles::new();
}
pub fn print_error(err: anyhow::Error) {
@ -52,6 +41,20 @@ pub fn format_error(err: &anyhow::Error) -> String {
}
}
pub fn anyhow_err_to_diagnostic(err: &anyhow::Error) -> Diagnostic<usize> {
if let Some(err) = err.downcast_ref::<DiagError>() {
err.diag.clone()
} else if let Some(err) = err.downcast_ref::<AstError>() {
err.to_diagnostic()
} else if let Some(err) = err.downcast_ref::<ConversionError>() {
err.to_diagnostic()
} else if let Some(err) = err.downcast_ref::<EvalError>() {
err.to_diagnostic()
} else {
gen_diagnostic!(err)
}
}
pub fn stringify_diagnostic(mut diagnostic: codespan_reporting::diagnostic::Diagnostic<usize>) -> anyhow::Result<String> {
diagnostic.labels.drain_filter(|label| Span(label.range.start, label.range.end, label.file_id).is_dummy());
@ -61,7 +64,7 @@ pub fn stringify_diagnostic(mut diagnostic: codespan_reporting::diagnostic::Diag
config.chars = chars;
let mut buf = Vec::new();
let mut writer = term::termcolor::Ansi::new(&mut buf);
let files = ERROR_HANDLING_CTX.lock().unwrap();
let files = YUCK_FILES.read().unwrap();
term::emit(&mut writer, &config, &*files, &diagnostic)?;
Ok(String::from_utf8(buf)?)
}

View file

@ -13,6 +13,7 @@ extern crate gtk;
extern crate gtk_layer_shell as gtk_layer_shell;
use anyhow::*;
use daemon_response::DaemonResponseReceiver;
use opts::ActionWithServer;
use std::{
os::unix::net,
@ -37,6 +38,7 @@ pub mod script_var_handler;
pub mod server;
pub mod util;
pub mod widgets;
mod daemon_response;
fn main() {
let eww_binary_name = std::env::args().next().unwrap();
@ -114,7 +116,7 @@ fn main() {
}
}
fn listen_for_daemon_response(mut recv: app::DaemonResponseReceiver) {
fn listen_for_daemon_response(mut recv: DaemonResponseReceiver) {
let rt = tokio::runtime::Builder::new_current_thread().enable_time().build().expect("Failed to initialize tokio runtime");
rt.block_on(async {
if let Ok(Some(response)) = tokio::time::timeout(Duration::from_millis(100), recv.recv()).await {

View file

@ -5,7 +5,10 @@ use simplexpr::dynval::DynVal;
use structopt::StructOpt;
use yuck::{config::window_geometry::AnchorPoint, value::Coords};
use crate::app;
use crate::{
app,
daemon_response::{self, DaemonResponse, DaemonResponseSender},
};
/// Struct that gets generated from `RawOpt`.
#[derive(Debug, Serialize, Deserialize, PartialEq)]
@ -158,7 +161,7 @@ fn parse_var_update_arg(s: &str) -> Result<(VarName, DynVal)> {
}
impl ActionWithServer {
pub fn into_daemon_command(self) -> (app::DaemonCommand, Option<app::DaemonResponseReceiver>) {
pub fn into_daemon_command(self) -> (app::DaemonCommand, Option<daemon_response::DaemonResponseReceiver>) {
let command = match self {
ActionWithServer::Update { mappings } => app::DaemonCommand::UpdateVars(mappings),
@ -166,7 +169,7 @@ impl ActionWithServer {
ActionWithServer::CloseAll => app::DaemonCommand::CloseAll,
ActionWithServer::Ping => {
let (send, recv) = tokio::sync::mpsc::unbounded_channel();
let _ = send.send(app::DaemonResponse::Success("pong".to_owned()));
let _ = send.send(DaemonResponse::Success("pong".to_owned()));
return (app::DaemonCommand::NoOp, Some(recv));
}
ActionWithServer::OpenMany { windows } => {
@ -197,10 +200,10 @@ impl ActionWithServer {
}
}
fn with_response_channel<T, O, F>(f: F) -> (O, Option<tokio::sync::mpsc::UnboundedReceiver<T>>)
fn with_response_channel<O, F>(f: F) -> (O, Option<tokio::sync::mpsc::UnboundedReceiver<DaemonResponse>>)
where
F: FnOnce(tokio::sync::mpsc::UnboundedSender<T>) -> O,
F: FnOnce(DaemonResponseSender) -> O,
{
let (sender, recv) = tokio::sync::mpsc::unbounded_channel();
let (sender, recv) = daemon_response::create_pair();
(f(sender), Some(recv))
}

View file

@ -1,9 +1,4 @@
use crate::{
app::{self, DaemonCommand},
config, error_handling_ctx,
eww_state::*,
ipc_server, script_var_handler, util, EwwPaths,
};
use crate::{EwwPaths, app::{self, DaemonCommand}, config, daemon_response, error_handling_ctx, eww_state::*, ipc_server, script_var_handler, util};
use anyhow::*;
use std::{
@ -22,11 +17,7 @@ pub fn initialize_server(paths: EwwPaths, action: Option<DaemonCommand>) -> Resu
log::info!("Loading paths: {}", &paths);
// disgusting global state, I hate this, but https://github.com/buffet told me that this is what I should do for peak maintainability
error_handling_ctx::clear_files();
let read_config =
config::EwwConfig::read_from_file(&mut error_handling_ctx::ERROR_HANDLING_CTX.lock().unwrap(), &paths.get_yuck_path());
let read_config = config::read_from_file(&paths.get_yuck_path());
let eww_config = match read_config {
Ok(config) => config,
@ -167,12 +158,12 @@ async fn run_filewatch<P: AsRef<Path>>(config_dir: P, evt_send: UnboundedSender<
debounce_done.store(true, Ordering::SeqCst);
});
let (daemon_resp_sender, mut daemon_resp_response) = tokio::sync::mpsc::unbounded_channel();
let (daemon_resp_sender, mut daemon_resp_response) = daemon_response::create_pair();
evt_send.send(app::DaemonCommand::ReloadConfigAndCss(daemon_resp_sender))?;
tokio::spawn(async move {
match daemon_resp_response.recv().await {
Some(app::DaemonResponse::Success(_)) => log::info!("Reloaded config successfully"),
Some(app::DaemonResponse::Failure(e)) => eprintln!("{}", e),
Some(daemon_response::DaemonResponse::Success(_)) => log::info!("Reloaded config successfully"),
Some(daemon_response::DaemonResponse::Failure(e)) => eprintln!("{}", e),
None => log::error!("No response to reload configuration-reload request"),
}
});

View file

@ -525,7 +525,7 @@ fn build_gtk_literal(bargs: &mut BuilderArgs) -> Result<gtk::Box> {
if !content.is_empty() {
let widget_node_result: AstResult<_> = try {
let ast = {
let mut yuck_files = error_handling_ctx::ERROR_HANDLING_CTX.lock().unwrap();
let mut yuck_files = error_handling_ctx::YUCK_FILES.write().unwrap();
let (span, asts) = yuck_files.load_str("<literal-content>".to_string(), content)?;
if let Some(file_id) = literal_file_id.replace(Some(span.2)) {
yuck_files.unload(file_id);