User manual › The command window — the command engine for a user
kind: manual#console#command-window#quick-code#variables#expressions#recipe#history#completion#manual

The command window — the command engine for a user#

The command window is the text way into ICoreBlocks. One line typed at its prompt can be a calculator expression over matrices and transfer functions (y = x*[1 2; 3 4]), a recipe statement that creates, wires or configures a block on the open diagram (g = block(Gain)), or a named command (modelConfig, templates, gitStatus). The same evaluator runs a line headlessly: ICoreBlocks --console "<line>" prints the result and exits 0 or 1. This page explains the engine — how a line is read, where variables live, what Tab and the arrow keys do, and how the console reaches the canvas. The roster of what you can type is Command glossary — console commands, verbs, functions; the recipe language, .iscript files and templates are on Recipes and templates — recording, replaying and reusing diagrams; words such as handle, recipe and subsystem are defined in User glossary — the vocabulary of using ICoreBlocks.

Where it is#

  • In the editor: the left panel page Quick Code (menu Code Engine → Scripting → Quick Code, or the panel strip). It is a transcript on top, a status row (A- 13pt A+ text-size control, ● ready / ● busy) and the prompt below, placeholder text Enter Command. The transcript is also reachable as View → Loggers → Command History.
  • Headless: ICoreBlocks --console "<line>". The line runs 1.5 s after startup through the very same function the panel calls (ICoreCommandWindow::evaluateLine, wired in src/ICoreSDK/Shell/Application.cpp); output goes to stdout on success, stderr on failure, and the process exit code is 0/1 by the line's verdict. A bare --console with no line never exits.
  • The Script Runner (Code Engine → Scripting → Script Runner) feeds a whole .iscript file to the same evaluator one line at a time — see below.

