EmranMR / tree-sitter-blade

tree-sitter grammar for Laravel blade files
MIT License
157 stars 5 forks source link

Tree-Sitter-Blade 🌳

⚠️ Please keep an eye on the release-notes until v1.0.0 is out.⚠️

⚠️ v0.9.0 Upgrade Guide ✨

Introduction (feel free to skip)

This project aims to write the tree-sitter grammar for Laravel Blade.

The grammar could potentially be used in any editors or services that are based on Tree-Sitter. Such as, but not limited to:

php injection

Sponsorship ❤️

If you found this project helpful, I would really appreciate if you can sponsor me so that I could keep maintaining and improving the grammar to include the entire Laravel Ecosystem inlcluding Livewire, AlpineJS, Inertia and so forth. Furthermore keeping the project up to date with future releases of Laravel.

Buy Me A Coffee

Nova Users alt text

Simply install the Laravel Suite Extension from the Extension Library. That includes:

  1. injections including the php injection out of the box!
  2. Autocompletion
  3. Folding
  4. Syntax Highlighting
  5. Auto Indentation

NeoVim Users

If you are a NeoVim user and would like to give this parser a shot, I would highly recommend checking out the NeoVim Discussion

Especially if you encounter any issues!

Injections:

You could have a look at the queries/injection.scm and simply copy and paste. But here are some detailed information:

1. (php)

((text) @injection.content
   (#not-has-ancestor? @injection.content "envoy")
   (#set! injection.combined)
   (#set! injection.language php))

2. (php_only)

((php_only) @injection.content
   (#set! injection.language php_only))

3. optional: (parameter)

((parameter) @injection.content
   (#set! injection.language php_only))

4. Envoy/Bash

((text) @injection.content
   (#has-ancestor? @injection.content "envoy")
   (#set! injection.combined)
   (#set! injection.language bash))
php injection

5. javascript

;; extends

; AlpineJS attributes
(attribute
  (attribute_name) @_attr
    (#lua-match? @_attr "^x%-%l")
  (quoted_attribute_value
    (attribute_value) @injection.content)
  (#set! injection.language "javascript"))

; Blade escaped JS attributes
; <x-foo ::bar="baz" />
(element
  (_
    (tag_name) @_tag
      (#lua-match? @_tag "^x%-%l")
  (attribute
    (attribute_name) @_attr
      (#lua-match? @_attr "^::%l")
    (quoted_attribute_value
      (attribute_value) @injection.content)
    (#set! injection.language "javascript"))))

; Blade PHP attributes
; <x-foo :bar="$baz" />
(element
  (_
    (tag_name) @_tag
      (#lua-match? @_tag "^x%-%l")
    (attribute
      (attribute_name) @_attr
        (#lua-match? @_attr "^:%l")
      (quoted_attribute_value
        (attribute_value) @injection.content)
      (#set! injection.language "php_only"))))

How to Highlight:

❗ Please note each editor uses it's own sets of predicates/variables so you need to look into their documentation.

This is what you need to use inside your highlights.scm. For ease of use, I managed to boil everything down to the following tree-sitter queries:

1. (directives) @theme_selector

2. (directive_start) @theme_selector

3. (directive_end) @theme_selector

4. optional: (attribute (directive) @theme_selector)

5. (comment) @theme_selector

6. optional: (bracket_start) @theme_selector

7. optional: (bracket_end) @theme_selector

Folding

❗ Please note each editor uses it's own sets of predicates/variables so you need to look into their documentation.

The grammar is written in a way to support code folding. You write them in the queries/folds.scm.

As long as your editor supports folds.scm , you can easily write predicates to implement foldings. This will allow you to clear up clutter and focus on the feature you are working in hand.

You can have a look at queries/folds.scm, which has the excerpts used to implement this feature in Nova.

The following is a list of nodes that you need to capture to implement the folding

  1. (directive_start) and (directive_end)
  2. (bracket_start) and (bracket_end)
; Example Query used in Nova to implement folding

(   (directive_start) @start
    (directive_end) @end.after
    (#set! role block))

(   (bracket_start) @start
    (bracket_end) @end
    (#set! role block))
php injection

Quick Note about queries/ folder

This is for tree-sitter cli. Your editor or service might use a different capture group name or predicates.

Consequently, you will need to find out how to approach queries or where they are stored and used in your editor's documentation. For example Nova does not use anything in this folder and uses its own Queries folder instead.

Issues

If something does not look right please raise an issue with a detailed examples of what you are trying to achieve. Add any of the following if necessary:

If you need help with anything else or would like to share tips and tricks for your fellow devs, feel free to use the discussion tab and create a discussion!

Contribution

See the contribution guidelines for more details, as well as in depth info about the grammar itself.