Skip to content

tymnim/not-html-blazejs.vim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

not-html-blaze.vim

A Neovim plugin that lets you edit Meteor BlazeJS HTML templates using a concise, readable syntax called not_html_blaze. When you open an .html file, it is automatically decompiled into not_html_blaze syntax -- including Spacebars expressions like {{#if}}, {{> template}}, and {{helper}}. When you save, it is transparently compiled back to HTML with Spacebars. The underlying .html file is never changed to a different format -- not_html_blaze is purely a visual editing layer.

What it looks like

HTML with Spacebars on disk:

<template name="taskList">
  {{! Task list component}}
  {{#if hasPermission}}
    <h2>{{title}}</h2>
    {{#each task in tasks}}
      <div class="task {{#if task.done}}completed{{/if}}">
        <span>{{task.name}}</span>
        {{> taskActions taskId=task._id canEdit=true}}
      </div>
    {{else}}
      <p>No tasks found.</p>
    {{/each}}
  {{else}}
    <p>Access denied.</p>
  {{/if}}
</template>

What you see and edit in Neovim:

~template(name: taskList) {
  $! { Task list component }
  #if (hasPermission) {
    ~h2 { ${title} }
    #each (task in tasks) {
      ~div(class: task ${#if (task.done) { completed }}) {
        ~span { ${task.name} }
        ~>taskActions (taskId: task._id canEdit: true)
      }
    } #else {
      ~p { No tasks found. }
    }
  } #else {
    ~p { Access denied. }
  }
}

Features

  • Transparent roundtrip -- open HTML with Spacebars, edit as not_html_blaze, save back. No data loss.
  • Full BlazeJS support -- helpers, block helpers (#if, #each, #with, #let), template inclusions, dynamic attributes, and Spacebars comments.
  • Preserves structure -- DOCTYPE declarations, HTML comments, Spacebars comments, blank lines, and line breaks all survive the roundtrip.
  • Syntax highlighting -- elements, attributes, Blaze helpers, block helpers, template inclusions, and escapes are all highlighted.
  • Zero dependencies -- pure Lua, no external tools or binaries required.
  • Toggle on/off -- disable the plugin with :NotHtmlBlazeToggle to edit raw HTML when needed.

Installation

{
  "tymnim/not-html-blazejs.vim",
  config = function()
    require("not_html_blaze").setup()
  end,
}
Plug 'tymnim/not-html-blazejs.vim'

Then in your init.lua:

require("not_html_blaze").setup()

Or in your init.vim:

lua require("not_html_blaze").setup()
use {
  "tymnim/not-html-blazejs.vim",
  config = function()
    require("not_html_blaze").setup()
  end,
}

Local development

Clone the repo and add it to your runtime path:

vim.opt.runtimepath:prepend("~/path/to/not-html-blazejs.vim")
require("not_html_blaze").setup()

Setup

Call setup() to activate the plugin. It hooks into BufReadCmd and BufWriteCmd for *.html and *.htm files.

require("not_html_blaze").setup({
  enabled = true, -- set to false to start disabled
})

Commands

Command Description
:NotHtmlBlazeToggle Toggle the plugin on/off. When off, HTML files open and save as raw HTML.
:NotHtmlBlazeCompile Convert the current buffer from not_html_blaze to HTML (in-place).
:NotHtmlBlazeDecompile Convert the current buffer from HTML to not_html_blaze (in-place).

Syntax reference

Elements

Every HTML element becomes ~tagname. Attributes go in (), children go in {}.

~div                                    → <div></div>
~img(src: photo.jpg)                    → <img src="photo.jpg"/>
~p { Hello }                            → <p>Hello</p>
~a(href: /, class: nav-link) { Home }   → <a href="/" class="nav-link">Home</a>

Attributes

Key-value pairs separated by :, multiple attributes separated by ,. Values are unquoted and run until the next , or ).

~meta(charset: utf-8)
~div(class: container main, id: app)

Boolean attributes are bare names:

~script(defer, src: app.js)
~input(disabled)

Helpers

Spacebars {{expression}} becomes ${expression}. Keyword args use : instead of =.

${username}                             → {{username}}
${formatDate createdAt format: short}   → {{formatDate createdAt format=short}}

Helpers can appear in text and attribute values, including concatenated directly with text (no space):

~p { Hello ${username} }                → <p>Hello {{username}}</p>
~div(class: item ${activeClass})        → <div class="item {{activeClass}}">
~div(id: tabs-${randomId})              → <div id="tabs-{{randomId}}">
~p { prefix-${name}-suffix }            → <p>prefix-{{name}}-suffix</p>

Raw helpers (HTML injection)

Spacebars {{{expression}}} (unescaped HTML) becomes ~${expression}:

~${rawContent}                          → {{{rawContent}}}
~${toHtmlString (helper arg)}           → {{{toHtmlString (helper arg)}}}

Block helpers

Spacebars block helpers use # prefix. Args in (), body in {}.

#if / #elseif / #else:

#if (isAdmin) {
  ~p { Admin panel }
} #elseif (isMod) {
  ~p { Moderator view }
} #else {
  ~p { Standard view }
}

#each:

#each (item in items) {
  ~li { ${item.name} }
} #else {
  ~li { No items found }
}

#with:

#with (currentUser) {
  ~span { ${name} }
}

#let:

#let (name: person.bio.firstName age: person.bio.age) {
  ~p { ${name} is ${age} years old }
}

Generic blocks:

#myBlock (args) {
  content
}

Blocks in attribute values (including concatenated with text):

~a(class: #if (active) { on } #else { off })
                                        → <a class="{{#if active}}on{{else}}off{{/if}}">
~div(class: container-#if (show) { visible } #else { hidden })
                                        → <div class="container-{{#if show}}visible{{else}}hidden{{/if}}">

Template inclusions

Spacebars {{> template args}} becomes ~>template (args):

~>myTemplate                            → {{> myTemplate}}
~>Template.contentBlock                 → {{> Template.contentBlock}}
~>userCard (name: (nameHelper person) timestamp: time)
                                        → {{> userCard name=(nameHelper person) timestamp=time}}

Dynamic attributes

Spacebars dynamic attributes <div {{attrs}}> become $-prefixed boolean attrs:

~div($attrs)                            → <div {{attrs}}>
~div(class: container, $dynamicAttrs)   → <div class="container" {{dynamicAttrs}}>

Comments

HTML comments use ~!, Spacebars comments use $!:

~! { TODO\: fix this }                  → <!-- TODO: fix this -->
$! { Template-only note }               → {{! Template-only note }}

DOCTYPE

~!doctype(html)                         → <!DOCTYPE html>

Escaping

Use \ to escape breaking characters (~ # { } ( ) : ,) and special sequences (${, $!) in text or attribute values:

~div(style: height\: 100px)
~p { Price is \~5 }
~p { \#not a block helper }
~p { \${not a helper} }

Running tests

nvim -l test/test_lua.lua

Full specification

See spec.md for the complete language specification, grammar, processing pipeline, and decompilation rules.

About

No description, website, or topics provided.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors