Skip to content
| Marketplace
Sign in
Visual Studio Code>Programming Languages>HXPS EDGECAM Postprocessor ToolsetNew to Visual Studio Code? Get it now.
HXPS EDGECAM Postprocessor Toolset

HXPS EDGECAM Postprocessor Toolset

Hexagon Production Software

|
168 installs
| (0) | Free
Syntax highlighting, code navigation (Go to Definition, Find References, Outline, Compare Definitions) and snippets for EDGECAM Postprocessor files (.cxt, .mxt, .cgs, .cgi).
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

HXPS EDGECAM Postprocessor Toolset

Syntax highlighting, code navigation, hover documentation, completion, and diagnostics for EDGECAM post-processor sources.

Supported file types: .cgs · .cgi · .mxt · .cxt


Features

Hover

Hover over You get
POSITION, ANGLE, … numeric system variable and its modifier number
TOOLDESCRIPTION, … string system variable and what it holds
STRMID, SIN, … the function's signature and behaviour
the number on %MACRO=15=… what that number means in every discipline
#MyVar / $MyStr which %DECLARE introduces it, and in which layer
!FT_XMOVE the %FORMAT line it resolves to
${CYCL/BORING} the msgctxt key it looks up in the PO catalogues
%CALL=Name every definition in the chain, and which one compiles in

A macro number always shows all disciplines that define it. That is deliberate: 15 is TOOLCHANGE in Mill and Turn but 165 in C Axis Turn, and 3 is MOVE ARC in Mill but SIMPLE TURN CYCLE in Turn. A number alone is not an answer.

Code navigation

Cursor on F12 jumps to
%CALL=ProcName %PROCEDURE=ProcName, winning definition first
@LABEL the label in the same macro or procedure
#MyVar / $MyStr the %DECLARE line
!FT_NAME the %FORMAT line whose trailing comment names it

Override order comes from the post's %INCLUDE chain — later wins — not from filename prefixes, so Common.cgi and GLOBAL_* sources rank correctly. Shift+F12 finds references; %INCLUDE= paths are clickable.

The EDGECAM template layer

Template code is baked into the .cgd and appears in no .cgi — only in the compiled .mxt/.cxt. In one real post that is 972 %DECLARE lines and 763 procedure definitions that a source-only search can never see. Since that code has to be read and investigated regularly, navigation reaches into compiled output:

  • F12 falls back to the .mxt/.cxt for procedures and variables. #MAXSUBNUMBER resolves to its %DECLARE there instead of coming up empty.
  • Shift+F12 appends compiled hits after the source ones. For a template variable that is the only place there are any: #MAXSUBNUMBER is declared at .mxt:939, set at 3402 and tested at 28378 and 30613, with no source occurrence at all.
  • Hover reads the template's own documentation. Compiled posts carry ;Setvar^ lines describing each configurable template variable, so hovering #MAXSUBNUMBER gives "Maximum Allowed Subroutine Number — category Subroutines · type INT · default 254", and a LIST variable such as #USERADS gives its allowed values (0 Never · 1 Except 360 or Helical · …). Undocumented in the official help, so it is labelled as read from the compiled file.

edgecam-pp.searchCompiledOutput (default on) controls the reference search. Go to Definition falls back regardless — otherwise a template variable would have no reachable definition at all.

If a template symbol is not found, the post has probably not been compiled yet: those declarations only become visible once the .mxt/.cxt exists.

Template awareness — what this post does not compile in

Generic sources serve many machines, and ;IF TEMPLATE= guards decide which parts reach any given post. Those regions are faded, the way VS Code fades unreachable code, so a shared file reads at a glance:

;IF TEMPLATE=3AXMILL^4AXMILL^5AXMILL      ← normal: this post is 5AXMILL
%PROCEDURE=VS_IS_HOLE_CYCLE
    …
%ENDM
;ENDIF

;IF TEMPLATE=2AXLATHE^2CYLATHE^…          ← faded: not compiled into this post
%PROCEDURE=VS_IS_HOLE_CYCLE
    …
%ENDM
;ENDIF

F12 puts the variant this post actually gets first, and hover names the rest with (not in this post) — nothing is hidden, because reading the variant another machine gets is ordinary work.

