Compare commits
8 Commits
6f4a0df871
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 45938c25e9 | |||
| 83fa4442d4 | |||
| bc37f8290c | |||
| c00dd4545a | |||
| 1875efe41e | |||
| 78810a6da7 | |||
| 1b0d825f1d | |||
| 62a5ac203b |
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://raw.githubusercontent.com/EmmyLuaLs/emmylua-analyzer-rust/refs/heads/main/crates/emmylua_code_analysis/resources/schema.json",
|
||||||
|
"runtime": {
|
||||||
|
"version": "LuaJIT",
|
||||||
|
"requirePattern": [
|
||||||
|
"lua/?.lua",
|
||||||
|
"lua/?/init.lua"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"diagnostics": {
|
||||||
|
"disable": [
|
||||||
|
"unnecessary-if",
|
||||||
|
"preferred-local-alias",
|
||||||
|
"redefined-local"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"workspace": {
|
||||||
|
"library": [
|
||||||
|
"/usr/share/nvim/runtime"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,16 +49,14 @@ ifneq ($(filter $(shell uname),FreeBSD NetBSD DragonFly),)
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) $(LANGUAGE_NAME).pc
|
parser: parser/tumblr.$(SOEXT)
|
||||||
|
|
||||||
# Neovim expects parser/<lang>.<soext> on its runtimepath. Build with
|
|
||||||
# `make nvim-parser` after cloning so the drop-in runtime tree works.
|
|
||||||
nvim-parser: parser/tumblr.$(SOEXT)
|
|
||||||
|
|
||||||
parser/tumblr.$(SOEXT): $(PARSER) $(EXTRAS)
|
parser/tumblr.$(SOEXT): $(PARSER) $(EXTRAS)
|
||||||
@mkdir -p parser
|
@mkdir -p parser
|
||||||
$(TS) build --output $@
|
$(TS) build --output $@
|
||||||
|
|
||||||
|
lib: lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) $(LANGUAGE_NAME).pc
|
||||||
|
|
||||||
lib$(LANGUAGE_NAME).a: $(OBJS)
|
lib$(LANGUAGE_NAME).a: $(OBJS)
|
||||||
$(AR) $(ARFLAGS) $@ $^
|
$(AR) $(ARFLAGS) $@ $^
|
||||||
|
|
||||||
@@ -86,7 +84,7 @@ $(SRC_DIR)/grammar.json: grammar.js
|
|||||||
$(PARSER): $(SRC_DIR)/grammar.json
|
$(PARSER): $(SRC_DIR)/grammar.json
|
||||||
$(TS) generate $^
|
$(TS) generate $^
|
||||||
|
|
||||||
install: all
|
install: lib
|
||||||
install -d '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/tumblr '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter '$(DESTDIR)$(PCLIBDIR)' '$(DESTDIR)$(LIBDIR)'
|
install -d '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/tumblr '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter '$(DESTDIR)$(PCLIBDIR)' '$(DESTDIR)$(LIBDIR)'
|
||||||
install -m644 bindings/c/tree_sitter/$(LANGUAGE_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h
|
install -m644 bindings/c/tree_sitter/$(LANGUAGE_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h
|
||||||
install -m644 $(LANGUAGE_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc
|
install -m644 $(LANGUAGE_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc
|
||||||
@@ -120,4 +118,4 @@ clean:
|
|||||||
test:
|
test:
|
||||||
$(TS) test
|
$(TS) test
|
||||||
|
|
||||||
.PHONY: all install uninstall clean test nvim-parser
|
.PHONY: parser lib install uninstall clean test
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
# tree-sitter-tumblr
|
||||||
|
|
||||||
|
A [tree-sitter](https://tree-sitter.github.io/) grammar for [Tumblr
|
||||||
|
theme](https://www.tumblr.com/docs/en/custom_themes) template syntax.
|
||||||
|
The repository also ships filetype detection, queries, and the build
|
||||||
|
glue Neovim needs, so you can install it directly as a plugin.
|
||||||
|
|
||||||
|
The grammar recognises the structure of theme files (variables, block
|
||||||
|
tags, attributes, `lang:` tags, prefixed forms, size suffixes) and
|
||||||
|
treats everything else as opaque content. Surrounding HTML is parsed
|
||||||
|
via injection, which in turn injects CSS into `<style>` and JS into
|
||||||
|
`<script>` through HTML's own queries.
|
||||||
|
|
||||||
|
## Install (Neovim)
|
||||||
|
|
||||||
|
The parser binary lives at `parser/tumblr.so` and is gitignored, so
|
||||||
|
every install path needs a build step that runs `make`.
|
||||||
|
|
||||||
|
### lazy.nvim
|
||||||
|
|
||||||
|
```lua
|
||||||
|
{
|
||||||
|
"https://git.owall.dev/warg/tree-sitter-tumblr",
|
||||||
|
build = "make",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### vim.pack
|
||||||
|
|
||||||
|
```lua
|
||||||
|
vim.api.nvim_create_autocmd("PackChanged", {
|
||||||
|
callback = function(ev)
|
||||||
|
if ev.data.spec.name ~= "tree-sitter-tumblr" then return end
|
||||||
|
if ev.data.kind == "install" or ev.data.kind == "update" then
|
||||||
|
vim.system({ "make" }, { cwd = ev.data.path }):wait()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
vim.pack.add({
|
||||||
|
{ src = "https://git.owall.dev/warg/tree-sitter-tumblr" },
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://git.owall.dev/warg/tree-sitter-tumblr /path/to/repo
|
||||||
|
cd /path/to/repo && make
|
||||||
|
```
|
||||||
|
|
||||||
|
```lua
|
||||||
|
vim.opt.runtimepath:append("/path/to/repo")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Injections
|
||||||
|
|
||||||
|
For HTML, CSS, and JS to highlight inside theme files, those parsers
|
||||||
|
need to be on `runtimepath` too. With `nvim-treesitter`:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:TSInstall html css javascript
|
||||||
|
```
|
||||||
|
|
||||||
|
## Filetype detection
|
||||||
|
|
||||||
|
Files are recognised as `tumblr` by extension or by double-extension:
|
||||||
|
|
||||||
|
- `*.tumblr`
|
||||||
|
- `*.tumblr.html`
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
```sh
|
||||||
|
tree-sitter generate # regenerate src/parser.c from grammar.js
|
||||||
|
tree-sitter test # run the test corpus under test/corpus/
|
||||||
|
make # build parser/tumblr.so
|
||||||
|
```
|
||||||
|
|
||||||
|
The known-name lists in `queries/tumblr/highlights.scm` were extracted
|
||||||
|
from the official Tumblr theme docs. They drive richer highlighting
|
||||||
|
(`@variable.builtin`, `@function.builtin`) for documented names while
|
||||||
|
unknown names still parse and highlight as generic captures.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Apache-2.0. See `LICENSE` for the full text and `NOTICE` for
|
||||||
|
third-party attributions.
|
||||||
@@ -1,20 +1,22 @@
|
|||||||
; Punctuation
|
[
|
||||||
"{" @punctuation.bracket
|
"{"
|
||||||
"}" @punctuation.bracket
|
"}"
|
||||||
":" @punctuation.delimiter
|
] @punctuation.bracket
|
||||||
"-" @punctuation.delimiter
|
|
||||||
"/" @punctuation.delimiter
|
[
|
||||||
|
":"
|
||||||
|
"-"
|
||||||
|
"/"
|
||||||
|
] @punctuation.delimiter
|
||||||
|
|
||||||
"=" @operator
|
"=" @operator
|
||||||
|
|
||||||
; Block and lang keywords inside their tags: the literal "block" / "lang".
|
[
|
||||||
(block_keyword) @keyword.directive
|
(block_keyword)
|
||||||
(lang_keyword) @keyword.directive
|
(lang_keyword)
|
||||||
|
] @keyword.directive
|
||||||
|
|
||||||
; Block names. Known data-block names get @function.builtin; If/IfNot
|
(block_name) @function
|
||||||
; toggles get @keyword.conditional (theme authors may define arbitrary
|
|
||||||
; If* / IfNot* names via <meta name="if:..."> so we match by prefix).
|
|
||||||
((block_name) @keyword.conditional
|
|
||||||
(#match? @keyword.conditional "^[Ii]f([Nn]ot)?[A-Z]"))
|
|
||||||
|
|
||||||
((block_name) @function.builtin
|
((block_name) @function.builtin
|
||||||
(#any-of? @function.builtin
|
(#any-of? @function.builtin
|
||||||
@@ -39,9 +41,12 @@
|
|||||||
"Submission" "SubmissionsEnabled" "TagPage" "Tags" "Text" "Thumbnail"
|
"Submission" "SubmissionsEnabled" "TagPage" "Tags" "Text" "Thumbnail"
|
||||||
"Title" "TrackName" "Video" "VideoThumbnail" "VideoThumbnails"))
|
"Title" "TrackName" "Video" "VideoThumbnail" "VideoThumbnails"))
|
||||||
|
|
||||||
(block_name) @function
|
; Theme authors invent new If*/IfNot* names via <meta name="if:...">.
|
||||||
|
((block_name) @keyword.conditional
|
||||||
|
(#match? @keyword.conditional "^[Ii]f([Nn]ot)?[A-Z]"))
|
||||||
|
|
||||||
|
(variable_name) @variable
|
||||||
|
|
||||||
; Variable names. Known builtins get @variable.builtin, others get @variable.
|
|
||||||
((variable_name) @variable.builtin
|
((variable_name) @variable.builtin
|
||||||
(#any-of? @variable.builtin
|
(#any-of? @variable.builtin
|
||||||
"AccentColor" "Album" "AlbumArtURL" "Alt" "AmPm" "Answer" "Answerer"
|
"AccentColor" "Album" "AlbumArtURL" "Alt" "AmPm" "Answer" "Answerer"
|
||||||
@@ -79,22 +84,14 @@
|
|||||||
"URLSafeSearchQuery" "URLSafeTag" "Username" "UserNumber" "Video"
|
"URLSafeSearchQuery" "URLSafeTag" "Username" "UserNumber" "Video"
|
||||||
"VideoEmbed" "VideoThumbnailURL" "WeekOfYear" "Year"))
|
"VideoEmbed" "VideoThumbnailURL" "WeekOfYear" "Year"))
|
||||||
|
|
||||||
(variable_name) @variable
|
(variable_modifier) @constant.builtin
|
||||||
|
|
||||||
; Size suffix on URL-style variables. Numeric forms read as numbers,
|
|
||||||
; named forms (HighRes, Panorama, ...) as constants.
|
|
||||||
((variable_modifier) @number
|
((variable_modifier) @number
|
||||||
(#match? @number "^[0-9]+(sq)?$"))
|
(#match? @number "^[0-9]+(sq)?$"))
|
||||||
(variable_modifier) @constant.builtin
|
|
||||||
|
|
||||||
; text: / color: / font: / image: prefix and its argument.
|
(variable_prefix) @keyword.directive
|
||||||
(variable_prefix) @keyword
|
(prefix_argument) @constant
|
||||||
(prefix_argument) @variable
|
|
||||||
|
|
||||||
; {lang:Translatable string}
|
|
||||||
(lang_tag) @string.special
|
|
||||||
(lang_text) @string
|
(lang_text) @string
|
||||||
|
|
||||||
; Block attributes: {block:Photoset rows="3"}
|
|
||||||
(attribute_name) @attribute
|
(attribute_name) @attribute
|
||||||
(attribute_value) @string
|
(attribute_value) @string
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
; All non-tag content is HTML. injection.combined concatenates every
|
|
||||||
; content node so an HTML tag opened in one chunk can close in another
|
|
||||||
; (across a {block:Foo}...{/block:Foo}). HTML's own injection queries
|
|
||||||
; then take over for <style> and <script>, giving us CSS and JS for free.
|
|
||||||
((content) @injection.content
|
((content) @injection.content
|
||||||
(#set! injection.language "html")
|
(#set! injection.language "html")
|
||||||
(#set! injection.combined))
|
(#set! injection.combined))
|
||||||
|
|||||||
Reference in New Issue
Block a user