XPP - VSCode Extension for XPPAUT FilesWrite XPPAUT models (
What's new in 0.4.1
Every release is listed in the changelog. DiagnosticsThe extension checks each
Names defined in The XPP syntax rules behind these checksAll of these were verified by running files through How XPP decides what a line is
Keyword prefixes. Only the first letters of the keyword matter: Keywords are not reserved names. Where spaces around
Lists. Comments and Operator precedence
XPP's expression parser groups some expressions differently from ordinary maths, and refuses others outright. This is long-standing XPPAUT behaviour that existing models rely on; the extension only makes it visible. Hover over
It all follows from one priority table: comparisons bind tighter than all arithmetic, the opposite of nearly every other language, and unary minus binds more weakly than both
Each rule, with examplesEverything below was confirmed by compiling the expression with 1.
|
| you write | XPP uses | |
|---|---|---|
@ total=2*3 |
2 |
not 6: @ values are not expressions |
@ total=4abc |
4 |
|
@ total=(4) |
0 |
atof finds no number to start with |
@ total= |
default | the option is dropped entirely |
@ total= 4 |
default | the value was split off, so the piece is not name=value |
@ total = 4 |
default | reads as the three unrelated words total, =, 4 |
@ t0=-5 |
-5 |
negative values are fine |
@ total=1e1 |
10 |
as is scientific notation |
Work the value out yourself, or put it in a par and use that in your equations. Options that take a name, a file or a keyword (meth=cvode, xp=x, output=out.dat) are left alone.
Initial values
Like @ values, init values are plain numbers read with atof(), and an initial condition y(0)= is a number too:
| you write | y starts at |
reported as |
|---|---|---|
init y=2*3 |
2 | error |
init y=a (with par a=2) |
0 | error |
y(0)=a |
0: the formula is only kept as y's history for delay equations |
warning (information in a model that uses delay) |
y(0)=2*3 |
2 | warning |
x[1..5](https://github.com/MuhammadMoustafa/XPP-ODE-Extension/blob/HEAD/0)=a*[j] |
a, 2a, ... as written: array conditions are evaluated |
— |
init y=-1.5e-3, y(0)=.5 |
as written | — |
Work the value out yourself, or, for an array, use the x[1..n](https://github.com/MuhammadMoustafa/XPP-ODE-Extension/blob/HEAD/0)= form.
Custom colours for variables and parameters
Give any name in your models its own look, independent of the theme: the membrane voltage always red, every parameter bold green, builtins italic, one variable in a box. The colours follow the parser, so a parameter is coloured everywhere it is used, not only on its par line.
Put a .xppsettings.json in a folder, and it applies to every .ode/.inc file in that folder and its subfolders:
{
"variables": {
"@states": "#ff7b72",
"@parameters": { "color": "#7ee787", "fontWeight": "bold" },
"@fixed": { "color": "#d2a8ff" },
"@builtins": { "fontStyle": "italic" },
"@options": { "opacity": 0.6 },
"v": { "color": "#ffffff", "borderColor": "#ff7b72", "borderRadius": "3px" },
"g_*": { "textDecoration": "underline" },
"iapp": { "light": { "color": "#a00000" }, "dark": { "color": "#ff8888" } }
}
}
Reading it: state variables are salmon and parameters bold green everywhere they appear. v is white in a salmon box, because an exact name wins over its group. Every name starting with g_ (g_na, g_k, g_l) is underlined in the theme's colour, because a wildcard wins over its group and replaces it entirely. iapp is dark red on light themes and pale red on dark ones. Option names on @ lines are faded.
Hex colours show a swatch you can click for the colour picker. Completion (Ctrl+Space, or typing " or @) offers the groups, every name declared in the folder's models with its kind, and the style properties with their allowed values; misspelled properties and invalid values are underlined. Changes apply immediately.
Where to put the configuration
| Place | Applies to | How |
|---|---|---|
"variables" in a .xppsettings.json in a folder |
every .ode/.inc file in that folder and its subfolders |
create the file; a file in a subfolder overrides one in a parent folder, key by key |
xpp-ode.variables in .vscode/settings.json |
the whole workspace | Settings > search "XPP-ODE" > edit in settings.json |
xpp-ode.variables in user settings |
every workspace | same |
Both places take the same object: the setting holds it directly, the file under its "variables" key. Files override the setting, key by key (see Which rule applies).
Keys
| Key | Meaning | Example |
|---|---|---|
| a name | that identifier, case-insensitive; an array name also covers its members | "v", "gsyn", "u" (covers u[j], u[0..9], u0...u9) |
a name with * |
every identifier matching the pattern (* = any letters, digits or _) |
"v_*", "*_syn", "u*x" |
@group |
a whole category, resolved by the parser | "@states", "@parameters" |
| Group | Contains |
|---|---|
@states |
state variables: x'=, dx/dt=, x(t+1)=, x(t)=, solv |
@parameters |
par and number parameters, !name= derived parameters |
@fixed |
fixed variables name=expression |
@functions |
user functions f(x)= |
@aux |
aux quantities |
@wiener |
wiener variables |
@markov |
markov variables |
@tables |
table and special names |
@options |
option names on @ lines (dt, total, xp, ...) |
@builtins |
builtin functions and constants (sin, heav, t, pi, ...) |
@keywords |
declaration keywords (par, init, aux, done, ...) |
Comments and text after done are never coloured.
Which rule applies
Every name gets at most one entry, chosen by these rules in order:
- Exact name (
"v"). For an array name, its members too ("u"coversu0...u9), unless a member has its own entry. - Wildcard (
"g_*"). When several match, the one listed last wins. - Group (
"@parameters"). A name belongs to one group only, so groups never compete.
The chosen entry replaces the others; properties are not combined. With "@parameters": { "fontWeight": "bold" } and "gna": "#ff0000", gna is red and not bold. Whatever the entry leaves out comes from the theme, not from a lower rule; to keep the bold, write it again: "gna": { "color": "#ff0000", "fontWeight": "bold" }.
When the same key appears in several places, the one closest to the file wins: the setting, then each .xppsettings.json from the workspace root down to the file's own folder, each overriding the one before for that key. The look and the description are overridden separately, so an entry that only adds a description keeps the colours given further up. The order above is applied afterwards, whatever the source: an exact name in your user settings still beats a wildcard in the folder's .xppsettings.json. Wildcards from all sources form one list, with the closer files' wildcards after (and so above) the setting's.
Inside a style, light/dark properties override the base properties for that kind of theme.
Values
A value is either a hex colour string or a style object.
"v": "#ff7b72"
"v": { "color": "#ff7b72", "fontWeight": "bold" }
| Property | Allowed values | Notes |
|---|---|---|
color |
#rgb, #rrggbb, #rrggbbaa |
text colour |
backgroundColor |
hex colour | use aa for a translucent highlight, e.g. #ffff0040 |
fontWeight |
bold, normal |
|
fontStyle |
italic, normal |
|
textDecoration |
underline, line-through, overline, underline wavy, underline dotted, underline dashed |
|
opacity |
0 to 1 |
0.5 fades the name |
borderColor |
hex colour | alone it draws a 1px solid box |
borderStyle |
solid, dashed, dotted, double |
|
borderWidth |
length: 1px, 0.1em |
|
borderRadius |
length: 3px |
rounded box corners |
light |
object with the properties above | applied only in light themes |
dark |
object with the properties above | applied only in dark themes |
description |
text | shown when hovering the name, see Descriptions on hover |
Every VS Code theme declares itself as light, dark or high-contrast; light/dark entries are layered on top of the base properties for that kind of theme. Entries the extension cannot use (unknown group, bad colour, unknown top-level key, ...) are skipped and reported once as a warning; the rest still apply.
Moving from .xppcolors.json
.xppcolors.json and the xpp-ode.identifierColors setting are deprecated. They still work in this release, with a warning, but will be removed:
- move the content of a
.xppcolors.jsonunder"variables"in a.xppsettings.jsonin the same folder, then delete the old file. While both exist,.xppsettings.jsonwins key by key; - rename the setting
xpp-ode.identifierColorstoxpp-ode.variables; its value is unchanged. While both are set,xpp-ode.variableswins key by key.
Descriptions on hover

Write what a name means in a # comment, like a docstring, and hovering the name anywhere in the code shows it with the name's kind:
par gna=120 # Maximal sodium conductance (mS/cm^2)
gna — parameter
Maximal sodium conductance (mS/cm^2) (line 1)
Names declared in #included files show their descriptions too.
Where to write a description
After the code, on the declaration line (or on any line of a line continued with \):
| Comment | Meaning |
|---|---|
par gna=120 # Max Na conductance |
one name on the line: the whole comment describes it |
par gna=120, gk=36 # gna: max Na; gk: max K |
name: text parts separated by ; describe each name |
par gna=120, gk=36 # conductances (mS/cm^2) |
several names and a plain comment: shared by all of them |
The comment is split into parts only when every part is name: text for a name on that line; otherwise it is plain text, so par gna=120 # units: mS/cm^2 describes gna as "units: mS/cm^2".
Above the declaration, one # name: text line per name, directly above it (no blank line in between). Handy for long lists; other comment lines, such as section headers, are ignored:
# ---- sodium current ----
# gna: maximal sodium conductance (mS/cm^2)
# ena: sodium reversal potential (mV)
par gna=120, ena=50
Keys are case-insensitive.
Arrays
An array such as x[1..10] is one name for a plain comment, and keys can pick its members:
| Key | Describes |
|---|---|
x: text |
the array and every member |
x[3..5]: text |
members x3..x5 |
x[3,5]: text |
members x3 and x5; lists and ranges mix: x[1..3, 7, 9] |
x7: text |
only x7 |
# x: membrane voltage of cell j (mV)
# x[1..3]: excitatory cells
# x7: the pacemaker cell
x[1..10]'=-x[j]+i_syn[j]
A key for a member the array does not have (x11: or x[9..12]: above) is a warning.
Several descriptions for one name
A name can have descriptions at several levels, and the hover shows them all, most specific first:
- its own:
x7:, or the plain comment on its own line; - a selection:
x[1..3]:,x[3,5]:; - inherited:
x:seen from a member, or a comment shared by the names of a line.
x7 — state variable (array x[1..10])
the pacemaker cell (line 3)
membrane voltage of cell j (mV) (line 1) — from x
Two descriptions at the same level (1 or 2) are a mistake: x3 above described by both x[1..3]: and a later x[3,5]:, or gna described both above its line and after it. The later one wins (a comment after the code counts as later than the lines above), and the other is marked with a warning "Description of "x3" is overridden by line 12" that links to the winner. Its quick fix (Ctrl+.) removes the overridden description.
Descriptions in .xppsettings.json
For names in files you cannot edit, or shared by a folder of models, add a description to the entry in .xppsettings.json or xpp-ode.variables. An entry may hold only a description, which leaves the colours alone:
{
"variables": {
"gna": { "color": "#7ee787", "description": "Maximal sodium conductance (mS/cm^2)" },
"v": { "description": "Membrane potential (mV)" },
"g_*": { "description": "A conductance" },
"@parameters": { "description": "Units: mS/cm^2 unless stated" }
}
}
These are shown after the comments, each with its key. Unlike colours, the levels do not hide each other: a name gets the description of its own entry, of every matching wildcard (last listed first) and of its group. An array member also gets its array's ("x" for x7). Keys with a selection ("x[1..3]") are not supported here.
Run ODE File
The "Run ODE File" button (editor title bar of any .ode file) saves the file, opens an integrated terminal in the file's folder, and runs:
<xpp-ode.runCommand> "<file name>.ode"
It runs in the file's folder because xppaut looks for #included files, table files and dll_lib libraries relative to the directory it is started from, and writes its output files there too.
The default command is xppaut, which works when xppaut is on your PATH. To change it: Settings (Ctrl + , / Cmd + ,) > search "XPP-ODE" > Run Command. Typical values:
| Setup | Run Command |
|---|---|
Linux, xppaut installed from the package manager or make install |
xppaut |
| macOS with XQuartz, xppaut not on the PATH | /usr/local/bin/xppaut (or wherever you installed it) |
| Windows, xppaut installed inside WSL (with WSLg or an X server) | wsl xppaut |
Windows, the Cygwin build from xppwin.zip |
C:\xppall\xppaut.exe (see below) |
| Extra options for every run | xppaut -xorfix, xppaut -silent, ... |
Since only the file name is passed, wsl xppaut works without translating Windows paths: WSL starts in the same folder. The setting can be set per workspace (.vscode/settings.json), so a project can carry its own command.
Windows with the Cygwin build
The Windows xppaut.exe is an X11 program. It needs two things, or it exits with "Failed to open X-Display":
- An X server running, such as Xming or VcXsrv. It sits in the tray once started.
- The
DISPLAYvariable telling xppaut where that server is. Starting the server does not set it; thexpp.batshipped with xppaut setsDISPLAY=127.0.0.1:0.0for this reason.
The extension handles both with xpp-ode.display and xpp-ode.xServer (see Settings). Before each run it checks whether a server is listening on the display. If none is and xpp-ode.xServer is set, it starts the server and waits for it; otherwise it shows a warning naming the address and the fix, and still runs xppaut so you see its own message too.
Do not chain the server into the run command (xming && xppaut): && waits for the first program to exit, and an X server never exits.
A complete Windows .vscode/settings.json:
{
"xpp-ode.runCommand": "C:\\xppall\\xppaut.exe",
"xpp-ode.xServer": "\"C:\\Program Files (x86)\\Xming\\Xming.exe\" :0 -multiwindow -clipboard"
}
Settings
| Setting | Default | Effect |
|---|---|---|
xpp-ode.variables |
{} |
colours, styles and descriptions per name, wildcard or group |
xpp-ode.precedence.comparison |
warning |
how to report a comparison next to arithmetic: warning, information, hint or off |
xpp-ode.precedence.logical |
warning |
how to report & or \| next to arithmetic, same values |
xpp-ode.precedence.power |
information |
how to report 2^3^2 and -2^2, same values |
xpp-ode.debounceDelay |
300 |
milliseconds to wait after typing before the file is checked again |
xpp-ode.runCommand |
xppaut |
the command the Run ODE File button runs; the file name is appended |
xpp-ode.display |
127.0.0.1:0.0 |
Windows only: DISPLAY given to xppaut when not already set |
xpp-ode.xServer |
empty | Windows only: X server command line to start when none is running, e.g. "C:\Program Files (x86)\Xming\Xming.exe" :0 -multiwindow -clipboard |
Future work
- Handle active comments.
.anianimation files: highlighting, and counting their references as uses of the.odenames.
Feedback and credits
Found a problem or want a feature? Open an issue or email me.
- This extension is a fork of Joe-McCann's XPP-ODE-Extension, which added the first highlighting of reserved functions, derivatives and comments, for any theme.
- Logo designed by Manar Moustafa.
- Thanks to Nianqi Deng for suggesting the Run ODE File button, and to Leqi (Sammy) Wang for suggesting custom colours.

