@@ -3,9 +3,9 @@ import type { Range } from 'vscode';
3
3
import type { Container } from '../../container' ;
4
4
import { relative } from '../../system/-webview/path' ;
5
5
import { filterMap } from '../../system/array' ;
6
- import { normalizePath } from '../../system/path' ;
6
+ import { joinPaths , normalizePath } from '../../system/path' ;
7
7
import { maybeStopWatch } from '../../system/stopwatch' ;
8
- import { getLines } from '../../system/string' ;
8
+ import { iterateByDelimiter , iterateByDelimiters } from '../../system/string' ;
9
9
import type { GitCommitLine , GitStashCommit } from '../models/commit' ;
10
10
import { GitCommit , GitCommitIdentity } from '../models/commit' ;
11
11
import type { GitFile } from '../models/file' ;
@@ -231,7 +231,7 @@ export function createLogParser<
231
231
let fieldCount = 0 ;
232
232
let field ;
233
233
234
- const fields = getLines ( data , options ?. separator ?? '\0' ) ;
234
+ const fields = iterateByDelimiters ( data , options ?. separator ?? '\0' ) ;
235
235
if ( options ?. skip ) {
236
236
for ( let i = 0 ; i < options . skip ; i ++ ) {
237
237
field = fields . next ( ) ;
@@ -266,7 +266,7 @@ export function createLogParserSingle(field: string): Parser<string> {
266
266
function * parse ( data : string | string [ ] ) : Generator < string > {
267
267
let field ;
268
268
269
- const fields = getLines ( data , '\0' ) ;
269
+ const fields = iterateByDelimiters ( data , '\0' ) ;
270
270
while ( true ) {
271
271
field = fields . next ( ) ;
272
272
if ( field . done ) break ;
@@ -295,7 +295,7 @@ export function createLogParserWithFiles<T extends Record<string, unknown>>(
295
295
}
296
296
297
297
function * parse ( data : string | string [ ] ) : Generator < ParsedEntryWithFiles < T > > {
298
- const records = getLines ( data , '\0\0\0' ) ;
298
+ const records = iterateByDelimiters ( data , '\0\0\0' ) ;
299
299
300
300
let entry : ParsedEntryWithFiles < T > ;
301
301
let files : ParsedEntryFile [ ] ;
@@ -304,7 +304,7 @@ export function createLogParserWithFiles<T extends Record<string, unknown>>(
304
304
for ( const record of records ) {
305
305
entry = { } as any ;
306
306
files = [ ] ;
307
- fields = getLines ( record , '\0' ) ;
307
+ fields = iterateByDelimiter ( record , '\0' ) ;
308
308
309
309
if ( fieldMapping != null ) {
310
310
// Skip the 2 starting NULs
@@ -353,13 +353,13 @@ export function createLogParserWithFilesAndStats<T extends Record<string, unknow
353
353
keys . push ( key ) ;
354
354
format += `%x00${ fieldMapping [ key ] } ` ;
355
355
}
356
- args = [ '-z' , `--format=${ format } ` , '--numstat' ] ;
356
+ args = [ '-z' , `--format=${ format } ` , '--numstat' , '--summary' ] ;
357
357
} else {
358
- args = [ '-z' , '--numstat' ] ;
358
+ args = [ '-z' , '--numstat' , '--summary' ] ;
359
359
}
360
360
361
361
function * parse ( data : string | string [ ] ) : Generator < ParsedEntryWithFilesAndStats < T > > {
362
- const records = getLines ( data , '\0\0\0' ) ;
362
+ const records = iterateByDelimiters ( data , '\0\0\0' , '\n \0\0') ;
363
363
364
364
let entry : ParsedEntryWithFilesAndStats < T > ;
365
365
let files : ParsedEntryFileWithStats [ ] ;
@@ -368,7 +368,7 @@ export function createLogParserWithFilesAndStats<T extends Record<string, unknow
368
368
for ( const record of records ) {
369
369
entry = { } as unknown as ParsedEntryWithFilesAndStats < T > ;
370
370
files = [ ] ;
371
- fields = getLines ( record , '\0' ) ;
371
+ fields = iterateByDelimiter ( record , '\0' ) ;
372
372
373
373
if ( fieldMapping != null ) {
374
374
// Skip the 2 starting NULs
@@ -385,6 +385,70 @@ export function createLogParserWithFilesAndStats<T extends Record<string, unknow
385
385
if ( fieldCount < keys . length ) {
386
386
entry [ keys [ fieldCount ++ ] ] = field . value as ParsedEntryWithFilesAndStats < T > [ keyof T ] ;
387
387
} else {
388
+ if ( ! field . value ) continue ;
389
+ if ( ! field . value . includes ( '\t' ) ) {
390
+ let match ;
391
+ let rename ;
392
+ let renamePrefix ;
393
+ let renameBefore ;
394
+ let renameAfter ;
395
+ let renameSuffix ;
396
+ let createOrDelete ;
397
+ let createOrDeletePath ;
398
+
399
+ for ( let line of field . value . split ( '\n' ) ) {
400
+ line = line . trim ( ) ;
401
+ if ( ! line ) continue ;
402
+
403
+ match =
404
+ / ( r e n a m e ) ( .* ?) \{ ? ( [ ^ { ] + ) \s + = > \s + ( [ ^ } ] + ) \} ? ( .* ?) ? (?: \( \d + % \) ) | ( c r e a t e | d e l e t e ) m o d e \d + ( .+ ) / . exec (
405
+ line ,
406
+ ) ;
407
+ if ( match == null ) continue ;
408
+
409
+ [
410
+ ,
411
+ rename ,
412
+ renamePrefix ,
413
+ renameBefore ,
414
+ renameAfter ,
415
+ renameSuffix ,
416
+ createOrDelete ,
417
+ createOrDeletePath ,
418
+ ] = match ;
419
+
420
+ let summaryPath ;
421
+ let summaryOriginalPath ;
422
+ let summaryStatus ;
423
+
424
+ if ( rename != null ) {
425
+ summaryPath = normalizePath ( joinPaths ( renamePrefix , renameAfter , renameSuffix ?? '' ) ) ;
426
+ summaryOriginalPath = normalizePath (
427
+ joinPaths ( renamePrefix , renameBefore , renameSuffix ?? '' ) ,
428
+ ) ;
429
+ summaryStatus = 'R' ;
430
+ } else {
431
+ summaryPath = normalizePath ( createOrDeletePath ) ;
432
+ summaryStatus = createOrDelete === 'create' ? 'A' : 'D' ;
433
+ }
434
+
435
+ const file = files . find ( f => f . path === summaryPath ) ;
436
+ if ( file == null ) {
437
+ debugger ;
438
+ continue ;
439
+ }
440
+
441
+ if ( file . status !== summaryStatus ) {
442
+ file . status = summaryStatus ;
443
+ if ( summaryOriginalPath != null ) {
444
+ file . originalPath = summaryOriginalPath ;
445
+ }
446
+ }
447
+ }
448
+
449
+ break ;
450
+ }
451
+
388
452
let [ additions , deletions , path ] = field . value . split ( '\t' ) ;
389
453
additions = additions . trim ( ) ;
390
454
deletions = deletions . trim ( ) ;
@@ -409,19 +473,8 @@ export function createLogParserWithFilesAndStats<T extends Record<string, unknow
409
473
}
410
474
}
411
475
412
- // Skip binary files which show as - for both additions and deletions
413
- if ( additions === '-' && deletions === '-' ) continue ;
414
-
415
476
const file : ParsedEntryFileWithStats = {
416
- status :
417
- status ??
418
- ( additions === '0' && deletions === '0'
419
- ? 'M'
420
- : additions === '0'
421
- ? 'D'
422
- : deletions === '0'
423
- ? 'A'
424
- : 'M' ) ,
477
+ status : status ?? 'M' ,
425
478
path : path ,
426
479
originalPath : originalPath ,
427
480
additions : additions === '-' ? 0 : parseInt ( additions , 10 ) ,
@@ -530,7 +583,7 @@ export function parseGitLog(
530
583
let i = 0 ;
531
584
let first = true ;
532
585
533
- const lines = getLines ( `${ data } </f>` ) ;
586
+ const lines = iterateByDelimiter ( `${ data } </f>` ) ;
534
587
// Skip the first line since it will always be </f>
535
588
let next = lines . next ( ) ;
536
589
if ( next . done ) return undefined ;
0 commit comments