Skip to main content
EmmyLua Analyzer supports code formatting through external formatting tools. This page explains how to configure formatting, integrate popular formatters like StyLua, and customize formatting behavior.

Overview

EmmyLua Analyzer delegates formatting to external command-line tools rather than implementing its own formatter. This design allows you to use any formatter that:
  • Accepts input via stdin
  • Outputs formatted code to stdout
  • Supports command-line arguments
The most popular choice for Lua formatting is StyLua, which is used in the examples below.

Format Configuration

Document Formatting

format.externalTool
object | null
default:"null"
Configuration for formatting entire documents.Properties:
  • program: Path to the external formatter executable
  • args: Array of command-line arguments
  • timeout: Timeout in milliseconds (default: 5000)
{
  "format": {
    "externalTool": {
      "program": "stylua",
      "args": [
        "-",
        "--stdin-filepath",
        "${file}"
      ],
      "timeout": 5000
    }
  }
}

Range Formatting

format.externalToolRangeFormat
object | null
default:"null"
Configuration for formatting selected ranges. Requires formatter support for range formatting.
{
  "format": {
    "externalToolRangeFormat": {
      "program": "stylua",
      "args": [
        "-",
        "--stdin-filepath",
        "${file}",
        "--range-start=${start_offset}",
        "--range-end=${end_offset}"
      ],
      "timeout": 5000
    }
  }
}

Diff Mode

format.useDiff
boolean
default:"false"
Use diff algorithm for formatting. When enabled, only the changed portions are sent to the editor, which can be more efficient for large files.
{
  "format": {
    "useDiff": true
  }
}

Variable Substitution

The args array supports variable substitution, allowing you to pass dynamic values from the editor to the formatter.

Simple Variables

${file}
variable
Full path of the current file.Example: /path/to/project/src/main.lua
${indent_size}
variable
Indentation size (number of spaces).Example: 4
${start_offset}
variable
Start byte offset of the selected range (for range formatting).Example: 0
${end_offset}
variable
End byte offset of the selected range (for range formatting).Example: 1250
${start_line}
variable
Start line number of the selection.Example: 1
${end_line}
variable
End line number of the selection.Example: 50

Conditional Variables

Conditional variables use the format ${variable?true_value:false_value}.
${use_tabs?value_if_true:value_if_false}
variable
Returns different values based on whether tabs are used for indentation.Example: ${use_tabs?Tabs:Spaces}Tabs or Spaces
${insert_final_newline?value}
variable
Returns value if final newline should be inserted, empty string otherwise.Example: ${insert_final_newline?--final-newline}--final-newline or empty
${non_standard_symbol?value}
variable
Returns value if non-standard symbols are allowed, empty string otherwise.Example: ${non_standard_symbol?--allow-non-standard}--allow-non-standard or empty
If a conditional variable results in an empty string, that argument is omitted from the command.

Formatter Examples

StyLua is the most popular Lua formatter with excellent support for Lua 5.1-5.4 and LuaJIT.
{
  "format": {
    "externalTool": {
      "program": "stylua",
      "args": ["-"],
      "timeout": 5000
    }
  }
}
{
  "format": {
    "externalTool": {
      "program": "stylua",
      "args": [
        "-",
        "--stdin-filepath",
        "${file}",
        "--indent-width=${indent_size}",
        "--indent-type",
        "${use_tabs?Tabs:Spaces}"
      ],
      "timeout": 5000
    }
  }
}
{
  "format": {
    "externalTool": {
      "program": "stylua",
      "args": [
        "-",
        "--stdin-filepath",
        "${file}"
      ]
    },
    "externalToolRangeFormat": {
      "program": "stylua",
      "args": [
        "-",
        "--stdin-filepath",
        "${file}",
        "--range-start=${start_offset}",
        "--range-end=${end_offset}"
      ],
      "timeout": 5000
    }
  }
}
{
  "format": {
    "externalTool": {
      "program": "stylua",
      "args": [
        "-",
        "--stdin-filepath",
        "${file}",
        "--config-path",
        ".stylua.toml"
      ]
    }
  }
}
Create .stylua.toml in your project root:
column_width = 120
line_endings = "Unix"
indent_type = "Spaces"
indent_width = 2
quote_style = "AutoPreferDouble"
call_parentheses = "Always"

EmmyLuaCodeStyle

EmmyLuaCodeStyle is another formatter specifically designed for EmmyLua-annotated code.
{
  "format": {
    "externalTool": {
      "program": "emmylua-codestyle",
      "args": [
        "format",
        "--stdin",
        "--indent-width=${indent_size}"
      ]
    }
  }
}

lua-format

Alternative formatter with different style options.
{
  "format": {
    "externalTool": {
      "program": "lua-format",
      "args": [
        "--indent-width=${indent_size}",
        "--use-tab=${use_tabs?true:false}"
      ]
    }
  }
}

Custom Formatter Script

You can wrap your formatter in a custom script for complex scenarios.
{
  "format": {
    "externalTool": {
      "program": "/path/to/custom-format.sh",
      "args": [
        "${file}",
        "${indent_size}"
      ]
    }
  }
}
custom-format.sh:
#!/bin/bash
FILE=$1
INDENT_SIZE=$2

# Read from stdin
INPUT=$(cat)

# Run custom formatting logic
echo "$INPUT" | stylua - --indent-width=$INDENT_SIZE | my-custom-post-processor

Formatter Installation

Installing StyLua

cargo install stylua

Installing EmmyLuaCodeStyle

Formatting Workflow

When you trigger code formatting:
1

Language Server Reads Configuration

EmmyLua Analyzer reads the format.externalTool or format.externalToolRangeFormat configuration.
2

Variables are Substituted

Variables in the args array are replaced with actual values from the editor.
3

Formatter Process Starts

The external formatting tool is spawned as a subprocess.
4

Code is Piped to stdin

The current file content (or selected range) is sent to the formatter’s stdin.
5

Formatter Processes Code

The formatter processes the input according to its configuration.
6

Formatted Code is Read

EmmyLua Analyzer reads the formatted output from the formatter’s stdout.
7

Changes are Applied

If formatting succeeds, the changes are applied to the editor. If useDiff is enabled, only modified sections are updated.

Troubleshooting

Error: Failed to execute formatter: program not foundSolution:
  • Ensure the formatter is installed and available in your PATH
  • Use absolute path to the formatter executable:
    {
      "format": {
        "externalTool": {
          "program": "/usr/local/bin/stylua"
        }
      }
    }
    
Error: Formatting operation timed outSolution:
  • Increase the timeout value:
    {
      "format": {
        "externalTool": {
          "timeout": 10000  // 10 seconds
        }
      }
    }
    
Error: Formatter returned invalid UTF-8Solution:
  • Ensure your formatter outputs UTF-8 encoded text
  • Check that the formatter is configured correctly
  • Test the formatter command manually:
    echo 'local x = 1' | stylua -
    
Error: Formatter exited with code 1Solution:
  • Check formatter logs for syntax errors in your code
  • Verify that all required formatter arguments are provided
  • Test the command manually to see error messages
Error: Range formatting fails or formats entire fileSolution:
  • Ensure your formatter supports range formatting
  • Check that ${start_offset} and ${end_offset} variables are correctly passed
  • Some formatters may not support precise range formatting

Format on Save

Format on save is configured in your editor, not in .emmyrc.json.
In settings.json:
{
  "[lua]": {
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "sumneko.lua"
  }
}

Best Practices

Use a formatter config file

Instead of passing all options via command-line, use a formatter-specific config file (like .stylua.toml) and commit it to your repository.

Keep timeout reasonable

Set timeout to 5-10 seconds. If formatting takes longer, investigate why (large file? slow formatter?).

Test formatter separately

Test your formatter command manually before adding it to .emmyrc.json to ensure it works correctly.

Team consistency

Share your .emmyrc.json and formatter config files with your team to ensure consistent formatting.

Build docs developers (and LLMs) love