Reference

Editor support

Editor support for OSL: the language server (osl lsp), checking from a terminal, the formatter, quick fixes, silencing warnings and syntax highlighting.

OSL's editor support is one program: osl lsp, a language server that speaks the Language Server Protocol over standard input and output. Any editor with an LSP client can use it. Alongside it, osl fmt formats files, osl fix applies the editor's quick fixes from a terminal, and osl lsp check prints what the editor would show. All of them use the same compiler that builds your programs, so the editor and osl run never disagree.

Connect an editor#

Point your editor's LSP client at the command osl lsp for files ending in .osl. The server takes no arguments and needs no configuration. Use the folder that holds opal.json (or the Git root) as the project root.

For Neovim:

vim.lsp.config("osl", {
  cmd = { "osl", "lsp" },
  filetypes = { "osl" },
  root_markers = { "opal.json", ".git" },
})
vim.lsp.enable("osl")
vim.filetype.add({ extension = { osl = "osl" } })

For any other editor, the settings are the same three facts:

SettingValue
Commandosl lsp
TransportStandard input and output
File type.osl files, language id osl

The server announces itself as OSL Language Server. It watches **/*.osl and **/opal.json, and rechecks open files when opal.json changes, so lint settings take effect on save. Set OSL_LSP_DEBUG=1 to make it log what it is doing to standard error.

What the server provides#

FeatureWhat you get
DiagnosticsErrors and warnings as you type, including those in imported files. See Diagnostics.
CompletionVariables, functions, types, package members, struct and class fields, methods on the value before the dot, import paths. Triggered by ., " and /.
HoverThe type of a name, and the documentation of a package function or method.
Signature helpParameter names and types while you type a call. Triggered by ( and ,.
Go to definition and type definitionJumps to where a name, type or imported module is declared.
References and renameEvery use of a name across the project. Names with non-ASCII letters, such as año, work.
Document highlightsHighlights the other uses of the name under the cursor.
SymbolsAn outline of the file, and a search across the workspace.
Call hierarchyWho calls a function, and what it calls.
Inlay hintsInferred types written next to auto variables and similar.
Folding and selection rangesFold blocks, and grow the selection to the enclosing expression.
Document linksImports become links to the files they name.
Semantic highlightingColours from the compiler's own understanding of each name.
FormattingThe same formatter as osl fmt.
Quick fixesSee Quick fixes.
Organize importsRemoves repeated top-level import lines.

Unsaved buffers are used in place of the files on disk, so diagnostics and completion see imports of code you have not saved yet. Positions follow the protocol's rule of counting UTF-16 code units.

Semantic token types#

The semantic highlighting legend has these types, in this order: namespace, type, class, enum, interface, struct, typeParameter, parameter, variable, property, enumMember, event, function, method, macro, keyword, modifier, comment, string, number, regexp, operator. There are no token modifiers.

Check from a terminal#

osl lsp check runs the same project check as the editor and prints the diagnostics for a file and every OSL file it reaches. It exits with 1 if any is an error, so it works in CI and in a pre-commit hook.

Terminal
osl lsp check src/main.osl
src/main.osl:3:7: osl: UnusedVariableWarning: Variable 'z' is never used. Name it _, or start its name with _, to ignore it.

   |
 3 |   int z = 3
   |       ^

Each line has the file, line and column, then the diagnostic's kind and message, then the source with the problem underlined. With nothing to report it prints No diagnostics.. Add -v for progress per file. osl lsp check and osl fix report every warning, where osl run and osl compile print the first 20 and count the rest.

Formatting#

osl fmt and the editor's format command are one formatter:

Terminal
osl fmt src/

What it does:

  • Indents with two spaces and puts call and grouping parentheses tight: foo( a ) becomes foo(a).
  • Puts a space between a block opener and its parenthesis: if ready( becomes if ready (.
  • Puts a blank line before def, class, type, struct and enum declarations, and after a leading block of import lines.
  • Expands inline blocks such as if ok ( return value ) onto their own lines.
  • Keeps comments and the contents of strings and templates as they are, and never changes what a program means.

If a file does not parse, osl fmt reports the line where the problem starts, leaves the file alone and exits with 1. When you give it a symlink, it rewrites the file the link points to.

Quick fixes#

Some diagnostics carry an exact replacement. The editor offers it as a quick fix (a "Replace with" action), and osl fix applies all of them from a terminal:

Terminal
osl fix src/

Fixes include removing a redundant .<T> assertion, replacing !(a == b) with a != b, replacing if r then true else false with r, adding void in front of a value that does nothing, and removing a repeated import. A fix is applied only when the file still contains the exact text the compiler reported, so a stale diagnostic never rewrites code.

osl fix also rewrites syntax that old versions of OSL accepted and the compiler no longer does: old type declarations, reserved words used as variable names, old lambda forms and string escapes. It prints each file it changed. See Command line.

Silencing a warning#

A comment on its own line silences warnings of one code on the line below it:

main.osl
// osl-disable-next-line OSL-UNUSED-VARIABLE
int scratch = 3
Click the code to edit it

// osl-disable-file OSL-UNUSED-VARIABLE anywhere in a file silences a code for the whole file. Without a code, the comment silences every warning. A code list can hold several codes separated by commas or spaces, and all matches every code. The comment has to be on a line by itself, and only the line directly after it is covered. Errors cannot be silenced. To change how a whole project treats a warning, use the lint settings in opal.json.

Syntax highlighting#

The language server's semantic highlighting is the accurate source of colour, because it knows whether a name is a type, a function or a variable. Editors that support semantic tokens get it with no extra setup. OSL does not bundle a TextMate or Tree-sitter grammar for editors without LSP. Those editors need a grammar of your own or a community one; osl ast file.osl prints the exact tokens and structure of a file if you are writing one.