diff --git a/data/playground/go/funcs.go b/data/playground/go/funcs.go new file mode 100644 index 0000000000..f90860a3d1 --- /dev/null +++ b/data/playground/go/funcs.go @@ -0,0 +1,29 @@ +package p + +func plainOldFunction() { + go func() { + // anonymous function + }() + _ = func() string { + return "x" + } +} + +func genericFunction[T int | int64](x T) T { + if x == 0 { + panic("zero") + } + return x +} + +func (a A) method() { + defer func() { + recover() + }() + []func(){ + func() { panic(0) }, + func() { panic(1) }, + }[a[0].(int)]() +} + +func stub() string diff --git a/packages/cursorless-engine/src/languages/go.ts b/packages/cursorless-engine/src/languages/go.ts index 010261b5f5..208d16e222 100644 --- a/packages/cursorless-engine/src/languages/go.ts +++ b/packages/cursorless-engine/src/languages/go.ts @@ -14,7 +14,6 @@ const nodeMatchers: Partial< ifStatement: "if_statement", functionCall: ["call_expression", "composite_literal"], functionCallee: ["call_expression[function]", "composite_literal[type]"], - namedFunction: ["function_declaration", "method_declaration"], type: [ "pointer_type", "qualified_type", @@ -22,8 +21,6 @@ const nodeMatchers: Partial< "function_declaration[result]", "method_declaration[result]", ], - functionName: ["function_declaration[name]", "method_declaration[name]"], - anonymousFunction: "func_literal", condition: conditionMatcher("*[condition]"), argumentOrParameter: cascadingMatcher( argumentMatcher("argument_list", "parameter_list"), diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunk.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunk.yml new file mode 100644 index 0000000000..0920f68c35 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunk.yml @@ -0,0 +1,23 @@ +languageId: go +command: + version: 6 + spokenForm: change funk + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: namedFunction} + usePrePhraseSnapshot: true +initialState: + documentContents: _ = func() { /* body */ } + selections: + - anchor: {line: 0, character: 25} + active: {line: 0, character: 25} + marks: {} +finalState: + documentContents: "_ = " + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkAir.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkAir.yml new file mode 100644 index 0000000000..3b54dbb4e7 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkAir.yml @@ -0,0 +1,27 @@ +languageId: go +command: + version: 6 + spokenForm: change funk air + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: namedFunction} + mark: {type: decoratedSymbol, symbolColor: default, character: a} + usePrePhraseSnapshot: true +initialState: + documentContents: func f[X any]() { /* body */ } + selections: + - anchor: {line: 0, character: 30} + active: {line: 0, character: 30} + marks: + default.a: + start: {line: 0, character: 9} + end: {line: 0, character: 12} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkBat.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkBat.yml new file mode 100644 index 0000000000..02c540e4a9 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkBat.yml @@ -0,0 +1,27 @@ +languageId: go +command: + version: 6 + spokenForm: change funk bat + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: namedFunction} + mark: {type: decoratedSymbol, symbolColor: default, character: b} + usePrePhraseSnapshot: true +initialState: + documentContents: func f() { /* body */ } + selections: + - anchor: {line: 0, character: 18} + active: {line: 0, character: 18} + marks: + default.b: + start: {line: 0, character: 14} + end: {line: 0, character: 18} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkBat2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkBat2.yml new file mode 100644 index 0000000000..f9971d700f --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkBat2.yml @@ -0,0 +1,27 @@ +languageId: go +command: + version: 6 + spokenForm: change funk bat + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: namedFunction} + mark: {type: decoratedSymbol, symbolColor: default, character: b} + usePrePhraseSnapshot: true +initialState: + documentContents: func (t T) f() { /* body */ } + selections: + - anchor: {line: 0, character: 29} + active: {line: 0, character: 29} + marks: + default.b: + start: {line: 0, character: 20} + end: {line: 0, character: 24} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkFine.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkFine.yml new file mode 100644 index 0000000000..66d21d30b0 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkFine.yml @@ -0,0 +1,27 @@ +languageId: go +command: + version: 6 + spokenForm: change funk fine + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: namedFunction} + mark: {type: decoratedSymbol, symbolColor: default, character: f} + usePrePhraseSnapshot: true +initialState: + documentContents: func f() { /* body */ } + selections: + - anchor: {line: 0, character: 18} + active: {line: 0, character: 18} + marks: + default.f: + start: {line: 0, character: 5} + end: {line: 0, character: 6} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkFine2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkFine2.yml new file mode 100644 index 0000000000..474df5384e --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkFine2.yml @@ -0,0 +1,27 @@ +languageId: go +command: + version: 6 + spokenForm: change funk fine + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: namedFunction} + mark: {type: decoratedSymbol, symbolColor: default, character: f} + usePrePhraseSnapshot: true +initialState: + documentContents: func (t T) f() { /* body */ } + selections: + - anchor: {line: 0, character: 29} + active: {line: 0, character: 29} + marks: + default.f: + start: {line: 0, character: 11} + end: {line: 0, character: 12} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkFine3.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkFine3.yml new file mode 100644 index 0000000000..1171de1198 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkFine3.yml @@ -0,0 +1,27 @@ +languageId: go +command: + version: 6 + spokenForm: change funk fine + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: namedFunction} + mark: {type: decoratedSymbol, symbolColor: default, character: f} + usePrePhraseSnapshot: true +initialState: + documentContents: func f() + selections: + - anchor: {line: 0, character: 8} + active: {line: 0, character: 8} + marks: + default.f: + start: {line: 0, character: 5} + end: {line: 0, character: 6} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkNameBat.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkNameBat.yml new file mode 100644 index 0000000000..31551919b6 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkNameBat.yml @@ -0,0 +1,27 @@ +languageId: go +command: + version: 6 + spokenForm: change funk name bat + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: functionName} + mark: {type: decoratedSymbol, symbolColor: default, character: b} + usePrePhraseSnapshot: true +initialState: + documentContents: func f() { /* body */ } + selections: + - anchor: {line: 0, character: 18} + active: {line: 0, character: 18} + marks: + default.b: + start: {line: 0, character: 14} + end: {line: 0, character: 18} +finalState: + documentContents: func () { /* body */ } + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkNameFine.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkNameFine.yml new file mode 100644 index 0000000000..7f78ebbf65 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkNameFine.yml @@ -0,0 +1,27 @@ +languageId: go +command: + version: 6 + spokenForm: change funk name fine + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: functionName} + mark: {type: decoratedSymbol, symbolColor: default, character: f} + usePrePhraseSnapshot: true +initialState: + documentContents: func f() { /* body */ } + selections: + - anchor: {line: 0, character: 18} + active: {line: 0, character: 18} + marks: + default.f: + start: {line: 0, character: 5} + end: {line: 0, character: 6} +finalState: + documentContents: func () { /* body */ } + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkTrap.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkTrap.yml new file mode 100644 index 0000000000..5bc5fe4a53 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeFunkTrap.yml @@ -0,0 +1,27 @@ +languageId: go +command: + version: 6 + spokenForm: change funk trap + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: namedFunction} + mark: {type: decoratedSymbol, symbolColor: default, character: t} + usePrePhraseSnapshot: true +initialState: + documentContents: func (t T) f() { /* body */ } + selections: + - anchor: {line: 0, character: 29} + active: {line: 0, character: 29} + marks: + default.t: + start: {line: 0, character: 8} + end: {line: 0, character: 9} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideFunk.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideFunk.yml new file mode 100644 index 0000000000..d9f780d1ef --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideFunk.yml @@ -0,0 +1,24 @@ +languageId: go +command: + version: 6 + spokenForm: change inside funk + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - {type: interiorOnly} + - type: containingScope + scopeType: {type: namedFunction} + usePrePhraseSnapshot: true +initialState: + documentContents: "func (t T) f() {\n\t_ = 1\n}" + selections: + - anchor: {line: 1, character: 6} + active: {line: 1, character: 6} + marks: {} +finalState: + documentContents: "func (t T) f() {\n\t\n}" + selections: + - anchor: {line: 1, character: 1} + active: {line: 1, character: 1} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideFunkBat.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideFunkBat.yml new file mode 100644 index 0000000000..163861e1c7 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideFunkBat.yml @@ -0,0 +1,28 @@ +languageId: go +command: + version: 6 + spokenForm: change inside funk bat + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - {type: interiorOnly} + - type: containingScope + scopeType: {type: namedFunction} + mark: {type: decoratedSymbol, symbolColor: default, character: b} + usePrePhraseSnapshot: true +initialState: + documentContents: func f() { /* body */ } + selections: + - anchor: {line: 0, character: 18} + active: {line: 0, character: 18} + marks: + default.b: + start: {line: 0, character: 14} + end: {line: 0, character: 18} +finalState: + documentContents: func f() { } + selections: + - anchor: {line: 0, character: 11} + active: {line: 0, character: 11} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideFunkBrace.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideFunkBrace.yml new file mode 100644 index 0000000000..6cd1ecf90e --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideFunkBrace.yml @@ -0,0 +1,28 @@ +languageId: go +command: + version: 6 + spokenForm: change inside funk brace + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - {type: interiorOnly} + - type: containingScope + scopeType: {type: namedFunction} + mark: {type: decoratedSymbol, symbolColor: default, character: '{'} + usePrePhraseSnapshot: true +initialState: + documentContents: "func f() {\n\t_ = 1\n}" + selections: + - anchor: {line: 2, character: 1} + active: {line: 2, character: 1} + marks: + default.{: + start: {line: 0, character: 9} + end: {line: 0, character: 10} +finalState: + documentContents: "func f() {\n\t\n}" + selections: + - anchor: {line: 1, character: 1} + active: {line: 1, character: 1} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideFunkFine.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideFunkFine.yml new file mode 100644 index 0000000000..552e7c97e9 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideFunkFine.yml @@ -0,0 +1,28 @@ +languageId: go +command: + version: 6 + spokenForm: change inside funk fine + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - {type: interiorOnly} + - type: containingScope + scopeType: {type: namedFunction} + mark: {type: decoratedSymbol, symbolColor: default, character: f} + usePrePhraseSnapshot: true +initialState: + documentContents: func (t T) f() { /* body */ } + selections: + - anchor: {line: 0, character: 29} + active: {line: 0, character: 29} + marks: + default.f: + start: {line: 0, character: 11} + end: {line: 0, character: 12} +finalState: + documentContents: func (t T) f() { } + selections: + - anchor: {line: 0, character: 17} + active: {line: 0, character: 17} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideLambda.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideLambda.yml new file mode 100644 index 0000000000..20f013e233 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideLambda.yml @@ -0,0 +1,24 @@ +languageId: go +command: + version: 6 + spokenForm: change inside lambda + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - {type: interiorOnly} + - type: containingScope + scopeType: {type: anonymousFunction} + usePrePhraseSnapshot: true +initialState: + documentContents: _ = func() { _ = 1 } + selections: + - anchor: {line: 0, character: 19} + active: {line: 0, character: 19} + marks: {} +finalState: + documentContents: _ = func() { } + selections: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 13} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideLambdaBat.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideLambdaBat.yml new file mode 100644 index 0000000000..1fa735bea3 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeInsideLambdaBat.yml @@ -0,0 +1,28 @@ +languageId: go +command: + version: 6 + spokenForm: change inside lambda bat + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - {type: interiorOnly} + - type: containingScope + scopeType: {type: anonymousFunction} + mark: {type: decoratedSymbol, symbolColor: default, character: b} + usePrePhraseSnapshot: true +initialState: + documentContents: _ = func() { /* body */ } + selections: + - anchor: {line: 0, character: 25} + active: {line: 0, character: 25} + marks: + default.b: + start: {line: 0, character: 16} + end: {line: 0, character: 20} +finalState: + documentContents: _ = func() { } + selections: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 13} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeLambdaBat.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeLambdaBat.yml new file mode 100644 index 0000000000..5b3598b4ad --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeLambdaBat.yml @@ -0,0 +1,27 @@ +languageId: go +command: + version: 6 + spokenForm: change lambda bat + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: anonymousFunction} + mark: {type: decoratedSymbol, symbolColor: default, character: b} + usePrePhraseSnapshot: true +initialState: + documentContents: _ = func() { /* body */ } + selections: + - anchor: {line: 0, character: 25} + active: {line: 0, character: 25} + marks: + default.b: + start: {line: 0, character: 16} + end: {line: 0, character: 20} +finalState: + documentContents: "_ = " + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeLambdaFine.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeLambdaFine.yml new file mode 100644 index 0000000000..c2dc15a907 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/go/changeLambdaFine.yml @@ -0,0 +1,27 @@ +languageId: go +command: + version: 6 + spokenForm: change lambda fine + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: anonymousFunction} + mark: {type: decoratedSymbol, symbolColor: default, character: f} + usePrePhraseSnapshot: true +initialState: + documentContents: _ = func() { /* body */ } + selections: + - anchor: {line: 0, character: 25} + active: {line: 0, character: 25} + marks: + default.f: + start: {line: 0, character: 4} + end: {line: 0, character: 8} +finalState: + documentContents: "_ = " + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} diff --git a/queries/go.scm b/queries/go.scm index 5f0def6b41..1f71bde6f5 100644 --- a/queries/go.scm +++ b/queries/go.scm @@ -184,3 +184,41 @@ ) @list @map (#not-parent-type? @list composite_literal) ) + +;; Functions + +;; function declaration, generic function declaration, function stub +;; func foo() {} +;; func foo[]() {} +;; func foo() +(function_declaration + name: (_) @functionName + body: (block + . + "{" @namedFunction.interior.start.endOf + "}" @namedFunction.interior.end.startOf + . + )? +) @namedFunction @functionName.domain + +;; method declaration +;; func (X) foo() {} +(method_declaration + name: (_) @functionName + body: (block + . + "{" @namedFunction.interior.start.endOf + "}" @namedFunction.interior.end.startOf + . + ) +) @namedFunction @functionName.domain + +;; func literal +(func_literal + body: (block + . + "{" @anonymousFunction.interior.start.endOf @namedFunction.interior.start.endOf + "}" @anonymousFunction.interior.end.startOf @namedFunction.interior.end.startOf + . + ) +) @anonymousFunction @namedFunction