diff --git a/cmd/cli/item.go b/cmd/cli/item.go index fd3cb7b..3fd69fe 100644 --- a/cmd/cli/item.go +++ b/cmd/cli/item.go @@ -12,6 +12,29 @@ import ( ) type item struct { + realtimeBefore float64 + + // [host:]pwd + differentHost bool + host string + home string + samePwd bool + pwd string + + // [G] [E#] + sameGitRepo bool + exitCode int + + cmdLineWithColor string + cmdLine string + + score float64 + + key string + // cmdLineRaw string +} + +type itemColumns struct { dateWithColor string date string @@ -26,7 +49,7 @@ type item struct { cmdLineWithColor string cmdLine string - score float64 + // score float64 key string // cmdLineRaw string @@ -37,16 +60,134 @@ func (i item) less(i2 item) bool { return i.score > i2.score } -func (i item) produceLine(flagLength int, showDate bool) (string, int) { +func formatDatetime(tm time.Time) string { + tmSince := time.Since(tm) + hrs := tmSince.Hours() + yrs := int(hrs / (365 * 24)) + if yrs > 1 { + return strconv.Itoa(yrs) + " years ago" + } + if yrs == 1 { + return "1 year ago" + } + months := int(hrs / (30 * 24)) + if months > 1 { + return strconv.Itoa(months) + " months ago" + } + if months == 1 { + return "1 month ago" + } + days := int(hrs / 24) + if days > 1 { + return strconv.Itoa(days) + " days ago" + } + if days == 1 { + return "1 day ago" + } + hrsInt := int(hrs) + if hrsInt > 1 { + return strconv.Itoa(hrsInt) + " hours ago" + } + if hrsInt == 1 { + return "1 hour ago" + } + mins := int(hrs * 60) + if mins > 1 { + return strconv.Itoa(mins) + " mins ago" + } + if mins == 1 { + return "1 min ago" + } + secs := int(hrs * 60 * 60) + if secs > 1 { + return strconv.Itoa(secs) + " secs ago" + } + if secs == 1 { + return "1 sec ago" + } + return "now" +} + +func (i item) drawItemColumns() itemColumns { + + // DISPLAY + // DISPLAY > date + secs := int64(i.realtimeBefore) + nsecs := int64((i.realtimeBefore - float64(secs)) * 1e9) + tm := time.Unix(secs, nsecs) + //date := tm.Format("2006-01-02 15:04 ") + // dateLength := len("12 months ago ") // longest date + date := formatDatetime(tm) + " " + // for len(date) < dateLength { + // date = " " + date + // } + dateWithColor := highlightDate(date) + + // DISPLAY > location + location := "" + locationWithColor := "" + if i.differentHost { + location += i.host + ":" + locationWithColor += highlightHost(i.host) + ":" + } + const locationLenght = 30 + // const locationLenght = 20 // small screenshots + pwdLength := locationLenght - len(location) + pwdTilde := strings.Replace(i.pwd, i.home, "~", 1) + location += leftCutPadString(pwdTilde, pwdLength) + if i.samePwd { + locationWithColor += highlightPwd(leftCutPadString(pwdTilde, pwdLength)) + } else { + locationWithColor += leftCutPadString(pwdTilde, pwdLength) + } + + // DISPLAY > flags + flags := "" + flagsWithColor := "" + if debug { + hitsStr := fmt.Sprintf("%.1f", i.score) + flags += " S" + hitsStr + } + if i.sameGitRepo { + flags += " G" + flagsWithColor += " " + highlightGit("G") + } + if i.exitCode != 0 { + flags += " E" + strconv.Itoa(i.exitCode) + flagsWithColor += " " + highlightWarn("E"+strconv.Itoa(i.exitCode)) + } + // NOTE: you can debug arbitrary metadata like this + // flags += " <" + record.GitOriginRemote + ">" + // flagsWithColor += " <" + record.GitOriginRemote + ">" + return itemColumns{ + date: date, + dateWithColor: dateWithColor, + location: location, + locationWithColor: locationWithColor, + flags: flags, + flagsWithColor: flagsWithColor, + cmdLine: i.cmdLine, + cmdLineWithColor: i.cmdLineWithColor, + // score: i.score, + key: i.key, + } +} + +func (ic itemColumns) produceLine(dateLength int, flagLength int, showDate bool) (string, int) { line := "" if showDate { - line += i.dateWithColor + date := ic.date + for len(date) < dateLength { + line += " " + date += " " + } + line += ic.dateWithColor } - line += i.locationWithColor - line += i.flagsWithColor - flags := i.flags - if flagLength < len(i.flags) { - log.Printf("produceLine can't specify line w/ flags shorter than the actual size. - len(flags) %v, requested %v\n", len(i.flags), flagLength) + line += ic.locationWithColor + line += ic.flagsWithColor + flags := ic.flags + if flagLength < len(ic.flags) { + log.Printf("produceLine can't specify line w/ flags shorter than the actual size. - len(flags) %v, requested %v\n", len(ic.flags), flagLength) } for len(flags) < flagLength { line += " " @@ -58,9 +199,9 @@ func (i item) produceLine(flagLength int, showDate bool) (string, int) { // because there is likely a long flag like E130 in the view spacer = " " } - line += spacer + i.cmdLineWithColor + line += spacer + ic.cmdLineWithColor - length := len(i.location) + flagLength + len(spacer) + len(i.cmdLine) + length := len(ic.location) + flagLength + len(spacer) + len(ic.cmdLine) return line, length } @@ -153,9 +294,9 @@ func newItemFromRecordForQuery(record records.CliRecord, query query, debug bool differentHost = true score -= differentHostScorePenalty } - errorExitStatus := false + // errorExitStatus := false if record.ExitCode != 0 { - errorExitStatus = true + // errorExitStatus = true score -= nonZeroExitCodeScorePenalty } if score <= 0 && !anyHit { @@ -169,51 +310,6 @@ func newItemFromRecordForQuery(record records.CliRecord, query query, debug bool record.GitOriginRemote + unlikelySeparator + record.Host // + strconv.Itoa(record.ExitCode) + unlikelySeparator - // DISPLAY - // DISPLAY > date - secs := int64(record.RealtimeBeforeLocal) - nsecs := int64((record.RealtimeBeforeLocal - float64(secs)) * 1e9) - tm := time.Unix(secs, nsecs) - date := tm.Format("2006-01-02_15:04 ") - dateWithColor := highlightDate(date) - - // DISPLAY > location - location := "" - locationWithColor := "" - if differentHost { - location += record.Host + ":" - locationWithColor += highlightHost(record.Host) + ":" - } - const locationLenght = 30 - // const locationLenght = 20 // small screenshots - pwdLength := locationLenght - len(location) - pwdTilde := strings.Replace(record.Pwd, record.Home, "~", 1) - location += leftCutPadString(pwdTilde, pwdLength) - if samePwd { - locationWithColor += highlightPwd(leftCutPadString(pwdTilde, pwdLength)) - } else { - locationWithColor += leftCutPadString(pwdTilde, pwdLength) - } - - // DISPLAY > flags - flags := "" - flagsWithColor := "" - if debug { - hitsStr := fmt.Sprintf("%.1f", score) - flags += " S" + hitsStr - } - if sameGitRepo { - flags += " G" - flagsWithColor += " " + highlightGit("G") - } - if errorExitStatus { - flags += " E" + strconv.Itoa(record.ExitCode) - flagsWithColor += " " + highlightWarn("E"+strconv.Itoa(record.ExitCode)) - } - // NOTE: you can debug arbitrary metadata like this - // flags += " <" + record.GitOriginRemote + ">" - // flagsWithColor += " <" + record.GitOriginRemote + ">" - // DISPLAY > cmdline // cmd := "<" + strings.ReplaceAll(record.CmdLine, "\n", ";") + ">" @@ -221,16 +317,20 @@ func newItemFromRecordForQuery(record records.CliRecord, query query, debug bool cmdLineWithColor := strings.ReplaceAll(cmd, "\n", ";") it := item{ - date: date, - dateWithColor: dateWithColor, - location: location, - locationWithColor: locationWithColor, - flags: flags, - flagsWithColor: flagsWithColor, - cmdLine: cmdLine, - cmdLineWithColor: cmdLineWithColor, - score: score, - key: key, + realtimeBefore: record.RealtimeBefore, + + differentHost: differentHost, + host: record.Host, + home: record.Home, + samePwd: samePwd, + pwd: record.Pwd, + + sameGitRepo: sameGitRepo, + exitCode: record.ExitCode, + cmdLine: cmdLine, + cmdLineWithColor: cmdLineWithColor, + score: score, + key: key, } return it, nil } diff --git a/cmd/cli/main.go b/cmd/cli/main.go index 147f90b..ca37a95 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -430,13 +430,21 @@ func SendCliMsg(m msg.CliMsg, port string) msg.CliResponse { func (m manager) normalMode(g *gocui.Gui, v *gocui.View) error { maxX, maxY := g.Size() + var data []itemColumns + + longestDateLen := 0 // at least 0 longestFlagsLen := 2 // at least 2 for i, itm := range m.s.data { if i == maxY { break } - if len(itm.flags) > longestFlagsLen { - longestFlagsLen = len(itm.flags) + ic := itm.drawItemColumns() + data = append(data, ic) + if len(ic.date) > longestDateLen { + longestDateLen = len(ic.date) + } + if len(ic.flags) > longestFlagsLen { + longestFlagsLen = len(ic.flags) } } @@ -449,14 +457,14 @@ func (m manager) normalMode(g *gocui.Gui, v *gocui.View) error { m.s.displayedItemsCount = maxY - topBoxSize - selectedLineCount - for i, itm := range m.s.data { + for i, itm := range data { if i == maxY-topBoxSize-selectedLineCount { if debug { log.Println(maxY) } break } - displayStr, _ := itm.produceLine(longestFlagsLen, true) + displayStr, _ := itm.produceLine(longestDateLen, longestFlagsLen, true) if m.s.highlightedItem == i { // maxX * 2 because there are escape sequences that make it hard to tell the real string lenght displayStr = doHighlightString(displayStr, maxX*2) diff --git a/pkg/records/records.go b/pkg/records/records.go index 04dd0ca..9283429 100644 --- a/pkg/records/records.go +++ b/pkg/records/records.go @@ -158,7 +158,7 @@ type CliRecord struct { GitOriginRemote string `json:"gitOriginRemote"` ExitCode int `json:"exitCode"` - RealtimeBeforeLocal float64 `json:"realtimeBeforeLocal"` + RealtimeBefore float64 `json:"realtimeBefore"` // RealtimeAfter float64 `json:"realtimeAfter"` // RealtimeDuration float64 `json:"realtimeDuration"` } @@ -166,14 +166,14 @@ type CliRecord struct { // NewCliRecord from EnrichedRecord func NewCliRecord(r EnrichedRecord) CliRecord { return CliRecord{ - SessionID: r.SessionID, - CmdLine: r.CmdLine, - Host: r.Host, - Pwd: r.Pwd, - Home: r.Home, - GitOriginRemote: r.GitOriginRemote, - ExitCode: r.ExitCode, - RealtimeBeforeLocal: r.RealtimeBeforeLocal, + SessionID: r.SessionID, + CmdLine: r.CmdLine, + Host: r.Host, + Pwd: r.Pwd, + Home: r.Home, + GitOriginRemote: r.GitOriginRemote, + ExitCode: r.ExitCode, + RealtimeBefore: r.RealtimeBefore, } }