Files
02f66a2e86 feat(lsp): start LSPs on demand, improve auto-start (#2103)
* feat(lsp): start LSPs on demand, improve auto-start

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* refactor: simplify

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* chore: fmt

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* feat: handle new session/load session

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* refactor: manager holds client list reference

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: do io in cmd

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: better manager

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: nil

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: err

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: properly handle restart

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: add stopped state

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: root markers

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: load for read files as well

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* chore(go.mod): move indirect dependency to the right block

---------

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
Co-authored-by: Andrey Nering <andreynering@users.noreply.github.com>
2026-02-06 16:12:18 -03:00

94 lines
2.4 KiB
Go

// Package filetracker provides functionality to track file reads in sessions.
package filetracker
import (
"context"
"fmt"
"log/slog"
"os"
"path/filepath"
"time"
"github.com/charmbracelet/crush/internal/db"
)
// Service defines the interface for tracking file reads in sessions.
type Service interface {
// RecordRead records when a file was read.
RecordRead(ctx context.Context, sessionID, path string)
// LastReadTime returns when a file was last read.
// Returns zero time if never read.
LastReadTime(ctx context.Context, sessionID, path string) time.Time
// ListReadFiles returns the paths of all files read in a session.
ListReadFiles(ctx context.Context, sessionID string) ([]string, error)
}
type service struct {
q *db.Queries
}
// NewService creates a new file tracker service.
func NewService(q *db.Queries) Service {
return &service{q: q}
}
// RecordRead records when a file was read.
func (s *service) RecordRead(ctx context.Context, sessionID, path string) {
if err := s.q.RecordFileRead(ctx, db.RecordFileReadParams{
SessionID: sessionID,
Path: relpath(path),
}); err != nil {
slog.Error("Error recording file read", "error", err, "file", path)
}
}
// LastReadTime returns when a file was last read.
// Returns zero time if never read.
func (s *service) LastReadTime(ctx context.Context, sessionID, path string) time.Time {
readFile, err := s.q.GetFileRead(ctx, db.GetFileReadParams{
SessionID: sessionID,
Path: relpath(path),
})
if err != nil {
return time.Time{}
}
return time.Unix(readFile.ReadAt, 0)
}
func relpath(path string) string {
path = filepath.Clean(path)
basepath, err := os.Getwd()
if err != nil {
slog.Warn("Error getting basepath", "error", err)
return path
}
relpath, err := filepath.Rel(basepath, path)
if err != nil {
slog.Warn("Error getting relpath", "error", err)
return path
}
return relpath
}
// ListReadFiles returns the paths of all files read in a session.
func (s *service) ListReadFiles(ctx context.Context, sessionID string) ([]string, error) {
readFiles, err := s.q.ListSessionReadFiles(ctx, sessionID)
if err != nil {
return nil, fmt.Errorf("listing read files: %w", err)
}
basepath, err := os.Getwd()
if err != nil {
return nil, fmt.Errorf("getting working directory: %w", err)
}
paths := make([]string, 0, len(readFiles))
for _, rf := range readFiles {
paths = append(paths, filepath.Join(basepath, rf.Path))
}
return paths, nil
}