diff --git a/internal/imports/fix.go b/internal/imports/fix.go index d859617b774..26ec2d52b4c 100644 --- a/internal/imports/fix.go +++ b/internal/imports/fix.go @@ -698,6 +698,12 @@ func candidateImportName(pkg *pkg) string { // GetAllCandidates calls wrapped for each package whose name starts with // searchPrefix, and can be imported from filename with the package name filePkg. func GetAllCandidates(ctx context.Context, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error { + return GetFilteredCandidates(ctx, nil, wrapped, searchPrefix, filename, filePkg, env) +} + +// GetFilteredCandidates calls wrapped for each package whose name starts with +// searchPrefix, and can be imported from filename with the package name filePkg. +func GetFilteredCandidates(ctx context.Context, shouldScanPackageDir func(pkgDir, importPathShort, packageName string) bool, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error { callback := &scanCallback{ rootFound: func(gopathwalk.Root) bool { return true @@ -708,8 +714,10 @@ func GetAllCandidates(ctx context.Context, wrapped func(ImportFix), searchPrefix } // Try the assumed package name first, then a simpler path match // in case of packages named vN, which are not uncommon. - return strings.HasPrefix(ImportPathToAssumedName(pkg.importPathShort), searchPrefix) || - strings.HasPrefix(path.Base(pkg.importPathShort), searchPrefix) + if !strings.HasPrefix(ImportPathToAssumedName(pkg.importPathShort), searchPrefix) && !strings.HasPrefix(path.Base(pkg.importPathShort), searchPrefix) { + return false + } + return shouldScanPackageDir == nil || shouldScanPackageDir(pkg.dir, pkg.importPathShort, pkg.packageName) }, packageNameLoaded: func(pkg *pkg) bool { if !strings.HasPrefix(pkg.packageName, searchPrefix) { diff --git a/internal/lsp/source/completion/completion.go b/internal/lsp/source/completion/completion.go index 45bb6db0c15..3f1ea684b48 100644 --- a/internal/lsp/source/completion/completion.go +++ b/internal/lsp/source/completion/completion.go @@ -15,6 +15,7 @@ import ( "go/token" "go/types" "math" + "path/filepath" "sort" "strconv" "strings" @@ -1468,6 +1469,7 @@ func (c *completer) unimportedPackages(ctx context.Context, seen map[string]stru if !strings.HasPrefix(pkg.GetTypes().Name(), prefix) { continue } + // TODO: Check that package is not defined in an excluded dir? paths = append(paths, path) } @@ -1548,9 +1550,25 @@ func (c *completer) unimportedPackages(ctx context.Context, seen map[string]stru }) count++ } + + shouldIncludePackage := func(pkgDir, importPathShort, packageName string) bool { + // pkgDir is an absolute path. Convert it to a workspace-relative folder. + pkgDir = filepath.ToSlash(pkgDir) + if !c.snapshot.View().Folder().IsFile() { + return true + } + workspaceDir := filepath.ToSlash(c.snapshot.View().Folder().Filename()) + workspaceRelativePkgDir := strings.TrimPrefix(pkgDir, workspaceDir) + if workspaceRelativePkgDir == pkgDir { + // Not in workspace, allow. + return true + } + disallowed := source.FiltersDisallow(workspaceRelativePkgDir, c.snapshot.View().Options().DirectoryFilters) + return !disallowed + } c.completionCallbacks = append(c.completionCallbacks, func(opts *imports.Options) error { defer cancel() - return imports.GetAllCandidates(ctx, add, prefix, c.filename, c.pkg.GetTypes().Name(), opts.Env) + return imports.GetFilteredCandidates(ctx, shouldIncludePackage, add, prefix, c.filename, c.pkg.GetTypes().Name(), opts.Env) }) return nil }