Skip to main content
While EmmyLua Analyzer includes a built-in formatter (EmmyLuaCodeStyle), you can configure it to use external formatting tools like StyLua or lua-format for maximum flexibility.

Why Use External Formatters?

Team Preference

Your team may already use a specific formatter

Custom Rules

External formatters may offer specific style rules you need

Migration

Easier migration from other Lua toolchains

Performance

Some external formatters may be faster for large files

Configuration Overview

External formatters are configured in .emmyrc.json using the reformat section:
.emmyrc.json
{
  "reformat": {
    "externalTool": {
      "program": "stylua",
      "args": ["--stdin-filepath", "${file}", "-"],
      "timeout": 5000
    },
    "externalToolRangeFormat": {
      "program": "stylua",
      "args": [
        "--stdin-filepath", "${file}",
        "--range-start=${start_offset}",
        "--range-end=${end_offset}",
        "-"
      ],
      "timeout": 5000
    },
    "useDiff": false
  }
}
externalTool
object
Configuration for full document formatting
externalToolRangeFormat
object
Configuration for range (selection) formatting
program
string
required
Path to the formatter executable (must be in PATH or absolute path)
args
string[]
required
Command-line arguments passed to the formatter
timeout
number
default:5000
Timeout in milliseconds for formatting operations
useDiff
boolean
default:false
Use diff-based formatting for better performance on large files

Variable Substitution

The args array supports variable substitution for dynamic values:

Simple Variables

VariableDescriptionExample Value
${file}Full path of the current file/path/to/script.lua
${indent_size}Indentation size (number of spaces)4
${start_offset}Start byte offset of selection0
${end_offset}End byte offset of selection100
${start_line}Start line number1
${end_line}End line number10

Conditional Variables

Conditional variables use ternary-like syntax:
${variable?true_value:false_value}
VariableReturns when trueReturns when false
${use_tabs?Tabs:Spaces}TabsSpaces
${use_tabs?--use-tabs:--use-spaces}--use-tabs--use-spaces
${insert_final_newline?--final-newline:}--final-newlineEmpty string
If a conditional variable evaluates to empty string, that argument is omitted entirely.

StyLua Integration

StyLua is a popular opinionated Lua formatter.

Installation

cargo install stylua

Configuration

.emmyrc.json
{
  "reformat": {
    "externalTool": {
      "program": "stylua",
      "args": [
        "-",
        "--stdin-filepath",
        "${file}",
        "--indent-width=${indent_size}",
        "--indent-type",
        "${use_tabs?Tabs:Spaces}"
      ],
      "timeout": 5000
    },
    "externalToolRangeFormat": {
      "program": "stylua",
      "args": [
        "-",
        "--stdin-filepath",
        "${file}",
        "--indent-width=${indent_size}",
        "--indent-type",
        "${use_tabs?Tabs:Spaces}",
        "--range-start=${start_offset}",
        "--range-end=${end_offset}"
      ],
      "timeout": 5000
    }
  }
}

StyLua Configuration File

Create stylua.toml in your project root:
stylua.toml
column_width = 120
line_endings = "Unix"
indent_type = "Spaces"
indent_width = 4
quote_style = "AutoPreferDouble"
call_parentheses = "Always"

[collapse_simple_statement]
enabled = true
  • column_width - Maximum line width
  • line_endings - Unix (LF) or Windows (CRLF)
  • indent_type - Spaces or Tabs
  • indent_width - Number of spaces per indent
  • quote_style - AutoPreferDouble, AutoPreferSingle, ForceDouble, ForceSingle
  • call_parentheses - Always, NoSingleString, NoSingleTable, None

lua-format Integration

lua-format is another popular Lua formatter.

Installation

# Clone and build
git clone --recurse-submodules https://github.com/Koihik/LuaFormatter
cd LuaFormatter
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --target lua-format

# Or use pre-built binary from releases

Configuration

.emmyrc.json
{
  "reformat": {
    "externalTool": {
      "program": "lua-format",
      "args": [
        "--stdin",
        "--column-limit=120",
        "--indent-width=${indent_size}",
        "${use_tabs?--use-tab:--no-use-tab}"
      ],
      "timeout": 5000
    }
  }
}

lua-format Configuration File

Create .lua-format in your project root:
.lua-format
column_limit: 120
indent_width: 4
use_tab: false
tab_width: 4
continuation_indent_width: 4
spaces_before_call: 1
keep_simple_control_block_one_line: true
keep_simple_function_one_line: true
align_args: true
break_after_functioncall_lp: false
break_before_functioncall_rp: false
spaces_inside_functioncall_parens: false
spaces_inside_functiondef_parens: false
align_parameter: true
chop_down_parameter: false
break_after_functiondef_lp: false
break_before_functiondef_rp: false
align_table_field: true
break_after_table_lb: true
break_before_table_rb: true
chop_down_table: false
chop_down_kv_table: true
extra_sep_at_table_end: false
column_table_limit: 120

Custom Formatter Integration

You can integrate any formatter that:
  1. Reads from stdin or accepts a file path
  2. Writes formatted output to stdout
  3. Supports command-line configuration

Example: Python-based Formatter

format_lua.py
#!/usr/bin/env python3
import sys

def format_lua(code):
    # Your formatting logic here
    return code

if __name__ == "__main__":
    code = sys.stdin.read()
    formatted = format_lua(code)
    sys.stdout.write(formatted)
.emmyrc.json
{
  "reformat": {
    "externalTool": {
      "program": "python3",
      "args": ["format_lua.py"],
      "timeout": 10000
    }
  }
}

Format on Save

Configure your editor to format automatically:
{
  "editor.formatOnSave": true,
  "[lua]": {
    "editor.defaultFormatter": "EmmyLua.emmylua"
  }
}

Troubleshooting

Formatter Not Found

Error: “Could not find executable: stylua”
Solutions:
  1. Ensure the formatter is installed and in PATH:
    which stylua  # Unix/macOS
    where stylua  # Windows
    
  2. Use absolute path in configuration:
    {
      "reformat": {
        "externalTool": {
          "program": "/usr/local/bin/stylua",
          "args": [...]
        }
      }
    }
    

Formatting Timeout

Error: “Formatting timed out”
Increase the timeout:
{
  "reformat": {
    "externalTool": {
      "timeout": 10000  // 10 seconds
    }
  }
}

Invalid Output

Error: “Formatter returned invalid UTF-8”
Ensure your formatter:
  1. Outputs valid UTF-8
  2. Doesn’t include extra debug messages
  3. Returns non-zero exit code on errors

Inconsistent Formatting

If formatting differs between runs:
  1. Check for non-deterministic formatter behavior
  2. Verify configuration files are committed to version control
  3. Ensure all team members use the same formatter version

Performance Considerations

For large files, enabling useDiff can significantly improve performance by only sending/receiving changed portions.
.emmyrc.json
{
  "reformat": {
    "useDiff": true
  }
}

Benchmarking

Compare formatter performance:
# StyLua
time stylua --check .

# lua-format
time find . -name "*.lua" -exec lua-format --check {} \;

# Built-in formatter
time emmylua_ls --format .

CI/CD Integration

GitHub Actions

.github/workflows/format.yml
name: Format Check

on: [pull_request]

jobs:
  format:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Install StyLua
        uses: JohnnyMorganz/stylua-action@v3
        with:
          version: latest
      
      - name: Check formatting
        run: stylua --check .

Pre-commit Hook

.git/hooks/pre-commit
#!/bin/bash

LUA_FILES=$(git diff --cached --name-only --diff-filter=ACMR | grep '\.lua$')

if [ -n "$LUA_FILES" ]; then
    # Format with external tool
    echo "Formatting Lua files..."
    echo "$LUA_FILES" | xargs stylua
    
    # Re-add formatted files
    echo "$LUA_FILES" | xargs git add
fi

Migration Strategies

From Built-in to External Formatter

1

Test formatter locally

Run the external formatter on a few files to verify output
2

Configure .emmyrc.json

Add external formatter configuration
3

Format entire codebase

Create a dedicated commit with formatting changes
4

Update CI/CD

Add format checking to your CI pipeline
5

Document for team

Update team documentation with new formatter setup

From External to Built-in Formatter

Simply remove the externalTool configuration:
.emmyrc.json
{
  "reformat": {
    "externalTool": null
  }
}

Comparison Table

FeatureBuilt-in (EmmyLuaCodeStyle)StyLualua-format
InstallationIncludedSeparate installSeparate install
SpeedFastVery FastModerate
Configuration.editorconfigstylua.toml.lua-format
OpinionatedModerateHighConfigurable
Range formattingYesYesLimited
Lua 5.4 supportYesYesYes
Active developmentYesYesModerate

Best Practices

  1. Choose one formatter - Don’t mix formatters across the team
  2. Commit config files - Version control formatter configuration
  3. Document setup - Include formatter setup in README
  4. Automate formatting - Use pre-commit hooks or CI checks
  5. Format incrementally - Format new/changed code rather than reformatting everything at once

Next Steps

Code Style Guide

Establish team style conventions

Performance Tuning

Optimize formatter performance

Build docs developers (and LLMs) love