compose-idents - an advanced token-manipulation macro library and a simpler alternative to macro_rules!.
It could be seen as a merger between paste and duplicate crates. The long-term plan for the project is to turn it into a fully fledged codegen-specific template engine.
Current features:
Identifier generation
Making new identifiers from parts using built-in DSL , e.g. concat(lower(FOO), _, to_ident("bar")) → foo_bar.
Turning non-ident-ish tokens into idents: normalize(&'static str) → static_str.
Code repetition
Making multiple different variations of the code (e.g., many tests for different types, bindings to C APIs, etc.).
String formatting
It is possible to format string literals, including in doc-attributes: #[doc = "This is a docstring for % my_fn %"].
Casing manipulation
Conversions between camelCase, snake_case, etc. are supported.
Unique/temporary identifier generation
Useful for globals whose names must not collide.
IDE friendliness
A major feature of the library is that it allows to do templating on Rust code without adding any new syntax (things like [< ... >] or $my_var), and therefore avoids confusing the IDE (syntax highlighting, formatting, etc.).
I sometimes use a combination of duplicate and paste, so I'm interested in this crate.
I have a question: why did you adopt the format % placeholder % for string formatting?
In my experience, when enclosing a placeholder with characters, using characters with distinct opening and closing characters like {placeholder} or ${placeholder} makes the separation clear and enhances readability. It also has the advantage of supporting nesting more easily.
On the other hand, when using a character without distinct opening and closing (e.g. %), it's sufficient to prepend that character to the placeholder, like $placeholder or %placeholder (though nesting isn't possible).
If the crate does not support nesting, the trailing % in % placeholder % seems redundant to me.
There was not much deep thinking on the syntax for this particular feature.
I actually agree that it looks a bit odd and is not something that other template-engines use. And usage of the same character for opening and closing is also odd.
Should I change it?
I want to drive the whole project towards Jinja-like experience so that a user can manipulate Rust code using for-loops, conditionals, and {% ... %} like placeholders (not only in the strings - in the code too). What do you think of that?
I think it should be changed somehow. If you refer to Jinja, statements would use {% ... %} and expressions would use {{ ... }}, but the problem is that {{ ... }} is also valid Rust code, which introduces ambiguity.
Due to my lack of experience with Jinja, I cannot determine whether using {% %} for both statements and expressions would cause any problems.
I want to drive the whole project towards Jinja-like experience
I think that loops, conditionals, and placeholders outside of strings can enable powerful code generation, but this would involve designing a kind of template language, which can be quite complex.
It would be sufficient to start by just changing the syntax of string formatting.