package diag
import (
"os"
"path/filepath"
)
// workspaceRoot is the directory a language server should be told is the
// workspace for path: the nearest ancestor holding one of markers — go.mod,
// Cargo.toml, package.json — and failing that the nearest .git, and failing
// that the file's own directory.
//
// The walk is not bounded by the agent's working root, deliberately. The
// working root is where the model is allowed to write; the workspace is what
// the compiler needs to see, and the two differ whenever the user points Codey
// at one package of a larger module. Handing gopls a subdirectory of the module
// gets a server that cannot resolve a single import.
func workspaceRoot(path string, markers []string) string {
dir := filepath.Dir(path)
if root := ancestorWith(dir, markers); root != "" {
return root
}
if root := ancestorWith(dir, []string{".git"}); root != "" {
return root
}
return dir
}
// ancestorWith walks from dir to the filesystem root and returns the first
// directory containing any of names, or "".
func ancestorWith(dir string, names []string) string {
for {
for _, n := range names {
if _, err := os.Stat(filepath.Join(dir, n)); err == nil {
return dir
}
}
parent := filepath.Dir(dir)
if parent == dir {
return ""
}
dir = parent
}
}