mirror of
https://github.com/girlbossceo/conduwuit.git
synced 2025-03-14 18:55:37 +00:00
generate fmt::Display for Config
Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
parent
dda27ffcb1
commit
9ab381e4eb
3 changed files with 63 additions and 435 deletions
|
@ -22,8 +22,8 @@ pub(super) async fn uptime(&self) -> Result<RoomMessageEventContent> {
|
|||
pub(super) async fn show_config(&self) -> Result<RoomMessageEventContent> {
|
||||
// Construct and send the response
|
||||
Ok(RoomMessageEventContent::text_markdown(format!(
|
||||
"```\n{}\n```",
|
||||
self.services.globals.config
|
||||
"{}",
|
||||
self.services.server.config
|
||||
)))
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ pub mod proxy;
|
|||
|
||||
use std::{
|
||||
collections::{BTreeMap, BTreeSet, HashSet},
|
||||
fmt,
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
@ -15,7 +14,6 @@ use either::{
|
|||
};
|
||||
use figment::providers::{Env, Format, Toml};
|
||||
pub use figment::{value::Value as FigmentValue, Figment};
|
||||
use itertools::Itertools;
|
||||
use regex::RegexSet;
|
||||
use ruma::{
|
||||
api::client::discovery::discover_support::ContactRole, OwnedRoomOrAliasId, OwnedServerName,
|
||||
|
@ -1859,405 +1857,6 @@ impl Config {
|
|||
pub fn check(&self) -> Result<(), Error> { check(self) }
|
||||
}
|
||||
|
||||
impl fmt::Display for Config {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(f, "Active config values:\n").expect("wrote line to formatter stream");
|
||||
let mut line = |key: &str, val: &str| {
|
||||
writeln!(f, "{key}: {val}").expect("wrote line to formatter stream");
|
||||
};
|
||||
|
||||
line("Server name", self.server_name.host());
|
||||
line("Database path", &self.database_path.to_string_lossy());
|
||||
line(
|
||||
"Database backup path",
|
||||
self.database_backup_path
|
||||
.as_ref()
|
||||
.map_or("", |path| path.to_str().unwrap_or("")),
|
||||
);
|
||||
line("Database backups to keep", &self.database_backups_to_keep.to_string());
|
||||
line("Database cache capacity (MB)", &self.db_cache_capacity_mb.to_string());
|
||||
line("Cache capacity modifier", &self.cache_capacity_modifier.to_string());
|
||||
line("PDU cache capacity", &self.pdu_cache_capacity.to_string());
|
||||
line("Auth chain cache capacity", &self.auth_chain_cache_capacity.to_string());
|
||||
line("Short eventid cache capacity", &self.shorteventid_cache_capacity.to_string());
|
||||
line("Eventid short cache capacity", &self.eventidshort_cache_capacity.to_string());
|
||||
line("Short statekey cache capacity", &self.shortstatekey_cache_capacity.to_string());
|
||||
line("Statekey short cache capacity", &self.statekeyshort_cache_capacity.to_string());
|
||||
line(
|
||||
"Server visibility cache capacity",
|
||||
&self.server_visibility_cache_capacity.to_string(),
|
||||
);
|
||||
line(
|
||||
"User visibility cache capacity",
|
||||
&self.user_visibility_cache_capacity.to_string(),
|
||||
);
|
||||
line("Stateinfo cache capacity", &self.stateinfo_cache_capacity.to_string());
|
||||
line(
|
||||
"Roomid space hierarchy cache capacity",
|
||||
&self.roomid_spacehierarchy_cache_capacity.to_string(),
|
||||
);
|
||||
line("DNS cache entry limit", &self.dns_cache_entries.to_string());
|
||||
line("DNS minimum TTL", &self.dns_min_ttl.to_string());
|
||||
line("DNS minimum NXDOMAIN TTL", &self.dns_min_ttl_nxdomain.to_string());
|
||||
line("DNS attempts", &self.dns_attempts.to_string());
|
||||
line("DNS timeout", &self.dns_timeout.to_string());
|
||||
line("DNS fallback to TCP", &self.dns_tcp_fallback.to_string());
|
||||
line("DNS query over TCP only", &self.query_over_tcp_only.to_string());
|
||||
line("Query all nameservers", &self.query_all_nameservers.to_string());
|
||||
line("Maximum request size (bytes)", &self.max_request_size.to_string());
|
||||
line("Sender retry backoff limit", &self.sender_retry_backoff_limit.to_string());
|
||||
line("Request connect timeout", &self.request_conn_timeout.to_string());
|
||||
line("Request timeout", &self.request_timeout.to_string());
|
||||
line("Request total timeout", &self.request_total_timeout.to_string());
|
||||
line("Idle connections per host", &self.request_idle_per_host.to_string());
|
||||
line("Request pool idle timeout", &self.request_idle_timeout.to_string());
|
||||
line("Well_known connect timeout", &self.well_known_conn_timeout.to_string());
|
||||
line("Well_known timeout", &self.well_known_timeout.to_string());
|
||||
line("Federation timeout", &self.federation_timeout.to_string());
|
||||
line("Federation pool idle per host", &self.federation_idle_per_host.to_string());
|
||||
line("Federation pool idle timeout", &self.federation_idle_timeout.to_string());
|
||||
line("Sender timeout", &self.sender_timeout.to_string());
|
||||
line("Sender pool idle timeout", &self.sender_idle_timeout.to_string());
|
||||
line("Appservice timeout", &self.appservice_timeout.to_string());
|
||||
line("Appservice pool idle timeout", &self.appservice_idle_timeout.to_string());
|
||||
line("Pusher pool idle timeout", &self.pusher_idle_timeout.to_string());
|
||||
line("Allow registration", &self.allow_registration.to_string());
|
||||
line(
|
||||
"Registration token",
|
||||
if self.registration_token.is_none()
|
||||
&& self.registration_token_file.is_none()
|
||||
&& self.allow_registration
|
||||
{
|
||||
"not set (⚠️ open registration!)"
|
||||
} else if self.registration_token.is_none() && self.registration_token_file.is_none()
|
||||
{
|
||||
"not set"
|
||||
} else {
|
||||
"set"
|
||||
},
|
||||
);
|
||||
line(
|
||||
"Registration token file path",
|
||||
self.registration_token_file
|
||||
.as_ref()
|
||||
.map_or("", |path| path.to_str().unwrap_or_default()),
|
||||
);
|
||||
line(
|
||||
"Allow guest registration (inherently false if allow registration is false)",
|
||||
&self.allow_guest_registration.to_string(),
|
||||
);
|
||||
line(
|
||||
"Log guest registrations in admin room",
|
||||
&self.log_guest_registrations.to_string(),
|
||||
);
|
||||
line(
|
||||
"Allow guests to auto join rooms",
|
||||
&self.allow_guests_auto_join_rooms.to_string(),
|
||||
);
|
||||
line("New user display name suffix", &self.new_user_displayname_suffix);
|
||||
line("Allow encryption", &self.allow_encryption.to_string());
|
||||
line("Allow federation", &self.allow_federation.to_string());
|
||||
line("Federation loopback", &self.federation_loopback.to_string());
|
||||
line(
|
||||
"Require authentication for profile requests",
|
||||
&self.require_auth_for_profile_requests.to_string(),
|
||||
);
|
||||
line(
|
||||
"Allow incoming federated presence requests (updates)",
|
||||
&self.allow_incoming_presence.to_string(),
|
||||
);
|
||||
line(
|
||||
"Allow outgoing federated presence requests (updates)",
|
||||
&self.allow_outgoing_presence.to_string(),
|
||||
);
|
||||
line(
|
||||
"Allow local presence requests (updates)",
|
||||
&self.allow_local_presence.to_string(),
|
||||
);
|
||||
line(
|
||||
"Allow incoming remote read receipts",
|
||||
&self.allow_incoming_read_receipts.to_string(),
|
||||
);
|
||||
line(
|
||||
"Allow outgoing remote read receipts",
|
||||
&self.allow_outgoing_read_receipts.to_string(),
|
||||
);
|
||||
line(
|
||||
"Block non-admin room invites (local and remote, admins can still send and receive \
|
||||
invites)",
|
||||
&self.block_non_admin_invites.to_string(),
|
||||
);
|
||||
line("Enable admin escape commands", &self.admin_escape_commands.to_string());
|
||||
line(
|
||||
"Activate admin console after startup",
|
||||
&self.admin_console_automatic.to_string(),
|
||||
);
|
||||
line("Execute admin commands after startup", &self.admin_execute.join(", "));
|
||||
line(
|
||||
"Continue startup even if some commands fail",
|
||||
&self.admin_execute_errors_ignore.to_string(),
|
||||
);
|
||||
line("Filter for admin command log capture", &self.admin_log_capture);
|
||||
line("Admin room tag", &self.admin_room_tag);
|
||||
line("Allow outgoing federated typing", &self.allow_outgoing_typing.to_string());
|
||||
line("Allow incoming federated typing", &self.allow_incoming_typing.to_string());
|
||||
line(
|
||||
"Incoming federated typing timeout",
|
||||
&self.typing_federation_timeout_s.to_string(),
|
||||
);
|
||||
line("Client typing timeout minimum", &self.typing_client_timeout_min_s.to_string());
|
||||
line("Client typing timeout maxmimum", &self.typing_client_timeout_max_s.to_string());
|
||||
line("Allow device name federation", &self.allow_device_name_federation.to_string());
|
||||
line(
|
||||
"Allow incoming profile lookup federation requests",
|
||||
&self
|
||||
.allow_inbound_profile_lookup_federation_requests
|
||||
.to_string(),
|
||||
);
|
||||
line(
|
||||
"Auto deactivate banned room join attempts",
|
||||
&self.auto_deactivate_banned_room_attempts.to_string(),
|
||||
);
|
||||
line("Notification push path", &self.notification_push_path);
|
||||
line("Allow room creation", &self.allow_room_creation.to_string());
|
||||
line(
|
||||
"Allow public room directory over federation",
|
||||
&self.allow_public_room_directory_over_federation.to_string(),
|
||||
);
|
||||
line(
|
||||
"Allow public room directory without authentication",
|
||||
&self.allow_public_room_directory_without_auth.to_string(),
|
||||
);
|
||||
line(
|
||||
"Lockdown public room directory (only allow admins to publish)",
|
||||
&self.lockdown_public_room_directory.to_string(),
|
||||
);
|
||||
line(
|
||||
"Trusted key servers",
|
||||
&self
|
||||
.trusted_servers
|
||||
.iter()
|
||||
.map(|server| server.host())
|
||||
.join(", "),
|
||||
);
|
||||
line("OpenID Token TTL", &self.openid_token_ttl.to_string());
|
||||
line(
|
||||
"TURN username",
|
||||
if self.turn_username.is_empty() {
|
||||
"not set"
|
||||
} else {
|
||||
&self.turn_username
|
||||
},
|
||||
);
|
||||
line("TURN password", {
|
||||
if self.turn_password.is_empty() {
|
||||
"not set"
|
||||
} else {
|
||||
"set"
|
||||
}
|
||||
});
|
||||
line("TURN secret", {
|
||||
if self.turn_secret.is_empty() && self.turn_secret_file.is_none() {
|
||||
"not set"
|
||||
} else {
|
||||
"set"
|
||||
}
|
||||
});
|
||||
line("TURN secret file path", {
|
||||
self.turn_secret_file
|
||||
.as_ref()
|
||||
.map_or("", |path| path.to_str().unwrap_or_default())
|
||||
});
|
||||
line("Turn TTL", &self.turn_ttl.to_string());
|
||||
line("Turn URIs", {
|
||||
let mut lst = Vec::with_capacity(self.turn_uris.len());
|
||||
for item in self.turn_uris.iter().cloned().enumerate() {
|
||||
let (_, uri): (usize, String) = item;
|
||||
lst.push(uri);
|
||||
}
|
||||
&lst.join(", ")
|
||||
});
|
||||
line("Auto Join Rooms", {
|
||||
let mut lst = Vec::with_capacity(self.auto_join_rooms.len());
|
||||
for room in &self.auto_join_rooms {
|
||||
lst.push(room);
|
||||
}
|
||||
&lst.into_iter().join(", ")
|
||||
});
|
||||
line("Zstd HTTP Compression", &self.zstd_compression.to_string());
|
||||
line("Gzip HTTP Compression", &self.gzip_compression.to_string());
|
||||
line("Brotli HTTP Compression", &self.brotli_compression.to_string());
|
||||
line("RocksDB database LOG level", &self.rocksdb_log_level);
|
||||
line("RocksDB database LOG to stderr", &self.rocksdb_log_stderr.to_string());
|
||||
line("RocksDB database LOG time-to-roll", &self.rocksdb_log_time_to_roll.to_string());
|
||||
line("RocksDB Max LOG Files", &self.rocksdb_max_log_files.to_string());
|
||||
line(
|
||||
"RocksDB database max LOG file size",
|
||||
&self.rocksdb_max_log_file_size.to_string(),
|
||||
);
|
||||
line(
|
||||
"RocksDB database optimize for spinning disks",
|
||||
&self.rocksdb_optimize_for_spinning_disks.to_string(),
|
||||
);
|
||||
line("RocksDB Direct-IO", &self.rocksdb_direct_io.to_string());
|
||||
line("RocksDB Parallelism Threads", &self.rocksdb_parallelism_threads.to_string());
|
||||
line("RocksDB Compression Algorithm", &self.rocksdb_compression_algo);
|
||||
line("RocksDB Compression Level", &self.rocksdb_compression_level.to_string());
|
||||
line(
|
||||
"RocksDB Bottommost Compression Level",
|
||||
&self.rocksdb_bottommost_compression_level.to_string(),
|
||||
);
|
||||
line(
|
||||
"RocksDB Bottommost Level Compression",
|
||||
&self.rocksdb_bottommost_compression.to_string(),
|
||||
);
|
||||
line("RocksDB Recovery Mode", &self.rocksdb_recovery_mode.to_string());
|
||||
line("RocksDB Repair Mode", &self.rocksdb_repair.to_string());
|
||||
line("RocksDB Read-only Mode", &self.rocksdb_read_only.to_string());
|
||||
line("RocksDB Secondary Mode", &self.rocksdb_secondary.to_string());
|
||||
line(
|
||||
"RocksDB Compaction Idle Priority",
|
||||
&self.rocksdb_compaction_prio_idle.to_string(),
|
||||
);
|
||||
line(
|
||||
"RocksDB Compaction Idle IOPriority",
|
||||
&self.rocksdb_compaction_ioprio_idle.to_string(),
|
||||
);
|
||||
line("RocksDB Compaction enabled", &self.rocksdb_compaction.to_string());
|
||||
line("RocksDB Statistics level", &self.rocksdb_stats_level.to_string());
|
||||
line("Media integrity checks on startup", &self.media_startup_check.to_string());
|
||||
line("Media compatibility filesystem links", &self.media_compat_file_link.to_string());
|
||||
line("Prune missing media from database", &self.prune_missing_media.to_string());
|
||||
line("Allow legacy (unauthenticated) media", &self.allow_legacy_media.to_string());
|
||||
line("Freeze legacy (unauthenticated) media", &self.freeze_legacy_media.to_string());
|
||||
line("Prevent Media Downloads From", {
|
||||
let mut lst = Vec::with_capacity(self.prevent_media_downloads_from.len());
|
||||
for domain in &self.prevent_media_downloads_from {
|
||||
lst.push(domain.host());
|
||||
}
|
||||
&lst.join(", ")
|
||||
});
|
||||
line("Forbidden Remote Server Names (\"Global\" ACLs)", {
|
||||
let mut lst = Vec::with_capacity(self.forbidden_remote_server_names.len());
|
||||
for domain in &self.forbidden_remote_server_names {
|
||||
lst.push(domain.host());
|
||||
}
|
||||
&lst.join(", ")
|
||||
});
|
||||
line("Forbidden Remote Room Directory Server Names", {
|
||||
let mut lst =
|
||||
Vec::with_capacity(self.forbidden_remote_room_directory_server_names.len());
|
||||
for domain in &self.forbidden_remote_room_directory_server_names {
|
||||
lst.push(domain.host());
|
||||
}
|
||||
&lst.join(", ")
|
||||
});
|
||||
line("Outbound Request IP Range (CIDR) Denylist", {
|
||||
let mut lst = Vec::with_capacity(self.ip_range_denylist.len());
|
||||
for item in self.ip_range_denylist.iter().cloned().enumerate() {
|
||||
let (_, ip): (usize, String) = item;
|
||||
lst.push(ip);
|
||||
}
|
||||
&lst.join(", ")
|
||||
});
|
||||
line("Forbidden usernames", {
|
||||
&self.forbidden_usernames.patterns().iter().join(", ")
|
||||
});
|
||||
line("Forbidden room aliases", {
|
||||
&self.forbidden_alias_names.patterns().iter().join(", ")
|
||||
});
|
||||
line(
|
||||
"URL preview bound interface",
|
||||
self.url_preview_bound_interface
|
||||
.as_ref()
|
||||
.map(Either::as_ref)
|
||||
.map(|either| either.map_left(ToString::to_string))
|
||||
.map(Either::either_into::<String>)
|
||||
.unwrap_or_default()
|
||||
.as_str(),
|
||||
);
|
||||
line(
|
||||
"URL preview domain contains allowlist",
|
||||
&self.url_preview_domain_contains_allowlist.join(", "),
|
||||
);
|
||||
line(
|
||||
"URL preview domain explicit allowlist",
|
||||
&self.url_preview_domain_explicit_allowlist.join(", "),
|
||||
);
|
||||
line(
|
||||
"URL preview domain explicit denylist",
|
||||
&self.url_preview_domain_explicit_denylist.join(", "),
|
||||
);
|
||||
line(
|
||||
"URL preview URL contains allowlist",
|
||||
&self.url_preview_url_contains_allowlist.join(", "),
|
||||
);
|
||||
line("URL preview maximum spider size", &self.url_preview_max_spider_size.to_string());
|
||||
line("URL preview check root domain", &self.url_preview_check_root_domain.to_string());
|
||||
line(
|
||||
"Allow check for updates / announcements check",
|
||||
&self.allow_check_for_updates.to_string(),
|
||||
);
|
||||
line("Enable netburst on startup", &self.startup_netburst.to_string());
|
||||
#[cfg(feature = "sentry_telemetry")]
|
||||
line("Sentry.io reporting and tracing", &self.sentry.to_string());
|
||||
#[cfg(feature = "sentry_telemetry")]
|
||||
line("Sentry.io send server_name in logs", &self.sentry_send_server_name.to_string());
|
||||
#[cfg(feature = "sentry_telemetry")]
|
||||
line("Sentry.io tracing sample rate", &self.sentry_traces_sample_rate.to_string());
|
||||
line("Sentry.io attach stacktrace", &self.sentry_attach_stacktrace.to_string());
|
||||
line("Sentry.io send panics", &self.sentry_send_panic.to_string());
|
||||
line("Sentry.io send errors", &self.sentry_send_error.to_string());
|
||||
line("Sentry.io tracing filter", &self.sentry_filter);
|
||||
line(
|
||||
"Well-known server name",
|
||||
self.well_known
|
||||
.server
|
||||
.as_ref()
|
||||
.map_or("", |server| server.as_str()),
|
||||
);
|
||||
line(
|
||||
"Well-known client URL",
|
||||
self.well_known
|
||||
.client
|
||||
.as_ref()
|
||||
.map_or("", |url| url.as_str()),
|
||||
);
|
||||
line(
|
||||
"Well-known support email",
|
||||
self.well_known
|
||||
.support_email
|
||||
.as_ref()
|
||||
.map_or("", |str| str.as_ref()),
|
||||
);
|
||||
line(
|
||||
"Well-known support Matrix ID",
|
||||
self.well_known
|
||||
.support_mxid
|
||||
.as_ref()
|
||||
.map_or("", |mxid| mxid.as_str()),
|
||||
);
|
||||
line(
|
||||
"Well-known support role",
|
||||
self.well_known
|
||||
.support_role
|
||||
.as_ref()
|
||||
.map_or("", |role| role.as_str()),
|
||||
);
|
||||
line(
|
||||
"Well-known support page/URL",
|
||||
self.well_known
|
||||
.support_page
|
||||
.as_ref()
|
||||
.map_or("", |url| url.as_str()),
|
||||
);
|
||||
line("Enable the tokio-console", &self.tokio_console.to_string());
|
||||
line("Admin room notices", &self.admin_room_notices.to_string());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn true_fn() -> bool { true }
|
||||
|
||||
fn default_address() -> ListeningAddr {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::{collections::HashSet, fmt::Write as _, fs::OpenOptions, io::Write as _};
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::Span;
|
||||
use quote::ToTokens;
|
||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{
|
||||
parse::Parser, punctuated::Punctuated, spanned::Spanned, Error, Expr, ExprLit, Field, Fields,
|
||||
FieldsNamed, ItemStruct, Lit, Meta, MetaList, MetaNameValue, Type, TypePath,
|
||||
|
@ -19,18 +19,24 @@ const HIDDEN: &[&str] = &["default"];
|
|||
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub(super) fn example_generator(input: ItemStruct, args: &[Meta]) -> Result<TokenStream> {
|
||||
if is_cargo_build() && !is_cargo_test() {
|
||||
generate_example(&input, args)?;
|
||||
}
|
||||
let write = is_cargo_build() && !is_cargo_test();
|
||||
let additional = generate_example(&input, args, write)?;
|
||||
|
||||
Ok(input.to_token_stream().into())
|
||||
Ok([input.to_token_stream(), additional]
|
||||
.into_iter()
|
||||
.collect::<TokenStream2>()
|
||||
.into())
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
#[allow(unused_variables)]
|
||||
fn generate_example(input: &ItemStruct, args: &[Meta]) -> Result<()> {
|
||||
fn generate_example(input: &ItemStruct, args: &[Meta], write: bool) -> Result<TokenStream2> {
|
||||
let settings = get_simple_settings(args);
|
||||
|
||||
let section = settings.get("section").ok_or_else(|| {
|
||||
Error::new(args[0].span(), "missing required 'section' attribute argument")
|
||||
})?;
|
||||
|
||||
let filename = settings.get("filename").ok_or_else(|| {
|
||||
Error::new(args[0].span(), "missing required 'filename' attribute argument")
|
||||
})?;
|
||||
|
@ -45,31 +51,33 @@ fn generate_example(input: &ItemStruct, args: &[Meta]) -> Result<()> {
|
|||
.split(' ')
|
||||
.collect();
|
||||
|
||||
let section = settings.get("section").ok_or_else(|| {
|
||||
Error::new(args[0].span(), "missing required 'section' attribute argument")
|
||||
})?;
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
let fopts = OpenOptions::new()
|
||||
.write(true)
|
||||
.create(section == "global")
|
||||
.truncate(section == "global")
|
||||
.append(section != "global")
|
||||
.open(filename)
|
||||
.map_err(|e| {
|
||||
Error::new(
|
||||
Span::call_site(),
|
||||
format!("Failed to open config file for generation: {e}"),
|
||||
)
|
||||
})?;
|
||||
.clone();
|
||||
|
||||
if let Some(header) = settings.get("header") {
|
||||
file.write_all(header.as_bytes())
|
||||
let mut file = write
|
||||
.then(|| {
|
||||
fopts.open(filename).map_err(|e| {
|
||||
let msg = format!("Failed to open file for config generation: {e}");
|
||||
Error::new(Span::call_site(), msg)
|
||||
})
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
if let Some(file) = file.as_mut() {
|
||||
if let Some(header) = settings.get("header") {
|
||||
file.write_all(header.as_bytes())
|
||||
.expect("written to config file");
|
||||
}
|
||||
|
||||
file.write_fmt(format_args!("\n[{section}]\n"))
|
||||
.expect("written to config file");
|
||||
}
|
||||
|
||||
file.write_fmt(format_args!("\n[{section}]\n"))
|
||||
.expect("written to config file");
|
||||
|
||||
let mut summary: Vec<TokenStream2> = Vec::new();
|
||||
if let Fields::Named(FieldsNamed { named, .. }) = &input.fields {
|
||||
for field in named {
|
||||
let Some(ident) = &field.ident else {
|
||||
|
@ -105,20 +113,41 @@ fn generate_example(input: &ItemStruct, args: &[Meta]) -> Result<()> {
|
|||
default
|
||||
};
|
||||
|
||||
file.write_fmt(format_args!("\n{doc}"))
|
||||
.expect("written to config file");
|
||||
if let Some(file) = file.as_mut() {
|
||||
file.write_fmt(format_args!("\n{doc}"))
|
||||
.expect("written to config file");
|
||||
|
||||
file.write_fmt(format_args!("#{ident} ={default}\n"))
|
||||
file.write_fmt(format_args!("#{ident} ={default}\n"))
|
||||
.expect("written to config file");
|
||||
}
|
||||
|
||||
let name = ident.to_string();
|
||||
summary.push(quote! {
|
||||
writeln!(out, "| {} | {:?} |", #name, self.#ident)?;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(file) = file.as_mut() {
|
||||
if let Some(footer) = settings.get("footer") {
|
||||
file.write_all(footer.as_bytes())
|
||||
.expect("written to config file");
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(footer) = settings.get("footer") {
|
||||
file.write_all(footer.as_bytes())
|
||||
.expect("written to config file");
|
||||
}
|
||||
let struct_name = &input.ident;
|
||||
let display = quote! {
|
||||
impl std::fmt::Display for #struct_name {
|
||||
fn fmt(&self, out: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(out, "| name | value |")?;
|
||||
writeln!(out, "| :--- | :--- |")?;
|
||||
#( #summary )*
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
Ok(display)
|
||||
}
|
||||
|
||||
fn get_default(field: &Field) -> Option<String> {
|
||||
|
|
Loading…
Add table
Reference in a new issue