A smart Neovim plugin for Super Factory Manager Language (.sfml / .sfm files).
Built from the actual mod source code (1.21.1 branch SFML.g4 + linter Java sources) — not from the VSCode extension.
- Syntax highlighting — full keyword coverage, resource IDs, strings, comments, numbers, operators
- Static linting (
:SFMLLint) — mirrors the mod's ownIProgramLintersuite:EACHused without a wildcard pattern → warningROUND ROBIN BY BLOCK+EACHtogether → warningROUND ROBIN BY LABELwith only 1 label → warning- OUTPUT resource type with no matching INPUT → warning
- INPUT resource type with no matching OUTPUT → warning
EVERY TICK DOwith non-energy resources → error- Timer interval below minimum → error
- Unknown resource type prefix → warning
- Label names exceeding 256 characters → error
- Unclosed
DO/END/IF/ENDblocks → error - INPUT forgotten (via
FORGET) without being OUTPUT'd → warning
- Live diagnostics — lints on every text change (debounced 400ms) and on save
- Completions (via
nvim-cmpor built-inomnifunc):- All keywords with context-awareness
- Resource type prefixes (
item::,fluid::,forge_energy::,fe::, etc.) - Label names collected from the current buffer
- Snippet-style insertion for
EVERY...DO...END,IF...THEN...END
- Folding —
EVERY...ENDandIF...ENDblocks fold naturally - Indentation — 4-space, auto-configured
- Formatter (
:SFMLFormat) — normalizes all keywords to uppercase, preserves resource IDs and strings
- Neovim ≥ 0.8
- Optional: nvim-cmp for completion integration
-- lazy.nvim
{
dir = "~/path/to/nvim-sfml",
ft = { "sfml", "sfm" },
config = function()
require("sfml").setup({
-- All options are optional
auto_lint = true, -- live lint on change
lint_delay_ms = 400, -- debounce ms
format_on_save = false, -- auto-uppercase keywords on write
register_cmp = true, -- register nvim-cmp source
})
end,
}If using nvim-cmp, add "sfml" to your sources:
require("cmp").setup({
sources = {
{ name = "sfml" },
-- ... your other sources
},
})| Command | Description |
|---|---|
:SFMLLint |
Run linter and populate quickfix list |
:SFMLFormat |
Normalize all keywords to uppercase |
| SFML syntax | Aliases |
|---|---|
item:: |
(default, implicit) |
fluid:: |
— |
forge_energy:: |
fe::, rf::, energy::, power:: |
chemical:: |
gas::, infusion:: |
mekanism_energy:: |
— |
redstone:: |
— |
- Keywords are case-insensitive (formatter normalizes to uppercase)
- Resource IDs use
*as a glob wildcard (converted to.*regex internally) ::suffix means "match all of this type" (e.g.,fluid::= all fluids)fluid::minecraft:water= specific fluid with namespace- Labels can be bare identifiers or quoted strings
- Labels named
TOP,BOTTOM,LEFT,RIGHT,FRONT,BACK,REDSTONE,GLOBAL,SECOND,SECONDSare valid (included in the grammar'sidentifierrule) FORGETwith no labels forgets all tracked labelsEVERY TICK DOonly allowsforge_energy/mekanism_energyresource types- Both
INPUT x FROM labelandFROM label INPUT xforms are valid - Both
OUTPUT x TO labelandTO label OUTPUT xforms are valid