Now we need to use this to reverse engineer the grammar so we can parse source code into AST without live connection to an instance of RouterOS.
LOL, apparently the forumβs ```routeros marks use a pretty poor coloring scheme and syntax scheme too. While not the whole story in βstatic schemas/ASTβ, for example /console/inspect gets you all the command, directory (like ip, interface, etc), and arguments. So those could always be used to βupdateβ a static grammar with the current set of things β perhaps with curation since there are 70k worth of keywords for example.
See this thread for one example of potentially βaugmentingβ a static/regex .rsc grammar with /console/inspect request=child data.
I updated the RouterOS LSP. The GitHub CHANGELOG.md details the changes. While I should do another animated GIFs - here are some screenshots showing it working in VSCode for Web & NeoVim too showing the newer features.
Download RouterOS LSP
Visual Studio Code use "Extensions"
This will like to the VSCode Extension in "Marketplace" (free) with the "Install" link for VSCode:
https://marketplace.visualstudio.com/items?itemName=TIKOCI.lsp-routeros-ts
or you can just search in VSCode for "RouterOS LSP" too
GitHub Release (for NeoVim) -
See README.md since it more complex... New downloads are at:
some notes...
Scripts with unescaped UTF-8 characters are not recommended...
In short, use Windows1252 encoding. Using "\74\23\12" is okay, but have something like β (em dash) or
(emojis) etc... may causes problems β even if they are in comments.
Still some problems with UTF-8 in comments β close/reopen will generally fix things with UTF-8. But it's complex situation to handle since VSCode "Position" is, essentially, UTF-16...but "tokens" from RouterOS for colors/diagnostics uses UTF-8 - which causes position not align always in some cases. The CHANGELOG details them, which is also shown in VSCode page for RouterOS LSP Extension.

Settings has a "debug level"...
If you have troubles with the LSP, change the level to "verbose". Messages go to VSCode's "Output" panel under "RouterOS LSP" from dropdown:
New Features
"Document Symbols" (for :local and :global)
In VSCode they appear in "Outline" from Explorer sidebar:
Multiple found variables should be groupable and kinda show the declaration from usage.
Completion have icons
... and "help text" if available from /console/inspect
VSCode Only "Walkthrough" shown on "Welcome" page
This is WIP but works to direct you to provide the need RouterOS "baseUrl" and account info:
Experimental TikBook RouterOS Notebook works too
This uses a related extension "TikBook" discussed about in this thread:
NeoVim still works...
Shown with the $PIANO script:
and also shows the "help text" add in this release:
If I may (and if it is possible) the thing that personally I have a lot of difficulties with when attempting to read/parse a script are the parenthesis/brackets.
I wonder if there could be a way to better distinguish (β¦ ) from [β¦ ] and {β¦ } (particulalrly the last two (which is usually but not always mitigated by indentation) but also square and round can be confused.
Having them with different colours?
Or using for them bold/a different font size?
Like this?
https://marketplace.visualstudio.com/items?itemName=MadsKristensen.RainbowBraces
P.S.: the stupid Discourse thinks that opening and closing square brackets without space in the middle (or even with it) means βAhh, the user wants to draw a little square, let me do it: !β
If it was adequate, it would draw a small circle with ()
(and why not a diamond/rhombus with {}?).
The newest version may be improved a bit actually. VSCode already does the same as βrainbow bracesβ does (AFAIK, using VSCode default theme). I tried in VSCode for Web, where I have no plugins other than this one.
I add some extra [ ] on one line to show it, but it does alternate colors for brackets correctly:
I did have some βcustom folding regexβ borrowed from another RouterOS plugin, but in current VSCodeβ¦ telling it RouterOS using {, [, ( braces was enough. No RegExp to define folding, which is also used in bracket matchingβ¦
This fixed issues where folding was not being detected right (which also mean bracket werenβt either), so may fixed color NOT alternating too. #DoingLessIsDoingMore
And you do mess up bracesβ¦ it now lights up like a Christmas Tree in latest LSP extension version β with a warning flagged to end of file past the originally found error from /console/inspect
That all being said, there is βmoreβ than can be done. Currently all the bracket-things are classified as syntax-meta which matches RouterOS scheme.
But the semantic token (used βhintβ VSCode on color) do offer βmodifiersβ. I currently donβt provide any, but I breakup the syntax-meta into sub-categories for different types βmetaβ chapters, which include the brackets and = etc. In VSCode (or any LSP editor) you could be able to explicitly set the colors differently on [ vs { etc. based on the token + modifier .
Whole different set of problems hereβ¦ [ ] are used for links in markdown, so yeah βraw cut-and-pasteβ in post may have odd results. And the highlight.js plugin for RouterOS used in the ```routeros code blocks only really knows V6 syntax, so it too can fail badly. Further doubt most folks think to add routeros to the end of ```β¦
MikroTik should just write a small discourse plugin that calls same /console/inspect request=highlight this does and set the colors on backend. Like it does when βunfurlingβ URL on a line. No highlight.js syntax/grammar updates and βperfectβ colors (i.e. matching CLI).
Also, in VSCode, you should be able to βjumpβ to matching bracket with
β + Shift + \
To see what matches any brace β that all should match it right AFAIK.
Check VSCodeβs_ Help > Keyboard Shortcut Reference if not using Mac to find the shortcut for this
RouterOS LSP 0.5.x Released
The RouterOS LSP has been updated with many small improvements to backend, and some new "commands" and a "watchdog" too. See CHANGELOG.md for details.
It is published on the VS Code marketplace for download within VS Code. As well as on Open-VSIX.
Please do try it out and report any feedback in this thread or open a GitHub issue or pull request is okay too
The RouterOS syntax coloring and completion is same, however both the backend and "UI" have been updated. Here are some some screenshots of the new 0.5.x features:
VS Code Command Palette
Access the LSP settings, logs, aliveness test (part of "watchdog"), as well as command to refresh colors ("Refresh emantic tokens"), and a way to apply to colors to user settings so they can be customized ("Apply RouterOS Syntax Colors")
Settings Changes
The timeout is now exposed in settings. And an option to allow future TikBook versions to "override" the LSP connection settings, to use TikBook extension's settings instead.
Watchdog (liveness check)
The "watchdog" in action... If RouterOS LSP cannot connect when it first loads, an error with appear to allow you to "fix it". The message are "raw" so something like status code 401 means bad password, but plan to use "friendly" messages at some point.
If successful, a small message appears with a RouterOS file is first loaded (which then causes RouterOS LSP to be loaded β extension start only when needed in VS Code):
LSP Core
The backend changes do not have screenshots - but there is good improvement in at unnecessary recalculation of tokens etc. These changes effect all LSP clients, not just VSCode β while the commands are VS Code only features.
On the subject of TikBook (i.e. there is now a settings for it in RouterOS LSP extension)...
TikBook Update Coming Soon
I'm working on an update for TikBook for RouterOS for VS Code with a revised serialization format to allow for both a notebook that is a valid RouterOS script & one that allow
```routerosblocks in Markdown files to be "Run". Conversion between the Markdown-first or RouterOS-first notebooks is possible. I'll start a new thread about when I release an update.
Hey man, thanks so much for making this tool!
Today was my first time ever using VSCode for RouterOS Script, so I guess I was just very lucky that you made this LSP just recently because it would have been quite a different experience otherwise.
I noticed some minor issues, will create reports in your Github Repo.
RouterOS LSP 0.5.4 Released
I updated the RouterOS LSP last week to version 0.5.4. In the new version, among other changes, is better error handling of connection issues. As well as additional support needed for TikBook...
Improved version of TikBook also released
This release has many, many improvements and changes from the prototype discussed in this thread. The file format has changed, so if you tried the 0.1.x version, you'll have to manually fix up the files (please reply if you need help).
To keep things separate, I created a new topic in "3rd Party Tools" for TikBook extension discussed above.
Nice work. Thnx
"Stable" Release 0.6.0
I have "promoted" the previous 0.5.4 "testing" (pre-release in VS Code terms) to a "stable" version of 0.6.0.
There are no significatant changes, other than minor dependacy updates based on bun audit. Even minor numbers are "stable", while odd numbers are "testing" builds, thus only the minor version change
But if you have any trouble, please report here or in GitHub Issues.
For VSCode, in most cases, the extension will auto-update. If not, just Install from VSCode Marketplace Extentions.
For other LSP-enabled editors, download RouterOS LSP Server from GitHub Releases:
TikBook also updated to "stable"...
The TikBook companion extension was also updated to "stable". I plan on adding some new features, including allowing direct editing of /system/scripts from VSCode, among others. For background, VSCode-only features always use the TikBook extension. RouterOS LSP was designed to work with any LSP-enabled editor, so VSCode-specific features are never added in the core LSP server..
https://marketplace.visualstudio.com/items?itemName=TIKOCI.tikbook
Interesting Factoid: Keep your scripts under 28K.
I've been slowing adding tests to RouterOS LSP. Undergirding all actual syntax checking/colors in the LSP /console/inspect request=completion discussed in this thread. This has worked well... but sometime it is slow with very large scripts files, and it seemed kinda random to me exactly what was going on. I ran some tests against a set of scripts from @eworm collection, my forum posts, as well as "synthetic" data (like a large script filled with all comments, for example).
28K is a magic number. Past 28K this, the robots tell me, "go quadriatic", luckily it did some charts... The test RouterOS is CHR with 1GB RAM, 4 Intel CPU cores, no other traffic than REST API to /console/inspect.
βΈ Profiling: synthetic-comments
0.1KB 2ms β
0.3KB 2ms β
0.5KB 3ms β
1.0KB 6ms β
2.0KB 11ms β
3.0KB 17ms β
4.0KB 21ms β
6.0KB 36ms β
8.0KB 63ms β
10.0KB 78ms ββ
12.0KB 105ms ββ
16.0KB 162ms βββ
20.0KB 227ms βββββ
24.0KB 330ms βββββββ
28.0KB 1494ms ββββββββββββββββββββββββββββββ
32.0KB 2199ms ββββββββββββββββββββββββββββββββββββββββββββ
βΈ Profiling: synthetic-commands
0.1KB 2ms β
0.3KB 3ms β
0.5KB 5ms β
1.0KB 8ms β
2.0KB 16ms β
3.0KB 26ms β
4.0KB 33ms β
6.0KB 59ms β
8.0KB 96ms ββ
10.0KB 116ms ββ
12.0KB 142ms βββ
16.0KB 226ms βββββ
20.0KB 310ms ββββββ
24.0KB 418ms ββββββββ
28.0KB 1777ms ββββββββββββββββββββββββββββββββββββ
32.0KB 2351ms βββββββββββββββββββββββββββββββββββββββββββββββ
βΈ Profiling: synthetic-mixed-paths
0.1KB 2ms β
0.3KB 3ms β
0.5KB 4ms β
1.0KB 8ms β
2.0KB 16ms β
3.0KB 25ms β
4.0KB 33ms β
6.0KB 54ms β
8.0KB 102ms ββ
10.0KB 113ms ββ
12.0KB 144ms βββ
16.0KB 222ms ββββ
20.0KB 322ms ββββββ
24.0KB 459ms βββββββββ
28.0KB 2098ms ββββββββββββββββββββββββββββββββββββββββββ
32.0KB 4557ms βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βΈ Profiling: synthetic-complex
0.1KB 5ms β
0.3KB 7ms β
0.5KB 14ms β
1.0KB 24ms β
2.0KB 46ms β
3.0KB 72ms β
4.0KB 110ms ββ
6.0KB 167ms βββ
8.0KB 242ms βββββ
10.0KB 335ms βββββββ
12.0KB 528ms βββββββββββ
16.0KB 755ms βββββββββββββββ
20.0KB 1027ms βββββββββββββββββββββ
24.0KB 1398ms ββββββββββββββββββββββββββββ
28.0KB 5158ms βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
32.0KB 6022ms ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βΈ Profiling: eworm/global-functions.rsc
0.1KB 3ms β
0.3KB 5ms β
0.5KB 10ms β
1.0KB 22ms β
2.0KB 53ms β
3.0KB 81ms ββ
4.0KB 134ms βββ
6.0KB 197ms ββββ
8.0KB 287ms ββββββ
10.0KB 392ms ββββββββ
12.0KB 458ms βββββββββ
16.0KB 627ms βββββββββββββ
20.0KB 943ms βββββββββββββββββββ
24.0KB 1198ms ββββββββββββββββββββββββ
28.0KB 4053ms βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
32.0KB 3721ms ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βΈ Profiling: edge-cases/oversize-32k.rsc
0.1KB 2ms β
0.3KB 4ms β
0.5KB 6ms β
1.0KB 10ms β
2.0KB 22ms β
3.0KB 34ms β
4.0KB 47ms β
6.0KB 77ms ββ
8.0KB 107ms ββ
10.0KB 146ms βββ
12.0KB 200ms ββββ
16.0KB 280ms ββββββ
20.0KB 440ms βββββββββ
24.0KB 571ms βββββββββββ
28.0KB 2163ms βββββββββββββββββββββββββββββββββββββββββββ
32.0KB 2441ms βββββββββββββββββββββββββββββββββββββββββββββββββ
βΈ Profiling: complex/piano.rsc
0.1KB 2ms β
0.3KB 3ms β
0.5KB 5ms β
1.0KB 10ms β
2.0KB 24ms β
3.0KB 38ms β
4.0KB 53ms β
6.0KB 86ms ββ
8.0KB 120ms ββ
10.0KB 160ms βββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
RouterOS Highlight API β Performance Profile
CHR: http://192.168.74.150 β’ 3 runs/point β’ 2 warmup runs
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
## Scaling Analysis
Script Profile Model RΒ² ms/KB
ββββββββββββββββββββββββββββββ ββββββββββββββ ββββββββββββββββββββββββββ ββββββ βββββββ
synthetic-comments comments quadratic (superlinear) 0.917 48.1
synthetic-commands single-path quadratic (superlinear) 0.920 54.2
synthetic-mixed-paths multi-path quadratic (superlinear) 0.877 86.4
synthetic-complex scripting quadratic (superlinear) 0.928 149.8
eworm/global-functions.rsc scripting quadratic (superlinear) 0.904 105.7
edge-cases/oversize-32k.rsc single-path quadratic (superlinear) 0.924 61.5
complex/piano.rsc scripting linear 0.994 15.8
## synthetic-comments
Pure comment lines β minimal tokenization work
Syntax profile: comments
Size Median Min Max Curve
βββββββ ββββββββ βββββββ βββββββ ββββββββββββββββββββββββββββββ
0.1K 2ms 2ms 2ms β
0.3K 2ms 2ms 3ms β
0.5K 3ms 3ms 3ms β
1.0K 6ms 5ms 6ms β
2.0K 11ms 10ms 13ms β
3.0K 17ms 16ms 18ms β
4.0K 21ms 21ms 22ms β
6.0K 36ms 36ms 39ms β
8.0K 63ms 56ms 67ms β
10.0K 78ms 76ms 78ms ββ
12.0K 105ms 102ms 111ms ββ
16.0K 162ms 160ms 162ms βββ
20.0K 227ms 225ms 239ms βββββ
24.0K 330ms 319ms 353ms βββββββ
28.0K 1494ms 1475ms 1519ms ββββββββββββββββββββββββββββββ
32.0K 2199ms 2119ms 2471ms ββββββββββββββββββββββββββββββββββββββββββββ
## synthetic-commands
Repetitive /ip firewall address-list add β same path each line
Syntax profile: single-path
Size Median Min Max Curve
βββββββ ββββββββ βββββββ βββββββ ββββββββββββββββββββββββββββββ
0.1K 2ms 2ms 2ms β
0.3K 3ms 2ms 3ms β
0.5K 5ms 5ms 5ms β
1.0K 8ms 7ms 8ms β
2.0K 16ms 15ms 16ms β
3.0K 26ms 25ms 28ms β
4.0K 33ms 31ms 33ms β
6.0K 59ms 57ms 66ms β
8.0K 96ms 83ms 96ms ββ
10.0K 116ms 107ms 117ms ββ
12.0K 142ms 142ms 144ms βββ
16.0K 226ms 224ms 230ms βββββ
20.0K 310ms 309ms 317ms ββββββ
24.0K 418ms 416ms 423ms ββββββββ
28.0K 1777ms 1768ms 1793ms ββββββββββββββββββββββββββββββββββββ
32.0K 2351ms 2276ms 2373ms βββββββββββββββββββββββββββββββββββββββββββββββ
## synthetic-mixed-paths
Mix of /ip, /interface, /queue, /system paths β wide path resolution
Syntax profile: multi-path
Size Median Min Max Curve
βββββββ ββββββββ βββββββ βββββββ ββββββββββββββββββββββββββββββ
0.1K 2ms 2ms 2ms β
0.3K 3ms 3ms 3ms β
0.5K 4ms 4ms 4ms β
1.0K 8ms 8ms 8ms β
2.0K 16ms 15ms 17ms β
3.0K 25ms 24ms 25ms β
4.0K 33ms 33ms 34ms β
6.0K 54ms 54ms 54ms β
8.0K 102ms 80ms 132ms ββ
10.0K 113ms 111ms 117ms ββ
12.0K 144ms 143ms 144ms βββ
16.0K 222ms 221ms 222ms ββββ
20.0K 322ms 319ms 329ms ββββββ
24.0K 459ms 457ms 460ms βββββββββ
28.0K 2098ms 2085ms 2318ms ββββββββββββββββββββββββββββββββββββββββββ
32.0K 4557ms 4201ms 4875ms βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
## synthetic-complex
Variables, functions, :for, :foreach, :if β heavy scripting
Syntax profile: scripting
Size Median Min Max Curve
βββββββ ββββββββ βββββββ βββββββ ββββββββββββββββββββββββββββββ
0.1K 5ms 4ms 5ms β
0.3K 7ms 6ms 9ms β
0.5K 14ms 12ms 14ms β
1.0K 24ms 22ms 27ms β
2.0K 46ms 45ms 47ms β
3.0K 72ms 69ms 80ms β
4.0K 110ms 98ms 139ms ββ
6.0K 167ms 166ms 191ms βββ
8.0K 242ms 233ms 248ms βββββ
10.0K 335ms 326ms 344ms βββββββ
12.0K 528ms 514ms 534ms βββββββββββ
16.0K 755ms 745ms 796ms βββββββββββββββ
20.0K 1027ms 991ms 1038ms βββββββββββββββββββββ
24.0K 1398ms 1369ms 1448ms ββββββββββββββββββββββββββββ
28.0K 5158ms 5120ms 5179ms βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
32.0K 6022ms 5665ms 6025ms ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
## eworm/global-functions.rsc
Eworm global functions library β dense scripting, many globals
Syntax profile: scripting
Size Median Min Max Curve
βββββββ ββββββββ βββββββ βββββββ ββββββββββββββββββββββββββββββ
0.1K 3ms 3ms 3ms β
0.3K 5ms 4ms 6ms β
0.5K 10ms 10ms 12ms β
1.0K 22ms 21ms 25ms β
2.0K 53ms 49ms 57ms β
3.0K 81ms 77ms 87ms ββ
4.0K 134ms 117ms 136ms βββ
6.0K 197ms 195ms 201ms ββββ
8.0K 287ms 280ms 309ms ββββββ
10.0K 392ms 390ms 395ms ββββββββ
12.0K 458ms 412ms 485ms βββββββββ
16.0K 627ms 618ms 692ms βββββββββββββ
20.0K 943ms 941ms 980ms βββββββββββββββββββ
24.0K 1198ms 1197ms 1252ms ββββββββββββββββββββββββ
28.0K 4053ms 3878ms 4239ms βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
32.0K 3721ms 3617ms 3972ms ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
## edge-cases/oversize-32k.rsc
Auto-generated repetitive address-list commands, >32KB
Syntax profile: single-path
Size Median Min Max Curve
βββββββ ββββββββ βββββββ βββββββ ββββββββββββββββββββββββββββββ
0.1K 2ms 2ms 2ms β
0.3K 4ms 3ms 4ms β
0.5K 6ms 5ms 6ms β
1.0K 10ms 10ms 11ms β
2.0K 22ms 21ms 23ms β
3.0K 34ms 32ms 38ms β
4.0K 47ms 46ms 49ms β
6.0K 77ms 75ms 84ms ββ
8.0K 107ms 106ms 112ms ββ
10.0K 146ms 144ms 149ms βββ
12.0K 200ms 197ms 204ms ββββ
16.0K 280ms 276ms 300ms ββββββ
20.0K 440ms 426ms 461ms βββββββββ
24.0K 571ms 564ms 582ms βββββββββββ
28.0K 2163ms 2094ms 2186ms βββββββββββββββββββββββββββββββββββββββββββ
32.0K 2441ms 2384ms 2489ms βββββββββββββββββββββββββββββββββββββββββββββββββ
## complex/piano.rsc
Piano player script β complex :beep, arrays, timing
Syntax profile: scripting
Size Median Min Max Curve
βββββββ ββββββββ βββββββ βββββββ ββββββββββββββββββββββββββββββ
0.1K 2ms 2ms 2ms β
0.3K 3ms 3ms 4ms β
0.5K 5ms 5ms 5ms β
1.0K 10ms 9ms 11ms β
2.0K 24ms 23ms 24ms β
3.0K 38ms 38ms 38ms β
4.0K 53ms 51ms 53ms β
6.0K 86ms 85ms 99ms ββ
8.0K 120ms 117ms 120ms ββ
10.0K 160ms 159ms 162ms βββ
## Key Comparisons
At 1KB:
synthetic-comments 6ms (comments)
synthetic-commands 8ms (single-path)
synthetic-mixed-paths 8ms (multi-path)
synthetic-complex 24ms (scripting)
eworm/global-functions.rsc 22ms (scripting)
edge-cases/oversize-32k.rsc 10ms (single-path)
complex/piano.rsc 10ms (scripting)
At 4KB:
synthetic-comments 21ms (comments)
synthetic-commands 33ms (single-path)
synthetic-mixed-paths 33ms (multi-path)
synthetic-complex 110ms (scripting)
eworm/global-functions.rsc 134ms (scripting)
edge-cases/oversize-32k.rsc 47ms (single-path)
complex/piano.rsc 53ms (scripting)
At 16KB:
synthetic-comments 162ms (comments)
synthetic-commands 226ms (single-path)
synthetic-mixed-paths 222ms (multi-path)
synthetic-complex 755ms (scripting)
eworm/global-functions.rsc 627ms (scripting)
edge-cases/oversize-32k.rsc 280ms (single-path)
At 32KB:
synthetic-comments 2199ms (comments)
synthetic-commands 2351ms (single-path)
synthetic-mixed-paths 4557ms (multi-path)
synthetic-complex 6022ms (scripting)
eworm/global-functions.rsc 3721ms (scripting)
edge-cases/oversize-32k.rsc 2441ms (single-path)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
CoPilot summary:
All 7 profiles are created and complete. The key findings:
- ALL syntax types scale quadratically β even pure
# commentlines. This is inherent to the RouterOS API, not syntax-specific. - Sharp inflection at ~28KB β every profile shows a dramatic 3.7β4.6Γ jump between 24KB and 28KB. This is almost certainly a RouterOS internal buffer boundary.
- Syntax IS a multiplier, but not the root cause. At 32KB:
- Comments: 2.2s (baseline)
- Simple commands: 2.4s (1.1Γ)
- Mixed paths: 4.6s (2.1Γ)
- Complex scripting: 6.0s (2.7Γ)
YourAmm0's theory was half right β complex syntax (variables, functions, path lookups) costs ~3Γ more than comments at the same size. But the quadratic base cost from pure length dominates. Both factors compound.
Oh, perhaps I should consider splitting my global-functions... ![]()
I suspect it does go through the same tokenizer... but likely only once in runtime since it does convert global functions into code it :parse format in /environment. The LSP has to do this every few seconds when typing... so it's a bigger issue there.
@eworm, I put an ATTRIBUTION.md with your scripts, and cross-ref in contributing docs - let me know if you have any problem with my code using them (not the expert in licensing, so my project is MIT since VSCode Extensions requires MIT or MIT-like.
The same is true for @rextended whose scripts are also part of the test corpus, his licensing rules I believe a "Thanks" and link, which was also cross-ref
Both sets of scripts are in GitHub for the units test (along with my posts). None of the scripts are published with the VSCode Extension. But either @eworm or @rextended ... let me know if you have any issue, and I'll remove them. Basically @eworm collection has some length+complexity and @rextended had volume+complexity.
The combo of scripts turned up that I was missing some "tokens":
variable-autoβ in 167 files. This is significant β it's the 13th most common token type and completely unhandled. Likely auto-created variables like$0,$1from regex captures or similar.obj-dynamicβ in 4 files. Likeobj-inactivebut for dynamic entries.obj-disabledβ in 2 files. Likeobj-inactivebut for disabled entries specifically.
Now these only affect coloring since they are no "error tokens". I believe RouterOS does not have text coloring for them AFAIK, still need to check.
My scripts are provided on the condition that:
- If there's an error, it's reported to me;
- Those who use them don't take credit for it, or rather, don't write who made it if they don't like me.

LOL. I don't know yet. I know only a few dozen had an error tokens. But since scripts were scraped, or may be partial examples, hard to know if there real (could be my LSP, could be extract, partials scripts, etc)... I don't have a detailed break down of that yet since I'm still building tests. That "large scripts" are very slow in VSCode was the more pressing problem. But I do plan to a "lint report" to build to know. But LSP, it's that the count of tokens don't change over time, and we want errors in test data. If you have a file/ZIP with your scripts, feel to post it (or email tikoci.repos at the common domain for google mail), and I'll add those.
Looping over them is pretty easy as unit tests bring up a CHR already, so some check that essentially tell you that if pasted into CLI would result in the red ANSI is possible. My problem is while ~95% sure my LSP find same things, I'm missing a test that use SSH in test run to read back the ANSI an actual RouterOS terminal to confirm that. Whether scripts work for the purpose designed... that be much hard. No errors (or warns on undeclared variables) is easier.
There is a "manifest" for the sources here: lsp-routeros-ts/test-data/forum/rextended/manifest.json at main Β· tikoci/lsp-routeros-ts Β· GitHub with the parent directory having the snippets.
Well, @rextended's "manifest.json" is >64K, so :deserialize did NOT work. There is now a indice.json that has a bit less data, but you can run them yourself now. Essentially this the dumb down version of the VSCode/generic RouterOS LSP (easier since LSP protocol uses Unicode (e.g. ln#, pos#), so UTF-8 is "one character" to an LSP since that's how Unicode editor see it... but ~3 chars to RouterOS, so real LSP has track all that...):
$rsclint script=<script-text-as-string>
Outputs: array
length - length of script in bytes
tokens - inspect's "request=highlight" results as array
error - location as index, actual "errors" tokens found
obj-inactive - location as index, "bad code"
:global rsclint do={
:local tokens ([/console/inspect request=highlight input=$script as-value]->"highlight")
:local report {
"length"=[:len $script];
"tokens"=$tokens;
"errors"=[:toarray ""];
"obj-inactive"=[:toarray ""];
}
:for pos from=0 to=($report->"length") do={
:if (($tokens->$pos) = "error") do={
:set ($report->"errors") (($report->"errors"),$pos)
}
:if (($tokens->$pos) = "obj-inactive") do={
:set ($report->"obj-inactive") (($report->"obj-inactive"),$pos)
}
}
:return $report
}
$rexlint - uses $rsclint above against GitHub with @rextended's scripts
Output when run is below, showing files with errors. I have full faith that @rextended can add his own flair, but data has the name/url/etc... just be a lot of output for forum. The was human written... the LLM are better at the TypeScript, scraping discourse, and ANSI graphics than me I assure you.
:global rexlint do={
:global rsclint
:local manifestUrl "https://raw.githubusercontent.com/tikoci/lsp-routeros-ts/refs/heads/main/test-data/forum/rextended/indice.json"
:local getGitHubUrlForScript do={
:return "https://raw.githubusercontent.com/tikoci/lsp-routeros-ts/refs/heads/main/test-data/forum/rextended/$fileName"
}
:local manifestJsonData [/tool/fetch url=$manifestUrl output=user as-value]
:local manifestArray [:deserialize from=json ($manifestJsonData->"data")]
:foreach scriptManifest in=$manifestArray do={
:local scriptdata [/tool/fetch url=[$getGitHubUrlForScript fileName=($scriptManifest->"fileName")] output=user as-value]
:local lintout [$rsclint script=($scriptdata->"data")]
:put " $($scriptManifest->"fileName") \t sym# $[:len ($lintout->"tokens")] \t err# $[:len ($lintout->"errors")] \t bad# $[:len ($lintout->"obj-inactive")]"
}
}
$rexlint
when run:
[admin@CHR] > :global rsclint do={
{... :local tokens ([/console/inspect request=highlight input=$script as-value]->"highlight")
{... :local report {
{{... "length"=[:len $script];
{{... "tokens"=$tokens;
{{... "errors"=[:toarray ""];
{{... "obj-inactive"=[:toarray ""];
{{... }
{... :for pos from=0 to=($report->"length") do={
{{... :if (($tokens->$pos) = "error") do={
{{{... :set ($report->"errors") (($report->"errors"),$pos)
{{{... }
{{... :if (($tokens->$pos) = "obj-inactive") do={
{{{... :set ($report->"obj-inactive") (($report->"obj-inactive"),$pos)
{{{... }
{{... }
{... :return $report
{... }
[admin@CHR] >
[admin@CHR] > :global rexlint do={
{... :global rsclint
{... :local manifestUrl "https://raw.githubusercontent.com/tikoci/lsp-routeros-ts/refs/heads/main/test-data/forum/rextended/indice.json"
{... :local getGitHubUrlForScript do={
{{... :return "https://raw.githubusercontent.com/tikoci/lsp-routeros-ts/refs/heads/main/test-data/forum/rextended/$fileName"
{{... }
{... :local manifestJsonData [/tool/fetch url=$manifestUrl output=user as-value]
{... :local manifestArray [:deserialize from=json ($manifestJsonData->"data")]
{... :foreach scriptManifest in=$manifestArray do={
{{... :local scriptdata [/tool/fetch url=[$getGitHubUrlForScript fileName=($scriptManifest->"fileName")] output=user as-value]
{{... :local lintout [$rsclint script=($scriptdata->"data")]
{{... :put " $($scriptManifest->"fileName") \t sym# $[:len ($lintout->"tokens")] \t err# $[:len ($lintout->"errors")] \t bad# $[:len ($lintout->"obj-inactive")]"
{{... }
{... }
[admin@CHR] >
[admin@CHR] > $rexlint
topic-151033-post-0010-snippet-01.rsc sym# 190 err# 0 bad# 0
topic-151033-post-0015-snippet-01.rsc sym# 1008 err# 0 bad# 0
topic-151033-post-0015-snippet-02.rsc sym# 1021 err# 0 bad# 0
topic-151033-post-0015-snippet-03.rsc sym# 161 err# 0 bad# 0
topic-151033-post-0015-snippet-04.rsc sym# 165 err# 0 bad# 0
topic-151033-post-0015-snippet-05.rsc sym# 172 err# 0 bad# 0
topic-151033-post-0015-snippet-06.rsc sym# 165 err# 0 bad# 0
topic-151033-post-0017-snippet-01.rsc sym# 653 err# 0 bad# 0
topic-151033-post-0017-snippet-02.rsc sym# 819 err# 0 bad# 0
topic-151033-post-0018-snippet-01.rsc sym# 451 err# 0 bad# 0
topic-151033-post-0018-snippet-02.rsc sym# 840 err# 0 bad# 0
topic-151033-post-0018-snippet-03.rsc sym# 492 err# 0 bad# 0
topic-151033-post-0018-snippet-04.rsc sym# 1207 err# 0 bad# 0
topic-151033-post-0019-snippet-01.rsc sym# 173 err# 0 bad# 0
topic-151033-post-0019-snippet-02.rsc sym# 333 err# 0 bad# 0
topic-151033-post-0020-snippet-01.rsc sym# 3892 err# 0 bad# 0
topic-151033-post-0020-snippet-02.rsc sym# 3891 err# 0 bad# 0
topic-151033-post-0021-snippet-01.rsc sym# 494 err# 0 bad# 0
topic-151033-post-0021-snippet-02.rsc sym# 658 err# 0 bad# 0
topic-151033-post-0034-snippet-01.rsc sym# 3806 err# 0 bad# 0
topic-151033-post-0034-snippet-02.rsc sym# 3306 err# 0 bad# 0
topic-151033-post-0048-snippet-01.rsc sym# 3524 err# 0 bad# 0
topic-151033-post-0048-snippet-02.rsc sym# 362 err# 1 bad# 9
topic-151033-post-0049-snippet-01.rsc sym# 4047 err# 0 bad# 0
topic-151033-post-0049-snippet-02.rsc sym# 226 err# 1 bad# 0
topic-151033-post-0056-snippet-01.rsc sym# 3265 err# 0 bad# 0
topic-151033-post-0056-snippet-02.rsc sym# 277 err# 1 bad# 0
topic-151033-post-0057-snippet-01.rsc sym# 3838 err# 0 bad# 0
topic-151033-post-0057-snippet-02.rsc sym# 648 err# 1 bad# 9
topic-151033-post-0058-snippet-01.rsc sym# 181 err# 1 bad# 0
topic-151033-post-0070-snippet-01.rsc sym# 3903 err# 0 bad# 0
topic-151033-post-0070-snippet-02.rsc sym# 3895 err# 0 bad# 0
topic-151033-post-0071-snippet-01.rsc sym# 3800 err# 0 bad# 0
topic-151033-post-0071-snippet-02.rsc sym# 243 err# 1 bad# 0
topic-151033-post-0072-snippet-01.rsc sym# 3296 err# 0 bad# 0
topic-151033-post-0072-snippet-02.rsc sym# 182 err# 0 bad# 0
topic-151033-post-0072-snippet-03.rsc sym# 614 err# 1 bad# 0
topic-103825-post-0017-snippet-01.rsc sym# 552 err# 0 bad# 0
topic-103825-post-0017-snippet-02.rsc sym# 717 err# 1 bad# 11
topic-103825-post-0021-snippet-01.rsc sym# 347 err# 0 bad# 0
topic-103825-post-0024-snippet-01.rsc sym# 188 err# 0 bad# 0
topic-132775-post-0017-snippet-01.rsc sym# 2306 err# 0 bad# 0
topic-132775-post-0017-snippet-02.rsc sym# 265 err# 0 bad# 0
topic-63496-post-0005-snippet-01.rsc sym# 1475 err# 0 bad# 0
topic-121369-post-0013-snippet-01.rsc sym# 1649 err# 0 bad# 0
topic-68576-post-0014-snippet-01.rsc sym# 1117 err# 0 bad# 0
topic-68576-post-0014-snippet-02.rsc sym# 1195 err# 0 bad# 0
topic-68576-post-0018-snippet-01.rsc sym# 1153 err# 0 bad# 0
topic-68576-post-0018-snippet-02.rsc sym# 186 err# 0 bad# 0
topic-68576-post-0019-snippet-01.rsc sym# 1425 err# 0 bad# 0
topic-68576-post-0024-snippet-01.rsc sym# 1883 err# 0 bad# 0
topic-68576-post-0033-snippet-01.rsc sym# 169 err# 0 bad# 0
topic-68576-post-0039-snippet-01.rsc sym# 187 err# 0 bad# 0
topic-143071-post-0014-snippet-01.rsc sym# 235 err# 1 bad# 8
topic-143071-post-0018-snippet-01.rsc sym# 845 err# 0 bad# 0
topic-143071-post-0018-snippet-02.rsc sym# 438 err# 0 bad# 0
topic-143071-post-0023-snippet-01.rsc sym# 3602 err# 0 bad# 0
topic-143071-post-0025-snippet-01.rsc sym# 2936 err# 0 bad# 0
topic-143071-post-0029-snippet-01.rsc sym# 1463 err# 0 bad# 0
topic-143071-post-0033-snippet-01.rsc sym# 502 err# 0 bad# 0
topic-143071-post-0052-snippet-01.rsc sym# 315 err# 0 bad# 0
topic-151020-post-0001-snippet-01.rsc sym# 350 err# 0 bad# 5
topic-151020-post-0001-snippet-02.rsc sym# 1006 err# 0 bad# 0
topic-115644-post-0004-snippet-01.rsc sym# 879 err# 0 bad# 0
topic-97913-post-0009-snippet-01.rsc sym# 277 err# 1 bad# 9
topic-97913-post-0011-snippet-01.rsc sym# 262 err# 0 bad# 0
topic-97913-post-0011-snippet-02.rsc sym# 369 err# 0 bad# 0
topic-97913-post-0014-snippet-01.rsc sym# 180 err# 0 bad# 3
topic-133640-post-0087-snippet-01.rsc sym# 187 err# 0 bad# 0
topic-133640-post-0088-snippet-01.rsc sym# 212 err# 1 bad# 3
topic-133640-post-0088-snippet-02.rsc sym# 241 err# 1 bad# 6
topic-133640-post-0088-snippet-03.rsc sym# 527 err# 1 bad# 12
topic-133640-post-0114-snippet-01.rsc sym# 382 err# 1 bad# 0
topic-133640-post-0114-snippet-02.rsc sym# 235 err# 1 bad# 0
topic-133640-post-0116-snippet-01.rsc sym# 673 err# 1 bad# 9
topic-133640-post-0120-snippet-01.rsc sym# 970 err# 0 bad# 0
topic-133640-post-0158-snippet-01.rsc sym# 2762 err# 0 bad# 0
topic-133640-post-0158-snippet-02.rsc sym# 565 err# 1 bad# 3
topic-133640-post-0158-snippet-03.rsc sym# 752 err# 0 bad# 0
topic-133640-post-0182-snippet-01.rsc sym# 180 err# 1 bad# 9
topic-133640-post-0197-snippet-01.rsc sym# 197 err# 0 bad# 0
topic-149116-post-0021-snippet-01.rsc sym# 329 err# 0 bad# 6
topic-149116-post-0021-snippet-02.rsc sym# 273 err# 1 bad# 1
topic-149116-post-0021-snippet-03.rsc sym# 384 err# 1 bad# 9
topic-149116-post-0027-snippet-01.rsc sym# 260 err# 1 bad# 0
topic-52654-post-0005-snippet-01.rsc sym# 198 err# 0 bad# 0
topic-52654-post-0005-snippet-02.rsc sym# 494 err# 0 bad# 0
topic-52654-post-0005-snippet-03.rsc sym# 169 err# 0 bad# 5
topic-52654-post-0005-snippet-04.rsc sym# 311 err# 0 bad# 0
topic-52654-post-0005-snippet-05.rsc sym# 578 err# 0 bad# 0
topic-52654-post-0006-snippet-01.rsc sym# 619 err# 0 bad# 0
topic-52654-post-0006-snippet-02.rsc sym# 399 err# 0 bad# 0
topic-150559-post-0002-snippet-01.rsc sym# 538 err# 0 bad# 0
topic-150559-post-0002-snippet-02.rsc sym# 900 err# 0 bad# 0
topic-150559-post-0007-snippet-01.rsc sym# 226 err# 0 bad# 0
topic-150195-post-0002-snippet-01.rsc sym# 638 err# 0 bad# 0
topic-150195-post-0008-snippet-01.rsc sym# 718 err# 0 bad# 0
topic-150195-post-0012-snippet-01.rsc sym# 268 err# 0 bad# 0
topic-150195-post-0012-snippet-02.rsc sym# 268 err# 0 bad# 0
topic-150516-post-0008-snippet-01.rsc sym# 211 err# 0 bad# 0
topic-150516-post-0008-snippet-02.rsc sym# 211 err# 0 bad# 0
topic-150516-post-0008-snippet-03.rsc sym# 502 err# 0 bad# 0
topic-150516-post-0025-snippet-01.rsc sym# 234 err# 0 bad# 0
topic-150516-post-0025-snippet-02.rsc sym# 309 err# 0 bad# 0
topic-150516-post-0027-snippet-01.rsc sym# 598 err# 0 bad# 0
topic-150066-post-0008-snippet-01.rsc sym# 471 err# 0 bad# 0
topic-150066-post-0010-snippet-01.rsc sym# 291 err# 1 bad# 0
topic-150050-post-0002-snippet-01.rsc sym# 254 err# 0 bad# 0
topic-150050-post-0002-snippet-02.rsc sym# 357 err# 0 bad# 0
topic-150050-post-0002-snippet-03.rsc sym# 248 err# 0 bad# 0
topic-150050-post-0004-snippet-01.rsc sym# 452 err# 0 bad# 0
topic-110950-post-0010-snippet-01.rsc sym# 493 err# 0 bad# 0
topic-110950-post-0028-snippet-01.rsc sym# 4049 err# 0 bad# 0
topic-79536-post-0006-snippet-01.rsc sym# 348 err# 0 bad# 0
topic-104992-post-0083-snippet-01.rsc sym# 210 err# 0 bad# 16
topic-149267-post-0001-snippet-01.rsc sym# 431 err# 0 bad# 0
topic-149267-post-0001-snippet-02.rsc sym# 422 err# 0 bad# 0
topic-148996-post-0004-snippet-01.rsc sym# 2044 err# 0 bad# 0
topic-148996-post-0004-snippet-02.rsc sym# 4109 err# 0 bad# 0
topic-148996-post-0004-snippet-03.rsc sym# 2203 err# 0 bad# 0
topic-148996-post-0004-snippet-04.rsc sym# 4267 err# 0 bad# 0
topic-148996-post-0036-snippet-01.rsc sym# 814 err# 1 bad# 4
topic-113429-post-0004-snippet-01.rsc sym# 1139 err# 0 bad# 0
topic-151793-post-0002-snippet-01.rsc sym# 223 err# 1 bad# 0
topic-151793-post-0002-snippet-02.rsc sym# 197 err# 1 bad# 0
topic-151793-post-0002-snippet-03.rsc sym# 302 err# 0 bad# 0
topic-151793-post-0009-snippet-01.rsc sym# 378 err# 0 bad# 0
topic-151793-post-0020-snippet-01.rsc sym# 187 err# 1 bad# 0
topic-151723-post-0005-snippet-01.rsc sym# 608 err# 1 bad# 0
topic-151723-post-0007-snippet-01.rsc sym# 948 err# 0 bad# 0
topic-151723-post-0007-snippet-02.rsc sym# 565 err# 1 bad# 0
topic-151870-post-0002-snippet-01.rsc sym# 1398 err# 0 bad# 0
topic-151870-post-0010-snippet-01.rsc sym# 737 err# 0 bad# 0
topic-77321-post-0015-snippet-01.rsc sym# 494 err# 0 bad# 0
topic-151933-post-0002-snippet-01.rsc sym# 217 err# 0 bad# 0
topic-151933-post-0005-snippet-01.rsc sym# 1722 err# 0 bad# 0
topic-151933-post-0005-snippet-02.rsc sym# 232 err# 1 bad# 4
topic-151933-post-0005-snippet-03.rsc sym# 225 err# 0 bad# 0
topic-145326-post-0006-snippet-01.rsc sym# 687 err# 0 bad# 0
topic-145326-post-0006-snippet-02.rsc sym# 1563 err# 0 bad# 0
topic-145326-post-0017-snippet-01.rsc sym# 265 err# 0 bad# 0
topic-145326-post-0017-snippet-02.rsc sym# 207 err# 0 bad# 0
topic-145326-post-0043-snippet-01.rsc sym# 159 err# 0 bad# 0
topic-145326-post-0056-snippet-01.rsc sym# 583 err# 1 bad# 0
topic-149189-post-0007-snippet-01.rsc sym# 1479 err# 0 bad# 6
topic-149189-post-0007-snippet-02.rsc sym# 373 err# 1 bad# 12
topic-149189-post-0007-snippet-03.rsc sym# 368 err# 1 bad# 0
topic-149189-post-0007-snippet-04.rsc sym# 345 err# 1 bad# 0
topic-149189-post-0007-snippet-05.rsc sym# 534 err# 1 bad# 0
topic-157724-post-0005-snippet-01.rsc sym# 5180 err# 0 bad# 0
topic-157724-post-0012-snippet-01.rsc sym# 5266 err# 0 bad# 0
topic-157724-post-0020-snippet-01.rsc sym# 149 err# 0 bad# 0
topic-157724-post-0036-snippet-01.rsc sym# 1561 err# 0 bad# 0
topic-157724-post-0037-snippet-01.rsc sym# 1053 err# 0 bad# 0
topic-157724-post-0037-snippet-02.rsc sym# 172 err# 0 bad# 0
topic-157724-post-0037-snippet-03.rsc sym# 190 err# 0 bad# 0
topic-157724-post-0040-snippet-01.rsc sym# 265 err# 0 bad# 0
topic-158109-post-0005-snippet-01.rsc sym# 795 err# 0 bad# 0
topic-158109-post-0005-snippet-02.rsc sym# 1258 err# 1 bad# 3
topic-158109-post-0015-snippet-01.rsc sym# 392 err# 0 bad# 0
topic-158109-post-0016-snippet-01.rsc sym# 1079 err# 0 bad# 0
topic-158109-post-0016-snippet-02.rsc sym# 583 err# 1 bad# 3
topic-158216-post-0004-snippet-01.rsc sym# 557 err# 0 bad# 0
topic-158216-post-0005-snippet-01.rsc sym# 515 err# 0 bad# 0
topic-158216-post-0005-snippet-02.rsc sym# 622 err# 0 bad# 0
topic-158216-post-0013-snippet-01.rsc sym# 867 err# 0 bad# 0
topic-158216-post-0013-snippet-02.rsc sym# 400 err# 0 bad# 0
topic-74610-post-0002-snippet-01.rsc sym# 369 err# 0 bad# 0
topic-74610-post-0004-snippet-01.rsc sym# 224 err# 0 bad# 0
topic-75450-post-0043-snippet-01.rsc sym# 172 err# 0 bad# 12
topic-75450-post-0043-snippet-02.rsc sym# 134 err# 1 bad# 5
topic-75450-post-0110-snippet-01.rsc sym# 173 err# 0 bad# 12
topic-75450-post-0110-snippet-02.rsc sym# 135 err# 1 bad# 5
topic-75450-post-0140-snippet-01.rsc sym# 4448 err# 1 bad# 5
topic-160011-post-0004-snippet-01.rsc sym# 1355 err# 0 bad# 0
topic-160011-post-0005-snippet-01.rsc sym# 1330 err# 0 bad# 0
topic-160011-post-0006-snippet-01.rsc sym# 862 err# 0 bad# 0
topic-160011-post-0007-snippet-01.rsc sym# 2096 err# 0 bad# 0
topic-161897-post-0005-snippet-01.rsc sym# 354 err# 1 bad# 1
topic-161897-post-0006-snippet-01.rsc sym# 1205 err# 0 bad# 0
topic-5183-post-0010-snippet-01.rsc sym# 973 err# 0 bad# 0
topic-5183-post-0010-snippet-02.rsc sym# 3036 err# 0 bad# 0
topic-5183-post-0017-snippet-01.rsc sym# 309 err# 0 bad# 0
topic-5183-post-0019-snippet-01.rsc sym# 3206 err# 0 bad# 0
topic-5183-post-0019-snippet-02.rsc sym# 230 err# 0 bad# 0
topic-5183-post-0022-snippet-01.rsc sym# 3943 err# 0 bad# 0
topic-5183-post-0022-snippet-02.rsc sym# 354 err# 0 bad# 0
topic-5183-post-0023-snippet-01.rsc sym# 883 err# 0 bad# 0
topic-162755-post-0002-snippet-01.rsc sym# 183 err# 1 bad# 5
topic-162755-post-0006-snippet-01.rsc sym# 1404 err# 1 bad# 5
topic-162848-post-0002-snippet-01.rsc sym# 381 err# 0 bad# 0
topic-162848-post-0004-snippet-01.rsc sym# 2605 err# 0 bad# 0
topic-163033-post-0003-snippet-01.rsc sym# 771 err# 0 bad# 0
topic-163033-post-0006-snippet-01.rsc sym# 401 err# 0 bad# 0
topic-163033-post-0015-snippet-01.rsc sym# 1677 err# 0 bad# 0
topic-163033-post-0018-snippet-01.rsc sym# 195 err# 1 bad# 0
topic-163033-post-0021-snippet-01.rsc sym# 1704 err# 0 bad# 0
topic-163033-post-0038-snippet-01.rsc sym# 251 err# 0 bad# 0
topic-163033-post-0038-snippet-02.rsc sym# 189 err# 0 bad# 0
topic-163033-post-0038-snippet-03.rsc sym# 223 err# 0 bad# 0
topic-163033-post-0042-snippet-01.rsc sym# 490 err# 0 bad# 0
topic-163033-post-0042-snippet-02.rsc sym# 480 err# 0 bad# 0
topic-163033-post-0046-snippet-01.rsc sym# 275 err# 0 bad# 0
topic-163033-post-0046-snippet-02.rsc sym# 216 err# 0 bad# 0
topic-163067-post-0009-snippet-01.rsc sym# 290 err# 0 bad# 0
topic-163067-post-0011-snippet-01.rsc sym# 801 err# 1 bad# 0
topic-163488-post-0005-snippet-01.rsc sym# 187 err# 1 bad# 1
topic-163850-post-0003-snippet-01.rsc sym# 650 err# 0 bad# 0
topic-163850-post-0007-snippet-01.rsc sym# 262 err# 0 bad# 0
topic-163718-post-0012-snippet-01.rsc sym# 3569 err# 0 bad# 0
topic-164329-post-0017-snippet-01.rsc sym# 851 err# 1 bad# 9
topic-164329-post-0018-snippet-01.rsc sym# 2776 err# 0 bad# 0
topic-164329-post-0025-snippet-01.rsc sym# 190 err# 1 bad# 1
topic-164329-post-0025-snippet-02.rsc sym# 183 err# 1 bad# 1
topic-164329-post-0025-snippet-03.rsc sym# 177 err# 1 bad# 1
topic-164329-post-0026-snippet-01.rsc sym# 4391 err# 0 bad# 0
topic-164329-post-0026-snippet-02.rsc sym# 4371 err# 0 bad# 0
topic-164329-post-0034-snippet-01.rsc sym# 212 err# 0 bad# 0
topic-164329-post-0035-snippet-01.rsc sym# 197 err# 0 bad# 0
topic-142687-post-0012-snippet-01.rsc sym# 144 err# 0 bad# 0
topic-142687-post-0013-snippet-01.rsc sym# 178 err# 0 bad# 0
topic-142687-post-0013-snippet-02.rsc sym# 184 err# 0 bad# 0
topic-142687-post-0013-snippet-03.rsc sym# 211 err# 0 bad# 0
topic-164889-post-0003-snippet-01.rsc sym# 2155 err# 0 bad# 0
topic-164889-post-0004-snippet-01.rsc sym# 3758 err# 0 bad# 0
topic-164889-post-0005-snippet-01.rsc sym# 1140 err# 0 bad# 0
topic-164889-post-0006-snippet-01.rsc sym# 1279 err# 0 bad# 0
topic-164889-post-0007-snippet-01.rsc sym# 2620 err# 0 bad# 0
topic-164889-post-0007-snippet-02.rsc sym# 416 err# 1 bad# 0
topic-164889-post-0008-snippet-01.rsc sym# 5087 err# 0 bad# 0
topic-166898-post-0002-snippet-01.rsc sym# 281 err# 1 bad# 0
topic-166898-post-0022-snippet-01.rsc sym# 6052 err# 0 bad# 0
topic-166898-post-0024-snippet-01.rsc sym# 6121 err# 0 bad# 0
topic-166898-post-0052-snippet-01.rsc sym# 778 err# 0 bad# 0
topic-167618-post-0003-snippet-01.rsc sym# 532 err# 0 bad# 0
topic-132192-post-0021-snippet-01.rsc sym# 189 err# 0 bad# 0
topic-132192-post-0022-snippet-01.rsc sym# 1069 err# 0 bad# 0
topic-132192-post-0022-snippet-02.rsc sym# 1163 err# 0 bad# 0
topic-132192-post-0026-snippet-01.rsc sym# 438 err# 0 bad# 0
topic-132192-post-0026-snippet-02.rsc sym# 313 err# 0 bad# 0
topic-132192-post-0029-snippet-01.rsc sym# 1440 err# 0 bad# 0
topic-132192-post-0039-snippet-01.rsc sym# 458 err# 1 bad# 4
topic-132192-post-0041-snippet-01.rsc sym# 197 err# 0 bad# 0
topic-132192-post-0042-snippet-01.rsc sym# 243 err# 1 bad# 0
topic-156344-post-0004-snippet-01.rsc sym# 233 err# 1 bad# 8
topic-156344-post-0004-snippet-02.rsc sym# 264 err# 0 bad# 0
topic-156344-post-0004-snippet-03.rsc sym# 268 err# 1 bad# 0
topic-156344-post-0004-snippet-04.rsc sym# 342 err# 0 bad# 0
topic-156344-post-0004-snippet-05.rsc sym# 625 err# 0 bad# 0
topic-156344-post-0004-snippet-06.rsc sym# 925 err# 0 bad# 0
topic-156344-post-0004-snippet-07.rsc sym# 1348 err# 0 bad# 0
topic-166576-post-0012-snippet-01.rsc sym# 231 err# 0 bad# 6
topic-166576-post-0035-snippet-01.rsc sym# 352 err# 0 bad# 0
topic-166576-post-0035-snippet-02.rsc sym# 356 err# 0 bad# 0
[admin@CHR] >
Now the lousy syntax highlight looks like ass in forum. In fairness, some my colors get remapped by VSCode theme ATM (a bug), but this what I see with the LSP in VSCode:
The contributed scripts are quite helpful to have some set of scripts to run RouterOS syntax/structure experiments. As noted in thread, there are some things /console/inspect cannot tell us about RotuerOS script/CLI, like current path. This is tricky since there is a lot of RouterOS syntax that can do a implict cd, so while handing a few case may cover a lot of ground (e.g. config files have a simple structure, so determine the path is easier). I have thought before that the :parse output of a script/CLI/config be easier to parse out the path, but building a recursive decent parser take me some time. For the robots, that's child play, compared say configuring VLANs on a bridge. So have some tests, and report, on what I called the "parseIL Format" (e.g. the code/"(code)" data type for scripting denizens).
For the LSP, using :parse is quicker at getting a "valid" or "invalid" script results, even one larger than ~25K. So for larger scripts, "pre-parsing" them using :parse avoid the more expensive tokenizing.
But more importantly /console/inspect data can "enhanced" with the 'parseIL' Format, since the code form has to "unwind" more complex "routeros script form". e.g. another way to look at it is all of RouterOS script/cli/config is just "syntax sugar" over the code types... so the simpler parseIL form tells us a few things without developing our own RouterOS script parser. The TL;DR for the current research:
From Β§ 7 "LSP feature payoffs",
The features unlocked or clarified by this spike β to be filed as concrete
backlog items once the spike is closed:
- Folding Ranges β straightforward off
do=;(evl β¦)boundaries.e.g. accurate "collapse" blocks in VSCode (the arrows up/down to hide/show parts of the code)
- Document Symbols: functions, not just variables β detect
(evl /localdo=β¦;name=$f)/(evl /globaldo=β¦;name=$F).e.g. existing "highlight" tokens do not seperate functions from other variable, types, but the pattern above allow identifications of RouterOS functions... this should allow the "Go to defination" etc option to "jump" to where the function is declared.
- "Show parseIL" command + hover supplement β verbatim IL display.
e.g. LSP currently shows the highlight token at a particular location so that if someone thought "LSP is wrong!", we'd know what token from RouterOS we got... so for a selection, seeing what the parseIL either directly or further parse for display as a "debug view" of the whole/part of script
- Hover canonicalisation hints β display
200ms β 00:00:00.200,
yes β true,:put β /put.e.g. some types like time are obvious in parseIL, like
time, so we can likely know those, perhaps others - need more experiments here to see full scope.
:parseshort-circuit before highlight β skip highlight when:parse
reports a fatal syntax error; surface that error directly with line/col.This is actually more useful to TikBook since parse is actually what should be shown, although still have to parse the string to find line/pos numbers since those are may not regularized accross versions, IDK
- Definition / References (with caveat) β feasible via IL scope
reconstruction; not free.e.g. figure out path is possible, but as noted, require more parsing of the parseIL than others.
Underlying research report from these :parse/parseIL tests:
Side note to @rextended / @eworm - the project is now using SQLite to store various experiments done on the set of scripts, so eventually should be able to produce more meaningful "report" on your script libraries. In my ecosystem there are about 50 tracked version of RouterOS (7.9 ->), so what is valid in one version may not be valid in another. So storing test results as JSON files likely results in thousands of files. And, in case of eworm's collection, there is actually another dimension that test could use, but don't, is
gitfor older versions - not sure we'll get there but the historical differences might hold different clues. At this point, I'm more trying to unwind the structure of RouterOS at this point, but results of tests will be in lsp-routeros-ts/test-data/corpus.sqlite at main Β· tikoci/lsp-routeros-ts Β· GitHub




















