{"record":{"id":"9d3f534baff1e70c","repo":"GraphiteEditor/Graphite","slug":"editor-commands-requires-a-module-with-an-inlin","errorCode":null,"errorMessage":"#[editor_commands] requires a module with an inline body","messagePattern":"#\\[editor_commands\\] requires a module with an inline body","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"proc-macros/src/editor_commands.rs","lineNumber":17,"sourceCode":"use convert_case::{Case, Casing};\nuse proc_macro2::TokenStream;\nuse quote::{quote, quote_spanned};\nuse syn::spanned::Spanned;\nuse syn::{Error, FnArg, Ident, Item, ItemFn, ItemMod, ItemUse, Pat, Visibility};\n\npub fn editor_commands_impl(attr: TokenStream, module: ItemMod) -> syn::Result<TokenStream> {\n\tif !attr.is_empty() {\n\t\treturn Err(Error::new(attr.span(), \"#[editor_commands] takes no arguments\"));\n\t}\n\tfor attr in &module.attrs {\n\t\tif !attr.path().is_ident(\"doc\") {\n\t\t\treturn Err(Error::new(attr.span(), \"the #[editor_commands] module may not have other attributes\"));\n\t\t}\n\t}\n\tlet Some((_, items)) = module.content else {\n\t\treturn Err(Error::new(module.mod_token.span, \"#[editor_commands] requires a module with an inline body\"));\n\t};\n\n\tlet mut imports: Vec<ItemUse> = Vec::new();\n\tlet mut functions: Vec<ItemFn> = Vec::new();\n\tfor item in items {\n\t\tmatch item {\n\t\t\tItem::Use(import) => imports.push(import),\n\t\t\tItem::Fn(function) => functions.push(function),\n\t\t\tother => return Err(Error::new(other.span(), \"only `use` imports and command functions may appear in an #[editor_commands] module\")),\n\t\t}\n\t}\n\n\tlet mut variants = TokenStream::new();\n\tlet mut stubs = TokenStream::new();\n\tlet mut arms = TokenStream::new();\n\n\tfor function in &functions {\n\t\tfor attr in &function.attrs {","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/proc-macros/src/editor_commands.rs#L1-L35","documentation":"Thrown by the #[editor_commands] attribute macro when it is applied to a module declared without an inline body (e.g. `mod commands;`). The macro must walk the module's items at compile time to collect `use` imports and command functions, so it can only see contents that are syntactically present inside `mod name { ... }`. An out-of-line module file gives it nothing to expand.","triggerScenarios":"Applying #[editor_commands] to `mod commands;` (semicolon form pointing at commands.rs) instead of an inline `mod commands { ... }` block. The check is `module.content` being None, which only happens for the semicolon form.","commonSituations":"Developers splitting a growing commands module into its own file, or copy-pasting an attribute onto a module declaration that was already out-of-line. Also appears when a formatter or refactor tool rewrites `mod x { }` into `mod x;` + file.","solutions":["Replace `mod commands;` with an inline `mod commands { ... }` containing the `use` statements and `fn name(args…) -> Message` command functions.","Keep the attribute directly above the inline module: `#[editor_commands] mod commands { ... }`.","Move any helper code that motivated the file split into a plain impl block outside the macro module."],"exampleFix":"// before\n#[editor_commands]\nmod commands;\n\n// after\n#[editor_commands]\nmod commands {\n\tuse crate::Message;\n\tfn select_layer(layer: u64) -> Message { Message::SelectLayer(layer) }\n}","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never point #[editor_commands] at an out-of-line module file; keep the body inline.","Run `cargo check` immediately after moving module code so the macro rejects the shape at compile time.","Document the required inline form next to the macro definition in onboarding docs."],"tags":["rust","proc-macro","editor-commands","module"],"backgroundTag":"proc-macro-input-validation","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}