thatsIch/sublime-rainmeter

View on GitHub
Rainmeter.sublime-syntax

Summary

Maintainability
Test Coverage
%YAML 1.2
---
name: Rainmeter
comment: "Rainmeter Syntax: r2708 beta"
scope: source.rainmeter
file_extensions: [ini, inc]
uuid: 6a53050b-d898-4e20-8fa0-c1726f4ce466
foldingStartMarker: "^\\s*\\[\\s*[^\\[\\]\\s]*\\s*\\]\\s*$"
foldingStopMarker: "^(?=\\s*\\[)"

variables:
  mouse_action_name: "(?i)((LeftMouseUp|LeftMouseDown|LeftMouseDoubleClick|RightMouseUp|RightMouseDown|RIghtMouseDoubleClick|MiddleMouseUp|MiddleMouseDown|MiddleMouseDoubleClick|X1MouseUp|X1MouseDown|X1MouseDoubleClick|X2MouseUp|X2MouseDown|X2MouseDoubleClick|MouseScrollUp|MouseScrollDown|MouseScrollLeft|MouseScrollRight|MouseOver|MouseLeave)Action|\\*)"
  meter-name: ".+|\".+\""

# template

    # # 
    # - match: 
    #   scope: 
    #   captures: 
    #     1: 
    #     2: 
    #     3: 

