fix!: bring the scope autocompletion in by changing style input syntax

BREAKING CHANGE: `styly`, `sassy` macros syntax change. Now requires `{"$code"}`.
This commit is contained in:
Yiffy Dev 2024-11-01 09:42:37 +05:00 • committed by spushk
commit 915467c01f
Signed by: spushk
GPG key ID: 7797B761E105E8AA
9 changed files with 133 additions and 101 deletions

View file

@ -24,8 +24,8 @@ At first, I'll show how this crate "tastes". With SABRY, its in your power to:
Write arbitrary SASS/SCSS code and ship it *as a crate* however you please: with modules, with feature flags, etc. Say "bye" to manual copying, cli-tools and consts. Write arbitrary SASS/SCSS code and ship it *as a crate* however you please: with modules, with feature flags, etc. Say "bye" to manual copying, cli-tools and consts.
```rust,ignore ```rust
sassy!(tokens {@mixin colored{color: red;}}); sabry::sassy!(tokens {"@mixin colored{color: red;}"});
``` ```
</td> </td>
@ -38,9 +38,9 @@ sassy!(tokens {@mixin colored{color: red;}});
Code your SASS in separate files to get proper syntax highlighting, or do sass-in-the-rust to keep things in one place Code your SASS in separate files to get proper syntax highlighting, or do sass-in-the-rust to keep things in one place
```rust,ignore ```rust
styly!(component {.btn {color: green;}}); sabry::styly!(component {".btn {color: green;}"});
styly!(extras "src/components/extras.scss"); sabry::styly!(extras "tests/assets/mixins.scss");
``` ```
</td> </td>
@ -68,11 +68,11 @@ tgk_brandstyle = {version = "0.0.1", features = ["utils"]}
`@use` your style-crates in sass code *naturally* `@use` your style-crates in sass code *naturally*
```rust,ignore ```rust
styly!(breadbadge { sabry::styly!(breadbadge {"
@use 'tokens'; @use 'tokens';
.scope {@include tokens.badge(primary);} .scope {@include tokens.badge(primary);}
}) "});
``` ```
</td> </td>
@ -85,10 +85,11 @@ styly!(breadbadge {
Keep things as private and modular as you wish Keep things as private and modular as you wish
```rust
sabry::styly!(pub cats "tests/assets/mixins.scss");
sabry::styly!(dogs {"#howl {border: none;}"});
```
```rust,ignore ```rust,ignore
styly!(pub cats "src/sections/cats/style.scss");
styly!(dogs {#howl {border: none;}})
/// something like render function /// something like render function
{ {
<div class={cats::meow}> <div class={cats::meow}>
@ -107,9 +108,9 @@ styly!(dogs {#howl {border: none;}})
Compile all the sweet SASS/SCSS into the optimized CSS bundle, ship it in CSS shunks or even include the compiled style into the binary Compile all the sweet SASS/SCSS into the optimized CSS bundle, ship it in CSS shunks or even include the compiled style into the binary
```rust,ignore ```rust
styly!(cssbundle {.c1 {color: white;}}) sabry::styly!(cssbundle {".c1 {color: white;}"});
styly!(const binary {.c2 {color: black;}}) sabry::styly!(const binary {".c2 {color: black;}"});
``` ```
</td> </td>
@ -127,8 +128,7 @@ Sabry will gladly:
- prepare ready CSS bundle and put it wherever you wish - prepare ready CSS bundle and put it wherever you wish
- include CSS into the build artifact - if you really want it - include CSS into the build artifact - if you really want it
Also, just about everything is pub-available in this crate - Sabry is ready for experiments. Also, just about everything is pub-available in this crate (with *internals* feature flag) - Sabry is ready for experiments.
## Usage ## Usage
@ -153,7 +153,7 @@ And a proc-macro
use sabry::sassy; use sabry::sassy;
sassy!(mixins "tests/assets/mixins.scss"); sassy!(mixins "tests/assets/mixins.scss");
sassy!(styles { sassy!(styles {"
$primary-color: black; $primary-color: black;
@mixin colored($col: primary) { @mixin colored($col: primary) {
@if $col == primary { @if $col == primary {
@ -162,8 +162,10 @@ sassy!(styles {
color: $col; color: $col;
} }
} }
}); "});
``` ```
*\* Unlike most of other crates that do sass-in-the-rust, sabry currently does not allow unquoted sass/scss. You still have to write it in a string-quotes. Unquoted sass/scss is reserved for the future, where we shall introduce variable injection.*
Now you can build and see two ready for export macros: `mixins!` and `styles!`. Now you can build and see two ready for export macros: `mixins!` and `styles!`.
These are usefull on their own, as invocation of `mixins!()` or `styles!()` - both shall give you the code literal. These are usefull on their own, as invocation of `mixins!()` or `styles!()` - both shall give you the code literal.
@ -183,7 +185,7 @@ And create a style scope wherever you want:
// breadbadgelist.rs // breadbadgelist.rs
use sabry::styly; use sabry::styly;
styly!(const styles { styly!(const styles {"
.badges { .badges {
display: flex; display: flex;
&__list { &__list {
@ -193,7 +195,7 @@ styly!(const styles {
#wolf { #wolf {
color: white; color: white;
} }
}); "});
/* Now you can use all scoped selectors: */ /* Now you can use all scoped selectors: */
let badges_scoped_class = styles::badges; let badges_scoped_class = styles::badges;
@ -242,9 +244,9 @@ Now lets get back to the code and use the mixin defined in another crate:
// breadbadgelist.rs // breadbadgelist.rs
use sabry::styly; use sabry::styly;
styly!(styles { styly!(styles {"
// "mixins" is available beacuse we did call mixins!() macro in the example below // 'mixins' is available beacuse we did call mixins!() macro in the example below
@use "mixins"; @use 'mixins';
.badges { .badges {
display: flex; display: flex;
&__list { &__list {
@ -254,7 +256,7 @@ styly!(styles {
#wolf { #wolf {
@include mixins.colored(white); @include mixins.colored(white);
} }
}); "});
``` ```
So the `mixins!` macro we just passed to the `usey!` macro inside of `buildy` function call is now accessible with simple and natural `@use "mixins"` SASS rule! So the `mixins!` macro we just passed to the `usey!` macro inside of `buildy` function call is now accessible with simple and natural `@use "mixins"` SASS rule!
@ -291,9 +293,9 @@ sabry = {version = "0.0.1", features = ["build", "lepty-scoping"]}
use leptos::prelude::*; use leptos::prelude::*;
use sabry::styly; use sabry::styly;
styly!(scope { styly!(scope {"
// assuming we have tokens!() macro generated by `sassy!`, which is handled by `buildy` // assuming we have tokens!() macro generated by `sassy!`, which is handled by `buildy`
@use "tokens"; @use 'tokens';
h1 { h1 {
@include tokens.sectionhead(); @include tokens.sectionhead();
img { img {
@ -306,7 +308,7 @@ styly!(scope {
@include tokens.badge(secondary); @include tokens.badge(secondary);
} }
} }
}); "});
#[component] #[component]
fn component() -> impl IntoView { fn component() -> impl IntoView {
@ -441,17 +443,17 @@ Examples:
```rust ```rust
use sabry::sassy; use sabry::sassy;
sassy!(module1 {$primary-color: red;}); sassy!(module1 {"$primary-color: red;"});
sassy!(module2 "tests/assets/mixins.scss"); sassy!(module2 "tests/assets/mixins.scss");
sassy!(module3:sass "tests/assets/mixins.sass"); sassy!(module3:sass "tests/assets/mixins.sass");
// works, but there are catches. // works, but there are catches.
sassy!(module4:sass { sassy!(module4:sass {"
=colored($col: primary) =colored($col: primary)
@if $col == primary @if $col == primary
color: white color: white
@else @else
color: red color: red
}); "});
``` ```
You may omit the syntax specifier - sabry uses SCSS as the default one. You may omit the syntax specifier - sabry uses SCSS as the default one.
@ -477,14 +479,14 @@ Examples
```rust ```rust
use sabry::styly; use sabry::styly;
styly!(private_fox {.fur {color: red; &-dark {color: black;}}}); styly!(private_fox {".fur {color: red; &-dark {color: black;}}"});
styly!(pub public_fox {.fur {color: red; &-dark {color: black;}}}); styly!(pub public_fox {".fur {color: red; &-dark {color: black;}}"});
styly!(pub const pub_compiletime_fox:sass { styly!(pub const pub_compiletime_fox:sass {"
.fur .fur
color: red color: red
&-dark &-dark
color: black color: black
}); "});
``` ```
Every of those calls will produce the styling scope as a module. Differences are explained right below. Every of those calls will produce the styling scope as a module. Differences are explained right below.
@ -522,7 +524,7 @@ As you've seen above, scope doe not contain any style code by itself. That's the
However you could still compile styles into the artifact by simply adding the `const` to the macro call: However you could still compile styles into the artifact by simply adding the `const` to the macro call:
```rust,ignore ```rust
sabry::styly!(const scope "tests/assets/mixins.scss"); sabry::styly!(const scope "tests/assets/mixins.scss");
``` ```
Which results in following: Which results in following:
@ -613,11 +615,11 @@ As for **SASS parent selectors**: they are currently handled in different way. I
walking up the syntax tree sabry just creates function member for the scope and leave the rest to grass: walking up the syntax tree sabry just creates function member for the scope and leave the rest to grass:
```rust ```rust
sabry::styly!(scope { sabry::styly!(scope {"
.cls1 { .cls1 {
&-dark {} &-dark {}
} }
}); "});
``` ```
is something like is something like
```rust,ignore ```rust,ignore
@ -648,10 +650,20 @@ Not any valid CSS selector is a valid rust identifier. In general this section s
*(sorted by my own priority)*, "dones" are excluded *(sorted by my own priority)*, "dones" are excluded
- [ ] Somehow achieve the autocompletion for scopes. The problem is explained in details [here](https://github.com/yiffyrusdev/sabry/issues/2) - [x] Somehow achieve the autocompletion for scopes. The problem is explained in details [here](https://github.com/yiffyrusdev/sabry/issues/2)
- [ ] some weird unrelated stuff I can see in autocompletion
- [ ] Crates of styled components - currently the only way to create them seems to be const styly. - [ ] Crates of styled components - currently the only way to create them seems to be const styly.
- [ ] CSS support - [ ] CSS support
- [ ] Currently the crate causes "dependency inheritance" infection. We cant get rid of it, however should be doable to at least get rid of flag inheritance - [ ] Currently the crate causes "dependency inheritance" infection. We cant get rid of it, however should be doable to at least get rid of flag inheritance
- [ ] Use sass-in-rust without quoted styles for variable injection:
```rust, ignore
let myvar = "content";
styly!(scope {
.c::after {
content: somehow(myvar);
}
})
```
- [ ] There are some strange parsing errors, seems like a bug, however very hard to reproduce. Have to investigate. Maybe do more tests. - [ ] There are some strange parsing errors, seems like a bug, however very hard to reproduce. Have to investigate. Maybe do more tests.
- [ ] Experience with cargo-leptos is fine, and we do use it, however its a bit "raughy". Need to do something about it. - [ ] Experience with cargo-leptos is fine, and we do use it, however its a bit "raughy". Need to do something about it.

View file

@ -994,7 +994,7 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]] [[package]]
name = "sabry" name = "sabry"
version = "0.0.1-alpha.1" version = "0.0.1-alpha.2"
dependencies = [ dependencies = [
"sabry_intrnl", "sabry_intrnl",
"sabry_procmacro", "sabry_procmacro",
@ -1002,10 +1002,11 @@ dependencies = [
[[package]] [[package]]
name = "sabry_intrnl" name = "sabry_intrnl"
version = "0.0.1-alpha.1" version = "0.0.1-alpha.2"
dependencies = [ dependencies = [
"base64", "base64",
"blake3", "blake3",
"cfg-if",
"const_format", "const_format",
"grass", "grass",
"lightningcss", "lightningcss",
@ -1021,14 +1022,14 @@ dependencies = [
[[package]] [[package]]
name = "sabry_procmacro" name = "sabry_procmacro"
version = "0.0.1-alpha.1" version = "0.0.1-alpha.2"
dependencies = [ dependencies = [
"sabry_procmacro_impl", "sabry_procmacro_impl",
] ]
[[package]] [[package]]
name = "sabry_procmacro_impl" name = "sabry_procmacro_impl"
version = "0.0.1-alpha.1" version = "0.0.1-alpha.2"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View file

@ -2,7 +2,7 @@ use sabry::sassy;
sassy!(style "src/style.scss"); sassy!(style "src/style.scss");
sassy!(utils { sassy!(utils {"
@mixin flex($direction, $align, $justify, $gap: .5rem) { @mixin flex($direction, $align, $justify, $gap: .5rem) {
display: flex; display: flex;
list-style: none; list-style: none;
@ -29,9 +29,9 @@ sassy!(utils {
justify-content: $justify; justify-content: $justify;
} }
} }
}); "});
sassy!(theme { sassy!(theme {"
$thm-surface-primary: #2b2a29; $thm-surface-primary: #2b2a29;
$thm-surface-secondary: #6C6C6C; $thm-surface-secondary: #6C6C6C;
$thm-surface-tertiary: #4C4C4C; $thm-surface-tertiary: #4C4C4C;
@ -75,10 +75,10 @@ sassy!(theme {
color: $thm-text-accent; color: $thm-text-accent;
} }
} }
}); "});
sassy!(tokens { sassy!(tokens {"
@use "theme"; @use 'theme';
@mixin clickable($style: accent, $scale: 1.2, $clickscale: 0.9){ @mixin clickable($style: accent, $scale: 1.2, $clickscale: 0.9){
@if $style == accent{ @if $style == accent{
@ -103,4 +103,4 @@ sassy!(tokens {
transform: scale($clickscale); transform: scale($clickscale);
} }
} }
}); "});

View file

@ -1,10 +1,10 @@
use leptos::prelude::*; use leptos::prelude::*;
use sabry::styly; use sabry::styly;
styly!(style { styly!(style {"
@use "tokens"; @use 'tokens';
@use "utils"; @use 'utils';
@use "theme"; @use 'theme';
h2 { h2 {
margin-bottom: 1rem; margin-bottom: 1rem;
@ -35,7 +35,7 @@ styly!(style {
text-transform: uppercase; text-transform: uppercase;
} }
}); "});
/// Renders the home page of your application. /// Renders the home page of your application.
#[component] #[component]

View file

@ -3,11 +3,11 @@ use sabry::{sassy, usey};
// This module will have the same name as define_styles_example::utils // This module will have the same name as define_styles_example::utils
// and sabry is configured to merge them // and sabry is configured to merge them
sassy!(utils { sassy!(utils {"
@mixin nonclickable(){ @mixin nonclickable(){
display: none; display: none;
} }
}); "});
fn main(){ fn main(){
/* Declare modules to use with sabry */ /* Declare modules to use with sabry */

View file

@ -1,7 +1,10 @@
use sabry::styly; use sabry::styly;
styly!(pub const bundlemod { // Sabry now (0.0.1-alpha.3) disallows unquoted styles
@use "tokens"; // you won't benefit from unqouted styles though, as you won't get syntax highlighting
// Also, unqouted styles are reserved for future
styly!(pub const bundlemod {"
@use 'tokens';
.someth { .someth {
@include tokens.clickable; @include tokens.clickable;
background-color: black; background-color: black;
@ -9,7 +12,9 @@ styly!(pub const bundlemod {
background-color: white; background-color: white;
} }
} }
}); "});
styly!(pub filemod:sass "src/main.sass");
fn main(){ fn main(){
println!("someth class codemod styles: {}", bundlemod::someth); println!("someth class codemod styles: {}", bundlemod::someth);

View file

@ -215,7 +215,7 @@ impl HashedSelector {
/// ///
/// Not every hashed selector is presentable for HTML-ish use: like `div`, in that case /// Not every hashed selector is presentable for HTML-ish use: like `div`, in that case
/// returns [None] /// returns [None]
pub fn make_hashed_html(value: &ScopedSelector, hash: &ScopeHash) -> Option<String> { pub fn make_hashed_html(value: &ScopedSelector, _hash: &ScopeHash) -> Option<String> {
match value { match value {
// Class scoping is done with class composition // Class scoping is done with class composition
ScopedSelector::Class(a) => { ScopedSelector::Class(a) => {
@ -223,7 +223,7 @@ impl HashedSelector {
if #[cfg(feature = "lepty-scoping")] { if #[cfg(feature = "lepty-scoping")] {
Some(a.ident.to_string()) Some(a.ident.to_string())
} else { } else {
Some(format!("{} {}", hash.as_str(), a.ident)) Some(format!("{} {}", _hash.as_str(), a.ident))
} }
} }
} }
@ -234,7 +234,7 @@ impl HashedSelector {
if #[cfg(feature = "lepty-scoping")] { if #[cfg(feature = "lepty-scoping")] {
Some(a.ident.to_string()) Some(a.ident.to_string())
} else { } else {
Some(format!("{}-{}", hash.as_str(), a.ident)) Some(format!("{}-{}", _hash.as_str(), a.ident))
} }
} }
} }

View file

@ -2,8 +2,9 @@ use std::{fmt::Debug, fs, path::PathBuf, str::FromStr};
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens, TokenStreamExt}; use quote::{quote, ToTokens, TokenStreamExt};
use regex::Regex;
use sabry_intrnl::compiler::CompilerSyntax; use sabry_intrnl::compiler::CompilerSyntax;
use syn::{braced, parse::Parse, spanned::Spanned, Ident, LitStr, Token}; use syn::{braced, parse::Parse, Ident, LitStr, Token};
pub mod sassy; pub mod sassy;
pub mod styly; pub mod styly;
@ -68,21 +69,17 @@ impl Parse for ArbitraryStyleBlock {
(code, path_tok.span()) (code, path_tok.span())
} else { } else {
// Does not work on stable! let s;
// We're on nightly though braced!(s in input);
// So what? if let Ok(stream) = s.parse::<LitStr>() {
// Then is works. let c = stream.value();
let _s; // shift the entire code for the first line ident
braced!(_s in input); let ident_regex = Regex::new(r"\n\s{4}").expect("BUG: base ident regex at sabry_procmacro_impl/src/impls/mod.rs:: impl Parse for ArbitraryStyleBlock");
let stream = _s.parse::<TokenStream>()?; let c = ident_regex.replace_all(&c, "\n").to_string();
(c, stream.span())
let c = match stream.span().source_text() { } else {
Some(stx) => stx, return Err(syn::Error::new(s.span(), "Use \"\" within the braces to specify your SASS/SCSS. Unquoted style syntax is reserved for the future. Unquoted SCSS/SASS doesnt make sense though, as you won't benefit from it in rust file.\n\ntip: use `{\"style\"}` instead of `{style}`"));
// TODO: rust-analyzer does fall into this even if all is fine }
None => "".to_string(), //return Err(syn::Error::new(stream.span(), "Source code expected")),
};
(c, stream.span())
}; };
Ok(Self { code, span }) Ok(Self { code, span })
@ -137,9 +134,9 @@ impl Parse for ArbitraryStyleSyntax {
_ => Err(syn::Error::new( _ => Err(syn::Error::new(
ident.span(), ident.span(),
format!( format!(
"Available syntax are `sass` (WIP) and `scss`, each of them requires feature flag. Omit to use default {:?} syntax", "Available syntax are `sass` and `scss`, omit to use default {:?} syntax",
Self::default() Self::default()
), ),
)), )),
} }
} }
@ -176,31 +173,49 @@ mod test {
fn arbitrary_style_block_sass() { fn arbitrary_style_block_sass() {
use super::ArbitraryStyleBlock; use super::ArbitraryStyleBlock;
let code = "#a let code = "
co:d #a
.sel co: red
di: pi .sel
.sel,div > sel co: white
f: \"into\""; &-dark
let braced_code = format!("{{{code}}}"); & > div
let block = syn::parse_str::<ArbitraryStyleBlock>(&braced_code).unwrap(); co: blue";
let expect_code = "
#a
co: red
.sel
co: white
&-dark
& > div
co: blue";
let input = format!("{{\"{code}\"}}");
let block = syn::parse_str::<ArbitraryStyleBlock>(&input).unwrap();
assert_eq!(code, block.code); assert_eq!(expect_code, block.code);
} }
#[test] #[test]
fn arbitrary_style_block_scss() { fn arbitrary_style_block_scss() {
use super::ArbitraryStyleBlock; use super::ArbitraryStyleBlock;
let code = "#a { let code = "
c:r; #a {
} c: r;
.b.c{ }
c:\"into\"; .b.c {
}"; c: 'into';
let braced_code = format!("{{{code}}}"); }";
let block = syn::parse_str::<ArbitraryStyleBlock>(&braced_code).unwrap(); let expect_code = "
#a {
c: r;
}
.b.c {
c: 'into';
}";
let input = format!("{{\"{code}\"}}");
let block = syn::parse_str::<ArbitraryStyleBlock>(&input).unwrap();
assert_eq!(code, block.code) assert_eq!(expect_code, block.code)
} }
} }

View file

@ -8,7 +8,6 @@ pub use sabry_build::buildmagic::buildy;
#[cfg(feature = "procmacro")] #[cfg(feature = "procmacro")]
pub use sabry_procmacro::*; pub use sabry_procmacro::*;
// reexports // reexports
#[cfg_attr(docsrs, doc(cfg(all(feature = "build", feature = "internals"))))] #[cfg_attr(docsrs, doc(cfg(all(feature = "build", feature = "internals"))))]
#[cfg(all(feature = "build", feature = "internals"))] #[cfg(all(feature = "build", feature = "internals"))]