Skip to main content

nctab

Terminal NC/G-code editor and toolkit for CNC programmers who work over SSH, in tmux, on a shop-floor PC without a Windows GUI.

uvx nctab stats part.nc
uvx nctab shift part.nc --z -0.02 -o part_z.nc
uvx nctab diff --ignore-n old.nc new.nc

Nothing is written without --in-place / -i or --output / -o: every transform prints a diff and stops. Writes are atomic, and --backup keeps a .bak copy. Numbers are Decimal throughout, and a line an operation does not touch comes back byte for byte.

Demo

If the player does not load, watch the demo video.

Status

Stages 0 to 3 of PLAN.md are done: the parser, machine profiles, all code transforms, search and replace, validation, NC-aware diff, the TUI editor and snippets. Packaging to PyPI and DNC sending are still to come.

The interface is English only.

Editor

uvx nctab edit part.nc
uvx nctab part.nc          # the same thing

Three panes. On the left a panel with two tabs: the outline of tool sections, and a file list showing the programs in your G-code folder. The editor is in the middle, and on the right an inspector decodes the word under the cursor and shows the modal state in effect on that line. Everything the inspector says comes from the machine profile, so a custom profile teaches it new codes.

Opening a file from the list is refused while the buffer has unsaved changes: save with Ctrl+S, or press Ctrl+R to discard them and open anyway.

The editor is always in insert mode, so no binding is a plain character: typing ] inserts ].

Key Action
Ctrl+F Find. Text, pattern, an address word, or a G/M code
F3, Shift+F3 Next and previous match, with a 3/17 counter
Ctrl+G Go to a line number, or N120 for a block
F4, Shift+F4 Next and previous tool change
F5, Shift+F5 Next and previous motion block
Ctrl+B then a letter Set a bookmark
Ctrl+J then a letter Jump to a bookmark
Ctrl+H Find and replace, with a preview of every change
Ctrl+N Renumber
Ctrl+T Shift, scale, mirror or rotate
F2 Insert a snippet, with a live preview of the body
F9 Switch the left panel between the outline and the file list
Ctrl+O Focus the left panel
Ctrl+P Command palette
Ctrl+S, Ctrl+Q Save, quit
F1 Key reminder in the status bar

Find and replace

Both keys open the same dialog, in find or replace mode. Pick how to search from one dropdown: plain text, a regular expression, an address word, or a G or M code.

The match count updates while you type, and every match is listed with its line and block number, so an empty search or a pattern that catches too much is obvious before you commit to it. Picking a row from the list jumps the editor straight to that match. In the file itself every match is highlighted at once and the current one picked out, so you can see the distribution at a glance.

In address mode there is no typing at all: one dropdown lists the addresses the program uses with their counts, the other lists the values that address actually takes, with the line each first appears on. No more guessing whether the file says F300 or F300..

Replace shows what each match becomes before anything is written, computed by the same code that performs the edit, so the preview cannot disagree with the result. A match that would not actually change is labelled as such. Individual rows can be switched off with Space, or in bulk with All and None, so "every F except that one" needs no cleverness with the pattern.

Commands

Inspect

Command What it does
nctab stats FILE Line and block counts, axis min/max, G/M histogram, tools, feeds, speeds, path lengths
nctab tools FILE Each tool section: first line, block count, D/H offsets, speeds, feeds, name from the nearest comment
nctab check FILE 21 validation rules; exit code 2 on an error, --strict also on a warning
nctab profiles Available machine profiles, with the active one marked
Command What it does
nctab find FILE "G41 D" Text search; --regex for a pattern, --case to match case
nctab find FILE --addr F Every distinct F value with counts and where it occurs
nctab find FILE --addr F --value 300 The F300 words themselves; --min/--max for a range
nctab find FILE --code G02 Every G02 block, however it is zero-padded
nctab replace FILE --addr F --value 300 --to 250 Batch replace keeping the source number style
nctab replace FILE --regex 'X(\d+)\.' --to 'X\1.0' Regex replace with back-references

Comments are never touched unless you pass --in-comments.

Transform