contexts:
  main:
    # comment lines
    - match: "^\\s*(;.*)$"
      scope: meta.comment.rainmeter
      captures:
        1: comment.line.character.rainmeter

    # all other options in a section
    - scope: meta.variables.section.rainmeter
      match: "(?i)^\\s*(\\[\\s*variables\\s*\\])\\s*$"
      captures:
        1: entity.name.section.rainmeter
      push:
        # comment lines
        - match: "^\\s*;.*$"
          captures:
            0: comment.line.character.rainmeter

        - include: color-definition
        - include: bangs
        - include: all-variables
        - include: includes

        # All other options in a section
        - include: variable-section-variables

        # next section
        - match: "^(?=\\s*\\[)"
          pop: true

    # section heads
    - match: "^\\s*\\[\\s*[^\\[\\]\\s]*\\s*\\]\\s*$"
      scope: entity.name.section.rainmeter

    # format option lines give formatting literals priority over environment variables
    - scope: meta.format.string.rainmeter
      match: "(?i)^\\s*(Format)\\s*(=)"
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
      push: 
        # uptime measure
        # String format placeholder
        - match: "%[1-4]+"
          captures: 
            0: constant.language.format.rainmeter
        - match: "![0-9]*i!"
          captures:
            0: constant.language.format.rainmeter
        
        # time measure
         # Formatting strings for time formats
        - match: "%#?[aAbBcdHIjmMpSUwWxXyYzZ]"
          captures:
            0: constant.language.format.rainmeter
        - match: "$"
          pop: true

    - include: all-variables

    # UserInput variable of InputText plugin
    - match: "(?i)\\$Userinput\\$"
      scope: support.variable.userinput.rainmeter

    # Deprecated bangs
    - match: "(?i)!((Rainmeter((SetClip)|(EditSkin)|(SetWallpaper)|(About)|(Manage)|(Log)|(LsBoxHook)|(ResetStats)|(TrayMenu)|(RefreshApp)|(Quit)|(SetOption(Group)?)|(WriteKeyValue)|(SetVariable(Group)?)|(Toggle(Group|Config)?)|(Move(Meter)?)|(DeactivateConfig(Group)?)|(ActivateConfig)|(Refresh(Group)?)|(Update)|(Redraw(Group)?)|(SetTransparency(Group)?)|((Show|Hide|Toggle)Fade(Group)?)|((Show|Hide|Toggle|Add|Remove)Blur)|(Draggable(Group)?)|(ZPos(Group)?)|(KeepOnScreen(Group)?)|(ClickThrough(Group)?)|AutoSelectScreen(Group)?|(SnapEdges(Group)?)|(SkinMenu)|(SkinCustomMenu)|((Show|Hide|Toggle|Update)Meter(Group)?)|(((Dis|En)able|Toggle|Update)Measure(Group)?)|(CommandMeasure)|((Show|Hide)(Group)?)))|Execute|(Rainmeter)?PluginBang)\\b"
      scope: invalid.deprecated.bang.rainmeter

    - include: bangs
      
    # Escaped dynamic sections (must be before normal ones to override them)
    - match: "\\[\\*[^\\[\\]\\s]+?\\*\\]"
      scope: meta.text.rainmeter

    # Section variables
    - match: "(?i)\\[[^\\[\\]\\s\\\\/!#\"%\\$]*?(:((((W|H|X|Y|(Min|Max)Value)|(/[-+]?[0-9]*\\.?[0-9]+(e[-+]?[0-9]+)?(,\\s*[0-9]+)?)|(%)|([0-9]+))(,\\s*((W|H|X|Y|(Min|Max)Value)|(/[-+]?[0-9]*\\.?[0-9]+(e[-+]?[0-9]+)?(,\\s*[0-9]+)?)|(%)|([0-9]+)))*?)|(EscapeRegExp|EncodeURL|TimeStamp))?)\\]"
      scope: variable.other.dynamic.section_variable.rainmeter
      captures: 
        1: constant.language.section_variable.spec.rainmeter

    # Measures used as dynamic values
    - match: "\\[[^\\[\\]\\s\\\\/!#\"%\\$]*\\]"
      scope: variable.other.dynamic.rainmeter

    # imageflip options
    - match: "(?i)^\\s*((Primary|Secondary|Both)?imageflip)\\s*(=)\\s*((None|Horizontal|Vertical|Both)|\"(None|Horizontal|Vertical|Both)\")\\s*$"
      scope: meta.option.imageflip.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: support.constant.option_values.rainmeter

    # invalid imageflip options
    - match: "(?i)^\\s*((Primary|Secondary|Both)?imageflip)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.imageflip.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        3: keyword.operator.option.equal.rainmeter
        5: invalid.rainmeter

    # UseExifOrientation options
    - match: "(?i)^\\s*(UseExifOrientation)\\s*(=)\\s*((0|1)|\"(0|1)\")\\s*$"
      scope: meta.option.UseExifOrientation.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # invalid UseExifOrientation options
    - match: "(?i)^\\s*(UseExifOrientation)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.UseExifOrientation.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # InputLimit options
    - match: "(?i)^\\s*(InputLimit)\\s*(=)\\s*((\\d+)|\"(\\+d)\")\\s*$"
      scope: meta.option.UseExifOrientation.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: constant.numeric.rainmeter

    # invalid InputLimit options
    - match: "(?i)^\\s*(InputLimit)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.UseExifOrientation.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # InputNumber options
    - match: "(?i)^\\s*(InputNumber)\\s*(=)\\s*((1|0)|\"(1|0)\")\\s*$"
      scope: meta.option.UseExifOrientation.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # invalid InputNumber options
    - match: "(?i)^\\s*(InputNumber)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.UseExifOrientation.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

        
    # Shape feature
    - match: "(?i)^\\s*(Shape([2-9]{1,1}|[0-9]{2,})?)\\s*(=)"
      scope: meta.option.shape.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        3: keyword.operator.option.equal.rainmeter
      push:
        - match: (Path[1]?)\s+([a-zA-Z0-9]+)
          captures:
            1: support.constant.option_values.rainmeter
            2: storage.type.variable.rainmeter
        - match: (Rectangle|Ellipse|Line|Arc|Curve|Combine)\s+
          captures:
            1: support.constant.option_values.rainmeter
        - include: meter-shape-modifier
        # capture measures
        - match: "(\\[.+\\])"
          captures:
            1: variable.other.dynamic.rainmeter
        # capture variables
        - match: "(\\#.+\\#)"
          captures:
            1: support.variable.rainmeter
        - match: $
          pop: true

    # 
    - match: "(?i)^\\s*(Paused)\\s*(=)\\s*((0|1)|\"(0|1)\")\\s*$"
      scope: meta.option.Paused.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    #
    - match: "(?i)^\\s*(Paused)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.Paused.invalid.rainmeter
      captures:
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(AccurateText)\\s*(=)\\s*((0|1)|\"(0|1)\")\\s*$"
      scope: meta.option.AccurateText.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # 
    - match: "(?i)^\\s*(AccurateText)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.AccurateText.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(DynamicWindowSize)\\s*(=)\\s*((0|1)|\"(0|1)\")\\s*$"
      scope: meta.option.DynamicWindowSize.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # 
    - match: "(?i)^\\s*(DynamicWindowSize)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.DynamicWindowSize.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter
    
    # #
    # - match: "(?i)^\\s*(DynamicWindowSize)\\s*(=)\\s*" 
    #   scope: meta.option.DynamicWindowSize.rainmeter
    #   captures:
    #     1: storage.type.option.predefined.rainmeter
    #     2: keyword.operator.option.equal.rainmeter
    #   push:
    #     - match: 1|0
    #       captures:
    #         0: support.constant.option_values.rainmeter
    #     - match: ".*(#.*#).*$"
    #       pop: true
    #       captures:
    #         1: storage.type.variable.rainmeter
    #     - match: $
    #       pop: true
    #     - match: ".*(\\[.*\\]).*$"
    #       captures:
    #         1: entity.name.section.rainmeter
    #     - match: .*
    #       captures:
    #         0: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(UpdateRandom)\\s*(=)\\s*((0|1)|\"(0|1)\")\\s*$"
      scope: meta.option.UpdateRandom.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # 
    - match: "(?i)^\\s*(UpdateRandom)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.UpdateRandom.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(UniqueRandom)\\s*(=)\\s*((0|1)|\"(0|1)\")\\s*$"
      scope: meta.option.UniqueRandom.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # 
    - match: "(?i)^\\s*(UniqueRandom)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.UniqueRandom.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(IfConditionMode)\\s*(=)\\s*((0|1)|\"(0|1)\")\\s*$"
      scope: meta.option.IfConditionMode.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # 
    - match: "(?i)^\\s*(IfConditionMode)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.IfConditionMode.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(IfMatchMode)\\s*(=)\\s*((0|1)|\"(0|1)\")\\s*$"
      scope: meta.option.IfMatchMode.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # 
    - match: "(?i)^\\s*(IfMatchMode)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.IfMatchMode.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(Measure)\\s*(=)\\s*((Calc|CPU|FreeDiskSpace|Loop|MediaKey|Memory|PhysicalMemory|SwapMemory|Net(In|Out|Total)|NowPlaying|Plugin|RecycleManager|Registry|Script|String|SysInfo|Time|Uptime|WebParser)|\"(Calc|CPU|FreeDiskSpace|Loop|MediaKey|Memory|PhysicalMemory|SwapMemory|Net(In|Out|Total)|NowPlaying|Plugin|RecycleManager|Registry|Script|String|SysInfo|Time|Uptime|WebParser)\")\\s*$"
      scope: meta.option.measure.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.names.rainmeter

    # 
    - match: "(?i)^\\s*(Measure)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.measure.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(RegHKey)\\s*(=)\\s*((HKEY_CURRENT_(Config|USER)|HKEY_LOCAL_MACHINE|HKEY_CLASSES_ROOT|HKEY_PERFORMANCE_DATA|HKEY_DYN_DATA)|\"(HKEY_CURRENT_(Config|USER)|HKEY_LOCAL_MACHINE|HKEY_CLASSES_ROOT|HKEY_PERFORMANCE_DATA|HKEY_DYN_DATA)\")\\s*$"
      scope: meta.option.RegHKey.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # 
    - match: "(?i)^\\s*(RegHKey)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.RegHKey.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(TimeZone)\\s*(=)\\s*(((local)|(\"local\"))|([-+]?[0-9]*\\.?[0-9]+(e[-+]?[0-9]+)?))\\s*$"
      scope: meta.option.TimeZone.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: support.constant.option_values.rainmeter

    # 
    - match: "(?i)^\\s*(TimeZone)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$|\\(.*\\)\\s*$))(.*)\\s*$"
      scope: meta.option.TimeZone.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(meter)\\s*(=)\\s*((BAR|BITMAP|BUTTON|HISTOGRAM|IMAGE|LINE|ROTATOR|ROUNDLINE|SHAPE|STRING)|\"(BAR|BITMAP|BUTTON|HISTOGRAM|IMAGE|LINE|ROTATOR|ROUNDLINE|SHAPE|STRING)\")\\s*$"
      scope: meta.option.meter.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.names.rainmeter

    # 
    - match: "(?i)^\\s*(meter)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.meter.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # Rainmeter plugins
    # they might be declared as:
    # - Plugin=ActionTimer
    # - Plugin=ActionTimer.dll
    # - Plugin=Plugins\ActionTimer.dll
    - match: "(?i)^\\s*(plugin)\\s*(=)\\s*(((Plugins\\\\)?(ActionTimer|AdvancedCPU|CoreTemp|FolderInfo|FileView|InputText|iTunesPlugin|PerfMon|PingPlugin|PowerPlugin|Process|QuotePlugin|ResMon|RunCommand|SpeedFanPlugin|VirtualDesktops|UsageMonitor|WiFiStatus|AudioLevel|Win7AudioPlugin|WindowMessagePlugin)(\\.dll)?)|\"((Plugins\\\\)?(ActionTimer|AdvancedCPU|CoreTemp|FolderInfo|InputText|iTunes|MediaKey|NowPlaying|PerfMon|Ping|Power|Process|Quote|RecycleManager|ResMon|RunCommand|SpeedFan|VirtualDesktops|WebParser|UsageMonitor|WiFiStatus|Win7Audio|WindowMessage)(\\.dll)?)\")\\s*$"
      scope: meta.option.plugin.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.names.rainmeter

    # Deprecated plugins
    # Were moved to measures; see announcement https://forum.rainmeter.net/viewtopic.php?f=13&t=27744
    - match: "(?i)^\\s*(plugin)\\s*(=)\\s*(((Plugins\\\\)?(MediaKey|NowPlaying|RecycleManager|WebParser)(\\.dll)?)|\"((Plugins\\\\)?(MediaKey|NowPlaying|RecycleManager|WebParser)(\\.dll)?)\")\\s*$"
      scope: meta.option.plugin.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: invalid.deprecated.bang.rainmeter

    # custom plugins
    - match: "(?i)^\\s*(plugin)\\s*(=)\\s*(MSIAfterburner.dll)\\s*$"
      scope: meta.option.plugin.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.names.rainmeter
    
    # MSI After Burner DataSource matching
    # the values are case sensitive so no ignore case
    # with ?-i the case sensivity is disabled
    - match:  "^\\s*(?i)(DataSource)(?-i)\\s*(=)\\s*(Core clock|Fan speed|Fan tachometer|Framerate|GPU usage|GPU temperature|GPU voltage|Memory clock|PCB temperature|Shader clock)\\s*$"
      scope: meta.option.plugin.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter
    # basically everything else is invalid
    - match: "^\\s*(?i)(DataSource)(?-i)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.meter.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(TooltipIcon)\\s*(=)\\s*((INFO|WARNING|ERROR|QUESTION|SHIELD)|\"(INFO|WARNING|ERROR|QUESTION|SHIELD)\")\\s*$"
      scope: meta.option.TooltipIcon.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # 
    - match: "(?i)^\\s*(TooltipIcon)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$|.*\\.ico\\s*$))(.*)\\s*$"
      scope: meta.option.TooltipIcon.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # Matches either Horizontal, Vertical or in quotation marks
    # group one captures GraphOrientation
    # because group 2 is the inner one
    - match: "(?i)^\\s*((Graph|Bar)Orientation)\\s*(=)\\s*((Horizontal|Vertical)|\"(Horizontal|Vertical)\")\\s*$"
      scope: meta.option.Orientation.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        3: keyword.operator.option.equal.rainmeter
        4: support.constant.option_values.rainmeter

    # 
    - match: "(?i)^\\s*((Graph|Bar)Orientation)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.Orientation.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        3: keyword.operator.option.equal.rainmeter
        5: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(bitmapalign)\\s*(=)\\s*((Left|Center|Right)|\"(Left|Center|Right)\")\\s*$"
      scope: meta.option.bitmapalign.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # 
    - match: "(?i)^\\s*(bitmapalign)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.bitmapalign.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(Autoscale)\\s*(=)\\s*((0|1(k)?|2(k)?)|\"(0|1(k)?|2(k)?)\")\\s*$"
      scope: meta.option.Autoscale.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # 
    - match: "(?i)^\\s*(Autoscale)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.Autoscale.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # GraphStart options
    - match: "(?i)^\\s*(GraphStart)\\s*(=)\\s*((Left|Right)|\"(Left|Right)\")\\s*$"
      scope: meta.option.GraphStart.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # invalid GraphStart options
    - match: "(?i)^\\s*(GraphStart)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.GraphStart.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # FontWeight attribute of String Meter
    - match: "(?i)^\\s*(fontweight)\\s*(=)\\s*([1-9]\\d{0,2})\\s*$"
      scope: meta.option.fontweight.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: constant.numeric.rainmeter

    # invalid FontWeight options
    - match: "(?i)^\\s*(fontweight)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.fontweight.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(stringalign)\\s*(=)\\s*(((Left|Right|Center)(Bottom|Top|Center)?)|\"((Left|Right|Center)(Bottom|Top|Center)?)\")\\s*$"
      scope: meta.option.align.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # 
    - match: "(?i)^\\s*(stringalign)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.align.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # StringStyle attribute of String Meter
    - match: "(?i)^\\s*(stringstyle)\\s*(=)\\s*((Normal|Bold|Italic|Bolditalic)|\"(Normal|Bold|Italic|Bolditalic)\")\\s*$"
      scope: meta.option.stringstyle.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # invalid string styles
    - match: "(?i)^\\s*(stringstyle)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.stringstyle.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(stringeffect)\\s*(=)\\s*((none|shadow|border)|\"(none|shadow|border)\")\\s*$"
      scope: meta.option.stringeffect.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # 
    - match: "(?i)^\\s*(stringeffect)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.stringeffect.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # 
    - match: "(?i)^\\s*(stringcase)\\s*(=)\\s*((none|upper|lower|proper)|\"(none|upper|lower|proper)\")\\s*$"
      scope: meta.option.stringcase.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter

    # 
    - match: "(?i)^\\s*(stringcase)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.stringcase.invalid.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter

    # Include statements
    - match: "(?i)\\s*(@include([^=])*)\\s*(=)"
      scope: meta.option.predefined.include.rainmeter
      captures: 
        1: storage.type.option.predefined.include.rainmeter
        3: keyword.operator.option.equal.rainmeter

    # Predefined options for meters and measures
    - match: "(?i)^\\s*(Program|Parameter|State|OutputFile|OutputType|StartInFolder|Background|BackgroundMode|BackgroundMargins|AccurateText|DefaultUpdateDivider|ImageCrop|Greyscale|Image(Name|Tint|Flip|Rotate|Alpha|Crop)|UseExifOrientation|SolidColor(2)?|GradientAngle|beveltype|Blur|BlurRegion([2-9]{1,1}|[0-9]{2,})?|Update|TransitionUpdate|Skin(Width|Height)|DragMargins|OnRefreshAction|OnCloseAction|On(Un)?FocusAction|OnChangeAction|OnUpdateAction|OnWakeAction|Author|Description|AppVersion|LocalFont([2-9]{1,1}|[0-9]{2,})?|DynamicVariables|Name|Information|Version|License|Group|Measure|InvertMeasure|Disabled|UpdateDivider|StartValue|EndValue|Increment|LoopCount|(Max|Min)Value|AverageSize|Action|ActionList([0-9])+|IgnoreWarnings|If(Above|Equal|Below)(Value|Action)|IfCondition([2-9]{1,1}|[0-9]{2,})?|If(True|False)Action([2-9]{1,1}|[0-9]{2,})?|IfMatch([2-9]{1,1}|[0-9]{2,})?|If(Not)?MatchAction([2-9]{1,1}|[0-9]{2,})?|Substitute|Formula|UpdateRandom|UniqueRandom|(Low|High)Bound|Processor|Drive|Total|Label|Type|IgnoreRemovable|DiskQuota|Net(In|Out|Total)Speed|Traffic(Action|Value)|Interface|Cumulative|Plugin|Reg(HKey|Key|Value)|ScriptFile|Format|TimeZone|TimeStamp|TimeStampFormat|TimeStampLocale|FormatLocale|DaylightSavingTime|AddDaysToHours|SecondsValue|Meter|X|Y|W|H|MeterStyle|Shape([2-9]{1,1}|[0-9]{2,})?|Inline(Pattern|Setting)(.*)?|MeasureName([2-9]{1,1}|[0-9]{2,})?|Hidden|AntiAlias|ToolTip(Text|Title|Icon|Type|Width|Hidden)|TransformationMatrix|Padding|Paused|Bar(Color|Image|Border|Orientation)|(Primary|Secondary|Both)?ColorMatrix[12345]|Flip|Bitmap(Image|Frames|TransitionFrames|ZeroFrame|Extend|Digits|Align|Separation)|Button(Image|Command)|SecondaryMeasureName|(Primary|Both|Secondary)(Color|Image(Crop|Tint|Flip|Rotate|Alpha)?|Greyscale)|(Primary|Both|Secondary)?ImagePath|Graph(Start|Orientation)|PreserveAspectRatio|ScaleMargins|Tile|MaskImageName|MaskImagePath|MaskImageFlip|MaskImageRotate|Line(Count|Width|Length|Start)|LineColor([2-9]{1,1}|[0-9]{2,})?|Scale([2-9]{1,1}|[0-9]{2,})?|HorizontalLine(s|Color)|Offset(X|Y)|(Start|Rotation)Angle|ValueRemainder|Control(Length|Start|Angle)|(Length|Start)Shift|Solid|Font(Color|Size|EffectColor|Face)|String(Align|Style|Effect|Case|)?|(Pre|Post)Fix|Autoscale|Percentual|NumOfDecimals|Text|ClipString(W|H)?|Angle|(Left|Right|Middle|(X(1|2)))Mouse(Down|Up|DoubleClick)Action|Mouse(Over|Leave)Action|MouseScroll(Down|Up|Left|Right)Action|MouseActionCursor(Name)?|CPUInclude|CPUExclude|TopProcess|CoreTemp(Type|Index)|Folder|InfoType|RegExpFilter|Include(SubFolders|(Hidden|System)Files)|Command[0-9]*|DefaultValue|Password|FocusDismiss|DefaultArtwork|Player(Name|Type|Path)|TrackChangeAction|DisableLeadingZero|PerfMon(Object|Counter|Instance|Difference)|DestAddress|UpdateRate|Timeout(Value)?|PowerState|ProcessName|PathName|Separator|Subfolders|FileFilter|RecycleType|ResCountType|SpeedFan(Type|Number|Scale)|SysInfo(Type|Data)|VD(Manager|MeasureType|DesktopCount|On((De)?Activate|Change)|Desktop|Width|Height|RefreshOnUpdate)|Desktop(Name|Wallpaper)|Screenshot|Url|RegExp(Substitute)?|FinishAction|OnRegExpErrorAction|OnConnectErrorAction|OnDownloadErrorAction|StringIndex(2)?|DecodeCharacterReference|Debug|Debug2File|Download(File)?|ErrorString|ForceReload|LogSubstringErrors|ProxyServer|UserAgent|Header([2-9]{1,1}|[0-9]{2,})?|CodePage|WiFiInfoType|WiFiIntfID|WiFiListStyle|Window(Name|Class|Message)|Context(Title|Action)([2-9]{1,1}|[0-9]{2,})?|Recursive|Count|Show(DotDot|Folder|File|Hidden|System)|(Hide)?Extensions|Sort(Date)?Type|SortAscending|Port|ID|RMSAttack|RMSDecay|RMSGain|PeakAttack|PeakDecay|PeakGain|FFTSize|FFTOverlap|FFTAttack|FFTDecay|Bands|FreqMin|FreqMax|Sensitivity|Parent|Channel|Type|FFTIdx|BandIdx|WildcardSearch|Index|IgnoreCount|DateType|Icon(Path|Size))\\s*(=)"
      scope: meta.option.predefined.rainmeter
      captures: 
        1: storage.type.option.predefined.rainmeter
        78: keyword.operator.option.equal.rainmeter

    # UsageMonitor plugin
    # Specific Alias Options
    - match: "(?i)^\\s*(Alias)\\s*(=)\\s*(CPU|RAM|RAMSHARED|IO|IOREAD|IOWRITE|GPU|VRAM|VRAMSHARED)"
      scope: meta.option.predefined.rainmeter
      captures:
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter
    # Specific Index Options
    - match: "(?i)^\\s*(Index)\\s*(=)\\s*(\\d+)"
      scope: meta.option.predefined.rainmeter
      captures:
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: constant.numeric.rainmeter
    # Specific Blacklist, Whitelist Options
    - match: "(?i)^\\s*(Blacklist|Whitelist)\\s*(=)\\s*"
      scope: meta.option.predefined.rainmeter
      captures:
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
      push: pipe-seperated-file-list

    # Specific Rollup, Percent, RawValue, PIDToName Options
    - match: "(?i)^\\s*(Rollup|Percent|RawValue|PIDToName)\\s*(=)\\s*(1|0)"
      scope: meta.option.predefined.rainmeter
      captures:
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: support.constant.option_values.rainmeter
    # Invalid Rollup, Percent, RawValue, PIDToName Options
    - match: "(?i)^\\s*(Rollup|Percent|RawValue|PIDToName)\\s*(=)\\s*(\\d+)\\s*$"
      scope: meta.option.predefined.rainmeter
      captures:
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        3: invalid.rainmeter
    # All UsageMonitor Options
    - match: "(?i)^\\s*(Alias|CategoryDefault|Counter|Index|Name|Blacklist|Whitelist|Rollup|Percent|RawValue|PIDToName)\\s*(=)\\s*"
      scope: meta.option.predefined.rainmeter
      captures:
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
    - match: "(?i)^\\s*(Alias|CategoryDefault|Counter|Index|Name|Blacklist|Whitelist|Rollup|Percent|RawValue|PIDToName)\\s*"
      scope: meta.option.predefined.rainmeter
      captures:
        1: storage.type.option.predefined.rainmeter
    # Invalid Alias options
    - match: "(?i)^\\s*(Alias|CategoryDefault|Counter|Index|Name|Blacklist|Whitelist|Rollup|Percent|RawValue|PIDToName)\\s*(=)\\s*(?!(.*#.*#.*$|.*\\[.*\\].*$))(.*)\\s*$"
      scope: meta.option.predefined.rainmeter
      captures:
        1: storage.type.option.predefined.rainmeter
        2: keyword.operator.option.equal.rainmeter
        4: invalid.rainmeter
    
    
    # Option Index
    #

    # Constants used in Calc measures
    - match: "(?i)\\b(PI|E|RANDOM)\\b"
      scope: support.constant.rainmeter

    # Functions used in Calc measures
    - match: "(?i)\\b(((a)?(tan(2)?|sin|cos))|abs|exp|log|ln|sqrt|sgn|frac|trunc|floor|ceil|min|max|clamp|round|rad|deg)\\s*(?=\\()"
      scope: support.function.math.rainmeter

    # All other options in a section
    - match: "^\\s*([^\\s=]+)\\s*(=)"
      scope: meta.option.rainmeter
      captures: 
        1: storage.type.option.rainmeter
        2: keyword.operator.option.equal.rainmeter

    # Format placeholder
    - match: "%[0-9]+"
      scope: constant.language.format.rainmeter

    # Formatting strings for time formats
    - match: "![0-9]*i!"
      scope: constant.language.format.rainmeter

    - include: color-definition


  color-definition:
    - include: dec-color-definition
    - include: hex-color-definition
  
  # RGB color definition
  dec-color-definition:
    - match: "\\b(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})(\\s*,\\s*(\\d{1,3}))?\\b"
      scope: meta.numeric.color.numeric.rainmeter
      captures: 
        1: constant.numeric.color.red.numeric.rainmeter
        2: constant.numeric.color.green.numericrainmeter
        3: constant.numeric.color.blue.numeric.rainmeter
        5: constant.numeric.color.alpha.numeric.rainmeter

  # Hex color definition
  hex-color-definition:
    - match: "\\b(\\h{2,2})(\\h{2,2})(\\h{2,2})(\\h{2,2})?\\b"
      scope: meta.numeric.color.hex.rainmeter
      captures: 
        1: constant.numeric.color.red.hex.rainmeter
        2: constant.numeric.color.green.hex.rainmeter
        3: constant.numeric.color.blue.hex.rainmeter
        4: constant.numeric.color.alpha.hex.rainmeter   


  all-variables:
    - include: built-in-variables
    - include: escaped-variables
    - include: static-variables
    - include: env-variables
    - include: mouse-variables

  built-in-variables:
      # Rainmeter builtin variables
    - match: "(?i)(#@#|#PROGRAMDRIVE#)|(#CONFIGEDITOR#)|(#PROGRAMPATH#)|(#SETTINGSPATH#)|(#SKINSPATH#)|(#PLUGINSPATH#)|(#ADDONSPATH#)|(#CURRENTPATH#)|(#ROOTCONFIGPATH#)|(#CURRENTFILE#)|(#CURRENTCONFIG#)|(#CURRENTSECTION#)|(#CURRENTCONFIGWIDTH#)|(#CURRENTCONFIGHEIGHT#)|(#CURRENTCONFIGX#)|(#CURRENTCONFIGY#)|(#[Pp]?WORKAREAX#)|(#[Pp]?WORKAREAY#)|(#[Pp]?WORKAREAWIDTH#)|(#[Pp]?WORKAREAHEIGHT#)|(#[PpVv]?SCREENAREAWIDTH#)|(#[PpVv]?SCREENAREAHEIGHT#)|(#CRLF#)|(#WORKAREAWIDTH#)|(#WORKAREAHEIGHT#)|(#[PpVv]?SCREENAREAX#)|(#[PpVv]?SCREENAREAY#)|(#WORKAREAX@\\d+#)|(#WORKAREAY@\\d+#)|(#WORKAREAWIDTH@\\d+#)|(#WORKAREAHEIGHT@\\d+#)|(#SCREENAREAX@\\d+#)|(#SCREENAREAY@\\d+#)|(#SCREENAREAWIDTH@\\d+#)|(#SCREENAREAHEIGHT@\\d+#)"
      scope: support.variable.rainmeter

  escaped-variables:
    # Escaped variables (must be before normal ones to override them)
    - match: "#\\*[^#\\s]+?\\*#"
      scope: meta.text.rainmeter

  static-variables:
    # Normal variables
    - match: "#[^#\\s]+?#"
      scope: variable.other.static.rainmeter

  env-variables:
    # Environment variables
    - match: "%[A-Za-z][0-9a-zA-Z_]+?%"
      scope: variable.other.env.rainmeter

  mouse-variables:
    # Mouse position variables
    - match: "(?i)\\$Mouse(X|Y)(:%)?\\$"
      scope: support.variable.rainmeter


  bangs:
    # Bangs
    - match: "(?i)!((FadeDuration(Group)?)|(EditSkin)|(SetClip)|(SetWallpaper)|(About)|(Manage)|(Log)|(LsBoxHook)|(ResetStats)|(TrayMenu)|(RefreshApp)|(Quit)|(SetOption(Group)?)|(WriteKeyValue)|(SetVariable(Group)?)|(Toggle(Group|Config)?)|(Move(Meter)?)|(DeactivateConfig(Group)?)|(ActivateConfig)|(Refresh(Group)?)|(Redraw(Group)?)|(SetTransparency(Group)?)|((Show|Hide|Toggle)Fade(Group)?)|((Show|Hide|Toggle|Add|Remove)Blur)|(Draggable(Group)?)|(ZPos(Group)?)|(KeepOnScreen(Group)?)|(ClickThrough(Group)?)|AutoSelectScreen(Group)?|(SnapEdges(Group)?)|(SkinMenu)|(SkinCustomMenu)|((Show|Hide|Toggle|Update)Meter(Group)?)|(((Dis|En)able|Toggle|Update)Measure(Group)?)|(CommandMeasure)|((Un|Toggle)?PauseMeasure)|((Show|Hide)(Group)?|(Update)|(LoadLayout)))\\b"
      scope: support.function.bang.rainmeter

    - include: mouse-action-bangs
  # https://docs.rainmeter.net/manual-beta/bangs/#MouseAction
  mouse-action-bangs:
    # reversed order because of priority of same common action names
    - include: skin-group-bangs
    - include: meter-group-bangs
    - include: meter-bangs
    
  meter-bangs:
    # Parameters: Meter, MouseAction(s), Config (optional)
    - match: "(?i)!((Disable|Clear|Enable|Toggle)MouseAction)"
      scope: support.function.bang.rainmeter
    - include: mouse-action-name
  meter-group-bangs:
    # Parameters: MouseAction(s), Group, Config (optional)
    - match: "(?i)!((Disable|Clear|Enable|Toggle)MouseActionGroup)"
      scope: support.function.bang.rainmeter
  skin-group-bangs:
    # Parameters: MouseAction(s), Group
    - match: "(?i)!((Disable|Clear|Enable|Toggle)MouseActionSkinGroup)"
      scope: support.function.bang.rainmeter
  mouse-action-name:
    # need other scopes if the action name is in front and thus a key
    - match: "({{mouse_action_name}})\\s*(=)"
      captures:
        1: storage.type.option.predefined.rainmeter
        4: keyword.operator.option.equal.rainmeter
    # this is a mouse action name in a parameter
    - match: "{{mouse_action_name}}"
      scope: support.constant.option_values.rainmeter

  # Include statements
  includes:
    - match: "(?i)\\s*(@include([^=])*)\\s*(=)"
      scope: meta.option.predefined.include.rainmeter
      captures: 
        1: storage.type.option.predefined.include.rainmeter
        3: keyword.operator.option.equal.rainmeter


  # negative lookahead to negate having @include as a variable
  variable-section-variables:
    - match: "(?i)^\\s*(?!@include([^=])*)([^\\s=]+)\\s*(=)"
      captures:
        2: storage.type.variable.rainmeter
        3: keyword.operator.option.equal.rainmeter


  meter-shape-modifier:
    # - meta_scope: source.rainmeter

    - include: meter-shape-fill-type
    - include: meter-shape-stroke-type
    - include: meter-shape-stroke-start-cap-type

    # attribute modifier
    - match: "|\\s*(Fill|Stroke(Width|StartCap|EndCap|DashCap|Dashes|LineJoin|DashOffset)?)\\s+"
      captures:
        1: support.constant.option_values.rainmeter
    # transform modifier
    - match: "|\\s*(Rotate|Scale|Skew|Offset|TransformOrder)\\s+"
      captures:
        1: support.constant.option_values.rainmeter
    # extend modifier
    - match: (Extend)
      captures:
        1: support.constant.option_values.rainmeter

  meter-shape-fill-type:
    - match: "(?i)\\s*(Fill)\\s+(Color|LinearGradient|RadialGradient)\\s+"
      captures:
        1: support.constant.option_values.rainmeter
        2: support.constant.option_values.rainmeter
  meter-shape-stroke-type:
    - match: "(?i)\\s*(Stroke)\\s+(Color|LinearGradient|RadialGradient)\\s+"
      captures:
        1: support.constant.option_values.rainmeter
        2: support.constant.option_values.rainmeter
  meter-shape-stroke-start-cap-type:  
    - match: "(?i)\\s*(StrokeStartCap)\\s+(Flat|Round|Square|Triangle)\\s*"
      captures:
        1: support.constant.option_values.rainmeter
        2: support.constant.option_values.rainmeter

  pipe-seperated-file-list:
    # match first entry in the pipe seperated list
    - match: "(?i)\\s*([a-zA-Z0-9._-]+)\\s*"
      captures:
        1: support.constant.option_values.rainmeter
    # match all entries being pipe seperated
    - match: "(?i)\\s*(\\|)\\s*([a-zA-Z0-9._-]+)\\s*"
      captures:
        1: keyword.operator.option.equal.rainmeter
        2: support.constant.option_values.rainmeter
    # invalid all other seperators 
    - match: "(?i)\\s*([^a-zA-Z0-9._-|\\s]+)\\s*"
      captures:
        1: invalid.rainmeter
    - match: "$"
      pop: true