VS Code Extensions
K2 Script Support

K2 Script Support

by JakubSchoberxd

K2 ERP Pascal script language support — syntax highlighting, code formatter, and error diagnostics

Downloads

33

Rating

5.0 / 5 (1)

Version

4.22.0

Last updated

Aug 26, 2026

Language support for K2Script, the Pascal-dialect scripting language used in K2 ERP.

Status: Early preview / incomplete — expect rough edges. The extension is actively being developed and tested. Some features may not work correctly in all situations.

Bug reports and feedback: Please report any issues via Microsoft Teams.


Features

Smart editing

  • Autocomplete (Ctrl+Space, or type . / :) — knows your own file's classes, variables and functions, everything pulled in via uses, the full K2 API, and — if a company_structure.json is present — your own company's custom modules and fields too
  • Hover — shows the signature/type of whatever's under your cursor, including any {$DESC '...'} parameter description as readable text instead of the raw directive
  • Parameter hints — shows the expected arguments as you type a call, and keeps refreshing while you edit an existing call's arguments
  • Type-aware argument completion — typing an argument for an enum/Boolean/String/data-module-typed parameter narrows the suggestion list to what actually fits there (enum values, True/False, in-scope strings, the script's own modules aliases) instead of the entire unfiltered list
  • then/begin suggested early — right after an if/while/for/case condition, or right after then/do/of/else/try/finally/except/repeat
  • Go to Definition (F12 / Ctrl+Click) — jumps to a function, variable, class, or usesd unit
  • Outline / breadcrumbs (Ctrl+Shift+O) — functions, procedures and classes (with their methods nested underneath), the main program body, // #flag bookmarks, and TODO/FIXME/HACK/NOTE marker comments, all as their own jump targets
  • Inlay hints at call sites (Foo(name: 'X', count: 3)) — also resolves Obj.Method(...) calls by walking the receiver's type; optionally skip a hint whenever the argument already spells out the parameter name (k2script.inlayHints.hideRedundantParamNames, off by default)
  • Rename (F2) — renames a symbol across the file, and across every other file that uses it
  • Find All References (Shift+F12) — lists every occurrence of a symbol across the file and every other file that uses it, using the same symbol resolution as Rename
  • Smart Expand/Shrink Selection (Ctrl+Shift+Right/Left) — grows the selection outward: word → statement → enclosing block → routine → class → whole file
  • CodeLens above every function/procedure — a one-click shortcut for the function ↔ procedure convert command, a same-file call count, and a live cross-project call count (click through into Call Hierarchy for the full incoming/outgoing detail)
  • TODO/FIXME/HACK/NOTE highlighting — a distinct color per keyword, so leftover-work comments stand out while reading

Refactoring toolkit

  • Convert a routine between function and procedure
  • Class completion — fills in method stubs that are declared but missing from the class body
  • Wrap selection, extract variable, invert if / negate a condition
  • Add / remove begin…end
  • Split / join declarations
  • Convert case ↔ if / else if
  • Change signature — add or remove a parameter and fix every call site, including in other files
  • Add {$DESC '...'} parameter description — quick fix on a program parameter that doesn't have one yet
  • Auto-import quick fix — on an unresolved-call warning, offers to add (or create) the uses entry for whichever workspace unit actually declares that name
  • Call Hierarchy (right-click a function/method → "Show Call Hierarchy") — incoming/outgoing calls across the file and every other file that uses it
  • Postfix completion — type an expression then .if / .nil / .not / .for / .var to wrap it in an if/if … = nil/negated form/for loop, or extract it to a variable
  • Inline Variable — the opposite of Extract Variable: replaces every read of a local var (with exactly one assignment) with the assigned value, and removes the declaration and the assignment
  • Optimize uses — one command removes every unused and duplicate uses entry at once, instead of clicking through each one's own quick fix

Snippets (Ctrl+J)

Type a shortcut and press Ctrl+J to expand it into a full skeleton — tf → try/finally, w → while, class → a full class skeleton, doc → the real K2 info documentation block (auto-filled with the file's own program/unit name), todo/fixme/hack → the matching marker comment, and many more. Press Ctrl+J with nothing typed to see the full picker.

Diagnostics

Inline warnings and errors as you type — and, in the style of the popular "Error Lens" extension, every one of them also shows dimmed at end-of-line, not just in the Problems panel. The type-mismatch family (below) is severity-error when the type came from THIS file's own declarations or a usesd workspace unit (parsed fresh every time — certain), and severity-warning whenever it came from the bundled K2/company registry instead (a point-in-time snapshot that can be stale or incomplete). Every check — regardless of severity — can still be silenced per-line or workspace-wide via the "Nezobrazovat tuto kontrolu" quick fix or k2script.disabledChecks, so an error here means "this is definitely wrong", not "this blocks anything":

  • Mismatched begin/end blocks, a missing ;
  • A .Create / .CreateDM with no matching .Free anywhere in the file — a memory leak
  • Error: .Free / FreeAndNil on CurrentDM, even through a type cast — this crashes the running script
  • An interactive dialog (ShowMessage, MessageBox, …) left inside a WTransaBegin … WTransaCommit transaction — blocks the whole company until someone clicks it
  • Unused local variables and unused uses entries, greyed out with a quick fix to remove them
  • Calls to a function the extension doesn't recognize (heuristic — always a warning, never an error)
  • A "..." double-quoted string — K2Script only ever accepts '...'
  • A call with fewer arguments than the callee actually requires (a trailing run of default-valued parameters can be omitted; a required one can't)
  • An unused function/procedure parameter, alongside unused locals and unused uses entries — quick fix opens the "remove parameter" command
  • The same unit listed twice in uses, or the same module alias declared twice in modules
  • An unexplained number used directly in a comparison (if Zbo.ID = 354) — flagged the first time it appears, with a quick fix to extract it into a named constant
  • A literal assigned to a variable whose declared type obviously can't hold it (Status: Boolean; Status := 0;) — deliberately narrow: only a literal as the whole right-hand side, only against a known primitive type (Integer/Real/Boolean/String family), never a general expression
  • The same check applied to call arguments (Helper(1, 2) when Helper's second parameter is String) — against a function/procedure declared in the same file, in a usesd workspace unit (same trust level — parsed fresh from that file too), or the bundled K2 registry treated as an OVERLOAD LIST (a literal is only flagged when every known overload of that name rejects it, so a real Pascal utility function like IfThen having several valid shapes doesn't produce a false positive)
  • Variable-to-variable assignment between incompatible declared types (Flag: Boolean; Name: String; Flag := Name;) — category-level, not exact-type: any two numeric types are mutually compatible, and a numeric value widens into a Real/Currency, matching how the literal check already treats an integer literal as valid for those
  • The literal check applied to a DOTTED property target too (Zbo.EX_OldId := 0; when EX_OldId is Boolean) — the property's type comes from the same DM/class registry completion and hover already use, so a custom field a company's own company_structure.json added to a standard K2 module is checked exactly like a standard one
  • The variable-to-variable check applied to CALL ARGUMENTS too (Helper(SomeVar) when Helper's parameter is Boolean and SomeVar is String), including a dot-qualified method call (Instance.Method(SomeVar)) resolved the same way the dotted-property check resolves its target's class
  • The variable-to-variable check applied to a DOTTED property target too (Zbo.EX_OldId := SomeVar;) — the other direction of the Tier C literal check above
  • A dotted property READ as a call argument too (Helper(Zbo.EX_Flag)) — the argument check resolves EX_Flag's type via the same class-member lookup, whether it's a bare variable or a property
  • A dotted property READ as a plain assignment's right-hand side too (Flag := Zbo.EX_Flag;) — the same variable-to-variable check now also accepts a two-level property read on either side of :=
  • Result := ... against the enclosing FUNCTION's own declared return type — a literal, a bare variable, or a dotted property, the one shape every other check here always excluded (Result/Self are keywords, not identifiers)
  • The literal-vs-declared-type call-argument check now also resolves a DOT-QUALIFIED method call (Instance.Method(42)), the same way the variable-argument check's own dotted support already does
  • A program parameter with no {$DESC '...'} description — the text K2 shows as that field's label when someone runs the script by hand — and a program script with no ///<summary> documentation block at all
  • Error-adjacent: an except block with nothing inside it — every exception reaching it is silently swallowed, no log, no re-raise
  • Readability/quality nudges, not correctness bugs: a long routine (60+ lines) with almost no comments; a block of 6+ lines duplicated elsewhere in the same file; 3+ commented-out lines that look like real code, not a description; a function/procedure with 8+ parameters; the same non-trivial number repeated 3+ times outside a const; CurrentIndex/SetState set to a bare number instead of the module's own named index constant — all suggested as candidates for splitting into functions, a named constant, or a refactor pass through Claude

Project-wide Database audit

Command Palette → "K2Script: Zkontrolovat Database (memory leaky, CurrentDM.Free)" — scans every .PAS script under Database/ (not just whatever's open in the editor) and opens the results in a tab: which scripts have a leak or a CurrentDM.Free mistake, how many times, on which lines, who wrote them — each one clickable straight to that line.

Command Palette → "K2Script: Zkontrolovat kvalitu kódu" — the same idea for all thirteen readability/quality checks (low readability, duplicate blocks, missing {$DESC}/doc block, empty except, dead code, long parameter lists, magic numbers, raw CurrentIndex/SetState indexes, double-quoted strings, missing call arguments, duplicate uses/modules entries, unexplained comparison numbers) across the whole Database/ folder at once, instead of file by file.

Company customization

If a company_structure.json is present in the workspace, your own custom modules and custom fields complete, hover and validate exactly like a standard K2 one — no more "looks undefined" on something that's real and in daily use.

Syntax highlighting

Full TextMate grammar for K2Script's own syntax — certificate headers, compiler directives, code-generation markers, date/time literals, info blocks, record-mode constants, K2's built-in functions and globals — on top of standard Pascal.

Code formatter

A full automatic code formatter for K2Script .PAS files. Trigger with the standard VS Code format command (Shift+Alt+F / Shift+Option+F on macOS, or right-click → Format Document). Handles indentation for every K2-specific block shape (modules, info...end, single-statement if/for/while, multi-line program(...) headers), collapses stray blank lines, and keeps column-0 markers ({!#CERT...}, {@GENERATED}) unindented.


Supported File Types

.PAS and .pas files are automatically recognised as K2Script.


Requirements

  • VS Code 1.80 or newer
  • No runtime dependencies — pure TypeScript, no external tools needed

Known Limitations

  • Formatter is not perfect. Complex nested constructs (deep case of, with blocks) may still indent incorrectly in edge cases — see CHANGELOG.md for what has been fixed so far.
  • Diagnostics coverage is limited. Only a small subset of possible errors is detected.
  • Type inference is static and partial. Types come from var/modules declarations, uses-included units and the bundled K2 registry — there's no real compiler behind it, so an expression whose type isn't declared anywhere won't resolve. Around 10% of member accesses in the official examples still fall into that gap.
  • The "looks undefined" warning is a heuristic and will flag project-specific functions the bundled registry doesn't know. It's a warning, never an error.
  • Tested only against internal K2 ERP .PAS scripts — third-party Pascal files may not format correctly.

About K2 ERP

K2 is a Czech ERP system. K2Script is a Pascal dialect used to write custom business logic, forms, and integrations directly inside K2. This extension is an unofficial community tool — not affiliated with K2 atmitec s.r.o.

Related extensions