`), then produces this IR:
+
+```text
+Group[
+ "{{#show_hint}}"
+ Indent[
+ Hardline
+ "
"
+ "Check your units!"
+ "
"
+ ]
+ Hardline
+ "{{/show_hint}}"
+]
+```
+
+The `Group` tries to print everything flat first. Since the content contains a block-level child, a `Hardline` forces the group to break, and `Indent` adds one level of indentation to the contents. The final output is:
+
+{/* prettier-ignore */}
+```html
+{{#show_hint}}
+
Check your units!
+{{/show_hint}}
+```
+
+## Bonus Features
+
+### Embedded languages
+
+PrairieLearn's templates don't just contain HTML and Mustache — they also embed CSS/JavaScript, and code snippets inside custom elements like `
`. The LSP and formatter need to handle all of these.
+
+In the LSP, I recognize these regions and delegate syntax highlighting to the appropriate VS Code textmate grammar. I delegate formatting to Prettier.
+
+### Custom lint rules
+
+I also added support for custom lint rules using CSS-selector-like syntax, which is useful for enforcing patterns specific to PrairieLearn. For example, we can check for hidden inputs inside `{{#items}}` sections:
+
+```json
+{
+ "id": "no-hidden-inputs-in-list",
+ "selector": "#items > input[type=hidden]",
+ "message": "Hidden inputs inside {{#items}} sections are usually a mistake"
+}
+```
+
+## Conclusion
+
+This was a fun project to build, and I learned a lot about tree-sitter in the process. Turning this grammar into a full LSP server (the grunt work)
+would not have been possible without the help of AI agents. It's so exciting to see what is now possible with a clever idea and a few prompts. As I
+mention in my [last blog post](https://www.prairielearn.com/about/blog/linting-pit-of-success), I believe that providing tooling to agents is essential for them to be successful -- creating the "missing tooling" for our
+question format will pay dividends!
+
+
+ You can check out the full implementation in the
+ [treesitter-htmlmustache](https://github.com/reteps/treesitter-htmlmustache)
+ repository. If you have questions or feedback, open an issue on the
+ repository!
+
+
+export default ({ children }) => (
+ {children}
+);
diff --git a/src/pages/about/blog/stylish-mustaches/linter.png b/src/pages/about/blog/stylish-mustaches/linter.png
new file mode 100644
index 00000000..37e11eb7
Binary files /dev/null and b/src/pages/about/blog/stylish-mustaches/linter.png differ
diff --git a/src/pages/about/blog/stylish-mustaches/stylish-mustache.png b/src/pages/about/blog/stylish-mustaches/stylish-mustache.png
new file mode 100644
index 00000000..c4067547
Binary files /dev/null and b/src/pages/about/blog/stylish-mustaches/stylish-mustache.png differ
diff --git a/src/pages/about/blog/stylish-mustaches/vscode.png b/src/pages/about/blog/stylish-mustaches/vscode.png
new file mode 100644
index 00000000..b25a199d
Binary files /dev/null and b/src/pages/about/blog/stylish-mustaches/vscode.png differ