Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>CaspianNew to Visual Studio Code? Get it now.
Caspian

Caspian

Jefferson Abraham Omier

|
15 installs
| (0) | Free
Python-first tooling for Caspian: HTML highlighting and IntelliSense inside html(r"""..."""), PulsePoint, components, and file-based routes
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Caspian VS Code Extension

Caspian is a VS Code extension for Caspian Python components, PulsePoint client code, and file-based routing.

Caspian projects are Python-only. Pages, layouts, and components are .py files, and all markup lives inside html(r"""...""") calls. This extension makes that embedded markup feel like a first-class HTML document: syntax highlighting, completions, hover, and navigation, without leaving the Python file.


Highlights

  • HTML syntax highlighting inside html(r"""...""") — tags, attributes, <script> JavaScript, <style> CSS, Jinja {{ ... }} / {% ... %}, and PulsePoint { ... } expressions
  • Single-brace PulsePoint expressions with IntelliSense and hover
  • PulsePoint script tooling for pp. and this. inside <script> blocks
  • PulsePoint and Caspian directive completions inside tags and <template> tags
  • Component tooling powered by settings/component-map.json:
    • x-* component tag and prop completions
    • auto-import edits that insert the matching from ... import ... line
    • hover and go-to-definition for component tags and Python import lines
  • Route and asset tooling powered by settings/files-list.json:
    • completions, hover, definitions, and document links
    • support for markup links, pp.redirect("..."), and Python redirect("...")
  • Global helper IntelliSense from .casp/global-functions.d.ts
  • PulsePoint state rename support inside a markup block
  • caspcomp Python snippet for authoring Caspian components

There are no diagnostics. The extension does not validate markup, props, imports, or routes — it only helps you read and write them.


Activation Model

The extension has two modes:

1) Full workspace mode

Full Caspian services boot only when the workspace root contains:

{}

saved as caspian.config.json.

When that file exists, the extension enables:

  • component map loading and watchers
  • markup completions, hover, definitions, document links, and rename
  • route and asset tooling
  • global helper loading from .casp/global-functions.d.ts

2) Snippet-only mode

Without caspian.config.json, the full Caspian providers stay dormant.

The caspcomp snippet still works in:

  • Python files
  • plain text / untitled files

Syntax highlighting inside html(r"""...""") is a TextMate grammar, so it always works — no workspace config required.


Markup Blocks

A markup block is any html(...) call whose first argument is a triple-quoted string. All of these are recognized:

def page():
    return html(r"""
<div>Hello</div>
""")


@component
def Card(**props):
    return html(r"""
<div {{ attributes }}>{{ children }}</div>
""",
        **{"attributes": attributes, "children": children},
    )


def layout():
    return html(r"""
<slot />
"""), {"title": "Dashboard"}


script = html(r"""
<script>pp.effect(() => {});</script>
""")

The @component decorator is not required — page(), layout(), module-level assignments, and nested calls such as Markup(html(r"""...""")) all work.


Current Feature Set

1) Highlighting

Inside a markup block:

