applyWorkspaceEdit function
Future<List<LspAppliedChange> >
applyWorkspaceEdit(
- ExecutionEnv env,
- LspWorkspaceEdit edit, {
- Map<
String, int> openFileVersions = const {},
Applies edit through env and returns the per-file changes.
Atomicity: edits for EVERY file are validated (overlap + bounds via a dry-run on the current content) and the version guard is checked before the first write; a failure leaves the workspace untouched.
Version guard: when the server's documentChanges advertised a
non-null textDocument.version for a URI and openFileVersions tracks
that URI at a different version, the edit is stale (the document moved
since the server computed it) and application is rejected up front.
Implementation
Future<List<LspAppliedChange>> applyWorkspaceEdit(
ExecutionEnv env,
LspWorkspaceEdit edit, {
Map<String, int> openFileVersions = const {},
}) async {
_guardVersions(env, edit, openFileVersions);
// Phase 1: validate and compute new contents without writing anything.
final planned = <String, String>{};
final counts = <String, int>{};
for (final entry in edit.textEdits.entries) {
final edits = entry.value;
if (edits.isEmpty) continue;
final path = uriToFile(entry.key);
final read = await env.readTextFile(path);
if (read.isErr) {
throw StateError('cannot apply LSP edits: ${read.errorOrNull}');
}
planned[path] = applyTextEditsToString(read.valueOrNull!, edits);
counts[path] = edits.length;
}
// Phase 2: write.
final applied = <LspAppliedChange>[];
for (final entry in planned.entries) {
final write = await env.writeFile(entry.key, entry.value);
if (write.isErr) {
throw StateError('cannot apply LSP edits: ${write.errorOrNull}');
}
applied.add(
LspAppliedChange(path: entry.key, editCount: counts[entry.key]!),
);
}
return applied;
}