The LSP helper communicates with the Language Server via stdin/stdout. In case of an LSP helper inside an emulator, the helper communicates with the Language Server via the (first) serial port.
The protocol is a binary protocol, consisting of 8-bit integers (BYTE), 32-bit integers (sent as Little Endian), and Strings (sent as NULL-terminated ASCII/UTF-8 strings). File content is transferred by a 32-bit length (in bytes) followed by the actual bytes of the file.
The Language server sends requests to the LSP Helper, which are answered by the
helper. In case the helper cannot answer the request, it sends STATUS_Invalid
(1) as a single byte. When a request has been handled, the language server can
send the next request.
There are 5 supported requests, determined by the first byte of the communication.
Value | Name | Description |
---|---|---|
100 | INST_GetModuleInfo | Send the content of a module file, and receive information about syntactic tokens, definitions, references, etc. |
101 | INST_AutoComplete | Send the prefix of a module file, and return possible completions for the last token of the prefix. |
102 | INST_ReFormat | Send the content of a module file and receive a list of tokens with their whitespace requirements before and after it, to aid in reformatting the file. |
103 | INST_SwitchEmbeddedMode | Switch the emulator to embedded mode where it only listens to RS232 and no other inputs. Only used by the Language Server if no emulator UI is provided. |
104 | INST_Exit | Exit the LSP helper. |
- BYTE:
INST_GetModuleInfo
(100) - INTEGER: Length of the file
- Content of the file
STATUS_OK
(0): No arguments, end of response, everything fineSTATUS_Invalid
(1): No arguments, end of response, something went wrongANSWER_ModuleName
(10): Name of the compiled module (String)ANSWER_ModuleImport
(11): Name of an imported module (String), used for dependency trackingANSWER_Error
(12): Position (INTEGER) and error message (C String)ANSWER_Warning
(60): Same for warning message (not used in Project Oberon)ANSWER_Information
(61): Same for information message (not used in Project Oberon)ANSWER_SymbolFileChanged
(13): No arguments, indicator that symbol file changed and dependent modules need to be re-analyzedANSWER_SyntaxElement
(14): Information about syntax element (see below)ANSWER_ProcedureStart
(15): Last syntax element was keywordPROCEDURE
that started a procedure (and not a procedure type declaration).ANSWER_ProcedureEnd
(16): Position (INTEGER) where the currently open procedure ends (i.e. semicolon). Used for outline and folding ranges.ANSWER_VarModified
(17): No arguments. The last syntax element was a variable name that is modified (e.g. by:=
symbol after it).ANSWER_RecordStart
(18): No arguments. last syntax element was a keyword that starts a record.ANSWER_RecordEnd
(19): No arguments. Last syntax element was a keyword that ends a record. Used for outline and folding ranges.ANSWER_NameExported
(20): Last syntax element was a*
which was used to export the previous syntax element.ANSWER_ImportAlias
(21): No arguments. Last syntax element which was reported as a module import was actually an import alias, next syntax element will be the module import instead.ANSWER_ProcParamStart
(22): Position (INTEGER) of an opening parenesthis that contains procedure parameters (used for context sensitive procedure signature help).ANSWER_CallParamStart
(23): Position (INTEGER) of an opening parenthesis that contains the parameters of a procedure invocation (for signature help).ANSWER_ParamNext
(24): Position (INTEGER) of a comma that starts the next parameterANSWER_ParamEnd
(25): Position (INTEGER) of the end of parametersANSWER_ForwardPointer
(26): No arguments. Last syntax element was a forward pointer that needs fixup once it is declared.ANSWER_ForwardPointerFixup
(27): Position (INTEGER) of pointer end, and position (INTEGER) of pointer target end. Used to fix up the forward pointer.ANSWER_DefinitionRepeat
(28): Last syntax element was a reference to a definition, that should not mark it as being used, but instead is only repeated due to syntax requirements (after anEND
keyword).ANSWER_DefinitionUsed
(29): Last syntax element was a definition that should be considered to be used, even if there is no export or reference assigned to it.ANSWER_DeclarationBlockStart
(30): Position (INTEGER) where a declaration block starts. A declaration block starts withVAR
,TYPE
, orCONST
keyword and goes to the next such keyword orBEGIN
.ANSWER_DeclarationBlockEnd
(31): Position (INTEGER) where the declaration block ends.ANSWER_DefinitionListStart
(32): Position (INTEGER) where a definition list starts. A definition list is a list of identifiers that are defined at that point and have a common type/valueANSWER_DefinitionListValue
(33): Position (INTEGER) where the type or value of that definition list startsANSWER_DefinitionListEnd
(34): Position (INTEGER) where the definition list endsANSWER_SymbolFileIndex
(35): Symbol file index (INTEGER), Module name (String, for re-exports), Offset of end of syntax element (INTEGER). Denotes that a symbol has been exported to the symbol file and may be referenced via the symbol file index from there.
A syntax element is part of the source code that has certain syntax properties (highlighting, definition, reference).
Each syntax element consists of the following arguments:
- INTEGER: Start position
- INTEGER: End position
- BYTE: Type (one of
SynOperator
(1),SynType
,SynKeyword
,SynString
,SynComment
,SynConstant
,SynUndefined
,SynModule
,SynVariable
,SynParameter
,SynRecordField
, orSynProcedure
(12)) - INTEGER: Definition end position
- STRING: Definition module name (omitted if definition end position is -1).
In case the definition end position and definition module name is the same as
the end position and current module name, this syntax element is the definition.
Otherwise this syntax element is a reference to the definition mentioned. A
negative definition end position (strictly less than -1) is a symbol file index,
which is mapped by the ANSWER_SymbolFileIndex
response packet when the
definition module name is/was parsed.
- BYTE:
INST_AutoComplete
(101) - INTEGER: Length of the file prefix
- Content of the file prefix
STATUS_OK
(0): No arguments, end of response, everything fineSTATUS_Invalid
(1): No arguments, end of response, something went wrongANSWER_Completion
(80): Syntax element constant (BYTE) and value (STRING) of a possible completion value.
The input file is divided into formatting tokens. Everything outside a formatting token needs to be whitespace. The token category describe what kind of white space should/may appear before or after the token. A category is a two-digit decimal integer, where each decimal digit has its own meaning:
x0
: No whitespace after token requestedx1
: Single whitespalce after token requestedx9
: Either no or single whitespace after token is acceptable0x
: No whitespace before token requested1x
: Single whitespace before token requested2x
: Line break before token requested3x
: Line break and empty line before token requested9x
: Either no or single white space before token is acceptable.
In case two adjacent tokens give different rules for the same white space between them, the token after the white space takes precedence.
- BYTE:
INST_ReFormat
(102) - INTEGER: Length of the file prefix
- Content of the file prefix
STATUS_OK
(0): No arguments, end of response, everything fineSTATUS_Invalid
(1): No arguments, end of response, something went wrongANSWER_FormatToken
(90): Start position (INTEGER), end position (INTEGER), and category (BYTE) of a formatting token.ANSWER_FormatTokenUpdate
(91): Change category (BYTE) of last token. Used when the token (like*
) has a category assigned by the lexer, but the category gets overwritten by the parser (e.g. module export instead of multiplication).ANSWER_IndentNextLine
(92): The line after the last token needs an indentation level higher than the current indentation level.ANSWER_OutdentThisLine
(93): In case the token is the first one of the line, this line needs an indentation level lower than the current indentation level. In case the token is in the middle of a line, apply the indentation to the next line instead.
- BYTE:
INST_SwitchEmbeddedMode
(103)
No response.
- BYTE:
INST_Exit
(104)
Communication stream is closed.