Closed nigeleke closed 9 months ago
Hi @nigeleke, Thank you for spending your time on this issue. As you have said one of the core logic of this repo is parsing the selector and inserting random classes in it. First I will try to answer why do we need nightly version and then try to give some solutions to that problem.
styel_sheet
or style_sheet_str
macro this is not a problem. This is due to fact that we are directly reading a css file to get css content and parsing that string as it is. When we parse it as a string all the space information are retained without any further step from ourside.style
and style_str
macro we are parsing css content as tokenstream(because it gives us a way to write css directly in rust). So when we parse it as tokenstream we need space information to insert random classes(though it can be considered as kind of hashing) that we have generated. style
macro we don't actually need nightly version. Because we are parsing the css as a token stream outside procedural macro contex using proc_macro2. We are parsing the css from the build.rsproc_macro
crate instead of proc_macro2
crate. Because of this reason we need nightly version.Note: Since the style_str
macro executes the 'from_ts()` method inside procedural macro context it requires nightly version of rust.
One possible solution can be, we can feature gate the style_str
macro so that all the other macros can be used without nightly.(As far as I think there shouldn't be any other nightly dependency, After clear testing we can confirm that)
We can think about some new way to parse the selector without space information(like getting the whole selector as a single rust string such as "div > .class1" or some other way). I want to mention here that we are trying to write css without enclosing them inside a string.
We can wait for span information to be available in stabel verstion of Rust.
I've got around the nightly build dependency with the following:
/// Recover the original source css embedded in the tokenstream.
/// Note: this can only be called from a macro invocation. The source
/// needs to be recovered directly from the source file otherwise.
///
pub fn source_from(tokens: &TokenStream) -> String {
let group = Group::new(Delimiter::None, tokens.clone());
let source = group.span().source_text().unwrap();
let tokens = Vec::from_iter(tokens.clone().into_iter());
let group_range = byte_range(&group.span());
let (first_range, last_range) =
if tokens.len() > 0 {
let len = tokens.len();
(byte_range(&tokens[0].span()), byte_range(&tokens[len-1].span()))
} else {
(group_range.clone(), group_range.clone())
};
let start_offset = first_range.start - group_range.start;
let length = last_range.end - first_range.start;
let end_offset = start_offset + length;
source[start_offset..end_offset].to_string()
}
and
/// Emualate the `proc_macro::Span::byte_range` method.
/// Rely on the debug format of `#n bytes(from..to))`.
/// TODO: Remove this when `byte_range` becomes available on the stable build...
///
pub fn byte_range(span: &Span) -> Range<usize> {
let span = &format!("{:?}", span);
let re = Regex::new(r"^(#\d+ )?bytes\((\d+)\.\.(\d+)\)$").unwrap();
let captures = re.captures(span).unwrap();
let start = captures[2].parse::<usize>().unwrap();
let end = captures[3].parse::<usize>().unwrap();
start..end
}
These are used in the "macro handling"; the "build" phase however reads directly from the file.
The above is currently used in the roll my own version (style4rs
), but could possibly get integrated into stylers
. I'm happy to try and put this approach in stylers
if you see any benefit. (I think it depends if / when .start()
/ .end()
become available in stable.
Hi, Thank you for your patience, I have held upon something. This weekend I will explore your repo, Then we will decide the further steps. I hope this will help us improve the stylers.
Hi, Thank you for your patience, I have held upon something. This weekend I will explore your repo, Then we will decide the further steps. I hope this will help us improve the stylers.
Sorry - I have only just spotted your reply too; happy to chat further on the difference. My solution "works for me", though the error handling in stylers is much better. The alternatives table in the README shows a summary - https://nigeleke.github.io/style4rs/#alternatives.
I love the work being done for this crate. I wanted to understand the reason for its dependency on the nightly build though, so I decided to take a fork with the potential to remove it.
I can see that the underlying reason for the dependency is to track line / column numbers of Spans. This are used:
My fork (see the feature/no_nightly branch on my repo):
Given the above (and just because I can & have time) I decided to "roll my own", just to see where it would take me... This has made me appreciate the considerable work that's involved in the original to a much larger extent.
The key differences between approaches are:
A deterministic class name is generated, rather than a random one (it's based on a hash of the tokens). This has meant that the compilation macro processing returns the class name and does the css syntax checking, but does not need to generate intermediate files.
The build.rs phase scans all source and creates the main.css output. It doesn't require the intermediate files to "pick-up" the random class name that gets generated during compilation. (This is the stage where I realise how much work as gone into to knowing where to insert the ".random-class-name" appropriately :) :) :) )
Source / target and output folders are currently by "convention" and cannot be changed during build - I'm yet to determine if that is workable.
The key point of this is discussion though is to understand the nightly build dependency, and whether, at some future date that's likely to no longer be necessary....