Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
"build": {
"dockerfile": "Dockerfile",
"args": {
// Update the VARIANT arg to pick a version of Go: 1, 1.25, 1.26
// Update the VARIANT arg to pick a version of Go: 1, 1.26, 1.27
// Append -trixie, -bookworm or -bullseye to pin to an OS version.
"VARIANT": "2-1.26-trixie",
"VARIANT": "2-1.27-trixie",

// Override me with your own timezone:
"TZ": "UTC",
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/composite/bootstrap-go/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ runs:
steps:
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
with:
go-version: "1.26.0"
go-version: "1.27.0"
cache-dependency-path: src/go.sum
2 changes: 1 addition & 1 deletion src/cache/clear.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func Clear(force bool, excludedFiles ...string) error {
}

func GetTTL() int {
cacheTTL, OK := Get[int](Device, TTL)
cacheTTL, OK := Device.Get[int](TTL)
if !OK || cacheTTL <= 0 {
cacheTTL = 7
}
Expand Down
4 changes: 2 additions & 2 deletions src/cache/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ func PersistCommandPath(command, path string, found bool) {
ttl = CommandPathNegativeTTL
}

Set(Session, commandPathKey(command), entry, ttl)
Session.Set(commandPathKey(command), entry, ttl)
}

// An entry persisted under a different PATH(+PATHEXT) environment is treated
// as a miss, so the caller falls through to a fresh exec.LookPath (which
// overwrites the entry with the current environment's hash).
func GetPersistedCommandPath(command string) (path string, found, ok bool) {
entry, exists := Get[commandPathEntry](Session, commandPathKey(command))
entry, exists := Session.Get[commandPathEntry](commandPathKey(command))
if !exists {
return "", false, false
}
Expand Down
2 changes: 1 addition & 1 deletion src/cache/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func TestGetPersistedCommandPathStalePathHashIsAMiss(t *testing.T) {
// Simulate an entry persisted under a different PATH environment (or a
// pre-PathHash entry, which decodes with PathHash == 0).
entry := commandPathEntry{Path: "/usr/bin/git", PathHash: pathEnvHash() + 1, Found: true}
Set(Session, commandPathKey("git"), entry, CommandPathTTL)
Session.Set(commandPathKey("git"), entry, CommandPathTTL)

_, _, ok := GetPersistedCommandPath("git")
assert.False(t, ok, "entry persisted under a different PATH must be treated as a miss")
Expand Down
16 changes: 2 additions & 14 deletions src/cache/init.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package cache

import (
"crypto/rand"
"fmt"
"os"
"sync"
"time"
"uuid"

"github.com/jandedobbeleer/oh-my-posh/src/log"
)
Expand Down Expand Up @@ -73,18 +73,6 @@ func Close() {
Device.close()
}

// newSessionID returns a random RFC 4122 version 4 UUID string, the same
// format github.com/google/uuid produced for session identifiers.
func newSessionID() string {
var b [16]byte
if _, err := rand.Read(b[:]); err != nil {
// crypto/rand never fails on supported platforms; fall back to a
// time-derived id rather than panicking in the prompt path
return fmt.Sprintf("%x", time.Now().UnixNano())
}

b[6] = (b[6] & 0x0f) | 0x40 // version 4
b[8] = (b[8] & 0x3f) | 0x80 // variant 10

return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:16])
return uuid.NewV4().String()
}
14 changes: 7 additions & 7 deletions src/cache/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ func touchSessionFile(filePath string) {
// process (serve) that keeps its cache in memory for the session: without
// it, a write from another process (e.g. `toggle`, `enable`/`disable`)
// would stay invisible until the daemon exits.
func Refresh(s Store) {
func (s Store) Refresh() {
defer log.Trace(time.Now(), string(s))

store := s.get()
Expand Down Expand Up @@ -202,7 +202,7 @@ func (s Store) close() {
// (e.g. right before the shell exits) isn't clobbered by this store's
// own, possibly stale, in-memory copy.
if store != nil && !store.locked && store.persist && store.dirty {
Refresh(s)
s.Refresh()
}

if store == nil || store.locked || !store.persist || !store.dirty {
Expand Down Expand Up @@ -250,7 +250,7 @@ func (s Store) close() {
}
}

func Get[T any](s Store, key string) (T, bool) {
func (s Store) Get[T any](key string) (T, bool) {
var zero T
defer log.Trace(time.Now(), string(s), key)

Expand Down Expand Up @@ -293,7 +293,7 @@ func Get[T any](s Store, key string) (T, bool) {
return zero, false
}

func Set[T any](s Store, key string, value T, duration Duration) {
func (s Store) Set[T any](key string, value T, duration Duration) {
defer log.Trace(time.Now(), string(s), key)

store := s.get()
Expand All @@ -318,7 +318,7 @@ func Set[T any](s Store, key string, value T, duration Duration) {
store.dirty = true
}

func Delete(s Store, key string) {
func (s Store) Delete(key string) {
defer log.Trace(time.Now(), string(s), key)

store := s.get()
Expand All @@ -332,7 +332,7 @@ func Delete(s Store, key string) {
store.dirty = true
}

func DeleteAll(s Store) {
func (s Store) DeleteAll() {
defer log.Trace(time.Now(), string(s))

store := s.get()
Expand All @@ -345,7 +345,7 @@ func DeleteAll(s Store) {
store.dirty = true
}

func Print(s Store) string {
func (s Store) Print() string {
defer log.Trace(time.Now(), string(s))

store := s.get()
Expand Down
24 changes: 12 additions & 12 deletions src/cache/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestStore(t *testing.T) {
return testStore
},
testFunc: func(t *testing.T) {
result := Print(Session)
result := Session.Print()
assert.Contains(t, result, "Key: test_key1")
assert.Contains(t, result, `Value: "test_value1"`) // Note: quotes are included in output
assert.Contains(t, result, "Type: string")
Expand All @@ -67,7 +67,7 @@ func TestStore(t *testing.T) {
return testStore
},
testFunc: func(t *testing.T) {
result := Print(Session)
result := Session.Print()
assert.Contains(t, result, "Store session is empty")
},
},
Expand All @@ -80,7 +80,7 @@ func TestStore(t *testing.T) {
},
testFunc: func(t *testing.T) {
// Since get() always creates a store, we test empty store behavior
result := Print(Session)
result := Session.Print()
assert.Contains(t, result, "Store session is empty")
},
},
Expand Down Expand Up @@ -154,15 +154,15 @@ func TestGetSurvivesGobPointerRegistration(t *testing.T) {
writer.persist = true
device = writer

Set(Device, "test_key", storeGobPointerType{Name: "value"}, Duration("1h"))
Device.Set("test_key", storeGobPointerType{Name: "value"}, Duration("1h"))
Device.close()

// Second process: fresh store, loaded from disk. This is the gob decode
// that flips the interface-typed value from T to *T.
device = nil
Device.init(fileName, true)

got, ok := Get[storeGobPointerType](Device, "test_key")
got, ok := Device.Get[storeGobPointerType]("test_key")
require.True(t, ok, "expected a cache hit after a gob round-trip of a pointer-registered type")
assert.Equal(t, "value", got.Name)
}
Expand Down Expand Up @@ -212,15 +212,15 @@ func TestRefreshMergesExternalWriteByTimestamp(t *testing.T) {
// Back to the daemon's perspective: refresh should pick up the new
// toggle_cache key from disk...
session = daemon
Refresh(Session)
Session.Refresh()

toggled, found := Get[map[string]bool](Session, TOGGLECACHE)
toggled, found := Session.Get[map[string]bool](TOGGLECACHE)
require.True(t, found, "toggle_cache written externally should be visible after Refresh")
assert.True(t, toggled["shell"])

// ...without clobbering the daemon's own newer value for a key both
// sides touched.
shared, found := Get[string](Session, "shared_key")
shared, found := Session.Get[string]("shared_key")
require.True(t, found)
assert.Equal(t, "daemon-value", shared, "a newer in-memory value must win over an older on-disk one")
}
Expand Down Expand Up @@ -272,11 +272,11 @@ func TestCloseRefreshesBeforePersistingToAvoidClobber(t *testing.T) {

session = &store{cache: onDisk.ToConcurrent()}

toggled, found := Get[map[string]bool](Session, TOGGLECACHE)
toggled, found := Session.Get[map[string]bool](TOGGLECACHE)
require.True(t, found, "the external write must survive the daemon's own shutdown flush")
assert.True(t, toggled["shell"])

count, found := Get[int](Session, "prompt_count_cache")
count, found := Session.Get[int]("prompt_count_cache")
require.True(t, found)
assert.Equal(t, 3, count)
}
Expand Down Expand Up @@ -310,9 +310,9 @@ func TestRefreshPicksUpDeviceStoreWrite(t *testing.T) {
Device.close()

device = daemon
Refresh(Device)
Device.Refresh()

reload, found := Get[bool](Device, "reload")
reload, found := Device.Get[bool]("reload")
require.True(t, found, "`enable reload` written externally should be visible after Refresh")
assert.True(t, reload)
}
Expand Down
6 changes: 2 additions & 4 deletions src/cli/auth/tui/copilot.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ type AccessTokenResponse struct {

func NewCopilot(env runtime.Environment) *CopilotAuth {
flow := &CopilotAuth{
model: model{
env: env,
},
env: env,
}

flow.model.status = flow.status
Expand Down Expand Up @@ -90,7 +88,7 @@ func (c *CopilotAuth) Authenticate() {
return
}

cache.Set(cache.Device, auth.CopilotTokenKey, token, cache.TWOYEARS)
cache.Device.Set(auth.CopilotTokenKey, token, cache.TWOYEARS)

setState(done)
}
Expand Down
6 changes: 2 additions & 4 deletions src/cli/auth/tui/ytmda.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ const (

func NewYtmda(env runtime.Environment) *Ytmda {
flow := &Ytmda{
model: model{
env: env,
},
env: env,
}

flow.model.status = flow.status
Expand Down Expand Up @@ -65,7 +63,7 @@ func (y *Ytmda) Authenticate() {
return
}

cache.Set(cache.Device, auth.YTMDATOKEN, token, cache.INFINITE)
cache.Device.Set(auth.YTMDATOKEN, token, cache.INFINITE)

setState(done)
}
Expand Down
8 changes: 3 additions & 5 deletions src/cli/auth/tui/ytmda_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,7 @@ func TestYtdma_Authenticate(t *testing.T) {
env.On("HTTPRequest", tokenURL).Return([]byte(tc.requestTokenResponse), tc.requestTokenError)

ytmda := &Ytmda{
model: model{
env: env,
},
env: env,
}

ytmda.Authenticate()
Expand All @@ -97,12 +95,12 @@ func TestYtdma_Authenticate(t *testing.T) {
}

if tc.shouldSetToken {
token, ok := cache.Get[string](cache.Device, auth.YTMDATOKEN)
token, ok := cache.Device.Get[string](auth.YTMDATOKEN)
require.True(t, ok)
assert.Equal(t, tc.expectedToken, token)
}

cache.DeleteAll(cache.Device)
cache.Device.DeleteAll()
})
}
}
4 changes: 2 additions & 2 deletions src/cli/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ You can do the following:
}

cache.Init(os.Getenv("POSH_SHELL"), cache.Persist)
cache.Set(cache.Device, cache.TTL, ttl, cache.INFINITE)
cache.Device.Set(cache.TTL, ttl, cache.INFINITE)
cache.Close()
case "show":
cache.Init(os.Getenv("POSH_SHELL"))
Expand All @@ -74,7 +74,7 @@ You can do the following:
store = cache.Session
}

fmt.Println(cache.Print(store))
fmt.Println(store.Print())
}
},
}
Expand Down
2 changes: 1 addition & 1 deletion src/cli/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ You can export or edit the config (via the editor specified in the environment v
switch args[0] {
case "edit":
cache.Init(os.Getenv("POSH_SHELL"))
if configPath, OK := cache.Get[string](cache.Session, config.SourceKey); OK {
if configPath, OK := cache.Session.Get[string](config.SourceKey); OK {
exitcode = editFileWithEditor(configPath)
return
}
Expand Down
8 changes: 3 additions & 5 deletions src/cli/config_export_data_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,9 @@ func newRecordedSessionSegment(t *testing.T, alias string) *config.Segment {
func TestBuildDataDocument_EnvSectionDropsInternalKeysKeepsRest(t *testing.T) {
template.Cache = &cache.Template{
Segments: maps.NewConcurrent[any](),
SimpleTemplate: cache.SimpleTemplate{
PWD: "/home/jan",
UserName: "jan",
Var: maps.Simple[any]{"foo": "bar"},
},
PWD: "/home/jan",
UserName: "jan",
Var: maps.Simple[any]{"foo": "bar"},
}

cfg := &config.Config{}
Expand Down
2 changes: 1 addition & 1 deletion src/cli/config_export_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func setConfigFlag() {
return
}

if configPath, OK := cache.Get[string](cache.Session, config.SourceKey); OK {
if configPath, OK := cache.Session.Get[string](config.SourceKey); OK {
configFlag = configPath
}
}
2 changes: 1 addition & 1 deletion src/cli/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,6 @@ func getDebugConfig(configpath string) *config.Config {
return config.Load(configpath)
}

reload, _ := cache.Get[bool](cache.Device, config.RELOAD)
reload, _ := cache.Device.Get[bool](config.RELOAD)
return config.Get(configpath, reload)
}
2 changes: 1 addition & 1 deletion src/cli/dsc/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var configurationSchema string

func ConfigDSC() *ConfigResource {
return &ConfigResource{
Resource: basedsc.Resource[*Configuration]{SchemaJSON: configurationSchema},
SchemaJSON: configurationSchema,
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/cli/enable.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ func toggleFeature(cmd *cmdtree.Command, feature string, enable bool) {
}

cache.Init(os.Getenv("POSH_SHELL"), cache.Persist)
cache.Set(cache.Device, feature, enable, cache.INFINITE)
cache.Device.Set(feature, enable, cache.INFINITE)
cache.Close()
}
4 changes: 2 additions & 2 deletions src/cli/font/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
// download fetches a font zip, reporting how much has arrived so a caller can draw a bar. report
// may be nil, which is what the DSC path and the tests pass.
func download(fontURL string, report func(fraction float64)) ([]byte, error) {
if zipPath, OK := cache.Get[string](cache.Device, fontURL); OK {
if zipPath, OK := cache.Device.Get[string](fontURL); OK {
if b, err := os.ReadFile(zipPath); err == nil {
return b, nil
}
Expand Down Expand Up @@ -57,7 +57,7 @@ func download(fontURL string, report func(fraction float64)) ([]byte, error) {
return b, nil
}

cache.Set(cache.Device, fontURL, zipPath, cache.ONEDAY)
cache.Device.Set(fontURL, zipPath, cache.ONEDAY)

return b, nil
}
Expand Down
Loading
Loading