A programming language without editor support is a programming language that nobody will use for long. Developers spend their entire working day inside their editor. If the editor does not understand the language -- if keywords are not highlighted, if brackets are not matched, if there are no snippets for common patterns -- every line of code feels like fighting the tool instead of working with it.
Visual Studio Code dominates the editor market. Building a VSCode extension was not optional for FLIN. It was a prerequisite for any developer adoption.
What the Extension Provides
The FLIN VSCode extension, built in Session 252, delivers three core features:
1. Full syntax highlighting for every FLIN token and construct. 2. 50+ code snippets for rapid scaffolding of common patterns. 3. Language configuration for bracket matching, comment toggling, and auto-closing pairs.
The extension ships as a .vsix file (32 KB) that can be installed locally or published to the VSCode Marketplace:
# Local installation
code --install-extension flin-lang-1.0.0-alpha.1.vsix# From Marketplace (once published) code --install-extension flin-lang.flin-lang ```
The TextMate Grammar
VSCode uses TextMate grammars for syntax highlighting. A TextMate grammar is a JSON file that maps regular expressions to scope names, which VSCode then maps to colors based on the active theme.
FLIN's grammar (syntaxes/flin.tmLanguage.json) covers every syntactic construct:
{
"scopeName": "source.flin",
"patterns": [
{ "include": "#comments" },
{ "include": "#strings" },
{ "include": "#keywords" },
{ "include": "#types" },
{ "include": "#decorators" },
{ "include": "#functions" },
{ "include": "#constants" },
{ "include": "#operators" },
{ "include": "#templates" }
]
}The grammar assigns TextMate scopes to FLIN syntax:
| FLIN Syntax | TextMate Scope |
|---|---|
entity, trait, impl | keyword.declaration.flin |
if, else, for, match | keyword.control.flin |
fn, async fn | keyword.declaration.function.flin |
save, delete, where | keyword.operator.data.flin |
@required, @email | entity.name.decorator.flin |
text, int, bool | storage.type.primitive.flin |
true, false, none | constant.language.flin |
| entity.name.tag.flin |
// comment | comment.line.flin |
"string" | string.quoted.double.flin |
{interpolation} | meta.embedded.expression.flin |
By mapping to standard TextMate scopes (like keyword.control, storage.type, constant.language), FLIN inherits correct coloring from every VSCode theme. Whether a developer uses Dark+, Solarized, Monokai, or any custom theme, FLIN code looks correct because the scopes follow established conventions.
Handling FLIN-Specific Syntax
The most challenging parts of the grammar are FLIN's unique constructs: the view template syntax, decorator annotations, and embedded CSS/JavaScript blocks.
View templates use JSX-like syntax within FLIN files. The grammar switches to a tag context when it encounters <, highlighting tag names, attributes, and interpolated expressions:
<div class="card">
<h2>{title}</h2>
<p>{description}</p>
{if showButton}
<button click={handleClick}>Submit</button>
{/if}
</div>In this example, div, h2, p, and button receive tag highlighting. class receives attribute highlighting. {title}, {description}, {showButton}, and {handleClick} receive expression highlighting within their interpolation delimiters.
Decorator annotations like @required, @email, @min(0), and @max(150) are highlighted as decorators, visually distinguishing validation rules from the field definitions they modify.
Embedded blocks for and switch to CSS and JavaScript grammars respectively, providing language-specific highlighting within FLIN files:
<style>
.card {
padding: 1rem;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
</style>The CSS inside the block receives full CSS syntax highlighting, including properties, values, colors, and units.
Fifty Code Snippets
Snippets are the productivity multiplier that makes developers love an extension. Type a prefix, press Tab, and the snippet expands into a complete code template with placeholders for customization.
FLIN's extension includes 50+ snippets organized by category:
{
"Entity Declaration": {
"prefix": "entity",
"body": [
"entity ${1:Name} {",
" ${2:field}: ${3:text}",
" $0",
"}"
],
"description": "Create a new entity"
},
"Function Declaration": {
"prefix": "fn",
"body": [
"fn ${1:name}(${2:params}) -> ${3:text} {",
" $0",
"}"
],
"description": "Create a new function"
},
"Arrow Function": {
"prefix": "arrow",
"body": "${1:name} = (${2:params}) => ${3:expression}",
"description": "Create an arrow function"
},
"API Route GET": {
"prefix": "routeget",
"body": [
"route GET \"/${1:path}\" {",
" $0",
"}"
],
"description": "Create a GET API route"
}
}The snippet categories cover every major FLIN feature:
| Category | Snippets | Examples |
|---|---|---|
| Entity | 2 | entity, entityv (with validation) |
| Functions | 3 | fn, afn (async), arrow |
| Pages | 2 | page, component |
| Routes | 3 | routeget, routepost, routeparam |
| Control Flow | 6 | if, ife, for, while, match, try |
| View | 3 | vfor, vif, vife |
| Data | 5 | save, find, all, where, delete |
| UI | 4 | button, input, style, script |
| Services | 4 | service, guard, middleware, socket |
| Types | 4 | trait, impl, struct, enum |
| Validators | 8+ | @required, @email, @min, @max, etc. |
Each snippet uses VSCode's placeholder syntax ($1, $2, $0) to create tab stops that guide the developer through the template. The $0 marker indicates the final cursor position after all placeholders are filled.
Language Configuration
The language-configuration.json file tells VSCode how to handle FLIN files for editing operations that are not related to highlighting:
{
"comments": {
"lineComment": "//",
"blockComment": ["/*", "*/"]
},
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"],
["<", ">"]
],
"autoClosingPairs": [
{ "open": "{", "close": "}" },
{ "open": "[", "close": "]" },
{ "open": "(", "close": ")" },
{ "open": "\"", "close": "\"" },
{ "open": "'", "close": "'" },
{ "open": "`", "close": "`" },
{ "open": "<", "close": ">" }
],
"surroundingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"],
["`", "`"]
]
}This configuration enables:
- Comment toggling -- Cmd+/ (or Ctrl+/) toggles line comments with
//. - Bracket matching -- Clicking on a bracket highlights its matching pair.
- Auto-closing -- Typing
{automatically inserts}and places the cursor between them. - Surrounding -- Selecting text and typing
"wraps the selection in quotes.
These are small conveniences individually, but collectively they make FLIN feel like a first-class language in VSCode rather than a plain text file that happens to have a .flin extension.
The Extension Package
The extension is structured as a standard VSCode extension package:
extensions/flin-vscode/
package.json # Extension manifest
language-configuration.json
syntaxes/
flin.tmLanguage.json # TextMate grammar
snippets/
flin.snippets.json # Code snippets
icons/
flin-icon.png # Extension icon
README.md # Marketplace description
CHANGELOG.md
PUBLISHING.md # Publishing guide
LICENSEThe package.json manifest declares the extension's identity, capabilities, and contributions:
{
"name": "flin-lang",
"displayName": "FLIN Language",
"description": "Language support for FLIN programming language",
"version": "1.0.0-alpha.1",
"publisher": "flin-lang",
"engines": { "vscode": "^1.75.0" },
"categories": ["Programming Languages"],
"contributes": {
"languages": [{
"id": "flin",
"aliases": ["FLIN", "flin"],
"extensions": [".flin"],
"configuration": "./language-configuration.json"
}],
"grammars": [{
"language": "flin",
"scopeName": "source.flin",
"path": "./syntaxes/flin.tmLanguage.json"
}],
"snippets": [{
"language": "flin",
"path": "./snippets/flin.snippets.json"
}]
}
}The packaged .vsix file is 32 KB -- small enough to include in the FLIN repository and distribute alongside the binary.
Future: Language Server Protocol
The current extension provides syntax-level features: highlighting, snippets, and bracket matching. The next major step is implementing a Language Server Protocol (LSP) server that provides semantic features:
- Go to definition -- Click on a function call to jump to its declaration.
- Find all references -- See everywhere a function or entity is used.
- Hover information -- Display type signatures and doc comments on hover.
- Auto-completion -- Context-aware suggestions for entity fields, function names, and imports.
- Inline diagnostics -- Show type errors and warnings directly in the editor without running
flin check.
The LSP server would run as a background process, maintaining a parsed representation of the project and responding to editor queries in real time. This is a significant undertaking -- essentially building an incremental compiler -- but it transforms the developer experience from "syntax support" to "intelligent assistance."
Editor Coverage
The VSCode extension was the first priority because VSCode holds the largest market share among developers. But the TextMate grammar is portable. Other editors that support TextMate grammars can reuse flin.tmLanguage.json with minimal adaptation:
- Zed -- Direct TextMate grammar support.
- Sublime Text -- Native TextMate grammar support.
- Neovim -- Via nvim-treesitter or TextMate integration.
- JetBrains IDEs -- Via TextMate bundle support.
Building one grammar and reusing it across editors is a deliberate strategy. Rather than maintaining separate highlighting definitions for each editor, we maintain one canonical grammar and adapt it where needed.
The VSCode extension turns FLIN from a language you can use into a language you want to use. Syntax highlighting provides visual structure. Snippets accelerate common patterns. Bracket matching prevents syntax errors. Together, they create an editing experience that feels native rather than foreign -- and that feeling of familiarity is what converts a curious developer into a committed user.
---
This is Part 177 of the "How We Built FLIN" series, documenting how a CEO in Abidjan and an AI CTO designed and built a programming language from scratch.
Series Navigation: - [176] Embedded Demo and Templates - [177] The FLIN VSCode Extension (you are here) - [178] The Module System and Imports