Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CSS] Nesting and &-selector #210

Open
jansalleine opened this issue Oct 26, 2023 · 4 comments
Open

[CSS] Nesting and &-selector #210

jansalleine opened this issue Oct 26, 2023 · 4 comments
Labels
css Caused by the css lexer

Comments

@jansalleine
Copy link

Nesting and the &-selector are now supported in CSS and shoud be enabled for the "normal" CSS lexer too.
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting/Using_CSS_nesting

Nesting check:
https://github.com/ScintillaOrg/lexilla/blob/master/lexers/LexCSS.cxx#L111
&-selector check:
https://github.com/ScintillaOrg/lexilla/blob/master/lexers/LexCSS.cxx#L370

@jansalleine
Copy link
Author

I don't know how all this "pull request" stuff works on github. I created a .patch file for LexCSS.cxx, that someone could use as a starting point.
I have tested this successfully with replacing the lexilla included in geany 2.0.0 with it.
LexCSS.patch.zip

diff --git a/lexers/LexCSS.cxx b/lexers/LexCSS.cxx
index b50fbaf2..3940299f 100644
--- a/lexers/LexCSS.cxx
+++ b/lexers/LexCSS.cxx
@@ -119,13 +119,9 @@ static void ColouriseCssDoc(Sci_PositionU startPos, Sci_Position length, int ini
 	CommentMode comment_mode = eCommentBlock;
 	bool hasSingleLineComments = isScssDocument || isLessDocument || isHssDocument;
 
-	// must keep track of nesting level in document types that support it (SCSS/LESS/HSS)
-	bool hasNesting = false;
-	int nestingLevel = 0;
-	if (isScssDocument || isLessDocument || isHssDocument) {
-		hasNesting = true;
-		nestingLevel = NestingLevelLookBehind(startPos, styler);
-	}
+	// must keep track of nesting level in document types that support it (CSS/SCSS/LESS/HSS)
+	bool hasNesting = true;
+	int nestingLevel = NestingLevelLookBehind(startPos, styler);
 
 	// "the loop"
 	for (; sc.More(); sc.Forward()) {
@@ -341,6 +337,16 @@ static void ColouriseCssDoc(Sci_PositionU startPos, Sci_Position length, int ini
 		else if (sc.ch == ')')
 			insideParentheses = false;
 
+		// nested rule parent selector
+		if (sc.ch == '&') {
+			switch (sc.state) {
+			case SCE_CSS_DEFAULT:
+			case SCE_CSS_IDENTIFIER:
+				sc.SetState(SCE_CSS_TAG);
+				continue;
+			}
+		}
+
 		// SCSS special modes
 		if (hasVariables) {
 			// variable name
@@ -366,19 +372,9 @@ static void ColouriseCssDoc(Sci_PositionU startPos, Sci_Position length, int ini
 					sc.SetState(SCE_CSS_VALUE);
 				}
 			}
-
-			// nested rule parent selector
-			if (sc.ch == '&') {
-				switch (sc.state) {
-				case SCE_CSS_DEFAULT:
-				case SCE_CSS_IDENTIFIER:
-					sc.SetState(SCE_CSS_TAG);
-					continue;
-				}
-			}
 		}
 
-		// nesting rules that apply to SCSS and Less
+		// nesting rules that apply to CSS, SCSS and Less
 		if (hasNesting) {
 			// check for nested rule selector
 			if (sc.state == SCE_CSS_IDENTIFIER && (IsAWordChar(sc.ch) || sc.ch == ':' || sc.ch == '.' || sc.ch == '#')) {

@nyamatongwe
Copy link
Member

This causes the lexer to re-read the document from the start (NestingLevelLookBehind) to the update position before each update. This may be expensive on large documents and even lead to quadratic slowdowns when lexing incrementally. Re-reading was included for the pre-processors on the basis that it worsened performance only when choosing a pre-processor mode, not for standard CSS.

You could make the nesting behaviour opt-in with an additional property similar to lexer.css.scss.language or remember the nesting level for each line with SetLineState. See other files such as LexR.cxx for an example of using SetLineState and GetLineState.

@jansalleine
Copy link
Author

I must admit I didn't look too deep into what the code actually does. After I saw that the if clause for the '&' selector was inside a (hasVariables) if clause I decided that either the code is kind of weird or I'm too much of a noob to get it – probably it's a bit of both.

The list of TODO comments seem to indicate that there's noone really caring at the moment. So I'll try my best to read more into this lexer nesting stuff and contribute if I'm able to.

Thanks for the hint with SetLineState.

@nyamatongwe
Copy link
Member

Another problem with NestingLevelLookBehind that it assumes every { and } is about nesting even when inside comments or strings.

@nyamatongwe nyamatongwe added the css Caused by the css lexer label Oct 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css Caused by the css lexer
Projects
None yet
Development

No branches or pull requests

2 participants