Command What it does
nctab renumber FILE --start 10 --step 10 Renumber N blocks; --width 4 for N0010, --strip to remove them
nctab strip FILE --n --comments --blank Remove block numbers, comments, blank lines, / marks or blocks, spaces
nctab case FILE upper Upper- or lower-case the code, leaving comments alone
nctab shift FILE --z -0.02 Translate absolute coordinates
nctab math FILE --addr Z --op add --value -0.013 Arithmetic on every word of an address
nctab feeds FILE --f-scale 0.9 --f-min 80 Scale and clamp feeds and spindle speeds
nctab scale FILE --factor 1.02 --about 0,0,0 Scale linear axes about a point
nctab mirror FILE --axis x Mirror an axis, swapping G02/G03 and G41/G42
nctab rotate FILE --deg 90 --cx 50 --cy 25 Rotate in the G17 plane; multiples of 90° are exact

Every transform takes --range / -r to limit the work: 10-200 for lines, N100-N500 for block numbers, T12 for one tool's section.

Snippets

nctab snippets
nctab snippets tool-change --set T=7 --set S=4500

Snippets are TOML files with typed fields and a body. Built-ins cover the program header and footer, tool change, safe retract and the drilling cycles; drop your own in ~/.config/nctab/snippets/, or in a <profile-id> folder under it to limit them to one control. A float field writes Z-10. rather than Z-10, because a missing decimal point is read as the least significant increment on some controls.

Compare

nctab diff old.nc new.nc --ignore-n --ignore-whitespace
nctab diff old.nc new.nc --normalize-all --side-by-side

Exit code is 1 when the files differ, so it can gate a CI step.

Machine profiles

fanuc-mill, fanuc-turn, haas-mill, siemens-iso, generic-iso. A profile describes the dialect: comment syntax, axis letters, plane codes, the G and M code dictionary, and the number format. Pick one with --profile / -p, or point it at your own file: -p ./my-control.toml. User profiles also load from ~/.config/nctab/profiles/.

Configuration

Layers, later ones winning: built-in defaults, ~/.config/nctab/config.toml, the nearest .nctab.toml at or above the working directory, NCTAB_* environment variables, then CLI flags.

[editor]
backup = true

[defaults]
directory = "~/nc"    # where the programs live
profile = "fanuc-mill"
digits = "preserve"   # or a number of fractional digits
rounding = "HALF_UP"
arc_tolerance = 0.001

directory is the folder of G-code programs. The editor's file list opens there, and a bare file name the CLI cannot find in the working directory is looked up there too, so nctab stats OP20.nc works from anywhere. A file that does exist where you are standing still wins. Unset means the working directory, so nothing changes until you set it. NCTAB_DIR overrides it for one command.

A malformed config layer is reported as a warning and skipped, never fatal.

JSON output

Every reporting command takes --json and emits a versioned schema, so stats, check, tools and diff can drive a CI job.

uvx nctab check part.nc --json | jq '.diagnostics[] | select(.severity=="error")'

Development

uv sync --all-extras
uv run pytest
uv run ruff check && uv run ruff format --check
uv run ty check src

License

MIT

Metadata

Release files for nctab 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nctab 0.1.0
File Size Uploaded
nctab-0.1.0.tar.gz 79.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nctab 0.1.0
File Interpreter ABI Platform
nctab-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 189.7 kB

Release files / nctab-0.1.0.tar.gz

Download URL nctab-0.1.0.tar.gz
Size 79.8 kB
Tags Source
SHA-256 checksum
How to use checksums
a58eb9e5e92ce27d5829d906ad31f1f1e6ec734ffefd74240201a569287e0751
BLAKE2b-256 checksum
How to use checksums
e01727bc16960d4e91f3b85459fb6cb2469127491dc7e78c33ed7eb70f2ceb0f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / nctab-0.1.0-py3-none-any.whl

Download URL nctab-0.1.0-py3-none-any.whl
Size 110.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
35be893698665a34fae1dfd49561c7bcbad03a05ddc4e4871733d2c989015abf
BLAKE2b-256 checksum
How to use checksums
e7613a2a0a9452f64d317b91c7b7f7bec732fef442a9cc52215e716fd3366706
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

0.2.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page