How do I get a Language Server Extension to trigger the creation of a new file , edit it, and display it in the attached client's workspace?
I have a LSP extension written with vscode-languageserver in node.js that executes a Command on the server via onExecuteCommand. I want this server-side command to trigger the client to create a new text file, populate it with some text, so it appears on the client's workspace list of open files.
Looking at https://github.com/microsoft/vscode-languageserver-node/blob/master/client-tests/src/helpers.test.ts I believe what I need to do is create a WorkspaceChange object, run createFile(), apply some changes (.insert) then tell the client to apply the edits via connection.workspace.applyEdit() but this does not work - no file is created and no errors are thrown in debugger.
Here is my code inside my server's onExecuteCommand:
//add some text
const textToAdd: string = "test string";
//create new WorkspaceChange obj
let workspaceChange = new WorkspaceChange();
//uri of the file we want to create
let newuri = 'file:///c:/temp/create.txt';
//make a TextEditChange obj. Fails if you do not supply version
let change = workspaceChange.getTextEditChange({ uri: newuri, version: 10 });
// give it some text
change.insert(Position.create(0, 1), textToAdd);
// add a createFile documentChange to the workspaceChange
workspaceChange.createFile(newuri);
// pass these edits to the client to apply:
let reply = connection.workspace.applyEdit(workspaceChange.edit);
console.log(reply); //always <Pending>
If I supply a non-existent file name, then the process fails - no file is created or opened in the workspace.
However if I supply an existing filename, the edits are applied and the file is opened in the workspace as expected.
I thought it was because I was supplying an edit prior to a createFile, but if I run getTextEditChange() before createFile() then the process fails with error "Workspace edit is not configured for document changes"
Thanks for the kick, yes I got this working some time later
It is implemented here: https://github.com/proclaimforum/vscode-proclaimscript-language/blob/master/server/src/server.ts
Lines 476 onwards are of note, where:
I copy the relevant code section below for reference, but have a look at the github link for full implementation, including setting up the client connection etc, setting capabilities etc.
//uri of new file
let currentPath :string = (thisdoc.uri).substr(0,thisdoc.uri.lastIndexOf('/'));
let newuri = currentPath+'/syntaxcheck.txt';
//construct a CreateFile variable
let createFile: CreateFile = { kind: 'create', uri: newuri };
//and make into array
let createFiles: CreateFile[] = [];
createFiles.push(createFile);
//make a new workspaceEdit variable, specifying a createFile document change
var workspaceEdit: WorkspaceEdit = { documentChanges: createFiles };
//pass to client to apply this edit
await connection.workspace.applyEdit(workspaceEdit);
//To insert the text (and pop up the window), create array of TextEdit
let textEdit: TextEdit[] = [];
//let document = documents.get(newuri);
let documentRange: Range = Range.create(0, 0, Number.MAX_VALUE, Number.MAX_VALUE);
//populate with the text, and where to insert (surely this is what workspaceChange.insert is for?)
let textEdits: TextEdit = { range: documentRange, newText: syntaxmessage };
textEdit.push(textEdits);
//make a new array of textDocumentEdits, containing our TextEdit (range and text)
let textDocumentEdit = TextDocumentEdit.create({ uri: newuri, version: 1 }, textEdit);
let textDocumentEdits: TextDocumentEdit[] = [];
textDocumentEdits.push(textDocumentEdit);
//set our workspaceEdit variable to this new TextDocumentEdit
workspaceEdit = { documentChanges: textDocumentEdits };
//and finally apply this to our workspace.
// we can probably do this some more elegant way
connection.workspace.applyEdit(workspaceEdit);