Tcl Library Source Code

Changes On Branch sak-work-review
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch sak-work-review Excluding Merge-Ins

This is equivalent to a diff from 728f8dc82c to a87b318066

2013-02-07
04:40
Merged sak review helper command (for release manager). check-in: 309ead7ea9 user: aku tags: trunk
04:37
Removed sak commands vcompare, rstatus, and note. Completely replaced by "review" and "readme" now. Tweaked "review" help reorganization dropped clear+next next - now skips to next un-reviewed package step is old next, single-step. Closed-Leaf check-in: a87b318066 user: aku tags: sak-work-review
02:15
Rewrite of the review functionality ... Integrated scan, separate from readme. check-in: a5cab9fbf7 user: andreask tags: sak-work-review
2013-02-06
19:32
Start on getting embedded doc into the repository, and nice commands for maintaining it. check-in: 7eba32ada7 user: andreask tags: embedded-doc-work
05:46
Tcllib 1.15 Release check-in: 411c419016 user: aku tags: trunk, tcllib-1-15, release
2013-02-02
01:54
Helper stuff for rel.mgr, interactive m/p review. check-in: c6bf264826 user: andreask tags: sak-work-review
2013-02-01
08:14
Merged json::write changes to release. Updated README. check-in: a9514707b9 user: aku tags: tcllib-1-15-rc
08:10
json, writing: Dropping the quoting of / as \/. check-in: 728f8dc82c user: aku tags: trunk
2013-01-30
23:28
Added more utilities to support class variables, class methods, and singleton classes. Packed version bumped to 1.1 for all these new features. check-in: 4eec538864 user: andreask tags: trunk

Changes to modules/doctools/changelog.man.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[comment {-*- tcl -*- doctools manpage}]
[manpage_begin doctools::changelog n 1]
[copyright {2003-2008 Andreas Kupries <[email protected]>}]
[moddesc   {Documentation tools}]
[titledesc {Processing text in Emacs ChangeLog format}]
[category  {Documentation tools}]
[require Tcl 8.2]
[require textutil]
[require doctools::changelog [opt 1]]
[description]

This package provides Tcl commands for the processing and reformatting
of text in the [file ChangeLog] format generated by [syscmd emacs].


[section API]

|
|





|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[comment {-*- tcl -*- doctools manpage}]
[manpage_begin doctools::changelog n 1.1]
[copyright {2003-2013 Andreas Kupries <[email protected]>}]
[moddesc   {Documentation tools}]
[titledesc {Processing text in Emacs ChangeLog format}]
[category  {Documentation tools}]
[require Tcl 8.2]
[require textutil]
[require doctools::changelog [opt 1.1]]
[description]

This package provides Tcl commands for the processing and reformatting
of text in the [file ChangeLog] format generated by [syscmd emacs].


[section API]
47
48
49
50
51
52
53







54
55
56
57
58
59
60
		...
	    }
	}
	{...}
    }
}]









[call [cmd ::doctools::changelog::toDoctools] [arg title] [arg module] [arg version] [arg entries]]

This command converts the pre-parsed ChangeLog [arg entries] as
generated by the command [cmd ::doctools::changelog::scan] into a
document in [term doctools] format and returns it as the result of the
command.







>
>
>
>
>
>
>







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
		...
	    }
	}
	{...}
    }
}]


[call [cmd ::doctools::changelog::flatten] [arg entries]]

This command converts a list of entries as generated by
[cmd change::scan] above into a simpler list of plain
text blocks each containing all the information of a
single entry.

[call [cmd ::doctools::changelog::toDoctools] [arg title] [arg module] [arg version] [arg entries]]

This command converts the pre-parsed ChangeLog [arg entries] as
generated by the command [cmd ::doctools::changelog::scan] into a
document in [term doctools] format and returns it as the result of the
command.

Changes to modules/doctools/changelog.tcl.

18
19
20
21
22
23
24
25






















26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44


package require Tcl 8.2
package require textutil

namespace eval ::doctools {}
namespace eval ::doctools::changelog {
    namespace export scan toDoctools






















}

# ::doctools::changelog::scan --
#
#	Scan a ChangeLog generated by 'emacs' and extract the relevant information.
#
# Result
#	List of entries. Each entry is a list of three elements. These
#	are date, author, and commentary. The commentary is a list of
#	sections. Each section is a list of two elements, a list of
#	files, and the associated text.


proc ::doctools::changelog::scan {text} {
    set text [split $text \n]
    set n    [llength $text]

    set entries [list]
    set clist [list]







|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>











<







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

59
60
61
62
63
64
65


package require Tcl 8.2
package require textutil

namespace eval ::doctools {}
namespace eval ::doctools::changelog {
    namespace export scan flatten merge toDoctools
}

proc ::doctools::changelog::flatten {entries} {
    # Reformat the entries into a simpler structure.

    set result {}
    foreach entry $entries {
	foreach {date user sections} $entry break
	set f {}
	set t {}
	foreach sec $sections {
	    foreach {files text} $sec break
	    foreach file $files { lappend f $file }
	    append t \n $text
	}

	set t [textutil::adjust::indent [textutil::adjust $t] "        "]
	lappend result \
	    "$date $user\n    [join $f ", "]:\n$t"
    }

    return $result
}

# ::doctools::changelog::scan --
#
#	Scan a ChangeLog generated by 'emacs' and extract the relevant information.
#
# Result
#	List of entries. Each entry is a list of three elements. These
#	are date, author, and commentary. The commentary is a list of
#	sections. Each section is a list of two elements, a list of
#	files, and the associated text.


proc ::doctools::changelog::scan {text} {
    set text [split $text \n]
    set n    [llength $text]

    set entries [list]
    set clist [list]
253
254
255
256
257
258
259
260
    lappend linebuffer [q manpage_end]
    return [join $linebuffer \n]
}

#------------------------------------
# Module initialization

package provide doctools::changelog 1







|
274
275
276
277
278
279
280
281
    lappend linebuffer [q manpage_end]
    return [join $linebuffer \n]
}

#------------------------------------
# Module initialization

package provide doctools::changelog 1.1

Changes to modules/doctools/pkgIndex.tcl.

1
2
3
4
5
6
if {![package vsatisfies [package provide Tcl] 8.2]} {return}
package ifneeded doctools            1.4.13 [list source [file join $dir doctools.tcl]]
package ifneeded doctools::toc       1.1.3  [list source [file join $dir doctoc.tcl]]
package ifneeded doctools::idx       1.0.4  [list source [file join $dir docidx.tcl]]
package ifneeded doctools::cvs       1      [list source [file join $dir cvs.tcl]]
package ifneeded doctools::changelog 1      [list source [file join $dir changelog.tcl]]





|
1
2
3
4
5
6
if {![package vsatisfies [package provide Tcl] 8.2]} {return}
package ifneeded doctools            1.4.13 [list source [file join $dir doctools.tcl]]
package ifneeded doctools::toc       1.1.3  [list source [file join $dir doctoc.tcl]]
package ifneeded doctools::idx       1.0.4  [list source [file join $dir docidx.tcl]]
package ifneeded doctools::cvs       1      [list source [file join $dir cvs.tcl]]
package ifneeded doctools::changelog 1.1    [list source [file join $dir changelog.tcl]]

Changes to sak.tcl.

1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678

proc __provided {} {
    array set packages [ppackages]
    nparray packages
    return
}


proc __vcompare {} {
    global argv
    set oldplist [lindex $argv 0]
    pkg-compare $oldplist
    return
}

proc __rstatus {} {
    global distribution approved

    catch {
	set f [file join $distribution .APPROVE]
	set f [open $f r]
	while {![eof $f]} {
	    if {[gets $f line] < 0} continue
	    set line [string trim $line]
	    if {$line == {}} continue
	    set approved($line) .
	}
	close $f
    }
    pkg-compare [location_PACKAGES]
    return
}

proc pkg-compare {oldplist} {
    global approved ; array set approved {}

    getpackage struct::set struct/sets.tcl

    array set curpkg [ipackages]
    array set oldpkg [loadpkglist $oldplist]
    array set mod {}
    array set changed {}
    foreach m [modified-modules] {
	set mod($m) .
    }

    foreach p [array names curpkg] {
	set __($p) .
	foreach {vlist module} $curpkg($p) break
	set curpkg($p) $vlist
	set changed($p) [info exists mod($module)]
    }
    foreach p [array names oldpkg] {set __($p) .}
    set unified [lsort [array names __]]
    unset __

    set maxl 0
    foreach name $unified {
        if {[string length $name] > $maxl} {
            set maxl [string length $name]
        }
    }

    set maxm 0
    foreach m [modules] {
        if {[string length $m] > $maxm} {
            set maxm [string length $m]
        }
    }

    set lastm ""
    foreach m [lsort -dict [modules]] {
	set packages {}
	foreach {p ___} [ppackages $m] {
	    lappend packages $p
	}
	foreach name [lsort -dict $packages] {
	    set skip 0
	    set suffix ""
	    set prefix "   "
	    if {![info exists curpkg($name)]} {set curpkg($name) {}}
	    if {![info exists oldpkg($name)]} {
		set oldpkg($name) {}
		set suffix " NEW"
		set prefix "Nn "
		set skip 1
	    }
	    if {!$skip} {
		# Draw attention to changed packages where version is
		# unchanged.

		set vequal [struct::set equal $oldpkg($name) $curpkg($name)]

		if {$changed($name)} {
		    if {$vequal} {
			# Changed according to ChangeLog, Version is not. ALERT.
			set prefix "!! "
			set suffix "\t<<< MISMATCH. Version ==, ChangeLog ++"
		    } else {
			# Both changelog and version number indicate a change.
			# Small alert, have to classify the order of changes.
			set prefix "cv "
			set suffix "\t=== Classify changes."
		    }
		} else {
		    if {$vequal} {
			# Versions are unchanged, changelog also indicates no change.
			# No particular attention here.
		    } else {
			# Versions changed, but according to changelog nothing in code. ALERT.
			set prefix "!! "
			set suffix "\t<<< MISMATCH. ChangeLog ==, Version ++"
		    }
		}
		if {[info exists approved($name)]} {
		    set prefix "   "
		    set suffix ""
		}
	    }

	    # To handle multiple versions we match the found versions up
	    # by major version. We assume that we have only one version
	    # per major version. This allows us to detect changes within
	    # each major version, new major versions, etc.

	    array set om {} ; foreach v $oldpkg($name) {set om([lindex [split $v .] 0]) $v}
	    array set cm {} ; foreach v $curpkg($name) {set cm([lindex [split $v .] 0]) $v}

	    set all [lsort -dict [struct::set union [array names om] [array names cm]]]

	    sakdebug {
		puts @@@@@@@@@@@@@@@@
		parray om
		parray cm
		puts all\ $all
		puts @@@@@@@@@@@@@@@@
	    }

	    foreach v $all {
		if {![string equal $m $lastm]} {
		    set mdis $m
		} else {
		    set mdis ""
		}
		set lastm $m

		if {[info exists om($v)]} {set ov $om($v)} else {set ov "--"}
		if {[info exists cm($v)]} {set cv $cm($v)} else {set cv "--"}

		puts stdout ${prefix}[format "%-*s %-*s %-*s %-*s" \
					  $maxm $mdis $maxl $name 8 $ov 8 $cv]$suffix
	    }

	    unset om cm
	}
    }
    return
}

proc checkmod {} {
    global argv
    package require sak::util
    return [sak::util::checkModules argv]
}

# -------------------------------------------------------------------------







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







1513
1514
1515
1516
1517
1518
1519
























































































































































1520
1521
1522
1523
1524
1525
1526

proc __provided {} {
    array set packages [ppackages]
    nparray packages
    return
}

























































































































































proc checkmod {} {
    global argv
    package require sak::util
    return [sak::util::checkModules argv]
}

# -------------------------------------------------------------------------
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
	set fh [open $f w] ; puts -nonewline $fh $notice$data ; close $fh
    }

    gd-gen-packages
    return
}

proc __approve {} {
    global argv distribution

    # Record the package as approved. This will suppress any alerts
    # for that package by rstatus. Required for packages which have
    # been classified, and for packages where a MISMATCH is bogus (due
    # to several packages sharing a ChangeLog)

    set f [open [file join $distribution .APPROVE] a]
    foreach package $argv {
	puts $f $package
    }
    close $f
    return
}

# --------------------------------------------------------------
# Documentation

proc __desc  {} {
    global argv ; if {![checkmod]} return
    array set pd [getpdesc]








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







2250
2251
2252
2253
2254
2255
2256
















2257
2258
2259
2260
2261
2262
2263
	set fh [open $f w] ; puts -nonewline $fh $notice$data ; close $fh
    }

    gd-gen-packages
    return
}

















# --------------------------------------------------------------
# Documentation

proc __desc  {} {
    global argv ; if {![checkmod]} return
    array set pd [getpdesc]

Deleted support/devel/sak/note/cmd.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# -*- tcl -*-
# Implementation of 'note'.

# Available variables
# * argv  - Cmdline arguments
# * base  - Location of sak.tcl = Top directory of Tcllib distribution
# * cbase - Location of all files relevant to this command.
# * sbase - Location of all files supporting the SAK.

package require sak::util
package require sak::note

set raw  0
set log  0
set stem {}
set tclv {}

if {![llength $argv]} {
    sak::note::show
    return
}
if {[llength $argv] == 1} {
    set f [lindex $argv 0]
    if {![file exists $f] ||
	![file isfile $f] ||
	![file readable $f]
    } {
	sak::note::usage
    }
    set c [open $f]
    set d [string trimright [read $c]]
    close $c

    foreach line [split $d \n] {
	if {[llength $line] < 3} {
	    puts stdout "\tBad line: '$line'"
	    exit 1
	}
	foreach {m p} $line break
	set notes [lrange $line 2 end]
	sak::note::run $m $p $notes
    }
    return
} elseif {[llength $argv] < 3} {
    sak::note::usage
}
foreach {m p} $argv break
set notes [lrange $argv 2 end]

sak::note::run $m $p $notes

##
# ###
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































































Deleted support/devel/sak/note/help.txt.

1
2
3
4
5
6
7
8
9
10
11
12

    note -- enter tags for the README generated by 'sak readme'.

    sak note module package tag...
    sak note path

    	This command saves tags for use by 'sak readme'.
	The single tag '---' shows that the package is unchanged.
	The tags 'D' and 'T', alone or in combination show that
	the package is changed, but not in a visible way.

	This is a support command for the release manager.
<
<
<
<
<
<
<
<
<
<
<
<
























Deleted support/devel/sak/note/note.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# -*- tcl -*-
# (C) 2009 Andreas Kupries <[email protected]>
##
# ###

namespace eval ::sak::note {}

# ###

proc ::sak::note::usage {} {
    package require sak::help
    puts stdout \n[sak::help::on note]
    exit 1
}

proc ::sak::note::run {m p tags} {
    global distribution
    variable notes
    LoadNotes

    set k [list $m $p]
    set notes($k) $tags

    set f [file join $distribution .NOTE]
    set f [open $f w]
    foreach k [array names notes] {
	puts $f [list $k $notes($k)]
    }
    close $f
    return
}

proc ::sak::note::show {} {
    variable notes
    LoadNotes

    getpackage struct::matrix   struct/matrix.tcl

    struct::matrix M ; M add columns 3
    foreach k [lsort -dict [array names notes]] {
	M add row [linsert $k end $notes($k)]
    }
    puts "    [join [split [M format 2string] \n] "\n    "]\n"
    return
}

proc ::sak::note::LoadNotes {} {
    global distribution
    variable  notes
    array set notes {}

    catch {
	set f [file join $distribution .NOTE]
	set f [open $f r]
	while {![eof $f]} {
	    if {[gets $f line] < 0} continue
	    set line [string trim $line]
	    if {$line == {}} continue
	    foreach {k t} $line break
	    set notes($k) $t
	}
	close $f
    }

    return
}


##
# ###

package provide sak::note 1.0
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
















































































































































Deleted support/devel/sak/note/pkgIndex.tcl.

1
2
if {![package vsatisfies [package provide Tcl] 8.2]} return
package ifneeded sak::note 1.0 [list source [file join $dir note.tcl]]
<
<




Deleted support/devel/sak/note/topic.txt.

1
note		Enter tags for the README generated by 'readme'
<


Changes to support/devel/sak/old/help.txt.

18
19
20
21
22
23
24

25
26
27
28
29
30
31
32
33
34
35
36
        lmodules         - See above, however one module per line
        imodules         - Return list of modules known to the installer.
        critcl-modules   - Return a list of modules with critcl enhancements.

        packages         - Return indexed packages in the bundle, plus versions,
                           one package per line. Extracted from the
                           package indices found in the modules.

        provided         - Return list and versions of provided packages
                           (in contrast to indexed).
        vcompare pkglist - Compare package list of previous 'packages'
                           call with current packages. Marks all new
                           and unchanged packages for higher attention.

        critcl ?module?  - Build a critcl module [default is @@].

        bench ?opt? ?module..?
                         - Run benchmark scripts (*.bench).

                Options: -throwerrors 0|1  Propagate errors if set.







>


<
<
<







18
19
20
21
22
23
24
25
26
27



28
29
30
31
32
33
34
        lmodules         - See above, however one module per line
        imodules         - Return list of modules known to the installer.
        critcl-modules   - Return a list of modules with critcl enhancements.

        packages         - Return indexed packages in the bundle, plus versions,
                           one package per line. Extracted from the
                           package indices found in the modules.

        provided         - Return list and versions of provided packages
                           (in contrast to indexed).




        critcl ?module?  - Build a critcl module [default is @@].

        bench ?opt? ?module..?
                         - Run benchmark scripts (*.bench).

                Options: -throwerrors 0|1  Propagate errors if set.
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
        gentip55 - Generate a TIP55-style DESCRIPTION.txt file.
        yml      - Generate a YAML description file.

        release name sf-user-id
                 - Marks the current state of all files as a new
                   release. This updates all ChangeLog's, and
                   regenerates the contents of PACKAGES

        rstatus  - Determines the status of the code base with regard
                   to the last release.

        approve pkg - Suppress named package in rstatus output.
                      I.e. mark the packages which are done while going
                      over all of them for a release.








<
<
<
<
<
<
<
<
96
97
98
99
100
101
102








        gentip55 - Generate a TIP55-style DESCRIPTION.txt file.
        yml      - Generate a YAML description file.

        release name sf-user-id
                 - Marks the current state of all files as a new
                   release. This updates all ChangeLog's, and
                   regenerates the contents of PACKAGES








Changes to support/devel/sak/readme/help.txt.

1
2
3
4
5
6
7
8
9
10


11
12

    readme -- Generate a readme listing changes to modules and packages.

    sak readme

    	This command compares the current state of the modules and
    	packages and against information from the last release
    	(support/releases/PACKAGES) and generates a README.txt listing
    	the relevant changes (new modules/packages, package version
    	changes, unchanged packages).



	This is a support command for the release manager.










>
>


1
2
3
4
5
6
7
8
9
10
11
12
13
14

    readme -- Generate a readme listing changes to modules and packages.

    sak readme

    	This command compares the current state of the modules and
    	packages and against information from the last release
    	(support/releases/PACKAGES) and generates a README.txt listing
    	the relevant changes (new modules/packages, package version
    	changes, unchanged packages).

	The generated README is written to stdout.

	This is a support command for the release manager.

Changes to support/devel/sak/readme/readme.tcl.

1
2
3
4
5


6


7
8
9
10
11
12
13
14
15
16
17
18
19
20
21


22
23
24
25
26
27
28
# -*- tcl -*-
# (C) 2009 Andreas Kupries <[email protected]>
##
# ###



namespace eval ::sak::readme {}



# ###

proc ::sak::readme::usage {} {
    package require sak::help
    puts stdout \n[sak::help::on readme]
    exit 1
}

proc ::sak::readme::run {} {
    global package_name package_version

    getpackage struct::set      struct/sets.tcl
    getpackage struct::matrix   struct/matrix.tcl
    getpackage textutil::adjust textutil/adjust.tcl



    # package -> list(version)
    set old_version    [loadoldv [location_PACKAGES]]
    array set releasep [loadpkglist [location_PACKAGES]]
    array set currentp [ipackages]

    # Determine which packages are potentially changed, from the set





>
>
|
>
>















>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# -*- tcl -*-
# (C) 2009 Andreas Kupries <[email protected]>
##
# ###

package require sak::color

namespace eval ::sak::readme {
    namespace import ::sak::color::*
}

# ###

proc ::sak::readme::usage {} {
    package require sak::help
    puts stdout \n[sak::help::on readme]
    exit 1
}

proc ::sak::readme::run {} {
    global package_name package_version

    getpackage struct::set      struct/sets.tcl
    getpackage struct::matrix   struct/matrix.tcl
    getpackage textutil::adjust textutil/adjust.tcl

    set issues {}

    # package -> list(version)
    set old_version    [loadoldv [location_PACKAGES]]
    array set releasep [loadpkglist [location_PACKAGES]]
    array set currentp [ipackages]

    # Determine which packages are potentially changed, from the set
124
125
126
127
128
129
130

131
132

133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152


153
154
155
156
157
158
159
		# Both changelog and version number indicate a
		# change. Small alert, have to classify the order of
		# changes. But not if there is a note, this is assumed
		# to be the classification.

		if {$note eq {}} {
		    set note "\t=== Classify changes."

		}
		Enter $m $name $note

		lappend chgm $m
		lappend chgp $name
		continue
	    }

	    #     Changed according to ChangeLog, Version is not. ALERT.
	    # or: Versions changed, but according to changelog nothing
	    #     in the code. ALERT.

	    # Suppress the alert if we have a note, and dispatch per
	    # the note's contents (some tags are special, instructions
	    # to us here).

	    if {($note eq {})} {
		if {$changed($name)} {
		    # Changed according to ChangeLog, Version is not. ALERT.
		    set note "\t<<< MISMATCH. Version ==, ChangeLog ++"
		} else {
		    set note "\t<<< MISMATCH. ChangeLog ==, Version ++"
		}


	    }

	    Enter $m $name $note
	    lappend chgm $m
	    lappend chgp $name
	}
    }







>


>




















>
>







130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
		# Both changelog and version number indicate a
		# change. Small alert, have to classify the order of
		# changes. But not if there is a note, this is assumed
		# to be the classification.

		if {$note eq {}} {
		    set note "\t=== Classify changes."
		    lappend issues [list $m $name "Classify changes"]
		}
		Enter $m $name $note

		lappend chgm $m
		lappend chgp $name
		continue
	    }

	    #     Changed according to ChangeLog, Version is not. ALERT.
	    # or: Versions changed, but according to changelog nothing
	    #     in the code. ALERT.

	    # Suppress the alert if we have a note, and dispatch per
	    # the note's contents (some tags are special, instructions
	    # to us here).

	    if {($note eq {})} {
		if {$changed($name)} {
		    # Changed according to ChangeLog, Version is not. ALERT.
		    set note "\t<<< MISMATCH. Version ==, ChangeLog ++"
		} else {
		    set note "\t<<< MISMATCH. ChangeLog ==, Version ++"
		}

		lappend issues [list $m $name [string range $note 5 end]]
	    }

	    Enter $m $name $note
	    lappend chgm $m
	    lappend chgp $name
	}
    }
222
223
224
225
226
227
228





















229
230
231
232
233
234
235
	puts ""
	puts [Indent "    " [textutil::adjust::adjust \
				 [join [lsort -dict $UCH] {, }] -length 64]]
    }

    variable legend
    puts $legend





















    return
}

proc ::sak::readme::Header {s {sep =}} {
    puts $s
    puts [string repeat $sep [string length $s]]
    return







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
	puts ""
	puts [Indent "    " [textutil::adjust::adjust \
				 [join [lsort -dict $UCH] {, }] -length 64]]
    }

    variable legend
    puts $legend

    if {![llength $issues]} return

    puts stderr [=red "Issues found ([llength $issues])"]
    puts stderr "  Please run \"./sak.tcl review\" to resolve,"
    puts stderr "  then run \"./sak.tcl readme\" again."
    puts stderr Details:

    struct::matrix ISS ; ISS add columns 3
    foreach issue $issues {
	foreach {m p w} $issue break
	set m "  $m"
	ISS add row [list $m $p $w]
    }

    puts stderr [ISS format 2string]


    puts stderr [=red "Issues found ([llength $issues])"]
    puts stderr "  Please run \"./sak.tcl review\" to resolve,"
    puts stderr "  then run \"./sak.tcl readme\" again."
    return
}

proc ::sak::readme::Header {s {sep =}} {
    puts $s
    puts [string repeat $sep [string length $s]]
    return
396
397
398
399
400
401
402


403
404
405
        Patch   B  :    Bug fixes.
                EX :    New examples.
                P  :    Performance enhancement.

        None    T  :    Testsuite changes.
                D  :    Documentation updates.
    }


}

package provide sak::readme 1.0







>
>



427
428
429
430
431
432
433
434
435
436
437
438
        Patch   B  :    Bug fixes.
                EX :    New examples.
                P  :    Performance enhancement.

        None    T  :    Testsuite changes.
                D  :    Documentation updates.
    }

    variable review {}
}

package provide sak::readme 1.0

Added support/devel/sak/review/cmd.tcl.



















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# -*- tcl -*-
# Implementation of 'review'.

# Available variables
# * argv  - Cmdline arguments
# * base  - Location of sak.tcl = Top directory of Tcllib distribution
# * cbase - Location of all files relevant to this command.
# * sbase - Location of all files supporting the SAK.

package require sak::util
package require sak::review

set raw  0
set log  0
set stem {}
set tclv {}

if {[llength $argv]} {
    sak::review::usage
}

sak::review::run

##
# ###

Added support/devel/sak/review/help.txt.





















>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10

    review -- Interactively review changed modules and packages

    sak review

    	This command scans the system for changes and then enters
	a sub-shell where the caller can interactively review and
	tag these changes.

	This is a support command for the release manager.