The template compared against comes from the compiled .mxt/.cxt, not from the .cgs. A .cgs declares an alias (AUTOMILL, AUTOLATHE) that matches no guard; the compiled file's first line carries the resolved name (5AXMILL, 2CYLATHE, …). So this only works once the post has been compiled — before that nothing is faded, because "unknown" must not look like "dead". In a generic source shared by several posts, a region is faded only where it is inactive for all of them.

Switch it off with edgecam-pp.diagnostics.dimInactiveTemplateBlocks.

No colour swatches on variables

VS Code's built-in colour provider reads #RGB, #RGBA, #RRGGBB and #RRGGBBAA as a colour literal in any language — and post-processor variable names collide with that badly. #FEED is four hex digits, so the feedrate variable would render as a colour swatch for #FFEEEEDD; in one production generic tree alone that is 1,079 occurrences, plus 37 other hex-like names such as #dec and #530.

The extension declares that this language has no colour syntax, which suppresses the built-in provider, and ships editor.colorDecorators: false scoped to [edgecam-pp] for the case where colour decorators are forced on globally.

Completion

Context-aware: procedures after %CALL=, labels of the current block after @, declared variables after #/$, format references after !, directives after %, and system variables and functions elsewhere.

Diagnostics

Switchable under edgecam-pp.diagnostics.*:

  • structural — unclosed blocks, nested definitions, %DECLARE inside a macro, a %GOTO whose label is not in the same block, duplicate labels, identifiers over 29 characters, an unterminated %ELSEIF chain, a nested %IF.
  • limits — more than 100 labels in a block (TOO MANY LABELS).
  • crossFile — unresolvable %CALL targets, a %CALL aimed at a %MACRO instead of a %PROCEDURE, missing include files, definitions shadowed later in the chain, and the two rules below.
  • variantOverrides — the override that has no name collision. A dispatcher shim decides which <PREFIX>_<BASE> variant runs with one hardcoded %CALL= line, so when CODECON_THREAD_CYCLE calls PRIVATE_THREAD_CYCLE, GENERIC_THREAD_CYCLE still compiles in and nothing reaches it. Reported on the bypassed definition; the mirror case — a PRIVATE_/CUST_ variant written but never routed to — is a warning, because that is the two-step edit half-done.
  • unreachableProcedures — dead code, faded. EDGECAM only ever invokes %MACRO blocks, so the macros in the compiled post are the roots, %CALL= is the only edge, and any procedure outside that closure is unreachable however plausible its name. Transitive: on one real post PT_PROBE_OFF does have a caller, but that caller is PT_PROBE_MODE, which nothing reaches — the whole probing subtree is dead there. Only files this post owns are judged, and nothing is reported until the post has been compiled.
  • practice — multi-line %IF, and UNVAR/USVAR slots read after a %CALL. Hints, never warnings.

Two things are deliberately not reported by default, because they fire on code that compiles and ships:

  • the documented 100-jump ceiling (tooManyJumps) — six blocks in one production generic tree exceed it, the busiest at 158;
  • #USERn usage (preferDeclareOverUser) — existing sources use those slots pervasively, and the guidance is to leave that code alone unless you are changing the block anyway.

Dead code

A %PROCEDURE is only ever reached by a %CALL, and EDGECAM itself only ever invokes %MACRO blocks. That makes reachability decidable rather than a guess: take the macros in the compiled post as roots, follow %CALL= edges, and whatever is left over is dead. The compiled .mxt/.cxt is what gets walked, because it is the whole merged program — the template layer's macros are the roots, and they exist in no .cgi.

Measured over 40 real posts: 524 unreachable procedures in post-owned files, a median of about 13 per post. Three turning posts account for 46 each — a full turning CODECONS.CGI was copied in and only part of it wired up, so CODECON_BARPULL, CODECON_SUBSPIN_RETRACT and CODECON_ATC_GEN-TOOLCH sit there with a definition, a debug label and no caller at all. The same CODECON_TAILSTOCK is dead in those posts and live in a fourth that calls it twice, so the verdict is per post, never a blanket claim about a name.

