11import type * as atomIde from "atom-ide-base"
22import Convert from "../convert"
3- import { LanguageClientConnection , ApplyWorkspaceEditParams , ApplyWorkspaceEditResponse } from "../languageclient"
3+ import {
4+ LanguageClientConnection ,
5+ ApplyWorkspaceEditParams ,
6+ ApplyWorkspaceEditResponse ,
7+ WorkspaceEdit ,
8+ TextDocumentEdit ,
9+ CreateFile ,
10+ RenameFile ,
11+ DeleteFile ,
12+ DocumentUri
13+ } from "../languageclient"
414import { TextBuffer , TextEditor } from "atom"
15+ import * as fs from 'fs' ;
516
617/** Public: Adapts workspace/applyEdit commands to editors. */
718export default class ApplyEditAdapter {
@@ -33,33 +44,28 @@ export default class ApplyEditAdapter {
3344 }
3445
3546 public static async onApplyEdit ( params : ApplyWorkspaceEditParams ) : Promise < ApplyWorkspaceEditResponse > {
36- let changes = params . edit . changes || { }
37-
38- if ( params . edit . documentChanges ) {
39- changes = { }
40- params . edit . documentChanges . forEach ( ( change ) => {
41- if ( change && "textDocument" in change && change . textDocument ) {
42- changes [ change . textDocument . uri ] = change . edits
43- }
44- } )
45- }
46-
47- const uris = Object . keys ( changes )
47+ return ApplyEditAdapter . apply ( params . edit )
48+ }
4849
50+ public static async apply ( workspaceEdit : WorkspaceEdit ) : Promise < ApplyWorkspaceEditResponse > {
51+ ApplyEditAdapter . normalize ( workspaceEdit )
52+
4953 // Keep checkpoints from all successful buffer edits
5054 const checkpoints : Array < { buffer : TextBuffer ; checkpoint : number } > = [ ]
5155
52- const promises = uris . map ( async ( uri ) => {
53- const path = Convert . uriToPath ( uri )
56+ const promises = ( workspaceEdit . documentChanges || [ ] ) . map ( async ( edit ) : Promise < void > => {
57+ if ( ! TextDocumentEdit . is ( edit ) ) {
58+ return ApplyEditAdapter . handleResourceOperation ( edit )
59+ }
60+ const path = Convert . uriToPath ( edit . textDocument . uri )
5461 const editor = ( await atom . workspace . open ( path , {
5562 searchAllPanes : true ,
5663 // Open new editors in the background.
5764 activatePane : false ,
5865 activateItem : false ,
5966 } ) ) as TextEditor
6067 const buffer = editor . getBuffer ( )
61- // Get an existing editor for the file, or open a new one if it doesn't exist.
62- const edits = Convert . convertLsTextEdits ( changes [ uri ] )
68+ const edits = Convert . convertLsTextEdits ( edit . edits )
6369 const checkpoint = ApplyEditAdapter . applyEdits ( buffer , edits )
6470 checkpoints . push ( { buffer, checkpoint } )
6571 } )
@@ -81,6 +87,35 @@ export default class ApplyEditAdapter {
8187 return { applied }
8288 }
8389
90+ private static async handleResourceOperation ( edit : ( CreateFile | RenameFile | DeleteFile ) ) : Promise < void >
91+ {
92+ if ( edit . kind === 'delete' ) {
93+ return fs . promises . unlink ( Convert . uriToPath ( edit . uri ) )
94+ } else if ( edit . kind === 'rename' ) {
95+ return fs . promises . rename ( Convert . uriToPath ( edit . oldUri ) , Convert . uriToPath ( edit . newUri ) )
96+ } else if ( edit . kind === 'create' ) {
97+ return fs . promises . writeFile ( edit . uri , '' )
98+ }
99+ }
100+
101+ private static normalize ( workspaceEdit : WorkspaceEdit ) : void {
102+ const documentChanges = workspaceEdit . documentChanges || [ ]
103+
104+ if ( ! workspaceEdit . hasOwnProperty ( 'documentChanges' ) && workspaceEdit . hasOwnProperty ( 'changes' ) ) {
105+ Object . keys ( workspaceEdit . changes || [ ] ) . forEach ( ( uri : DocumentUri ) => {
106+ documentChanges . push ( {
107+ textDocument : {
108+ version : null ,
109+ uri : uri
110+ } ,
111+ edits : workspaceEdit . changes ! [ uri ]
112+ } )
113+ } )
114+ }
115+
116+ workspaceEdit . documentChanges = documentChanges
117+ }
118+
84119 /** Private: Do some basic sanity checking on the edit ranges. */
85120 private static validateEdit ( buffer : TextBuffer , edit : atomIde . TextEdit , prevEdit : atomIde . TextEdit | null ) : void {
86121 const path = buffer . getPath ( ) || ""
0 commit comments