internal/lsp/completion: move postfix completions behind option

Move postfix completion functionality behind an experimental option
flag. For now users can enable it by setting
"experimentalPostfixCompletions" or "allExperiments".

I added a RunnerOption so regtest tests can tweak *source.Options. I
didn't refactor the "Experimental" mode to use the new RunnerOption
because I didn't fully understand its purpose.

Change-Id: I75ed748710cae7fa99f4ea6ea117ce245a4e9749
Reviewed-on: https://go-review.googlesource.com/c/tools/+/296109
Run-TryBot: Muir Manders <muir@mnd.rs>
gopls-CI: kokoro <noreply+kokoro@google.com>
Trust: Heschi Kreinick <heschi@google.com>
Trust: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/source/api_json.go b/internal/lsp/source/api_json.go
index 5a91a59..a106c61 100755
--- a/internal/lsp/source/api_json.go
+++ b/internal/lsp/source/api_json.go
@@ -222,6 +222,19 @@
 				Hierarchy: "ui.completion",
 			},
 			{
+				Name: "experimentalPostfixCompletions",
+				Type: "bool",
+				Doc:  "experimentalPostfixCompletions enables artifical method snippets\nsuch as \"someSlice.sort!\".\n",
+				EnumKeys: EnumKeys{
+					ValueType: "",
+					Keys:      nil,
+				},
+				EnumValues: nil,
+				Default:    "false",
+				Status:     "experimental",
+				Hierarchy:  "ui.completion",
+			},
+			{
 				Name: "importShortcut",
 				Type: "enum",
 				Doc:  "importShortcut specifies whether import statements should link to\ndocumentation or go to definitions.\n",
diff --git a/internal/lsp/source/completion/completion.go b/internal/lsp/source/completion/completion.go
index 0ed474f..8864081 100644
--- a/internal/lsp/source/completion/completion.go
+++ b/internal/lsp/source/completion/completion.go
@@ -522,7 +522,7 @@
 			literal:           opts.LiteralCompletions && opts.InsertTextFormat == protocol.SnippetTextFormat,
 			budget:            opts.CompletionBudget,
 			snippets:          opts.InsertTextFormat == protocol.SnippetTextFormat,
-			postfix:           opts.PostfixCompletions,
+			postfix:           opts.ExperimentalPostfixCompletions,
 		},
 		// default to a matcher that always matches
 		matcher:        prefixMatcher(""),
diff --git a/internal/lsp/source/options.go b/internal/lsp/source/options.go
index 49936a0..826faa6 100644
--- a/internal/lsp/source/options.go
+++ b/internal/lsp/source/options.go
@@ -129,8 +129,9 @@
 						SymbolStyle:    DynamicSymbols,
 					},
 					CompletionOptions: CompletionOptions{
-						Matcher:          Fuzzy,
-						CompletionBudget: 100 * time.Millisecond,
+						Matcher:                        Fuzzy,
+						CompletionBudget:               100 * time.Millisecond,
+						ExperimentalPostfixCompletions: false,
 					},
 					Codelenses: map[string]bool{
 						string(command.Generate):          true,
@@ -144,7 +145,6 @@
 			},
 			InternalOptions: InternalOptions{
 				LiteralCompletions:      true,
-				PostfixCompletions:      true,
 				TempModfile:             true,
 				CompleteUnimported:      true,
 				CompletionDocumentation: true,
@@ -294,6 +294,10 @@
 	// Matcher sets the algorithm that is used when calculating completion
 	// candidates.
 	Matcher Matcher `status:"advanced"`
+
+	// ExperimentalPostfixCompletions enables artifical method snippets
+	// such as "someSlice.sort!".
+	ExperimentalPostfixCompletions bool `status:"experimental"`
 }
 
 type DocumentationOptions struct {
@@ -437,11 +441,6 @@
 	// their expected values.
 	LiteralCompletions bool
 
-	// PostfixCompletions enables pseudo method snippets such as
-	// "someSlice.sort!". Tests disable this flag to simplify their
-	// expected values.
-	PostfixCompletions bool
-
 	// VerboseWorkDoneProgress controls whether the LSP server should send
 	// progress reports for all work done outside the scope of an RPC.
 	// Used by the regression tests.
@@ -687,6 +686,7 @@
 // should be enabled in enableAllExperimentMaps.
 func (o *Options) enableAllExperiments() {
 	o.SemanticTokens = true
+	o.ExperimentalPostfixCompletions = true
 }
 
 func (o *Options) enableAllExperimentMaps() {
@@ -858,6 +858,9 @@
 	case "expandWorkspaceToModule":
 		result.setBool(&o.ExpandWorkspaceToModule)
 
+	case "experimentalPostfixCompletions":
+		result.setBool(&o.ExperimentalPostfixCompletions)
+
 	case "experimentalWorkspaceModule":
 		result.setBool(&o.ExperimentalWorkspaceModule)
 
diff --git a/internal/lsp/source/source_test.go b/internal/lsp/source/source_test.go
index b08c570..23df0c5 100644
--- a/internal/lsp/source/source_test.go
+++ b/internal/lsp/source/source_test.go
@@ -178,7 +178,7 @@
 		opts.CompleteUnimported = false
 		opts.InsertTextFormat = protocol.SnippetTextFormat
 		opts.LiteralCompletions = strings.Contains(string(src.URI()), "literal")
-		opts.PostfixCompletions = strings.Contains(string(src.URI()), "postfix")
+		opts.ExperimentalPostfixCompletions = strings.Contains(string(src.URI()), "postfix")
 	})
 	got = tests.FilterBuiltins(src, got)
 	if diff := tests.DiffCompletionItems(want, got); diff != "" {
@@ -277,7 +277,7 @@
 	_, got := r.callCompletion(t, src, func(opts *source.Options) {
 		opts.DeepCompletion = true
 		opts.Matcher = source.Fuzzy
-		opts.PostfixCompletions = true
+		opts.ExperimentalPostfixCompletions = true
 	})
 	if msg := tests.CheckCompletionOrder(want, got, true); msg != "" {
 		t.Errorf("%s: %s", src, msg)
@@ -931,6 +931,7 @@
 
 // These are pure LSP features, no source level functionality to be tested.
 func (r *runner) Link(t *testing.T, uri span.URI, wantLinks []tests.Link) {}
+
 func (r *runner) SuggestedFix(t *testing.T, spn span.Span, actionKinds []string, expectedActions int) {
 }
 func (r *runner) FunctionExtraction(t *testing.T, start span.Span, end span.Span) {}