The rules the engine enforces#

  • A line is split into statements on top-level ; — a ; inside (...), [...] or <...> is not a separator, which is what lets [1 2; 3 4] stay one matrix literal. Statements run in order and stop at the first failure.
  • A statement ending in ; is silent when it succeeds (MATLAB's rule). Failures are always printed; silencing never hides an error.
  • Each statement is classified in this order, first match wins:
    1. a recipe statement — block(...), subsystem(...), connect(...), area/image/textbox(...), plot(...), selectionModel(), clearDiagram(...), handle.method(...), or a bare handle name;
    2. an assignment name = rhs;
    3. a bare name that is a defined variable (echoes it);
    4. an expression — a number, a [...] literal, or anything carrying an operator (+ - * / | & ' ( ));
    5. a registered command: first word is the command, the rest are its arguments; name() is accepted as name. Nothing matched → unknown command: <first word> and the line fails.
  • A command name is never shadowed. A variable named like a command is not echoed by its bare name, and an expression whose first word is a command (reverse a+b, clear()) is dispatched as that command.
  • A block handle beats a variable of the same name in name.method(...); a name that is only a variable falls through to the math grammar (h.values(), G.step(10)), which is how time series and transfer functions get their members.
  • Results are annotated with their type7 # Integer, 0.333333 # Double, [[3, 6], [9, 12]] # Matrix of Double, and likewise # Polynomial, # Transfer Function, # State Space, # Time Series, # String. The annotation is the variable system's real type name; a scalar whose value is whole prints as Integer.
  • Only one line runs at a time. While a line runs the prompt is disabled and the status shows ● busy; a second line cannot slip in underneath.

The variables space#

  • Create: x = 3, A = [1 2; 3 4], label = hello, G = tf([1],[1,2,1]). The right-hand side is either a literal (stored as typed), a bare name (copies an existing variable, otherwise stores the word as a string), or an expression (evaluated, then stored). The reply echoes the stored value: x = 3 # Integer.
  • Types are derived from the stored text: Integer, Double, Matrix of Double, String, Transfer Function, State Space, Polynomial, Time Series (src/ICoreSDK/ICoreMath/ICoreVariable.cpp). Matrices print in Python list form; the stored form is MATLAB syntax.
  • Read: the bare name echoes it; use it in any expression.
  • List: the left panel page Variables is the table view of the same store. There is no console command that lists all variables (checked 2026-08-17 against the roster in Command glossary — console commands, verbs, functions).
  • Clear: clearVariablesSpace empties the store; clearAll also wipes the logs and the recipe handles.
  • One store, project-wide. There is exactly one variables space; blocks in every subsystem see it. Its variables are saved with the project: the .iproj file is recipe text and its first lines are name = value; declarations (generateRecipe shows exactly what will be written; see the run below). A headless --console process starts with an empty store and an unsaved project, so nothing carries from one invocation to the next.
  • A block can read a console variable. Type a variable's name into a block parameter (Gain Value = K). When the run starts the block's configuration is loaded and every parameter whose text is not itself a number or matrix is looked up by name in the variables space; a numeric hit supplies the matrix, a miss leaves the text as a string (ICoreBlockSolverEnvironment::loadBlockConfig, src/ICoreSDK/ICoreModel/SolverEnvironments/). The lookup happens at run start, so change K and re-run; the block does not track it live.
  • v = handle.get(prop) / v = handle.getConfig(name) store a numeric snapshot as an ordinary variable — later block edits do not update v, and text properties refuse to bind.

Things that surprise users#

(More symptoms, beyond the console, are collected on Troubleshooting — the messages you will meet and what to do.)

  • unknown command: x for a variable you just made — each --console process is fresh, and clearVariablesSpace/clearAll empty the store; a bare name that is not a variable, a handle or a command falls all the way through to the command dispatcher, whose message this is. Same cause for a typo in a variable name.
  • unknown command: 2^3 — there is no power operator. The engine decides a statement is an expression by seeing one of + - * / | & ' ( ) outside brackets; ^ is not one, so the text is tried as a command. Use the matrix functions in Command glossary — console commands, verbs, functions (pow(A,n) element-wise, mpower(A,n), inv(A), …) instead. Bounds and precision of the evaluator: Numerics — what the solver will and will not do.
  • A chained line printed only its last result — every statement you closed with ; was silent by design; only the unterminated tail speaks.
  • error: division by zero stops the rest of the line — statements after the failing one do not run; the exit code is 1.
  • A variable named like a command will not echoclear, help, echo and every other registered name are dispatched as commands first; such a variable is reachable only inside an expression. Pick another name.
  • Tab completed nothing — completion only offers at a statement head, right after =, or right after a . (ICoreCompletion::tokenStart); mid-argument it stays quiet, and it completes names from the glossary only (commands, matrix functions, recipe verbs) — not your variables, not block types.
  • The suggestion popup ate my Enter — with the popup open, Enter on an entry you arrowed onto takes the entry; Enter with nothing highlighted closes the list and submits the line exactly as typed.
  • Up arrow recalls last week's commands — history is on disk (below).
  • The .iproj grew a K = 2.5; line — that is the variables space being saved with the project. It is intended.

Tab, the popup, and history#

  • Tab completes the current token from the glossary (case-insensitive prefix match): the longest common prefix is filled in, and if more than one name is still open the popup lists them (at most 8 visible, scrolling). If an entry is already highlighted, Tab takes it exactly as Enter does.
  • The popup appears as you type at a completable position and filters by prefix. Up/Down move inside it; Enter takes the highlighted entry; clicking an entry does the same.
  • Up/Down with the popup closed walk the submitted-line history (newest first); the half-typed draft is kept and comes back at the bottom.
  • History is persisted in commandHistory.txt inside the app's data folder (on macOS ~/Library/Application Support/ICore Blocks/), appended on every submit — a crash loses nothing. Settings → Editor → Command Console → Command History Kept sets how many lines Up can reach (default 500, max 5000; 0 stops recording without erasing). clearCommandHistory deletes the file and empties the in-memory list.
  • glossary prints the full catalog the popup draws from; help lists the registered commands only.
  • Ctrl+wheel / Ctrl+plus/minus / Ctrl+0 zoom the transcript; cls or clear wipe it; clearAllLogs wipes every output log.

Scripts#

A script is a plain-text file with the extension .iscript, one console line per line; blank lines and lines starting with # are skipped. It may contain anything the prompt accepts — recipe statements, assignments, expressions, commands. Scripts live in <project folder>/scripts and are run from the Script Runner panel (Run for the open script, Run All for every script in the folder, name order); a script stops at its first failing line and the panel reports which line. The recorded form of a diagram is itself an .iscript (Import Diagram, generateRecipe, saveTemplate/useTemplate) — the whole story is on Recipes and templates — recording, replaying and reusing diagrams. There is no console command that runs a script file by name (checked 2026-08-17).

The console and the canvas#

Recipe statements act on the open project: block(Type, Parent) creates a block in a subsystem (parent defaults to Home), connect(a<1>, b<0>) links output port 1 of a to input port 0 of b, .setConfig(name, value), .move, .rename, .delete edit it, .info and .listConfig report it, and generateRecipe [path] prints the recipe that reproduces a whole level. Handles (g, s) are names for live objects and are listed in the Objects Tracker panel; .delete is permanent (no trash, no undo). Headlessly "the open diagram" is the empty, unsaved project the app starts with — the run below creates a block at ICore Blocks/Home/Gain — so a --console recipe is a way to test a line, not a way to edit a saved project (open it in the editor for that, or use the Script Runner). Verbs are listed under Recipe verbs in Command glossary — console commands, verbs, functions.

Real runs#

Binary build-mac/ICoreBlocks.app built 2026-08-16 23:39 (source at approximately commit 2e126fbf). Every run below is one process, HOME=<scratch> QT_QPA_PLATFORM=offscreen ICoreBlocks --console "<line>", with the toolkit's startup noise removed; exit= is the process exit code.

(a) Arithmetic and variables

>>> x = 3; y = x*[1 2; 3 4]; y
y = [[3, 6], [9, 12]]  # Matrix of Double
exit=0

>>> A = [1 2; 3 4]; A' | A
[[1, 3, 1, 2], [2, 4, 3, 4]]  # Matrix of Double
exit=0

>>> label = hello; label
label = 'hello'  # String
exit=0

>>> x = 3; clearVariablesSpace; x
unknown command: x
exit=1

(' is transpose, | horizontal and & vertical concatenation — read in src/ICoreSDK/ICoreMath/ICoreExpressionEvaluator.cpp.)

(b) An unknown command, and a non-operator

>>> frobnicate 3
unknown command: frobnicate
exit=1

>>> 2^3
unknown command: 2^3
exit=1

(c) Recipe verbs on the headless diagram

>>> K = 2.5; g = block(Gain); g.setConfig(Gain Value, K); g.listConfig; generateRecipe
K = 2.5;
Gain = block(Control_Systems/Base_Blocks/Gain);
Gain.rename(Gain);
Gain.move(0, 0);
Gain.resize(70, 70);
Gain.setConfig(Sampling Time (s), -1);
Gain.setConfig(Gain Value, K);
Gain.setConfig(Multiplication Type, Element-wise (K.*u)%~%Matrix (K*u)%~%Matrix (u*K)%~%Matrix (K*u) (u vector)~~Element-wise (K.*u));
subsystemTimes(ICore Blocks/Home, 1786955336275, 1786955337779);
exit=0

>>> g = block(Gain); s = block(Step); connect(s<0>, g<0>); g.getConfig(Gain Value)
Gain Value = 1
exit=0

g.info on the same block printed the full property sheet (name, type, fullType: Control_Systems/Base_Blocks/Gain, path: ICore Blocks/Home/Gain, size, rotation, ports and the block's description) — 60 lines, not repeated here. Note the first line of the recipe: the console variable K is part of what the project saves.

(d) A statement chain with and without the trailing ;

>>> x = 3; y = x*2
y = 6  # Integer
exit=0

>>> x = 3; y = x*2;

exit=0

>>> x = 3; x; x*2; 1/3
0.333333  # Double
exit=0

>>> x = 3; y = x/0; y
error: division by zero
exit=1

For contributors#

The evaluator's order of resolution is ICoreCommandWindow::evaluateLine (src/ICoreSDK/ICoreStudio/StudioObjects/Panels/CommandWindow/), and the console-facing invariants — result handlers, main-thread only, the ; terminator the serializer emits, --console exit codes — are stated on the contributor page for the command system (icorecoder), with the expression grammar on icoremath and the --console hook on shell.