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 } }