Usage
nessemble is driven from the command line. This page documents its options and
subcommands.
Usage: nessemble [OPTIONS] [infile.asm]
nessemble <COMMAND>
Commands:
init initialize new project
scripts install scripts
reference get reference info about assembly terms
lsp run the language server (stdio)
format format assembly source
lint lint assembly source
coverage report runtime coverage from a CDL capture
help Print this message or the help of the given subcommand(s)
Arguments:
[infile.asm] assembly source to assemble (stdin if omitted)
Options:
-o, --output <outfile.rom> output file
-f, --format <NES|RAW> output format
-e, --empty <hex> empty byte value
-u, --undocumented use undocumented opcodes
-l, --list <listfile.txt> generate list of labels and constants
--mlist include labels created by macros in the list file
-p, --pseudo <pseudo.txt> use custom pseudo-instruction functions
--root <dir> project root for `@/`-relative paths
--max-operations <n> cap each pseudo-op script's Rhai operation count
--time-scripts report per-directive script call count and wall time
-c, --check check syntax only
-v, --version display program version
-L, --license display program license
-h, --help Print help
The help text above is generated by clap; run
nessemble --help (or nessemble <command> --help) for the current output.
The lsp command starts the built-in Language Server for use with
LSP-capable editors. The format command reformats assembly source (§
format) and the lint command reports style problems
without rewriting it (§ lint). The coverage command reports
coverage from an emulator CDL capture, the -p Rhai scripts, or both (§
coverage).
Options
-o, --output <outfile.rom>
Sets the filename where output is written. An outfile of - (or omitting the
flag) writes to stdout.
nessemble infile.asm --output outfile.rom
-f, --format
Specifies the output format:
NES— an iNES ROM, complete with a 16-byte header.RAW— raw assembled 6502 code.
The format is RAW by default, but if iNES header directives (.inesprg,
.ineschr, …) are present, it becomes NES unless overridden.
-e, --empty <hex>
Sets the fill value for empty/unwritten ROM bytes. Defaults to FF.
nessemble infile.asm --empty 00
-u, --undocumented
Allows the use of undocumented ("illegal") opcodes.
-l, --list <listfile.txt>
Writes a list of labels and constants to the given file.
Labels defined inside a macro body are omitted by default, so the list is
not cluttered with the per-invocation labels a macro emits each time it is called
(for example a loop target uniquified with \@). Pass --mlist to include them.
--mlist
Includes labels created by macro expansion in the --list output. Has no effect
unless --list is also given.
nessemble infile.asm --list listing.txt --mlist
Constants defined in macros always appear in the list; --mlist affects only the
[labels] section. See Macros for more on macro-defined
labels.
-p, --pseudo <pseudo.txt>
Points to a mapping file that enables custom pseudo-instructions. See Extending.
--root <dir>
Sets the project root that @/-prefixed
filename arguments resolve against, overriding the usual walk-up for the nearest
.nessemblerc, .nessemblerc.json, or .nessembleignore.
nessemble src/main.asm --root .
dir must exist; a missing or non-directory path is rejected before assembly
starts.
--no-cache
Neither reads nor writes the custom pseudo-instruction cache: every directive's script runs. Reach for this when a build looks stale, or to confirm that a suspected caching problem is one.
--max-operations <n>
Overrides the runaway-script guard
on every pseudo-op script, in place of the built-in default of 10,000,000
Rhai operations. 0 means unlimited.
nessemble src/main.asm --pseudo pseudo.txt --max-operations 50000000
--time-scripts
Prints a per-directive report to stderr after assembly: how many times each
.foo-style directive was called, how many of those were cache hits versus
real script runs, and the total wall time spent in it — busiest directive
first. See Runaway-script guard and
timing.
-c, --check
Checks the input for syntax errors only; produces no output.
-v, --version / -L, --license / -h, --help
Print the version, license, or usage message respectively.
Commands
init [<arg> ...]
Scaffolds a new project, prompting for any values not supplied as arguments:
nessemble init [filename] [prg] [chr] [mapper] [mirroring]
filename— file to create.prg/chr— number of PRG / CHR banks.mapper/mirroring— iNES mapper and mirroring.
scripts
Installs the bundled custom-pseudo-instruction scripts into
~/.nessemble/scripts. See Extending.
cache info | cache clear
Inspects or empties the custom pseudo-instruction
cache in ~/.nessemble/cache.
nessemble cache info # where the cache is, how many entries, how many bytes
nessemble cache clear # delete every entry
Clearing is always safe: an entry is a saved result, never the only copy of anything, so the next build recomputes what it needs.
reference [<category>] [<term>]
Prints reference information from locally bundled data. With no arguments it
lists the categories (instructions, directives, script); with a category it
lists its entries; with a term it prints the details (e.g. reference instructions LDA).
The script category is the host API a custom pseudo-op
script can call, grouped by domain:
nessemble reference script # every function, method, and property
nessemble reference script nes_shade # signature, summary, and a docs link
A name catalogued more than once prints each meaning — read_blob is both a
method on an open file handle and a one-call function — and an entry that needs
a build feature says so, since the WebAssembly build has neither
filesystem access nor random
numbers.
format [<opt> ...] <path> ...
Reformats nessemble assembly source in an opinionated, Prettier-style
way: consistent indentation and comma spacing, .db/.dw/.color data
consolidated a fixed number of values per line, a blank line after each
RTS/RTI, collapsed runs of blank lines, and a normalized final newline.
Formatting is cosmetic only — the assembled ROM is never changed.
nessemble format path/to/file.asm # print formatted source to stdout
nessemble format --write path/to/dir # rewrite files in place
nessemble format --check path/to/dir # CI gate: exit non-zero if unformatted
- A single file with no flags prints the formatted result to
stdout, leaving the file untouched. -w,--writerewrites each changed file in place and prints its path.-c,--checkwrites nothing; it lists files that are not already formatted and exits non-zero — the gate for CI.- A directory is walked recursively (for the configured extensions,
.asmby default) and requires--writeor--check. --config <file>uses<file>as the.nessemblerc;--no-configignores any.nessemblercand uses built-in defaults.
The editor Language Server's "format document" action runs this same formatter, so editors and the CLI produce identical output.
lint [<opt> ...] <path> ...
Reports style problems in nessemble assembly. Where format is Prettier, lint
is ESLint: it only reports and never rewrites source.
nessemble lint path/to/file.asm # report problems for one file
nessemble lint path/to/dir # walk a tree and report problems
src/prg/07.asm
42:1 warning code block `sound_engine` has no nearby comment require-block-comment
103:1 warning unknown comment directive `@nessemble-formt` unknown-comment-directive
✖ 2 problems (0 errors, 2 warnings)
The rules:
| Rule | Flags |
|---|---|
require-block-comment | A block-opening label with no comment nearby — a named label whose preceding non-comment line is blank or the top of the file. Internal branch targets and anonymous labels are never flagged. |
unknown-comment-directive | A comment directive naming no known directive (@nessemble-formt), or a known one with wrong arguments (@nessemble-format stride=x). |
deprecated-comment-directive | A directive written with a deprecated alias — today, @fmt for @nessemble-format. |
ineffective-comment-directive | A well-formed directive that cannot apply where it is written: in a trailing comment, a -next-line with no following line, a stride hint with no data run after it, or an unbalanced ignore-region bound. (An unclosed region is not flagged — that is the documented whole-file opt-out.) |
invalid-routine-signature | A routine annotation that binds to no label (code intervenes, or the file ends), or names the same slot twice. |
undeclared-clobber | A routine that writes a register its @nessemble-clobbers omits — the annotation and the code disagree. Only routines that declared a clobber list are checked. |
overdeclared-clobber | A routine that declares a clobber its body cannot produce. Fires only when the body holds no unknowns (no macro invocation, unannotated call, indirect jump, or data run). |
require-routine-doc | A called routine with no annotations at all. Off by default — switch it on per project once you are using the convention. |
- Each finding prints as
LINE:COL severity message rule-id, grouped by file, with a problem-count footer; a clean run prints✓ No problems. - Exit code: any
error-severity finding fails the run (exit non-zero);warnfindings do not, unless--max-warnings <n>is exceeded. This is the CI gate. - A directory is walked recursively (for the configured extensions,
.asmby default), skipping.nessembleignorepaths. --quietreports errors only (suppresses warnings).--config <file>uses<file>as the.nessemblerc;--no-configignores any.nessemblercand uses built-in defaults.
Every rule defaults to warn except require-routine-doc, which defaults to
off. Rules, their severities, the comment window, and the label-name ignore
list are configured under the lint key of .nessemblerc. The editor
Language Server surfaces the same findings inline as you type,
including quick fixes for the deprecated directive spelling and for a register
missing from a clobber list.
Suppressing a finding
Two directives silence findings at the site, for when a rule is wrong about a particular routine:
; @nessemble-lint-ignore-next-line [rule[, rule...]]
; @nessemble-lint-ignore start|end [rule[, rule...]]
Bare, they suppress every rule. With a comma-separated list of rule ids, only
those. An unknown rule name is reported as
unknown-comment-directive, so a typo cannot silently
silence nothing.
These exist because the clobber analysis has two known blind spots, both of which force an author to choose between a false annotation and a false finding. Suppressing at the site is the third, better option:
Fall-through entry points. A routine's body is read as its own block plus
the JSR/JMP targets it names; a routine that falls through into the next one
is not followed. So assign_chr_bank below really does clobber A, X, Y — via
the routine it falls into — but its own block writes no register, and
overdeclared-clobber fires:
; @nessemble-lint-ignore-next-line overdeclared-clobber
; @nessemble-clobbers A, X, Y, [chr_bank_arg]
assign_chr_bank:
STA <chr_bank_arg
; falls through ↓
; @nessemble-clobbers A, X, Y
find_or_evict_chr_slot:
...
Save/restore pairs. A PHA … PLA around a routine's body preserves A,
but the restore is not modeled, so undeclared-clobber asks you to declare A
clobbered — inverting what the tag means:
; @nessemble-lint-ignore-next-line undeclared-clobber
; @nessemble-clobbers X, Y, [draw_tmp]
ppu_set_xy_addr:
PHA
...
PLA
RTS
In both cases the annotation stays truthful — it is what a caller needs to know — and exactly one bogus finding is suppressed.
The rules are the coverage directives' rules, because it is the same mechanism:
-next-linetargets the next significant line, skipping blank and comment lines. That is what lets it sit above a whole@nessemble-paramblock and still land on the label, which is where the routine rules report.startopens a region andendcloses it; an unclosed region runs to end of file (the whole-file opt-out), regions do not nest, and a region never crosses into an.included file.- A directive in a trailing comment is inert, and reported.
- Matching is by the line a finding is reported at. Most rules report at the
label — including
undeclared-clobber,overdeclared-clobber, andrequire-block-comment— so-next-lineabove the label reaches them.invalid-routine-signatureand the comment-directive rules report at the annotation line instead, so use the region form to suppress those. - A suppressed finding is gone, not downgraded: it does not print, does not
count toward
--max-warnings, and does not affect the exit code, even when the rule's configured severity iserror. Severity is your choice in.nessemblerc, so it is not a reason to withhold the escape hatch. - Suppression applies to lint findings only. It never silences a parse or assembly error.
coverage <infile.asm> --cdl <file.cdl> ...
Reports runtime execution coverage of an assembled ROM against a CDL
(Code/Data Logger) capture an emulator wrote after running the ROM, line
coverage for the -p Rhai scripts a build runs, or both. It never writes a
ROM.
nessemble coverage main.asm --cdl capture.cdl # coverage.json + coverage.lcov
nessemble coverage main.asm --cdl capture.cdl --format lcov --out cov.lcov
nessemble coverage main.asm --cdl a.cdl --cdl b.cdl --emulator mesen
nessemble coverage main.asm -p pseudo.txt --scripts # scripts only, no CDL, no emulator
At least one of --cdl or --scripts is required.
With --cdl, the source assembles with a byte-exact source map and each
PRG-emitting line is classified as code (executed), data (read),
mixed (both), or unaccessed (present but never touched). Only the PRG
section is classified; lines that emit only CHR data are omitted.
-
--cdl <file>— the CDL to read; repeatable (multiple files are merged by bitwise OR). Required unless--scriptsis given. -
--emulator <fceux|mesen>— the CDL format, defaultfceux. FCEUX and Mesen flat masks are the same size but bit-incompatible, so there is no auto-detect; state the emulator that produced the file. (BizHawk's container format is not yet supported.) -
--format <json|lcov|all>— report format, defaultall. JSON carries the full four-way class per line, plus a"kind"of"rom"or"script"per file; LCOV is line hit/not-hit for coverage tools and has nokind. -
--out <path>— output file for a single format, or a directory forall(coverage.json+coverage.lcov); defaults to the current directory. -
-p,--pseudo <pseudo.txt>— custom pseudo-op mapping, as in assemble mode. -
--root <dir>— project root for@/-relative paths, as in assemble mode. -
--max-operations <n>— caps each pseudo-op script's Rhai operation count, as in assemble mode. -
--scripts— also report line coverage for the-pRhai scripts, so you can see which parts of a custom pseudo-op never ran during assembly. Each project script appears as its own file (each line executed or not); bundled~/.nessemblescripts are excluded. Available when the binary is built with thecoveragefeature (on by default).Given without
--cdl, this reports scripts alone: the source assembles without forcing NES mode or a source map, no CDL is read, and no--emulatoris consulted — the shape a CI job without an emulator playthrough can produce. Every script the-pmapping names is included, even one whose directive the build never reaches (reported at 0%, not omitted); a script mapped under two directive names appears once. A run that instruments no script at all — no-pmapping given, or the mapping named nothing readable — prints a warning saying why instead of a silent, unscripted report. -
--no-ignore— report every line, disabling the@nessemble-coverage-ignore…directives.
Source can exclude lines it does not want measured with the coverage ignore directives; excluded lines leave both the numerator and the denominator, and the run reports how many were dropped:
coverage: 812/900 lines (90.2%) — 14 lines, 1 file ignored
When both --cdl and --scripts contribute files, the single percentage above
can move for reasons that have nothing to do with the ROM, so the summary also
splits the two:
coverage: 812/900 lines (90.2%) — rom 780/840, scripts 32/60
The CDL must be the same size as this ROM's PRG+CHR (it carries no ROM identity of its own); a size mismatch is a hard error. Equal sizes still do not guarantee the CDL came from this exact build, so capture it from the ROM this source assembles to.
Comment directives
Some nessemble tools take instructions from the source itself, written as comment directives: a comment whose first token names the tool and what to do.
; @nessemble-<name> [args] [; trailing prose]
| Directive | Applies to | Tool |
|---|---|---|
@nessemble-format stride=N[,N,...] | the next data run (skipping blank, comment, and label lines) | format |
@nessemble-coverage-ignore-next-line | the next significant line | coverage |
@nessemble-coverage-ignore start | end | every line between the two | coverage |
@nessemble-param <slot> [description] | the routine below — a register it reads | lint, editor |
@nessemble-returns <slot> [description] | the routine below — a slot it defines | lint, editor |
@nessemble-clobbers <slot>[, ...] | none | the routine below — what it destroys | lint, editor |
@nessemble-lint-ignore-next-line [rule[, ...]] | findings on the next significant line | lint |
@nessemble-lint-ignore start | end [rule[, ...]] | findings on every line between the two | lint |
@fmt stride=N[,N,...] | deprecated alias of @nessemble-format | format |
The rules are the same for every directive:
The routine annotations are described in Documenting routines; the rules below apply to every directive.
- It must be on its own line — a directive in a trailing comment
(
LDA #$00 ; @nessemble-…) does nothing, and is reported. - The
@…token must come first in the comment, after the;(or;;,;;;) and any spaces. A directive mentioned mid-sentence is prose. - Names are exact and lower-case; anything after the arguments and a second
;is free-text prose. - A directive applies to what follows it, and blank lines, comment lines, and label or constant definitions in between are skipped — so a directive can sit above the label that names its subject, and an explanation can follow the directive.
- An unrecognized
@nessemble-…name, or a known one with wrong arguments, is reported bylintand in the editor rather than silently ignored — that is what the namespace buys you. Ordinary@-comments (; @todo,; @param) are never touched.
Excluding lines from coverage
Two directives keep lines out of a coverage
report. Excluded lines leave both sides of the ratio — they are not counted
as covered, and not counted at all — so the percentage reflects only the lines
you meant to measure.
@nessemble-coverage-ignore-next-line excludes the next significant line;
blank and comment lines in between are skipped, so an explanation can follow the
directive:
; @nessemble-coverage-ignore-next-line
; only reachable from a mapper IRQ we can't trigger in CI
JMP nmi_stub
@nessemble-coverage-ignore start … end excludes a whole region:
; @nessemble-coverage-ignore start
mapper3_init:
LDA #$00
STA mapper_reg
; @nessemble-coverage-ignore end
- An unclosed region runs to the end of the file — put a lone
; @nessemble-coverage-ignore startin the header to opt a whole file out. A file with nothing left to report is dropped from the report entirely (noSF:record) and counted as an ignored file. - Regions are per file: one does not extend into an
.included file, and each included file carries its own directives. - Regions do not nest. A
startinside an open region, or anendwith nostart, does nothing and is reported bylint. - Rhai scripts (under
--scripts) honor both directives, written as//comments. nessemble coverage --no-ignorereports every line regardless — useful in CI, or to see what the directives are hiding. The stdout summary always names how much was excluded, and the JSON report carriesignored/ignoredFilescounts.
Documenting routines
The 6502 has no calling convention: every routine invents its own, and the only record of it is usually a comment, if that. Three directives write that convention down where the tools can read it — which registers a routine takes, what it hands back, and what it destroys:
; Draw one metasprite from `metasprite_table` into the OAM shadow buffer.
;
; @nessemble-param A metasprite index into `metasprite_table`
; @nessemble-param X screen x, in pixels
; @nessemble-param Y screen y, in pixels
; @nessemble-returns C set when the sprite was clipped off-screen
; @nessemble-clobbers A, X, Y, [oam_cursor]
draw_metasprite:
...
RTS
Hovering any use of draw_metasprite — including the operand of a JSR,
in this file or another open one — shows that table, so "does this call eat my
Y?" is answered without leaving the call site.
Slots. A slot is a place a value lives across a call. The vocabulary is closed, so a typo is reported rather than silently accepted:
| Slot | Meaning |
|---|---|
A, X, Y | the registers |
S | the stack pointer |
P | the whole status register |
C, Z, N, V, D, I | one flag — @nessemble-returns C is how a 6502 routine returns a boolean |
[symbol] | a named memory location, e.g. [oam_cursor] |
$NN, $NNNN, $NN-$NN | an address or inclusive range, e.g. $10-$1F |
none | (clobbers only) preserves everything |
Slot names are case-insensitive (a and A both work) and always render
upper-case. Memory needs its brackets or its $: that is what lets
@nessemble-clobbers AX be reported as a bad slot instead of quietly becoming a
symbol named AX.
What the tags mean.
@nessemble-paramand@nessemble-returnstake one slot each, followed by a free-text description (a;in it is part of the description). Repeat the tag for each slot.@nessemble-clobberstakes a list, and means anything not listed is preserved. A returned slot is clobbered by definition and need not be repeated.@nessemble-clobbers noneclaims the routine preserves everything. That is different from writing no@nessemble-clobbersat all, which claims nothing.- Annotations bind to the first label below them; blank lines and prose comments in between are skipped, so a summary can sit above the tags. A line of code in between binds them to nothing, and is reported.
The declaration is checked. nessemble lint compares each declared clobber
list against what the routine actually writes:
src/prg/sprite.asm
42:1 warning routine `draw_metasprite` writes Y but does not declare it clobbered undeclared-clobber
- Only
A,X,Y, andSare verified. Flags are documentation — nearly every instruction disturbsN/Z, so checking them would flag everything. Memory slots are documentation too. - Only routines that declared a clobber list are checked, so a project adopts this one routine at a time.
- A routine's body runs from its label to the next block-opening label. A call to
another annotated routine contributes that routine's declared clobbers; a
call to an unannotated one, a macro invocation, an indirect jump, or a data run
inside the body makes the body "not fully understood", which silences
overdeclared-clobberbut neverundeclared-clobber. - A routine that falls through into the next one is under-reported rather than
over-reported: the analysis prefers a missed warning to a wrong one. Where that
costs a wrong finding — a fall-through entry point, or a
PHA/PLApair the analysis does not model — suppress it at the site with@nessemble-lint-ignore…and keep the annotation truthful. - The stack pointer counts as clobbered only for
TXS. Pushes and pulls moveS, but routines balance them.
.nessemblerc
Formatting is configurable, Prettier-style, via an optional .nessemblerc (or
.nessemblerc.json) file discovered by walking up from the file or directory
being formatted. It is JSON; every key is optional and takes the default shown
below, so a project with no .nessemblerc still gets fully-formatted output.
Unknown keys are rejected (to catch typos early).
{
"extensions": [".asm"],
"indentStyle": "space",
"indentWidth": 4,
"commaSpacing": true,
"finalNewline": true,
"indentDirectives": false,
"alignContinuations": true,
"dataPerLine": 8,
"respectStrideHints": true,
"blankLineAfterReturn": true,
"maxConsecutiveBlankLines": 2,
"mnemonicCase": "preserve",
"hexDigitCase": "preserve",
"overrides": []
}
| Key | Default | Meaning |
|---|---|---|
extensions | [".asm"] | File extensions formatted during a directory walk. |
indentStyle | "space" | Instruction indent: "space" or "tab". |
indentWidth | 4 | Spaces per indent level (space style only). |
commaSpacing | true | ", " between values; false for tight commas. |
finalNewline | true | Ensure the file ends in exactly one newline. |
indentDirectives | false | Indent directive lines (.db, .dw, .include, …) to block depth like instructions. false pins them to column 0 (house style); true suits codebases that indent data under labels. Labels and constants stay at column 0 either way. |
alignContinuations | true | Align the continuation lines of a multi-line statement (operands wrapped onto the next line by a trailing comma) under the opening line's first argument. false indents them to the block indent (indentWidth). See below. |
dataPerLine | 8 | Values per consolidated .db/.dw/.color line; 0 disables consolidation. |
respectStrideHints | true | Honor ; @fmt stride=N[,N,...] comments (see below). |
blankLineAfterReturn | true | Insert one blank line after every RTS/RTI. |
maxConsecutiveBlankLines | 2 | Collapse longer runs of blank lines down to this. |
mnemonicCase | "preserve" | Case the instruction mnemonic: "preserve", "lower", or "upper". |
hexDigitCase | "preserve" | Case hex-digit letters ($ab vs $AB): "preserve", "lower", or "upper". |
overrides | [] | Per-glob option overrides (see below). |
Directive names (.db, .DB) are never re-cased — nessemble is case-sensitive
about them.
Stride hints
To override dataPerLine for one data block, place a
; @nessemble-format stride=N comment directive
before it. Multiple strides cycle in order and the last one repeats:
; @nessemble-format stride=2
.db $01, $02
.db $03, $04
The hint binds to the next data run, skipping blank lines, comment lines, and label or constant definitions on the way — the run's own label and an explanatory comment are both transparent:
; @nessemble-format stride=3
; one row of the tile per line
palette_rows:
.db $01, $02, $03
.db $04, $05, $06
If the first thing that is not one of those is anything but a .db/.dw/
.color line, the hint applies to nothing and
lint reports it as ineffective-comment-directive.
format and lint resolve the target the same way, so a hint the formatter
honors is exactly a hint the linter calls effective.
Deprecated spelling. The original
; @fmt stride=Nstill works and always will — it is an alias, not a removal. It is reported by thedeprecated-comment-directiverule, and the editor offers a one-click rename. To migrate a tree in bulk:grep -rl '@fmt' --include='*.asm' . | xargs sed -i 's/@fmt/@nessemble-format/g'
Continuation alignment
When a statement's operand list wraps onto further lines (a trailing comma
continues it onto the next physical line), alignContinuations (on by default)
lines up each continuation under the opening line's first argument:
.metasprite $FA, $02, $00, $FA,
$FA, $03, $00, $02,
$02, $0D, $00, $FA
With alignContinuations: false, continuation lines fall to the block indent
instead:
.metasprite $FA, $02, $00, $FA,
$FA, $03, $00, $02,
$02, $0D, $00, $FA
The alignment is computed from the opening line's actual indent, so it stays
correct together with indentDirectives. Under indentStyle: "tab" the
continuation reuses the opening line's leading tab and then pads to the
first-argument column with spaces. Only leading whitespace changes, so the
assembled output is unaffected.
Overrides
overrides is an ordered list of { "files": <glob>, "options": { … } }
entries; for each formatted file, later matching entries layer their options on
top of the base config. Globs support *, **, and ?.
{
"dataPerLine": 8,
"overrides": [
{ "files": "src/data/**/*.asm", "options": { "dataPerLine": 16 } }
]
}
.nessembleignore
A .nessembleignore file (gitignore-style globs, one per line) excludes matching
paths from directory walks. It is discovered the same way as .nessemblerc.
lint
The lint subcommand is configured under a lint key in the
same .nessemblerc. With no config the linter is on with its defaults (every
rule at "warn" except require-routine-doc, which is "off"; a comment window
of 3; and no ignores), so nessemble lint is useful out of the box.
{
"lint": {
"rules": {
"require-block-comment": ["warn", { "window": 3 }],
"unknown-comment-directive": "error",
"deprecated-comment-directive": "off",
"require-routine-doc": "warn"
},
"ignore": ["^loc_[0-9A-Fa-f]", "^data_[0-9A-Fa-f]"]
}
}
| Key | Default | Meaning |
|---|---|---|
rules | {} | Per-rule severity. Each value is "off", "warn", or "error", or a [severity, { …options }] pair. Unknown rule names are rejected. |
ignore | [] | Regexes matched against a label's name; a match exempts it from every rule. Anchors (^) are yours to add. |
Severity. A rule at "off" is not run. An "error" finding fails the run
(non-zero exit); a "warn" finding does not, unless the CLI's --max-warnings
is exceeded. In the editor, findings appear at a gentle severity (Information for
error, Hint for warn) with the nessemble-lint source, distinct from the
assembler's own errors and warnings.
Rule options. require-block-comment takes a window (default 3): a block
label is clean if any line within ±window lines carries a comment. The
directive and routine-signature rules take no options.
Ignore patterns. List the name shapes that should never be flagged — most
often machine-generated disassembly labels (loc_8000:, data_c123:). No
patterns ship by default, so a fresh project flags every undocumented block until
you opt specific shapes out. (Ignore patterns match label names, so they do not
affect the comment-directive rules; silence those with a
severity of "off". They do apply to the routine rules, which are keyed by the
routine's label name.)
Per-glob overrides may carry a lint block too, so a data-heavy
directory can loosen or disable a rule for its files:
{
"overrides": [
{ "files": "src/data/**/*.asm",
"options": { "lint": { "rules": { "require-block-comment": "off" } } } }
]
}