vscode-languageserver-textdocument#TextEdit TypeScript Examples
The following examples show how to use
vscode-languageserver-textdocument#TextEdit.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: server.ts From vscode-groovy-lint with GNU General Public License v3.0 | 6 votes |
// Handle formatting request from client
connection.onDocumentFormatting(async (params: DocumentFormattingParams): Promise<TextEdit[]> => {
const { textDocument } = params;
debug(`Formatting request received from client for ${textDocument.uri} with params ${JSON.stringify(params)}`);
if (params && params.options.tabSize) {
docManager.updateDocumentSettings(textDocument.uri, { tabSize: params.options.tabSize });
}
const document = docManager.getDocumentFromUri(textDocument.uri);
const textEdits: TextEdit[] = await docManager.formatTextDocument(document);
// Lint again the sources
setTimeout(async () => {
const documentUpdated = docManager.getDocumentFromUri(textDocument.uri);
await docManager.validateTextDocument(documentUpdated);
}, 500);
// Return textEdits to client that will apply them
return textEdits;
});
Example #2
Source File: DocumentsManager.ts From vscode-groovy-lint with GNU General Public License v3.0 | 5 votes |
// Format a text document
async formatTextDocument(textDocument: TextDocument): Promise<TextEdit[]> {
return await this.validateTextDocument(textDocument, { format: true });
}
Example #3
Source File: clientUtils.ts From vscode-groovy-lint with GNU General Public License v3.0 | 5 votes |
// Create a TextDocumentEdit that will be applied on client workspace
export function createTextDocumentEdit(docManager: DocumentsManager, textDocument: TextDocument, updatedSource: string, where: any = {}): TextDocumentEdit {
const textEdit: TextEdit = createTextEdit(docManager, textDocument, updatedSource, where);
const textDocEdit: TextDocumentEdit = TextDocumentEdit.create({ uri: textDocument.uri, version: textDocument.version }, [textEdit]);
return textDocEdit;
}
Example #4
Source File: clientUtils.ts From vscode-groovy-lint with GNU General Public License v3.0 | 5 votes |
// Create text edit for the whole file from updated source
export function createTextEdit(docManager: DocumentsManager, textDocument: TextDocument, updatedSource: string, where: any = {}): TextEdit {
const allLines = docManager.getTextDocumentLines(textDocument);
// If range is not sent, replace all file lines
let textEdit: TextEdit;
// Insert at position
if (where.insertLinePos || where.insertLinePos === 0) {
allLines.splice(where.insertLinePos, 0, updatedSource);
textEdit = {
range: {
start: { line: 0, character: 0 },
end: { line: allLines.length - 1, character: allLines[allLines.length - 1].length }
},
newText: allLines.join(os.EOL)
};
}
// Replace line at position
else if (where.replaceLinePos || where.replaceLinePos === 0) {
textEdit = {
range: {
start: { line: where.replaceLinePos, character: 0 },
end: { line: where.replaceLinePos, character: allLines[where.replaceLinePos].length }
},
newText: updatedSource
};
}
// Replace all source
else if (!where?.range) {
textEdit = {
range: {
start: { line: 0, character: 0 },
end: { line: allLines.length - 1, character: allLines[allLines.length - 1].length }
},
newText: updatedSource
};
}
// Provided range
else {
textEdit = {
range: where.range,
newText: updatedSource
};
}
return textEdit;
}
Example #5
Source File: DocumentsManager.ts From vscode-groovy-lint with GNU General Public License v3.0 | 4 votes |
// Validate a text document by calling linter
async validateTextDocument(textDocument: TextDocument, opts: any = {}): Promise<TextEdit[]> {
// Find if document is already being formatted or fixed
const currentLintsOnDoc = this.currentlyLinted.filter((currLinted) =>
currLinted.uri === textDocument.uri
);
const duplicateLintsOnDoc = currentLintsOnDoc.filter((currLinted) =>
!this.isUpdateRequest(currLinted.options) &&
currLinted.source === textDocument.getText()
);
const currentActionsOnDoc = currentLintsOnDoc.filter((currLinted) =>
this.isUpdateRequest(currLinted.options)
);
// Duplicate lint request with same doc content: do not trigger a new lint as there is a current one
if (duplicateLintsOnDoc.length > 0 && !this.isUpdateRequest(opts)) {
return Promise.resolve([]);
}
// Current document is not currently formatted/fixed, let's lint it now !
else if (currentActionsOnDoc.length === 0 &&
(!(this.isUpdateRequest(opts) && currentLintsOnDoc.length > 0))
) {
// Add current lint in currentlyLinted
const source = textDocument.getText();
this.currentlyLinted.push({ uri: textDocument.uri, options: opts, source: source });
const res = await executeLinter(textDocument, this, opts);
// Remove current lint from currently linted
const justLintedPos = this.currentlyLinted.findIndex((currLinted) =>
JSON.stringify({ uri: currLinted.uri, options: currLinted.options }) === JSON.stringify({ uri: textDocument.uri, options: opts }) &&
currLinted.source === source);
this.currentlyLinted.splice(justLintedPos, 1);
// Check if there is another lint in queue for the same file
const indexNextInQueue = this.queuedLints.findIndex((queuedItem) => queuedItem.uri === textDocument.uri);
// There is another lint in queue for the same file: process it
if (indexNextInQueue > -1) {
const lintToProcess = this.queuedLints[indexNextInQueue];
this.queuedLints.splice(indexNextInQueue, 1);
debug(`Run queued lint for ${textDocument.uri} (${JSON.stringify(lintToProcess.options || '{}')})`);
this.validateTextDocument(textDocument, lintToProcess.options).then(async (resVal) => {
// If format has not been performed by queue request , lint again after it is processed
if (lintToProcess.options.format === true, resVal && resVal.length > 0) {
const documentUpdated = this.getDocumentFromUri(textDocument.uri);
const newDoc = this.getUpToDateTextDocument(documentUpdated);
this.validateTextDocument(newDoc);
}
// If fix has not been performed by queue request , lint again after it is processed
else if (lintToProcess.options.fix === true) {
const documentUpdated = this.getDocumentFromUri(textDocument.uri);
const newDoc = this.getUpToDateTextDocument(documentUpdated);
this.validateTextDocument(newDoc);
}
});
return Promise.resolve([]);
} else {
return res;
}
}
// Document is currently formatted or fixed: add the request in queue !
else {
// gather current lints details
const currentFormatsOnDoc = currentActionsOnDoc.filter((currLinted) => currLinted.options && currLinted.options.format === true);
const currentFixesOnDoc = currentActionsOnDoc.filter((currLinted) => currLinted.options && currLinted.options.fix === true);
// Format request and no current format or fix: add in queue
if (opts.format === true && currentFormatsOnDoc.length === 0 && currentFixesOnDoc.length === 0) {
// add applyNow option because TextEdits won't be returned to formatting provided. edit textDocument directly from language server
opts.applyNow = true;
this.queuedLints.push({ uri: textDocument.uri, options: opts });
debug(`Added in queue: ${textDocument.uri} (${JSON.stringify(opts)})`);
}
// Fix request and no current fix: add in queue
else if (opts.fix === true && currentFixesOnDoc.length === 0) {
this.queuedLints.push({ uri: textDocument.uri, options: opts });
debug(`Added in queue: ${textDocument.uri} (${JSON.stringify(opts || '{}')})`);
}
// All other cases: do not add in queue, else actions would be redundant
else {
debug(`WE SHOULD NOT BE HERE : ${textDocument.uri} (${JSON.stringify(opts || '{}')})`);
}
return Promise.resolve([]);
}
}
Example #6
Source File: linter.ts From vscode-groovy-lint with GNU General Public License v3.0 | 4 votes |
// Validate a groovy file (just lint, or also format or fix)
export async function executeLinter(textDocument: TextDocument, docManager: DocumentsManager, opts: any = { fix: false, format: false, showDocumentIfErrors: false, force: false }): Promise<TextEdit[]> {
debug(`Request execute npm-groovy-lint for ${textDocument.uri} with options ${JSON.stringify(opts)}`);
const perfStart = performance.now();
// Get settings and stop if action not enabled
let settings = await docManager.getDocumentSettings(textDocument.uri);
// Linter disabled
if (settings.enable === false) {
debug(`VsCodeGroovyLint is disabled: activate it in VsCode GroovyLint settings`);
return Promise.resolve([]);
}
// Formatter disabled
if (opts.format && settings.format.enable === false) {
debug(`Formatter is disabled: activate it in VsCode settings`);
return Promise.resolve([]);
}
// Fixer disabled
if (opts.fix && settings.fix.enable === false) {
debug(`Fixing is disabled: activate it in VsCode GroovyLint settings`);
return Promise.resolve([]);
}
// In case lint was queues, get most recent version of textDocument
textDocument = docManager.getUpToDateTextDocument(textDocument);
let source: string = textDocument.getText();
// Propose to replace tabs by spaces if there are, because CodeNarc hates tabs :/
const fileNm = path.basename(textDocument.uri);
source = await manageFixSourceBeforeCallingLinter(source, textDocument, docManager);
// If user was prompted and did not respond, do not lint
if (source === 'cancel') {
debug(`User did not answer to the question: leave`);
return Promise.resolve([]);
}
// If file is empty, do not lint
else if (source === '') {
debug(`Empty file: no sources to lint`);
return Promise.resolve([]);
}
// Check if there is an existing NpmGroovyLint instance with same source (except if format, fix or force)
let isSimpleLintIdenticalSource = false;
const prevLinter = docManager.getDocLinter(textDocument.uri);
if (prevLinter && prevLinter.options.source === source && ![opts.format, opts.fix, opts.force].includes(true)) {
isSimpleLintIdenticalSource = true;
}
// Manage format & fix params
let format = false;
let verb = 'analyzing';
// Add format param if necessary
if (opts.format) {
format = true;
verb = 'formatting';
}
// Add fix param if necessary
let fix = false;
if (opts.fix) {
fix = true;
verb = 'auto-fixing';
}
// Remove already existing diagnostics except if format
await docManager.resetDiagnostics(textDocument.uri, { verb: verb, deleteLinter: !isSimpleLintIdenticalSource });
// Get a new task id
const linterTaskId = docManager.getNewTaskId();
// If the first lint request is not completed yet, wait for it, to be sure the CodeNarc server is already running to process next requests
if (linterTaskId > 1 && docManager.getRuleDescriptions().size === 0) {
debug('Wait for initial lint request to be completed before running the following ones');
await new Promise((resolve) => {
const waitSrvInterval = setInterval(() => {
if (docManager.getRuleDescriptions().size > 0) {
clearInterval(waitSrvInterval);
resolve(true);
}
}, 300);
// FailSafe just in case... but we shouldn't get there
setTimeout(() => {
if (docManager.getRuleDescriptions().size === 0) {
clearInterval(waitSrvInterval);
resolve(true);
}
}, 120000);
});
}
// Notify client that lint is starting
docManager.connection.sendNotification(StatusNotification.type, {
id: linterTaskId,
state: 'lint.start' + (fix ? '.fix' : format ? '.format' : ''),
documents: [{ documentUri: textDocument.uri }],
lastFileName: fileNm
});
// Build NmpGroovyLint config
const npmGroovyLintConfig: any = {
source: source,
sourcefilepath: URI.parse(textDocument.uri).fsPath,
parse: true, // Parse by default but not if format or fix mode
nolintafter: true,
loglevel: (format) ? 'info' : settings.basic.loglevel,
returnrules: docManager.getRuleDescriptions().size > 0 ? false : true,
insight: ((settings?.insight?.enable) ? true : false),
output: 'none',
verbose: settings.basic.verbose
};
const npmGroovyLintExecParam: any = {};
// Request formatting
if (format) {
npmGroovyLintConfig.format = true;
npmGroovyLintConfig.parse = false;
} else if (fix) {
// Request fixing
npmGroovyLintConfig.fix = true;
npmGroovyLintConfig.parse = false;
// Request fixing only some rules
if (opts.fixrules) {
npmGroovyLintConfig.rulesets = opts.fixrules.join(',');
npmGroovyLintConfig.fixrules = opts.fixrules.join(',');
}
}
else {
// Calculate requestKey (used to cancel current lint when a duplicate new one is incoming) only if not format or fix
const requestKey = npmGroovyLintConfig.sourcefilepath + '-' + npmGroovyLintConfig.output;
npmGroovyLintExecParam.requestKey = requestKey;
}
let linter;
// Use generic config file if defined in VsCode
if (settings.basic.config) {
npmGroovyLintConfig.config = settings.basic.config ;
}
// Add Indent size provided by VsCode API
if (settings.tabSize && settings.format.useDocumentIndentSize === true) {
npmGroovyLintConfig.rulesets = `Indentation{"spacesPerIndentLevel":${settings.tabSize}}`;
npmGroovyLintConfig.rulesetsoverridetype = "appendConfig";
}
// Disable Indentation rule if Indent size setting is not found
else if (settings.format.useDocumentIndentSize === true) {
npmGroovyLintConfig.rulesets = `Indentation{"enabled":false}`;
npmGroovyLintConfig.rulesetsoverridetype = "appendConfig";
}
// Java & options override
if (settings.java.executable) {
npmGroovyLintConfig.javaexecutable = settings.java.executable;
}
if (settings.java.options) {
npmGroovyLintConfig.javaoptions = settings.java.options;
}
// If source has not changed, do not lint again
if (isSimpleLintIdenticalSource === true) {
debug(`Ignoring new analyze of ${textDocument.uri} as its content has not changed since previous lint`);
linter = prevLinter;
}
else {
// Run npm-groovy-lint linter/fixer
docManager.deleteDocLinter(textDocument.uri);
console.info(`Start ${verb} ${textDocument.uri}`);
linter = new NpmGroovyLint(npmGroovyLintConfig, npmGroovyLintExecParam);
try {
await linter.run();
if (!format) {
docManager.setDocLinter(textDocument.uri, linter);
}
// Managed cancelled lint case
if (linter.status === 9) {
docManager.connection.sendNotification(StatusNotification.type, {
id: linterTaskId,
state: 'lint.cancel',
documents: [{ documentUri: textDocument.uri }],
lastFileName: fileNm
});
return Promise.resolve([]);
} else if (linter.status !== 0 && linter.error && linter.error.msg) {
// Fatal unexpected error: display in console
console.error('===========================================================================');
console.error('===========================================================================');
console.error('npm-groovy-lint error: ' + linter.error.msg + '\n' + linter.error.stack);
console.error(`If you still have an error, post an issue to get help: ${issuesUrl}`);
console.error('===========================================================================');
console.error('===========================================================================');
// Notify UI of the error
docManager.connection.sendNotification(StatusNotification.type, {
id: linterTaskId,
state: 'lint.error',
documents: [{ documentUri: textDocument.uri }],
lastFileName: fileNm
});
// If user decided so, do not display future crashes
if (docManager.ignoreNotifyCrashes === true) {
return Promise.resolve([]);
}
// Display message to user
const doNotDisplayAgain = 'Do not display again';
const reportErrorLabel = 'Report error';
let errorMessageForUser = `There has been an unexpected error while calling npm-groovy-lint. Please join the end of the logs in Output/GroovyLint if you report the issue`;
await new Promise(resolve => {
require("find-java-home")((err: any) => {
if (err) {
errorMessageForUser = "Java is required to use VsCode Groovy Lint, as CodeNarc is written in Java/Groovy. Please install Java (version 8 minimum) https://www.java.com/download ,then type \"java -version\" in command line to verify that the installation is correct";
}
resolve(true);
});
});
const msg: ShowMessageRequestParams = {
type: MessageType.Error,
message: errorMessageForUser,
actions: [
{ title: reportErrorLabel },
{ title: doNotDisplayAgain }
]
};
const res = await docManager.connection.sendRequest(ShowMessageRequest.type, msg);
// Open repo issues page if use clicks on Report
if (res?.title === reportErrorLabel) {
docManager.connection.sendNotification(OpenNotification.type, { url: issuesUrl });
}
else if (res?.title === doNotDisplayAgain) {
docManager.ignoreNotifyCrashes = true;
}
return Promise.resolve([]);
}
} catch (e) {
// If error, send notification to client
const ex = e as any ;
console.error('VsCode Groovy Lint error: ' + ex.message + '\n' + ex.stack);
debug(`Error processing ${textDocument.uri}` + ex.message + '\n' + ex.stack);
docManager.connection.sendNotification(StatusNotification.type, {
id: linterTaskId,
state: 'lint.error',
documents: [{ documentUri: textDocument.uri }],
lastFileName: fileNm
});
return Promise.resolve([]);
}
console.info(`Completed ${verb} ${textDocument.uri} in ${(performance.now() - perfStart).toFixed(0)} ms`);
}
// Parse results
const lintResults = linter.lintResult || {};
const { diagnostics, fixFailures } = parseLinterResults(lintResults, source, textDocument, docManager);
// Store rules descriptions if returned
if (lintResults.rules) {
debug(`Store rule descriptions from NpmGroovyLint`);
docManager.setRuleDescriptions(lintResults.rules);
}
textDocument = docManager.getUpToDateTextDocument(textDocument);
const sourceAfterLintButBeforeApply: string = textDocument.getText();
let textEdits: TextEdit[] = [];
// Check if the document has been manually updated during the format or fix
if ([format, fix].includes(true) && sourceAfterLintButBeforeApply !== source) {
// Show message to user and propose to process again the format or fix action
debug(`Source of ${textDocument.uri} has been updated: updates not applied`);
const processAgainTitle = 'Process Again';
const msg: ShowMessageRequestParams = {
type: MessageType.Warning,
message: `GroovyLint did not update the sources of ${path.parse(textDocument.uri).name} as it has been manually during the request`,
actions: [
{ title: processAgainTitle }
]
};
docManager.connection.sendRequest('window/showMessageRequest', msg).then(async (rqstResp: any) => {
// If user clicked Process Again, run again the related command
if (rqstResp?.title === processAgainTitle) {
const commandAgain = (format) ? 'vscode.executeFormatDocumentProvider' : (fix) ? COMMAND_LINT_FIX.command : '';
debug(`Process again command ${commandAgain} after user clicked on message`);
await docManager.connection.client.executeCommand(commandAgain, [textDocument.uri], {});
}
});
}
// Send updated sources to client if format mode
else if (format === true && linter.status === 0 && linter.lintResult.summary.totalFixedNumber > 0) {
const updatedSource = getUpdatedSource(linter, source);
if (opts.applyNow) {
await applyTextDocumentEditOnWorkspace(docManager, textDocument, updatedSource);
}
else {
const textEdit = createTextEdit(docManager, textDocument, updatedSource);
textEdits.push(textEdit);
}
// Display fix failures if existing
await notifyFixFailures(fixFailures, docManager);
}
// Send updated sources to client if fix mode
else if (fix === true && linter.status === 0 && linter.lintResult.summary.totalFixedNumber > 0) {
const updatedSource = getUpdatedSource(linter, source);
await applyTextDocumentEditOnWorkspace(docManager, textDocument, updatedSource);
// Display fix failures if existing
await notifyFixFailures(fixFailures, docManager);
}
// Call if from lintFolder: open document and display diagnostics if
if (opts.showDocumentIfErrors == true && diagnostics.length > 0) {
await docManager.connection.sendNotification(OpenNotification.type, { uri: textDocument.uri, preview: false });
await docManager.updateDiagnostics(textDocument.uri, diagnostics);
}
// Remove diagnostics in case the file has been closed since the lint request
else if (!docManager.isDocumentOpenInClient(textDocument.uri) && !(opts.displayErrorsEvenIfDocumentClosed === true)) {
await docManager.updateDiagnostics(textDocument.uri, []);
}
// Update diagnostics if this is not a format or fix calls (for format & fix, a lint is called just after)
else if (![format, fix].includes(true)) {
await docManager.updateDiagnostics(textDocument.uri, diagnostics);
}
// Notify client of end of linting
docManager.connection.sendNotification(StatusNotification.type, {
id: linterTaskId,
state: 'lint.end' + (fix ? '.fix' : format ? '.format' : ''),
documents: [{
documentUri: textDocument.uri
}],
lastFileName: fileNm,
lastLintTimeMs: performance.now() - perfStart
});
// Return textEdits only in case of formatting request
return Promise.resolve(textEdits);
}