General refactors
This commit is contained in:
parent
27ce9e798a
commit
2a7255c3d5
9 changed files with 97 additions and 76 deletions
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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")?;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
39
crates/eww/src/daemon_response.rs
Normal file
39
crates/eww/src/daemon_response.rs
Normal 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>;
|
|
@ -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)?)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue