Skip to content

views/

The sidebar: the component tree, its badges, and the detail webview.

component-tree.ts

Builds an N-level trie from the dotted tags, so atoms.forms.input nests three deep. A node can be both a folder and a component at once — Cotton's index convention means button/index.html is <c-button />, so button may have children and be a component itself.

The tag filter lives here, not in the input box that edits it. matchesFilter compares against the full dotted tag, which is why both atoms and button reach atoms.button. Keep it that way: matching only the row label would break every dotted search.

setFilter triggers a full rebuild rather than a surgical refresh, because the match set changes structurally and the cached items have to be re-walked.

tree-decorations.ts

Badges hang off a cotton: URI scheme through FileDecorationProvider. That is the only way to colour a tree row by severity — TreeItem has no API for it.

A component shows one number: the count of its highest severity present, capped at 9+. The full breakdown goes in the row description instead.

component-detail.ts and source-highlight.ts

A webview and its highlighter. The highlighter is hand-rolled and dependency-free because the grammar is small and bounded: three Django delimiters, HTML tag and attribute pairs, and the annotation vocabulary.

It escapes everything it emits and runs with scripts disabled. Attribute spans come from scanTagAttributes, so the panel classifies :size and ::class the same way the diagnostics do.

Adding to the tree

Tree items are cached by full path in _items, which is what makes surgical fire(item) refreshes possible — VS Code only updates items it issued. If you add a new item type, it has to go in that cache or its refreshes will be silently ignored.