diff --git a/data/fixtures/scopes/c/functionCall.chain.scope b/data/fixtures/scopes/c/functionCall.chain.scope new file mode 100644 index 0000000000..6297108ea1 --- /dev/null +++ b/data/fixtures/scopes/c/functionCall.chain.scope @@ -0,0 +1,19 @@ +foo().bar(); +--- + +[#1 Content] = +[#1 Removal] = +[#1 Domain] = 0:0-0:5 + >-----< +0| foo().bar(); + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = +[#2 Domain] = 0:0-0:11 + >-----------< +0| foo().bar(); + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/c/functionCallee.chain.scope b/data/fixtures/scopes/c/functionCallee.chain.scope new file mode 100644 index 0000000000..b4a1e073a1 --- /dev/null +++ b/data/fixtures/scopes/c/functionCallee.chain.scope @@ -0,0 +1,25 @@ +foo().bar(); +--- + +[#1 Content] = +[#1 Removal] = 0:0-0:3 + >---< +0| foo().bar(); + +[#1 Domain] = 0:0-0:5 + >-----< +0| foo().bar(); + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = 0:0-0:9 + >---------< +0| foo().bar(); + +[#2 Domain] = 0:0-0:11 + >-----------< +0| foo().bar(); + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/csharp/functionCall.chain.scope b/data/fixtures/scopes/csharp/functionCall.chain.scope new file mode 100644 index 0000000000..979d301b16 --- /dev/null +++ b/data/fixtures/scopes/csharp/functionCall.chain.scope @@ -0,0 +1,19 @@ +Foo().Bar(); +--- + +[#1 Content] = +[#1 Removal] = +[#1 Domain] = 0:0-0:5 + >-----< +0| Foo().Bar(); + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = +[#2 Domain] = 0:0-0:11 + >-----------< +0| Foo().Bar(); + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/csharp/functionCallee.chain.scope b/data/fixtures/scopes/csharp/functionCallee.chain.scope new file mode 100644 index 0000000000..640b71bf60 --- /dev/null +++ b/data/fixtures/scopes/csharp/functionCallee.chain.scope @@ -0,0 +1,25 @@ +Foo().Bar(); +--- + +[#1 Content] = +[#1 Removal] = 0:0-0:3 + >---< +0| Foo().Bar(); + +[#1 Domain] = 0:0-0:5 + >-----< +0| Foo().Bar(); + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = 0:0-0:9 + >---------< +0| Foo().Bar(); + +[#2 Domain] = 0:0-0:11 + >-----------< +0| Foo().Bar(); + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/csharp/functionCallee.method.scope b/data/fixtures/scopes/csharp/functionCallee.method.scope index f30f0f7536..2d5d171438 100644 --- a/data/fixtures/scopes/csharp/functionCallee.method.scope +++ b/data/fixtures/scopes/csharp/functionCallee.method.scope @@ -1,13 +1,13 @@ -foo.bar(); +Foo.Bar(); --- [Content] = [Removal] = 0:0-0:7 >-------< -0| foo.bar(); +0| Foo.Bar(); [Domain] = 0:0-0:9 >---------< -0| foo.bar(); +0| Foo.Bar(); [Insertion delimiter] = " " diff --git a/data/fixtures/scopes/csharp/functionCallee.scope b/data/fixtures/scopes/csharp/functionCallee.scope index 3071a48ae9..252e7fe961 100644 --- a/data/fixtures/scopes/csharp/functionCallee.scope +++ b/data/fixtures/scopes/csharp/functionCallee.scope @@ -1,13 +1,13 @@ -foo(); +Foo(); --- [Content] = [Removal] = 0:0-0:3 >---< -0| foo(); +0| Foo(); [Domain] = 0:0-0:5 >-----< -0| foo(); +0| Foo(); [Insertion delimiter] = " " diff --git a/data/fixtures/scopes/java/functionCall.chain.scope b/data/fixtures/scopes/java/functionCall.chain.scope new file mode 100644 index 0000000000..6297108ea1 --- /dev/null +++ b/data/fixtures/scopes/java/functionCall.chain.scope @@ -0,0 +1,19 @@ +foo().bar(); +--- + +[#1 Content] = +[#1 Removal] = +[#1 Domain] = 0:0-0:5 + >-----< +0| foo().bar(); + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = +[#2 Domain] = 0:0-0:11 + >-----------< +0| foo().bar(); + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/java/functionCallee.chain.scope b/data/fixtures/scopes/java/functionCallee.chain.scope new file mode 100644 index 0000000000..b4a1e073a1 --- /dev/null +++ b/data/fixtures/scopes/java/functionCallee.chain.scope @@ -0,0 +1,25 @@ +foo().bar(); +--- + +[#1 Content] = +[#1 Removal] = 0:0-0:3 + >---< +0| foo().bar(); + +[#1 Domain] = 0:0-0:5 + >-----< +0| foo().bar(); + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = 0:0-0:9 + >---------< +0| foo().bar(); + +[#2 Domain] = 0:0-0:11 + >-----------< +0| foo().bar(); + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/javascript.core/functionCall.chain.scope b/data/fixtures/scopes/javascript.core/functionCall.chain.scope new file mode 100644 index 0000000000..6297108ea1 --- /dev/null +++ b/data/fixtures/scopes/javascript.core/functionCall.chain.scope @@ -0,0 +1,19 @@ +foo().bar(); +--- + +[#1 Content] = +[#1 Removal] = +[#1 Domain] = 0:0-0:5 + >-----< +0| foo().bar(); + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = +[#2 Domain] = 0:0-0:11 + >-----------< +0| foo().bar(); + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/javascript.core/functionCallee.chain.scope b/data/fixtures/scopes/javascript.core/functionCallee.chain.scope new file mode 100644 index 0000000000..b4a1e073a1 --- /dev/null +++ b/data/fixtures/scopes/javascript.core/functionCallee.chain.scope @@ -0,0 +1,25 @@ +foo().bar(); +--- + +[#1 Content] = +[#1 Removal] = 0:0-0:3 + >---< +0| foo().bar(); + +[#1 Domain] = 0:0-0:5 + >-----< +0| foo().bar(); + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = 0:0-0:9 + >---------< +0| foo().bar(); + +[#2 Domain] = 0:0-0:11 + >-----------< +0| foo().bar(); + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/lua/functionCall.chain.scope b/data/fixtures/scopes/lua/functionCall.chain.scope new file mode 100644 index 0000000000..c73434c70d --- /dev/null +++ b/data/fixtures/scopes/lua/functionCall.chain.scope @@ -0,0 +1,19 @@ +foo().bar() +--- + +[#1 Content] = +[#1 Removal] = +[#1 Domain] = 0:0-0:5 + >-----< +0| foo().bar() + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = +[#2 Domain] = 0:0-0:11 + >-----------< +0| foo().bar() + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/lua/functionCall.chain2.scope b/data/fixtures/scopes/lua/functionCall.chain2.scope new file mode 100644 index 0000000000..7e87ac4c3b --- /dev/null +++ b/data/fixtures/scopes/lua/functionCall.chain2.scope @@ -0,0 +1,19 @@ +foo():bar() +--- + +[#1 Content] = +[#1 Removal] = +[#1 Domain] = 0:0-0:5 + >-----< +0| foo():bar() + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = +[#2 Domain] = 0:0-0:11 + >-----------< +0| foo():bar() + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/lua/functionCallee.chain.scope b/data/fixtures/scopes/lua/functionCallee.chain.scope new file mode 100644 index 0000000000..b0b9872650 --- /dev/null +++ b/data/fixtures/scopes/lua/functionCallee.chain.scope @@ -0,0 +1,25 @@ +foo().bar() +--- + +[#1 Content] = +[#1 Removal] = 0:0-0:3 + >---< +0| foo().bar() + +[#1 Domain] = 0:0-0:5 + >-----< +0| foo().bar() + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = 0:0-0:9 + >---------< +0| foo().bar() + +[#2 Domain] = 0:0-0:11 + >-----------< +0| foo().bar() + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/lua/functionCallee.chain2.scope b/data/fixtures/scopes/lua/functionCallee.chain2.scope new file mode 100644 index 0000000000..da8ae230c1 --- /dev/null +++ b/data/fixtures/scopes/lua/functionCallee.chain2.scope @@ -0,0 +1,25 @@ +foo():bar() +--- + +[#1 Content] = +[#1 Removal] = 0:0-0:3 + >---< +0| foo():bar() + +[#1 Domain] = 0:0-0:5 + >-----< +0| foo():bar() + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = 0:0-0:9 + >---------< +0| foo():bar() + +[#2 Domain] = 0:0-0:11 + >-----------< +0| foo():bar() + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/python/functionCall.chain.scope b/data/fixtures/scopes/python/functionCall.chain.scope new file mode 100644 index 0000000000..c73434c70d --- /dev/null +++ b/data/fixtures/scopes/python/functionCall.chain.scope @@ -0,0 +1,19 @@ +foo().bar() +--- + +[#1 Content] = +[#1 Removal] = +[#1 Domain] = 0:0-0:5 + >-----< +0| foo().bar() + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = +[#2 Domain] = 0:0-0:11 + >-----------< +0| foo().bar() + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/python/functionCallee.chain.scope b/data/fixtures/scopes/python/functionCallee.chain.scope new file mode 100644 index 0000000000..b0b9872650 --- /dev/null +++ b/data/fixtures/scopes/python/functionCallee.chain.scope @@ -0,0 +1,25 @@ +foo().bar() +--- + +[#1 Content] = +[#1 Removal] = 0:0-0:3 + >---< +0| foo().bar() + +[#1 Domain] = 0:0-0:5 + >-----< +0| foo().bar() + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = 0:0-0:9 + >---------< +0| foo().bar() + +[#2 Domain] = 0:0-0:11 + >-----------< +0| foo().bar() + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/r/functionCall.chain.scope b/data/fixtures/scopes/r/functionCall.chain.scope new file mode 100644 index 0000000000..c73434c70d --- /dev/null +++ b/data/fixtures/scopes/r/functionCall.chain.scope @@ -0,0 +1,19 @@ +foo().bar() +--- + +[#1 Content] = +[#1 Removal] = +[#1 Domain] = 0:0-0:5 + >-----< +0| foo().bar() + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = +[#2 Domain] = 0:0-0:11 + >-----------< +0| foo().bar() + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/r/functionCallee.chain.scope b/data/fixtures/scopes/r/functionCallee.chain.scope new file mode 100644 index 0000000000..b0b9872650 --- /dev/null +++ b/data/fixtures/scopes/r/functionCallee.chain.scope @@ -0,0 +1,25 @@ +foo().bar() +--- + +[#1 Content] = +[#1 Removal] = 0:0-0:3 + >---< +0| foo().bar() + +[#1 Domain] = 0:0-0:5 + >-----< +0| foo().bar() + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = 0:0-0:9 + >---------< +0| foo().bar() + +[#2 Domain] = 0:0-0:11 + >-----------< +0| foo().bar() + +[#2 Insertion delimiter] = " " diff --git a/data/scopeSupportFacetInfos.md b/data/scopeSupportFacetInfos.md index 3e78e4b016..c76c69a114 100644 --- a/data/scopeSupportFacetInfos.md +++ b/data/scopeSupportFacetInfos.md @@ -143,12 +143,14 @@ ### functionCall - `functionCall` A function call +- `functionCall.chain` A chain of function calls, eg `foo().bar()` - `functionCall.constructor` A constructor call - `functionCall.method` A method call ### functionCallee - `functionCallee` The function being called in a function call +- `functionCallee.chain` The function being called in a chain of function calls, including parent objects. - `functionCallee.constructor` The class being constructed in a class instantiation, including the `new` keyword. - `functionCallee.method` The function being called in a method call, including parent objects. diff --git a/packages/common/src/scopeSupportFacets/c.ts b/packages/common/src/scopeSupportFacets/c.ts index 944f13664b..c20c7bc6e4 100644 --- a/packages/common/src/scopeSupportFacets/c.ts +++ b/packages/common/src/scopeSupportFacets/c.ts @@ -39,8 +39,10 @@ export const cCoreScopeSupport: LanguageScopeSupportFacetMap = { functionCall: supported, "functionCall.method": supported, + "functionCall.chain": supported, functionCallee: supported, "functionCallee.method": supported, + "functionCallee.chain": supported, "argument.actual.singleLine": supported, "argument.actual.multiLine": supported, diff --git a/packages/common/src/scopeSupportFacets/csharp.ts b/packages/common/src/scopeSupportFacets/csharp.ts index 0d3d64074b..cbaf8f4924 100644 --- a/packages/common/src/scopeSupportFacets/csharp.ts +++ b/packages/common/src/scopeSupportFacets/csharp.ts @@ -20,9 +20,11 @@ export const csharpScopeSupport: LanguageScopeSupportFacetMap = { functionCall: supported, "functionCall.constructor": supported, "functionCall.method": supported, + "functionCall.chain": supported, functionCallee: supported, "functionCallee.constructor": supported, "functionCallee.method": supported, + "functionCallee.chain": supported, namedFunction: supported, "namedFunction.iteration.document": supported, diff --git a/packages/common/src/scopeSupportFacets/css.ts b/packages/common/src/scopeSupportFacets/css.ts index e58f96723d..0ab9014eda 100644 --- a/packages/common/src/scopeSupportFacets/css.ts +++ b/packages/common/src/scopeSupportFacets/css.ts @@ -155,6 +155,10 @@ export const cssScopeSupport: LanguageScopeSupportFacetMap = { "value.return.lambda": notApplicable, "interior.lambda": notApplicable, + // Function call chain + "functionCall.chain": notApplicable, + "functionCallee.chain": notApplicable, + // Keyword argument "name.argument.actual": notApplicable, "name.argument.actual.iteration": notApplicable, diff --git a/packages/common/src/scopeSupportFacets/html.ts b/packages/common/src/scopeSupportFacets/html.ts index dcf81e3748..a78a8bb97e 100644 --- a/packages/common/src/scopeSupportFacets/html.ts +++ b/packages/common/src/scopeSupportFacets/html.ts @@ -135,6 +135,8 @@ export const htmlScopeSupport: LanguageScopeSupportFacetMap = { // Function call functionCall: notApplicable, functionCallee: notApplicable, + "functionCall.chain": notApplicable, + "functionCallee.chain": notApplicable, "argumentList.actual.empty": notApplicable, "argumentList.actual.singleLine": notApplicable, "argumentList.actual.multiLine": notApplicable, diff --git a/packages/common/src/scopeSupportFacets/java.ts b/packages/common/src/scopeSupportFacets/java.ts index 601bd52c74..f6f387a5c2 100644 --- a/packages/common/src/scopeSupportFacets/java.ts +++ b/packages/common/src/scopeSupportFacets/java.ts @@ -79,9 +79,11 @@ export const javaScopeSupport: LanguageScopeSupportFacetMap = { functionCall: supported, "functionCall.constructor": supported, "functionCall.method": supported, + "functionCall.chain": supported, functionCallee: supported, "functionCallee.constructor": supported, "functionCallee.method": supported, + "functionCallee.chain": supported, "namedFunction.constructor": supported, "namedFunction.method": supported, diff --git a/packages/common/src/scopeSupportFacets/javascript.ts b/packages/common/src/scopeSupportFacets/javascript.ts index f7647f4ce6..2dcd0db13e 100644 --- a/packages/common/src/scopeSupportFacets/javascript.ts +++ b/packages/common/src/scopeSupportFacets/javascript.ts @@ -58,9 +58,11 @@ export const javascriptCoreScopeSupport: LanguageScopeSupportFacetMap = { functionCall: supported, "functionCall.constructor": supported, "functionCall.method": supported, + "functionCall.chain": supported, functionCallee: supported, "functionCallee.constructor": supported, "functionCallee.method": supported, + "functionCallee.chain": supported, "argument.actual.singleLine": supported, "argument.actual.multiLine": supported, diff --git a/packages/common/src/scopeSupportFacets/json.ts b/packages/common/src/scopeSupportFacets/json.ts index 637f851562..4045d3d9ac 100644 --- a/packages/common/src/scopeSupportFacets/json.ts +++ b/packages/common/src/scopeSupportFacets/json.ts @@ -138,6 +138,8 @@ export const jsonScopeSupport: LanguageScopeSupportFacetMap = { // Function call functionCall: notApplicable, functionCallee: notApplicable, + "functionCall.chain": notApplicable, + "functionCallee.chain": notApplicable, "argumentList.actual.empty": notApplicable, "argumentList.actual.singleLine": notApplicable, "argumentList.actual.multiLine": notApplicable, diff --git a/packages/common/src/scopeSupportFacets/lua.ts b/packages/common/src/scopeSupportFacets/lua.ts index 8410b459cc..2101dc2f5c 100644 --- a/packages/common/src/scopeSupportFacets/lua.ts +++ b/packages/common/src/scopeSupportFacets/lua.ts @@ -15,8 +15,10 @@ export const luaScopeSupport: LanguageScopeSupportFacetMap = { functionCall: supported, "functionCall.method": supported, + "functionCall.chain": supported, functionCallee: supported, "functionCallee.method": supported, + "functionCallee.chain": supported, "key.attribute": notApplicable, diff --git a/packages/common/src/scopeSupportFacets/markdown.ts b/packages/common/src/scopeSupportFacets/markdown.ts index 5d083c1d28..86e04dbfaa 100644 --- a/packages/common/src/scopeSupportFacets/markdown.ts +++ b/packages/common/src/scopeSupportFacets/markdown.ts @@ -136,6 +136,8 @@ export const markdownScopeSupport: LanguageScopeSupportFacetMap = { // Function call functionCall: notApplicable, functionCallee: notApplicable, + "functionCall.chain": notApplicable, + "functionCallee.chain": notApplicable, "argumentList.actual.empty": notApplicable, "argumentList.actual.singleLine": notApplicable, "argumentList.actual.multiLine": notApplicable, diff --git a/packages/common/src/scopeSupportFacets/python.ts b/packages/common/src/scopeSupportFacets/python.ts index c28fb6a87d..58a17d62bd 100644 --- a/packages/common/src/scopeSupportFacets/python.ts +++ b/packages/common/src/scopeSupportFacets/python.ts @@ -200,9 +200,11 @@ export const pythonScopeSupport: LanguageScopeSupportFacetMap = { functionCall: supported, "functionCall.constructor": supported, "functionCall.method": supported, + "functionCall.chain": supported, functionCallee: supported, "functionCallee.constructor": supported, "functionCallee.method": supported, + "functionCallee.chain": supported, disqualifyDelimiter: supported, pairDelimiter: supported, diff --git a/packages/common/src/scopeSupportFacets/r.ts b/packages/common/src/scopeSupportFacets/r.ts index 75833a1983..2fbf78b394 100644 --- a/packages/common/src/scopeSupportFacets/r.ts +++ b/packages/common/src/scopeSupportFacets/r.ts @@ -27,8 +27,10 @@ export const rScopeSupport: LanguageScopeSupportFacetMap = { functionCall: supported, "functionCall.method": supported, + "functionCall.chain": supported, functionCallee: supported, "functionCallee.method": supported, + "functionCallee.chain": supported, "comment.line": supported, ifStatement: supported, diff --git a/packages/common/src/scopeSupportFacets/scm.ts b/packages/common/src/scopeSupportFacets/scm.ts index a627cd6bb4..289b73d8b8 100644 --- a/packages/common/src/scopeSupportFacets/scm.ts +++ b/packages/common/src/scopeSupportFacets/scm.ts @@ -137,6 +137,10 @@ export const scmScopeSupport: LanguageScopeSupportFacetMap = { "value.return.lambda": notApplicable, "interior.lambda": notApplicable, + // Function call chain + "functionCall.chain": notApplicable, + "functionCallee.chain": notApplicable, + // Keyword argument "name.argument.actual": notApplicable, "name.argument.actual.iteration": notApplicable, diff --git a/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts b/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts index 55fb92433b..daf1940fbc 100644 --- a/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts +++ b/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts @@ -225,6 +225,10 @@ export const scopeSupportFacetInfos: Record< description: "A method call", scopeType: "functionCall", }, + "functionCall.chain": { + description: "A chain of function calls, eg `foo().bar()`", + scopeType: "functionCall", + }, functionCallee: { description: "The function being called in a function call", scopeType: "functionCallee", @@ -239,6 +243,11 @@ export const scopeSupportFacetInfos: Record< "The function being called in a method call, including parent objects.", scopeType: "functionCallee", }, + "functionCallee.chain": { + description: + "The function being called in a chain of function calls, including parent objects.", + scopeType: "functionCallee", + }, "argument.actual.singleLine": { description: "A single line argument in a function call", diff --git a/packages/common/src/scopeSupportFacets/scopeSupportFacets.types.ts b/packages/common/src/scopeSupportFacets/scopeSupportFacets.types.ts index 8513746cb4..1a574409cb 100644 --- a/packages/common/src/scopeSupportFacets/scopeSupportFacets.types.ts +++ b/packages/common/src/scopeSupportFacets/scopeSupportFacets.types.ts @@ -72,9 +72,11 @@ export const scopeSupportFacets = [ "functionCall", "functionCall.constructor", "functionCall.method", + "functionCall.chain", "functionCallee", "functionCallee.constructor", "functionCallee.method", + "functionCallee.chain", "argument.actual.singleLine", "argument.actual.multiLine", diff --git a/packages/common/src/scopeSupportFacets/talon.ts b/packages/common/src/scopeSupportFacets/talon.ts index e7e524e56d..37942c443f 100644 --- a/packages/common/src/scopeSupportFacets/talon.ts +++ b/packages/common/src/scopeSupportFacets/talon.ts @@ -146,6 +146,10 @@ export const talonScopeSupport: LanguageScopeSupportFacetMap = { "argument.actual.multiLine": notApplicable, "argumentList.actual.multiLine": notApplicable, + // Function call chain + "functionCall.chain": notApplicable, + "functionCallee.chain": notApplicable, + // Anonymous function / lambda anonymousFunction: notApplicable, "argumentList.formal.lambda.empty": notApplicable, diff --git a/packages/common/src/scopeSupportFacets/xml.ts b/packages/common/src/scopeSupportFacets/xml.ts index 1b7b88c1c9..17688c761c 100644 --- a/packages/common/src/scopeSupportFacets/xml.ts +++ b/packages/common/src/scopeSupportFacets/xml.ts @@ -135,6 +135,8 @@ export const xmlScopeSupport: LanguageScopeSupportFacetMap = { // Function call functionCall: notApplicable, functionCallee: notApplicable, + "functionCall.chain": notApplicable, + "functionCallee.chain": notApplicable, "argumentList.actual.empty": notApplicable, "argumentList.actual.singleLine": notApplicable, "argumentList.actual.multiLine": notApplicable, diff --git a/packages/common/src/scopeSupportFacets/yaml.ts b/packages/common/src/scopeSupportFacets/yaml.ts index 5ab4c73fb4..1579ce7d3e 100644 --- a/packages/common/src/scopeSupportFacets/yaml.ts +++ b/packages/common/src/scopeSupportFacets/yaml.ts @@ -144,6 +144,8 @@ export const yamlScopeSupport: LanguageScopeSupportFacetMap = { // Function call functionCall: notApplicable, functionCallee: notApplicable, + "functionCall.chain": notApplicable, + "functionCallee.chain": notApplicable, "argumentList.actual.empty": notApplicable, "argumentList.actual.singleLine": notApplicable, "argumentList.actual.multiLine": notApplicable, diff --git a/packages/cursorless-engine/src/languages/TreeSitterQuery/QueryCapture.ts b/packages/cursorless-engine/src/languages/TreeSitterQuery/QueryCapture.ts index 856bfadc15..0c4eba64b9 100644 --- a/packages/cursorless-engine/src/languages/TreeSitterQuery/QueryCapture.ts +++ b/packages/cursorless-engine/src/languages/TreeSitterQuery/QueryCapture.ts @@ -21,6 +21,7 @@ export interface SimpleSyntaxNode { interface SimpleChildSyntaxNode extends SimpleSyntaxNode { readonly startPosition: Point; readonly endPosition: Point; + readonly text: string; } /** diff --git a/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts b/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts index eeac765dae..12e5559a0a 100644 --- a/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts +++ b/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts @@ -1,11 +1,11 @@ -import type { Position } from "@cursorless/common"; -import { Range, adjustPosition } from "@cursorless/common"; +import { Position, Range, adjustPosition } from "@cursorless/common"; +import type { Point } from "web-tree-sitter"; import { z } from "zod"; +import { isEven } from "./isEven"; import { makeRangeFromPositions } from "./makeRangeFromPositions"; +import { q } from "./operatorArgumentSchemaTypes"; import type { MutableQueryCapture } from "./QueryCapture"; import { QueryPredicateOperator } from "./QueryPredicateOperator"; -import { isEven } from "./isEven"; -import { q } from "./operatorArgumentSchemaTypes"; /** * A predicate operator that returns true if the node is at an even index within @@ -226,7 +226,7 @@ class GrowToNamedSiblings extends QueryPredicateOperator { schema = z.union([z.tuple([q.node]), z.tuple([q.node, q.string])]); run(nodeInfo: MutableQueryCapture, notText?: string) { - const { node, range, document } = nodeInfo; + const { node, range } = nodeInfo; if (node.parent == null) { throw Error("Node has no parent"); @@ -234,7 +234,7 @@ class GrowToNamedSiblings extends QueryPredicateOperator { const { children } = node.parent; const nodeIndex = children.findIndex((n) => n.id === node.id); - let endPosition: Position | null = null; + let endPosition: Point | undefined; if (nodeIndex === -1) { throw Error("Node not found in parent"); @@ -245,20 +245,72 @@ class GrowToNamedSiblings extends QueryPredicateOperator { if (!child.isNamed) { break; } - const childRange = makeRangeFromPositions( - child.startPosition, - child.endPosition, - ); - if (notText != null && notText === document.getText(childRange)) { + if (notText != null && notText === child.text) { break; } - endPosition = childRange.end; + endPosition = child.endPosition; } if (endPosition != null) { - nodeInfo.range = new Range(range.start, endPosition); + nodeInfo.range = new Range( + range.start, + new Position(endPosition.row, endPosition.column), + ); + } + + return true; + } +} +/** + * A predicate operator that modifies the range of the match to grow to leading siblings of the same type. + * + * The `leadingSeparator` argument specificies the separator each node except the first sibling will be separated by. + * + * ``` + * (#call-chain! @foo ".") + * ``` + */ +class CallChain extends QueryPredicateOperator { + name = "call-chain!" as const; + schema = z.union([z.tuple([q.node]), z.tuple([q.node, q.string])]); + + run(nodeInfo: MutableQueryCapture, leadingSeparator: string) { + const { node } = nodeInfo; + + if (node.parent == null) { + throw Error("Node has no parent"); + } + + const { children } = node.parent; + const nodeIndex = children.findIndex((n) => n.id === node.id); + + if (nodeIndex === -1) { + throw Error("Node not found in parent"); + } + + let start = children[nodeIndex]; + + for (let i = nodeIndex; i > -1; --i) { + const child = children[i]; + + if (child.type !== node.type) { + break; + } + + start = child; + + if (!child.text.startsWith(leadingSeparator)) { + break; + } + } + + if (start.id !== node.id) { + nodeInfo.range = makeRangeFromPositions( + start.startPosition, + children[nodeIndex].endPosition, + ); } return true; @@ -442,6 +494,7 @@ export const queryPredicateOperators = [ new CharacterRange(), new ShrinkToMatch(), new GrowToNamedSiblings(), + new CallChain(), new AllowMultiple(), new InsertionDelimiter(), new SingleOrMultilineDelimiter(), diff --git a/queries/r.scm b/queries/r.scm index 0de9ecff10..0f37c81fe9 100644 --- a/queries/r.scm +++ b/queries/r.scm @@ -134,22 +134,23 @@ ;; Function calls ;;!! foo() ;;! ^^^^^ -;;! ----- -(call) @functionCall @argumentOrParameter.iteration.domain - -;;!! foo() ;;! ^^^ ;;! ----- -(call - (identifier) @functionCallee -) @_.domain +( + (call + (identifier) @functionCallee.end + ) @functionCall @functionCallee.start.startOf @functionCallee.domain + (#call-chain! @functionCall ".") + (#call-chain! @functionCallee.start.startOf ".") + (#call-chain! @functionCallee.domain ".") +) ;; Technically lists and arrays are just calls to the function `list` or `c` ;;!! list(1, 2, 3) ;;! ^^^^^^^^^^^^^ (call - function: (identifier) @name - (#match? @name "^(c|list)$") + function: (identifier) @_dummy + (#match? @_dummy "^(c|list)$") ) @list (binary_operator