Construct Highlighted as
<div class="..."> HTML
<script> contents JavaScript
<style> contents CSS
onclick="doThing()" JavaScript
{count + 1} JavaScript expression
{{ children }}, {{ value \| e }} Jinja expression
{% if x %}, {# note #} Jinja statement / comment
<div {{ attributes }}> Jinja expression (not attribute names)
pp-for, pp-ref, … PulsePoint attribute

Everything outside the triple-quoted string keeps normal Python highlighting, including trailing tuple returns and keyword arguments after the closing """.

2) Template expressions

Caspian treats single-brace expressions as JavaScript-like template expressions:

return html(r"""
<script>
  const [count, setCount] = pp.state(0);

  function increment() {
    setCount(count + 1);
  }
</script>

<div>{count + 1}</div>
""")

What the extension provides:

  • completions for state variables discovered from the block's <script>
  • completions for functions discovered from the block's <script>
  • completions for common JS globals such as Date, Math, JSON, and console
  • object-property completions for state like {user.}
  • loop-alias completions inside pp-for scopes
  • hover for state variables and functions inside mustache expressions
  • go-to-definition from a mustache expression to its pp.state(...) declaration

3) PulsePoint tooling inside <script>

Typing pp. or this. offers the current PulsePoint API surface:

state, effect, layoutEffect, ref, memo, callback, reducer, context, provideContext, portal, props, createContext, mount, redirect, rpc, enablePerf, disablePerf, getPerfStats, resetPerfStats

Hover documentation is available for PulsePoint methods.

4) PulsePoint attribute completions

For ordinary tags:

pp-component, pp-spread, pp-ref, pp-style, pp-loading-content, pp-loading-url, pp-loading-transition, pp-reset-scroll, pp-spa

For <template> tags:

pp-for, pp-owner

When the cursor is inside a pp-for loop scope, it also suggests a key="..." attribute.

5) Components

Component tooling is driven by settings/component-map.json.

Components are imported with ordinary Python imports and used as x-* tags:

from src.components.Button import Button
from src.components.Card import Card as ProfileCard

def page():
    return html(r"""
<x-button size="sm"></x-button>
<x-profile-card title="Hello" />
""")

The tag mapper is strict:

  • Button becomes x-button
  • ProfileCard becomes x-profile-card
  • PascalCase tag usage is not treated as a component tag

What the extension does:

  • component tag completion for x-* tags
  • auto-import: selecting an un-imported component inserts from <importRoute> import <Name> after the existing imports
  • prop-name completion for imported components
  • literal and boolean-ish value suggestions when prop metadata provides options or Literal[...] / bool
  • hover for component tags, component props, and component symbols on Python import lines
  • go-to-definition from a component tag or from a symbol on a Python import line

6) Global helper functions

If the workspace contains .casp/global-functions.d.ts, the extension loads helper signatures and exposes them inside markup expressions and <script> blocks, with completion, hover, and go-to-definition.

The loader expects definitions in this shape:

// @source: ./helpers/format
const formatPrice: (value: number) => string;

The @source comment is used to resolve definition targets.

7) File-based routing and asset intelligence

Routing and asset tooling is driven by settings/files-list.json.

Recognized route entries are derived from:

  • src/app/index.py -> /
  • src/app/(auth)/signin/index.py -> /signin
  • src/app/users/[id]/index.py -> /users/{id}
  • src/app/docs/[...slug]/index.py -> /docs/{...slug}

Route groups such as (auth) are ignored in the public URL.

Current route and asset support includes:

  • completions in double-quoted href="..." inside markup
  • completions in double-quoted src="..." inside markup
  • completions in pp.redirect("...") inside markup
  • completions in Python redirect("...") outside markup
  • hover for route targets and static assets
  • go-to-definition for routes and assets
  • document links for href routes and src assets

Dynamic routes are inserted as snippets so you can tab through parameters.

The provider also supports query-parameter fallback matching, so links such as /users?id=123 can still resolve to /users/{id} when the route metadata matches.

8) Rename support for PulsePoint state

Inside a markup block, the rename provider supports PulsePoint-oriented symbol updates:

  • renaming a program-scope pp.state(...) variable updates both the state variable and its derived setter
  • matching references in the block's <script> are updated
  • matching references in the markup are updated
  • local script-scope renames stay local instead of rewriting markup state names

Rename is scoped to the markup block under the cursor, not the whole workspace.

9) Python component authoring

In Python or plain text files, typing caspcomp inserts a Caspian component scaffold built around **props, children, class merging, attribute rendering, and an html(r"""...""") body.


Supported File Types

  • Python: the full Caspian feature set
  • Plain text / untitled: caspcomp snippet only

HTML files are not supported. Caspian projects no longer contain them.


Project Metadata

Caspian intentionally depends on explicit generated metadata instead of scanning the whole workspace on every keystroke.

1) caspian.config.json

This file is the switch that enables full Caspian workspace services.

2) settings/component-map.json

This file should contain an array of component records similar to:

[
  {
    "componentName": "Button",
    "filePath": "C:/project/src/components/Button.py",
    "relativePath": "src/components/Button.py",
    "importRoute": "src.components.Button",
    "acceptsArbitraryProps": true,
    "props": [
      {
        "name": "size",
        "type": "Literal['sm', 'lg']",
        "hasDefault": false,
        "options": ["sm", "lg"]
      }
    ]
  }
]

It powers component tag and prop completion, auto-imports, and hover/definition resolution.

3) settings/files-list.json

This file should contain a JSON array of known project files. Both Windows and POSIX-style paths are normalized.

It powers route completion, static asset completion, and hover/definitions/document links for routes and assets.

4) .casp/global-functions.d.ts (optional)

This file is optional. If present, it powers global helper completion, hover, and definitions.

All of these metadata files are watched and reloaded automatically when they change.


Recommended VS Code Settings

Markup lives inside Python strings, so quick suggestions in strings must be enabled for completions to trigger:

"editor.quickSuggestions": {
  "strings": "on",
  "other": "on"
}

Known Limitations

  • Full Caspian services do not boot until caspian.config.json exists at the workspace root.
  • Route and asset tooling targets double-quoted href and src attributes.
  • pp.redirect("...") and Python redirect("...") support targets string literals, not arbitrary computed expressions.
  • Route detection is intentionally opinionated around src/app/**/index.py entry files.
  • Markup blocks are found by scanning for html( followed by a triple-quoted string, so an html( mentioned inside a comment or another string can be picked up.
  • If settings/component-map.json, settings/files-list.json, or .casp/global-functions.d.ts are missing or stale, related suggestions and navigation will be incomplete.

Roadmap

  • richer component documentation in hover text
  • smarter route refactors and rename/move workflows
  • better multi-root workspace behavior
  • workspace bootstrap tooling for generating Caspian metadata files

Contributing

Contributions are welcome.

  • Open an issue with a minimal repro.
  • Submit a focused PR with tests when behavior changes.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft