11 "github.com/charmbracelet/crush/internal/config"
14const projectsFileName = "projects.json"
16// Project represents a tracked project directory.
18 Path string `json:"path"`
19 DataDir string `json:"data_dir"`
20 LastAccessed time.Time `json:"last_accessed"`
23// ProjectList holds the list of tracked projects.
24type ProjectList struct {
25 Projects []Project `json:"projects"`
30// projectsFilePath returns the path to the projects.json file.
31func projectsFilePath() string {
32 return filepath.Join(filepath.Dir(config.GlobalConfigData()), projectsFileName)
35// Load reads the projects list from disk.
36func Load() (*ProjectList, error) {
40 path := projectsFilePath()
41 data, err := os.ReadFile(path)
43 if os.IsNotExist(err) {
44 return &ProjectList{Projects: []Project{}}, nil
50 if err := json.Unmarshal(data, &list); err != nil {
57// Save writes the projects list to disk.
58func Save(list *ProjectList) error {
62 path := projectsFilePath()
64 // Ensure directory exists
65 if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
69 data, err := json.MarshalIndent(list, "", " ")
74 return os.WriteFile(path, data, 0o600)
77// Register adds or updates a project in the list.
78func Register(workingDir, dataDir string) error {
84 now := time.Now().UTC()
86 // Check if project already exists
88 for i, p := range list.Projects {
89 if p.Path == workingDir {
90 list.Projects[i].DataDir = dataDir
91 list.Projects[i].LastAccessed = now
98 list.Projects = append(list.Projects, Project{
105 // Sort by last accessed (most recent first)
106 slices.SortFunc(list.Projects, func(a, b Project) int {
107 if a.LastAccessed.After(b.LastAccessed) {
110 if a.LastAccessed.Before(b.LastAccessed) {
119// List returns all tracked projects sorted by last accessed.
120func List() ([]Project, error) {
125 return list.Projects, nil
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list