build.rs: add proc-macro to generate Override structs for configuration
parent
1db2c16f95
commit
0169025d50
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* meli -
|
||||
*
|
||||
* Copyright Manos Pitsidianakis
|
||||
*
|
||||
* This file is part of meli.
|
||||
*
|
||||
* meli is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* meli is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
// Write ConfigStructOverride to overrides.rs
|
||||
pub fn override_derive(filenames: &[(&str, &str)]) {
|
||||
let mut output_file =
|
||||
File::create("src/conf/overrides.rs").expect("Unable to open output file");
|
||||
let mut output_string = r##"/*
|
||||
* meli - conf/overrides.rs
|
||||
*
|
||||
* Copyright 2020 Manos Pitsidianakis
|
||||
*
|
||||
* This file is part of meli.
|
||||
*
|
||||
* meli is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* meli is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//! This module is automatically generated by build.rs.
|
||||
use super::*;
|
||||
|
||||
"##
|
||||
.to_string();
|
||||
|
||||
'file_loop: for (filename, ident) in filenames {
|
||||
println!("cargo:rerun-if-changed={}", filename);
|
||||
let mut file = File::open(&filename).expect(&format!("Unable to open file `{}`", filename));
|
||||
|
||||
let mut src = String::new();
|
||||
file.read_to_string(&mut src).expect("Unable to read file");
|
||||
|
||||
let syntax = syn::parse_file(&src).expect("Unable to parse file");
|
||||
if syntax.items.iter().any(|item| {
|
||||
if let syn::Item::Struct(s) = item {
|
||||
if s.ident.to_string().ends_with("Override") {
|
||||
println!("ident {} exists, skipping {}", ident, filename);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}) {
|
||||
continue 'file_loop;
|
||||
}
|
||||
|
||||
for item in syntax.items.iter() {
|
||||
if let syn::Item::Struct(s) = item {
|
||||
if s.ident != ident {
|
||||
continue;
|
||||
}
|
||||
if s.ident.to_string().ends_with("Override") {
|
||||
unreachable!();
|
||||
}
|
||||
let override_ident: syn::Ident = format_ident!("{}Override", s.ident);
|
||||
let mut field_tokentrees = vec![];
|
||||
let mut field_idents = vec![];
|
||||
for f in &s.fields {
|
||||
let ident = &f.ident;
|
||||
let ty = &f.ty;
|
||||
let attrs = f
|
||||
.attrs
|
||||
.iter()
|
||||
.filter_map(|f| {
|
||||
let mut new_attr = f.clone();
|
||||
if let quote::__private::TokenTree::Group(g) =
|
||||
f.tokens.clone().into_iter().next().unwrap()
|
||||
{
|
||||
let attr_inner_value = f.tokens.to_string();
|
||||
if !attr_inner_value.starts_with("( default")
|
||||
&& !attr_inner_value.starts_with("( default =")
|
||||
{
|
||||
return None;
|
||||
}
|
||||
if attr_inner_value.starts_with("( default =") {
|
||||
let rest = g.stream().clone().into_iter().skip(4);
|
||||
new_attr.tokens = quote! { ( #(#rest)*) };
|
||||
if new_attr.tokens.to_string().as_str() == "( )" {
|
||||
return None;
|
||||
}
|
||||
} else if attr_inner_value.starts_with("( default") {
|
||||
let rest = g.stream().clone().into_iter().skip(2);
|
||||
new_attr.tokens = quote! { ( #(#rest)*) };
|
||||
if new_attr.tokens.to_string().as_str() == "( )" {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(new_attr)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let t = quote! {
|
||||
#(#attrs)*
|
||||
#[serde(default)]
|
||||
pub #ident : Option<#ty>
|
||||
};
|
||||
field_idents.push(ident);
|
||||
field_tokentrees.push(t);
|
||||
}
|
||||
//let fields = &s.fields;
|
||||
|
||||
let literal_struct = quote! {
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct #override_ident {
|
||||
#(#field_tokentrees),*
|
||||
}
|
||||
|
||||
|
||||
impl Default for #override_ident {
|
||||
fn default() -> Self {
|
||||
#override_ident {
|
||||
#(#field_idents: None),*
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
output_string.extend(literal_struct.to_string().chars());
|
||||
output_string.push_str("\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
let mut rustfmt = Command::new("rustfmt")
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("failed to execute rustfmt");
|
||||
|
||||
{
|
||||
// limited borrow of stdin
|
||||
let stdin = rustfmt
|
||||
.stdin
|
||||
.as_mut()
|
||||
.expect("failed to get rustfmt stdin");
|
||||
stdin
|
||||
.write_all(output_string.as_bytes())
|
||||
.expect("failed to write to rustfmit stdin");
|
||||
}
|
||||
|
||||
let output = rustfmt
|
||||
.wait_with_output()
|
||||
.expect("failed to wait on rustfmt child");
|
||||
if !output.stderr.is_empty() {
|
||||
panic!(format!("{}", String::from_utf8_lossy(&output.stderr)));
|
||||
}
|
||||
|
||||
output_file.write_all(&output.stdout).unwrap();
|
||||
*/
|
||||
output_file.write_all(output_string.as_bytes()).unwrap();
|
||||
}
|
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* meli - conf/overrides.rs
|
||||
*
|
||||
* Copyright 2020 Manos Pitsidianakis
|
||||
*
|
||||
* This file is part of meli.
|
||||
*
|
||||
* meli is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* meli is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//! This module is automatically generated by build.rs.
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct PagerSettingsOverride {
|
||||
#[doc = " Number of context lines when going to next page."]
|
||||
#[doc = " Default: 0"]
|
||||
#[serde(alias = "pager-context")]
|
||||
#[serde(default)]
|
||||
pub pager_context: Option<usize>,
|
||||
#[doc = " Stop at the end instead of displaying next mail."]
|
||||
#[doc = " Default: false"]
|
||||
#[serde(alias = "pager-stop")]
|
||||
#[serde(default)]
|
||||
pub pager_stop: Option<bool>,
|
||||
#[doc = " Always show headers when scrolling."]
|
||||
#[doc = " Default: true"]
|
||||
#[serde(alias = "headers-sticky")]
|
||||
#[serde(default)]
|
||||
pub headers_sticky: Option<bool>,
|
||||
#[doc = " The height of the pager in mail view, in percent."]
|
||||
#[doc = " Default: 80"]
|
||||
#[serde(alias = "pager-ratio")]
|
||||
#[serde(default)]
|
||||
pub pager_ratio: Option<usize>,
|
||||
#[doc = " A command to pipe mail output through for viewing in pager."]
|
||||
#[doc = " Default: None"]
|
||||
#[serde(deserialize_with = "non_empty_string")]
|
||||
#[serde(default)]
|
||||
pub filter: Option<Option<String>>,
|
||||
#[doc = " A command to pipe html output before displaying it in a pager"]
|
||||
#[doc = " Default: None"]
|
||||
#[serde(deserialize_with = "non_empty_string", alias = "html-filter")]
|
||||
#[serde(default)]
|
||||
pub html_filter: Option<Option<String>>,
|
||||
#[doc = " Respect \"format=flowed\""]
|
||||
#[doc = " Default: true"]
|
||||
#[serde(alias = "format-flowed")]
|
||||
#[serde(default)]
|
||||
pub format_flowed: Option<bool>,
|
||||
#[doc = " Split long lines that would overflow on the x axis."]
|
||||
#[doc = " Default: true"]
|
||||
#[serde(alias = "split-long-lines")]
|
||||
#[serde(default)]
|
||||
pub split_long_lines: Option<bool>,
|
||||
#[doc = " Minimum text width in columns."]
|
||||
#[doc = " Default: 80"]
|
||||
#[serde(alias = "minimum-width")]
|
||||
#[serde(default)]
|
||||
pub minimum_width: Option<usize>,
|
||||
#[doc = " Choose `text/html` alternative if `text/plain` is empty in `multipart/alternative`"]
|
||||
#[doc = " attachments."]
|
||||
#[doc = " Default: true"]
|
||||
#[serde(alias = "auto-choose-multipart-alternative")]
|
||||
#[serde(default)]
|
||||
pub auto_choose_multipart_alternative: Option<ToggleFlag>,
|
||||
}
|
||||
impl Default for PagerSettingsOverride {
|
||||
fn default() -> Self {
|
||||
PagerSettingsOverride {
|
||||
pager_context: None,
|
||||
pager_stop: None,
|
||||
headers_sticky: None,
|
||||
pager_ratio: None,
|
||||
filter: None,
|
||||
html_filter: None,
|
||||
format_flowed: None,
|
||||
split_long_lines: None,
|
||||
minimum_width: None,
|
||||
auto_choose_multipart_alternative: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ListingSettingsOverride {
|
||||
#[doc = " Number of context lines when going to next page."]
|
||||
#[doc = " Default: 0"]
|
||||
#[serde(alias = "context-lines")]
|
||||
#[serde(default)]
|
||||
pub context_lines: Option<usize>,
|
||||
#[doc = " Datetime formatting passed verbatim to strftime(3)."]
|
||||
#[doc = " Default: %Y-%m-%d %T"]
|
||||
#[serde(alias = "datetime-fmt")]
|
||||
#[serde(default)]
|
||||
pub datetime_fmt: Option<Option<String>>,
|
||||
#[doc = " Show recent dates as `X {minutes,hours,days} ago`, up to 7 days."]
|
||||
#[doc = " Default: true"]
|
||||
#[serde(alias = "recent-dates")]
|
||||
#[serde(default)]
|
||||
pub recent_dates: Option<bool>,
|
||||
#[doc = " Show only envelopes that match this query"]
|
||||
#[doc = " Default: None"]
|
||||
#[serde(default)]
|
||||
pub filter: Option<Option<Query>>,
|
||||
#[serde(alias = "index-style")]
|
||||
#[serde(default)]
|
||||
pub index_style: Option<IndexStyle>,
|
||||
}
|
||||
impl Default for ListingSettingsOverride {
|
||||
fn default() -> Self {
|
||||
ListingSettingsOverride {
|
||||
context_lines: None,
|
||||
datetime_fmt: None,
|
||||
recent_dates: None,
|
||||
filter: None,
|
||||
index_style: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct NotificationsSettingsOverride {
|
||||
#[doc = " A command to pipe notifications through"]
|
||||
#[doc = " Default: None"]
|
||||
#[serde(default)]
|
||||
pub script: Option<Option<String>>,
|
||||
#[doc = " A file location which has its size changed when new mail arrives (max 128 bytes). Can be"]
|
||||
#[doc = " used to trigger new mail notifications eg with `xbiff(1)`"]
|
||||
#[doc = " Default: None"]
|
||||
#[serde(alias = "xbiff-file-path")]
|
||||
#[serde(default)]
|
||||
pub xbiff_file_path: Option<Option<String>>,
|
||||
#[serde(alias = "play-sound")]
|
||||
#[serde(default)]
|
||||
pub play_sound: Option<super::ToggleFlag>,
|
||||
#[serde(alias = "sound-file")]
|
||||
#[serde(default)]
|
||||
pub sound_file: Option<Option<String>>,
|
||||
}
|
||||
impl Default for NotificationsSettingsOverride {
|
||||
fn default() -> Self {
|
||||
NotificationsSettingsOverride {
|
||||
script: None,
|
||||
xbiff_file_path: None,
|
||||
play_sound: None,
|
||||
sound_file: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ShortcutsOverride {
|
||||
#[serde(default)]
|
||||
pub general: Option<GeneralShortcuts>,
|
||||
#[serde(default)]
|
||||
pub listing: Option<ListingShortcuts>,
|
||||
#[serde(default)]
|
||||
pub composing: Option<ComposingShortcuts>,
|
||||
#[serde(alias = "compact-listing")]
|
||||
#[serde(default)]
|
||||
pub compact_listing: Option<CompactListingShortcuts>,
|
||||
#[serde(alias = "contact-list")]
|
||||
#[serde(default)]
|
||||
pub contact_list: Option<ContactListShortcuts>,
|
||||
#[serde(alias = "envelope-view")]
|
||||
#[serde(default)]
|
||||
pub envelope_view: Option<EnvelopeViewShortcuts>,
|
||||
#[serde(alias = "thread-view")]
|
||||
#[serde(default)]
|
||||
pub thread_view: Option<ThreadViewShortcuts>,
|
||||
#[serde(default)]
|
||||
pub pager: Option<PagerShortcuts>,
|
||||
}
|
||||
impl Default for ShortcutsOverride {
|
||||
fn default() -> Self {
|
||||
ShortcutsOverride {
|
||||
general: None,
|
||||
listing: None,
|
||||
composing: None,
|
||||
compact_listing: None,
|
||||
contact_list: None,
|
||||
envelope_view: None,
|
||||
thread_view: None,
|
||||
pager: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ComposingSettingsOverride {
|
||||
#[doc = " A command to pipe new emails to"]
|
||||
#[doc = " Required"]
|
||||
#[serde(default)]
|
||||
pub mailer_cmd: Option<String>,
|
||||
#[doc = " Command to launch editor. Can have arguments. Draft filename is given as the last argument. If it's missing, the environment variable $EDITOR is looked up."]
|
||||
#[serde(alias = "editor-cmd")]
|
||||
#[serde(default)]
|
||||
pub editor_cmd: Option<Option<String>>,
|
||||
#[doc = " Embed editor (for terminal interfaces) instead of forking and waiting."]
|
||||
#[serde(default)]
|
||||
pub embed: Option<bool>,
|
||||
#[doc = " Set \"format=flowed\" in plain text attachments."]
|
||||
#[doc = " Default: true"]
|
||||
#[serde(alias = "format-flowed")]
|
||||
#[serde(default)]
|
||||
pub format_flowed: Option<bool>,
|
||||
#[doc = " Set default header values for new drafts"]
|
||||
#[doc = " Default: empty"]
|
||||
#[serde(alias = "default-header-values")]
|
||||
#[serde(default)]
|
||||
pub default_header_values: Option<HashMap<String, String>>,
|
||||
}
|
||||
impl Default for ComposingSettingsOverride {
|
||||
fn default() -> Self {
|
||||
ComposingSettingsOverride {
|
||||
mailer_cmd: None,
|
||||
editor_cmd: None,
|
||||
embed: None,
|
||||
format_flowed: None,
|
||||
default_header_values: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct TagsSettingsOverride {
|
||||
#[serde(deserialize_with = "tag_color_de")]
|
||||
#[serde(default)]
|
||||
pub colors: Option<HashMap<u64, Color>>,
|
||||
#[serde(deserialize_with = "tag_set_de", alias = "ignore-tags")]
|
||||
#[serde(default)]
|
||||
pub ignore_tags: Option<HashSet<u64>>,
|
||||
}
|
||||
impl Default for TagsSettingsOverride {
|
||||
fn default() -> Self {
|
||||
TagsSettingsOverride {
|
||||
colors: None,
|
||||
ignore_tags: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct PGPSettingsOverride {
|
||||
#[doc = " auto verify signed e-mail according to RFC3156"]
|
||||
#[serde(alias = "auto-verify-signatures")]
|
||||
#[serde(default)]
|
||||
pub auto_verify_signatures: Option<bool>,
|
||||
#[doc = " always sign sent messages"]
|
||||
#[serde(alias = "auto-sign")]
|
||||
#[serde(default)]
|
||||
pub auto_sign: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub key: Option<Option<String>>,
|
||||
#[doc = " gpg binary name or file location to use"]
|
||||
#[serde(alias = "gpg-binary")]
|
||||
#[serde(default)]
|
||||
pub gpg_binary: Option<Option<String>>,
|
||||
}
|
||||
impl Default for PGPSettingsOverride {
|
||||
fn default() -> Self {
|
||||
PGPSettingsOverride {
|
||||
auto_verify_signatures: None,
|
||||
auto_sign: None,
|
||||
key: None,
|
||||
gpg_binary: None,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue