Skip to content

fix: preserve Less negative values - #62

Merged
g-plane merged 4 commits into
g-plane:mainfrom
magic-akari:fix/issue-61
Jul 8, 2026
Merged

fix: preserve Less negative values#62
g-plane merged 4 commits into
g-plane:mainfrom
magic-akari:fix/issue-61

Conversation

@magic-akari

@magic-akari magic-akari commented Jul 6, 2026

Copy link
Copy Markdown
Contributor
  • The pull request description was written manually by me and was not generated by an AI tool or agent.
  • I have read and understood the relevant parts of the existing codebase before making these changes.
  • I have carefully reviewed and understood all code changes, and ensured that they match the style, architecture, and conventions of the existing codebase.
  • I understand that pull requests containing blindly generated or unreviewed AI-generated code may be closed without review.

Summary

Fixes Less formatting for negative values that appear after another value.

Malva previously formatted:

margin: 0 -@card-spacing;

as:

margin: 0 - @card-spacing;

In Less, those are not equivalent. The first is a value list containing 0 and -@card-spacing; the second is binary subtraction.

This PR preserves unary negative values such as:

margin: 0 -@card-spacing;
margin: 0 -(@card-spacing);

while still formatting actual binary subtraction normally:

margin: 0 - @card-spacing;
margin: 0 - (@card-spacing);

Format Flow

flowchart TD
  A["Less input: margin: 2 -@x * 2"] --> B["Raffia AST: LessBinaryOperation"]
  B --> C{"Is spaced unary negative?"}

  C -->|"minus operator, left ends before -, and - touches right"| D["Find the start atom of the right expression"]
  C -->|"otherwise"| E["Print operator with normal spacing"]

  D --> F["If right is nested LessBinaryOperation, follow its left operand"]
  F --> G{"Start atom can be a Less negative value?"}

  G -->|"yes: @var, @@var, $prop, (...), or @var[lookup]"| H["Print operator without suffix space"]
  G -->|"no"| E

  H --> I["Output: margin: 2 -@x * 2"]
  E --> J["Output: binary subtraction formatting"]
  I --> K["Less value-list semantics preserved"]
Loading

Tests

Added Less snapshot coverage for:

  • margin: 2 -@card-spacing;
  • margin: 2 - @card-spacing;
  • margin: 2-@card-spacing;
  • margin: 2 -(@card-spacing);
  • margin: 2 - (@card-spacing);

Also updated the existing parenthesized negative-value snapshot to preserve Less semantics.

Verified with:

cargo fmt --all --check
RUST_MIN_STACK=33554432 cargo test

@magic-akari

Copy link
Copy Markdown
Contributor Author

Follow-up Fix

After the previous commit, I found one more edge case: Less negative values can be followed by a higher-precedence operation, such as multiplication.

For example:

margin: 2 -@card-spacing * 2;
margin: 2 -(@card-spacing) * 2;

The previous fix handled cases where the right-hand side of the outer LessBinaryOperation was directly a Less negative-value atom, such as @var or (...).

That missed cases where Raffia parses the right-hand side as another LessBinaryOperation. For 2 -@card-spacing * 2, the outer operation is effectively:

left: 2
op: -
right:
  left: @card-spacing
  op: *
  right: 2

So the right-hand side is not directly @card-spacing; it is a multiplication expression whose start atom is @card-spacing.

Side note: this feels like we are fitting the gap between Raffia's parser and Less syntax.

The new fix models this more accurately. Instead of asking whether the entire right-hand side is a Less negative value, it asks whether the right-hand side starts with a value that can be negated in Less. If the right-hand side is a nested LessBinaryOperation, it recursively checks its left operand until it reaches the starting atom.

This preserves cases like:

margin: 2 -@card-spacing * 2;
margin: 2 -@card-spacing / 2;
margin: 2 -(@card-spacing + 1px) * 2;

while still formatting real binary subtraction normally:

margin: 2 - @card-spacing * 2;
margin: 2 - (@card-spacing) * 2;

@magic-akari
magic-akari marked this pull request as ready for review July 6, 2026 06:39
@g-plane

g-plane commented Jul 7, 2026

Copy link
Copy Markdown
Owner

This should be a parser bug. I'll fix this in parser.

@g-plane
g-plane merged commit 899a029 into g-plane:main Jul 8, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Less negative values after another value are formatted as binary subtraction

2 participants