dream-ini
dream-ini imports settings from Morrowind.ini into an openmw.cfg-style file. It is a standalone Rust importer compatible with OpenMW's Morrowind.ini import needs, with deliberate UX improvements over the original C++ tool.
Build
Desktop builds use the default feature set, which includes the native GUI and the CLI:
Release platform support is intentionally split by build shape:
| Platform | Release build shape | Availability |
|---|---|---|
| Linux x64, Windows x64, macOS x64/ARM64 | default features | Desktop GUI and CLI |
| PortMaster ARM64 | --no-default-features --features portmaster-gui |
Framebuffer GUI and CLI |
| Android ARM64 | --no-default-features |
CLI/importer only |
Other targets may build the library or CLI, but GUI, launcher installation, and controller support are only promised for the platform rows above.
Usage
--ini is required for imports. By default, the imported cfg text is written to stdout and diagnostics go to stderr, so shell redirection is safe. Use --output to write a separate cfg file or --in-place with --cfg to update the base cfg. If --cfg is provided, it is read first and intentionally imported keys are replaced. In-place and same-directory output preserve unrelated comments, entries, chain controls, and relative/token path spelling through openmw-config's preservation-oriented serializer. Relocated --cfg + --output writes a resolved export so relative paths do not silently change meaning. If --cfg is omitted, import starts from an empty config.
Import paths are flag-based. Positional Morrowind.ini or openmw.cfg arguments are intentionally unsupported; use --ini, optional --cfg, and optional --output or --in-place.
GUI
When built with the default gui feature, running dream-ini with no arguments opens the desktop graphical importer in a native window. The GUI uses the same explicit import model as the CLI: choose Morrowind.ini, optionally choose an existing openmw.cfg, pick import options, then either preview, save as a separate cfg, or update the existing cfg.
PortMaster builds use the separate portmaster-gui feature with default features disabled. That build draws the same importer UI directly to the Linux framebuffer instead of using desktop windowing. Clipboard support is unavailable in the PortMaster shell. Diagnostic logs, when enabled by the launcher or environment, are written by the launcher/script beside the executable or to the configured log path.
Controller navigation is available in the desktop GUI on Linux, Windows, and macOS, and in the PortMaster framebuffer GUI:
- D-pad or left stick: move between fields, picker entries, and result tabs.
- A / South: activate the selected field, toggle checkboxes, open directories, or choose files.
- B / East or Select: cancel the picker; on the main form it exits the GUI.
- X / West: clear the selected path field.
- Start: import from the main form, or choose the current/expected picker path.
- Left / Right: adjust options; in the picker, Left enters the parent directory and Right enters the selected directory or chooses the selected file.
- LB / left shoulder: toggle hidden directories in the picker. This is useful for OpenMW paths under
~/.config/openmwor~/.local/share/openmw. - RB / right shoulder: page down through the generated cfg preview.
- Right stick: scroll the generated cfg preview vertically and horizontally.
On desktop Linux and PortMaster, controller support reads /dev/input event devices directly. If your desktop session does not grant read permission for those devices, the GUI will still run but controller navigation will not appear. Windows and macOS use gilrs for controller input. PortMaster uses the Linux controller backend with a handheld-specific menu/trigger remap for Anbernic-style evdev button codes; the on-screen help shows the behavior used by that build.
Path reminder: Data Files directory is the Morrowind content/archive search path used during import. Classic Morrowind usually points at one Data Files folder; OpenMW can later use many data= directories. data-local, resources, and user-data are OpenMW cfg singleton outputs; they are not used as importer search paths.
Options
-c, --cfg <FILE>: optional openmw.cfg input/base path. It is only overwritten when--in-placeis supplied.-d, --data <DIR>: explicit Data Files directory searched before cfg/default data paths. Relative paths are resolved from the output cfg directory, from--cfgfor stdout preview, or from the current directory and written absolute when stdout has no cfg context.-l, --data-local <DIR>: set the singletondata-localcfg key, replacing any existing value. The value is written as supplied and is not used as an importer search path.-e, --encoding <ENCODING>: character encoding for imported content-file names;win1250,win1251, orwin1252.-f, --fonts: import bitmap font fallback settings.-g, --game-files: import.esmand.espcontent files.-h, --help: print help.-i, --ini <FILE>: Morrowind.ini input path.-n, --no-archives: disable BSA archive import.-r, --resources <DIR>: set the singletonresourcescfg key, replacing any existing value. The value is written as supplied.-u, --user-data <DIR>: set the singletonuser-datacfg key, replacing any existing value. The value is written as supplied; this is OpenMW's saves/screenshots/navmesh-cache location, not a mod data directory.-v, --verbose: print content-file timestamp messages during--game-filesimport.-C, --generate-completion <SHELL>: write a completion script forbash,zsh,fish,powershell, orelvishto stdout.-w, --in-place: update--cfgin place. Requires--cfgand conflicts with--output.-M, --generate-manpage: write a roff manpage to stdout.-o, --output <FILE>: output cfg path.-V, --version: print version information.
Commands
install-launcher: install a desktop launcher and icon for the current user. This is intended for Linux and Windows desktop builds. On Linux this writes a.desktopfile and hicolor PNG icon to$XDG_DATA_HOMEwhen it is absolute, otherwise to~/.local/share. On Windows this writes a Start Menu shortcut and.icoicon under%APPDATA%. Non-Linux/non-Windows targets, including macOS and Android, return an unsupported-platform error. PortMaster is a Linux build, but launcher installation is not part of the supported PortMaster release flow.
Behavior
- Existing cfg output is updated through
openmw-config's preservation-oriented serialization when the output remains in the same cfg directory. Comments, unrelated entries, and relative/token path spelling are preserved unless a key is intentionally replaced by the import. - Existing cfg output written to a different directory uses resolved flattened serialization so relative paths keep their resolved meaning instead of becoming relative to the new output directory.
- Output generated without
--cfgis newopenmw.cfgtext built from imported/authored values. It has no source comments or formatting to preserve. - When no
--outputor--in-placemode is selected, cfg text is written to stdout. Diagnostics are written to stderr in stdout mode. - Missing cfg files are treated as empty configs and are not created unless they are also the
--outputpath or--in-placetarget. - Omitting cfg starts from an empty config.
- Missing INI files fail with shell exit code
253, matching the C++ importer'sreturn -3behavior. - Existing cfg entries are preserved unless replaced by imported keys such as
encoding,no-sound,fallback,fallback-archive, orcontent, or by explicit singleton path options such as--data-local,--resources, and--user-data. - Content-file and fallback-archive import searches explicit
--datapaths first, then existingdatacfg paths, then<Morrowind.ini parent>/Data Filesas a fallback.data-localis OpenMW's highest-precedence runtime data directory, but this importer treats it as an output-only singleton rather than a Morrowind.ini content/archive source. Every.esm/.espand.bsaentry imported from the INI must be found or the import fails. Any used explicit or fallback data directory is written asdata=...if an equivalentdataentry is not already present. - Relative
--datawith--output,--cfg, or--in-placeis interpreted relative to that cfg context and written as supplied. Relative--datawith stdout and no--cfgis interpreted relative to the current directory and written as an absolute path. - Explicit singleton options (
--data-local,--resources, and--user-data) are output-only and are applied after content/archive resolution. Use--datato add an importer search path. - Directory-valued keys read from an existing cfg are interpreted by
openmw-configfor filesystem lookup. Their authored spelling is not rewritten for normal cfg output. - Config, Lua, and event path values are UTF-8 text. Non-UTF-8 operating-system paths are outside the supported API contract and may be represented lossy when converted for cfg/Lua output.
Deliberate Differences From OpenMW's C++ Importer
- Warnings are written to stderr instead of stdout.
- Game-file import requires filenames ending in
.esmor.esp; the C++ importer accepts any suffix ending inesmoresp. - Unreadable input files are reported as errors instead of silently importing from an empty stream.
- Game-file timestamp sorting uses Rust's full
SystemTimeprecision instead of C++time_tseconds. --verbosegates content-file timestamp messages. The C++ importer accepts--verbosebut prints those messages unconditionally during game-file import.
Lua API
Enable the optional Lua embedding API with the lua feature. It uses mlua with vendored LuaJIT 2.1 in Lua 5.2 compatibility mode.
The crate does not build a Lua require module or cdylib. Lua support is embedding-only; embedders create or register the API table explicitly:
let lua = new;
let module = create_module?;
lua.globals.set?;
Lua usage:
local result = dream_ini.
print
for _, warning in ipairs
for _, event in ipairs
For import_paths, relative data_dirs are resolved from the cfg file's directory when cfg is supplied. cfg_dir is primarily for import_maps, where there is no cfg path to provide that context; for import_paths without cfg, cfg_dir supplies the cfg context.
Available functions:
parse_ini(text, opts): parses a Morrowind INI byte string and returns{ entries = multimap, warnings = { ... } }.parse_cfg(text): parses OpenMW cfg text and returns a multimap.serialize_cfg(multimap): serializes a multimap to normalized cfg text.import_maps(cfg, ini, opts): imports parsed multimap data and returns{ cfg = multimap, text = string, warnings = { ... }, events = { ... } }.import_paths(opts): imports fromopts.iniand optionalopts.cfg, returning the same result shape asimport_maps.
Warnings are returned in the warnings array. Hard failures such as missing required options, unsupported encodings, malformed multimap input, missing files, or failed imports are raised as Lua errors.
Import events are structured tables. Current event kinds are:
{ kind = "content_file_resolved", path = string, modified = unix_seconds }{ kind = "data_dir_added_for_content", path = string }{ kind = "archive_resolved", path = string }{ kind = "data_dir_added_for_archive", path = string }
Import warnings are structured tables with a formatted message. Current warning kinds are:
{ kind = "ignored_empty_value", key = string, message = string }{ kind = "malformed_ini_line", line = string, message = string }
Multimaps are represented as key -> array of strings to preserve duplicate keys:
Rust API
Generate crate documentation with:
The library exposes the same multimap model used by the CLI and Lua API. Start with IniImporter, ImportOptions, ImportEvent, ImportWarning, parse_cfg_str, parse_ini_bytes_with_warnings, and serialize_cfg. Path values serialized into cfg text, Lua tables, or import events are UTF-8 strings.
Development
Lua feature checks:
The Criterion benchmark measures a large synthetic parse/import/serialize round trip. It does not include plugin header IO from --game-files. Use cargo bench --no-run to verify the benchmark builds without running measurements.
License
dream-ini is licensed under GPL-3.0-only.