Auto-derive Default for KeyGroups
This commit is contained in:
parent
f3efff68f5
commit
03c7fb567c
4 changed files with 63 additions and 151 deletions
|
|
@ -132,19 +132,6 @@ pub struct General {
|
|||
pub log: KeyBinding,
|
||||
}
|
||||
|
||||
impl Default for General {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
exit: default::general::exit(),
|
||||
abort: default::general::abort(),
|
||||
confirm: default::general::confirm(),
|
||||
focus: default::general::focus(),
|
||||
help: default::general::help(),
|
||||
log: default::general::log(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Document, KeyGroup)]
|
||||
pub struct Scroll {
|
||||
/// Scroll up one line.
|
||||
|
|
@ -170,20 +157,6 @@ pub struct Scroll {
|
|||
pub center_cursor: KeyBinding,
|
||||
}
|
||||
|
||||
impl Default for Scroll {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
up_line: default::scroll::up_line(),
|
||||
down_line: default::scroll::down_line(),
|
||||
up_half: default::scroll::up_half(),
|
||||
down_half: default::scroll::down_half(),
|
||||
up_full: default::scroll::up_full(),
|
||||
down_full: default::scroll::down_full(),
|
||||
center_cursor: default::scroll::center_cursor(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Document, KeyGroup)]
|
||||
pub struct Cursor {
|
||||
/// Move up.
|
||||
|
|
@ -200,17 +173,6 @@ pub struct Cursor {
|
|||
pub to_bottom: KeyBinding,
|
||||
}
|
||||
|
||||
impl Default for Cursor {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
up: default::cursor::up(),
|
||||
down: default::cursor::down(),
|
||||
to_top: default::cursor::to_top(),
|
||||
to_bottom: default::cursor::to_bottom(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Document, KeyGroup)]
|
||||
pub struct EditorCursor {
|
||||
/// Move left.
|
||||
|
|
@ -239,21 +201,6 @@ pub struct EditorCursor {
|
|||
pub down: KeyBinding,
|
||||
}
|
||||
|
||||
impl Default for EditorCursor {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
left: default::editor_cursor::left(),
|
||||
right: default::editor_cursor::right(),
|
||||
left_word: default::editor_cursor::left_word(),
|
||||
right_word: default::editor_cursor::right_word(),
|
||||
start: default::editor_cursor::start(),
|
||||
end: default::editor_cursor::end(),
|
||||
up: default::editor_cursor::up(),
|
||||
down: default::editor_cursor::down(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Document, KeyGroup)]
|
||||
pub struct EditorAction {
|
||||
/// Delete before cursor.
|
||||
|
|
@ -270,17 +217,6 @@ pub struct EditorAction {
|
|||
pub external: KeyBinding,
|
||||
}
|
||||
|
||||
impl Default for EditorAction {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
backspace: default::editor_action::backspace(),
|
||||
delete: default::editor_action::delete(),
|
||||
clear: default::editor_action::clear(),
|
||||
external: default::editor_action::external(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Document)]
|
||||
pub struct Editor {
|
||||
#[serde(default)]
|
||||
|
|
@ -323,22 +259,6 @@ pub struct RoomsAction {
|
|||
pub change_sort_order: KeyBinding,
|
||||
}
|
||||
|
||||
impl Default for RoomsAction {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
connect: default::rooms_action::connect(),
|
||||
connect_all: default::rooms_action::connect_all(),
|
||||
disconnect: default::rooms_action::disconnect(),
|
||||
disconnect_all: default::rooms_action::disconnect_all(),
|
||||
connect_autojoin: default::rooms_action::connect_autojoin(),
|
||||
disconnect_non_autojoin: default::rooms_action::disconnect_non_autojoin(),
|
||||
new: default::rooms_action::new(),
|
||||
delete: default::rooms_action::delete(),
|
||||
change_sort_order: default::rooms_action::change_sort_order(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Document)]
|
||||
pub struct Rooms {
|
||||
#[serde(default)]
|
||||
|
|
@ -365,18 +285,6 @@ pub struct RoomAction {
|
|||
pub present: KeyBinding,
|
||||
}
|
||||
|
||||
impl Default for RoomAction {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
authenticate: default::room_action::authenticate(),
|
||||
account: default::room_action::account(),
|
||||
nick: default::room_action::nick(),
|
||||
more_messages: default::room_action::more_messages(),
|
||||
present: default::room_action::present(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Document)]
|
||||
pub struct Room {
|
||||
#[serde(default)]
|
||||
|
|
@ -413,21 +321,6 @@ pub struct TreeCursor {
|
|||
// TODO Bindings inspired by vim's ()/[]/{} bindings?
|
||||
}
|
||||
|
||||
impl Default for TreeCursor {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
to_above_sibling: default::tree_cursor::to_above_sibling(),
|
||||
to_below_sibling: default::tree_cursor::to_below_sibling(),
|
||||
to_parent: default::tree_cursor::to_parent(),
|
||||
to_root: default::tree_cursor::to_root(),
|
||||
to_older_message: default::tree_cursor::to_older_message(),
|
||||
to_newer_message: default::tree_cursor::to_newer_message(),
|
||||
to_older_unseen_message: default::tree_cursor::to_older_unseen_message(),
|
||||
to_newer_unseen_message: default::tree_cursor::to_newer_unseen_message(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Split up in "message", "nicklist", "room"?
|
||||
#[derive(Debug, Deserialize, Document, KeyGroup)]
|
||||
pub struct TreeAction {
|
||||
|
|
@ -460,22 +353,6 @@ pub struct TreeAction {
|
|||
pub links: KeyBinding,
|
||||
}
|
||||
|
||||
impl Default for TreeAction {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
reply: default::tree_action::reply(),
|
||||
reply_alternate: default::tree_action::reply_alternate(),
|
||||
new_thread: default::tree_action::new_thread(),
|
||||
fold_tree: default::tree_action::fold_tree(),
|
||||
toggle_seen: default::tree_action::toggle_seen(),
|
||||
mark_visible_seen: default::tree_action::mark_visible_seen(),
|
||||
mark_older_seen: default::tree_action::mark_older_seen(),
|
||||
inspect: default::tree_action::info(),
|
||||
links: default::tree_action::links(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Document)]
|
||||
pub struct Tree {
|
||||
#[serde(default)]
|
||||
|
|
|
|||
|
|
@ -1,14 +1,9 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{Data, DataEnum, DataStruct, DeriveInput, ExprPath, Field, Ident, LitStr, Type};
|
||||
use syn::{Data, DataEnum, DataStruct, DeriveInput, Field, Ident, LitStr};
|
||||
|
||||
use crate::util;
|
||||
|
||||
enum SerdeDefault {
|
||||
Default(Type),
|
||||
Path(ExprPath),
|
||||
}
|
||||
use crate::util::{self, SerdeDefault};
|
||||
|
||||
#[derive(Default)]
|
||||
struct FieldInfo {
|
||||
|
|
@ -53,17 +48,7 @@ impl FieldInfo {
|
|||
}
|
||||
|
||||
// Find `#[serde(default)]` or `#[serde(default = "bla")]`.
|
||||
for arg in util::attribute_arguments(field, "serde")? {
|
||||
if arg.path.is_ident("default") {
|
||||
if let Some(value) = arg.value {
|
||||
if let Some(path) = util::into_litstr(value) {
|
||||
self.serde_default = Some(SerdeDefault::Path(path.parse()?));
|
||||
}
|
||||
} else {
|
||||
self.serde_default = Some(SerdeDefault::Default(field.ty.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
self.serde_default = util::serde_default(field)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -102,13 +87,9 @@ fn from_struct(ident: Ident, data: DataStruct) -> syn::Result<TokenStream> {
|
|||
doc.value_info.default = Some(#default.to_string());
|
||||
});
|
||||
} else if let Some(serde_default) = info.serde_default {
|
||||
setters.push(match serde_default {
|
||||
SerdeDefault::Default(ty) => quote! {
|
||||
doc.value_info.default = Some(crate::doc::toml_value_as_markdown(&<#ty as Default>::default()));
|
||||
},
|
||||
SerdeDefault::Path(path) => quote! {
|
||||
doc.value_info.default = Some(crate::doc::toml_value_as_markdown(&#path()));
|
||||
},
|
||||
let value = serde_default.value();
|
||||
setters.push(quote! {
|
||||
doc.value_info.default = Some(crate::doc::toml_value_as_markdown(&#value));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use quote::quote;
|
|||
use syn::spanned::Spanned;
|
||||
use syn::{Data, DeriveInput};
|
||||
|
||||
use crate::util;
|
||||
use crate::util::{self, bail};
|
||||
|
||||
fn decapitalize(s: &str) -> String {
|
||||
let mut chars = s.chars();
|
||||
|
|
@ -20,15 +20,26 @@ pub fn derive_impl(input: DeriveInput) -> syn::Result<TokenStream> {
|
|||
};
|
||||
|
||||
let mut bindings = vec![];
|
||||
let mut defaults = vec![];
|
||||
for field in &data.fields {
|
||||
if let Some(field_ident) = &field.ident {
|
||||
let docstring = util::docstring(field)?;
|
||||
let description = decapitalize(&docstring);
|
||||
let description = description.strip_suffix('.').unwrap_or(&description);
|
||||
|
||||
let default = util::serde_default(field)?;
|
||||
let Some(default) = default else {
|
||||
return bail(field_ident.span(), "must have serde default");
|
||||
};
|
||||
let default_value = default.value();
|
||||
|
||||
bindings.push(quote! {
|
||||
(&self.#field_ident, #description)
|
||||
});
|
||||
|
||||
defaults.push(quote! {
|
||||
#field_ident: #default_value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -41,5 +52,13 @@ pub fn derive_impl(input: DeriveInput) -> syn::Result<TokenStream> {
|
|||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for #ident {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
#( #defaults )*
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use proc_macro2::Span;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::parse::Parse;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::{Expr, ExprLit, Field, Lit, LitStr, Path, Token};
|
||||
use syn::{Expr, ExprLit, ExprPath, Field, Lit, LitStr, Path, Token, Type};
|
||||
|
||||
pub fn bail<T>(span: Span, message: &str) -> syn::Result<T> {
|
||||
Err(syn::Error::new(span, message))
|
||||
|
|
@ -80,3 +81,37 @@ pub fn attribute_arguments(field: &Field, path: &str) -> syn::Result<Vec<Attribu
|
|||
|
||||
Ok(attrs)
|
||||
}
|
||||
|
||||
pub enum SerdeDefault {
|
||||
Default(Type),
|
||||
Path(ExprPath),
|
||||
}
|
||||
|
||||
impl SerdeDefault {
|
||||
pub fn value(&self) -> TokenStream {
|
||||
match self {
|
||||
Self::Default(ty) => quote! {
|
||||
<#ty as Default>::default()
|
||||
},
|
||||
Self::Path(path) => quote! {
|
||||
#path()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Find `#[serde(default)]` or `#[serde(default = "bla")]`.
|
||||
pub fn serde_default(field: &Field) -> syn::Result<Option<SerdeDefault>> {
|
||||
for arg in attribute_arguments(field, "serde")? {
|
||||
if arg.path.is_ident("default") {
|
||||
if let Some(value) = arg.value {
|
||||
if let Some(path) = into_litstr(value) {
|
||||
return Ok(Some(SerdeDefault::Path(path.parse()?)));
|
||||
}
|
||||
} else {
|
||||
return Ok(Some(SerdeDefault::Default(field.ty.clone())));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue