Configuration
July 9, 2026 · View on GitHub
The extension supports the following configuration options. All settings are prefixed with sight. and can be configured in VS Code's Settings UI or in your settings.json file.
Contents
- Diagnostics
- Tuning autocomplete behavior
- Indexing
- ADO Paths
- Comments
- Project Configuration File
- See Also
Diagnostics
Control how the LSP reports errors, warnings, and other diagnostics.
| Setting | Type | Default | Description |
|---|---|---|---|
sight.diagnostics.enabled | boolean | true | Enable or disable all diagnostics |
sight.diagnostics.severity.undefinedMacro | enum | "warning" | Severity level for undefined macro references. Options: "error", "warning", "information", "hint", "off" |
sight.diagnostics.severity.undefinedVariable | enum | "off" | [Experimental] Severity level for undefined variable references. Options: "error", "warning", "information", "hint", "off" |
sight.diagnostics.severity.styleWarnings | enum | "information" | Severity level for style warnings. Options: "error", "warning", "information", "hint", "off" |
sight.diagnostics.severity.malformedOperator | enum | "warning" | Severity for malformed operator diagnostics (e.g., = = instead of ==). Options: "error", "warning", "information", "hint", "off" |
sight.diagnostics.severity.spacedCompoundOperator | enum | "information" | Severity for spaced compound operator diagnostics that Stata accepts as the compact form (e.g., < = → <=). Options: "error", "warning", "information", "hint", "off" |
sight.diagnostics.severity.invalidOperatorSequence | enum | "error" | Severity for invalid operator sequence diagnostics (e.g., < |). Options: "error", "warning", "information", "hint", "off" |
sight.diagnostics.severity.cStyleLogicalInControlFlow | enum | "information" | Severity for C-style logical operators (&&, ||) in if/else if control flow statements. These work but are stylistically discouraged. Options: "error", "warning", "information", "hint", "off" |
sight.diagnostics.severity.chainedComparison | enum | "warning" | Severity for suspicious chained comparisons (e.g., a != b != c). Stata evaluates comparisons left-to-right, not as a mathematical chain. Options: "error", "warning", "information", "hint", "off" |
sight.diagnostics.severity.literalMacroAdjacency | enum | "hint" | Severity for a literal placed directly against a macro reference in an expression (e.g., a == 1\b'). Options: "error", "warning", "information", "hint", "off"` |
sight.diagnostics.indentation | boolean | false | Enable indentation diagnostics (missing indentation in blocks, unnecessary indentation after comments) |
When the scope resolver can prove a referenced macro or variable exists but is
unreachable, Sight replaces the generic undefined-symbol diagnostic with a more
specific OUT_OF_SCOPE_SYMBOL message at the same severity. This applies when
the symbol is defined later in the same file, defined after the relevant call
site in another file, or excluded because local macros do not inherit through
do/run. If the underlying undefined diagnostic is disabled, the rewrite is
also suppressed.
Why Indentation Diagnostics Are Disabled by Default
Unlike Python, Stata ignores indentation - it's purely stylistic and doesn't affect code execution. Indentation diagnostics are disabled by default for several reasons:
- Stylistic, not semantic: "Wrong" indentation won't break your code
- Legacy codebase noise: Existing codebases may produce many warnings, causing alert fatigue
- Subjective preferences: Teams may have different indentation conventions
- Opt-in philosophy: Mature LSPs (TypeScript, ESLint) default stylistic rules to off
To enable indentation diagnostics:
- VS Code: Set
sight.diagnostics.indentationtotruein Settings- Project config: Add
[diagnostics] indentation = truetosight.toml
Forward Reference Detection
The LSP detects "forward references" - using a macro before it's defined in execution order. Stata executes code sequentially, so a macro doesn't exist until the line defining it runs.
Local macros must be defined before use within the same file:
// Warning: `fruit' is not yet defined
local result: list fruit - other
local fruit apple banana
local other banana
Global macros in the same file must also be defined before use:
// Warning: file_global is not yet defined
local result: list file_global - other
global file_global value
When a foreach or forvalues loop creates macro names from statically known
iterator values, Sight expands those concrete names and treats them as defined
from the local or global statement that creates them. A reference later in
the same loop body is in scope; a reference before that statement is still a
forward reference.
foreach g in age sex educ {
summarize `g'
local mean_`g' = r(mean) // defines mean_age, mean_sex, mean_educ
}
display `mean_age' // no "undefined macro" warning
This covers the common name-building forms — local `i',
local `i'_suffix, local prefix_`i' — across foreach VAR in <list>,
foreach VAR of local <macro>, and forvalues VAR = <range> when the values
are statically known. When a value is dynamic (e.g. forvalues i = 1/`=_N')
the loop is left alone and no names are expanded.
Global macros from other files also produce warnings unless the LSP can determine the relationship. By default (crossFile.backwardDependencies: "auto"), the LSP scans the workspace at startup to discover which files call which, and automatically resolves parent–child symbol inheritance. It also follows do, run, and include commands within each file for forward resolution. For cases where auto-detection doesn't work (e.g., dynamic paths with macros), you can use explicit directives (sight: done-by, sight: included-by, sight: do, sight: run, sight: include). The older @lsp- forms remain permanent aliases. The workspace indexer provides globals for completions and go-to-definition, but does not suppress undefined macro warnings. See Cross-File Awareness for details.
First definition wins: When a macro is defined multiple times, references before the first definition produce warnings, but references after the first definition do not (even if they appear before later redefinitions).
Macro-creating options: The analyzer recognizes local() and global() options on built-in commands (levelsof, glevelsof) and user-defined programs (via c_local `option' and global `option' patterns matching syntax declarations).
Mata st_local / st_global: The analyzer recognizes the two-argument setter forms st_local("name", value) and st_global("NAME", value) inside Mata blocks — both the inline mata: form and mata … end / mata { … } blocks — and declares the named macro. The name must be a literal double-quoted identifier; dynamic names (variables, expressions, compound quotes, or embedded macro references) are not resolved. The one-argument read form st_local("name") does not declare anything. The declaration is forward-only: a reference before the setter is still flagged. For an inline mata: setter the macro only becomes visible after the inline statement ends, so a `name' reference within the same mata: unit — including the setter's own value argument (mata: st_local("x", "x'")`) — is reported undefined, matching Stata's macro expansion order; references after the statement resolve normally.
Tuning autocomplete behavior
If autocomplete feels too aggressive, there are a few knobs to adjust.
- When the completions menu appears. By default it pops up almost instantly as you type. You can delay it, or turn automatic popups off entirely and trigger the menu manually with Ctrl+Space.
- How completions get accepted. By default both Enter and Tab accept the highlighted suggestion when the menu is open. You can turn off Enter (so Enter always inserts a newline), turn off Tab (so Tab always indents), or both.
Changing settings
The first three knobs below are editor.* settings. Open the VS Code Settings UI either with
the keyboard (Cmd+, on macOS, Ctrl+, on Windows/Linux) or through the menu (Code → Settings →
Settings on macOS, File → Preferences → Settings on Windows/Linux). Paste the setting ID into
the search box at the top, then change the value inline.
| Setting | Default | What it does / how to change |
|---|---|---|
editor.acceptSuggestionOnEnter | "on" | "on" accepts on Enter; "off" makes Enter always insert a newline; "smart" only accepts when the suggestion would change the code. Set to "off" if you want Enter to always start a new line, even with the menu open. |
editor.quickSuggestionsDelay | 10 ms | Raise this (e.g., 500) to delay the popup so it doesn't appear mid-keystroke. Or set editor.quickSuggestions to "off" entirely and use Ctrl+Space to trigger suggestions on demand. |
editor.acceptSuggestionOnCommitCharacter | true | Typing a "commit character" like ., (, or : both accepts the highlighted suggestion and inserts the character. Set to false if you'd rather those characters insert literally and only explicit keys (Tab / Enter) accept. |
Stopping Tab from accepting suggestions
VS Code doesn't ship an editor.acceptSuggestionOnTab toggle — unbinding Tab is a keyboard
shortcut change rather than a setting. Open the Keyboard Shortcuts editor either with the
keyboard (Cmd+K Cmd+S on macOS, Ctrl+K Ctrl+S on Windows/Linux) or through the menu (Code →
Settings → Keyboard Shortcuts on macOS, File → Preferences → Keyboard Shortcuts on
Windows/Linux). Search for acceptSelectedSuggestion — the entry bound to Tab is the one you
want. Right-click it and choose Remove Keybinding. Tab will now indent even when the
completions menu is open, while Enter still accepts (unless you also changed
editor.acceptSuggestionOnEnter).
If you'd rather edit the JSON directly, open keybindings.json (from the Keyboard Shortcuts
editor, click the "Open Keyboard Shortcuts (JSON)" icon in the top right) and add:
{
"key": "tab",
"command": "-acceptSelectedSuggestion",
"when": "suggestWidgetVisible && textInputFocus && !editorReadonly"
}
The leading - removes Tab from that command specifically.
Indexing
Configure workspace indexing behavior for cross-file features.
| Setting | Type | Default | Description |
|---|---|---|---|
sight.indexWorkspace | boolean | true | Enable workspace-wide symbol indexing |
sight.indexing.maxFileSizeBytes | number | 500000 | Maximum file size in bytes for indexing (~500KB) |
Excluding files and directories
Exclude generated or vendored directories from analysis with workspace-relative
glob patterns. This is most useful for repositories that mix hand-written Stata
source with generated output (for example, downloaded .do files under
output/) that would otherwise dominate sight check results.
| Setting | Type | Default | Description |
|---|---|---|---|
sight.exclude | array | [] | Workspace-relative glob patterns to skip during bulk analysis |
You can set this in two places:
-
sight.tomlat the project root, asworkspace.exclude. This is read by both the editor (LSP server) and thesight checkCLI:[workspace] exclude = ["output/**", "**/_generated/**", "**/*.gen.do"] -
VS Code settings — your User
settings.jsonor the project's Workspace settings (.vscode/settings.json) — as thesight.excludekey. This affects the editor only:{ "sight.exclude": ["output/**", "**/_generated/**", "**/*.gen.do"] }
sight check(the CLI used in CI) reads onlysight.toml(or a file passed with--config). It does not read VS Code settings, which are client-side and reach only the running LSP server. So to exclude paths from CI runs, put them insight.toml. When both are present for the editor, the LSP server letssight.tomltake precedence over VS Code settings (see Project Configuration File).
Behavior:
sight checkdoes not read or report diagnostics for excluded paths when walking a directory (including the default workspace-root walk).- The workspace indexer skips excluded paths when building cross-file context.
- Explicitly-named files are always checked.
sight check output/foo.doanalyzes that file even whenoutput/**is excluded; exclusion only filters directory walks. - Files opened directly in the editor are still analyzed. Exclusion governs
bulk scanning and
sight check, not in-editor live diagnostics — if you open a generated file you still get diagnostics and navigation for it.
Patterns use picomatch glob syntax
(*, **, ?, {a,b}) and are matched relative to the workspace root. A
leading ! re-includes a previously-excluded path (e.g.
["output/**", "!output/manifest.do"]).
exclude only applies to files inside your workspace folder. Sight also scans
your configured ADO paths (and auto-detected Stata install directories), which
normally live outside the workspace — exclude has no effect on those files, so
you cannot use it to filter ADO scanning. (If you point an ADO path at a folder
inside the workspace, it is in-workspace like any other file and exclude
patterns do apply to it.)
ADO Paths
Configure additional search paths for ADO files.
| Setting | Type | Default | Description |
|---|---|---|---|
sight.adoPaths | array | [] | Additional paths to search for ADO files |
Example:
{
"sight.adoPaths": [
"/path/to/custom/ado",
"/another/ado/directory"
]
}
Auto-detected Stata install paths
In addition to the paths you configure, Sight automatically consults the standard Stata install and user ado directories when resolving help topics for the SMCL help viewer:
- macOS:
/Applications/Stata/ado/{base,site,updates}, itsStataMP/StataSE/StataBE/StataICvariants, the StataNow channel directory/Applications/StataNow/ado/{base,site,updates}, and~/Library/Application Support/Stata/ado/{personal,plus}. - Linux:
/usr/local/stata<version>/ado/{base,site,updates}and/opt/stata<version>/…for versions 13–20, plus unversionedstatadirectories. - Windows:
Stata<version>\ado\{base,site,updates}under eachProgram Files/Program Files (x86)directory that Windows reports via its environment variables. - All platforms: the legacy
~/ado,~/ado/personal, and~/ado/plusconventions.
Only directories that actually exist are used, and the auto-detected paths are only consulted for .sthlp lookups — they are not scanned into the workspace symbol index. Use sight.adoPaths to override or supplement this list when you install Stata in a non-standard location.
Comments
Configure the line comment character used by VS Code's toggle comment shortcut.
| Setting | Type | Default | Description |
|---|---|---|---|
sight.lineCommentStyle | string | "//" | Line comment character used by the toggle comment shortcut. In Stata, // can appear anywhere on a line while * must be at the start of a line. Options: "//", "*" |
To use * for comment toggling instead of //:
{
"sight.lineCommentStyle": "*"
}
Project Configuration File
Sight reads sight.toml as the portable project configuration file. The LSP
discovers it by walking upward from the active workspace root; sight check
will use the same discovery from --workspace.
Project config wins over client/editor settings per key. Keys omitted from
sight.toml continue to come from editor settings or built-in defaults.
In a multi-root workspace, the project config is loaded only from the first
workspace folder and applied to every document; a separate sight.toml in
another folder is not resolved per-root. The server logs a note when it detects
multiple folders. Open one project per window, or place a single sight.toml
at a shared root, if you need distinct project settings.
.sight.json is no longer supported. Convert its contents to TOML syntax;
renaming the file is not enough because JSON and TOML are different languages.
Naming convention and case aliasing
The canonical spelling for every setting is camelCase (e.g.
crossFile.maxChainDepth, formatting.preserveAlignment,
diagnostics.severity.undefinedMacro). This is the form used throughout this
documentation and matches comparable tools (Pyright, rust-analyzer,
typescript-language-server).
As a permanent guarantee, every setting also accepts its snake_case
spelling as an equivalent alias, and vice-versa — so you never have to
remember which form a given setting uses. crossFile.maxChainDepth and
cross_file.max_chain_depth are identical, as are formatting.preserveAlignment
and formatting.preserve_alignment. Section names alias too
(crossFile ≡ cross_file), and matching is case-insensitive overall
(CrossFile also works). You may even mix conventions within a single config.
This aliasing applies uniformly to every configuration entry point:
sight.toml, editor settings.json (VS Code), and the initializationOptions
non-VS-Code clients send (Neovim, Helix, Zed, Claude Code). When two spellings
of the same key appear together and neither is the canonical camelCase form,
both are ignored and a warning is emitted; when one of them is canonical, the
canonical spelling wins.
indexWorkspace = true
adoPaths = []
lineCommentStyle = "//"
debug = false
[workspace]
exclude = ["output/**"]
[diagnostics]
enabled = true
indentation = false
[diagnostics.severity]
undefinedMacro = "warning"
undefinedVariable = "off"
styleWarnings = "information"
malformedOperator = "warning"
spacedCompoundOperator = "information"
invalidOperatorSequence = "error"
cStyleLogicalInControlFlow = "information"
mixedLogicalOperators = "warning"
[formatting]
indentSize = 4
indentStyle = "spaces"
lineWidth = 80
preferredCommentStyle = "line"
normalizeCommentStyle = false
commentLineWidth = 72
mode = "source-preserving"
preserveAlignment = true
[completion]
cacheSize = 200
prefixMaxItems = 200
[indexing]
maxFileSizeBytes = 500000
[crossFile]
indexWorkspace = true
maxIndexedFiles = 1000
assumeCallSite = "end"
backwardDependencies = "auto"
maxBackwardDepth = 10
maxForwardDepth = 10
maxChainDepth = 20
maxCalleeRevalidations = 10
maxCachedFiles = 2000
maxCachedScopes = 1000
maxCachedForwardClosures = 2000
[crossFile.diagnostics]
missingFile = "warning"
maxDepth = "information"
callSiteIdentification = "information"
caseMismatch = "auto"
| Option | Type | Default | Description |
|---|---|---|---|
indexWorkspace | boolean | true | Global workspace-indexing switch |
adoPaths | string array | [] | Additional ADO search paths |
workspace.exclude | string array | [] | Workspace-relative globs to skip during sight check and indexing |
lineCommentStyle | "//" | "*" | "//" | Line comment style used when formatting resolves "line" |
debug | boolean | false | Enable debug logging |
diagnostics.enabled | boolean | true | Enable diagnostics |
diagnostics.indentation | boolean | false | Enable indentation diagnostics |
diagnostics.severity.* | severity | varies | Severity for diagnostic families |
formatting.* | mixed | varies | Server formatting behavior |
completion.cacheSize | number | 200 | Completion cache size |
completion.prefixMaxItems | number | 200 | Maximum prefix-command completions |
indexing.maxFileSizeBytes | number | 500000 | Maximum indexed file size |
crossFile.backwardDependencies | "auto" | "explicit" | "auto" | "auto": discover parents from workspace scan; "explicit": require directives |
crossFile.indexWorkspace | boolean | true | Enable workspace-wide file indexing |
crossFile.maxIndexedFiles | number | 1000 | Maximum files to index |
crossFile.maxBackwardDepth | number | 10 | Maximum recursion depth for backward directive resolution |
crossFile.maxForwardDepth | number | 10 | Maximum recursion depth for forward scope resolution |
crossFile.maxChainDepth | number | 20 | Maximum combined depth for forward + backward resolution |
crossFile.maxCalleeRevalidations | number | 10 | Maximum number of open callee documents to revalidate per caller change |
crossFile.maxCachedFiles | number | 2000 | LRU capacity of the parsed-file cache. A memory-safety backstop: eviction only costs recomputation, never correctness. Very low values degrade performance on deep chains. |
crossFile.maxCachedScopes | number | 1000 | LRU capacity of the resolved-scope cache |
crossFile.maxCachedForwardClosures | number | 2000 | LRU capacity of the forward-closure memo (see docs/cross-file.md) |
crossFile.assumeCallSite | "end" | "start" | "end" | Where to assume call site when not specified and inference fails |
crossFile.diagnostics.missingFile | severity | "warning" | Severity for missing directive file diagnostics |
crossFile.diagnostics.callSiteIdentification | severity | "information" | Severity for call site identification diagnostics |
crossFile.diagnostics.caseMismatch | severity + "auto" | "auto" | Severity for case-only path mismatch diagnostics. "auto" maps to information on case-insensitive filesystems (macOS/Windows) and warning on case-sensitive ones (Linux/CI). Independent of missingFile; not suppressible via sight: ignore — silence with "off" or fix the path. |
Severity options: "error", "warning", "information", "off" (alias:
"info" for "information"). crossFile.diagnostics.caseMismatch also
accepts "auto" (not valid for other cross-file severity keys).
Both indexWorkspace and crossFile.indexWorkspace default to true.
Workspace indexing runs only when both are enabled; setting either to false
disables it.
The shared canonical paths and permanent compatibility aliases are specified in Shared project configuration schema.
See Also
Additional settings are documented alongside their features:
- Formatting settings - Indentation, line width, comment normalization
- Send to Stata settings - Stata app, auto-save, cursor advancement, working directory