Skip to content

Commit

Permalink
Merge pull request #99 from avamsi/jj_onysotmvlwnn
Browse files Browse the repository at this point in the history
history: skip snapshots with no changes (+0 -0)
  • Loading branch information
sachaos committed Oct 15, 2023
2 parents 3b12059 + 106e52d commit af7a4b8
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 100 deletions.
23 changes: 15 additions & 8 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,15 @@ type runtimeConfig struct {
}

type general struct {
shell string
shellOptions string
debug bool
bell bool
differences bool
noTitle bool
pty bool
unfold bool
shell string
shellOptions string
debug bool
bell bool
differences bool
skipEmptyDiffs bool
noTitle bool
pty bool
unfold bool
}

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

if err := v.BindPFlag("general.skip_empty_diffs", flagSet.Lookup("skip-empty-diffs")); err != nil {
return nil, err
}

if err := v.BindPFlag("general.no_title", flagSet.Lookup("no-title")); err != nil {
return nil, err
}
Expand All @@ -165,6 +171,7 @@ func newConfig(v *viper.Viper, args []string) (*config, error) {
conf.general.shellOptions = v.GetString("general.shell_options")
conf.general.bell, _ = flagSet.GetBool("bell")
conf.general.differences, _ = flagSet.GetBool("differences")
conf.general.skipEmptyDiffs, _ = flagSet.GetBool("skip-empty-diffs")
conf.general.noTitle, _ = flagSet.GetBool("no-title")
conf.general.unfold = v.GetBool("general.unfold")
conf.general.pty = v.GetBool("general.pty")
Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Usage:
Options:
-b, --bell ring terminal bell changes between updates
-d, --differences highlight changes between updates
-s, --skip-empty-diffs skip snapshots with no changes (+0 -0) in history
-n, --interval <interval> seconds to wait between updates (default "2s")
-p, --precise attempt run command in precise intervals
-c, --clockwork run command in precise intervals forcibly
Expand Down
3 changes: 2 additions & 1 deletion snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ type Snapshot struct {
finish chan<- struct{}
}

//nolint:lll
// NewSnapshot returns Snapshot object.
//
//nolint:lll
func NewSnapshot(id int64, command string, args []string, shell string, shellOpts string, before *Snapshot, finish chan<- struct{}) *Snapshot {
return &Snapshot{
id: id,
Expand Down
185 changes: 94 additions & 91 deletions viddy.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"html/template"
"io"
"os"
"sort"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -43,12 +42,12 @@ type Viddy struct {
timeView *tview.TextView
historyView *tview.Table
historyRows map[int64]*HistoryRow
sync.RWMutex

// bWidth store current pty width.
bWidth atomic.Value

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

bodyView *tview.TextView
app *tview.Application
Expand All @@ -69,6 +68,7 @@ type Viddy struct {
isNoTitle bool
isRingBell bool
isShowDiff bool
skipEmptyDiffs bool
isEditQuery bool
unfold bool
pty bool
Expand Down Expand Up @@ -124,17 +124,20 @@ func NewViddy(conf *config) *Viddy {
snapshots: sync.Map{},
historyRows: map[int64]*HistoryRow{},

historyRowCount: map[int64]int{},

snapshotQueue: snapshotQueue,
queue: make(chan int64),
finishedQueue: make(chan int64),
diffQueue: make(chan int64, 100),

isRingBell: conf.general.bell,
isShowDiff: conf.general.differences,
isNoTitle: conf.general.noTitle,
isDebug: conf.general.debug,
unfold: conf.general.unfold,
pty: conf.general.pty,
isRingBell: conf.general.bell,
isShowDiff: conf.general.differences,
skipEmptyDiffs: conf.general.skipEmptyDiffs,
isNoTitle: conf.general.noTitle,
isDebug: conf.general.debug,
unfold: conf.general.unfold,
pty: conf.general.pty,

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

func (v *Viddy) SetIsShowDiff(b bool) {
v.isShowDiff = b
v.setSelection(v.currentID)
v.setSelection(v.currentID, -1)
v.arrange()
}

func (v *Viddy) SetIsTimeMachine(b bool) {
v.isTimeMachine = b
if !v.isTimeMachine {
v.setSelection(v.latestFinishedID)
v.setSelection(v.latestFinishedID, -1)
}

v.arrange()
Expand All @@ -183,6 +186,26 @@ func (v *Viddy) startRunner() {
}
}

func (v *Viddy) updateSelection() {
if !v.isTimeMachine {
v.setSelection(v.latestFinishedID, -1)
} else {
v.setSelection(v.currentID, -1)
}
}

func (v *Viddy) addSnapshotToView(id int64, r *HistoryRow) {
v.historyView.InsertRow(0)
v.historyView.SetCell(0, 0, r.id)
v.historyView.SetCell(0, 1, r.addition)
v.historyView.SetCell(0, 2, r.deletion)
v.historyView.SetCell(0, 3, r.exitCode)

v.historyRowCount[id] = v.historyView.GetRowCount()

v.updateSelection()
}

func (v *Viddy) diffQueueHandler() {
for {
func() {
Expand All @@ -203,17 +226,24 @@ func (v *Viddy) diffQueueHandler() {
return
}

if v.isRingBell {
if s.diffAdditionCount > 0 || s.diffDeletionCount > 0 {
if s.diffAdditionCount > 0 || s.diffDeletionCount > 0 {
if v.isRingBell {
fmt.Print(string(byte(7)))
}
} else if v.skipEmptyDiffs {
return
}

r, ok := v.historyRows[id]
if !ok {
return
}

// if skipEmptyDiffs is true, queueHandler wouldn't have added the
// snapshot to view, so we need to add it here.
if v.skipEmptyDiffs {
v.addSnapshotToView(id, r)
}
r.addition.SetText("+" + strconv.Itoa(s.diffAdditionCount))
r.deletion.SetText("-" + strconv.Itoa(s.diffDeletionCount))
}()
Expand Down Expand Up @@ -249,11 +279,7 @@ func (v *Viddy) queueHandler() {
ls := v.getSnapShot(v.latestFinishedID)
if ls == nil || s.start.After(ls.start) {
v.latestFinishedID = id
if !v.isTimeMachine {
v.setSelection(id)
} else {
v.setSelection(v.currentID)
}
v.updateSelection()
}
case id := <-v.queue:
if v.isSuspend {
Expand All @@ -266,34 +292,41 @@ func (v *Viddy) queueHandler() {
deletionCell := tview.NewTableCell("").SetTextColor(tcell.ColorRed)
exitCodeCell := tview.NewTableCell("").SetTextColor(tcell.ColorYellow)

v.historyRows[s.id] = &HistoryRow{
r := &HistoryRow{
id: idCell,
addition: additionCell,
deletion: deletionCell,
exitCode: exitCodeCell,
}

v.historyView.InsertRow(0)
v.historyView.SetCell(0, 0, idCell)
v.historyView.SetCell(0, 1, additionCell)
v.historyView.SetCell(0, 2, deletionCell)
v.historyView.SetCell(0, 3, exitCodeCell)

v.Lock()
v.idList = append(v.idList, id)
v.Unlock()

if !v.isTimeMachine {
v.setSelection(v.latestFinishedID)
} else {
v.setSelection(v.currentID)
v.historyRows[s.id] = r

// if skipEmptyDiffs is true, we need to check if the snapshot
// is empty before adding it to the view (in diffQueueHandler).
//
// This means we're trading off two things:
//
// 1. We're not showing the snapshot in history view until the
// command finishes running, which means it's not possible
// to see partial output.
// 2. Order of the snapshots in history view is lost
// (in non-sequential modes), as some commands could finish
// running quicker than others for whatever reason.
//
// It of course is possible to address these issues by adding
// all snapshots to the history view and then removing the empty
// ones but it unnecessarily complicates the implementation.
if !v.skipEmptyDiffs {
v.addSnapshotToView(id, r)
}
}
}()
}
}

func (v *Viddy) setSelection(id int64) {
// setSelection selects the given row in the history view. If row is -1, it will
// attempt to select the row corresponding to the given id (or default to the
// latest row if id doesn't exist).
func (v *Viddy) setSelection(id int64, row int) {
if id == -1 {
return
}
Expand All @@ -305,14 +338,11 @@ func (v *Viddy) setSelection(id int64) {
v.historyView.SetSelectable(true, false)
}

v.RLock()
index := sort.Search(len(v.idList), func(i int) bool {
return v.idList[i] >= id
})
i := len(v.idList) - index - 1
v.RUnlock()
if row == -1 {
row = v.historyView.GetRowCount() - v.historyRowCount[id]
}

v.historyView.Select(i, 0)
v.historyView.Select(row, 0)
v.currentID = id
unix := v.begin + id*int64(time.Millisecond)
v.timeView.SetText(time.Unix(unix/int64(time.Second), unix%int64(time.Second)).String())
Expand Down Expand Up @@ -628,81 +658,54 @@ func (v *Viddy) Run() error {
return app.Run()
}

func (v *Viddy) goToRow(row int) {
if row < 0 {
row = 0
} else if count := v.historyView.GetRowCount(); row >= count {
row = count - 1
}
var (
cell = v.historyView.GetCell(row, 0)
id, err = strconv.ParseInt(cell.Text, 10, 64)
)
if err == nil { // if _no_ error
v.setSelection(id, row)
}
}

func (v *Viddy) goToPastOnTimeMachine() {
count := v.historyView.GetRowCount()
selection, _ := v.historyView.GetSelection()

if selection+1 < count {
cell := v.historyView.GetCell(selection+1, 0)
if id, err := strconv.ParseInt(cell.Text, 10, 64); err == nil {
v.setSelection(id)
}
}
v.goToRow(selection + 1)
}

func (v *Viddy) goToFutureOnTimeMachine() {
selection, _ := v.historyView.GetSelection()
if 0 <= selection-1 {
cell := v.historyView.GetCell(selection-1, 0)
if id, err := strconv.ParseInt(cell.Text, 10, 64); err == nil {
v.setSelection(id)
}
}
v.goToRow(selection - 1)
}

func (v *Viddy) goToMorePastOnTimeMachine() {
count := v.historyView.GetRowCount()
selection, _ := v.historyView.GetSelection()

if selection+10 < count {
cell := v.historyView.GetCell(selection+10, 0)
if id, err := strconv.ParseInt(cell.Text, 10, 64); err == nil {
v.setSelection(id)
}
} else {
cell := v.historyView.GetCell(count-1, 0)
if id, err := strconv.ParseInt(cell.Text, 10, 64); err == nil {
v.setSelection(id)
}
}
v.goToRow(selection + 10)
}

func (v *Viddy) goToMoreFutureOnTimeMachine() {
selection, _ := v.historyView.GetSelection()
if 0 <= selection-10 {
cell := v.historyView.GetCell(selection-10, 0)
if id, err := strconv.ParseInt(cell.Text, 10, 64); err == nil {
v.setSelection(id)
}
} else {
cell := v.historyView.GetCell(0, 0)
if id, err := strconv.ParseInt(cell.Text, 10, 64); err == nil {
v.setSelection(id)
}
}
v.goToRow(selection - 10)
}

func (v *Viddy) goToNowOnTimeMachine() {
cell := v.historyView.GetCell(0, 0)
if id, err := strconv.ParseInt(cell.Text, 10, 64); err == nil {
v.setSelection(id)
}
v.goToRow(0)
}

func (v *Viddy) goToOldestOnTimeMachine() {
count := v.historyView.GetRowCount()
cell := v.historyView.GetCell(count-1, 0)

if id, err := strconv.ParseInt(cell.Text, 10, 64); err == nil {
v.setSelection(id)
}
v.goToRow(v.historyView.GetRowCount() - 1)
}

var helpTemplate = `Press ESC or q to go back
[::b]Key Bindings[-:-:-]
[::u]General[-:-:-]
[::u]General[-:-:-]
Toggle time machine mode : [yellow]SPACE[-:-:-]
Toggle suspend execution : [yellow]s[-:-:-]
Expand Down

0 comments on commit af7a4b8

Please sign in to comment.