7
7
"html/template"
8
8
"io"
9
9
"os"
10
- "sort"
11
10
"strconv"
12
11
"strings"
13
12
"sync"
@@ -43,12 +42,12 @@ type Viddy struct {
43
42
timeView * tview.TextView
44
43
historyView * tview.Table
45
44
historyRows map [int64 ]* HistoryRow
46
- sync.RWMutex
47
45
48
46
// bWidth store current pty width.
49
47
bWidth atomic.Value
50
48
51
- idList []int64
49
+ // id -> row count (as of just after the snapshot was added).
50
+ historyRowCount map [int64 ]int
52
51
53
52
bodyView * tview.TextView
54
53
app * tview.Application
@@ -69,6 +68,7 @@ type Viddy struct {
69
68
isNoTitle bool
70
69
isRingBell bool
71
70
isShowDiff bool
71
+ skipEmptyDiffs bool
72
72
isEditQuery bool
73
73
unfold bool
74
74
pty bool
@@ -124,17 +124,20 @@ func NewViddy(conf *config) *Viddy {
124
124
snapshots : sync.Map {},
125
125
historyRows : map [int64 ]* HistoryRow {},
126
126
127
+ historyRowCount : map [int64 ]int {},
128
+
127
129
snapshotQueue : snapshotQueue ,
128
130
queue : make (chan int64 ),
129
131
finishedQueue : make (chan int64 ),
130
132
diffQueue : make (chan int64 , 100 ),
131
133
132
- isRingBell : conf .general .bell ,
133
- isShowDiff : conf .general .differences ,
134
- isNoTitle : conf .general .noTitle ,
135
- isDebug : conf .general .debug ,
136
- unfold : conf .general .unfold ,
137
- pty : conf .general .pty ,
134
+ isRingBell : conf .general .bell ,
135
+ isShowDiff : conf .general .differences ,
136
+ skipEmptyDiffs : conf .general .skipEmptyDiffs ,
137
+ isNoTitle : conf .general .noTitle ,
138
+ isDebug : conf .general .debug ,
139
+ unfold : conf .general .unfold ,
140
+ pty : conf .general .pty ,
138
141
139
142
currentID : - 1 ,
140
143
latestFinishedID : - 1 ,
@@ -153,14 +156,14 @@ func (v *Viddy) SetIsNoTitle(b bool) {
153
156
154
157
func (v * Viddy ) SetIsShowDiff (b bool ) {
155
158
v .isShowDiff = b
156
- v .setSelection (v .currentID )
159
+ v .setSelection (v .currentID , - 1 )
157
160
v .arrange ()
158
161
}
159
162
160
163
func (v * Viddy ) SetIsTimeMachine (b bool ) {
161
164
v .isTimeMachine = b
162
165
if ! v .isTimeMachine {
163
- v .setSelection (v .latestFinishedID )
166
+ v .setSelection (v .latestFinishedID , - 1 )
164
167
}
165
168
166
169
v .arrange ()
@@ -183,6 +186,26 @@ func (v *Viddy) startRunner() {
183
186
}
184
187
}
185
188
189
+ func (v * Viddy ) updateSelection () {
190
+ if ! v .isTimeMachine {
191
+ v .setSelection (v .latestFinishedID , - 1 )
192
+ } else {
193
+ v .setSelection (v .currentID , - 1 )
194
+ }
195
+ }
196
+
197
+ func (v * Viddy ) addSnapshotToView (id int64 , r * HistoryRow ) {
198
+ v .historyView .InsertRow (0 )
199
+ v .historyView .SetCell (0 , 0 , r .id )
200
+ v .historyView .SetCell (0 , 1 , r .addition )
201
+ v .historyView .SetCell (0 , 2 , r .deletion )
202
+ v .historyView .SetCell (0 , 3 , r .exitCode )
203
+
204
+ v .historyRowCount [id ] = v .historyView .GetRowCount ()
205
+
206
+ v .updateSelection ()
207
+ }
208
+
186
209
func (v * Viddy ) diffQueueHandler () {
187
210
for {
188
211
func () {
@@ -203,17 +226,24 @@ func (v *Viddy) diffQueueHandler() {
203
226
return
204
227
}
205
228
206
- if v . isRingBell {
207
- if s . diffAdditionCount > 0 || s . diffDeletionCount > 0 {
229
+ if s . diffAdditionCount > 0 || s . diffDeletionCount > 0 {
230
+ if v . isRingBell {
208
231
fmt .Print (string (byte (7 )))
209
232
}
233
+ } else if v .skipEmptyDiffs {
234
+ return
210
235
}
211
236
212
237
r , ok := v .historyRows [id ]
213
238
if ! ok {
214
239
return
215
240
}
216
241
242
+ // if skipEmptyDiffs is true, queueHandler wouldn't have added the
243
+ // snapshot to view, so we need to add it here.
244
+ if v .skipEmptyDiffs {
245
+ v .addSnapshotToView (id , r )
246
+ }
217
247
r .addition .SetText ("+" + strconv .Itoa (s .diffAdditionCount ))
218
248
r .deletion .SetText ("-" + strconv .Itoa (s .diffDeletionCount ))
219
249
}()
@@ -249,11 +279,7 @@ func (v *Viddy) queueHandler() {
249
279
ls := v .getSnapShot (v .latestFinishedID )
250
280
if ls == nil || s .start .After (ls .start ) {
251
281
v .latestFinishedID = id
252
- if ! v .isTimeMachine {
253
- v .setSelection (id )
254
- } else {
255
- v .setSelection (v .currentID )
256
- }
282
+ v .updateSelection ()
257
283
}
258
284
case id := <- v .queue :
259
285
if v .isSuspend {
@@ -266,34 +292,41 @@ func (v *Viddy) queueHandler() {
266
292
deletionCell := tview .NewTableCell ("" ).SetTextColor (tcell .ColorRed )
267
293
exitCodeCell := tview .NewTableCell ("" ).SetTextColor (tcell .ColorYellow )
268
294
269
- v . historyRows [ s . id ] = & HistoryRow {
295
+ r : = & HistoryRow {
270
296
id : idCell ,
271
297
addition : additionCell ,
272
298
deletion : deletionCell ,
273
299
exitCode : exitCodeCell ,
274
300
}
275
-
276
- v .historyView .InsertRow (0 )
277
- v .historyView .SetCell (0 , 0 , idCell )
278
- v .historyView .SetCell (0 , 1 , additionCell )
279
- v .historyView .SetCell (0 , 2 , deletionCell )
280
- v .historyView .SetCell (0 , 3 , exitCodeCell )
281
-
282
- v .Lock ()
283
- v .idList = append (v .idList , id )
284
- v .Unlock ()
285
-
286
- if ! v .isTimeMachine {
287
- v .setSelection (v .latestFinishedID )
288
- } else {
289
- v .setSelection (v .currentID )
301
+ v .historyRows [s .id ] = r
302
+
303
+ // if skipEmptyDiffs is true, we need to check if the snapshot
304
+ // is empty before adding it to the view (in diffQueueHandler).
305
+ //
306
+ // This means we're trading off two things:
307
+ //
308
+ // 1. We're not showing the snapshot in history view until the
309
+ // command finishes running, which means it's not possible
310
+ // to see partial output.
311
+ // 2. Order of the snapshots in history view is lost
312
+ // (in non-sequential modes), as some commands could finish
313
+ // running quicker than others for whatever reason.
314
+ //
315
+ // It of course is possible to address these issues by adding
316
+ // all snapshots to the history view and then removing the empty
317
+ // ones but it unnecessarily complicates the implementation.
318
+ if ! v .skipEmptyDiffs {
319
+ v .addSnapshotToView (id , r )
290
320
}
291
321
}
292
322
}()
293
323
}
294
324
}
295
325
296
- func (v * Viddy ) setSelection (id int64 ) {
326
+ // setSelection selects the given row in the history view. If row is -1, it will
327
+ // attempt to select the row corresponding to the given id (or default to the
328
+ // latest row if id doesn't exist).
329
+ func (v * Viddy ) setSelection (id int64 , row int ) {
297
330
if id == - 1 {
298
331
return
299
332
}
@@ -305,14 +338,11 @@ func (v *Viddy) setSelection(id int64) {
305
338
v .historyView .SetSelectable (true , false )
306
339
}
307
340
308
- v .RLock ()
309
- index := sort .Search (len (v .idList ), func (i int ) bool {
310
- return v .idList [i ] >= id
311
- })
312
- i := len (v .idList ) - index - 1
313
- v .RUnlock ()
341
+ if row == - 1 {
342
+ row = v .historyView .GetRowCount () - v .historyRowCount [id ]
343
+ }
314
344
315
- v .historyView .Select (i , 0 )
345
+ v .historyView .Select (row , 0 )
316
346
v .currentID = id
317
347
unix := v .begin + id * int64 (time .Millisecond )
318
348
v .timeView .SetText (time .Unix (unix / int64 (time .Second ), unix % int64 (time .Second )).String ())
@@ -628,81 +658,54 @@ func (v *Viddy) Run() error {
628
658
return app .Run ()
629
659
}
630
660
661
+ func (v * Viddy ) goToRow (row int ) {
662
+ if row < 0 {
663
+ row = 0
664
+ } else if count := v .historyView .GetRowCount (); row >= count {
665
+ row = count - 1
666
+ }
667
+ var (
668
+ cell = v .historyView .GetCell (row , 0 )
669
+ id , err = strconv .ParseInt (cell .Text , 10 , 64 )
670
+ )
671
+ if err == nil { // if _no_ error
672
+ v .setSelection (id , row )
673
+ }
674
+ }
675
+
631
676
func (v * Viddy ) goToPastOnTimeMachine () {
632
- count := v .historyView .GetRowCount ()
633
677
selection , _ := v .historyView .GetSelection ()
634
-
635
- if selection + 1 < count {
636
- cell := v .historyView .GetCell (selection + 1 , 0 )
637
- if id , err := strconv .ParseInt (cell .Text , 10 , 64 ); err == nil {
638
- v .setSelection (id )
639
- }
640
- }
678
+ v .goToRow (selection + 1 )
641
679
}
642
680
643
681
func (v * Viddy ) goToFutureOnTimeMachine () {
644
682
selection , _ := v .historyView .GetSelection ()
645
- if 0 <= selection - 1 {
646
- cell := v .historyView .GetCell (selection - 1 , 0 )
647
- if id , err := strconv .ParseInt (cell .Text , 10 , 64 ); err == nil {
648
- v .setSelection (id )
649
- }
650
- }
683
+ v .goToRow (selection - 1 )
651
684
}
652
685
653
686
func (v * Viddy ) goToMorePastOnTimeMachine () {
654
- count := v .historyView .GetRowCount ()
655
687
selection , _ := v .historyView .GetSelection ()
656
-
657
- if selection + 10 < count {
658
- cell := v .historyView .GetCell (selection + 10 , 0 )
659
- if id , err := strconv .ParseInt (cell .Text , 10 , 64 ); err == nil {
660
- v .setSelection (id )
661
- }
662
- } else {
663
- cell := v .historyView .GetCell (count - 1 , 0 )
664
- if id , err := strconv .ParseInt (cell .Text , 10 , 64 ); err == nil {
665
- v .setSelection (id )
666
- }
667
- }
688
+ v .goToRow (selection + 10 )
668
689
}
669
690
670
691
func (v * Viddy ) goToMoreFutureOnTimeMachine () {
671
692
selection , _ := v .historyView .GetSelection ()
672
- if 0 <= selection - 10 {
673
- cell := v .historyView .GetCell (selection - 10 , 0 )
674
- if id , err := strconv .ParseInt (cell .Text , 10 , 64 ); err == nil {
675
- v .setSelection (id )
676
- }
677
- } else {
678
- cell := v .historyView .GetCell (0 , 0 )
679
- if id , err := strconv .ParseInt (cell .Text , 10 , 64 ); err == nil {
680
- v .setSelection (id )
681
- }
682
- }
693
+ v .goToRow (selection - 10 )
683
694
}
684
695
685
696
func (v * Viddy ) goToNowOnTimeMachine () {
686
- cell := v .historyView .GetCell (0 , 0 )
687
- if id , err := strconv .ParseInt (cell .Text , 10 , 64 ); err == nil {
688
- v .setSelection (id )
689
- }
697
+ v .goToRow (0 )
690
698
}
691
699
692
700
func (v * Viddy ) goToOldestOnTimeMachine () {
693
- count := v .historyView .GetRowCount ()
694
- cell := v .historyView .GetCell (count - 1 , 0 )
695
-
696
- if id , err := strconv .ParseInt (cell .Text , 10 , 64 ); err == nil {
697
- v .setSelection (id )
698
- }
701
+ v .goToRow (v .historyView .GetRowCount () - 1 )
699
702
}
700
703
701
704
var helpTemplate = `Press ESC or q to go back
702
705
703
706
[::b]Key Bindings[-:-:-]
704
707
705
- [::u]General[-:-:-]
708
+ [::u]General[-:-:-]
706
709
707
710
Toggle time machine mode : [yellow]SPACE[-:-:-]
708
711
Toggle suspend execution : [yellow]s[-:-:-]
0 commit comments