White-glove Tx3 language support for all JetBrains IDEs (IntelliJ IDEA, WebStorm, Rider, CLion, etc.)
Tx3 is a DSL for describing UTxO protocol interfaces on Cardano. → Tx3 Documentation | GitHub
Tx3 compatibility: confirmed against Tx3
v0.22.0(compilertx3c 0.22.0, toolchaintrix 0.26.2). Compatibility is validated in CI two ways: thetrix check/trix buildfixture insrc/test/testData/trix-project/, and thetestLangTourparser test, which parses the canonicallang_tourexample with zero errors. When bumping to a newer Tx3 release, update these badges, refreshLangTour.tx3fromtx3_example_get lang_tour, and re-run the checks.
Full token-level and semantic highlighting with separate configurable colors for:
- Declaration keywords (
party,policy,record,type,tx,env,asset) — bold, distinct color - Block keywords (
input,output,burn,mint,locals,collateral,reference,signers,validity,metadata,cardano) — teal/blue - Field keywords (
from,to,amount,datum,datum_is,redeemer,min_amount,ref,script,hash,since_slot,until_slot,drep,stake,version,coin) — italic purple - Control keywords (
import,let,if,else,true,false) - Built-in types (
Int,Bytes,Bool,Unit,UtxoRef,Address,Value,List,Map) — green - Built-in symbols (
Ada,fees) — gold - Operators, literals, comments — all individually configurable
- Both Default (light) and Darcula (dark) themes are included
Context-aware completion that knows where you are:
- Top level → suggests
party,policy,record,type,txsnippets - Inside
tx { }→ suggestsinput,output,let - Inside
input { }→ suggestsfrom,min_amount,ref,redeemer,datum+ all declared parties - Inside
output { }→ suggeststo,amount,datum+ parties, tx params, input block names - Type positions → built-in types and user-defined record/type names from the same file
- Expressions →
Ada(...)with auto-parens,fees, parties, tx params, let bindings - All completions show type text and tail text for instant documentation
- Tx parameter types shown inline:
quantity/*: Int*/ - Record field types shown after field name:
lock_until/*: Int*/ - Configurable in Settings → Editor → Inlay Hints → Tx3
Collapses any { ... } block that spans multiple lines:
tx Name(...) { ... }— shows tx name and param signaturetype Name { 3 fields }/record Name { 3 fields }— shows field/variant countenv { 2 fields }— shows field countlocals { ... }— local variable bindings inside transactionsinput source { ... }/output { ... }— shows optional block name- Inline record literals (
State { ... }) — folds when 2+ fields - Variant construction (
TypeName::CaseName { ... }) — folds when 2+ fields - Variant case bodies inside type declarations
policy Name = import(very/long/path/...)— folds long import paths/* block comments */— when multi-line- Consecutive
// line comments— when 2+ lines
Press Cmd+7 (macOS) or Alt+7 (Windows/Linux) to open the file outline showing:
- All parties with party icon
- All policies with policy icon
- All types/records with their fields (name and type)
- All transactions with full param signature and nested input/output blocks
- Click any item to jump directly to its definition
Inline semantic warnings:
- Output block missing
tooramount— yellow warning - Input block missing
fromorref— yellow warning - Unresolved name reference — weak warning (wavy underline)
- Bad characters — red error highlight
- Quick-fix: add trailing comma where missing in record and block fields
Trigger templates by typing the abbreviation and pressing Tab:
| Abbreviation | Expands to |
|---|---|
party |
party Name; |
policy |
policy Name = import(path); |
record |
record Name { field: Type, } |
type |
type Name { ... } (variant/record declaration) |
tx |
Full tx declaration skeleton |
inp |
input source { from: Party, min_amount: Ada(...) } |
inpref |
input locked { ref: utxo, redeemer: () } |
out |
output { to: Party, amount: ... } |
outd |
Output block with datum |
change |
Change-back output (source - Ada(qty) - fees) |
let |
let name = expr; |
transfer |
Full 2-party transfer protocol |
File → New → Tx3 Protocol File shows a dialog with starter templates:
- Blank — empty file with header comment
- Simple Transfer — 2-party value transfer
- Vesting Contract — full time-locked vesting protocol (lock and unlock)
- Cmd+/ — toggle
//line comments - Ctrl+Shift+/ — toggle
/* */block comments
Braces {}, parentheses (), and brackets [] auto-close and match.
Ctrl+Alt+L / Cmd+Alt+L — format the entire file with:
- Consistent 4-space indentation inside blocks
- Spaces around operators
- Space after commas and colons
- Opening brace on the same line
- Closing brace on its own line
Identifiers are excluded from spell-checking (blockchain names are intentionally non-dictionary words). Comments and strings are still spell-checked.
tx3-toolkit/
├── build.gradle.kts # Gradle build with grammarkit
├── settings.gradle.kts
├── src/main/
│ ├── kotlin/io/txpipe/tx3/intellij/
│ │ ├── Tx3Language.kt # Language singleton
│ │ ├── Tx3FileType.kt # .tx3 file type
│ │ ├── Tx3Icons.kt # Icon registry
│ │ ├── Tx3Commenter.kt # // and /* */ comments
│ │ ├── Tx3TypedHandler.kt # Auto-closing braces
│ │ ├── Tx3EnterHandler.kt # Smart enter key handling
│ │ ├── Tx3FindUsagesProvider.kt # Alt+F7 find usages
│ │ ├── Tx3ReferenceContributor.kt # Go-to-definition
│ │ ├── Tx3TemplateContextType.kt # Live template context
│ │ ├── Tx3SpellcheckingStrategy.kt # Spell check exclusions
│ │ ├── lexer/
│ │ │ ├── Tx3Lexer.flex # JFlex lexer grammar
│ │ │ ├── Tx3TokenTypes.kt # Token type constants
│ │ │ └── Tx3LexerAdapter.kt # FlexAdapter wrapper
│ │ ├── parser/
│ │ │ ├── Tx3Parser.kt # Recursive descent parser
│ │ │ ├── Tx3ParserDefinition.kt # IntelliJ parser wiring
│ │ │ └── Tx3ElementTypes.kt # AST element types
│ │ ├── psi/
│ │ │ ├── Tx3File.kt # PSI file root
│ │ │ ├── Tx3NamedElement.kt # Named element interface
│ │ │ └── impl/Tx3PsiImpls.kt # All PSI implementations
│ │ ├── highlighting/
│ │ │ ├── Tx3SyntaxHighlighter.kt # Token → color mapping
│ │ │ ├── Tx3SyntaxHighlighterFactory.kt # Factory + color settings page
│ │ │ ├── Tx3Annotator.kt # Semantic error annotations
│ │ │ └── Tx3AddTrailingCommaFix.kt # Quick-fix for trailing commas
│ │ ├── completion/
│ │ │ └── Tx3CompletionContributor.kt # Context-aware completion
│ │ ├── folding/
│ │ │ └── Tx3FoldingBuilder.kt # Code folding regions
│ │ ├── structure/
│ │ │ └── Tx3StructureViewFactory.kt # Structure panel
│ │ ├── hints/
│ │ │ └── Tx3InlayHintsProvider.kt # Type inlay hints
│ │ ├── formatting/
│ │ │ └── Tx3FormattingModelBuilder.kt # Auto-formatter
│ │ └── actions/
│ │ └── Tx3NewFileAction.kt # New file wizard
│ └── resources/
│ ├── META-INF/plugin.xml # Plugin manifest
│ ├── icons/ # SVG icons
│ ├── colorschemes/ # Light + dark theme colors
│ ├── fileTemplates/ # New file templates
│ └── liveTemplates/Tx3.xml # Live template snippets
- JDK 21+
- Gradle 9.0 (wrapper included)
- IntelliJ IDEA 2024.3+ (to run/debug the plugin)
# Generate lexer from JFlex grammar
./gradlew generateLexer
# Build the plugin
./gradlew buildPlugin
# Run a sandboxed IDE with the plugin installed
./gradlew runIde
# Run all tests
./gradlew testThe generated JAR/zip will be in build/distributions/.
The JFlex lexer is defined in src/main/kotlin/.../lexer/Tx3Lexer.flex. Running
./gradlew generateLexer generates src/main/gen/.../Tx3FlexLexer.java.
The parser is hand-written (not auto-generated from a grammar file).
export PUBLISH_TOKEN="your-marketplace-token"
./gradlew publishPlugin// Declare a party (participant in transactions)
party Sender;
party Receiver;
// Declare a policy (on-chain validator script)
policy TimeLock = import(validators/vesting.ak);
// Declare environment variables
env {
lock_until: Int,
owner: Bytes,
}
// Declare a record type (used for datums and redeemers)
record State {
lock_until: Int,
owner: Bytes,
beneficiary: Bytes,
}
// Declare a variant type (sum type / enum)
type Action {
Lock { until: Int },
Unlock,
}
// Declare a transaction template
tx lock(quantity: Int, until: Int) {
// Input block: selects UTxOs matching criteria
input source {
from: Sender,
min_amount: Ada(quantity),
}
// Output block: creates new UTxOs
output target {
to: TimeLock,
amount: Ada(quantity),
datum: State {
lock_until: until,
owner: Sender,
beneficiary: Receiver,
}
}
// Change back to sender
output {
to: Sender,
amount: source - Ada(quantity) - fees,
}
}
Built-in types: Int, Bytes, Bool, Unit, UtxoRef, Address,
Value, List, Map
Built-in symbols: Ada(lovelace), fees
Input fields: from, min_amount, ref, redeemer, datum
Output fields: to, amount, datum
- Fork the repository
- Run
./gradlew runIdeto open a dev IDE - Make your changes
- Run
./gradlew testto ensure tests pass - Open a Pull Request
Please follow the Tx3 language spec when updating parser grammar.
Apache 2.0 — the same as the Tx3 language itself.