Editor
AXIS Pine editor: CodeMirror 6, diagnostics, 80-col ruler, git sync, stats, docked vs popout, editor bridge.
This page
Editor
The editor is the source axis of intent: Pine text the operator authorizes the engine to run. Completion and hover can use local builtins metadata and optional remote LSP; evaluation is always an engine plugin.
Abstract
| Module | Role |
|---|---|
EditorPane.tsx | Docked/standalone chrome, header tools, detach |
tabbed-editor.tsx | Multi-tab docs, stats strip, Problems, Colors, Symbols, git bar |
PyneEditor.tsx | CM6 mount (extensions + view APIs) |
pyne-language.ts | StreamLanguage / highlighting (namespaces, types, multiline strings) |
pine-symbols.ts + SymbolEmojiManager.tsx | TV-editor-safe glyph catalog + insert panel |
pyne-lsp.ts + data/pyne-builtins.json | Offline completion/hover corpus |
column-ruler.ts | 80-character guide line |
diagnostics.ts | Underlines, gutter, jump-to from last run |
editor-intel.ts | Settings bag for lint / hover / complete / marks / timings |
inline-debug.ts | EOL chips, pin gutter, line flash |
git-sync.ts + ui/EditorGitBar.tsx | Pull / push / storage status |
ui/EditorProblems.tsx | Collapsible problems list |
editor-bridge.ts | Cross-window doc + run messages |
cm-void.ts | Void-theme CM styling |
Conceptual model
Rendering…
Why run on main? Chart, bars, and pane manager live in the main window. Popout is a pure editing surface.
Interface surface
Docked mode
- Right dock by default (
panelChrome.editor); may sit side-by-side with other right panels (e.g. Indicators left of Editor) - FloatableShell: dock left/right/bottom, float, new window
- Detach → popup or tab (
openEditorWindow)
Popout mode
- Main shows “Editor detached” chip + Reattach
- Shared doc key + bridge messages:
hello,doc,run,run-status,reattach,popout-opened,popout-closed
Run entry points
- Editor / topbar Run →
runAndApply(getDoc()) - Popout Run → bridge → main executes
- Command palette: save library, git push/pull, jump to line, toggles
Header tools (axis-editor-tools)
Icon-only (labels in tooltips / aria-label). Open in new tab is in the left hamburger menu with dock options.
| Control | Effect |
|---|---|
| Run | Run script against loaded bars |
| Scriptlogs | Open last-run log.* panel |
| Profiler | profilerEnabled + optional line % gutter; re-run when enabling |
| Debug | Inline end-of-line log/error chips (inlineDebugEnabled) |
| Pins | Chart markers + 📍 gutter (debugPinsEnabled); Alt+P |
| Ruler | 80-column guide (editorRulerEnabled) |
| Hamburger → Open in new tab | Editor in a full browser tab (vs New window popup) |
Details: Debugging.
Stats strip
Bottom of tabbed editor (data-testid="axis-editor-stats"):
| Field | Meaning |
|---|---|
| Pos L:C | Cursor line:column (1-based) |
| Ln | Total lines in document |
| Words / Chars | Document stats |
| Diagnostics badge | Error/warning count from last run — click jumps to first |
| Problems | Expand/collapse problems list |
| Colors | Color chips / picker / converter for hex and color.* |
| Symbols | Insert TV-editor-safe arrows, box drawing, marks, spaces, and chart emoji (raw, quoted, or plotchar) |
| wrap | Soft wrap toggle (editorWrapEnabled, default on) |
Symbols & emoji
Status-bar Symbols (data-testid="axis-editor-symbols") opens a searchable catalog of glyphs used in Pine Script™ plotchar / label.new / table text.
- Mono-safe — ~1 cell in IBM Plex Mono / the TV editor (box drawing,
▲▼●◆✓★, arrows). - Wide / chart-only — official
🠅🠇and emoji (🔥🚀📈). Filter with Mono-safe. - Click inserts at the cursor (replaces the selection). Right-click copies.
- Insert mode: raw glyph, quoted string, or a
plotchar(cond, "mark", "…", location.belowbar)snippet.
Sources: TradingView Exploring Unicode, Text and shapes, box-drawing U+2500, PineCoders conventions.
Highlighting
pyne-language.ts is a stateful stream tokenizer: //@ annotations, // and /* */ (including across lines), quoted and """ / ''' strings with \\n escapes, #RRGGBB(AA) colors, namespaces (ta., label.new), types (int / float / string, series / simple in qualifier position, and declared UDTs / enums as typeName, bold in the void theme), control vs definition keywords, and function names before (. Format leaves continuation lines of an open string or block comment untouched.
Four information surfaces
| Surface | When | Answers |
|---|---|---|
| Hover | Rest on a symbol | Keyword, type, series, namespace, builtin, user input/function, or hex color |
| Param checklist | Inside a call | Used / current / unused args with type + default |
| Pre-eval | While typing / Save | What is wrong before Run |
| Debug chips | After Run, Debug on | Last-run log.* / errors on that source line |
Hover + param checklist are writing-time docs — not a TradingView® debug API. Pre-eval marks the buffer; chips still read last run. Details: Debugging.
Diagnostics & Problems
Pre-eval (as you type) — schedulePreeval waits the idle delay after the last keystroke (default PREEVAL_IDLE_MS = 1000 ms; tab switch uses a shorter beat). Marks clear while typing unless Clear marks while typing is off. Local parse/lint (localPreevaluate) plus POST /lsp/diagnostics when engine=server and remote lint is on. Severity error disables Run when Block Run on errors is on (topbar, editor, Mod-Enter, command palette). Warnings and typos do not block.
Every lint / hover / complete / underline / chip option lives in Settings → Editor (command palette: Open Editor Settings). Defaults match the previous hardcoded behavior.
Local checks: unclosed ( / [ / { and strings, missing entry point, study() → indicator() / strategy(), bare security() → request.security, duplicate indicator() / strategy() / library(), unknown builtin members (strategy.etry, plt → “did you mean …?”). User functions and import aliases are not flagged.
Merge: remote style-noise C001–C004 is dropped; remote syntax errors win the same span; local unknown-member marks still show when remote is down. Hover tooltips use the diagnostic message (including the suggestion).
After a run, diagnosticsFromLastRun(lastRun, doc) still builds ranges from engine error, meta.errors / diagnostics, and error logs with line refs (line 12:, L12:, …). Live pre-eval for the current buffer is listed first; last-run engine messages are kept when they add detail (dropped only when the buffer no longer matches the stamped run source).
- CodeMirror: wavy underlines, severity gutter, hover tooltips
- Problems panel: clickable rows →
scrollToLine/jumpToDiagnostic; originpre-evalvsrunwhen the diagnostic has a source - Empty / pending pre-eval stays No problems (no flicker)
- Unit tests:
tests/editor-diagnostics.test.ts,tests/editor-problems.test.ts,tests/preevaluate.test.ts
80-column ruler
columnRulerExtension paints a dashed guide at character column 80 (measured via CM coords). Toggle Ruler or command palette “Toggle Editor Ruler”.
Git sync bar
Tab toolbar Pull / Push / status (EditorGitBar):
- Uses active storage plugin (
local|cloud|git) - Push →
writeScript(git commits when storage is git) - Pull → optional plugin
sync('pull')+ list/reload bound library id - Config stays in Settings / Script Library (no second credentials UI)
Completion corpus
src/editor/data/pyne-builtins.json is synced from PYNE (scripts/sync-pyne-builtins.sh). Offline completion/hover fall back to this catalog; optional remote LSP when the Pro API is available.
Library load
loadLibraryDoc(doc, name) on editorRef injects storage reads into the active tab.
Internals
editorRef pattern
App holds { getDoc, setDoc?, loadLibraryDoc?, scrollToLine?, jumpToDiagnostic?, getCursor?, insertAtCursor? } populated by CM mount—avoids full-doc store writes every keystroke (doc also mirrored to EDITOR_DOC_KEY).
Persistence
| Key / field | Role |
|---|---|
store.editor + panelChrome.editor | Dock geometry, open, mode |
pynescript.axis.editor.doc | Draft text |
profilerEnabled / inlineDebugEnabled / debugPinsEnabled / editorRulerEnabled / editorWrapEnabled | Editor tools |
Invariants
- Empty doc Run is a no-op at topbar/editor handlers.
- Popout does not own PaneManager.
- Reattach restores shared doc into docked CM.
- AXIS ≠ engine: editor never fully evaluates Pine itself; pre-eval is parse/lint only.
- Debug/Pins still read last run; static diagnostics also come from pre-eval.
Failure modes
| Symptom | Mitigation |
|---|---|
| Two editors diverge | Prefer bridge doc events; reattach |
| Detached but no window | Popup blocked; allow popups; reattach |
| Lost text on crash | editor.doc localStorage; library Save / git push |
| Blank CM (no lines) | Dock column height chain; editor must fill strip |
| No chips/pins | Enable Debug/Pins; logs need line and/or bar_index |
See also
- Debugging — Debug vs Pins, Scriptlogs, Profiler
- UI shell — Topbar, docks, command palette
- Indicators
- Script library