github.com/v2fly/tools@v0.100.0/internal/lsp/source/options.go (about)

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package source
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"path/filepath"
    11  	"regexp"
    12  	"strings"
    13  	"sync"
    14  	"time"
    15  
    16  	"github.com/v2fly/tools/go/analysis"
    17  	"github.com/v2fly/tools/go/analysis/passes/asmdecl"
    18  	"github.com/v2fly/tools/go/analysis/passes/assign"
    19  	"github.com/v2fly/tools/go/analysis/passes/atomic"
    20  	"github.com/v2fly/tools/go/analysis/passes/atomicalign"
    21  	"github.com/v2fly/tools/go/analysis/passes/bools"
    22  	"github.com/v2fly/tools/go/analysis/passes/buildtag"
    23  	"github.com/v2fly/tools/go/analysis/passes/cgocall"
    24  	"github.com/v2fly/tools/go/analysis/passes/composite"
    25  	"github.com/v2fly/tools/go/analysis/passes/copylock"
    26  	"github.com/v2fly/tools/go/analysis/passes/deepequalerrors"
    27  	"github.com/v2fly/tools/go/analysis/passes/errorsas"
    28  	"github.com/v2fly/tools/go/analysis/passes/fieldalignment"
    29  	"github.com/v2fly/tools/go/analysis/passes/httpresponse"
    30  	"github.com/v2fly/tools/go/analysis/passes/ifaceassert"
    31  	"github.com/v2fly/tools/go/analysis/passes/loopclosure"
    32  	"github.com/v2fly/tools/go/analysis/passes/lostcancel"
    33  	"github.com/v2fly/tools/go/analysis/passes/nilfunc"
    34  	"github.com/v2fly/tools/go/analysis/passes/nilness"
    35  	"github.com/v2fly/tools/go/analysis/passes/printf"
    36  	"github.com/v2fly/tools/go/analysis/passes/shadow"
    37  	"github.com/v2fly/tools/go/analysis/passes/shift"
    38  	"github.com/v2fly/tools/go/analysis/passes/sortslice"
    39  	"github.com/v2fly/tools/go/analysis/passes/stdmethods"
    40  	"github.com/v2fly/tools/go/analysis/passes/stringintconv"
    41  	"github.com/v2fly/tools/go/analysis/passes/structtag"
    42  	"github.com/v2fly/tools/go/analysis/passes/testinggoroutine"
    43  	"github.com/v2fly/tools/go/analysis/passes/tests"
    44  	"github.com/v2fly/tools/go/analysis/passes/unmarshal"
    45  	"github.com/v2fly/tools/go/analysis/passes/unreachable"
    46  	"github.com/v2fly/tools/go/analysis/passes/unsafeptr"
    47  	"github.com/v2fly/tools/go/analysis/passes/unusedresult"
    48  	"github.com/v2fly/tools/go/analysis/passes/unusedwrite"
    49  	"github.com/v2fly/tools/internal/lsp/analysis/fillreturns"
    50  	"github.com/v2fly/tools/internal/lsp/analysis/fillstruct"
    51  	"github.com/v2fly/tools/internal/lsp/analysis/nonewvars"
    52  	"github.com/v2fly/tools/internal/lsp/analysis/noresultvalues"
    53  	"github.com/v2fly/tools/internal/lsp/analysis/simplifycompositelit"
    54  	"github.com/v2fly/tools/internal/lsp/analysis/simplifyrange"
    55  	"github.com/v2fly/tools/internal/lsp/analysis/simplifyslice"
    56  	"github.com/v2fly/tools/internal/lsp/analysis/undeclaredname"
    57  	"github.com/v2fly/tools/internal/lsp/analysis/unusedparams"
    58  	"github.com/v2fly/tools/internal/lsp/command"
    59  	"github.com/v2fly/tools/internal/lsp/diff"
    60  	"github.com/v2fly/tools/internal/lsp/diff/myers"
    61  	"github.com/v2fly/tools/internal/lsp/protocol"
    62  	errors "golang.org/x/xerrors"
    63  )
    64  
    65  var (
    66  	optionsOnce    sync.Once
    67  	defaultOptions *Options
    68  )
    69  
    70  // DefaultOptions is the options that are used for Gopls execution independent
    71  // of any externally provided configuration (LSP initialization, command
    72  // invokation, etc.).
    73  func DefaultOptions() *Options {
    74  	optionsOnce.Do(func() {
    75  		var commands []string
    76  		for _, c := range command.Commands {
    77  			commands = append(commands, c.ID())
    78  		}
    79  		defaultOptions = &Options{
    80  			ClientOptions: ClientOptions{
    81  				InsertTextFormat:                  protocol.PlainTextTextFormat,
    82  				PreferredContentFormat:            protocol.Markdown,
    83  				ConfigurationSupported:            true,
    84  				DynamicConfigurationSupported:     true,
    85  				DynamicWatchedFilesSupported:      true,
    86  				LineFoldingOnly:                   false,
    87  				HierarchicalDocumentSymbolSupport: true,
    88  			},
    89  			ServerOptions: ServerOptions{
    90  				SupportedCodeActions: map[FileKind]map[protocol.CodeActionKind]bool{
    91  					Go: {
    92  						protocol.SourceFixAll:          true,
    93  						protocol.SourceOrganizeImports: true,
    94  						protocol.QuickFix:              true,
    95  						protocol.RefactorRewrite:       true,
    96  						protocol.RefactorExtract:       true,
    97  					},
    98  					Mod: {
    99  						protocol.SourceOrganizeImports: true,
   100  						protocol.QuickFix:              true,
   101  					},
   102  					Sum: {},
   103  				},
   104  				SupportedCommands: commands,
   105  			},
   106  			UserOptions: UserOptions{
   107  				BuildOptions: BuildOptions{
   108  					ExpandWorkspaceToModule:     true,
   109  					ExperimentalPackageCacheKey: true,
   110  					MemoryMode:                  ModeNormal,
   111  				},
   112  				UIOptions: UIOptions{
   113  					DiagnosticOptions: DiagnosticOptions{
   114  						ExperimentalDiagnosticsDelay: 250 * time.Millisecond,
   115  						Annotations: map[Annotation]bool{
   116  							Bounds: true,
   117  							Escape: true,
   118  							Inline: true,
   119  							Nil:    true,
   120  						},
   121  					},
   122  					DocumentationOptions: DocumentationOptions{
   123  						HoverKind:    FullDocumentation,
   124  						LinkTarget:   "pkg.go.dev",
   125  						LinksInHover: true,
   126  					},
   127  					NavigationOptions: NavigationOptions{
   128  						ImportShortcut: Both,
   129  						SymbolMatcher:  SymbolFuzzy,
   130  						SymbolStyle:    DynamicSymbols,
   131  					},
   132  					CompletionOptions: CompletionOptions{
   133  						Matcher:                        Fuzzy,
   134  						CompletionBudget:               100 * time.Millisecond,
   135  						ExperimentalPostfixCompletions: false,
   136  					},
   137  					Codelenses: map[string]bool{
   138  						string(command.Generate):          true,
   139  						string(command.RegenerateCgo):     true,
   140  						string(command.Tidy):              true,
   141  						string(command.GCDetails):         false,
   142  						string(command.UpgradeDependency): true,
   143  						string(command.Vendor):            true,
   144  					},
   145  				},
   146  			},
   147  			InternalOptions: InternalOptions{
   148  				LiteralCompletions:      true,
   149  				TempModfile:             true,
   150  				CompleteUnimported:      true,
   151  				CompletionDocumentation: true,
   152  				DeepCompletion:          true,
   153  			},
   154  			Hooks: Hooks{
   155  				ComputeEdits:         myers.ComputeEdits,
   156  				URLRegexp:            urlRegexp(),
   157  				DefaultAnalyzers:     defaultAnalyzers(),
   158  				TypeErrorAnalyzers:   typeErrorAnalyzers(),
   159  				ConvenienceAnalyzers: convenienceAnalyzers(),
   160  				StaticcheckAnalyzers: map[string]*Analyzer{},
   161  				GoDiff:               true,
   162  			},
   163  		}
   164  	})
   165  	return defaultOptions
   166  }
   167  
   168  // Options holds various configuration that affects Gopls execution, organized
   169  // by the nature or origin of the settings.
   170  type Options struct {
   171  	ClientOptions
   172  	ServerOptions
   173  	UserOptions
   174  	InternalOptions
   175  	Hooks
   176  }
   177  
   178  // ClientOptions holds LSP-specific configuration that is provided by the
   179  // client.
   180  type ClientOptions struct {
   181  	InsertTextFormat                  protocol.InsertTextFormat
   182  	ConfigurationSupported            bool
   183  	DynamicConfigurationSupported     bool
   184  	DynamicWatchedFilesSupported      bool
   185  	PreferredContentFormat            protocol.MarkupKind
   186  	LineFoldingOnly                   bool
   187  	HierarchicalDocumentSymbolSupport bool
   188  	SemanticTypes                     []string
   189  	SemanticMods                      []string
   190  	RelatedInformationSupported       bool
   191  	CompletionTags                    bool
   192  	CompletionDeprecated              bool
   193  }
   194  
   195  // ServerOptions holds LSP-specific configuration that is provided by the
   196  // server.
   197  type ServerOptions struct {
   198  	SupportedCodeActions map[FileKind]map[protocol.CodeActionKind]bool
   199  	SupportedCommands    []string
   200  }
   201  
   202  type BuildOptions struct {
   203  	// BuildFlags is the set of flags passed on to the build system when invoked.
   204  	// It is applied to queries like `go list`, which is used when discovering files.
   205  	// The most common use is to set `-tags`.
   206  	BuildFlags []string
   207  
   208  	// Env adds environment variables to external commands run by `gopls`, most notably `go list`.
   209  	Env map[string]string
   210  
   211  	// DirectoryFilters can be used to exclude unwanted directories from the
   212  	// workspace. By default, all directories are included. Filters are an
   213  	// operator, `+` to include and `-` to exclude, followed by a path prefix
   214  	// relative to the workspace folder. They are evaluated in order, and
   215  	// the last filter that applies to a path controls whether it is included.
   216  	// The path prefix can be empty, so an initial `-` excludes everything.
   217  	//
   218  	// Examples:
   219  	//
   220  	// Exclude node_modules: `-node_modules`
   221  	//
   222  	// Include only project_a: `-` (exclude everything), `+project_a`
   223  	//
   224  	// Include only project_a, but not node_modules inside it: `-`, `+project_a`, `-project_a/node_modules`
   225  	DirectoryFilters []string
   226  
   227  	// MemoryMode controls the tradeoff `gopls` makes between memory usage and
   228  	// correctness.
   229  	//
   230  	// Values other than `Normal` are untested and may break in surprising ways.
   231  	MemoryMode MemoryMode `status:"experimental"`
   232  
   233  	// ExpandWorkspaceToModule instructs `gopls` to adjust the scope of the
   234  	// workspace to find the best available module root. `gopls` first looks for
   235  	// a go.mod file in any parent directory of the workspace folder, expanding
   236  	// the scope to that directory if it exists. If no viable parent directory is
   237  	// found, gopls will check if there is exactly one child directory containing
   238  	// a go.mod file, narrowing the scope to that directory if it exists.
   239  	ExpandWorkspaceToModule bool `status:"experimental"`
   240  
   241  	// ExperimentalWorkspaceModule opts a user into the experimental support
   242  	// for multi-module workspaces.
   243  	ExperimentalWorkspaceModule bool `status:"experimental"`
   244  
   245  	// ExperimentalPackageCacheKey controls whether to use a coarser cache key
   246  	// for package type information to increase cache hits. This setting removes
   247  	// the user's environment, build flags, and working directory from the cache
   248  	// key, which should be a safe change as all relevant inputs into the type
   249  	// checking pass are already hashed into the key. This is temporarily guarded
   250  	// by an experiment because caching behavior is subtle and difficult to
   251  	// comprehensively test.
   252  	ExperimentalPackageCacheKey bool `status:"experimental"`
   253  
   254  	// AllowModfileModifications disables -mod=readonly, allowing imports from
   255  	// out-of-scope modules. This option will eventually be removed.
   256  	AllowModfileModifications bool `status:"experimental"`
   257  
   258  	// AllowImplicitNetworkAccess disables GOPROXY=off, allowing implicit module
   259  	// downloads rather than requiring user action. This option will eventually
   260  	// be removed.
   261  	AllowImplicitNetworkAccess bool `status:"experimental"`
   262  }
   263  
   264  type UIOptions struct {
   265  	DocumentationOptions
   266  	CompletionOptions
   267  	NavigationOptions
   268  	DiagnosticOptions
   269  
   270  	// Codelenses overrides the enabled/disabled state of code lenses. See the
   271  	// "Code Lenses" section of the
   272  	// [Settings page](https://github.com/golang/tools/blob/master/gopls/doc/settings.md)
   273  	// for the list of supported lenses.
   274  	//
   275  	// Example Usage:
   276  	//
   277  	// ```json5
   278  	// "gopls": {
   279  	// ...
   280  	//   "codelens": {
   281  	//     "generate": false,  // Don't show the `go generate` lens.
   282  	//     "gc_details": true  // Show a code lens toggling the display of gc's choices.
   283  	//   }
   284  	// ...
   285  	// }
   286  	// ```
   287  	Codelenses map[string]bool
   288  
   289  	// SemanticTokens controls whether the LSP server will send
   290  	// semantic tokens to the client.
   291  	SemanticTokens bool `status:"experimental"`
   292  }
   293  
   294  type CompletionOptions struct {
   295  	// Placeholders enables placeholders for function parameters or struct
   296  	// fields in completion responses.
   297  	UsePlaceholders bool
   298  
   299  	// CompletionBudget is the soft latency goal for completion requests. Most
   300  	// requests finish in a couple milliseconds, but in some cases deep
   301  	// completions can take much longer. As we use up our budget we
   302  	// dynamically reduce the search scope to ensure we return timely
   303  	// results. Zero means unlimited.
   304  	CompletionBudget time.Duration `status:"debug"`
   305  
   306  	// Matcher sets the algorithm that is used when calculating completion
   307  	// candidates.
   308  	Matcher Matcher `status:"advanced"`
   309  
   310  	// ExperimentalPostfixCompletions enables artifical method snippets
   311  	// such as "someSlice.sort!".
   312  	ExperimentalPostfixCompletions bool `status:"experimental"`
   313  }
   314  
   315  type DocumentationOptions struct {
   316  	// HoverKind controls the information that appears in the hover text.
   317  	// SingleLine and Structured are intended for use only by authors of editor plugins.
   318  	HoverKind HoverKind
   319  
   320  	// LinkTarget controls where documentation links go.
   321  	// It might be one of:
   322  	//
   323  	// * `"godoc.org"`
   324  	// * `"pkg.go.dev"`
   325  	//
   326  	// If company chooses to use its own `godoc.org`, its address can be used as well.
   327  	LinkTarget string
   328  
   329  	// LinksInHover toggles the presence of links to documentation in hover.
   330  	LinksInHover bool
   331  }
   332  
   333  type FormattingOptions struct {
   334  	// Local is the equivalent of the `goimports -local` flag, which puts
   335  	// imports beginning with this string after third-party packages. It should
   336  	// be the prefix of the import path whose imports should be grouped
   337  	// separately.
   338  	Local string
   339  
   340  	// Gofumpt indicates if we should run gofumpt formatting.
   341  	Gofumpt bool
   342  }
   343  
   344  type DiagnosticOptions struct {
   345  	// Analyses specify analyses that the user would like to enable or disable.
   346  	// A map of the names of analysis passes that should be enabled/disabled.
   347  	// A full list of analyzers that gopls uses can be found
   348  	// [here](https://github.com/golang/tools/blob/master/gopls/doc/analyzers.md).
   349  	//
   350  	// Example Usage:
   351  	//
   352  	// ```json5
   353  	// ...
   354  	// "analyses": {
   355  	//   "unreachable": false, // Disable the unreachable analyzer.
   356  	//   "unusedparams": true  // Enable the unusedparams analyzer.
   357  	// }
   358  	// ...
   359  	// ```
   360  	Analyses map[string]bool
   361  
   362  	// Staticcheck enables additional analyses from staticcheck.io.
   363  	Staticcheck bool `status:"experimental"`
   364  
   365  	// Annotations specifies the various kinds of optimization diagnostics
   366  	// that should be reported by the gc_details command.
   367  	Annotations map[Annotation]bool `status:"experimental"`
   368  
   369  	// ExperimentalDiagnosticsDelay controls the amount of time that gopls waits
   370  	// after the most recent file modification before computing deep diagnostics.
   371  	// Simple diagnostics (parsing and type-checking) are always run immediately
   372  	// on recently modified packages.
   373  	//
   374  	// This option must be set to a valid duration string, for example `"250ms"`.
   375  	ExperimentalDiagnosticsDelay time.Duration `status:"experimental"`
   376  }
   377  
   378  type NavigationOptions struct {
   379  	// ImportShortcut specifies whether import statements should link to
   380  	// documentation or go to definitions.
   381  	ImportShortcut ImportShortcut
   382  
   383  	// SymbolMatcher sets the algorithm that is used when finding workspace symbols.
   384  	SymbolMatcher SymbolMatcher `status:"advanced"`
   385  
   386  	// SymbolStyle controls how symbols are qualified in symbol responses.
   387  	//
   388  	// Example Usage:
   389  	//
   390  	// ```json5
   391  	// "gopls": {
   392  	// ...
   393  	//   "symbolStyle": "dynamic",
   394  	// ...
   395  	// }
   396  	// ```
   397  	SymbolStyle SymbolStyle `status:"advanced"`
   398  }
   399  
   400  // UserOptions holds custom Gopls configuration (not part of the LSP) that is
   401  // modified by the client.
   402  type UserOptions struct {
   403  	BuildOptions
   404  	UIOptions
   405  	FormattingOptions
   406  
   407  	// VerboseOutput enables additional debug logging.
   408  	VerboseOutput bool `status:"debug"`
   409  }
   410  
   411  // EnvSlice returns Env as a slice of k=v strings.
   412  func (u *UserOptions) EnvSlice() []string {
   413  	var result []string
   414  	for k, v := range u.Env {
   415  		result = append(result, fmt.Sprintf("%v=%v", k, v))
   416  	}
   417  	return result
   418  }
   419  
   420  // SetEnvSlice sets Env from a slice of k=v strings.
   421  func (u *UserOptions) SetEnvSlice(env []string) {
   422  	u.Env = map[string]string{}
   423  	for _, kv := range env {
   424  		split := strings.SplitN(kv, "=", 2)
   425  		if len(split) != 2 {
   426  			continue
   427  		}
   428  		u.Env[split[0]] = split[1]
   429  	}
   430  }
   431  
   432  // Hooks contains configuration that is provided to the Gopls command by the
   433  // main package.
   434  type Hooks struct {
   435  	LicensesText         string
   436  	GoDiff               bool
   437  	ComputeEdits         diff.ComputeEdits
   438  	URLRegexp            *regexp.Regexp
   439  	GofumptFormat        func(ctx context.Context, src []byte) ([]byte, error)
   440  	DefaultAnalyzers     map[string]*Analyzer
   441  	TypeErrorAnalyzers   map[string]*Analyzer
   442  	ConvenienceAnalyzers map[string]*Analyzer
   443  	StaticcheckAnalyzers map[string]*Analyzer
   444  }
   445  
   446  // InternalOptions contains settings that are not intended for use by the
   447  // average user. These may be settings used by tests or outdated settings that
   448  // will soon be deprecated. Some of these settings may not even be configurable
   449  // by the user.
   450  type InternalOptions struct {
   451  	// LiteralCompletions controls whether literal candidates such as
   452  	// "&someStruct{}" are offered. Tests disable this flag to simplify
   453  	// their expected values.
   454  	LiteralCompletions bool
   455  
   456  	// VerboseWorkDoneProgress controls whether the LSP server should send
   457  	// progress reports for all work done outside the scope of an RPC.
   458  	// Used by the regression tests.
   459  	VerboseWorkDoneProgress bool
   460  
   461  	// The following options were previously available to users, but they
   462  	// really shouldn't be configured by anyone other than "power users".
   463  
   464  	// CompletionDocumentation enables documentation with completion results.
   465  	CompletionDocumentation bool
   466  
   467  	// CompleteUnimported enables completion for packages that you do not
   468  	// currently import.
   469  	CompleteUnimported bool
   470  
   471  	// DeepCompletion enables the ability to return completions from deep
   472  	// inside relevant entities, rather than just the locally accessible ones.
   473  	//
   474  	// Consider this example:
   475  	//
   476  	// ```go
   477  	// package main
   478  	//
   479  	// import "fmt"
   480  	//
   481  	// type wrapString struct {
   482  	//     str string
   483  	// }
   484  	//
   485  	// func main() {
   486  	//     x := wrapString{"hello world"}
   487  	//     fmt.Printf(<>)
   488  	// }
   489  	// ```
   490  	//
   491  	// At the location of the `<>` in this program, deep completion would suggest the result `x.str`.
   492  	DeepCompletion bool
   493  
   494  	// TempModfile controls the use of the -modfile flag in Go 1.14.
   495  	TempModfile bool
   496  }
   497  
   498  type ImportShortcut string
   499  
   500  const (
   501  	Both       ImportShortcut = "Both"
   502  	Link       ImportShortcut = "Link"
   503  	Definition ImportShortcut = "Definition"
   504  )
   505  
   506  func (s ImportShortcut) ShowLinks() bool {
   507  	return s == Both || s == Link
   508  }
   509  
   510  func (s ImportShortcut) ShowDefinition() bool {
   511  	return s == Both || s == Definition
   512  }
   513  
   514  type Matcher string
   515  
   516  const (
   517  	Fuzzy           Matcher = "Fuzzy"
   518  	CaseInsensitive Matcher = "CaseInsensitive"
   519  	CaseSensitive   Matcher = "CaseSensitive"
   520  )
   521  
   522  type SymbolMatcher string
   523  
   524  const (
   525  	SymbolFuzzy           SymbolMatcher = "Fuzzy"
   526  	SymbolCaseInsensitive SymbolMatcher = "CaseInsensitive"
   527  	SymbolCaseSensitive   SymbolMatcher = "CaseSensitive"
   528  )
   529  
   530  type SymbolStyle string
   531  
   532  const (
   533  	// PackageQualifiedSymbols is package qualified symbols i.e.
   534  	// "pkg.Foo.Field".
   535  	PackageQualifiedSymbols SymbolStyle = "Package"
   536  	// FullyQualifiedSymbols is fully qualified symbols, i.e.
   537  	// "path/to/pkg.Foo.Field".
   538  	FullyQualifiedSymbols SymbolStyle = "Full"
   539  	// DynamicSymbols uses whichever qualifier results in the highest scoring
   540  	// match for the given symbol query. Here a "qualifier" is any "/" or "."
   541  	// delimited suffix of the fully qualified symbol. i.e. "to/pkg.Foo.Field" or
   542  	// just "Foo.Field".
   543  	DynamicSymbols SymbolStyle = "Dynamic"
   544  )
   545  
   546  type HoverKind string
   547  
   548  const (
   549  	SingleLine            HoverKind = "SingleLine"
   550  	NoDocumentation       HoverKind = "NoDocumentation"
   551  	SynopsisDocumentation HoverKind = "SynopsisDocumentation"
   552  	FullDocumentation     HoverKind = "FullDocumentation"
   553  
   554  	// Structured is an experimental setting that returns a structured hover format.
   555  	// This format separates the signature from the documentation, so that the client
   556  	// can do more manipulation of these fields.
   557  	//
   558  	// This should only be used by clients that support this behavior.
   559  	Structured HoverKind = "Structured"
   560  )
   561  
   562  type MemoryMode string
   563  
   564  const (
   565  	ModeNormal MemoryMode = "Normal"
   566  	// In DegradeClosed mode, `gopls` will collect less information about
   567  	// packages without open files. As a result, features like Find
   568  	// References and Rename will miss results in such packages.
   569  	ModeDegradeClosed MemoryMode = "DegradeClosed"
   570  )
   571  
   572  type OptionResults []OptionResult
   573  
   574  type OptionResult struct {
   575  	Name  string
   576  	Value interface{}
   577  	Error error
   578  
   579  	State       OptionState
   580  	Replacement string
   581  }
   582  
   583  type OptionState int
   584  
   585  const (
   586  	OptionHandled = OptionState(iota)
   587  	OptionDeprecated
   588  	OptionUnexpected
   589  )
   590  
   591  type LinkTarget string
   592  
   593  func SetOptions(options *Options, opts interface{}) OptionResults {
   594  	var results OptionResults
   595  	switch opts := opts.(type) {
   596  	case nil:
   597  	case map[string]interface{}:
   598  		// If the user's settings contains "allExperiments", set that first,
   599  		// and then let them override individual settings independently.
   600  		var enableExperiments bool
   601  		for name, value := range opts {
   602  			if b, ok := value.(bool); name == "allExperiments" && ok && b {
   603  				enableExperiments = true
   604  				options.enableAllExperiments()
   605  			}
   606  		}
   607  		seen := map[string]struct{}{}
   608  		for name, value := range opts {
   609  			results = append(results, options.set(name, value, seen))
   610  		}
   611  		// Finally, enable any experimental features that are specified in
   612  		// maps, which allows users to individually toggle them on or off.
   613  		if enableExperiments {
   614  			options.enableAllExperimentMaps()
   615  		}
   616  	default:
   617  		results = append(results, OptionResult{
   618  			Value: opts,
   619  			Error: errors.Errorf("Invalid options type %T", opts),
   620  		})
   621  	}
   622  	return results
   623  }
   624  
   625  func (o *Options) ForClientCapabilities(caps protocol.ClientCapabilities) {
   626  	// Check if the client supports snippets in completion items.
   627  	if c := caps.TextDocument.Completion; c.CompletionItem.SnippetSupport {
   628  		o.InsertTextFormat = protocol.SnippetTextFormat
   629  	}
   630  	// Check if the client supports configuration messages.
   631  	o.ConfigurationSupported = caps.Workspace.Configuration
   632  	o.DynamicConfigurationSupported = caps.Workspace.DidChangeConfiguration.DynamicRegistration
   633  	o.DynamicWatchedFilesSupported = caps.Workspace.DidChangeWatchedFiles.DynamicRegistration
   634  
   635  	// Check which types of content format are supported by this client.
   636  	if hover := caps.TextDocument.Hover; len(hover.ContentFormat) > 0 {
   637  		o.PreferredContentFormat = hover.ContentFormat[0]
   638  	}
   639  	// Check if the client supports only line folding.
   640  	fr := caps.TextDocument.FoldingRange
   641  	o.LineFoldingOnly = fr.LineFoldingOnly
   642  	// Check if the client supports hierarchical document symbols.
   643  	o.HierarchicalDocumentSymbolSupport = caps.TextDocument.DocumentSymbol.HierarchicalDocumentSymbolSupport
   644  	// Check if the client supports semantic tokens
   645  	o.SemanticTypes = caps.TextDocument.SemanticTokens.TokenTypes
   646  	o.SemanticMods = caps.TextDocument.SemanticTokens.TokenModifiers
   647  	// we don't need Requests, as we support full functionality
   648  	// we don't need Formats, as there is only one, for now
   649  
   650  	// Check if the client supports diagnostic related information.
   651  	o.RelatedInformationSupported = caps.TextDocument.PublishDiagnostics.RelatedInformation
   652  	// Check if the client completion support incliudes tags (preferred) or deprecation
   653  	if caps.TextDocument.Completion.CompletionItem.TagSupport.ValueSet != nil {
   654  		o.CompletionTags = true
   655  	} else if caps.TextDocument.Completion.CompletionItem.DeprecatedSupport {
   656  		o.CompletionDeprecated = true
   657  	}
   658  }
   659  
   660  func (o *Options) Clone() *Options {
   661  	result := &Options{
   662  		ClientOptions:   o.ClientOptions,
   663  		InternalOptions: o.InternalOptions,
   664  		Hooks: Hooks{
   665  			GoDiff:        o.Hooks.GoDiff,
   666  			ComputeEdits:  o.Hooks.ComputeEdits,
   667  			GofumptFormat: o.GofumptFormat,
   668  			URLRegexp:     o.URLRegexp,
   669  		},
   670  		ServerOptions: o.ServerOptions,
   671  		UserOptions:   o.UserOptions,
   672  	}
   673  	// Fully clone any slice or map fields. Only Hooks, ExperimentalOptions,
   674  	// and UserOptions can be modified.
   675  	copyStringMap := func(src map[string]bool) map[string]bool {
   676  		dst := make(map[string]bool)
   677  		for k, v := range src {
   678  			dst[k] = v
   679  		}
   680  		return dst
   681  	}
   682  	result.Analyses = copyStringMap(o.Analyses)
   683  	result.Codelenses = copyStringMap(o.Codelenses)
   684  
   685  	copySlice := func(src []string) []string {
   686  		dst := make([]string, len(src))
   687  		copy(dst, src)
   688  		return dst
   689  	}
   690  	result.SetEnvSlice(o.EnvSlice())
   691  	result.BuildFlags = copySlice(o.BuildFlags)
   692  	result.DirectoryFilters = copySlice(o.DirectoryFilters)
   693  
   694  	copyAnalyzerMap := func(src map[string]*Analyzer) map[string]*Analyzer {
   695  		dst := make(map[string]*Analyzer)
   696  		for k, v := range src {
   697  			dst[k] = v
   698  		}
   699  		return dst
   700  	}
   701  	result.DefaultAnalyzers = copyAnalyzerMap(o.DefaultAnalyzers)
   702  	result.TypeErrorAnalyzers = copyAnalyzerMap(o.TypeErrorAnalyzers)
   703  	result.ConvenienceAnalyzers = copyAnalyzerMap(o.ConvenienceAnalyzers)
   704  	result.StaticcheckAnalyzers = copyAnalyzerMap(o.StaticcheckAnalyzers)
   705  	return result
   706  }
   707  
   708  func (o *Options) AddStaticcheckAnalyzer(a *analysis.Analyzer, enabled bool) {
   709  	o.StaticcheckAnalyzers[a.Name] = &Analyzer{Analyzer: a, Enabled: enabled}
   710  }
   711  
   712  // enableAllExperiments turns on all of the experimental "off-by-default"
   713  // features offered by gopls. Any experimental features specified in maps
   714  // should be enabled in enableAllExperimentMaps.
   715  func (o *Options) enableAllExperiments() {
   716  	o.SemanticTokens = true
   717  	o.ExperimentalPostfixCompletions = true
   718  }
   719  
   720  func (o *Options) enableAllExperimentMaps() {
   721  	if _, ok := o.Codelenses[string(command.GCDetails)]; !ok {
   722  		o.Codelenses[string(command.GCDetails)] = true
   723  	}
   724  	if _, ok := o.Analyses[unusedparams.Analyzer.Name]; !ok {
   725  		o.Analyses[unusedparams.Analyzer.Name] = true
   726  	}
   727  }
   728  
   729  func (o *Options) set(name string, value interface{}, seen map[string]struct{}) OptionResult {
   730  	// Flatten the name in case we get options with a hierarchy.
   731  	split := strings.Split(name, ".")
   732  	name = split[len(split)-1]
   733  
   734  	result := OptionResult{Name: name, Value: value}
   735  	if _, ok := seen[name]; ok {
   736  		result.errorf("duplicate configuration for %s", name)
   737  	}
   738  	seen[name] = struct{}{}
   739  
   740  	switch name {
   741  	case "env":
   742  		menv, ok := value.(map[string]interface{})
   743  		if !ok {
   744  			result.errorf("invalid type %T, expect map", value)
   745  			break
   746  		}
   747  		if o.Env == nil {
   748  			o.Env = make(map[string]string)
   749  		}
   750  		for k, v := range menv {
   751  			o.Env[k] = fmt.Sprint(v)
   752  		}
   753  
   754  	case "buildFlags":
   755  		iflags, ok := value.([]interface{})
   756  		if !ok {
   757  			result.errorf("invalid type %T, expect list", value)
   758  			break
   759  		}
   760  		flags := make([]string, 0, len(iflags))
   761  		for _, flag := range iflags {
   762  			flags = append(flags, fmt.Sprintf("%s", flag))
   763  		}
   764  		o.BuildFlags = flags
   765  	case "directoryFilters":
   766  		ifilters, ok := value.([]interface{})
   767  		if !ok {
   768  			result.errorf("invalid type %T, expect list", value)
   769  			break
   770  		}
   771  		var filters []string
   772  		for _, ifilter := range ifilters {
   773  			filter := fmt.Sprint(ifilter)
   774  			if filter[0] != '+' && filter[0] != '-' {
   775  				result.errorf("invalid filter %q, must start with + or -", filter)
   776  				return result
   777  			}
   778  			filters = append(filters, strings.TrimRight(filepath.FromSlash(filter), "/"))
   779  		}
   780  		o.DirectoryFilters = filters
   781  	case "memoryMode":
   782  		if s, ok := result.asOneOf(
   783  			string(ModeNormal),
   784  			string(ModeDegradeClosed),
   785  		); ok {
   786  			o.MemoryMode = MemoryMode(s)
   787  		}
   788  	case "completionDocumentation":
   789  		result.setBool(&o.CompletionDocumentation)
   790  	case "usePlaceholders":
   791  		result.setBool(&o.UsePlaceholders)
   792  	case "deepCompletion":
   793  		result.setBool(&o.DeepCompletion)
   794  	case "completeUnimported":
   795  		result.setBool(&o.CompleteUnimported)
   796  	case "completionBudget":
   797  		result.setDuration(&o.CompletionBudget)
   798  	case "matcher":
   799  		if s, ok := result.asOneOf(
   800  			string(Fuzzy),
   801  			string(CaseSensitive),
   802  			string(CaseInsensitive),
   803  		); ok {
   804  			o.Matcher = Matcher(s)
   805  		}
   806  
   807  	case "symbolMatcher":
   808  		if s, ok := result.asOneOf(
   809  			string(SymbolFuzzy),
   810  			string(SymbolCaseInsensitive),
   811  			string(SymbolCaseSensitive),
   812  		); ok {
   813  			o.SymbolMatcher = SymbolMatcher(s)
   814  		}
   815  
   816  	case "symbolStyle":
   817  		if s, ok := result.asOneOf(
   818  			string(FullyQualifiedSymbols),
   819  			string(PackageQualifiedSymbols),
   820  			string(DynamicSymbols),
   821  		); ok {
   822  			o.SymbolStyle = SymbolStyle(s)
   823  		}
   824  
   825  	case "hoverKind":
   826  		if s, ok := result.asOneOf(
   827  			string(NoDocumentation),
   828  			string(SingleLine),
   829  			string(SynopsisDocumentation),
   830  			string(FullDocumentation),
   831  			string(Structured),
   832  		); ok {
   833  			o.HoverKind = HoverKind(s)
   834  		}
   835  
   836  	case "linkTarget":
   837  		result.setString(&o.LinkTarget)
   838  
   839  	case "linksInHover":
   840  		result.setBool(&o.LinksInHover)
   841  
   842  	case "importShortcut":
   843  		if s, ok := result.asOneOf(string(Both), string(Link), string(Definition)); ok {
   844  			o.ImportShortcut = ImportShortcut(s)
   845  		}
   846  
   847  	case "analyses":
   848  		result.setBoolMap(&o.Analyses)
   849  
   850  	case "annotations":
   851  		result.setAnnotationMap(&o.Annotations)
   852  
   853  	case "codelenses", "codelens":
   854  		var lensOverrides map[string]bool
   855  		result.setBoolMap(&lensOverrides)
   856  		if result.Error == nil {
   857  			if o.Codelenses == nil {
   858  				o.Codelenses = make(map[string]bool)
   859  			}
   860  			for lens, enabled := range lensOverrides {
   861  				o.Codelenses[lens] = enabled
   862  			}
   863  		}
   864  
   865  		// codelens is deprecated, but still works for now.
   866  		// TODO(rstambler): Remove this for the gopls/v0.7.0 release.
   867  		if name == "codelens" {
   868  			result.State = OptionDeprecated
   869  			result.Replacement = "codelenses"
   870  		}
   871  
   872  	case "staticcheck":
   873  		result.setBool(&o.Staticcheck)
   874  
   875  	case "local":
   876  		result.setString(&o.Local)
   877  
   878  	case "verboseOutput":
   879  		result.setBool(&o.VerboseOutput)
   880  
   881  	case "verboseWorkDoneProgress":
   882  		result.setBool(&o.VerboseWorkDoneProgress)
   883  
   884  	case "tempModfile":
   885  		result.setBool(&o.TempModfile)
   886  
   887  	case "gofumpt":
   888  		result.setBool(&o.Gofumpt)
   889  
   890  	case "semanticTokens":
   891  		result.setBool(&o.SemanticTokens)
   892  
   893  	case "expandWorkspaceToModule":
   894  		result.setBool(&o.ExpandWorkspaceToModule)
   895  
   896  	case "experimentalPostfixCompletions":
   897  		result.setBool(&o.ExperimentalPostfixCompletions)
   898  
   899  	case "experimentalWorkspaceModule":
   900  		result.setBool(&o.ExperimentalWorkspaceModule)
   901  
   902  	case "experimentalDiagnosticsDelay":
   903  		result.setDuration(&o.ExperimentalDiagnosticsDelay)
   904  
   905  	case "experimentalPackageCacheKey":
   906  		result.setBool(&o.ExperimentalPackageCacheKey)
   907  
   908  	case "allowModfileModifications":
   909  		result.setBool(&o.AllowModfileModifications)
   910  
   911  	case "allowImplicitNetworkAccess":
   912  		result.setBool(&o.AllowImplicitNetworkAccess)
   913  
   914  	case "allExperiments":
   915  		// This setting should be handled before all of the other options are
   916  		// processed, so do nothing here.
   917  
   918  	// Replaced settings.
   919  	case "experimentalDisabledAnalyses":
   920  		result.State = OptionDeprecated
   921  		result.Replacement = "analyses"
   922  
   923  	case "disableDeepCompletion":
   924  		result.State = OptionDeprecated
   925  		result.Replacement = "deepCompletion"
   926  
   927  	case "disableFuzzyMatching":
   928  		result.State = OptionDeprecated
   929  		result.Replacement = "fuzzyMatching"
   930  
   931  	case "wantCompletionDocumentation":
   932  		result.State = OptionDeprecated
   933  		result.Replacement = "completionDocumentation"
   934  
   935  	case "wantUnimportedCompletions":
   936  		result.State = OptionDeprecated
   937  		result.Replacement = "completeUnimported"
   938  
   939  	case "fuzzyMatching":
   940  		result.State = OptionDeprecated
   941  		result.Replacement = "matcher"
   942  
   943  	case "caseSensitiveCompletion":
   944  		result.State = OptionDeprecated
   945  		result.Replacement = "matcher"
   946  
   947  	// Deprecated settings.
   948  	case "wantSuggestedFixes":
   949  		result.State = OptionDeprecated
   950  
   951  	case "noIncrementalSync":
   952  		result.State = OptionDeprecated
   953  
   954  	case "watchFileChanges":
   955  		result.State = OptionDeprecated
   956  
   957  	case "go-diff":
   958  		result.State = OptionDeprecated
   959  
   960  	default:
   961  		result.State = OptionUnexpected
   962  	}
   963  	return result
   964  }
   965  
   966  func (r *OptionResult) errorf(msg string, values ...interface{}) {
   967  	prefix := fmt.Sprintf("parsing setting %q: ", r.Name)
   968  	r.Error = errors.Errorf(prefix+msg, values...)
   969  }
   970  
   971  func (r *OptionResult) asBool() (bool, bool) {
   972  	b, ok := r.Value.(bool)
   973  	if !ok {
   974  		r.errorf("invalid type %T, expect bool", r.Value)
   975  		return false, false
   976  	}
   977  	return b, true
   978  }
   979  
   980  func (r *OptionResult) setBool(b *bool) {
   981  	if v, ok := r.asBool(); ok {
   982  		*b = v
   983  	}
   984  }
   985  
   986  func (r *OptionResult) setDuration(d *time.Duration) {
   987  	if v, ok := r.asString(); ok {
   988  		parsed, err := time.ParseDuration(v)
   989  		if err != nil {
   990  			r.errorf("failed to parse duration %q: %v", v, err)
   991  			return
   992  		}
   993  		*d = parsed
   994  	}
   995  }
   996  
   997  func (r *OptionResult) setBoolMap(bm *map[string]bool) {
   998  	m := r.asBoolMap()
   999  	*bm = m
  1000  }
  1001  
  1002  func (r *OptionResult) setAnnotationMap(bm *map[Annotation]bool) {
  1003  	all := r.asBoolMap()
  1004  	if all == nil {
  1005  		return
  1006  	}
  1007  	// Default to everything enabled by default.
  1008  	m := make(map[Annotation]bool)
  1009  	for k, enabled := range all {
  1010  		a, err := asOneOf(
  1011  			k,
  1012  			string(Nil),
  1013  			string(Escape),
  1014  			string(Inline),
  1015  			string(Bounds),
  1016  		)
  1017  		if err != nil {
  1018  			// In case of an error, process any legacy values.
  1019  			switch k {
  1020  			case "noEscape":
  1021  				m[Escape] = false
  1022  				r.errorf(`"noEscape" is deprecated, set "Escape: false" instead`)
  1023  			case "noNilcheck":
  1024  				m[Nil] = false
  1025  				r.errorf(`"noNilcheck" is deprecated, set "Nil: false" instead`)
  1026  			case "noInline":
  1027  				m[Inline] = false
  1028  				r.errorf(`"noInline" is deprecated, set "Inline: false" instead`)
  1029  			case "noBounds":
  1030  				m[Bounds] = false
  1031  				r.errorf(`"noBounds" is deprecated, set "Bounds: false" instead`)
  1032  			default:
  1033  				r.errorf(err.Error())
  1034  			}
  1035  			continue
  1036  		}
  1037  		m[Annotation(a)] = enabled
  1038  	}
  1039  	*bm = m
  1040  }
  1041  
  1042  func (r *OptionResult) asBoolMap() map[string]bool {
  1043  	all, ok := r.Value.(map[string]interface{})
  1044  	if !ok {
  1045  		r.errorf("invalid type %T for map[string]bool option", r.Value)
  1046  		return nil
  1047  	}
  1048  	m := make(map[string]bool)
  1049  	for a, enabled := range all {
  1050  		if enabled, ok := enabled.(bool); ok {
  1051  			m[a] = enabled
  1052  		} else {
  1053  			r.errorf("invalid type %T for map key %q", enabled, a)
  1054  			return m
  1055  		}
  1056  	}
  1057  	return m
  1058  }
  1059  
  1060  func (r *OptionResult) asString() (string, bool) {
  1061  	b, ok := r.Value.(string)
  1062  	if !ok {
  1063  		r.errorf("invalid type %T, expect string", r.Value)
  1064  		return "", false
  1065  	}
  1066  	return b, true
  1067  }
  1068  
  1069  func (r *OptionResult) asOneOf(options ...string) (string, bool) {
  1070  	s, ok := r.asString()
  1071  	if !ok {
  1072  		return "", false
  1073  	}
  1074  	s, err := asOneOf(s, options...)
  1075  	if err != nil {
  1076  		r.errorf(err.Error())
  1077  	}
  1078  	return s, err == nil
  1079  }
  1080  
  1081  func asOneOf(str string, options ...string) (string, error) {
  1082  	lower := strings.ToLower(str)
  1083  	for _, opt := range options {
  1084  		if strings.ToLower(opt) == lower {
  1085  			return opt, nil
  1086  		}
  1087  	}
  1088  	return "", fmt.Errorf("invalid option %q for enum", str)
  1089  }
  1090  
  1091  func (r *OptionResult) setString(s *string) {
  1092  	if v, ok := r.asString(); ok {
  1093  		*s = v
  1094  	}
  1095  }
  1096  
  1097  // EnabledAnalyzers returns all of the analyzers enabled for the given
  1098  // snapshot.
  1099  func EnabledAnalyzers(snapshot Snapshot) (analyzers []*Analyzer) {
  1100  	for _, a := range snapshot.View().Options().DefaultAnalyzers {
  1101  		if a.IsEnabled(snapshot.View()) {
  1102  			analyzers = append(analyzers, a)
  1103  		}
  1104  	}
  1105  	for _, a := range snapshot.View().Options().TypeErrorAnalyzers {
  1106  		if a.IsEnabled(snapshot.View()) {
  1107  			analyzers = append(analyzers, a)
  1108  		}
  1109  	}
  1110  	for _, a := range snapshot.View().Options().ConvenienceAnalyzers {
  1111  		if a.IsEnabled(snapshot.View()) {
  1112  			analyzers = append(analyzers, a)
  1113  		}
  1114  	}
  1115  	for _, a := range snapshot.View().Options().StaticcheckAnalyzers {
  1116  		if a.IsEnabled(snapshot.View()) {
  1117  			analyzers = append(analyzers, a)
  1118  		}
  1119  	}
  1120  	return analyzers
  1121  }
  1122  
  1123  func typeErrorAnalyzers() map[string]*Analyzer {
  1124  	return map[string]*Analyzer{
  1125  		fillreturns.Analyzer.Name: {
  1126  			Analyzer:   fillreturns.Analyzer,
  1127  			ActionKind: []protocol.CodeActionKind{protocol.SourceFixAll, protocol.QuickFix},
  1128  			Enabled:    true,
  1129  		},
  1130  		nonewvars.Analyzer.Name: {
  1131  			Analyzer: nonewvars.Analyzer,
  1132  			Enabled:  true,
  1133  		},
  1134  		noresultvalues.Analyzer.Name: {
  1135  			Analyzer: noresultvalues.Analyzer,
  1136  			Enabled:  true,
  1137  		},
  1138  		undeclaredname.Analyzer.Name: {
  1139  			Analyzer: undeclaredname.Analyzer,
  1140  			Fix:      UndeclaredName,
  1141  			Enabled:  true,
  1142  		},
  1143  	}
  1144  }
  1145  
  1146  func convenienceAnalyzers() map[string]*Analyzer {
  1147  	return map[string]*Analyzer{
  1148  		fillstruct.Analyzer.Name: {
  1149  			Analyzer:   fillstruct.Analyzer,
  1150  			Fix:        FillStruct,
  1151  			Enabled:    true,
  1152  			ActionKind: []protocol.CodeActionKind{protocol.RefactorRewrite},
  1153  		},
  1154  	}
  1155  }
  1156  
  1157  func defaultAnalyzers() map[string]*Analyzer {
  1158  	return map[string]*Analyzer{
  1159  		// The traditional vet suite:
  1160  		asmdecl.Analyzer.Name:       {Analyzer: asmdecl.Analyzer, Enabled: true},
  1161  		assign.Analyzer.Name:        {Analyzer: assign.Analyzer, Enabled: true},
  1162  		atomic.Analyzer.Name:        {Analyzer: atomic.Analyzer, Enabled: true},
  1163  		bools.Analyzer.Name:         {Analyzer: bools.Analyzer, Enabled: true},
  1164  		buildtag.Analyzer.Name:      {Analyzer: buildtag.Analyzer, Enabled: true},
  1165  		cgocall.Analyzer.Name:       {Analyzer: cgocall.Analyzer, Enabled: true},
  1166  		composite.Analyzer.Name:     {Analyzer: composite.Analyzer, Enabled: true},
  1167  		copylock.Analyzer.Name:      {Analyzer: copylock.Analyzer, Enabled: true},
  1168  		errorsas.Analyzer.Name:      {Analyzer: errorsas.Analyzer, Enabled: true},
  1169  		httpresponse.Analyzer.Name:  {Analyzer: httpresponse.Analyzer, Enabled: true},
  1170  		ifaceassert.Analyzer.Name:   {Analyzer: ifaceassert.Analyzer, Enabled: true},
  1171  		loopclosure.Analyzer.Name:   {Analyzer: loopclosure.Analyzer, Enabled: true},
  1172  		lostcancel.Analyzer.Name:    {Analyzer: lostcancel.Analyzer, Enabled: true},
  1173  		nilfunc.Analyzer.Name:       {Analyzer: nilfunc.Analyzer, Enabled: true},
  1174  		printf.Analyzer.Name:        {Analyzer: printf.Analyzer, Enabled: true},
  1175  		shift.Analyzer.Name:         {Analyzer: shift.Analyzer, Enabled: true},
  1176  		stdmethods.Analyzer.Name:    {Analyzer: stdmethods.Analyzer, Enabled: true},
  1177  		stringintconv.Analyzer.Name: {Analyzer: stringintconv.Analyzer, Enabled: true},
  1178  		structtag.Analyzer.Name:     {Analyzer: structtag.Analyzer, Enabled: true},
  1179  		tests.Analyzer.Name:         {Analyzer: tests.Analyzer, Enabled: true},
  1180  		unmarshal.Analyzer.Name:     {Analyzer: unmarshal.Analyzer, Enabled: true},
  1181  		unreachable.Analyzer.Name:   {Analyzer: unreachable.Analyzer, Enabled: true},
  1182  		unsafeptr.Analyzer.Name:     {Analyzer: unsafeptr.Analyzer, Enabled: true},
  1183  		unusedresult.Analyzer.Name:  {Analyzer: unusedresult.Analyzer, Enabled: true},
  1184  
  1185  		// Non-vet analyzers:
  1186  		atomicalign.Analyzer.Name:      {Analyzer: atomicalign.Analyzer, Enabled: true},
  1187  		deepequalerrors.Analyzer.Name:  {Analyzer: deepequalerrors.Analyzer, Enabled: true},
  1188  		fieldalignment.Analyzer.Name:   {Analyzer: fieldalignment.Analyzer, Enabled: false},
  1189  		nilness.Analyzer.Name:          {Analyzer: nilness.Analyzer, Enabled: false},
  1190  		shadow.Analyzer.Name:           {Analyzer: shadow.Analyzer, Enabled: false},
  1191  		sortslice.Analyzer.Name:        {Analyzer: sortslice.Analyzer, Enabled: true},
  1192  		testinggoroutine.Analyzer.Name: {Analyzer: testinggoroutine.Analyzer, Enabled: true},
  1193  		unusedparams.Analyzer.Name:     {Analyzer: unusedparams.Analyzer, Enabled: false},
  1194  		unusedwrite.Analyzer.Name:      {Analyzer: unusedwrite.Analyzer, Enabled: false},
  1195  
  1196  		// gofmt -s suite:
  1197  		simplifycompositelit.Analyzer.Name: {
  1198  			Analyzer:   simplifycompositelit.Analyzer,
  1199  			Enabled:    true,
  1200  			ActionKind: []protocol.CodeActionKind{protocol.SourceFixAll, protocol.QuickFix},
  1201  		},
  1202  		simplifyrange.Analyzer.Name: {
  1203  			Analyzer:   simplifyrange.Analyzer,
  1204  			Enabled:    true,
  1205  			ActionKind: []protocol.CodeActionKind{protocol.SourceFixAll, protocol.QuickFix},
  1206  		},
  1207  		simplifyslice.Analyzer.Name: {
  1208  			Analyzer:   simplifyslice.Analyzer,
  1209  			Enabled:    true,
  1210  			ActionKind: []protocol.CodeActionKind{protocol.SourceFixAll, protocol.QuickFix},
  1211  		},
  1212  	}
  1213  }
  1214  
  1215  func urlRegexp() *regexp.Regexp {
  1216  	// Ensure links are matched as full words, not anywhere.
  1217  	re := regexp.MustCompile(`\b(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?\b`)
  1218  	re.Longest()
  1219  	return re
  1220  }
  1221  
  1222  type APIJSON struct {
  1223  	Options   map[string][]*OptionJSON
  1224  	Commands  []*CommandJSON
  1225  	Lenses    []*LensJSON
  1226  	Analyzers []*AnalyzerJSON
  1227  }
  1228  
  1229  type OptionJSON struct {
  1230  	Name       string
  1231  	Type       string
  1232  	Doc        string
  1233  	EnumKeys   EnumKeys
  1234  	EnumValues []EnumValue
  1235  	Default    string
  1236  	Status     string
  1237  	Hierarchy  string
  1238  }
  1239  
  1240  type EnumKeys struct {
  1241  	ValueType string
  1242  	Keys      []EnumKey
  1243  }
  1244  
  1245  type EnumKey struct {
  1246  	Name    string
  1247  	Doc     string
  1248  	Default string
  1249  }
  1250  
  1251  type EnumValue struct {
  1252  	Value string
  1253  	Doc   string
  1254  }
  1255  
  1256  type CommandJSON struct {
  1257  	Command string
  1258  	Title   string
  1259  	Doc     string
  1260  	ArgDoc  string
  1261  }
  1262  
  1263  type LensJSON struct {
  1264  	Lens  string
  1265  	Title string
  1266  	Doc   string
  1267  }
  1268  
  1269  type AnalyzerJSON struct {
  1270  	Name    string
  1271  	Doc     string
  1272  	Default bool
  1273  }