1- import { TextEdit , Position , Range , TextDocument } from 'vscode' ;
1+ import { TextEdit , Position , Range , TextDocument , WorkspaceEdit } from 'vscode' ;
2+ import * as vscode from 'vscode' ;
23import * as dmp from 'diff-match-patch' ;
34import { EOL } from 'os' ;
45import * as fs from 'fs' ;
@@ -60,7 +61,7 @@ export function getTextEditsFromPatch(before: string, patch: string): TextEdit[]
6061 if ( ! Array . isArray ( patches ) || patches . length === 0 ) {
6162 throw new Error ( 'Unable to parse Patch string' ) ;
6263 }
63- let textEdits = [ ] ;
64+ let textEdits : TextEdit [ ] = [ ] ;
6465
6566 // Add line feeds
6667 // & build the text edits
@@ -69,24 +70,95 @@ export function getTextEditsFromPatch(before: string, patch: string): TextEdit[]
6970 diff [ 1 ] += EOL ;
7071 } ) ;
7172
72- textEdits = textEdits . concat ( getTextEditsInternal ( before , patch . diffs , patch . start1 ) ) ;
73+ getTextEditsInternal ( before , patch . diffs , patch . start1 ) . forEach ( edit => textEdits . push ( edit . apply ( ) ) ) ;
7374 } ) ;
7475
7576 return textEdits ;
7677}
78+ export function getWorkspaceEditsFromPatch ( filePatches : string [ ] ) : WorkspaceEdit {
79+ const workspaceEdit = new WorkspaceEdit ( ) ;
80+ filePatches . forEach ( patch => {
81+ const indexOfAtAt = patch . indexOf ( '@@' ) ;
82+ if ( indexOfAtAt === - 1 ) {
83+ return ;
84+ }
85+ const fileNameLines = patch . substring ( 0 , indexOfAtAt ) . split ( / \r ? \n / g)
86+ . map ( line => line . trim ( ) )
87+ . filter ( line => line . length > 0 &&
88+ line . toLowerCase ( ) . endsWith ( '.py' ) &&
89+ line . indexOf ( ' a' ) > 0 ) ;
90+
91+ if ( patch . startsWith ( '---' ) ) {
92+ // Strip the first two lines
93+ patch = patch . substring ( indexOfAtAt ) ;
94+ }
95+ if ( patch . length === 0 ) {
96+ return ;
97+ }
98+ // We can't find the find name
99+ if ( fileNameLines . length === 0 ) {
100+ return ;
101+ }
102+
103+ let fileName = fileNameLines [ 0 ] . substring ( fileNameLines [ 0 ] . indexOf ( ' a' ) + 3 ) . trim ( ) ;
104+ fileName = path . isAbsolute ( fileName ) ? fileName : path . resolve ( vscode . workspace . rootPath , fileName ) ;
105+ if ( ! fs . existsSync ( fileName ) ) {
106+ return ;
107+ }
108+
109+ // Remove the text added by unified_diff
110+ // # Work around missing newline (http://bugs.python.org/issue2142).
111+ patch = patch . replace ( / \\ N o n e w l i n e a t e n d o f f i l e [ \r \n ] / , '' ) ;
112+
113+ let d = new dmp . diff_match_patch ( ) ;
114+ let patches : any [ ] = patch_fromText . call ( d , patch ) ;
115+ if ( ! Array . isArray ( patches ) || patches . length === 0 ) {
116+ throw new Error ( 'Unable to parse Patch string' ) ;
117+ }
118+
119+ const fileSource = fs . readFileSync ( fileName ) . toString ( 'utf8' ) ;
120+ const fileUri = vscode . Uri . file ( fileName ) ;
121+
122+ // Add line feeds
123+ // & build the text edits
124+ patches . forEach ( patch => {
125+ patch . diffs . forEach ( diff => {
126+ diff [ 1 ] += EOL ;
127+ } ) ;
128+
129+ getTextEditsInternal ( fileSource , patch . diffs , patch . start1 ) . forEach ( edit => {
130+ switch ( edit . action ) {
131+ case EDIT_DELETE : {
132+ workspaceEdit . delete ( fileUri , new Range ( edit . start , edit . end ) ) ;
133+ }
134+ case EDIT_INSERT : {
135+ workspaceEdit . insert ( fileUri , edit . start , edit . text ) ;
136+ }
137+ case EDIT_REPLACE : {
138+ workspaceEdit . replace ( fileUri , new Range ( edit . start , edit . end ) , edit . text ) ;
139+ }
140+ }
141+ } ) ;
142+ } ) ;
143+
144+
145+ } ) ;
146+
147+ return workspaceEdit ;
148+ }
77149export function getTextEdits ( before : string , after : string ) : TextEdit [ ] {
78150 let d = new dmp . diff_match_patch ( ) ;
79151 let diffs = d . diff_main ( before , after ) ;
80- return getTextEditsInternal ( before , diffs ) ;
152+ return getTextEditsInternal ( before , diffs ) . map ( edit => edit . apply ( ) ) ;
81153}
82- function getTextEditsInternal ( before : string , diffs : [ number , string ] [ ] , startLine : number = 0 ) : TextEdit [ ] {
154+ function getTextEditsInternal ( before : string , diffs : [ number , string ] [ ] , startLine : number = 0 ) : Edit [ ] {
83155 let line = startLine ;
84156 let character = 0 ;
85157 if ( line > 0 ) {
86158 let beforeLines = < string [ ] > before . split ( / \r ? \n / g) ;
87159 beforeLines . filter ( ( l , i ) => i < line ) . forEach ( l => character += l . length + NEW_LINE_LENGTH ) ;
88160 }
89- let edits : TextEdit [ ] = [ ] ;
161+ const edits : Edit [ ] = [ ] ;
90162 let edit : Edit = null ;
91163
92164 for ( let i = 0 ; i < diffs . length ; i ++ ) {
@@ -128,15 +200,15 @@ function getTextEditsInternal(before: string, diffs: [number, string][], startLi
128200
129201 case dmp . DIFF_EQUAL :
130202 if ( edit != null ) {
131- edits . push ( edit . apply ( ) ) ;
203+ edits . push ( edit ) ;
132204 edit = null ;
133205 }
134206 break ;
135207 }
136208 }
137209
138210 if ( edit != null ) {
139- edits . push ( edit . apply ( ) ) ;
211+ edits . push ( edit ) ;
140212 }
141213
142214 return edits ;
0 commit comments