Changelog
All notable changes to the Ion language and its tooling are recorded here.
Format follows Keep a Changelog; the
project follows SemVer for the published crates
(ion-derive, ion-core, ionrs-cli, ion-lsp).
Editor extensions track their own version numbers under each entry.
[0.9.6] — 2026-05-06
Section titled “[0.9.6] — 2026-05-06”- Prevented release builds from eagerly constructing dynamic Ion error detail
strings before redaction by routing runtime/compiler/parser/stdlib error
formatting through the release-safe
ion_format!facade. - Redacted rewrite malformed-binding detail with
redacted_error::detail!so release builds do not retain binding names solely for diagnostics. - Stripped release binary symbols by default to avoid publishing symbol-table strings in normal release artifacts.
- Added a release-mode guard that verifies
ion_format!does not evaluate its format arguments in release builds.
[0.9.5] — 2026-05-06
Section titled “[0.9.5] — 2026-05-06”- Added
llms.txtwith AI-agent notes for host integration, including theHostSignatureregistration path and the preference for named arguments over fixed-shape option dictionaries. - Added
VM_AUDIT.mdwith verified VM correctness, soundness, performance, and architecture findings plus post-fix verification notes.
- Isolated VM exception handlers by function frame so
tryhandlers from a returning callee cannot catch later caller errors with stale chunk offsets. - Prevented bytecode operand truncation for large calls and other u8-count operands; large normal calls now lower through resolved-call bytecode when needed.
- Replaced unchecked integer arithmetic in the VM, tree-walk interpreter, async
continuation scaffold, and constant folding with checked behavior that
reports
integer overflow. - Normalized reverse and inclusive slice bounds for list, string, and bytes
syntax and
.slice()methods, including saturated inclusive ends ati64::MAX. - Rejected negative string repeat counts across VM, tree-walk, and async runtime paths instead of panicking.
- Discarded
break valueresults from statement loops while preserving loop expression break values, preventing orphaned stack values on loop exit.
[0.9.4] — 2026-05-05
Section titled “[0.9.4] — 2026-05-05”Changed
Section titled “Changed”- Reworked Rust error handling to follow the workspace redaction guideline:
debug builds keep diagnostic detail, while release
DisplayandDebugoutput use stable public messages. - Moved the Rust error-handling guide to
docs/error-handling.mdand updated the design docs to describe release redaction and compile-time name hiding. - Replaced direct string-obfuscation plumbing with the
redacted-errorfacade built without its optional obfuscation backend.
- Prevented release-facing CLI, LSP, stdio, MessagePack, semver, filesystem, async runtime, host conversion, and rewrite error paths from exposing raw paths, OS errors, host names, type names, or other runtime detail.
Removed
Section titled “Removed”- Removed the legacy string-obfuscation cargo feature and direct
string-obfuscation dependency from
ion-core.
[0.9.3] — 2026-05-05
Section titled “[0.9.3] — 2026-05-05”- Python-style argument resolution for Ion and host callables:
*args,**kwargs,*expr,**expr, positional-only/, and keyword-only*. - Signature-aware host registration APIs:
Engine::{register_fn_sig, register_closure_sig, register_async_fn_sig}and matchingModule::*_sigvariants.
Changed
Section titled “Changed”- Keyword calls to legacy unsigned host callables now error instead of dropping keyword names path-dependently.
- Extra positional arguments and duplicate positional/keyword bindings now error consistently across tree-walk, VM, and async-runtime paths.
- Duplicate Ion parameter names are now rejected at parse time.
- VM call handling now includes
CallResolved,TailCallNamed,TailCallResolved,MethodCallResolved,SpawnCallResolved,KwInsert, andKwMergefor named and spread-containing calls.
- Method calls now expand
*exprlist spreads consistently across tree-walk, VM, and async-runtime paths, while rejecting keyword arguments before method dispatch. - Named and spread tail calls now preserve VM tail-call optimization.
- External
EngineHandle::call_asynccallbacks into signed host callables now apply signature defaults and slot resolution.
[0.9.2] — 2026-05-05
Section titled “[0.9.2] — 2026-05-05”This release expands the standard library around binary data, randomness, and
file-padding workflows, and publishes the public crates in lockstep:
ion-derive, ion-core, ionrs-cli, and ion-lsp.
bytes::stdlib module with constructors and helpers for binary data:new,zeroed,repeat,from_list,from_str,from_hex,from_base64,concat, andjoin.- Endian byte helpers on both bytes values and the
bytes::module:read_u16_le/read_u16_be,read_u32_le/read_u32_be,read_u64_le/read_u64_be, signedread_i*variants, and packing helpersbytes::u16_*,bytes::u32_*,bytes::u64_*,bytes::i16_*,bytes::i32_*, andbytes::i64_*. rand::stdlib module withint,float,bool,bytes,choice,shuffle, andsample. Bounded numeric helpers use half-open ranges;choicereturnsNonefor empty inputs;samplesamples without replacement.- Random file helpers in
fs:::fs::append_random(path, count) -> intandfs::pad_random(path, target_size) -> int. Both stream random bytes in bounded chunks and are available in sync andasync-runtimebuilds.
Changed
Section titled “Changed”- The embedded stdlib documentation manifest now includes the
bytes::,rand::, and newfs::helper entries for editor completion and hover surfaces. - Language and stdlib reference docs now cover the new binary, random, and file-padding APIs.
- Test documentation was refreshed to match current default and async-runtime suite sizes.
[0.9.0] — 2026-05-03
Section titled “[0.9.0] — 2026-05-03”This release implements host-name hiding: every host-registered identifier
(enum names, variant names, struct/field names, module names, function names,
qualified mod::fn paths) is folded to a 64-bit FNV-1a hash at compile time
and never appears in the release binary’s .rodata. See
docs/hide-names.md.
strings target/release/host_bin now reveals zero Ion-level identifiers
from registered types or stdlib functions.
This is a major breaking-change release for embedders. Any host that
calls Engine::register_fn, Engine::register_module, Module::new,
Module::register_*, Module::set, or constructs HostStructDef /
HostEnumDef directly will need to migrate. Scripts themselves do not
change. Test counts: 1100+ across default, async-runtime, and
legacy-threaded-concurrency feature combinations.
Changed (breaking)
Section titled “Changed (breaking)”- Module / Engine registration APIs take
u64name hashes instead of&str. Use the newion_core::h!("name")macro (compile-time FNV-1a) at the call site:The literal// beforeengine.register_fn("square", |args| { ... });let mut math = Module::new("math");math.register_fn("add", |args| { ... });math.set("PI", Value::Float(std::f64::consts::PI));// afteruse ion_core::h;engine.register_fn(h!("square"), |args| { ... });let mut math = Module::new(h!("math"));math.register_fn(h!("add"), |args| { ... });math.set(h!("PI"), Value::Float(std::f64::consts::PI));"square"/"math"/"add"/"PI"is consumed byh!()’s const evaluation at compile time and folded to au64. No string survives in the release binary. (Module::register_fn,register_closure,register_async_fn,set;Engine::register_fn,register_closure,register_async_fn.) Value::HostEnum,Value::HostStruct,Value::BuiltinFn,Value::BuiltinClosure,Value::AsyncBuiltinClosurereshaped to carry only u64 hashes — no name strings:// beforeValue::HostEnum { enum_name: String, variant: String, data: Vec<Value> }Value::HostStruct { type_name: String, fields: IndexMap<String, Value> }Value::BuiltinFn(String, BuiltinFn)// afterValue::HostEnum { enum_hash: u64, variant_hash: u64, data: Vec<Value> }Value::HostStruct { type_hash: u64, fields: IndexMap<u64, Value> }Value::BuiltinFn { qualified_hash: u64, func: BuiltinFn }Value::BuiltinFnshrinks from ~32 bytes to 16 bytes and saves aString::cloneper construction.HostStructDef,HostEnumDef,HostVariantDefcarry hashes:name: String→name_hash: u64;HostStructDef.fields: Vec<String>→Vec<u64>. Useh!("Color")etc. at construction.Value::Module(Arc<ModuleTable>)is a new variant distinct fromValue::Dict. Modules registered throughEngine::register_moduleproduceValue::Module;Value::Dictremains for script-side user-built dicts.mod::fnanduse mod::*now hit the typed module path; the legacyValue::Dict-as-module behaviour still works for back-compat with hosts that injected dicts directly.Module::to_value→Module::into_value, returningValue::Module(Arc<ModuleTable>)directly.Module::namefield removed; useModule::name_hash().#[derive(IonType)]emitsu64literals instead ofname.to_string(). Field names, variant names, and the type name are hashed at proc-macro expansion; the source identifier never reaches the generatedTokenStream. Generatedto_ionandion_type_defalso include acfg(debug_assertions)block that registers the hashes back to their source-form names withion_core::names, so Display and diagnostic output render readably in dev builds.TypeRegistry::construct_structnow takesIndexMap<u64, Value>(pre-hashed field names); callers (interpreter, VM, async runtime) hash script-source identifiers at the boundary.- JSON / MessagePack output of
Value::HostEnum/Value::HostStructchanges: field/variant keys come from the optionalnamesregistry when populated; otherwise hex-formatted hashes ("#0123456789abcdef") are emitted. Round-trips losslessly within the same registry.
ion_core::hashmodule withconst fn fnv1a64(matches canonical FNV-1a test vectors),const fn h(&str) -> u64,const fn mix(u64, u64) -> u64, plush!()andqh!()macros that fold their inputs to compile-timeu64constants.ion_core::namesmodule — optional runtime hash → name mapping used byDisplay,to_json, and error rendering. Populated three ways:- Debug builds (
cfg(debug_assertions)): everyh!()andqh!()site auto-registers its source literal exactly once on first execution. Tests, dev binaries, andcargo runall see readable names with no extra setup. - Release builds: empty by default. Hosts can call
names::register/register_many, or load a sidecar JSON withnames::load_sidecar_json. - Sidecar workflow: a build script can call
names::dump_sidecar_jsonon a fully-populated debug build to emitmyapp.names, which the release host loads at startup.
- Debug builds (
embedded-stdlib-docscargo feature onion-core. Gates theSTDLIB_DOCS_JSONconstant (theionDocManifestfor stdlib hover / completion / docs-site rendering). Off by default — release embedders who don’t ship a docs surface skip the JSON blob entirely.ion-lspenables it.Module::new(u64),register_fn(u64, fn),register_closure(u64, fn),register_async_fn(u64, fn),set(u64, value),register_submodule(Module),into_value() -> Value,name_hash() -> u64,name_hashes() -> Vec<u64>— the hash-only builder API.Env::define_h(u64, Value),get_h(u64) -> Option<&Value>,get_sym_or_global(Symbol) -> Option<&Value>for host-registered globals that bypass theStringPool.- Hash collision detection:
Module::register_fnand friends panic on duplicate insertion at startup.TypeRegistry::register_struct/register_enumpanic on real shape mismatch (different fields or variants under the same name hash) but are idempotent on identical re-registrations.
Removed
Section titled “Removed”Module::name: Stringfield — replaced byname_hash().Module::names() -> Vec<String>— replaced byname_hashes() -> Vec<u64>.- String-taking
register_fn(&str, …)/set(&str, …)overloads onModuleandEngine. These would have leaked the literal into.rodata; they are removed outright (no shim).
Additional hardening (release builds only)
Section titled “Additional hardening (release builds only)”ion_str!/ion_static_str!macros are gated oncfg(debug_assertions). Release builds replace every diagnostic literal with the generic placeholder"runtime error"/"value". Combined with themod::fnstrip above, this meansstrings target/release/host_binshows none of the stdlib’s human-readable error text either — only the generic placeholders.- Derive-emitted error messages are
cfg-split. Debug builds format"expected Player, got …"; release builds format"expected host struct #abcd…, got …", dropping the literal type name from.rodata. Module::register_*lazily registers the qualified name inion_core::nameswhen both the module and item names are individually known, so debug builds get readable<builtin math::abs>Display without an extraqh!()site.
Performance side-effects
Section titled “Performance side-effects”Value::BuiltinFnshrunk from(String, BuiltinFn)≈ 32 bytes to{ u64, BuiltinFn }= 16 bytes; lists/dicts of builtins benefit.- Builtin registration cost dropped: no
format!("{}::{}", …)and noString::cloneper fn — it’s aVec::pushof an integer-keyed slot. - Stdlib error message strings stripped of
mod::fnqualifiers; helper functions (semver_parse_arg,fs_arg_str,arg_str,io_err) refactored to dropfn_nameparameters. Generic error strings dedup across the whole stdlib. - The aggressive bytecode-level dispatch reshape (u64 operands inline in
bytecode, new
GetModuleSlotop) is deferred as a follow-up.mod::fncalls still hash the script-source string at runtime in the VM. Hiding goal is unaffected.
Trade-offs
Section titled “Trade-offs”- Diagnostic context: stdlib closures emit generic errors
(
"takes 1 argument","requires a number") — themod::fnprefix no longer appears in the error string. The script source span (line:col) identifies the call site. The renderer can re-prepend the resolved name fromnames::lookup(qualified_hash)if an embedder wants it. Preserves runtime semantics oftry { … } catch e { e }. - Module reflection:
use mod::*now binds entries by hash on the glob path. Scripts that introspect modules via dictionary iteration break (DESIGN.md does not promise this surface).
Editor extensions
Section titled “Editor extensions”zed-ionbumped to0.9.0for parity with the language version.
Documentation
Section titled “Documentation”README.mdcode samples updated to theh!()form.docs/embedding.mdupdated with the new registration APIs and a section on thenamessidecar workflow.docs/hide-names.mdadded as the concise reference for the shipped host-name hiding behavior.
[0.8.0] — 2026-05-03
Section titled “[0.8.0] — 2026-05-03”- Canonical stdlib doc manifest in
ion-core. Newion_core::STDLIB_DOCS_JSONconstant — a completeIonDocManifest(schema v2) describing every global builtin, built-in type, type-method, and stdlib-module function/constant. Embedded viainclude_str!so it ships with every build. Single source of truth for the LSP and the forthcoming documentation site; eliminates drift between editor tooltips and published docs. IonDocManifestschema v2 inion-lsp. Adds member kindsmethod,type, andbuiltin(alongside the existingfunctionandconstant); per-member optionalreceiver,methods,variants,examples, andsincefields; and top-level optionalhomepage,repository,license, andcategoriesfor package metadata. v1 manifests continue to load unchanged. v3+ rejected.ion --check <file|->parse-only mode inionrs-cli. Lex and parse a script (or stdin) without evaluating; exits non-zero with all parse errors on stderr. Used by the docs-site CI to verify.ioncode blocks compile.
Changed
Section titled “Changed”ion-lspDocCatalog::builtins()is now manifest-driven. The hardcodedBUILTINS/METHODS/TYPES/ per-module member tables (~1000 lines) have been replaced by a single call that parsesion_core::STDLIB_DOCS_JSON. Hover, completion, and module overviews see the same data they always did — but adding or fixing a stdlib doc string is now a one-file change.
Editor extensions
Section titled “Editor extensions”- No editor extension changes in this release.
[0.7.7] — 2026-05-03
Section titled “[0.7.7] — 2026-05-03”ion-lspinitialize response no longer double-nestscapabilities. The server passed the fullInitializeResulttoConnection::initialize(), butlsp-serveritself wraps that argument in{ "capabilities": ... }. Strict clients (VS Code) parsedresult.capabilities.hoverProviderasundefined, concluded the server didn’t advertise hover, and never sent a singletextDocument/hoverrequest — hover, completion, and goto-definition all silently no-op’d while the LSP process looked healthy. Switched toinitialize_start/initialize_finishso the result shape is correct.ion-lspdocument symbols passselectionRange ⊆ rangevalidation.def_to_symbolreturned a zero-lengthrange((line, 0)..(line, 0)) alongside aselectionRangethat extended out to(line, col + name_len), causing VS Code to reject every outline entry withselectionRange must be contained in fullRange. Range now spans the full declaration line.- VS Code extension VSIX now bundles
vscode-languageclient.editors/vscode/.vscodeignoreexcludednode_modules/**while the extension was unbundled (tsconly), so the published 9 KB VSIX was missing every runtime dep and crashed on activation withCannot find module 'vscode-languageclient/node'. Highlighting (a static contribution) survived; everything LSP-driven died. Trimmed.vscodeignoreto keep prod deps and added anpm run packagescript that produces the full ~280 KB VSIX.
Editor extensions
Section titled “Editor extensions”- VS Code 0.7.2 → 0.7.7
[0.7.6] — 2026-05-02 (JetBrains extension only)
Section titled “[0.7.6] — 2026-05-02 (JetBrains extension only)”- JetBrains plugin now provides native syntax highlighting for the registered
Ionfile type, restoring colors after.ionstopped being highlighted by TextMate-only association. - Ion LSP startup now logs the resolved command in IDE logs, making attachment issues visible.
Editor extensions
Section titled “Editor extensions”- JetBrains 0.7.5 → 0.7.6
[0.7.5] — 2026-05-02 (JetBrains extension only)
Section titled “[0.7.5] — 2026-05-02 (JetBrains extension only)”- JetBrains plugin now registers
.ionas a nativeIonfile type and maps that file type to LSP4IJ, so the Ion language server attaches reliably in RustRover instead of relying only on TextMate filename matching.
Editor extensions
Section titled “Editor extensions”- JetBrains 0.7.4 → 0.7.5
[0.7.4] — 2026-05-02 (JetBrains extension only)
Section titled “[0.7.4] — 2026-05-02 (JetBrains extension only)”- JetBrains plugin now normalizes custom Windows + WSL
ion-lspcommands through a shell with$HOME/.cargo/binonPATH, fixing LSP startup and hover documentation when users configured commands such aswsl.exe -d Ubuntu --cd /project ion-lsp.
Editor extensions
Section titled “Editor extensions”- JetBrains 0.7.3 → 0.7.4
[0.7.3] — 2026-05-02 (JetBrains extension only)
Section titled “[0.7.3] — 2026-05-02 (JetBrains extension only)”- JetBrains plugin now targets 2024.2+ and uses LSP4IJ 0.14.2, which restores
LSP hover routing for TextMate-backed
.ionfiles in current JetBrains IDEs.
Editor extensions
Section titled “Editor extensions”- JetBrains 0.7.2 → 0.7.3
[0.7.2] — 2026-05-02 (editor extensions only)
Section titled “[0.7.2] — 2026-05-02 (editor extensions only)”- VS Code and JetBrains editor launchers now handle Windows + WSL projects when
spawning
ion-lsp, so hover/completion features work when the server is installed inside the distro. - Zed now honors
[lsp.ion-lsp.binary]settings, detects WSL UNC worktrees, and falls back to an executable$HOME/.cargo/bin/ion-lspwhen Zed’s PATH misses Cargo-installed tools. - Zed extension builds now follow current Zed docs with
zed_extension_api0.7.0, requiring Zed 0.205.x or newer for dev-extension installs.
Editor extensions
Section titled “Editor extensions”- VS Code 0.7.0 → 0.7.2
- Zed 0.7.0 → 0.7.2
- JetBrains 0.7.0 → 0.7.2
[0.7.1] — 2026-05-02 (ion-lsp only)
Section titled “[0.7.1] — 2026-05-02 (ion-lsp only)”- Workspace-provided Ion docs for
ion-lsp— host runtimes can provide.jsondoc manifests for modules such assensor,host,ipc, andwin32without forking editor plugins or hard-coding runtime-specific docs into generic Ion. - Manifests are versioned with
ionDocVersion: 1and load from<workspace>/.ion/ion-docs/*.json,<workspace>/ion-docs/*.json, andION_LSP_DOCSpaths. - External docs support module overview hover, member hover, completion after
module::, nested module completion such assensor::session::, and function/constant completion kinds.
Changed
Section titled “Changed”- LSP hover/completion docs now flow through a shared documentation catalog. Built-in stdlib docs load first; external docs may add modules or override built-in module/member keys.
- Invalid or missing external doc manifests no longer risk crashing the LSP; load failures are reported as diagnostic-safe stderr warnings.
[0.7.0] — 2026-05-02
Section titled “[0.7.0] — 2026-05-02”os::stdlib module — OS / arch detection (os::name,os::arch,os::family,os::pointer_width,os::dll_extension,os::exe_extension), env vars (env_var,has_env_var,env_vars), and process info (cwd,pid,args,temp_dir). Pure-std, no new dependencies. Enabled by default; embedders can opt out withdefault-features = falseonion-core.Engine::set_args/Engine::with_args/Engine::argsto inject script arguments reachable from Ion asos::args(). TheionCLI now passes positional args after the script path through toos::args().path::stdlib module — pure-string path manipulation:sep,join,parent,basename,stem,extension,with_extension,is_absolute,is_relative,components,normalize. No I/O, always-on, no feature gate.fs::stdlib module — filesystem I/O withread,read_bytes,write,append,exists,is_file,is_dir,list_dir,create_dir,create_dir_all,remove_file,remove_dir,remove_dir_all,rename,copy,metadata,canonicalize. Single non-coloured surface — same names in sync and async builds. Newfscargo feature (in default).- LSP hover/completion learn the
os::,path::, andfs::namespaces. - Tree-sitter, VS Code, JetBrains, and Zed grammars recognise
os,path, andfsas builtin module names. ionCLI gains anasync-runtimecargo feature that sets up a current-thread Tokio runtime and drivesEngine::eval_asyncfor bothrun_fileand the REPL.
Changed
Section titled “Changed”io::print*no longer blocks the executor underasync-runtime. Theio::module is now registered with async builtins that dispatch the underlyingOutputHandler::writecall onto Tokio’s blocking thread pool viaspawn_blocking. Sync builds keep the old direct-call path. TheOutputHandlertrait is unchanged; embedder code is unaffected.Engine::evalandEngine::vm_evalare removed underasync-runtime. The sync and async runtimes are now mutually exclusive at the cargo-feature level — async builds must useEngine::eval_async. This guarantees that non-coloured stdlib functions (fs::read,io::println, …) resolve to one implementation per build.
Editor extensions
Section titled “Editor extensions”- VS Code 0.6.0 → 0.7.0
- Zed 0.6.0 → 0.7.0
- JetBrains 0.6.0 → 0.7.0
[0.6.0] — 2026-05-02
Section titled “[0.6.0] — 2026-05-02”semver::stdlib module —parse,is_valid,format,compare,eq/gt/gte/lt/lte,satisfies,bump_major/bump_minor/bump_patch. Backed by thesemvercrate. Versions round-trip through dicts shaped#{major, minor, patch, pre, build}. Enabled by default; embedders can opt out withdefault-features = falseonion-core.- New
semvercargo feature onion-core(indefault). - LSP hover/completion learn the
semver::namespace. - Tree-sitter, VS Code, JetBrains, and Zed grammars recognise
semveras a builtin module name.
Editor extensions
Section titled “Editor extensions”- VS Code 0.5.0 → 0.6.0
- Zed 0.5.0 → 0.6.0
- JetBrains 0.5.0 → 0.6.0
[0.5.0] — 2026-05-02
Section titled “[0.5.0] — 2026-05-02”- Aliased
useimports —use io::println as say;,use math::{add as sum, PI};. Both single and braced-list forms accept an optionalas <ident>clause; the original name is used for module lookup, the alias becomes the local binding. Glob imports (use m::*) cannot be aliased. Supported by the tree-walking interpreter, the bytecode VM, the LSP (hover showsuse m::name as alias), and tree-sitter / TextMate highlighting. asrecognized as a keyword across all editor grammars (tree-sitter, VS Code TextMate, JetBrains TextMate bundle).- Tree-sitter grammar gains an
import_itemnode withname/aliasfields.
Editor extensions
Section titled “Editor extensions”- VS Code 0.4.0 → 0.5.0
- Zed 0.4.0 → 0.5.0
- JetBrains 0.4.0 → 0.5.0
0.4.0 — 2026-05-01
Section titled “0.4.0 — 2026-05-01”log::stdlib module withtrace,debug,info,warn,error, plusset_level,level,enabled. Each level function takes(message, fields?); the optional dict argument is passed through to the handler as structured fields.- Compile-time level cap in both the bytecode compiler and the tree-walk
interpreter —
log::<level>(...)callsites whose level is aboveCOMPILE_LOG_CAPare stripped (args and all). Mirrorstracing’srelease_max_level_*semantics. - Cargo features on
ion-coreto set the cap:log_max_level_off|error|warn|info|debug|trace. With none enabled the cap defaults toTraceunderdebug_assertionsandInfootherwise. LogHandlertrait + defaultStdLogHandler(stderr,LEVEL message [k=v ...]format) honouring an engine-wide threshold.tracingfeature that exposesTracingLogHandler, forwarding each level totracing::event!so embedders inherit subscriber filtering, spans, and structured fields.Engine::with_handlers,Engine::set_log_handler,Engine::set_log_handler_arc,Engine::set_log_level,Engine::log_level,register_stdlib_with_handlers,register_builtins_with_handlers,Interpreter::with_handlers.- LSP hover/completion learn the
log::namespace. - VS Code, JetBrains, Zed, and tree-sitter grammars recognize
logas a builtin module name.
Editor extensions
Section titled “Editor extensions”- VS Code 0.3.2 → 0.4.0
- Zed 0.3.2 → 0.4.0
- JetBrains 0.3.2 → 0.4.0
0.3.2 — 2026-05-01 (ion-lsp only)
Section titled “0.3.2 — 2026-05-01 (ion-lsp only)”- Hover overhaul in
ion-lsp:- Method hover (
xs.push,s.to_upper,task.await, …). - Module-member hover (
math::sqrt,math::PI,io::println,json::decode). - Module-name hover (cursor on
mathshows the module overview). - Type-name hover for
Option,Result,bool,dict,list,tuple,set,cell,any,fn. - Function parameters tracked as definitions so they hover.
lethover now shows the full source initializer withmutand type annotation (e.g.let mut total: int = 0).
- Method hover (
- All hover responses include a token range so editors highlight the hovered identifier.
- 13 new hover tests in
ion-lsp.
Changed
Section titled “Changed”- The method, module-member, and type-name tables are lifted into shared module-level statics so hover and completion stay in sync.
Editor extensions
Section titled “Editor extensions”- VS Code 0.3.1 → 0.3.2
- Zed 0.3.1 → 0.3.2
- JetBrains 0.3.1 → 0.3.2
0.3.1 — 2026-05-01 (editor extensions only)
Section titled “0.3.1 — 2026-05-01 (editor extensions only)”- Distinct scope (
storage.type.string.ion/@string.special.symbol) for the f-stringfprefix so themes can color it apart from the string body. - Explicit
punctuation.definition.string.{begin,end}captures on string delimiters in the TextMate grammars.
Editor extensions
Section titled “Editor extensions”- VS Code 0.2.0 → 0.3.1
- Zed 0.2.0 → 0.3.1
- JetBrains 0.2.1 → 0.3.1
0.3.0 — 2026-04-30
Section titled “0.3.0 — 2026-04-30”- Native async runtime (
async-runtimeCargo feature) with structured concurrency,spawn/.await,select, channels, timers, and cooperative scheduling. Replaces the legacy threaded backend for new embedders. Engine::eval_asyncentry point and async host-function registration (register_async_fn). Tokio embedding documented indocs/concurrency.md.- Async module host functions in stdlib.
Changed
Section titled “Changed”- VM optimizations folded into the
vmfeature flag (peephole, constant folding, dead-code elimination, tail-call optimization). - Legacy threaded concurrency renamed to
legacy-threaded-concurrencyfeature (off by default). - Editor extensions updated for Ion 0.3 syntax — async /
select/ spawn /.awaitkeywords, nested module paths, loop labels, cell type annotations, named arguments, expanded standard module APIs.
- JetBrains Ion file highlighting (TextMate file-type registration).
0.2.3 — earlier
Section titled “0.2.3 — earlier”referencesandrenamerequest handlers inion-lsp.- Labeled
breakandcontinue('outer: for ... { break 'outer; }).
- Friendlier “ion-lsp missing binary” error from the editor extensions.
- JetBrains plugin TextMate registration.
0.2.2 — earlier
Section titled “0.2.2 — earlier”- JetBrains IDE plugin (TextMate-based, optional LSP4IJ integration).
- MessagePack byte encoding round-trips (
Value::to_msgpack/from_msgpack,msgpackCargo feature).
0.2.0 — earlier
Section titled “0.2.0 — earlier”- Module/namespace system with
useimports and::path syntax. - Built-in stdlib modules:
math,json,io,string. rewritefeature for replacing top-level global values in source.- Tokio embedding via closure-backed builtins (
Engine::register_closure). - Tier A cooperative-scheduler concurrency runtime; Tier C plan documented.
- Zed editor support with tree-sitter grammar and WASM build pipeline.
- Comprehensive parser error recovery (multiple diagnostics per parse).
- Lazy
Value::Rangeto avoid allocating large lists for integer ranges. - 196 cross-validation tests covering sets, spread, match, closures.
Changed
Section titled “Changed”- Removed backward-compatible top-level builtins; stdlib access is now
namespaced (
math::abs,io::println, …). - Optimized VM: cloning avoided in conditionals, faster string ops, broader constant deduplication.
- Comprehensive audit: guarded panics, removed dead code, broadened test coverage.
0.1.0 — initial release
Section titled “0.1.0 — initial release”- Tree-walk interpreter with a Starlark-influenced syntax.
- Optional bytecode VM (
vmfeature). #[derive(IonType)]for host struct/enum injection.- VS Code extension (TextMate grammar + LSP client).
- Initial
ion-lspwith definitions, document symbols, completion, hover, diagnostics.