Skip to content

Commit

Permalink
Create macro for compile time spaces string
Browse files Browse the repository at this point in the history
I hate it too
I wasted too much time on another solution that
didn't work because you can't use (constant)
variable values in procedural macros.
I didn't want to waste it all, so I used this
GitHub Copilot macro xddd
It's horrible I know
But I get compile-time, dynamic indent XD
:crying:
  • Loading branch information
fsktom committed Jun 12, 2024
1 parent 8760925 commit ca04384
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 19 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,28 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
- run: cargo check && cd endsong_ui && cargo check
- run: cargo check && cd endsong_ui && cargo check && cd endsong_macros && cargo check

test:
name: Test Suite
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
- run: cargo test --all-features && cd endsong_ui && cargo test --all-features
- run: cargo test --all-features && cd endsong_ui && cargo test --all-features && cd endsong_macros && cargo test --all-features

fmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
- run: cargo fmt --all --check && cd endsong_ui && cargo fmt --all --check
- run: cargo fmt --all --check && cd endsong_ui && cargo fmt --all --check && cd endsong_macros && cargo fmt --all --check

clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
- run: cargo clippy -- --deny warnings && cd endsong_ui && cargo clippy -- --deny warnings
- run: cargo clippy -- --deny warnings && cd endsong_ui && cargo clippy -- --deny warnings && cd endsong_macros && cargo clippy -- --deny warnings
9 changes: 9 additions & 0 deletions endsong_ui/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions endsong_ui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ itertools = "0.13"
textwrap = "0.16"
thiserror = "1.0"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
endsong_macros = { path = "endsong_macros"}

[dev-dependencies]
criterion = "0.5"
Expand Down
47 changes: 47 additions & 0 deletions endsong_ui/endsong_macros/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions endsong_ui/endsong_macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "endsong_macros"
version = "0.1.0"
edition = "2021"

[dependencies]
quote = "1.0"
syn = { version = "2.0", features = ["full"] }

[lib]
proc-macro = true
24 changes: 24 additions & 0 deletions endsong_ui/endsong_macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, LitInt};

#[proc_macro]
/// Generates match arms for creating space strings
pub fn generate_spaces_match(input: TokenStream) -> TokenStream {
let n = parse_macro_input!(input as LitInt);
let n = n.base10_parse::<usize>().unwrap();

let arms = (1..=n).map(|i| {
let spaces = " ".repeat(i);
quote! { #i => #spaces, }
});

let expanded = quote! {
match num {
#( #arms )*
_ => "",
}
};

expanded.into()
}
6 changes: 6 additions & 0 deletions endsong_ui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ pub mod print;
pub mod trace;
pub mod ui;

/// Creates a string with the given number of spaces
#[must_use]
pub const fn spaces(num: usize) -> &'static str {
endsong_macros::generate_spaces_match!(100)
}

/// Prelude containing all the modules,
/// a function for parsing dates, some structs used for printing,
/// and a trait to add a method to [`Duration`][endsong::prelude::Duration]
Expand Down
15 changes: 8 additions & 7 deletions endsong_ui/src/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use endsong::prelude::*;
use itertools::Itertools;
use thiserror::Error;

use crate::spaces;

/// An enum that is among other things used by functions such as
/// [`top()`] and its derivatives to know whether
/// to print top songs ([`Aspect::Songs`]), albums ([`Aspect::Albums`])
Expand Down Expand Up @@ -195,7 +197,7 @@ pub fn aspect(entries: &[SongEntry], asp: &AspectFull) {
match *asp {
AspectFull::Artist(art) => {
println!("{} | {} plays", art, gather::plays(entries, art));
artist(entries, &gather::albums_from_artist(entries, art));
artist(entries, &gather::albums_from_artist(entries, art), 4);
}
AspectFull::Album(alb) => {
println!("{} | {} plays", alb, gather::plays(entries, alb));
Expand All @@ -210,7 +212,7 @@ pub fn aspect(entries: &[SongEntry], asp: &AspectFull) {
/// Prints each [`Album`] of `albums` with the playcount
///
/// Preferably `albums` contains only albums from one artist
fn artist(entries: &[SongEntry], albums: &HashMap<Album, usize>) {
fn artist(entries: &[SongEntry], albums: &HashMap<Album, usize>, indent: usize) {
// albums sorted by their playcount descending (primary)
// and name ascending (secondary) if plays are equal
let albums_vec: Vec<(&Album, &usize)> = albums
Expand All @@ -219,8 +221,8 @@ fn artist(entries: &[SongEntry], albums: &HashMap<Album, usize>) {
.collect_vec();

for (alb, plays) in albums_vec {
println!(" {} | {plays} plays", alb.name);
album(&gather::songs_from(entries, alb), 8);
println!("{}{} | {plays} plays", spaces(indent), alb.name);
album(&gather::songs_from(entries, alb), 2 * indent);
}
}

Expand All @@ -235,10 +237,8 @@ fn album(songs: &HashMap<Song, usize>, indent: usize) {
.sorted_unstable_by_key(|t| (Reverse(t.1), t.0))
.collect_vec();

let indent = " ".repeat(indent);

for (song, plays) in songs_vec {
println!("{indent}{} | {plays} plays", song.name);
println!("{}{} | {plays} plays", spaces(indent), song.name);
}
}

Expand Down Expand Up @@ -275,6 +275,7 @@ pub fn aspect_date(
artist(
entries_within_dates,
&gather::albums_from_artist(entries_within_dates, art),
4,
);
}
AspectFull::Album(alb) => {
Expand Down
12 changes: 4 additions & 8 deletions endsong_ui/src/ui/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ fn print(title: &str, commands: &[Command]) {
/// Prefixes the actual command alias
const ALIAS: &str = "alias: ";

/// Length of "alias: "
const ALIAS_LENGTH: usize = ALIAS.len();
/// Spaces going to start of description
const INDENT: &str = crate::spaces(COMMAND_LENGTH + ARROW_LENGTH);

let phrase = format!(" {title} commands ");
// centered, filled with '=' on both sides
Expand All @@ -58,19 +58,15 @@ fn print(title: &str, commands: &[Command]) {

println!("{light_green}{centered_title}{reset}");

let indent = " ".repeat(COMMAND_LENGTH + ARROW_LENGTH);
for Command(command, alias, description) in commands {
let description_lines = textwrap::wrap(description, DESCRIPTION_LENGTH);
let description_first = description_lines.first().unwrap();

println!("{red}{command:>COMMAND_LENGTH$}{reset}{ARROW}{description_first}");
for line in description_lines.iter().skip(1) {
println!("{indent}{line}",);
println!("{INDENT}{line}",);
}
println!(
"{pink}{ALIAS:>width$}{alias}{reset}",
width = COMMAND_LENGTH + ARROW_LENGTH + ALIAS_LENGTH
);
println!("{pink}{INDENT}{ALIAS}{alias}{reset}");
}
}

Expand Down

0 comments on commit ca04384

Please sign in to comment.