Hot++

Language server internals

This page describes how hot-ls works inside, and how an editor uses it with clangd. For the setup steps see Tools.

hot-ls is a stdio LSP 3.17 server. It serves .hot files only. A .cpp script is a C++ file for clangd (see C++ scripts). The code is in src/ls/. The extension in editors/vscode/ starts it.

Editor setup: two servers

An editor uses two language servers on one project:

Steps:

  1. Install the clangd extension (llvm-vs-code-extensions.vscode-clangd) and clangd. Set it up for the C++ build as usual.
  2. Build hot-ls and install the extension in editors/vscode/. Put the hot-ls arguments in hot.server.args. The include dirs come from the script hosts (next subsection). The flags -I and --cxxflag still work as overrides.
  3. Optional, for workspace symbols and the background index of scripts: run hotc <file.hot>... --gen N --out-dir DIR --compile-commands CDIR. Give --compile-commands-dir CDIR to hot-ls.
  4. Add .cache/ to the ignore list of the project (for example in .gitignore).

Both servers can use the same project and the same .cache/ directory. They do not disturb each other:

hot-ls supports many workspace folders. The index directory and the clangd directory are in the first folder that initialize gives. Each is one flat directory for all folders, so a shard of any folder is in it. The clangd child keeps its directory for the whole session. If initialize gives no folder, the first folder that the editor adds gives the index directory. The editor can add or remove a folder (workspace/didChangeWorkspaceFolders). The server then updates the folder list and reloads the host files. For a removed folder, it deletes the shards of the files of that folder. It keeps a shard of a file that another folder still holds.

A workspace symbol request also lists the classes and members of the .hot files of all folders. Cost rule: the request never analyzes a closed file. It lists a closed file only if the index has a valid shard for it. A shard comes from a rename or references request that scans the file, and from a document that closes with the text of the file on disk. An open document uses its own analysis. An empty query lists no script symbol.

Automatic setup (script hosts)

A script host tells hot-ls how the engine compiles its scripts. CMake writes the host files. So the user does not pass -I flags.

include(cmake/HotScripts.cmake)
# hot_add_scripts calls hot_script_host by themselves.
# Call it directly for a host without these functions:
hot_script_host(NAME engine TARGET engine
                SCRIPT_DIRS ${CMAKE_SOURCE_DIR}/scripts
                INCLUDES ${CMAKE_SOURCE_DIR}/engine)

How it works:

Features:

The #line check: clangd reports the real line of the generated file, not the #line line. So the generated C++ keeps its #line directives. No translator option is necessary.

From C++ to the script:

Limits:

The tests are in tests/integration/ls/ (LanguageServer.*). They run the server on a thread with an LSP client over pipes. The clangd tests are skipped when clangd is missing. Set HOT_LS_CLANGD_LOG=file to get the clangd log of a test.

Formatter rules

The formatter of hot-ls works on a token stream. It keeps the comments and the literals as tokens. It does not parse the script. The code is src/ls/format.cpp. The function format_hot is pure. It is idempotent and it never changes a token: only white space changes. Tests check this on all example scripts.

Range formatting runs the formatter on the whole text. The edit holds the new text of the lines in the range only. A line inside a string or a block comment does not change.