Fossil SCM
Add the --tk option to "fossil diff" in order to launch a Tcl/Tk GUI display of colorized side-by-side diffs.
Commit
22e5d711e50de36f1023b0ce8c9f11617a2179ab
Parent
ecb85f61a9a9a2f…
2 files changed
+73
+1
-1
+73
| --- src/diffcmd.c | ||
| +++ src/diffcmd.c | ||
| @@ -473,10 +473,78 @@ | ||
| 473 | 473 | zDefault = 0; |
| 474 | 474 | zName = "diff-command"; |
| 475 | 475 | } |
| 476 | 476 | return db_get(zName, zDefault); |
| 477 | 477 | } |
| 478 | + | |
| 479 | +/* A Tcl/Tk script used to render diff output. | |
| 480 | +*/ | |
| 481 | +static const char zDiffScript[] = | |
| 482 | +@ wm withdraw . | |
| 483 | +@ wm title . {Fossil Diff} | |
| 484 | +@ wm iconname . {Fossil Diff} | |
| 485 | +@ set body {} | |
| 486 | +@ set mx 80 ;# Length of the longest line of text | |
| 487 | +@ set nLine 0 ;# Number of lines of text | |
| 488 | +@ text .t -width 180 -yscroll {.sb set} | |
| 489 | +@ if {$tcl_platform(platform)=="windows"} {.t config -font {courier 9}} | |
| 490 | +@ .t tag config ln -foreground gray | |
| 491 | +@ .t tag config chng -background {#d0d0ff} | |
| 492 | +@ .t tag config add -background {#c0ffc0} | |
| 493 | +@ .t tag config rm -background {#ffc0c0} | |
| 494 | +@ proc dehtml {x} {return [string map {& & < < > >} $x]} | |
| 495 | +@ set in [open $cmd r] | |
| 496 | +@ while {![eof $in]} { | |
| 497 | +@ set line [gets $in] | |
| 498 | +@ if {[regexp {^<a name="chunk.*"></a>} $line]} continue | |
| 499 | +@ if {[regexp {^===} $line]} { | |
| 500 | +@ set n [string length $line] | |
| 501 | +@ if {$n>$mx} {set mx $n} | |
| 502 | +@ } | |
| 503 | +@ incr nLine | |
| 504 | +@ while {[regexp {^(.*?)<span class="diff([a-z]+)">(.*?)</span>(.*)$} $line \ | |
| 505 | +@ all pre class mid tail]} { | |
| 506 | +@ .t insert end [dehtml $pre] {} [dehtml $mid] $class | |
| 507 | +@ set line $tail | |
| 508 | +@ } | |
| 509 | +@ .t insert end [dehtml $line]\n {} | |
| 510 | +@ } | |
| 511 | +@ close $in | |
| 512 | +@ if {$mx>250} {set mx 250} ;# Limit window width to 200 lines | |
| 513 | +@ if {$nLine>55} {set nLine 55} ;# Limit window height to 55 lines | |
| 514 | +@ .t config -height $nLine -width $mx | |
| 515 | +@ pack .t -side left -fill both -expand 1 | |
| 516 | +@ scrollbar .sb -command {.t yview} -orient vertical | |
| 517 | +@ pack .sb -side left -fill y | |
| 518 | +@ wm deiconify . | |
| 519 | +; | |
| 520 | + | |
| 521 | +/* | |
| 522 | +** Show diff output in a Tcl/Tk window, in response to the --tk option | |
| 523 | +** to the diff command. | |
| 524 | +** | |
| 525 | +** Steps: | |
| 526 | +** (1) Write the Tcl/Tk script used for rendering into a temp file. | |
| 527 | +** (2) Invoke "wish" on the temp file using fossil_system(). | |
| 528 | +** (3) Delete the temp file. | |
| 529 | +*/ | |
| 530 | +static void diff_tk(void){ | |
| 531 | + int i; | |
| 532 | + Blob script; | |
| 533 | + char *zTempFile; | |
| 534 | + char *zCmd; | |
| 535 | + blob_zero(&script); | |
| 536 | + blob_appendf(&script, "set cmd {| \"%s\" diff --html -y", g.argv[0]); | |
| 537 | + for(i=2; i<g.argc; i++){ | |
| 538 | + blob_appendf(&script, " \"%s\"", g.argv[i]); | |
| 539 | + } | |
| 540 | + blob_appendf(&script, "}\n%s", zDiffScript); | |
| 541 | + zTempFile = write_blob_to_temp_file(&script); | |
| 542 | + zCmd = mprintf("wish \"%s\"", zTempFile); | |
| 543 | + fossil_system(zCmd); | |
| 544 | + file_delete(zTempFile); | |
| 545 | +} | |
| 478 | 546 | |
| 479 | 547 | /* |
| 480 | 548 | ** COMMAND: diff |
| 481 | 549 | ** COMMAND: gdiff |
| 482 | 550 | ** |
| @@ -509,10 +577,11 @@ | ||
| 509 | 577 | ** --brief Show filenames only |
| 510 | 578 | ** --context|-c N Use N lines of context |
| 511 | 579 | ** --from|-r VERSION select VERSION as source for the diff |
| 512 | 580 | ** -i use internal diff logic |
| 513 | 581 | ** --new-file|-N output complete text of added or deleted files |
| 582 | +** --tk Launch a Tcl/Tk GUI for display | |
| 514 | 583 | ** --to VERSION select VERSION as target for the diff |
| 515 | 584 | ** --side-by-side|-y side-by-side diff |
| 516 | 585 | ** --width|-W N Width of lines in side-by-side diff |
| 517 | 586 | */ |
| 518 | 587 | void diff_cmd(void){ |
| @@ -524,10 +593,14 @@ | ||
| 524 | 593 | const char *zBranch; /* Branch to diff */ |
| 525 | 594 | const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */ |
| 526 | 595 | u64 diffFlags = 0; /* Flags to control the DIFF */ |
| 527 | 596 | int f; |
| 528 | 597 | |
| 598 | + if( find_option("tk",0,0)!=0 ){ | |
| 599 | + diff_tk(); | |
| 600 | + return; | |
| 601 | + } | |
| 529 | 602 | isGDiff = g.argv[1][0]=='g'; |
| 530 | 603 | isInternDiff = find_option("internal","i",0)!=0; |
| 531 | 604 | zFrom = find_option("from", "r", 1); |
| 532 | 605 | zTo = find_option("to", 0, 1); |
| 533 | 606 | zBranch = find_option("branch", 0, 1); |
| 534 | 607 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -473,10 +473,78 @@ | |
| 473 | zDefault = 0; |
| 474 | zName = "diff-command"; |
| 475 | } |
| 476 | return db_get(zName, zDefault); |
| 477 | } |
| 478 | |
| 479 | /* |
| 480 | ** COMMAND: diff |
| 481 | ** COMMAND: gdiff |
| 482 | ** |
| @@ -509,10 +577,11 @@ | |
| 509 | ** --brief Show filenames only |
| 510 | ** --context|-c N Use N lines of context |
| 511 | ** --from|-r VERSION select VERSION as source for the diff |
| 512 | ** -i use internal diff logic |
| 513 | ** --new-file|-N output complete text of added or deleted files |
| 514 | ** --to VERSION select VERSION as target for the diff |
| 515 | ** --side-by-side|-y side-by-side diff |
| 516 | ** --width|-W N Width of lines in side-by-side diff |
| 517 | */ |
| 518 | void diff_cmd(void){ |
| @@ -524,10 +593,14 @@ | |
| 524 | const char *zBranch; /* Branch to diff */ |
| 525 | const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */ |
| 526 | u64 diffFlags = 0; /* Flags to control the DIFF */ |
| 527 | int f; |
| 528 | |
| 529 | isGDiff = g.argv[1][0]=='g'; |
| 530 | isInternDiff = find_option("internal","i",0)!=0; |
| 531 | zFrom = find_option("from", "r", 1); |
| 532 | zTo = find_option("to", 0, 1); |
| 533 | zBranch = find_option("branch", 0, 1); |
| 534 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -473,10 +473,78 @@ | |
| 473 | zDefault = 0; |
| 474 | zName = "diff-command"; |
| 475 | } |
| 476 | return db_get(zName, zDefault); |
| 477 | } |
| 478 | |
| 479 | /* A Tcl/Tk script used to render diff output. |
| 480 | */ |
| 481 | static const char zDiffScript[] = |
| 482 | @ wm withdraw . |
| 483 | @ wm title . {Fossil Diff} |
| 484 | @ wm iconname . {Fossil Diff} |
| 485 | @ set body {} |
| 486 | @ set mx 80 ;# Length of the longest line of text |
| 487 | @ set nLine 0 ;# Number of lines of text |
| 488 | @ text .t -width 180 -yscroll {.sb set} |
| 489 | @ if {$tcl_platform(platform)=="windows"} {.t config -font {courier 9}} |
| 490 | @ .t tag config ln -foreground gray |
| 491 | @ .t tag config chng -background {#d0d0ff} |
| 492 | @ .t tag config add -background {#c0ffc0} |
| 493 | @ .t tag config rm -background {#ffc0c0} |
| 494 | @ proc dehtml {x} {return [string map {& & < < > >} $x]} |
| 495 | @ set in [open $cmd r] |
| 496 | @ while {![eof $in]} { |
| 497 | @ set line [gets $in] |
| 498 | @ if {[regexp {^<a name="chunk.*"></a>} $line]} continue |
| 499 | @ if {[regexp {^===} $line]} { |
| 500 | @ set n [string length $line] |
| 501 | @ if {$n>$mx} {set mx $n} |
| 502 | @ } |
| 503 | @ incr nLine |
| 504 | @ while {[regexp {^(.*?)<span class="diff([a-z]+)">(.*?)</span>(.*)$} $line \ |
| 505 | @ all pre class mid tail]} { |
| 506 | @ .t insert end [dehtml $pre] {} [dehtml $mid] $class |
| 507 | @ set line $tail |
| 508 | @ } |
| 509 | @ .t insert end [dehtml $line]\n {} |
| 510 | @ } |
| 511 | @ close $in |
| 512 | @ if {$mx>250} {set mx 250} ;# Limit window width to 200 lines |
| 513 | @ if {$nLine>55} {set nLine 55} ;# Limit window height to 55 lines |
| 514 | @ .t config -height $nLine -width $mx |
| 515 | @ pack .t -side left -fill both -expand 1 |
| 516 | @ scrollbar .sb -command {.t yview} -orient vertical |
| 517 | @ pack .sb -side left -fill y |
| 518 | @ wm deiconify . |
| 519 | ; |
| 520 | |
| 521 | /* |
| 522 | ** Show diff output in a Tcl/Tk window, in response to the --tk option |
| 523 | ** to the diff command. |
| 524 | ** |
| 525 | ** Steps: |
| 526 | ** (1) Write the Tcl/Tk script used for rendering into a temp file. |
| 527 | ** (2) Invoke "wish" on the temp file using fossil_system(). |
| 528 | ** (3) Delete the temp file. |
| 529 | */ |
| 530 | static void diff_tk(void){ |
| 531 | int i; |
| 532 | Blob script; |
| 533 | char *zTempFile; |
| 534 | char *zCmd; |
| 535 | blob_zero(&script); |
| 536 | blob_appendf(&script, "set cmd {| \"%s\" diff --html -y", g.argv[0]); |
| 537 | for(i=2; i<g.argc; i++){ |
| 538 | blob_appendf(&script, " \"%s\"", g.argv[i]); |
| 539 | } |
| 540 | blob_appendf(&script, "}\n%s", zDiffScript); |
| 541 | zTempFile = write_blob_to_temp_file(&script); |
| 542 | zCmd = mprintf("wish \"%s\"", zTempFile); |
| 543 | fossil_system(zCmd); |
| 544 | file_delete(zTempFile); |
| 545 | } |
| 546 | |
| 547 | /* |
| 548 | ** COMMAND: diff |
| 549 | ** COMMAND: gdiff |
| 550 | ** |
| @@ -509,10 +577,11 @@ | |
| 577 | ** --brief Show filenames only |
| 578 | ** --context|-c N Use N lines of context |
| 579 | ** --from|-r VERSION select VERSION as source for the diff |
| 580 | ** -i use internal diff logic |
| 581 | ** --new-file|-N output complete text of added or deleted files |
| 582 | ** --tk Launch a Tcl/Tk GUI for display |
| 583 | ** --to VERSION select VERSION as target for the diff |
| 584 | ** --side-by-side|-y side-by-side diff |
| 585 | ** --width|-W N Width of lines in side-by-side diff |
| 586 | */ |
| 587 | void diff_cmd(void){ |
| @@ -524,10 +593,14 @@ | |
| 593 | const char *zBranch; /* Branch to diff */ |
| 594 | const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */ |
| 595 | u64 diffFlags = 0; /* Flags to control the DIFF */ |
| 596 | int f; |
| 597 | |
| 598 | if( find_option("tk",0,0)!=0 ){ |
| 599 | diff_tk(); |
| 600 | return; |
| 601 | } |
| 602 | isGDiff = g.argv[1][0]=='g'; |
| 603 | isInternDiff = find_option("internal","i",0)!=0; |
| 604 | zFrom = find_option("from", "r", 1); |
| 605 | zTo = find_option("to", 0, 1); |
| 606 | zBranch = find_option("branch", 0, 1); |
| 607 |
+1
-1
| --- src/vfile.c | ||
| +++ src/vfile.c | ||
| @@ -535,11 +535,11 @@ | ||
| 535 | 535 | } |
| 536 | 536 | |
| 537 | 537 | /* |
| 538 | 538 | ** Write a BLOB into a random filename. Return the name of the file. |
| 539 | 539 | */ |
| 540 | -static char *write_blob_to_temp_file(Blob *pBlob){ | |
| 540 | +char *write_blob_to_temp_file(Blob *pBlob){ | |
| 541 | 541 | sqlite3_uint64 r; |
| 542 | 542 | char *zOut = 0; |
| 543 | 543 | do{ |
| 544 | 544 | sqlite3_free(zOut); |
| 545 | 545 | sqlite3_randomness(8, &r); |
| 546 | 546 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -535,11 +535,11 @@ | |
| 535 | } |
| 536 | |
| 537 | /* |
| 538 | ** Write a BLOB into a random filename. Return the name of the file. |
| 539 | */ |
| 540 | static char *write_blob_to_temp_file(Blob *pBlob){ |
| 541 | sqlite3_uint64 r; |
| 542 | char *zOut = 0; |
| 543 | do{ |
| 544 | sqlite3_free(zOut); |
| 545 | sqlite3_randomness(8, &r); |
| 546 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -535,11 +535,11 @@ | |
| 535 | } |
| 536 | |
| 537 | /* |
| 538 | ** Write a BLOB into a random filename. Return the name of the file. |
| 539 | */ |
| 540 | char *write_blob_to_temp_file(Blob *pBlob){ |
| 541 | sqlite3_uint64 r; |
| 542 | char *zOut = 0; |
| 543 | do{ |
| 544 | sqlite3_free(zOut); |
| 545 | sqlite3_randomness(8, &r); |
| 546 |