Two limits keep it honest:

  • A shared source is never judged. A generic library procedure this machine does not use is the normal state of shared code; across those 40 posts that is 2,822 unreachable procedures in shared files against the 524 in post-owned ones.
  • Nothing is reported before the post has been compiled, for the same reason template fading waits: "cannot say" must not read as "dead".

Where the variant rules already have something to say — a bypassed or unrouted variant is unreachable too — that more specific marker is the only one shown, because it also names the variant that runs instead.

Outline, folding, Compare Definitions

%PROCEDURE, %MACRO (shown as e.g. Toolchange (15)), %MACHINE and %FORMAT appear in the Outline, with their labels as children — matching the fact that a label belongs to its block and nowhere else. %COMMAND blocks and ;IF TEMPLATE= regions fold.

A ↕ Compare definitions CodeLens appears above any procedure another file in the post also defines, and opens a diff of the two bodies.

A second ↕ Compare with … CodeLens appears where the sibling has a different name — GENERIC_THREAD_CYCLE against PRIVATE_THREAD_CYCLE — which is how most overrides actually look. The routed variant is on the right, so the diff reads the same way round as the same-name one. On one real 5-axis mill post the two bodies are 88 and 89 lines and differ in exactly one: the CYCLE70 retract plane.

Reference counts

Above every %PROCEDURE sits a 3 references CodeLens, the way Visual Studio puts one above a C# member. Clicking it opens the peek window on those call sites.

Only procedures get one: a %MACRO is invoked by EDGECAM itself, not by %CALL, so a count on one would always read zero and mean nothing.

Where a procedure has no %CALL in the sources but the compiled post does call it, the count says 1 reference (template) — that is the EDGECAM template layer, and it is the normal state of a CODECON_* dispatcher: 66 of the 89 in one real CODECONS.CGI are reached that way and from no .cgi at all. The two are never added together, because the compiled file is the merged program and already contains each source call once; summing them would double every count. And 0 references is rendered as plain text rather than a link, since there is nothing to peek at — on GENERIC_CODECONS.CGI that is 11 of 112 procedures, GENERIC_THREAD_CYCLE among them, which is the same finding the variant rule reports from the other side.

Compiled posts get counts too, and this is where they are hardest to come by otherwise: the template layer exists only in the .mxt/.cxt, and nothing else tells you who calls one of its procedures. There the count is scoped to that one file, because a compiled post is one whole post — 603 lenses on a real 30,631-line .mxt, with ENTER_PROCEDURE at 345 references and PT_BINC at 346. No (template) suffix appears, since every call in such a file is the compiled program's. Compare Definitions stays absent there: the compiler resolved every override before writing the file, so it holds one definition per name and there is no second body to diff.

Snippets

For .cgs, .cgi, .po, .ini and JavaScript.


A note on multi-line %IF

The language has three conditional shapes:

%IF #X=1 %THEN #Y=1 %ELSE #Y=2          ; single line - the safe one

%IF $W="a" %THEN                         ; continuation: body on the next line,
    $W="b" : %GOTO @done                 ; bound by INDENTATION

%IF #P=1 %THEN                           ; %ELSEIF chain
    #A=1
%ELSEIF #P=2 %THEN
    #A=2
%ENDIF

The last two are highlighted so existing code reads properly, but they get no folding and no auto-indent, and the practice tier hints against them. They depend on indentation to bind their body and cannot be nested, so a formatter that touched the whitespace could change the program. %GOTO branching is the safe form.


Post-processor layout

{POSTNAME}.cgs             — the include list; its ORDER decides what overrides what
{POSTNAME}.mxt / .cxt      — compiled output (read-only; the only place the
                             EDGECAM template layer is visible)
CGI/
  PRIVATE_CODECONS.cgi     — this machine only
  CODECONS.cgi
…/<customer library>/…
  CUST_CODECONS.cgi        — this customer's posts
…/<generic tree>/…
  Common.cgi               — shared, no prefix
  GENERIC_CODECONS.cgi     — every post that includes it

Precedence is the include order: a later %INCLUDE overrides an earlier one. Layer names (GENERIC, CUST, GLOBAL, PRIVATE) are shown for orientation, but the chain is what decides.


Requirements

VS Code ^1.75.0

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft