Fossil Wrapper

Check-in [6933053d49]
Login

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

Overview
Comment:one bug and one regression less.
Timelines: family | ancestors | descendants | both | dresden
Files: files | file ages | folders
SHA1: 6933053d49e0e19045ed0926a7cc46e0d150c96d
User & Date: j 2019-07-05 16:50:57
Context
2019-07-21
12:27
merged `grep'. check-in: 8df6e8d8f7 user: j tags: dresden
2019-07-05
16:52
a first try at improving/augmenting `fossil grep'. check-in: bd064e74b7 user: j tags: grep
16:50
one bug and one regression less. check-in: 6933053d49 user: j tags: dresden
2019-06-25
12:16
deleted redundant `show' interceptor and defined a new alias `s' to `changes --differ' which does exactly the same thing. check-in: eb6ae3b1a6 user: j tags: dresden
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to fsl.

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
...
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
...
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
...
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
...
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
...
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
...
585
586
587
588
589
590
591



592
593
594
595
596
597
598
599
...
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
...
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
...
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
...
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
...
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
...
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
...
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
...
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
....
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
....
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
....
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
          2. Getting help:
          Issuing `fsl help COMMAND' works for all `fossil' commands as well
          as for the command interceptors defined by `fsl' (see the wiki
          for further information). Currently these are:
             - alias
             - wrapper
             - df
          
          Issuing `fsl -help' provides a short help text for the `fsl' specific
          options.
       }
       return $mantext
    }

    proc init {filename} {
................................................................................
   # options so it is not sufficient to just test for command name in
   # this case (currently the only example I'm aware of is
   # "amend -e").

   # define a regexp pattern identifying the option bearing
   # commands (and their valid abbreviations) that need interaction.
   # append further commands to the pattern via alteration (logical
   # OR)): 
   append needInteraction {^(am(e(nd?)?)?.* (-e|--edit-comment)( |$))}

   if {[regexp $needInteraction $params]} {
      return true
   } else {
      set command [first $params]
      switch -re $command {
................................................................................
      dict set numrevs $rev :$numrev
   }

   # append chronological revision numbers to sha1 hashes. in order
   # to keep this reasonably fast on large repos, we do *not* use
   # thousands of `regsub' calls on the whole timeline but rather
   # perform those only on a per-line basis and join everything
   # afterwards. 

   set timeline {}
   foreach line $lines {
      if {[regexp $rgxrev $line {} {} {} {} {} sha1rev]} {
         set val [dict get $numrevs $sha1rev]
         regsub $rgxrev $line &$val line
      }
................................................................................

   array set colors {
      descendants yellow
      finfo       blue
      search      yellow
      timeline    yellow

   } 
   set timdcol $colors($command)

   # colorize
   regsub -all $rgxdatehead $timeline \\1[coloured blue {\2\3\4}]\\5 timeline
   regsub -all $rgxtimd $timeline \\1[coloured $timdcol \\2] timeline
   regsub -all $rgxarti $timeline \\1[coloured red \\2]\\3\\4[coloured magenta \\5] timeline
   regsub -all $rgxuser $timeline \\1[coloured yellow \\2][coloured green \\5] timeline
   regsub -all $rgxtags $timeline [coloured yellow \\1][coloured cyan \\3]\\4 timeline 
   regsub      $rgxcurr $timeline [display bright &] timeline
   regsub -all $rgxfmbr $timeline [display underscored &] timeline
   regsub      $rgxlast $timeline [display reversed &] timeline

   set timeline [string trimright $timeline "\n"]
   set lines [split $timeline "\n" ]
   set lines [map {x {set x "$x\n"}}  $lines]
................................................................................
         set rev "\[$rev\]"
         # hopefully, all these are still on the same line ...:
         set date [coloured blue $date]
         set user [coloured green $user]
         set branch [coloured cyan $branch]
      }
      if {![catch {set numrev [dict get $revnums $rev]}]} {
         set rev "$rev:$numrev" 
      }
      set words [lreplace $words 0 3 $rev $date $user $branch]
      set line [join $words]
      lappend out $line\n
   }
   return $out
}


proc computeRevnums {params} {
#-----------------------------------------------------------------------
# generate a dictionary of SHA1 keys vs. revision numbers
#-----------------------------------------------------------------------
   set revcnt  0
   set numrev  0
................................................................................
      }
   }
   return $revnums
}

proc adjustWidth params {
   set widopt {}
   regexp -- {(timeline|finfo|search|descendants).*(-W)} $params widopt 
   if {$widopt == ""} then {
      # determine total number of checkins for computation of required
      # additional space. the following works for the current format of
      # `fossil info' output...

      set rgxrepo {\-R\s+.+}
      set repo {}
      regexp $rgxrepo $params repo
      if {[catch {set fslinfo [exec fossil info {*}$repo]}]} {
         return $params
      }
      
      # we need to ensure that the `fslinfo' string is a valid Tcl list. 
      # this is not guaranteed a priori (e.g. `this is my "string"definition'
      # would fail. so we first explicitly split it:
      set fslinfo [split $fslinfo]

      set numrev [lindex $fslinfo end]; #tot. no. of checkins
      set numrev [expr $numrev - 1]; #ordinal no. of last checkin

................................................................................

      set size   [exec stty size]
      set cols   [lindex $size end]
      set need   [expr [string length $numrev] + $more]
      set width  [expr $cols - $need]

      regsub {(timeline|finfo|search|descendants)} $params "\\1 -W $width" params



   } 
   return $params
}

proc processoptions argv {
   # a `package require cmdline' sometimes can take ages for the lookup
   # of the location if not yet cached (problem encountered under OSX
   # at some point). we try to avoid this by assuming `tcllib' is
................................................................................
   # `cmdline.tcl' directly before resorting to `package require'.
   # whether this workaround continues to make sense is not quite
   # sure but it does no harm either ...

   set status [catch {
      set dname [file dirname $::tcl_library]
      set dir [lindex [lsort -dictionary [glob -directory $dname "*tcllib*"]] 0]
      source [file join $dir cmdline cmdline.tcl] 
   }]
   if {$status != 0} { package require cmdline }

   set progid [::cmdline::getArgv0]

   set knownoptions {
      { reset       "Recreate the default `~/.fslrc' config file by overwriting the existing one." }
................................................................................

      `$progid' {options} command {command_options} {file(s)}

      where `command' is either one of the `$progid'-specific alias definitions
      or command interceptors or a native `fossil' command.

      Options recognized by `$progid':
      
   "

   # `getoptions' raises error even when called with `-help'. this is
   # irritating, so we work around it ...
   if { [catch {::cmdline::getoptions argv $knownoptions $usage} optlist] } {
      if { [string length $argv] } {
         puts "[lindex $argv 0]: invalid option, see `fsl -help'. Giving up"
................................................................................

proc interceptor {command_spec body} {
    # cf. `apply' documentation: the anonymous function for `apply'
    # has to be specified in the form {args body namespace} where
    # `args' spefifies the formal arguments of the function. in the
    # present case `args' is identical to `params'. in the current setup
    # the `namespace' argument is apparently redundant and could be
    # ommitted: 

    set fn [list {params} $body [uplevel 1 {namespace current}]]
    
    foreach command [triggers_for $command_spec] {
       # this loop sets up the dictionary `config::commands' whose
       # keys are the known interceptor commands and whose values are
       # the corresponding anonymous function definitions. note that each
       # alternate name in `command_spec' (e.g., a, ali, alias etc.)
       # generates a further entry (with identical value).
       dict set config::commands $command $fn
................................................................................
}

interceptor ig:ignore {
# ------------------------------------------------------------------------
# report the list of files in the checkout currently ignored by `fossil'
# ------------------------------------------------------------------------
   set afilter ::config::fslrc::status
   
   if { [catch {exec fossil extras} pattern] } {
      puts $pattern
      exit 1
   }
   regsub -all {\n} $pattern {|} pattern
   if {$pattern != ""} {
      set pattern "($pattern)";  #the required OR pattern
................................................................................
   # since it is not guaranteed that this command is issued only when
   # being in the local root of the repo:
   if { [catch {exec fossil status} report] } {
      puts $report
      exit 1
   }
   regexp -line {^local-root:[ ]*(.*)$} $report {} localroot
   
   foreach name $uvfiles {
      if { [catch {exec fossil uv export $name $localroot$name} msg] } {
         puts $msg
         exit 1
      } else { puts $localroot$name }
   }
}

interceptor ll {
# ------------------------------------------------------------------------
# Provide `ls -v' output plus some eye candy
# ------------------------------------------------------------------------
   set afilter ::config::fslrc::status
   
   catch {exec fossil ls -v} lsrep 

   set lsrep [split $lsrep \n]
   foreach line $lsrep {
      filter_with $afilter "$line"
      puts ""
   }
}
................................................................................
#  * trim leading and trailing blanks, if any
#  * replace remaining blanks by underscore
#  * append "-fsl"
#  * use resulting name as checkout directory and create it
#  * clone repo into this directory under the invariant name `.fslrepo'
#
# Otherwise (if FILENAME is provided) just pass the call unmodified to
# fossil. 
# ------------------------------------------------------------------------
   set defaultName .fslrepo
   set params [lreplace $params 0 0 clone]
   set hasOpts [regexp {^-} [lindex $params 1]]
   if {!$hasOpts && [llength $params] == 3} {
      # we do not want to parse all possible `clone' options properly,
      # but this case (a call without options but two arguments...)
................................................................................
      # by `clone' and thus the intention to automaticlly
      # "clone+open" the repo using the described naming strategy.
      set uri [lindex $params end]
      set remoteName [lindex [file split $uri] end]
      set checkout [split [string trimleft $remoteName .] .]
      if {[llength $checkout] > 1} {
         set checkout [lreplace $checkout end end]
      } 
      set checkout [string trim [join $checkout]]
      regsub {(.*)-fsl$} $checkout {\1} checkout
      regsub -all { } $checkout {_} checkout
      append checkout -fsl
      if {[file exists $checkout]} {
         puts "$checkout: file exists"
         exit 1
................................................................................
            exit 1
         } else {
            if {[catch {exec fossil open $defaultName} msg]} {
               puts $msg
               exit 1
            }
         }
      } 
   } else { return $params }
}

interceptor w:wrapper {
# ------------------------------------------------------------------------
# This interceptor provides a compilation of the current aliases, filters,
# and interceptors.
................................................................................
      if {$word == {--to}} {
         set tidx [expr $idx + 1]
         continue
      }
   }
   if {$fidx > 0} {set fversion [lindex $params $fidx]}
   if {$tidx > 0} {set tversion [lindex $params $tidx]}
   
   if {[dict exists $num2hash $fversion]} {
      set fversion [dict get $num2hash $fversion]
   }
   if {[dict exists $num2hash $tversion]} {
      set tversion [dict get $num2hash $tversion]
   }

................................................................................
    while 1 {
        if {[interactive? $params]} {
            interact; break
        }
        expect {
            eof { break }
            \n {
            #collect everything and postpone filtering
            lappend lines $expect_out(buffer)
        }
            -notransfer -re {[?:] $} {
                # [*] Under certain conditions, an incomplete output
                # fragment will match this pattern; check whether
                # there's a pending newline character:
                set timeout 0
                #after 1
                expect -notransfer \n {
................................................................................
          $command == "search"      ||
          $command == "descendants"
          ) && [llength $lines] > 1} {
          set revnums [computeRevnums $params]
          set lines [reformTimeline $lines $revnums $command]
       } elseif {$command == "finfo" && [llength $lines] > 1} {
          if {[regexp {finfo \s*-p} $params]} {
             # this is `finfo -p' (a.k.a. `cat').
	     # prevent further filtering and pass through as is
             # resetting filter chain to `cat' filter:
             #
             set chain ::config::fslrc::cat
          } elseif {[regexp {finfo.*-b} $params]} {
             set revnums [computeRevnums $params]
             set lines [reformFinfo-b $lines $revnums]
          } else {
             set revnums [computeRevnums $params]
             set lines [reformTimeline $lines $revnums $command]
          }







|







 







|







 







|







 







|







|







 







|







<







 







|











|
|







 







>
>
>
|







 







|







 







|







 







|


|







 







|







 







|













|
|







 







|







 







|







 







|







 







|







 







|
|
|







 







|
|
|
<
|







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
...
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
...
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
...
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
...
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523

524
525
526
527
528
529
530
...
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
...
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
...
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
...
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
...
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
...
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
...
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
...
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
...
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
...
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
....
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
....
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
....
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426

1427
1428
1429
1430
1431
1432
1433
1434
          2. Getting help:
          Issuing `fsl help COMMAND' works for all `fossil' commands as well
          as for the command interceptors defined by `fsl' (see the wiki
          for further information). Currently these are:
             - alias
             - wrapper
             - df

          Issuing `fsl -help' provides a short help text for the `fsl' specific
          options.
       }
       return $mantext
    }

    proc init {filename} {
................................................................................
   # options so it is not sufficient to just test for command name in
   # this case (currently the only example I'm aware of is
   # "amend -e").

   # define a regexp pattern identifying the option bearing
   # commands (and their valid abbreviations) that need interaction.
   # append further commands to the pattern via alteration (logical
   # OR)):
   append needInteraction {^(am(e(nd?)?)?.* (-e|--edit-comment)( |$))}

   if {[regexp $needInteraction $params]} {
      return true
   } else {
      set command [first $params]
      switch -re $command {
................................................................................
      dict set numrevs $rev :$numrev
   }

   # append chronological revision numbers to sha1 hashes. in order
   # to keep this reasonably fast on large repos, we do *not* use
   # thousands of `regsub' calls on the whole timeline but rather
   # perform those only on a per-line basis and join everything
   # afterwards.

   set timeline {}
   foreach line $lines {
      if {[regexp $rgxrev $line {} {} {} {} {} sha1rev]} {
         set val [dict get $numrevs $sha1rev]
         regsub $rgxrev $line &$val line
      }
................................................................................

   array set colors {
      descendants yellow
      finfo       blue
      search      yellow
      timeline    yellow

   }
   set timdcol $colors($command)

   # colorize
   regsub -all $rgxdatehead $timeline \\1[coloured blue {\2\3\4}]\\5 timeline
   regsub -all $rgxtimd $timeline \\1[coloured $timdcol \\2] timeline
   regsub -all $rgxarti $timeline \\1[coloured red \\2]\\3\\4[coloured magenta \\5] timeline
   regsub -all $rgxuser $timeline \\1[coloured yellow \\2][coloured green \\5] timeline
   regsub -all $rgxtags $timeline [coloured yellow \\1][coloured cyan \\3]\\4 timeline
   regsub      $rgxcurr $timeline [display bright &] timeline
   regsub -all $rgxfmbr $timeline [display underscored &] timeline
   regsub      $rgxlast $timeline [display reversed &] timeline

   set timeline [string trimright $timeline "\n"]
   set lines [split $timeline "\n" ]
   set lines [map {x {set x "$x\n"}}  $lines]
................................................................................
         set rev "\[$rev\]"
         # hopefully, all these are still on the same line ...:
         set date [coloured blue $date]
         set user [coloured green $user]
         set branch [coloured cyan $branch]
      }
      if {![catch {set numrev [dict get $revnums $rev]}]} {
         set rev "$rev:$numrev"
      }
      set words [lreplace $words 0 3 $rev $date $user $branch]
      set line [join $words]
      lappend out $line\n
   }
   return $out
}


proc computeRevnums {params} {
#-----------------------------------------------------------------------
# generate a dictionary of SHA1 keys vs. revision numbers
#-----------------------------------------------------------------------
   set revcnt  0
   set numrev  0
................................................................................
      }
   }
   return $revnums
}

proc adjustWidth params {
   set widopt {}
   regexp -- {(timeline|finfo|search|descendants).*(-W)} $params widopt
   if {$widopt == ""} then {
      # determine total number of checkins for computation of required
      # additional space. the following works for the current format of
      # `fossil info' output...

      set rgxrepo {\-R\s+.+}
      set repo {}
      regexp $rgxrepo $params repo
      if {[catch {set fslinfo [exec fossil info {*}$repo]}]} {
         return $params
      }

      # we need to ensure that the `fslinfo' string is a valid Tcl list.
      # this is not guaranteed a priori (e.g. `this is my "string"definition'
      # would fail. so we first explicitly split it:
      set fslinfo [split $fslinfo]

      set numrev [lindex $fslinfo end]; #tot. no. of checkins
      set numrev [expr $numrev - 1]; #ordinal no. of last checkin

................................................................................

      set size   [exec stty size]
      set cols   [lindex $size end]
      set need   [expr [string length $numrev] + $more]
      set width  [expr $cols - $need]

      regsub {(timeline|finfo|search|descendants)} $params "\\1 -W $width" params
      # we need do undo the -W insertion in case we are dealing with
      # `finfo -p'
      regsub {(finfo)( -W .*)( -p)(.*)} $params "\\1\\3\\4" params
   }
   return $params
}

proc processoptions argv {
   # a `package require cmdline' sometimes can take ages for the lookup
   # of the location if not yet cached (problem encountered under OSX
   # at some point). we try to avoid this by assuming `tcllib' is
................................................................................
   # `cmdline.tcl' directly before resorting to `package require'.
   # whether this workaround continues to make sense is not quite
   # sure but it does no harm either ...

   set status [catch {
      set dname [file dirname $::tcl_library]
      set dir [lindex [lsort -dictionary [glob -directory $dname "*tcllib*"]] 0]
      source [file join $dir cmdline cmdline.tcl]
   }]
   if {$status != 0} { package require cmdline }

   set progid [::cmdline::getArgv0]

   set knownoptions {
      { reset       "Recreate the default `~/.fslrc' config file by overwriting the existing one." }
................................................................................

      `$progid' {options} command {command_options} {file(s)}

      where `command' is either one of the `$progid'-specific alias definitions
      or command interceptors or a native `fossil' command.

      Options recognized by `$progid':

   "

   # `getoptions' raises error even when called with `-help'. this is
   # irritating, so we work around it ...
   if { [catch {::cmdline::getoptions argv $knownoptions $usage} optlist] } {
      if { [string length $argv] } {
         puts "[lindex $argv 0]: invalid option, see `fsl -help'. Giving up"
................................................................................

proc interceptor {command_spec body} {
    # cf. `apply' documentation: the anonymous function for `apply'
    # has to be specified in the form {args body namespace} where
    # `args' spefifies the formal arguments of the function. in the
    # present case `args' is identical to `params'. in the current setup
    # the `namespace' argument is apparently redundant and could be
    # ommitted:

    set fn [list {params} $body [uplevel 1 {namespace current}]]

    foreach command [triggers_for $command_spec] {
       # this loop sets up the dictionary `config::commands' whose
       # keys are the known interceptor commands and whose values are
       # the corresponding anonymous function definitions. note that each
       # alternate name in `command_spec' (e.g., a, ali, alias etc.)
       # generates a further entry (with identical value).
       dict set config::commands $command $fn
................................................................................
}

interceptor ig:ignore {
# ------------------------------------------------------------------------
# report the list of files in the checkout currently ignored by `fossil'
# ------------------------------------------------------------------------
   set afilter ::config::fslrc::status

   if { [catch {exec fossil extras} pattern] } {
      puts $pattern
      exit 1
   }
   regsub -all {\n} $pattern {|} pattern
   if {$pattern != ""} {
      set pattern "($pattern)";  #the required OR pattern
................................................................................
   # since it is not guaranteed that this command is issued only when
   # being in the local root of the repo:
   if { [catch {exec fossil status} report] } {
      puts $report
      exit 1
   }
   regexp -line {^local-root:[ ]*(.*)$} $report {} localroot

   foreach name $uvfiles {
      if { [catch {exec fossil uv export $name $localroot$name} msg] } {
         puts $msg
         exit 1
      } else { puts $localroot$name }
   }
}

interceptor ll {
# ------------------------------------------------------------------------
# Provide `ls -v' output plus some eye candy
# ------------------------------------------------------------------------
   set afilter ::config::fslrc::status

   catch {exec fossil ls -v} lsrep

   set lsrep [split $lsrep \n]
   foreach line $lsrep {
      filter_with $afilter "$line"
      puts ""
   }
}
................................................................................
#  * trim leading and trailing blanks, if any
#  * replace remaining blanks by underscore
#  * append "-fsl"
#  * use resulting name as checkout directory and create it
#  * clone repo into this directory under the invariant name `.fslrepo'
#
# Otherwise (if FILENAME is provided) just pass the call unmodified to
# fossil.
# ------------------------------------------------------------------------
   set defaultName .fslrepo
   set params [lreplace $params 0 0 clone]
   set hasOpts [regexp {^-} [lindex $params 1]]
   if {!$hasOpts && [llength $params] == 3} {
      # we do not want to parse all possible `clone' options properly,
      # but this case (a call without options but two arguments...)
................................................................................
      # by `clone' and thus the intention to automaticlly
      # "clone+open" the repo using the described naming strategy.
      set uri [lindex $params end]
      set remoteName [lindex [file split $uri] end]
      set checkout [split [string trimleft $remoteName .] .]
      if {[llength $checkout] > 1} {
         set checkout [lreplace $checkout end end]
      }
      set checkout [string trim [join $checkout]]
      regsub {(.*)-fsl$} $checkout {\1} checkout
      regsub -all { } $checkout {_} checkout
      append checkout -fsl
      if {[file exists $checkout]} {
         puts "$checkout: file exists"
         exit 1
................................................................................
            exit 1
         } else {
            if {[catch {exec fossil open $defaultName} msg]} {
               puts $msg
               exit 1
            }
         }
      }
   } else { return $params }
}

interceptor w:wrapper {
# ------------------------------------------------------------------------
# This interceptor provides a compilation of the current aliases, filters,
# and interceptors.
................................................................................
      if {$word == {--to}} {
         set tidx [expr $idx + 1]
         continue
      }
   }
   if {$fidx > 0} {set fversion [lindex $params $fidx]}
   if {$tidx > 0} {set tversion [lindex $params $tidx]}

   if {[dict exists $num2hash $fversion]} {
      set fversion [dict get $num2hash $fversion]
   }
   if {[dict exists $num2hash $tversion]} {
      set tversion [dict get $num2hash $tversion]
   }

................................................................................
    while 1 {
        if {[interactive? $params]} {
            interact; break
        }
        expect {
            eof { break }
            \n {
                #collect everything and postpone filtering
                lappend lines $expect_out(buffer)
            }
            -notransfer -re {[?:] $} {
                # [*] Under certain conditions, an incomplete output
                # fragment will match this pattern; check whether
                # there's a pending newline character:
                set timeout 0
                #after 1
                expect -notransfer \n {
................................................................................
          $command == "search"      ||
          $command == "descendants"
          ) && [llength $lines] > 1} {
          set revnums [computeRevnums $params]
          set lines [reformTimeline $lines $revnums $command]
       } elseif {$command == "finfo" && [llength $lines] > 1} {
          if {[regexp {finfo \s*-p} $params]} {
             # this is `finfo -p' (a.k.a. `cat'). prevent further
             # filtering and pass through as is by (re)setting filter
             # chain to `passthrough' filter:

             set chain ::config::fslrc::passthrough
          } elseif {[regexp {finfo.*-b} $params]} {
             set revnums [computeRevnums $params]
             set lines [reformFinfo-b $lines $revnums]
          } else {
             set revnums [computeRevnums $params]
             set lines [reformTimeline $lines $revnums $command]
          }