How To Work with Text Documents¶
Help Wanted!
This guide is incomplete and needs to be expanded upon to provide more details to cover topics including:
(Breif!) explanation of the position encoding handshake during
initializeUsing the
PositionCodecto convert between LSP and Python positions (and why it’s necessary)
If this is something you would like to help with, please open an issue or pull request (even if it is a draft!) on our GitHub, so that we don’t accicdentally duplicate your work.
This guide explains how to access TextDocuments via the Workspace in your language server.
Accessing Text Documents¶
The state of all TextDocuments in the user’s project are managed by the Workspace object attached to every language server.
Text documents are identified by their uri which is typically included with the params object for the current message.
Passing the uri to the get_text_document() method will return the corresponding document.
@server.feature(types.TEXT_DOCUMENT_DID_OPEN)
async def did_open(ls, params: types.DidOpenTextDocumentParams):
# Get document from workspace
text_doc = ls.workspace.get_text_document(params.text_document.uri)
Accessing Document Contents¶
Once you have a TextDocument you can access its contents via the source attribute.
@server.feature(types.TEXT_DOCUMENT_DID_OPEN)
async def did_open(ls, params: types.DidOpenTextDocumentParams):
text_doc = ls.workspace.get_text_document(params.text_document.uri)
contents = text_doc.source
...
It’s common to want to process the individual lines of a text document, in which case you can use the lines property to access all of the lines
@server.feature(types.TEXT_DOCUMENT_DID_OPEN)
async def did_open(ls, params: types.DidOpenTextDocumentParams):
text_doc = ls.workspace.get_text_document(params.text_document.uri)
for line in text_doc.lines:
...
Editing Text Documents¶
There are scenarios where you may want to edit the contents of a text document, for example when implementing a quickfix or refactoring command.
This is done by instructing the client to apply an edit on your behalf using the workspace/applyEdit request. The following example is taken from our example Code Lens server
@server.command("codeLens.evaluateSum")
def evaluate_sum(ls: LanguageServer, args: EvaluateSumArgs):
logging.info("arguments: %s", args)
document = ls.workspace.get_text_document(args.uri)
line = document.lines[args.line]
# Compute the edit that will update the document with the result.
answer = args.left + args.right
edit = types.TextDocumentEdit(
text_document=types.OptionalVersionedTextDocumentIdentifier(
uri=args.uri,
version=document.version,
),
edits=[
types.TextEdit(
new_text=f"{line.strip()} {answer}\n",
range=types.Range(
start=types.Position(line=args.line, character=0),
end=types.Position(line=args.line + 1, character=0),
),
)
],
)
# Apply the edit.
ls.workspace_apply_edit(
types.ApplyWorkspaceEditParams(
edit=types.WorkspaceEdit(document_changes=[edit]),
),
)