Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tests/ export-ignore
Comment thread
rchl marked this conversation as resolved.
Outdated
64 changes: 64 additions & 0 deletions .github/workflows/ci-syntax-tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: CI Syntax Tests

on:
push:
branches:
- 'main'
tags-ignore:
- '**'
paths:
- '.github/workflows/ci-syntax-tests.yml'
- '**.sublime-syntax'
- '**/syntax_test_*'
- '**.tmPreferences'
pull_request:
branches:
- '**'
paths:
- '.github/workflows/ci-syntax-tests.yml'
- '**.sublime-syntax'
- '**/syntax_test_*'
- '**.tmPreferences'
workflow_dispatch:

jobs:
syntax_tests:
name: Sublime Text ${{ matrix.build }}
runs-on: ubuntu-latest
timeout-minutes: 15 # default is 6 hours!
strategy:
matrix:
include:
- build: 4180
default_packages: v4180
- build: 4200
default_packages: v4200
- build: latest
default_packages: master
steps:
- name: Checkout Default Packages
uses: actions/checkout@v4
with:
repository: sublimehq/Packages
ref: ${{ matrix.default_packages }}
path: st_syntax_tests/Data/Packages

- name: Delete default package tests
run: |
find st_syntax_tests/Data/Packages/*/ -type f -name 'syntax_test*' -exec rm -v '{}' \;

- name: Checkout ESPHome
uses: actions/checkout@v4
with:
path: st_syntax_tests/Data/Packages/ESPHome

- name: Run Syntax Tests for Sublime Text ${{ matrix.build }}
run: |
if [[ "${{ matrix.build }}" == "latest" ]]; then
wget -O st_syntax_tests.tar.xz https://download.sublimetext.com/latest/dev/linux/x64/syntax_tests
else
wget -O st_syntax_tests.tar.xz https://download.sublimetext.com/st_syntax_tests_build_${{ matrix.build }}_x64.tar.xz
fi
tar xf st_syntax_tests.tar.xz
cd st_syntax_tests
./syntax_tests
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.8
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# ESPHome

ESPHome YAML configuration file syntax.

See [ESPHome YAML configuration documentation](https://esphome.io/guides/yaml/).
19 changes: 19 additions & 0 deletions YAML (esphome) - Comments.tmPreferences
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>scope</key>
<string>source.yaml-esphome</string>
Comment thread
rchl marked this conversation as resolved.
Outdated
<key>settings</key>
<dict>
<key>shellVariables</key>
<array>
<dict>
<key>name</key>
<string>TM_COMMENT_START</string>
<key>value</key>
<string># </string>
</dict>
</array>
</dict>
</dict>
</plist>
14 changes: 14 additions & 0 deletions YAML (esphome) - Indentation Rules.tmPreferences
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>scope</key>
<string>source.yaml-esphome - string - comment</string>
<key>settings</key>
<dict>
<key>increaseIndentPattern</key>
<string>^.*[:\[{]\s*$</string>
<key>decreaseIndentPattern</key>
<string>^\s*[\]}]</string>
</dict>
</dict>
</plist>
8 changes: 8 additions & 0 deletions YAML (esphome).sublime-settings
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
// YAML mandates that tabs aren't used for indentation
"translate_tabs_to_spaces": true,

// In practice, editing YAML files with anything other than two space
// indentation is tedious, due to the "- " list prefix
"tab_size": 2,
}
107 changes: 107 additions & 0 deletions YAML (esphome).sublime-syntax
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
%YAML 1.2
# Extends built-in YAML syntax with support for embedded c++ blocks.
# The blocks can either be specified using a "lambda" key or "!lambda" tag.
# See https://esphome.io/guides/yaml/ and https://esphome.io/automations/templates/#config-lambda
# for more details.
#
# Notes:
# - Single and double-quoted "lambda" keys are not supported.
# - Code between "yaml-esphome begin" and "yaml-esphome end" tags are additions
# relative to the orignal YAML syntax. The rest of the code is copied from
# YAML syntax.
---
# http://www.sublimetext.com/docs/syntax.html
name: YAML (esphome)
scope: source.yaml-esphome
version: 2

extends: Packages/YAML/YAML.sublime-syntax

contexts:
block-pair:
- match: ( *)(\?)(?=\s)
captures:
2: meta.mapping.yaml punctuation.definition.key-value.begin.yaml
push: block-key-explicit

# --- yaml-esphome begin ---
- match: (lambda)\s*(:)(?=\s+|$)
captures:
1: meta.mapping.key.yaml meta.string.yaml string.unquoted.plain.out.yaml
2: meta.mapping.yaml punctuation.separator.key-value.mapping.yaml
push: lambda-body
# --- yaml-esphome end ---

# Attempt to match plain-out scalars and highlight as "meta.mapping.key",
# if followed by a colon
- match: '{{_flow_key_out_lookahead}}'
push: block-key-implicit
- match: :(?=\s)
scope: meta.mapping.yaml punctuation.separator.key-value.mapping.yaml
Comment thread
rchl marked this conversation as resolved.
Outdated

property-body:
- meta_scope: meta.property.yaml

# --- yaml-esphome begin ---
- match: (?=!lambda)\s*
set: lambda-body
# --- yaml-esphome end ---

# &Anchor
# http://yaml.org/spec/1.2/spec.html#&%20anchor//
- match: (&)({{ns_anchor_name}})(\S+)?
captures:
1: keyword.control.property.anchor.yaml punctuation.definition.anchor.yaml
2: entity.name.other.anchor.yaml
3: invalid.illegal.character.anchor.yaml
pop: 1
# !Tag Handle
# http://yaml.org/spec/1.2/spec.html#tag/property/
- match: '{{c_ns_tag_property}}(?=\ |\t|$)'
scope: storage.type.tag-handle.yaml
pop: 1
- match: \S+
scope: invalid.illegal.tag-handle.yaml
pop: 1
Comment thread
rchl marked this conversation as resolved.
Outdated

# --- yaml-esphome begin ---
lambda-body:
- meta_include_prototype: false
- match: (!lambda)\s*
captures:
1: meta.property.yaml keyword.control.directive.tag.yaml
Comment thread
rchl marked this conversation as resolved.
Outdated
- include: block-scalar-lambda
Comment thread
deathaxe marked this conversation as resolved.
Outdated
- match: (["'])
pop: 1
embed: scope:source.c++
embed_scope: source.c++.embedded.yaml
escape: \1
Comment thread
rchl marked this conversation as resolved.
Outdated
- match: (?=[^\s]|$)
pop: 1
embed: scope:source.c++
embed_scope: source.c++.embedded.yaml
escape: $
Comment thread
rchl marked this conversation as resolved.
Outdated

block-scalar-lambda:
- match: (?:(\|)|(>))(?:([1-9])([-+])|([-+])?([1-9])?) # c-b-block-header(m,t)
captures:
1: keyword.control.flow.block-scalar.literal.yaml
2: keyword.control.flow.block-scalar.folded.yaml
3: constant.numeric.indentation-indicator.yaml
4: storage.modifier.chomping-indicator.yaml
5: storage.modifier.chomping-indicator.yaml
6: constant.numeric.indentation-indicator.yaml
set: block-scalar-body-lambda
Comment thread
deathaxe marked this conversation as resolved.
Outdated

block-scalar-body-lambda:
Comment thread
deathaxe marked this conversation as resolved.
Outdated
- meta_include_prototype: false
- match: ^([ ]+)(?! )
pop: 1
embed: scope:source.c++
embed_scope: source.c++.embedded.yaml
Comment thread
rchl marked this conversation as resolved.
Outdated
escape: ^(?!\1|\s*$)
- match: ^(?=\S) # the block is empty
pop: 1
- match: .+
scope: invalid.illegal.expected-comment-or-newline.yaml
# --- yaml-esphome end ---
102 changes: 102 additions & 0 deletions tests/syntax_test_lambda.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# SYNTAX TEST "Packages/ESPHome/YAML (esphome).sublime-syntax"
# <- source.yaml-esphome comment


## Lambda mappings

lambda: return id(uri) == "";
# <- meta.mapping.key meta.string string.unquoted.plain.out
#^^^^^ meta.mapping.key meta.string string.unquoted.plain.out
# ^ - source.c++
# ^^^^^^^^^^^^^^^^^^^^^ source.c++

lambda: 'return id(uri) == "";'
# <- meta.mapping.key meta.string string.unquoted.plain.out
#^^^^^ meta.mapping.key meta.string string.unquoted.plain.out
# ^^ - source.c++
# ^^^^^^^^^^^^^^^^^^^^^ source.c++
# ^ - source.c++

lambda: "return id(uri);"
# <- meta.mapping.key meta.string string.unquoted.plain.out
#^^^^^ meta.mapping.key meta.string string.unquoted.plain.out
# ^^ - source.c++
# ^^^^^^^^^^^^^^^ source.c++
# ^ - source.c++

lambda: |-
# ^ keyword.control.flow.block-scalar.literal
# ^ storage.modifier.chomping-indicator
return id(uri);
#^^^^^^^^^^^^^^ source.c++
foo: 1
# <- - source.c++


## Lambda tags

foo: !lambda return id(uri)
# ^^^^^^^ meta.property keyword.control.directive.tag
# ^^^^^^^^^^^^^^ source.c++

foo: !lambda 'return id(uri)'
# ^^^^^^^ meta.property keyword.control.directive.tag
# ^ - source.c++
# ^^^^^^^^^^^^^^ source.c++
# ^ - source.c++

foo: !lambda "return id(uri)"
# ^^^^^^^ meta.property keyword.control.directive.tag
# ^ - source.c++
# ^^^^^^^^^^^^^^ source.c++
# ^ - source.c++

foo: !lambda |-
# ^^^^^^^ meta.property keyword.control.directive.tag
# ^ keyword.control.flow.block-scalar.literal
# ^ storage.modifier.chomping-indicator
const id = id(uri);
#^^^^^^^^^^^^^^^^^^^ source.c++
return id;
#^^^^^^^^^^ source.c++
foo: 1
# <- - source.c++


## Lambda key with lambda tag

lambda: !lambda return id(uri);
# ^^^^^^^ meta.property keyword.control.directive.tag
# ^^^^^^^^^^^^^^^ source.c++

lambda: !lambda "return id(uri);"
# ^^^^^^^ meta.property keyword.control.directive.tag
# ^ - source.c++
# ^^^^^^^^^^^^^^^ source.c++
# ^ - source.c++

lambda: !lambda 'return id(uri);'
# ^^^^^^^ meta.property keyword.control.directive.tag
# ^ - source.c++
# ^^^^^^^^^^^^^^^ source.c++
# ^ - source.c++

lambda: !lambda |-
# ^^^^^^^ meta.property keyword.control.directive.tag
# ^ keyword.control.flow.block-scalar.literal
# ^ storage.modifier.chomping-indicator
return id(uri);
#^^^^^^^^^^^^^^^ source.c++
foo: 1
# <- - source.c++


## Unterminated

lambda:
foo: 1
# <- - source.c++

foo: !lambda
foo: 1
# <- - source.c++