Search code examples
regexyamlsyntax-highlightingsublime-text-pluginsublimetext4

How to set different colors each rows based on the number of spaces?


I want to change the text color to red on a line if it has 4 spaces, blue color if it has 8 spaces, 12 spaces to green and so on. I'm using .YAML format to achieve this, but the text always set to red color no matter how many spaces in the beginning of the line.

These are how I tried:

- match: ^\s{4}[\w\d_\.', ]*$
  scope: indent_1

- match: ^\s{8}[\w\d_\.', ]*$
  scope: indent_2

- match: ^\s{12}[\w\d_\.', ]*$
  scope: indent_3

Apparently, this code sets the whole texts to red

text 1 (red)
    text 2 (red)
        text 3 (red)

Second try, I combined 2 matches using capture keywords

- match: \s{4}[\w\d_\.', ]*$
  captures:
    1: indent_1
    2: indent_2
  push:
    - match: \s{4}, 
      scope: indent_1
    - match: $
      pop: true
  push:
    - match: \s{8}, 
      scope: indent_2
    - match: $
      pop: true

This throws an error;

error: Error loading syntax file "Packages/note/note.sublime-syntax": Error trying to parse sublime-syntax: Duplicate key in mapping in :35:7

Another try, I added OR(|) operator in between the \s{n} expressions, but this code sets its color to only the spaces in the beginning of the lines.

- match: (\s{4})|(\s{8})[\w\d_\.', ]*$
  captures:
    1: indent_1
    2: indent_2
  push:
    - match: \s{4}
      scope: indent_1
    - match: $
      pop: true
    - match: \s{8}
      scope: indent_2
    - match: $
      pop: true


    (color black) text 1
        (color black) text 2
            (color black) text 3

Are there any ways to fix this problem?


Solution

  • You are using this pattern:

    ^\s{4}[\w\d_\.', ]*$
    

    Here \s can also match newlines, and the character class [\w\d_\.', ] can also match a space.

    So the pattern matches at least 4 whitespace characters, but it can also match a space after it and this pattern will then match for all the cases.

    Note that \w also matches \d and _ and you don't have to escape the dot \. in the character class.

    Matching whitespace chars without newlines instead of a single space could be done with [^\S\r\n] or for example \h if that is supported. Then you would for example also match 8 tabs.

    If you want to start the match with 4 spaces, and there has to be at least a single char from the character class following that is not a space:

    ^[ ]{4}[\w.',][\w.', ]*$
    

    The pattern matches:

    • ^ Start of string
    • [ ]{4} Match 8 spaces (the square brackets are for clarity only)
    • [\w.',] Match a single word char or . ' ,
    • [\w.', ]* Match optional word chars or . ' , or a space
    • $ End of string

    Then the second pattern will be matching 8 spaces etc..

    ^[ ]{8}[\w.',][\w.', ]*$