Added support/devel/sak/review/pkgIndex.tcl.





>
>
1
2
if {![package vsatisfies [package provide Tcl] 8.2]} return
package ifneeded sak::review 1.0 [list source [file join $dir review.tcl]]

Added support/devel/sak/review/review.tcl.



























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
# -*- tcl -*-
# # ## ### ##### ######## ############# ##################### 
# (C) 2013 Andreas Kupries <[email protected]>
##
# ###

package require linenoise
package require sak::color

getpackage fileutil                 fileutil/fileutil.tcl
getpackage doctools::changelog      doctools/changelog.tcl
getpackage struct::set              struct/sets.tcl
getpackage term::ansi::send         term/ansi/send.tcl

namespace eval ::sak::review {
    namespace import ::sak::color::*
}

# ###

proc ::sak::review::usage {} {
    package require sak::help
    puts stdout \n[sak::help::on review]
    exit 1
}

proc ::sak::review::run {} {
    Scan ; Review
    return
}

# # ## ### ##### ######## ############# ##################### 
## Phase I. Determine which modules require a review.
## A derivative of the code in ::sak::readme.

proc ::sak::review::Scan {} {
    global distribution
    variable review

    Banner "Scan for modules and packages to review..."

    # Determine which packages are potentially changed and therefore
    # in need of review, from the set of modules touched since the
    # last release, as per their changelog ... (future: md5sum of
    # files in a module, and file/package association).

    array set review {}

    # package -> list(version)
    set old_version    [loadoldv [location_PACKAGES]]
    array set releasep [loadpkglist [location_PACKAGES]]
    array set currentp [ipackages]

    set modifiedm [modified-modules]
    array set changed {}
    foreach p [array names currentp] {
	foreach {vlist module} $currentp($p) break
	set currentp($p) $vlist
	set changed($p) [struct::set contains $modifiedm $module]
    }

    LoadNotes

    set np 0
    # Process all packages in all modules ...
    foreach m [lsort -dict [modules]] {
	Next ; Progress " $m"
	foreach name [lsort -dict [Provided $m]] {
	    #Next ; Progress "... $m/$name"
	    # Define list of versions, if undefined so far.
	    if {![info exists currentp($name)]} {
		set currentp($name) {}
	    }

	    # Detect new packages. Ignore them.

	    if {![info exists releasep($name)]} {
		#Progress " /new"
		continue
	    }

	    # The package is not new, but possibly changed. And even
	    # if the version has not changed it may have been, this is
	    # indicated by changed(), which is based on the ChangeLog.

	    set vequal [struct::set equal $releasep($name) $currentp($name)]
	    set note   [Note $m $name]

	    # Detect packages whose versions are unchanged, and whose
	    # changelog also indicates no change. Ignore these too.

	    if {!$changed($name) && $vequal} {
		#Progress " /not changed"
		continue
	    }

	    # Now look for packages where both changelog and version
	    # number indicate a change. These we have to review.

	    if {$changed($name) && !$vequal} {
		lappend review($m) [list $name classify $note]
		#Progress " [=cya classify]"
		incr np
		continue
	    }

	    # What remains are packages which are changed according to
	    # their changelog, but their version disagrees. Or the
	    # reverse. These need a big review to see who is right.
	    # We may have to bump their version information, not just
	    # classify changes. Of course, in modules with multiple
	    # packages it is quite possible to be unchanged and the
	    # changelog refers to the siblings.

	    lappend review($m) [list $name mismatch $note]
	    #Progress " [=cya mismatch]"
	    incr np
	}
    }

    Close

    # Postprocessing phase, pull in all relevant changelogs.

    foreach m [array names review] {
	set clog [fileutil::cat $distribution/modules/$m/ChangeLog]
	set entries {}
	foreach e [doctools::changelog::scan $clog] {
	    if {[string match -nocase "*Released and tagged*" $e]} break
	    lappend entries $e
	}
	set entries [doctools::changelog::flatten $entries]

	set review($m) [list $review($m) [join $entries \n\n]]
    }

    set review() $np
    return
}

# see also readme
proc ::sak::review::Provided {m} {
    set result {}
    foreach {p ___} [ppackages $m] {
	lappend result $p
    }
    return $result
}

# see also readme
proc ::sak::review::loadoldv {fname} {
    set f [open $fname r]
    foreach line [split [read $f] \n] {
	set line [string trim $line]
	if {[string match @* $line]} {
	    foreach {__ __ v} $line break
	    close $f
	    return $v
	}
    }
    close $f
    return -code error {Version not found}
}

proc ::sak::review::Progress {text} {
    puts -nonewline stdout $text
    flush stdout
    return
}

proc ::sak::review::Next {} {
    # erase to end of line, then move back to start of line.
    term::ansi::send::eeol
    puts -nonewline stdout \r
    flush stdout
    return
}

proc ::sak::review::Close {} {
    puts stdout ""
    return
}

proc ::sak::review::Clear {} {
    term::ansi::send::clear
    return
}

proc ::sak::review::Banner {text} {
    Clear
    puts stdout "\n <<SAK Tcllib: $text>>\n"
    return
}

proc ::sak::review::Note {m p} {
    # Look for a note, and present to caller, if any.
    variable notes
    #parray notes
    set k [list $m $p]
    #puts <$k>
    if {[info exists notes($k)]} {
	return $notes($k)
    }
    return ""
}

