Skip to content

Commit af7a4b8

Browse files
authored
Merge pull request #99 from avamsi/jj_onysotmvlwnn
history: skip snapshots with no changes (+0 -0)
2 parents 3b12059 + 106e52d commit af7a4b8

File tree

4 files changed

+112
-100
lines changed

4 files changed

+112
-100
lines changed

config.go

+15-8
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,15 @@ type runtimeConfig struct {
3838
}
3939

4040
type general struct {
41-
shell string
42-
shellOptions string
43-
debug bool
44-
bell bool
45-
differences bool
46-
noTitle bool
47-
pty bool
48-
unfold bool
41+
shell string
42+
shellOptions string
43+
debug bool
44+
bell bool
45+
differences bool
46+
skipEmptyDiffs bool
47+
noTitle bool
48+
pty bool
49+
unfold bool
4950
}
5051

5152
type theme struct {
@@ -87,6 +88,7 @@ func newConfig(v *viper.Viper, args []string) (*config, error) {
8788
// general
8889
flagSet.BoolP("bell", "b", false, "ring terminal bell changes between updates")
8990
flagSet.BoolP("differences", "d", false, "highlight changes between updates")
91+
flagSet.BoolP("skip-empty-diffs", "s", false, "skip snapshots with no changes (+0 -0) in history")
9092
flagSet.BoolP("no-title", "t", false, "turn off header")
9193
flagSet.Bool("debug", false, "")
9294
flagSet.String("shell", "", "shell (default \"sh\")")
@@ -148,6 +150,10 @@ func newConfig(v *viper.Viper, args []string) (*config, error) {
148150
return nil, err
149151
}
150152

153+
if err := v.BindPFlag("general.skip_empty_diffs", flagSet.Lookup("skip-empty-diffs")); err != nil {
154+
return nil, err
155+
}
156+
151157
if err := v.BindPFlag("general.no_title", flagSet.Lookup("no-title")); err != nil {
152158
return nil, err
153159
}
@@ -165,6 +171,7 @@ func newConfig(v *viper.Viper, args []string) (*config, error) {
165171
conf.general.shellOptions = v.GetString("general.shell_options")
166172
conf.general.bell, _ = flagSet.GetBool("bell")
167173
conf.general.differences, _ = flagSet.GetBool("differences")
174+
conf.general.skipEmptyDiffs, _ = flagSet.GetBool("skip-empty-diffs")
168175
conf.general.noTitle, _ = flagSet.GetBool("no-title")
169176
conf.general.unfold = v.GetBool("general.unfold")
170177
conf.general.pty = v.GetBool("general.pty")

main.go

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ Usage:
7777
Options:
7878
-b, --bell ring terminal bell changes between updates
7979
-d, --differences highlight changes between updates
80+
-s, --skip-empty-diffs skip snapshots with no changes (+0 -0) in history
8081
-n, --interval <interval> seconds to wait between updates (default "2s")
8182
-p, --precise attempt run command in precise intervals
8283
-c, --clockwork run command in precise intervals forcibly

snapshot.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ type Snapshot struct {
4747
finish chan<- struct{}
4848
}
4949

50-
//nolint:lll
5150
// NewSnapshot returns Snapshot object.
51+
//
52+
//nolint:lll
5253
func NewSnapshot(id int64, command string, args []string, shell string, shellOpts string, before *Snapshot, finish chan<- struct{}) *Snapshot {
5354
return &Snapshot{
5455
id: id,

viddy.go

+94-91
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"html/template"
88
"io"
99
"os"
10-
"sort"
1110
"strconv"
1211
"strings"
1312
"sync"
@@ -43,12 +42,12 @@ type Viddy struct {
4342
timeView *tview.TextView
4443
historyView *tview.Table
4544
historyRows map[int64]*HistoryRow
46-
sync.RWMutex
4745

4846
// bWidth store current pty width.
4947
bWidth atomic.Value
5048

51-
idList []int64
49+
// id -> row count (as of just after the snapshot was added).
50+
historyRowCount map[int64]int
5251

5352
bodyView *tview.TextView
5453
app *tview.Application
@@ -69,6 +68,7 @@ type Viddy struct {
6968
isNoTitle bool
7069
isRingBell bool
7170
isShowDiff bool
71+
skipEmptyDiffs bool
7272
isEditQuery bool
7373
unfold bool
7474
pty bool
@@ -124,17 +124,20 @@ func NewViddy(conf *config) *Viddy {
124124
snapshots: sync.Map{},
125125
historyRows: map[int64]*HistoryRow{},
126126

127+
historyRowCount: map[int64]int{},
128+
127129
snapshotQueue: snapshotQueue,
128130
queue: make(chan int64),
129131
finishedQueue: make(chan int64),
130132
diffQueue: make(chan int64, 100),
131133

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,
138141

139142
currentID: -1,
140143
latestFinishedID: -1,
@@ -153,14 +156,14 @@ func (v *Viddy) SetIsNoTitle(b bool) {
153156

154157
func (v *Viddy) SetIsShowDiff(b bool) {
155158
v.isShowDiff = b
156-
v.setSelection(v.currentID)
159+
v.setSelection(v.currentID, -1)
157160
v.arrange()
158161
}
159162

160163
func (v *Viddy) SetIsTimeMachine(b bool) {
161164
v.isTimeMachine = b
162165
if !v.isTimeMachine {
163-
v.setSelection(v.latestFinishedID)
166+
v.setSelection(v.latestFinishedID, -1)
164167
}
165168

166169
v.arrange()
@@ -183,6 +186,26 @@ func (v *Viddy) startRunner() {
183186
}
184187
}
185188

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+
186209
func (v *Viddy) diffQueueHandler() {
187210
for {
188211
func() {
@@ -203,17 +226,24 @@ func (v *Viddy) diffQueueHandler() {
203226
return
204227
}
205228

206-
if v.isRingBell {
207-
if s.diffAdditionCount > 0 || s.diffDeletionCount > 0 {
229+
if s.diffAdditionCount > 0 || s.diffDeletionCount > 0 {
230+
if v.isRingBell {
208231
fmt.Print(string(byte(7)))
209232
}
233+
} else if v.skipEmptyDiffs {
234+
return
210235
}
211236

212237
r, ok := v.historyRows[id]
213238
if !ok {
214239
return
215240
}
216241

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+
}
217247
r.addition.SetText("+" + strconv.Itoa(s.diffAdditionCount))
218248
r.deletion.SetText("-" + strconv.Itoa(s.diffDeletionCount))
219249
}()
@@ -249,11 +279,7 @@ func (v *Viddy) queueHandler() {
249279
ls := v.getSnapShot(v.latestFinishedID)
250280
if ls == nil || s.start.After(ls.start) {
251281
v.latestFinishedID = id
252-
if !v.isTimeMachine {
253-
v.setSelection(id)
254-
} else {
255-
v.setSelection(v.currentID)
256-
}
282+
v.updateSelection()
257283
}
258284
case id := <-v.queue:
259285
if v.isSuspend {
@@ -266,34 +292,41 @@ func (v *Viddy) queueHandler() {
266292
deletionCell := tview.NewTableCell("").SetTextColor(tcell.ColorRed)
267293
exitCodeCell := tview.NewTableCell("").SetTextColor(tcell.ColorYellow)
268294

269-
v.historyRows[s.id] = &HistoryRow{
295+
r := &HistoryRow{
270296
id: idCell,
271297
addition: additionCell,
272298
deletion: deletionCell,
273299
exitCode: exitCodeCell,
274300
}
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)
290320
}
291321
}
292322
}()
293323
}
294324
}
295325

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) {
297330
if id == -1 {
298331
return
299332
}
@@ -305,14 +338,11 @@ func (v *Viddy) setSelection(id int64) {
305338
v.historyView.SetSelectable(true, false)
306339
}
307340

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+
}
314344

315-
v.historyView.Select(i, 0)
345+
v.historyView.Select(row, 0)
316346
v.currentID = id
317347
unix := v.begin + id*int64(time.Millisecond)
318348
v.timeView.SetText(time.Unix(unix/int64(time.Second), unix%int64(time.Second)).String())
@@ -628,81 +658,54 @@ func (v *Viddy) Run() error {
628658
return app.Run()
629659
}
630660

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+
631676
func (v *Viddy) goToPastOnTimeMachine() {
632-
count := v.historyView.GetRowCount()
633677
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)
641679
}
642680

643681
func (v *Viddy) goToFutureOnTimeMachine() {
644682
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)
651684
}
652685

653686
func (v *Viddy) goToMorePastOnTimeMachine() {
654-
count := v.historyView.GetRowCount()
655687
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)
668689
}
669690

670691
func (v *Viddy) goToMoreFutureOnTimeMachine() {
671692
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)
683694
}
684695

685696
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)
690698
}
691699

692700
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)
699702
}
700703

701704
var helpTemplate = `Press ESC or q to go back
702705
703706
[::b]Key Bindings[-:-:-]
704707
705-
[::u]General[-:-:-]
708+
[::u]General[-:-:-]
706709
707710
Toggle time machine mode : [yellow]SPACE[-:-:-]
708711
Toggle suspend execution : [yellow]s[-:-:-]

0 commit comments

Comments
 (0)