|
| Group | Prefixes |
|---|---|
| Script skeletons | indicator, strategy, library, indicator.full, strategy.full, header, version, import, export |
| Declarations and control flow | fn, fntuple, method, type, typemethod, enum, enuminput, var, varip, if, switch, switchcond, for, forin, forby, forbreak, while, once, runtime.error, log |
| Comments and documentation | section, divider, notes, date, todo, docfn, doctype, docenum, docvar, alertmsg |
| Inputs | input.int, input.float, input.bool, input.string, input.source, input.color, input.timeframe, input.symbol, input.session, input.time, input.price, input.text_area, inputs.inline, inputs.group |
| Plots and drawings | plot, plotshape, plotchar, plotarrow, plotcandle, plotbar, bgcolor, barcolor, hline, fill, gradient, label.new, line.new, box.new, table, polyline, debug |
| Alerts | alertcondition, alert, alert.json |
| Requests, time and sessions | request.security, request.security.tuple, request.security.confirmed, request.security_lower_tf, secfn, session, newbar, backtest, islast |
| Strategy | strategy.entry, strategy.exit, strategy.close, position, sltp, trail |
| Technical analysis | cross, mafn, bb, rsi, atrstop, breakout |
| Collections | array, map, matrix |
A few worth trying first:
strategy.fullwrites astrategy()call with every commonly used parameter on its own line, with choices for quantity type, currency and commission type.sltpadds percent based stop loss and take profit inputs and the twostrategy.exit()calls that use them.request.security.confirmedinserts the non-repainting form of a higher timeframe request;request.security.tuplefetches open, high, low and close in one call.bb,rsiandmafnare complete, plotted indicator sections.mafnincludes a moving average function selected by a string input.tablecreates a table once and fills it on the last bar;debugprints any value in a label on the last bar.section,notesanddatekeep long scripts readable;docfnanddoctypewrite the//@blocks the outline and hover use.
Formatting that respects how Pine reads a file
Format Document and Format Selection work out of the box; turn on editor.formatOnSave if you want it automatic.
Pine is indentation sensitive, so the formatter is deliberately conservative: it never joins or splits a line, and it never moves code between lines. What it does do:
- Indents every local block with exactly four spaces per level, the only width the compiler accepts. A two space block, or a file that mixes tabs and spaces, comes out correct. If your editor is set to tabs, it indents with tabs instead.
- Keeps a wrapped line aligned where you put it, and shifts it off a block indent when Pine would otherwise read it as a new block. Wrapping a long
strategy()call across ten lines stays exactly as you aligned it. - Puts single spaces around operators and after commas, removes them inside brackets, and keeps
close[1],ta.sma,array.new<float>()andimport user/lib/1tight. - Leaves strings, comments and triple-quoted blocks byte for byte alone, including the gap in front of a trailing comment.
- Trims trailing whitespace, caps runs of blank lines at two, and ends the file with a single newline.
Padding used to align a column of assignments is collapsed to one space, which is the one change that is a matter of taste.
Every snippet in this extension and every test fixture has been run through the formatter and back through the TradingView compiler: none of them changed meaning, and formatting twice gives the same file.
Checks that never leave your machine
Every Pine document is checked as you type, using the reference data that ships with the extension. This is on by default because nothing is sent anywhere; the TradingView compiler is still a separate, opt-in setting.
| Rule | What it catches |
|---|---|
missing-version / old-version |
No //@version, or one older than v6. Both offer a fix. |
legacy-name |
A bare v4 name that moved into a namespace: sma, security, tostring, abs. Offers the v6 name. |
local-scope-call |
plot, hline, fill, bgcolor, alertcondition and friends inside an if, for or function body, which the compiler rejects. |
unknown-argument |
A named argument the function does not take, including options dropped between versions such as transp. Suggests the near miss. |
duplicate-argument |
The same named argument passed twice. |
unused-variable / unused-parameter / unused-import |
Declarations nothing reads, shown faded rather than as warnings. |
Turn the whole thing off with pinescript.lint.enabled, or silence single rules with pinescript.lint.disabledRules.
Pine Script: Convert to v6 applies the version, legacy-name and argument fixes across the whole file in one go, which is most of the work of bringing an old script forward. It says exactly what it changed, including any argument it had to remove, and it is a single undo.
Colours you can see and click
Every colour a script names gets a swatch in the gutter of the line: hex literals such as #FF9800, the built-in constants, color.new(color.blue, 25) and color.rgb(255, 152, 0, 40). Click one to open the colour picker; the value is written back as a hex literal or a color.rgb() call, transparency included.
Highlighting that knows your symbols
On top of the grammar, the extension tells the editor which identifiers are yours. Parameters inside a function body, enum members, type fields and import aliases are coloured for what they are rather than guessed at from their spelling. Both bundled themes carry matching colours; other themes pick it up through the standard token types.
Structure, libraries and diagnostics
- Outline. Functions, methods, types with fields, enums with members and top-level variables in the Outline view and breadcrumbs.
- Libraries. Workspace files that call
library()are indexed: their exports complete after the import alias and show up on hover. Withpinescript.libraries.remoteon,importcompletion also lists published TradingView libraries and hover shows their exports. - Compiler diagnostics (opt-in). Set
pinescript.diagnostics.remotetotrueto send the document to the TradingView compiler and see its errors and warnings inline, on open, on save and shortly after you stop typing. - Quick fixes. With diagnostics on, the lightbulb offers a fix for the mistakes the compiler reports most: a v4 name that moved into a namespace (
sma→ta.sma,security→request.security),study→indicator, a misspelt built-in or one of your own names, a misspelt or removed argument (titel→title, droptransp), a variable initialised withnathat needs a type keyword, a declared type that is too narrow, a name that hides a built-in (renamed everywhere at once), and a missing//@version=6. - Commands. New Indicator / Strategy / Library from a template, Generate Docstring (also a lightbulb on declarations), Add Type Annotations for untyped declarations, Open Reference for the built-in under the cursor.
Bringing an old script forward is mostly clicking the lightbulb. This one goes from eight compiler complaints to a clean compile:
study("Legacy", overlay=true) //@version=6
ma = sma(src, len) indicator("Legacy", overlay = true)
daily = security(tickerid, "D", close) ma = ta.sma(src, len)
int slow = ta.ema(close, 50) ==> daily = request.security(tickerid, "D", close)
open = 1 float slow = ta.ema(close, 50)
holder = na openValue = 1
plot(ma, color=color.blue, transp=40) float holder = na
plot(ma, color = color.blue)
Highlighting and themes
- A grammar generated from the v6 reference: every namespace, keyword, annotation, triple-quoted string, format placeholder and hex color gets its own scope, so any theme works and the two bundled ones shine.
- Pine Dark and Pine Light are tuned for every scope the grammar produces and are checked in CI so that no token is left uncolored.
- Folding, bracket matching, auto-closing pairs, comment toggling and four-space indentation are configured for
.pinefiles out of the box.
Files ending in .pine or .pinescript, or starting with //@version=, are recognized automatically.
Pine Script v6 compatibility
The grammar and the documentation data are generated from the v6 reference, so v6 behaviors such as dynamic request.*() calls with series string arguments, short-circuit and/or, point-based text sizes, text.format_bold / text.format_italic, order trimming and negative array indices are covered wherever they have syntax to highlight or document. They are compiler behaviors; the extension does not emulate them.
Commands
| Command | What it does |
|---|---|
| Pine Script: New Indicator | Opens an untitled document from the indicator template |
| Pine Script: New Strategy | Opens an untitled document from the strategy template |
| Pine Script: New Library | Opens an untitled document from the library template |
| Pine Script: Generate Docstring | Inserts or completes //@function, //@param, //@returns, //@type, //@field, //@enum for the declaration at the cursor |
| Pine Script: Add Type Annotations | Prefixes untyped declarations with their inferred type in the selection or the whole file |
| Pine Script: Open Reference | Opens the v6 reference at the built-in under the cursor |
| Pine Script: Convert to v6 | Adds or raises the version pragma and rewrites the v4 names that moved into namespaces |
Settings
| Setting | Default | Meaning |
|---|---|---|
pinescript.completion.enabled |
true |
Completion provider |
pinescript.hover.enabled |
true |
Hover provider |
pinescript.signatureHelp.enabled |
true |
Parameter hints |
pinescript.libraries.local.include |
**/*.pine |
Glob for workspace library discovery |
pinescript.libraries.remote |
true |
Look up published libraries on TradingView for import completion and hover |
pinescript.diagnostics.remote |
false |
Send the document to the TradingView compiler for diagnostics |
pinescript.format.enabled |
true |
Format Document and Format Selection |
pinescript.lint.enabled |
true |
Offline checks; nothing is sent anywhere |
pinescript.lint.disabledRules |
[] |
Rule names the offline checker should skip |
Privacy
Everything works offline. Two features talk to TradingView, both through undocumented endpoints that may change:
- With
pinescript.libraries.remoteon, the prefix you type afterimportand the ids of imported libraries are sent to fetch library metadata and source. - With
pinescript.diagnostics.remoteon, the full text of each open Pine document is sent to the compiler on open, on save and 600 ms after you stop typing.
Nothing else leaves your machine. When a request fails, the feature is paused for five minutes and the reason is written to the "Pine Script" output channel.
Recommended companions
- vscode-icons for a
.pinefile icon.
How it works
src/
grammar.mjs grammar rules, expressed as data
data/
functions.json built-in functions, grouped by namespace (grammar source)
variables.json built-in variables, grouped by namespace (grammar source)
constants.json built-in constants, grouped by namespace (grammar source)
annotations.json compiler annotations
reference.json full v6 documentation, generated by scripts/scrape-reference.mjs
extension/
core/ pure TypeScript: tokenizer, document model, completion context,
symbol resolution, type inference, docstrings, formatter,
offline rules, quick fixes, colours, semantic tokens, templates,
TradingView client
providers/ VS Code adapters: completion, hover, signature help, symbols,
navigation, formatting, colours, semantic tokens, code actions,
diagnostics, offline checks, library index
commands/ command implementations
scripts/
build-grammar.mjs compiles src/ into syntaxes/pinescript.tmLanguage.json and
checks it against reference.json
build-extension.mjs bundles src/extension into dist/extension.cjs with esbuild
scrape-reference.mjs regenerates src/data/reference.json (maintainers, needs network)
check-themes.mjs verifies both themes cover every grammar scope
themes/ Pine Dark and Pine Light
tests/
core/ vitest suites for src/extension and the snippet catalogue
unit/ scope assertions (vscode-tmgrammar-test)
snapshots/ full-file snapshots (vscode-tmgrammar-snap)
syntaxes/pinescript.tmLanguage.json, src/data/reference.json and dist/ are generated. Do not edit them by hand.
Development
git clone https://github.com/yankikucuk/pine-script-syntax-highlighter.git
cd pine-script-syntax-highlighter
npm install
npm run build # grammar + extension bundle
npm run watch # rebuild the bundle on change
npm test # grammar and theme checks, type check, core and grammar tests
npm run package # build the .vsix
Press F5 in VS Code to launch an Extension Development Host with the extension loaded. Use Developer: Inspect Editor Tokens and Scopes to see which scope a token receives.
See CONTRIBUTING.md for the pull request checklist and CHANGELOG.md for release history.
License
MIT © Yankı Küçük
Pine Script® is a registered trademark of TradingView, Inc. This project is not affiliated with TradingView.
