diff --git a/docs/SETTINGS.md b/docs/SETTINGS.md index 8d89f67e..3b1e528d 100644 --- a/docs/SETTINGS.md +++ b/docs/SETTINGS.md @@ -22,26 +22,30 @@ Path to the Terraform binary. This is usually looked up automatically from `$PATH` and should not need to be specified in majority of cases. Use this to override the automatic lookup. -## `rootModulePaths` (`[]string`) +## **DEPRECATED**: `rootModulePaths` (`[]string`) -This allows overriding automatic root module discovery by passing a static list -of absolute or relative paths to root modules (i.e. folders with `*.tf` files -which have been `terraform init`-ed). Conflicts with `ExcludeModulePaths` option. +This option is deprecated and ignored from v0.29+, it was used as an escape hatch +to force indexing of paths in cases where indexer wouldn't index them otherwise. +Indexer in 0.29.0 no longer limited to just initialized modules (folders with `.terraform`) +and instead indexes all directories with `*.tf` files in them. +Therefore this option is no longer relevant. -Relative paths are resolved relative to the directory opened in the editor. +If you previously used it to force indexing of a folder outside of a workspace, +you can just add that folder to the workspace and it will be indexed as usual. -Path separators are converted automatically to the match separators -of the target platform (e.g. `\` on Windows, or `/` on Unix), -symlinks are followed, trailing slashes automatically removed, -and `~` is replaced with your home directory. +## **DEPRECATED**: `excludeModulePaths` (`[]string`) -## `excludeModulePaths` (`[]string`) +Deprecated in favour of `ignorePaths` -This allows exclude root module path when automatic root module discovery by passing a static list -of absolute or relative paths to root modules (i.e. folders with `*.tf` files -which have been `terraform init`-ed). Conflicts with `rootModulePaths` option. +## `indexing.ignorePaths` (`[]string`) -Relative paths are resolved relative to the directory opened in the editor. +Paths to ignore when indexing the workspace on initialization. This can serve +as an escape hatch in large workspaces. Key side effect of ignoring a path +is that go-to-definition, go-to-references and generally most IntelliSense +related to local `module` blocks will **not** work until the target module code +is explicitly opened. + +Relative paths are resolved relative to the root (workspace) path opened in the editor. Path separators are converted automatically to the match separators of the target platform (e.g. `\` on Windows, or `/` on Unix), @@ -68,7 +72,11 @@ Or if left empty This setting should be deprecated once the language server supports multiple workspaces, as this arises in VS code because a server instance is started per VS Code workspace. -## `ignoreDirectoryNames` (`[]string`) +## **DEPRECATED**: `ignoreDirectoryNames` (`[]string`) + +Deprecated in favour of `indexing.ignoreDirectoryNames` + +## `indexing.ignoreDirectoryNames` (`[]string`) This allows excluding directories from being indexed upon initialization by passing a list of directory names. diff --git a/internal/langserver/handlers/initialize.go b/internal/langserver/handlers/initialize.go index 4d78ce79..3ae95a59 100644 --- a/internal/langserver/handlers/initialize.go +++ b/internal/langserver/handlers/initialize.go @@ -183,11 +183,11 @@ func getTelemetryProperties(out *settings.DecodedOptions) map[string]interface{} "lsVersion": "", } - properties["options.rootModulePaths"] = len(out.Options.ModulePaths) > 0 - properties["options.rootModulePaths"] = len(out.Options.ModulePaths) > 0 - properties["options.excludeModulePaths"] = len(out.Options.ExcludeModulePaths) > 0 + properties["options.rootModulePaths"] = len(out.Options.XLegacyModulePaths) > 0 + properties["options.excludeModulePaths"] = len(out.Options.XLegacyExcludeModulePaths) > 0 properties["options.commandPrefix"] = len(out.Options.CommandPrefix) > 0 - properties["options.ignoreDirectoryNames"] = len(out.Options.IgnoreDirectoryNames) > 0 + properties["options.indexing.ignoreDirectoryNames"] = len(out.Options.IgnoreDirectoryNames) > 0 + properties["options.indexing.ignorePaths"] = len(out.Options.IgnorePaths) > 0 properties["options.experimentalFeatures.prefillRequiredFields"] = out.Options.ExperimentalFeatures.PrefillRequiredFields properties["options.experimentalFeatures.validateOnSave"] = out.Options.ExperimentalFeatures.ValidateOnSave properties["options.ignoreSingleFileWarning"] = out.Options.IgnoreSingleFileWarning @@ -248,14 +248,33 @@ func (svc *service) setupWalker(ctx context.Context, params lsp.InitializeParams return err } - var excludeModulePaths []string - for _, rawPath := range options.ExcludeModulePaths { + if len(options.XLegacyModulePaths) != 0 { + jrpc2.ServerFromContext(ctx).Notify(ctx, "window/showMessage", &lsp.ShowMessageParams{ + Type: lsp.Warning, + Message: fmt.Sprintf("rootModulePaths (%q) is deprecated (no-op), add a folder to workspace "+ + "instead if you'd like it to be indexed", options.XLegacyModulePaths), + }) + } + if len(options.XLegacyExcludeModulePaths) != 0 { + jrpc2.ServerFromContext(ctx).Notify(ctx, "window/showMessage", &lsp.ShowMessageParams{ + Type: lsp.Warning, + Message: fmt.Sprintf("excludeModulePaths (%q) is deprecated (no-op), use indexing.ignorePaths instead", + options.XLegacyExcludeModulePaths), + }) + } + + var ignoredPaths []string + for _, rawPath := range options.IgnorePaths { modPath, err := resolvePath(root.Path(), rawPath) if err != nil { - svc.logger.Printf("Ignoring excluded module path %s: %s", rawPath, err) + jrpc2.ServerFromContext(ctx).Notify(ctx, "window/showMessage", &lsp.ShowMessageParams{ + Type: lsp.Warning, + Message: fmt.Sprintf("Unable to ignore path (unsupported or invalid URI): %s: %s", + rawPath, err), + }) continue } - excludeModulePaths = append(excludeModulePaths, modPath) + ignoredPaths = append(ignoredPaths, modPath) } err = svc.stateStore.WalkerPaths.EnqueueDir(root) @@ -268,7 +287,7 @@ func (svc *service) setupWalker(ctx context.Context, params lsp.InitializeParams if !uri.IsURIValid(folder.URI) { jrpc2.ServerFromContext(ctx).Notify(ctx, "window/showMessage", &lsp.ShowMessageParams{ Type: lsp.Warning, - Message: fmt.Sprintf("Ignoring workspace folder (unsupport or invalid URI) %s."+ + Message: fmt.Sprintf("Ignoring workspace folder (unsupported or invalid URI) %s."+ " This is most likely bug, please report it.", folder.URI), }) continue @@ -288,10 +307,10 @@ func (svc *service) setupWalker(ctx context.Context, params lsp.InitializeParams } } - svc.closedDirWalker.SetIgnoreDirectoryNames(options.IgnoreDirectoryNames) - svc.closedDirWalker.SetExcludeModulePaths(excludeModulePaths) - svc.openDirWalker.SetIgnoreDirectoryNames(options.IgnoreDirectoryNames) - svc.openDirWalker.SetExcludeModulePaths(excludeModulePaths) + svc.closedDirWalker.SetIgnoredDirectoryNames(options.IgnoreDirectoryNames) + svc.closedDirWalker.SetIgnoredPaths(ignoredPaths) + svc.openDirWalker.SetIgnoredDirectoryNames(options.IgnoreDirectoryNames) + svc.openDirWalker.SetIgnoredPaths(ignoredPaths) return nil } diff --git a/internal/langserver/handlers/initialize_test.go b/internal/langserver/handlers/initialize_test.go index 4669bd87..de48418f 100644 --- a/internal/langserver/handlers/initialize_test.go +++ b/internal/langserver/handlers/initialize_test.go @@ -196,7 +196,7 @@ func TestInitialize_ignoreDirectoryNames(t *testing.T) { "rootUri": %q, "processId": 12345, "initializationOptions": { - "ignoreDirectoryNames": [%q] + "indexing.ignoreDirectoryNames": [%q] } }`, tmpDir.URI, "ignore")}) waitForWalkerPath(t, ss, wc, tmpDir) diff --git a/internal/settings/settings.go b/internal/settings/settings.go index bc9002d7..dec70088 100644 --- a/internal/settings/settings.go +++ b/internal/settings/settings.go @@ -16,11 +16,9 @@ type ExperimentalFeatures struct { } type Options struct { - // ModulePaths describes a list of absolute paths to modules to load - ModulePaths []string `mapstructure:"rootModulePaths"` - ExcludeModulePaths []string `mapstructure:"excludeModulePaths"` CommandPrefix string `mapstructure:"commandPrefix"` - IgnoreDirectoryNames []string `mapstructure:"ignoreDirectoryNames"` + IgnoreDirectoryNames []string `mapstructure:"indexing.ignoreDirectoryNames"` + IgnorePaths []string `mapstructure:"indexing.ignorePaths"` // ExperimentalFeatures encapsulates experimental features users can opt into. ExperimentalFeatures ExperimentalFeatures `mapstructure:"experimentalFeatures"` @@ -30,13 +28,12 @@ type Options struct { TerraformExecPath string `mapstructure:"terraformExecPath"` TerraformExecTimeout string `mapstructure:"terraformExecTimeout"` TerraformLogFilePath string `mapstructure:"terraformLogFilePath"` + + XLegacyModulePaths []string `mapstructure:"rootModulePaths"` + XLegacyExcludeModulePaths []string `mapstructure:"excludeModulePaths"` } func (o *Options) Validate() error { - if len(o.ModulePaths) != 0 && len(o.ExcludeModulePaths) != 0 { - return fmt.Errorf("at most one of `rootModulePaths` and `excludeModulePaths` could be set") - } - if o.TerraformExecPath != "" { path := o.TerraformExecPath if !filepath.IsAbs(path) { diff --git a/internal/settings/settings_test.go b/internal/settings/settings_test.go index 9c267ac8..cbca1730 100644 --- a/internal/settings/settings_test.go +++ b/internal/settings/settings_test.go @@ -16,14 +16,14 @@ func TestDecodeOptions_nil(t *testing.T) { } opts := out.Options - if opts.ModulePaths != nil { - t.Fatalf("expected no options for nil, %#v given", opts.ModulePaths) + if opts.IgnoreDirectoryNames != nil { + t.Fatalf("expected no options for nil, %#v given", opts.IgnoreDirectoryNames) } } func TestDecodeOptions_wrongType(t *testing.T) { _, err := DecodeOptions(map[string]interface{}{ - "rootModulePaths": "/random/path", + "indexing.ignorePaths": "/random/path", }) if err == nil { t.Fatal("expected decoding of wrong type to result in error") @@ -32,14 +32,14 @@ func TestDecodeOptions_wrongType(t *testing.T) { func TestDecodeOptions_success(t *testing.T) { out, err := DecodeOptions(map[string]interface{}{ - "rootModulePaths": []string{"/random/path"}, + "indexing.ignorePaths": []string{"/random/path"}, }) if err != nil { t.Fatal(err) } opts := out.Options expectedPaths := []string{"/random/path"} - if diff := cmp.Diff(expectedPaths, opts.ModulePaths); diff != "" { + if diff := cmp.Diff(expectedPaths, opts.IgnorePaths); diff != "" { t.Fatalf("options mismatch: %s", diff) } } @@ -55,7 +55,7 @@ func TestValidate_IgnoreDirectoryNames_error(t *testing.T) { for _, table := range tables { out, err := DecodeOptions(map[string]interface{}{ - "ignoreDirectoryNames": []string{table.input}, + "indexing.ignoreDirectoryNames": []string{table.input}, }) if err != nil { t.Fatal(err) @@ -69,7 +69,7 @@ func TestValidate_IgnoreDirectoryNames_error(t *testing.T) { } func TestValidate_IgnoreDirectoryNames_success(t *testing.T) { out, err := DecodeOptions(map[string]interface{}{ - "ignoreDirectoryNames": []string{"directory"}, + "indexing.ignoreDirectoryNames": []string{"directory"}, }) if err != nil { t.Fatal(err) diff --git a/internal/walker/walker.go b/internal/walker/walker.go index 11f32126..31e3bc6a 100644 --- a/internal/walker/walker.go +++ b/internal/walker/walker.go @@ -44,8 +44,8 @@ type Walker struct { cancelFunc context.CancelFunc - excludeModulePaths map[string]bool - ignoreDirectoryNames map[string]bool + ignoredPaths map[string]bool + ignoredDirectoryNames map[string]bool } type WalkFunc func(ctx context.Context, modHandle document.DirHandle) (job.IDs, error) @@ -62,12 +62,12 @@ type ModuleStore interface { func NewWalker(fs fs.ReadDirFS, pathStore PathStore, modStore ModuleStore, walkFunc WalkFunc) *Walker { return &Walker{ - fs: fs, - pathStore: pathStore, - modStore: modStore, - walkFunc: walkFunc, - logger: discardLogger, - ignoreDirectoryNames: skipDirNames, + fs: fs, + pathStore: pathStore, + modStore: modStore, + walkFunc: walkFunc, + logger: discardLogger, + ignoredDirectoryNames: skipDirNames, } } @@ -75,19 +75,19 @@ func (w *Walker) SetLogger(logger *log.Logger) { w.logger = logger } -func (w *Walker) SetExcludeModulePaths(excludeModulePaths []string) { - w.excludeModulePaths = make(map[string]bool) - for _, path := range excludeModulePaths { - w.excludeModulePaths[path] = true +func (w *Walker) SetIgnoredPaths(ignoredPaths []string) { + w.ignoredPaths = make(map[string]bool) + for _, path := range ignoredPaths { + w.ignoredPaths[path] = true } } -func (w *Walker) SetIgnoreDirectoryNames(ignoreDirectoryNames []string) { +func (w *Walker) SetIgnoredDirectoryNames(ignoredDirectoryNames []string) { if w.cancelFunc != nil { panic("cannot set ignorelist after walking started") } - for _, path := range ignoreDirectoryNames { - w.ignoreDirectoryNames[path] = true + for _, path := range ignoredDirectoryNames { + w.ignoredDirectoryNames[path] = true } } @@ -154,12 +154,12 @@ func (w *Walker) collectJobIds(jobIds job.IDs) { } func (w *Walker) isSkippableDir(dirName string) bool { - _, ok := w.ignoreDirectoryNames[dirName] + _, ok := w.ignoredDirectoryNames[dirName] return ok } func (w *Walker) walk(ctx context.Context, dir document.DirHandle) error { - if _, ok := w.excludeModulePaths[dir.Path()]; ok { + if _, ok := w.ignoredPaths[dir.Path()]; ok { w.logger.Printf("skipping walk due to dir being excluded: %s", dir.Path()) return nil }