summaryrefslogtreecommitdiff
path: root/alacritty_config_derive/src/lib.rs
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2022-08-31 22:48:38 +0000
committerGitHub <noreply@github.com>2022-09-01 01:48:38 +0300
commit4ddb608563d985060d69594d1004550a680ae3bd (patch)
tree0b02a330b3e59300cff80a147f3c1bdab7f9ea57 /alacritty_config_derive/src/lib.rs
parent18f9c2793924aec91c80a69ccb45f529adaffae5 (diff)
downloadalacritty-4ddb608563d985060d69594d1004550a680ae3bd.tar.gz
alacritty-4ddb608563d985060d69594d1004550a680ae3bd.zip
Add IPC config subcommand
This patch adds a new mechanism for changing configuration options without editing the configuration file, by sending options to running instances through `alacritty msg`. Each window will load Alacritty's configuration file by default and then accept IPC messages for config updates using the `alacritty msg config` subcommand. By default all windows will be updated, individual windows can be addressed using `alacritty msg config --window-id "$ALACRITTY_WINDOW_ID"`. Each option will replace the config's current value and cannot be reset until Alacritty is restarted or the option is overwritten with a new value. Configuration options are passed in the format `field.subfield=value`, where `value` is interpreted as yaml. Closes #472.
Diffstat (limited to 'alacritty_config_derive/src/lib.rs')
-rw-r--r--alacritty_config_derive/src/lib.rs77
1 files changed, 63 insertions, 14 deletions
diff --git a/alacritty_config_derive/src/lib.rs b/alacritty_config_derive/src/lib.rs
index af8f2e7f..116d4828 100644
--- a/alacritty_config_derive/src/lib.rs
+++ b/alacritty_config_derive/src/lib.rs
@@ -2,25 +2,27 @@
#![cfg_attr(feature = "cargo-clippy", deny(warnings))]
use proc_macro::TokenStream;
-use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Error, Fields, Path};
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+use syn::parse::{self, Parse, ParseStream};
+use syn::punctuated::Punctuated;
+use syn::{GenericParam, Ident, LitStr, Path, Token, TypeParam};
-mod de_enum;
-mod de_struct;
+mod config_deserialize;
+mod serde_replace;
-/// Error if the derive was used on an unsupported type.
-const UNSUPPORTED_ERROR: &str = "ConfigDeserialize must be used on a struct with fields";
+/// Error message when attempting to flatten multiple fields.
+pub(crate) const MULTIPLE_FLATTEN_ERROR: &str =
+ "At most one instance of #[config(flatten)] is supported";
#[proc_macro_derive(ConfigDeserialize, attributes(config))]
pub fn derive_config_deserialize(input: TokenStream) -> TokenStream {
- let input = parse_macro_input!(input as DeriveInput);
-
- match input.data {
- Data::Struct(DataStruct { fields: Fields::Named(fields), .. }) => {
- de_struct::derive_deserialize(input.ident, input.generics, fields.named)
- },
- Data::Enum(data_enum) => de_enum::derive_deserialize(input.ident, data_enum),
- _ => Error::new(input.ident.span(), UNSUPPORTED_ERROR).to_compile_error().into(),
- }
+ config_deserialize::derive(input)
+}
+
+#[proc_macro_derive(SerdeReplace)]
+pub fn derive_serde_replace(input: TokenStream) -> TokenStream {
+ serde_replace::derive(input)
}
/// Verify that a token path ends with a specific segment.
@@ -28,3 +30,50 @@ pub(crate) fn path_ends_with(path: &Path, segment: &str) -> bool {
let segments = path.segments.iter();
segments.last().map_or(false, |s| s.ident == segment)
}
+
+/// Storage for all necessary generics information.
+#[derive(Default)]
+struct GenericsStreams {
+ unconstrained: TokenStream2,
+ constrained: TokenStream2,
+ phantoms: TokenStream2,
+}
+
+/// Create the necessary generics annotations.
+///
+/// This will create three different token streams, which might look like this:
+/// - unconstrained: `T`
+/// - constrained: `T: Default + Deserialize<'de>`
+/// - phantoms: `T: PhantomData<T>,`
+pub(crate) fn generics_streams<T>(params: &Punctuated<GenericParam, T>) -> GenericsStreams {
+ let mut generics = GenericsStreams::default();
+
+ for generic in params {
+ // NOTE: Lifetimes and const params are not supported.
+ if let GenericParam::Type(TypeParam { ident, .. }) = generic {
+ generics.unconstrained.extend(quote!( #ident , ));
+ generics.constrained.extend(quote! {
+ #ident : Default + serde::Deserialize<'de> + alacritty_config::SerdeReplace,
+ });
+ generics.phantoms.extend(quote! {
+ #ident : std::marker::PhantomData < #ident >,
+ });
+ }
+ }
+
+ generics
+}
+
+/// Field attribute.
+pub(crate) struct Attr {
+ ident: String,
+ param: Option<LitStr>,
+}
+
+impl Parse for Attr {
+ fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
+ let ident = input.parse::<Ident>()?.to_string();
+ let param = input.parse::<Token![=]>().and_then(|_| input.parse()).ok();
+ Ok(Self { ident, param })
+ }
+}