proc ::sak::review::SaveNote {at t} {
    global distribution
    set    f [open [file join $distribution .NOTE] a]
    puts  $f [list $at $t]
    close $f
    return
}

proc ::sak::review::LoadNotes {} {
    global distribution
    variable  notes
    array set notes {}

    catch {
	set f [file join $distribution .NOTE]
	set f [open $f r]
	while {![eof $f]} {
	    if {[gets $f line] < 0} continue
	    set line [string trim $line]
	    if {$line == {}} continue
	    foreach {k t} $line break
	    set notes($k) $t
	}
	close $f
    }

    return
}

# # ## ### ##### ######## ############# ##################### 
## Phase II. Interactively review the changes packages.

# Namespace variables
#
# review      : array, database of all modules, keyed by name
# nm          : number of modules
# modules     : list of module names, keys to --> review
# current     : index in -> modules, current module
# np          : number of packages in current module
# packages    : list of packages in current module
# currentp    : index in --> packages
# im          : 1+current  | indices for display
# ip          : 1+currentp |
# end         : array : module (name) --> index of last package
# stop        : repl exit flag
# map         : array : text -> module/package index
# commands    : proper commands
# allcommands : commands + namesof(map)
# 

proc ::sak::review::Review {} {
    variable review   ;# table of everything to review
    variable nm       ;# number of modules
    variable modules  ;# list of module names, sorted
    variable stop 0   ;# repl exit flag
    variable end      ;# last module/package index.

    variable navcommands
    variable allcommands ;# list of all commands, sorted
    variable commands    ;# list of proper commands, sorted
    variable map         ;# map from package names to module/package indices.
    variable prefix

    Banner "Packages to review: $review()"
    unset   review()

    set nm [array size review]
    if {!$nm} return

    set modules [lsort -dict [array names review]]

    # Map package name --> module/package index.
    set im 0
    foreach m $modules {
	foreach {packages clog} $review($m) break
	set ip 0
	foreach p $packages {
	    set end($im) $ip
	    set end($m) $ip
	    set end() [list $im $ip]
	    foreach {name what tags} $p break
	    lappend map(@$name)    [list $im $ip]
	    lappend map(@$name/$m) [list $im $ip]
	    incr ip
	}
	incr im
    }

    # Drop amibigous mappings, and fill the list of commands.
    foreach k [array names map] {
	# Skip already dropped keys (extended forms).
	if {![info exists map($k)]} continue
	if {[llength $map($k)] < 2} {
	    set map($k) [lindex $map($k) 0]
	    # Drop extended form, not needed.
	    array unset map $k/*
	} else {
	    unset map($k)
	}
    }

    # Map module name --> module/package index
    # If not preempted by package mapping.
    set im -1
    foreach m $modules {
	incr im
	if {[info exists map(@$m)]} continue
	set map(@$m) [list $im 0]
    }

    # Map command prefix -> full command.

    array set prefix {}
    foreach c [info commands ::sak::review::C_*] {
	set c [string range [namespace tail $c] 2 end]
	lappend commands    $c
	lappend allcommands $c
	set buf {}
	foreach ch [split $c {}] {
	    append buf $ch
	    lappend prefix($buf) $c
	}
    }

    foreach c [array names map] {
	lappend allcommands $c
	set buf {}
	foreach ch [split $c {}] {
	    append buf $ch
	    lappend prefix($buf) $c
	}
    }

    set commands    [lsort -dict $commands]
    set allcommands [lsort -dict $allcommands]
    set navcommands [lsort -dict [array names map]]

    # Enter the REPL
    Goto {0 0} 1
    linenoise::cmdloop \
	-history   1 \
	-exit      ::sak::review::Exit \
	-continued ::sak::review::Continued \
	-prompt1   ::sak::review::Prompt \
	-complete  ::sak::review::Complete \
	-dispatch  ::sak::review::Dispatch
    return
}

# # ## ### ##### ######## ############# ##################### 

proc ::sak::review::RefreshDisplay {} {
    variable m
    variable im
    variable nm
    variable clog
    variable what

    Banner "\[$im/$nm\] [=blue [string totitle $what]] [=green $m]"
    puts "| [join [split $clog \n] \n|]\n"
    return
}

proc ::sak::review::Exit {} {
    variable stop
    return  $stop
}

proc ::sak::review::Continued {buffer} {
    return 0
}

proc ::sak::review::Prompt {} {
    variable ip
    variable np
    variable name
    variable tags

    return "\[$ip/$np\] $name ($tags): "
}

proc ::sak::review::Complete {line} {
    variable allcommands
    if {$line eq {}} {
	return $allcommands
    } elseif {[llength $line] == 1} {
	set r {}
	foreach c $allcommands {
	    if {![string match ${line}* $c]} continue
	    lappend r $c
	}
	return $r
    } else {
	return {}
    }
}

proc ::sak::review::Dispatch {line} {
    variable prefix
    variable map

    if {$line == ""} { set line next }

    set cmd [lindex $line 0]

    if {![info exists prefix($cmd)]} {
	return -code error "Unknown command $cmd, use help or ? to list them"
    } elseif {[llength $prefix($cmd)] > 1} {
	return -code error "Ambigous prefix \"$cmd\", expected [join $prefix($cmd) {, }]"
    }

    # Map prefix to actual command
    set line [lreplace $line 0 0 $prefix($cmd)]

    # Run command.
    if {[info exists map($cmd)]} {
	Goto $map($cmd)
	return
    }
    eval C_$line
}

proc ::sak::review::Goto {loc {skip 0}} {
    variable review
    variable modules
    variable packages
    variable clog
    variable current
    variable currentp
    variable nm
    variable np
    variable at
    variable tags
    variable what
    variable name

    variable m
    variable p
    variable ip
    variable im

    foreach {current currentp} $loc break

    puts "Goto ($current/$currentp)"

    set m [lindex $modules $current]
    foreach {packages clog} $review($m) break

    set np [llength $packages]
    set p  [lindex  $packages $currentp]

    foreach {name what tags} $p break
    set at [list $m $name]

    set im [expr {1+$current}]
    set ip [expr {1+$currentp}]

    if {$skip && ([llength $tags] ||
		  ($tags == "---"))} {
	C_next
    } else {
	RefreshDisplay
    }
    return
}

proc ::sak::review::C_exit {} { variable stop 1 }
proc ::sak::review::C_quit {} { variable stop 1 }

proc ::sak::review::C_? {} { C_help }
proc ::sak::review::C_help {} {
    variable commands
    return [join $commands {, }]
}

proc ::sak::review::C_@? {} { C_@help }
proc ::sak::review::C_@help {} {
    variable navcommands
    return [join $navcommands {, }]
}

proc ::sak::review::C_@start {} { Goto {0 0} }
proc ::sak::review::C_@0     {} { Goto {0 0} }
proc ::sak::review::C_@end   {} { variable end ; Goto $end() }

proc ::sak::review::C_next {} {
    variable tags
    variable current
    variable currentp

    C_step 0

    set stop @$current/$currentp
    while {[llength $tags] ||
	   ($tags == "---")} {
	C_step 0
	if {"@$current/$currentp" == "$stop"} break
    }

    RefreshDisplay
    return
}

proc ::sak::review::C_step {{refresh 1}} {
    variable nm
    variable np
    variable current
    variable currentp
    variable packages

    incr currentp
    if {$currentp >= $np} {
	# skip to next module, first package
	incr current
	if {$current >= $nm} {
	    # skip to first module
	    set current 0
	}
	set currentp 0

    }
    Goto [list $current $currentp]
    return
}

proc ::sak::review::C_prev {} {
    variable end
    variable nm
    variable np
    variable current
    variable currentp
    variable packages

    incr currentp -1
    if {$currentp < 0} {
	# skip to previous module, last package
	incr current -1
	if {$current < 0} {
	    # skip to back to last module
	    set current [expr {$nm - 1}]
	}
	set currentp $end($current)
    }
    Goto [list $current $currentp]
    return
}

# Commands to add/remove tags, clear set, replace set

proc ::sak::review::C_feature {} { +T EF }
proc ::sak::review::C_test    {} { +T T }
proc ::sak::review::C_doc     {} { +T D }
proc ::sak::review::C_bug     {} { +T B }
proc ::sak::review::C_perf    {} { +T P }
proc ::sak::review::C_example {} { +T EX }
proc ::sak::review::C_api     {} { +T API }
proc ::sak::review::C_impl    {} { +T I }

proc ::sak::review::C_-feature {} { -T EF }
proc ::sak::review::C_-test    {} { -T T }
proc ::sak::review::C_-doc     {} { -T D }
proc ::sak::review::C_-bug     {} { -T B }
proc ::sak::review::C_-perf    {} { -T P }
proc ::sak::review::C_-example {} { -T EX }
proc ::sak::review::C_-api     {} { -T API }
proc ::sak::review::C_-impl    {} { -T I }

proc ::sak::review::C_---   {} { =T --- }
proc ::sak::review::C_clear {} { =T --- }
#proc ::sak::review::C_cn {} { C_clear ; C_next }

proc ::sak::review::+T {tag} {
    variable tags
    if {[lsearch -exact $tags $tag] >= 0} {
	RefreshDisplay
	return
    }
    =T [linsert $tags end $tag]
    return
}

proc ::sak::review::-T {tag} {
    variable tags
    set pos [lsearch -exact $tags $tag]
    if {$pos < 0} {
	RefreshDisplay
	return
    }
    =T [lreplace $tags $pos $pos]
    return
}

proc ::sak::review::=T {newtags} {
    variable review
    variable clog
    variable packages
    variable currentp
    variable p
    variable m
    variable at
    variable name
    variable what
    variable tags

    if {([llength $newtags] > 1) &&
	([set pos [lsearch -exact $newtags ---]] >= 0)} {
	# Drop --- if there are other tags.
	set newtags [lreplace $newtags $pos $pos]
    }

    set tags       [lsort -dict $newtags]
    set p          [list $name $what $newtags]
    set packages   [lreplace $packages $currentp $currentp $p]
    set review($m) [list $packages $clog]

    SaveNote $at $tags
    RefreshDisplay
    return
}

proc ::sak::review::?T {} {
    variable tags
    return $tags
}

##
# ###

namespace eval ::sak::review {}

package provide sak::review 1.0

Added support/devel/sak/review/topic.txt.



>
1
review		Interactively review changes since the last release.