Skip to content

Commit c32eb66

Browse files
authored
fixup macos zsh_history (merge wave history back to => ~/.zsh_history) (#2625)
1 parent 5e78147 commit c32eb66

File tree

8 files changed

+164
-7
lines changed

8 files changed

+164
-7
lines changed

cmd/server/main-server.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,10 @@ func main() {
465465
return
466466
}
467467

468+
err = shellutil.FixupWaveZshHistory()
469+
if err != nil {
470+
log.Printf("error fixing up wave zsh history: %v\n", err)
471+
}
468472
createMainWshClient()
469473
sigutil.InstallShutdownSignalHandlers(doShutdown)
470474
sigutil.InstallSIGUSR1Handler()

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ require (
8181
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
8282
github.com/mailru/easyjson v0.7.7 // indirect
8383
github.com/mattn/go-isatty v0.0.20 // indirect
84+
github.com/outrigdev/goid v0.3.0 // indirect
8485
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
8586
github.com/rivo/uniseg v0.4.7 // indirect
8687
github.com/sirupsen/logrus v1.9.3 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuE
146146
github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
147147
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
148148
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
149+
github.com/outrigdev/goid v0.3.0 h1:t/otQD3EXc45cLtQVPUnNgEyRaTQA4cPeu3qVcrsIws=
150+
github.com/outrigdev/goid v0.3.0/go.mod h1:hEH7f27ypN/GHWt/7gvkRoFYR0LZizfUBIAbak4neVE=
149151
github.com/photostorm/pty v1.1.19-0.20230903182454-31354506054b h1:cLGKfKb1uk0hxI0Q8L83UAJPpeJ+gSpn3cCU/tjd3eg=
150152
github.com/photostorm/pty v1.1.19-0.20230903182454-31354506054b/go.mod h1:KO+FcPtyLAiRC0hJwreJVvfwc7vnNz77UxBTIGHdPVk=
151153
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=

pkg/telemetry/telemetry.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,10 +254,13 @@ func RecordTEvent(ctx context.Context, tevent *telemetrydata.TEvent) error {
254254
}
255255

256256
func CleanOldTEvents(ctx context.Context) error {
257+
daysToKeep := 7
258+
if !IsTelemetryEnabled() {
259+
daysToKeep = 1
260+
}
261+
olderThan := time.Now().AddDate(0, 0, -daysToKeep).UnixMilli()
257262
return wstore.WithTx(ctx, func(tx *wstore.TxWrap) error {
258-
// delete events older than 28 days
259263
query := `DELETE FROM db_tevent WHERE ts < ?`
260-
olderThan := time.Now().AddDate(0, 0, -28).UnixMilli()
261264
tx.Exec(query, olderThan)
262265
return nil
263266
})

pkg/util/envutil/envutil.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,27 @@ func RmEnv(envStr string, key string) string {
6767
delete(envMap, key)
6868
return MapToEnv(envMap)
6969
}
70+
71+
func SliceToEnv(env []string) string {
72+
var sb strings.Builder
73+
for _, envVar := range env {
74+
if len(envVar) == 0 {
75+
continue
76+
}
77+
sb.WriteString(envVar)
78+
sb.WriteByte('\x00')
79+
}
80+
return sb.String()
81+
}
82+
83+
func EnvToSlice(envStr string) []string {
84+
envLines := strings.Split(envStr, "\x00")
85+
result := make([]string, 0, len(envLines))
86+
for _, line := range envLines {
87+
if len(line) == 0 {
88+
continue
89+
}
90+
result = append(result, line)
91+
}
92+
return result
93+
}

pkg/util/shellutil/shellintegration/zsh_zshrc.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ if [[ -n ${_comps+x} ]]; then
1818
source <(wsh completion zsh)
1919
fi
2020

21+
# fix history (macos)
22+
if [[ "$HISTFILE" == "$WAVETERM_ZDOTDIR/.zsh_history" ]]; then
23+
HISTFILE="$HOME/.zsh_history"
24+
fi
25+
2126
typeset -g _WAVETERM_SI_FIRSTPRECMD=1
2227

2328
# shell integration

pkg/util/shellutil/shellutil.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"sync"
1919
"time"
2020

21+
"github.com/wavetermdev/waveterm/pkg/util/envutil"
2122
"github.com/wavetermdev/waveterm/pkg/util/utilfn"
2223
"github.com/wavetermdev/waveterm/pkg/wavebase"
2324
"github.com/wavetermdev/waveterm/pkg/waveobj"
@@ -47,6 +48,8 @@ var (
4748

4849
//go:embed shellintegration/pwsh_wavepwsh.sh
4950
PwshStartup_wavepwsh string
51+
52+
ZshExtendedHistoryPattern = regexp.MustCompile(`^: [0-9]+:`)
5053
)
5154

5255
const DefaultTermType = "xterm-256color"
@@ -74,6 +77,7 @@ const (
7477
PwshIntegrationDir = "shell/pwsh"
7578
FishIntegrationDir = "shell/fish"
7679
WaveHomeBinDir = "bin"
80+
ZshHistoryFileName = ".zsh_history"
7781
)
7882

7983
func DetectLocalShellPath() string {
@@ -208,6 +212,46 @@ func GetLocalZshZDotDir() string {
208212
return filepath.Join(wavebase.GetWaveDataDir(), ZshIntegrationDir)
209213
}
210214

215+
func HasWaveZshHistory() (bool, int64) {
216+
zshDir := GetLocalZshZDotDir()
217+
historyFile := filepath.Join(zshDir, ZshHistoryFileName)
218+
fileInfo, err := os.Stat(historyFile)
219+
if err != nil {
220+
return false, 0
221+
}
222+
return true, fileInfo.Size()
223+
}
224+
225+
func IsExtendedZshHistoryFile(fileName string) (bool, error) {
226+
file, err := os.Open(fileName)
227+
if err != nil {
228+
if os.IsNotExist(err) {
229+
return false, nil
230+
}
231+
return false, err
232+
}
233+
defer file.Close()
234+
235+
buf := make([]byte, 1024)
236+
n, err := file.Read(buf)
237+
if err != nil {
238+
return false, err
239+
}
240+
241+
content := string(buf[:n])
242+
lines := strings.Split(content, "\n")
243+
244+
for _, line := range lines {
245+
line = strings.TrimSpace(line)
246+
if line == "" {
247+
continue
248+
}
249+
return ZshExtendedHistoryPattern.MatchString(line), nil
250+
}
251+
252+
return false, nil
253+
}
254+
211255
func GetLocalWshBinaryPath(version string, goos string, goarch string) (string, error) {
212256
ext := ""
213257
if goarch == "amd64" {
@@ -422,6 +466,80 @@ func getShellVersion(shellPath string, shellType string) (string, error) {
422466
return matches[1], nil
423467
}
424468

469+
func FixupWaveZshHistory() error {
470+
if runtime.GOOS != "darwin" {
471+
return nil
472+
}
473+
474+
hasHistory, size := HasWaveZshHistory()
475+
if !hasHistory {
476+
return nil
477+
}
478+
479+
zshDir := GetLocalZshZDotDir()
480+
waveHistFile := filepath.Join(zshDir, ZshHistoryFileName)
481+
482+
if size == 0 {
483+
err := os.Remove(waveHistFile)
484+
if err != nil {
485+
log.Printf("error removing wave zsh history file %s: %v\n", waveHistFile, err)
486+
}
487+
return nil
488+
}
489+
490+
log.Printf("merging wave zsh history %s into ~/.zsh_history\n", waveHistFile)
491+
492+
homeDir, err := os.UserHomeDir()
493+
if err != nil {
494+
return fmt.Errorf("error getting home directory: %w", err)
495+
}
496+
realHistFile := filepath.Join(homeDir, ".zsh_history")
497+
498+
isExtended, err := IsExtendedZshHistoryFile(realHistFile)
499+
if err != nil {
500+
return fmt.Errorf("error checking if history is extended: %w", err)
501+
}
502+
503+
hasExtendedStr := "false"
504+
if isExtended {
505+
hasExtendedStr = "true"
506+
}
507+
508+
quotedWaveHistFile := utilfn.ShellQuote(waveHistFile, true, -1)
509+
510+
script := fmt.Sprintf(`
511+
HISTFILE=~/.zsh_history
512+
HISTSIZE=999999
513+
SAVEHIST=999999
514+
has_extended_history=%s
515+
[[ $has_extended_history == true ]] && setopt EXTENDED_HISTORY
516+
fc -RI
517+
fc -RI %s
518+
fc -W
519+
`, hasExtendedStr, quotedWaveHistFile)
520+
521+
ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
522+
defer cancelFn()
523+
524+
cmd := exec.CommandContext(ctx, "zsh", "-f", "-i", "-c", script)
525+
cmd.Stdin = nil
526+
envStr := envutil.SliceToEnv(os.Environ())
527+
envStr = envutil.RmEnv(envStr, "ZDOTDIR")
528+
cmd.Env = envutil.EnvToSlice(envStr)
529+
output, err := cmd.CombinedOutput()
530+
if err != nil {
531+
return fmt.Errorf("error executing zsh history fixup script: %w, output: %s", err, string(output))
532+
}
533+
534+
err = os.Remove(waveHistFile)
535+
if err != nil {
536+
log.Printf("error removing wave zsh history file %s: %v\n", waveHistFile, err)
537+
}
538+
log.Printf("successfully merged wave zsh history %s into ~/.zsh_history\n", waveHistFile)
539+
540+
return nil
541+
}
542+
425543
func FormatOSC(oscNum int, parts ...string) string {
426544
if len(parts) == 0 {
427545
return fmt.Sprintf("\x1b]%d\x07", oscNum)

pkg/wcloud/wcloud.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -214,11 +214,11 @@ func sendTEvents(clientId string) (int, error) {
214214
}
215215

216216
func SendAllTelemetry(clientId string) error {
217-
defer func() {
218-
ctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
219-
defer cancelFn()
220-
telemetry.CleanOldTEvents(ctx)
221-
}()
217+
ctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
218+
defer cancelFn()
219+
if err := telemetry.CleanOldTEvents(ctx); err != nil {
220+
log.Printf("error cleaning old telemetry events: %v\n", err)
221+
}
222222
if !telemetry.IsTelemetryEnabled() {
223223
log.Printf("telemetry disabled, not sending\n")
224224
return nil

0 commit comments

Comments
 (0)