Repository navigation
[Enhancement] show a warning or error if the language server gets an languageId that is not supported by RobotCode #575
Description
First of all thank you for this awesome tool!
Describe the bug
I use Helix editor with robotcode language-server --stdio as a language server. I noticed that the file I open first or the files that are already open when robotcode is (re-)started are ignored by the language server - there are no suggestions and features like "go to definition" do not work, the language server seems to just return result null. But when I open another file after robotcode finished starting up, it all works fine for that file.
Below are some of the logs of the JSON messages (obtained from helix logs via hx -v) between the editor and language server, unfortunately I have not found an option to get more debug output out of the language server.
To me (as somebody who knows nothing about LSP) it looks like the first textDocument/didOpen is not handled properly by the language server which is why it does not provide diagnostics and just responds to methods like textDocument/definition with "result": null.
Steps To Reproduce
Steps to reproduce the behavior:
- Open
hx -v(with the language server configured) - Open a robot file
- Open a different robot file
- Notice that the first-opened file does not have working LSP features (no suggestions, no goto definition) and the second one does
This was reproduced with a directory containing nothing but this file twice:
*** Test Cases ***
My Example Test
No OperationExpected behavior
LSP features work for both opened files.
Logs
When opening the first file:
2026-02-26T09:43:13.862 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{"general":{"positionEncodings":["utf-8","utf-32","utf-16"]},"textDocument":{"codeAction":{"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["","quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}},"dataSupport":true,"disabledSupport":true,"isPreferredSupport":true,"resolveSupport":{"properties":["edit","command"]}},"completion":{"completionItem":{"deprecatedSupport":true,"insertReplaceSupport":true,"resolveSupport":{"properties":["documentation","detail","additionalTextEdits"]},"snippetSupport":true,"tagSupport":{"valueSet":[1]}},"completionItemKind":{}},"formatting":{"dynamicRegistration":false},"hover":{"contentFormat":["markdown"]},"inlayHint":{"dynamicRegistration":false},"publishDiagnostics":{"tagSupport":{"valueSet":[1,2]},"versionSupport":true},"rename":{"dynamicRegistration":false,"honorsChangeAnnotations":false,"prepareSupport":true},"signatureHelp":{"signatureInformation":{"activeParameterSupport":true,"documentationFormat":["markdown"],"parameterInformation":{"labelOffsetSupport":true}}}},"window":{"workDoneProgress":true},"workspace":{"applyEdit":true,"configuration":true,"didChangeConfiguration":{"dynamicRegistration":false},"didChangeWatchedFiles":{"dynamicRegistration":true,"relativePatternSupport":false},"executeCommand":{"dynamicRegistration":false},"fileOperations":{"didRename":true,"willRename":true},"inlayHint":{"refreshSupport":false},"symbol":{"dynamicRegistration":false},"workspaceEdit":{"documentChanges":true,"failureHandling":"abort","normalizesLineEndings":false,"resourceOperations":["create","rename","delete"]},"workspaceFolders":true}},"clientInfo":{"name":"helix","version":"25.07.1 (a05c151b)"},"processId":25760,"rootPath":"/home/etaric/src/playground/robot/robotcode-bugreport","rootUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport","workspaceFolders":[{"name":"robotcode-bugreport","uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport"}]},"id":0}
2026-02-26T09:43:14.277 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":0,"result":{"capabilities":{"positionEncoding":"utf-16","textDocumentSync":{"openClose":true,"change":2,"willSave":true,"willSaveWaitUntil":true,"save":{"includeText":true}},"completionProvider":{"triggerCharacters":[" ","*","\t",".","/","{","=","/"],"resolveProvider":true,"completionItem":{"labelDetailsSupport":true},"workDoneProgress":true},"hoverProvider":{"workDoneProgress":true},"signatureHelpProvider":{"triggerCharacters":[" ","\t"],"retriggerCharacters":[" ","\t"]},"definitionProvider":true,"implementationProvider":true,"referencesProvider":{"workDoneProgress":true},"documentHighlightProvider":{"workDoneProgress":true},"codeActionProvider":{"codeActionKinds":["refactor.extract.function","refactor.surround","quickfix","source"],"resolveProvider":true},"codeLensProvider":{"resolveProvider":true},"workspaceSymbolProvider":true,"documentFormattingProvider":{"workDoneProgress":true},"documentRangeFormattingProvider":{"workDoneProgress":true},"renameProvider":{"prepareProvider":true,"workDoneProgress":true},"foldingRangeProvider":true,"selectionRangeProvider":{"workDoneProgress":true},"executeCommandProvider":{"commands":[]},"semanticTokensProvider":{"legend":{"tokenTypes":["namespace","type","class","enum","interface","struct","typeParameter","parameter","variable","property","enumMember","event","function","method","macro","keyword","modifier","comment","string","number","regexp","operator","decorator","settingImport","setting","header","headerSettings","headerVariable","headerTestcase","headerTask","headerComment","headerKeyword","testcaseName","keywordName","controlFlow","argument","variable","keywordCall","keywordCallInner","bddPrefix","nameCall","continuation","separator","terminator","forSeparator","variableBegin","variableEnd","expressionBegin","expressionEnd","variableExpression","escape","namespace","error","config","namedArgument","var","documentation"],"tokenModifiers":["declaration","definition","readonly","static","deprecated","abstract","async","modification","documentation","defaultLibrary","builtin","embedded"]},"full":true},"inlineValueProvider":{"workDoneProgress":true,"documentSelector":[{"language":"robotframework"}]},"inlayHintProvider":{},"workspace":{"workspaceFolders":{"supported":true,"changeNotifications":"81bd7109-5584-4549-951a-4d6f8e0c7854"},"fileOperations":{"didCreate":{"filters":[{"pattern":{"glob":"**/*.{yaml,robot,py,yml,resource}"}}]},"willCreate":{"filters":[{"pattern":{"glob":"**/*.{yaml,robot,py,yml,resource}"}}]},"didRename":{"filters":[{"pattern":{"glob":"**/*.{yaml,robot,py,yml,resource}"}}]},"willRename":{"filters":[{"pattern":{"glob":"**/*.{yaml,robot,py,yml,resource}"}}]},"didDelete":{"filters":[{"pattern":{"glob":"**/*.{yaml,robot,py,yml,resource}"}}]},"willDelete":{"filters":[{"pattern":{"glob":"**/*.{yaml,robot,py,yml,resource}"}}]}}}},"serverInfo":{"name":"RobotCode Language Server","version":"2.2.0"}}}
2026-02-26T09:43:14.277 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","method":"initialized","params":{}}
2026-02-26T09:43:14.277 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"languageId":"robot","text":"*** Test Cases ***\nMy Example Test\n No Operation\n","uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example0.robot","version":0}}}
2026-02-26T09:43:14.282 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":1,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport","section":"robotcode.robot"}]}}
2026-02-26T09:43:14.282 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":1}
2026-02-26T09:43:14.283 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":2,"method":"workspace/configuration","params":{"items":[{"section":"robotcode.documentationServer"}]}}
2026-02-26T09:43:14.283 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":2}
2026-02-26T09:43:14.287 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":3,"method":"client/registerCapability","params":{"registrations":[{"id":"16a6790d-b40e-45cf-81da-465edcc35d3c","method":"workspace/didChangeWatchedFiles","registerOptions":{"watchers":[{"globPattern":"**/*.{robot,resource}","kind":5}]}}]}}
2026-02-26T09:43:14.287 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":4,"method":"client/registerCapability","params":{"registrations":[{"id":"81875a4e-36d0-48aa-b7cc-0cc07b743b2b","method":"workspace/didChangeWatchedFiles","registerOptions":{"watchers":[{"globPattern":"**/*.{yaml,robot,py,yml,resource}","kind":7}]}}]}}
2026-02-26T09:43:14.287 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":3}
2026-02-26T09:43:14.287 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":4}
2026-02-26T09:43:14.287 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":5,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport","section":"robotcode"}]}}
2026-02-26T09:43:14.287 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":5}
2026-02-26T09:43:14.289 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":6,"method":"window/workDoneProgress/create","params":{"token":"55c1db6c-d785-4ec6-b327-d40ced0da6e0"}}
2026-02-26T09:43:14.289 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"$/progress","params":{"token":"55c1db6c-d785-4ec6-b327-d40ced0da6e0","value":{"title":"RobotCode","kind":"begin","cancellable":false,"message":"Collect sources"}}}
2026-02-26T09:43:14.289 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":6}
2026-02-26T09:43:14.289 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"$/progress","params":{"token":"55c1db6c-d785-4ec6-b327-d40ced0da6e0","value":{"kind":"end"}}}
2026-02-26T09:43:14.290 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":7,"method":"window/workDoneProgress/create","params":{"token":"1d14484b-1e49-4f5f-b76e-1160af9c4d05"}}
2026-02-26T09:43:14.290 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":7}
2026-02-26T09:43:14.291 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"$/progress","params":{"token":"1d14484b-1e49-4f5f-b76e-1160af9c4d05","value":{"kind":"end"}}}
2026-02-26T09:43:14.291 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":8,"method":"window/workDoneProgress/create","params":{"token":"ca545fc4-9e0e-44f3-90f6-c0da1653e615"}}
2026-02-26T09:43:14.291 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":8}
2026-02-26T09:43:14.292 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":9,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example0.robot","section":"robotcode.analysis"}]}}
2026-02-26T09:43:14.292 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":9}
2026-02-26T09:43:14.295 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":10,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport","section":"robotcode.analysis.cache"}]}}
2026-02-26T09:43:14.295 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":10}
2026-02-26T09:43:14.296 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":11,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport","section":"robotcode.analysis.robot"}]}}
2026-02-26T09:43:14.296 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":11}
2026-02-26T09:43:14.306 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":12,"method":"client/registerCapability","params":{"registrations":[{"id":"2f280da0-f312-46d6-b11a-88286b83e3a3","method":"workspace/didChangeWatchedFiles","registerOptions":{"watchers":[{"globPattern":"/home/etaric/src/playground/robot/robotcode-bugreport/.venv/lib/python3.12/site-packages/robot/libraries/**"}]}}]}}
2026-02-26T09:43:14.306 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"$/progress","params":{"token":"ca545fc4-9e0e-44f3-90f6-c0da1653e615","value":{"kind":"end"}}}
2026-02-26T09:43:14.306 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":13,"method":"window/workDoneProgress/create","params":{"token":"60791b17-44dc-4e1f-8c87-6ca5196aa819"}}
2026-02-26T09:43:14.306 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":12}
2026-02-26T09:43:14.306 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":13}
2026-02-26T09:43:14.306 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"$/progress","params":{"token":"60791b17-44dc-4e1f-8c87-6ca5196aa819","value":{"kind":"end"}}}
When opening the second file:
2026-02-26T09:46:35.075 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"languageId":"robot","text":"*** Test Cases ***\nMy Example Test\n No Operation\n","uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example1.robot","version":0}}}
2026-02-26T09:46:36.375 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":14,"method":"window/workDoneProgress/create","params":{"token":"218fc89b-a36a-4a64-a757-973245785ef6"}}
2026-02-26T09:46:36.376 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":14}
2026-02-26T09:46:36.378 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"$/progress","params":{"token":"218fc89b-a36a-4a64-a757-973245785ef6","value":{"kind":"end"}}}
2026-02-26T09:46:36.379 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":15,"method":"window/workDoneProgress/create","params":{"token":"2a551ba2-b411-46f7-b0d1-da91bee6ae69"}}
2026-02-26T09:46:36.379 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":16,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport","section":"robotcode.robocop"}]}}
2026-02-26T09:46:36.380 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":15}
2026-02-26T09:46:36.380 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":16}
2026-02-26T09:46:36.452 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":17,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example1.robot","section":"robotcode.analysis.diagnosticModifiers"}]}}
2026-02-26T09:46:36.452 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":17}
2026-02-26T09:46:36.454 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example1.robot","diagnostics":[{"range":{"start":{"line":1,"character":0},"end":{"line":1,"character":15}},"message":"Missing documentation in 'My Example Test' test case","severity":2,"code":"DOC02-missing-doc-test-case","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc02-missing-doc-test-case"},"source":"robocop"},{"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":0}},"message":"Missing documentation in suite","severity":2,"code":"DOC03-missing-doc-suite","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc03-missing-doc-suite"},"source":"robocop"}],"version":0}}
2026-02-26T09:46:36.454 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example1.robot","diagnostics":[{"range":{"start":{"line":1,"character":0},"end":{"line":1,"character":15}},"message":"Missing documentation in 'My Example Test' test case","severity":2,"code":"DOC02-missing-doc-test-case","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc02-missing-doc-test-case"},"source":"robocop"},{"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":0}},"message":"Missing documentation in suite","severity":2,"code":"DOC03-missing-doc-suite","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc03-missing-doc-suite"},"source":"robocop"}],"version":0}}
2026-02-26T09:46:36.454 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example1.robot","diagnostics":[{"range":{"start":{"line":1,"character":0},"end":{"line":1,"character":15}},"message":"Missing documentation in 'My Example Test' test case","severity":2,"code":"DOC02-missing-doc-test-case","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc02-missing-doc-test-case"},"source":"robocop"},{"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":0}},"message":"Missing documentation in suite","severity":2,"code":"DOC03-missing-doc-suite","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc03-missing-doc-suite"},"source":"robocop"}],"version":0}}
2026-02-26T09:46:36.454 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example1.robot","diagnostics":[{"range":{"start":{"line":1,"character":0},"end":{"line":1,"character":15}},"message":"Missing documentation in 'My Example Test' test case","severity":2,"code":"DOC02-missing-doc-test-case","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc02-missing-doc-test-case"},"source":"robocop"},{"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":0}},"message":"Missing documentation in suite","severity":2,"code":"DOC03-missing-doc-suite","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc03-missing-doc-suite"},"source":"robocop"}],"version":0}}
2026-02-26T09:46:36.454 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"$/progress","params":{"token":"2a551ba2-b411-46f7-b0d1-da91bee6ae69","value":{"kind":"end"}}}
When doing a go to definition in the first file:
2026-02-26T09:56:30.003 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","method":"textDocument/definition","params":{"position":{"character":8,"line":2},"textDocument":{"uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example0.robot"}},"id":1}
2026-02-26T09:56:30.008 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":1,"result":null}
Additional context
None
Desktop (please complete the following information):
- Helix version: helix 25.07.1 (a05c151b)
- RobotCode Version: robotcode, version 2.2.0
- OS: Ubuntu 24.04.4 LTS
- Python Version: Python 3.12.3 (also tested with 3.13.12)
- RobotFramework Version: Robot Framework 7.4.1 (Python 3.12.3 on linux)
- RoboCop Version: robocop, version 6.10.1 (got no suggestions on 8.X)
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity
BrachystochroneSD commentedon Mar 26, 2026
I can reproduce the same behavior with Emacs + Eglot: the file that is already open when Eglot starts RobotCode gets no LSP features (no diagnostics, completion, goto definition; requests return
null). Files opened after the server has finished starting work normally.It looks like RobotCode doesn’t handle an “early”
textDocument/didOpen(sent right afterinitialized) correctly. In the failing trace,didOpenhappens before RobotCode finishes itsworkspace/configurationphase; in the working trace,didOpenhappens after more configuration/setup, and then diagnostics start.Here is the failing trace (didOpen very early; no publishDiagnostics ever for that URI)
Working trace (open file after server startup; diagnostics published)
For comparison,
robotframework_lsworks fine even whendidOpenis sent immediately afterinitialized(it publishes diagnostics for the initially opened file):This shows another Robot Framework LS handles the same ordering correctly (diagnostics are published for the initially opened file), so the issue is specific to RobotCode’s handling of early
didOpen/ initialization.Environment:
EDIT: Note that in helix logs and mine, the languageid is set to
robotand notrobotframework, let me investigate a bitd-biehl commentedon Mar 30, 2026
Sorry, I do not currently have Helix or Emacs set up, and I do not have enough time right now to test them properly.
One possible explanation is that the
languageIdis being set torobotinstead ofrobotframework. At the moment, the language server only supportsrobotframeworkas thelanguageId.I know that this works with Neovim using LSP support, and I have also tested it successfully with other editors such as Kate and QtCreator.
Could you try changing the
languageIdtorobotframeworkand see whether that fixes the problem?BrachystochroneSD commentedon Mar 31, 2026
I think that was the issue indeed!
seems to work when enforcing the language id (within emacs):
d-biehl commentedon Mar 31, 2026
super!!! @UniqueActive can you try this under helix?
BrachystochroneSD commentedon Mar 31, 2026
Note that it was hard to find the root cause, and the language server somehow was kind of work even with a wrong language id.
Maybe I miss something but wouldn't the language server fail with a message stating that the language id is not supported ?
UniqueActive commentedon Mar 31, 2026
Hi, thank you for looking into it @d-biehl ! I tried helix with
languageIdset to "robotframework" and it works correctly now.It would be nice to have one of these solutions:
languageIdresults in an error, not this strange semi-working state ;)If you don't intend on supporting the language id "robot" then I'll get this changed in helix's upstream default configuration.
d-biehl commentedon Mar 31, 2026
I need to take a deeper look at this, but I think the important part here is how
languageIdis intended to work in LSP.According to the LSP specification, text documents have a
languageIdso the server can identify the document language “to avoid re-interpreting the file extension”. It also says that for some listed programming languages certain ids are recommended, but that is a recommendation for those listed languages, not a general rule that every language must use one short or obvious identifier.That is also why I do not think the server should try to re-classify files purely from their extension. The client is the component that opens the document and decides which
languageIdit gets. The server is supposed to use that classification, not guess it again from the path.This is especially relevant for Robot Framework, because Robot Framework is not tied to a single extension. Resource files are recommended to use
.resource, but for backwards compatibility.robot,.txt, and.tsvalso work. In addition, Robot Framework also supports reStructuredText-based files such as.rstand.rest, and JSON-based files such as.jsonand.rsrc. So there is not a single extension that uniquely identifies “this is definitely Robot Framework”. On the contrary, several of these extensions clearly have meanings outside Robot Framework as well:.txtis completely generic,.rst/.restare associated with reStructuredText in general, and.jsonis of course a generic data format used everywhere.Because of that, I intentionally chose
robotframeworkas the language id and not justrobot.For me,
robotframeworkis the more precise and less ambiguous identifier.robotis too generic, and it is also already used by other tools in other contexts. If a client wants Robot Framework language features to work correctly, then the client should classify the document accordingly and use the properlanguageIdwhen opening it.So from my point of view, the issue is not that the server should switch to
robot, but that the client must decide whichlanguageIda file gets, and the server then uses exactly that classification.d-biehl commentedon Mar 31, 2026
I do not really know how this is configured in Helix or Emacs specifically, but I would assume they have some equivalent mechanism on the client side to decide how files are classified and which languageId is sent to the server, similar to how this is configured in VS Code.
d-biehl commentedon Mar 31, 2026
Also, if either of you already has a working Helix or Emacs setup for RobotCode, would you maybe be interested in contributing a small documentation section for that? We already have a small setup guide for Neovim, so it would be great to have similar documentation for other editors as well:
https://robotcode.io/04_tip_and_tricks/04_neovim_lsp_setup
I think that would probably help other users more than trying to make the server compensate for editor-specific client configuration issues.
BrachystochroneSD commentedon Mar 31, 2026
I agree with your points about
languageId, the client is responsible for classifying documents, androbotframeworkis the right choice given the ambiguity ofrobotand the variety of file extensions Robot Framework supports.From the Emacs side, the root cause is
robot-mode, which predates the broader file extension support and only associates with.robotfiles. It sets the language id torobotrather thanrobotframework. That's something to fix on the client/mode side, not in the server, no disagreement there.That said, one small improvement that could help users across all editors: when the server receives a
textDocument/didOpenwith alanguageIdthat isn'trobotframeworkbut the file extension suggests it could be a Robot Framework file (.robot,.resource, etc.), the server could send awindow/showMessagewarning, something like:This wouldn't change any server behavior or add any file-extension guessing logic. It's just a one-time hint to the user that their client configuration is off. Right now the server continue to work silently, which is hard to diagnose and leads to issues like this one being opened. A visible message would point people to the fix immediately, and redirect the problem to the client/modes.
Regarding the Emacs documentation, I'd be happy to contribute
d-biehl commentedon Mar 31, 2026
very cool!!!
I am not sure if a message is the right solution, maybe a log or a critical warning message in the log output or something like this, have to think about it...
d-biehl commentedon Apr 1, 2026
sorry closed this to early, wanted to make it an enhancement ...
[-][BUG] language-server ignores files opened early[/-][+][Enhancement] show a warning or error if the language server gets an languageId that is not supported by RobotCode[/+]UniqueActive commentedon Apr 2, 2026
Thank you for the detailed explanation regarding
languageId, it makes sense to keeprobotframeworkhere and instead just make this a logging enhancement. :)Regarding making a guide: helix has built-in LSP support and ships with language server configurations. I will update the upstream configuration with the correct
languageIdso that it should simply work out of the box, then a user would only need to install robotcode's language server - I don't think a guide is needed for that.UniqueActive commentedon May 28, 2026
My MR for fixed support in Helix was merged a few days ago so robotcode is supported properly in Helix master. A release was not tagged yet though.