11import {
22 asyncSafety ,
33 type ActionDescriptor ,
4+ type Modifier ,
45 type ScopeType ,
56 type SimpleScopeTypeType ,
67} from "@cursorless/common" ;
@@ -11,9 +12,10 @@ import { endToEndTestSetup } from "../endToEndTestSetup";
1112
1213const testData = generateTestData ( 100 ) ;
1314
14- const textBasedThresholdMs = 100 ;
15- const parseTreeThresholdMs = 500 ;
16- const surroundingPairThresholdMs = 500 ;
15+ const smallThresholdMs = 100 ;
16+ const largeThresholdMs = 500 ;
17+
18+ type ModifierType = "containing" | "previous" | "every" ;
1719
1820suite ( "Performance" , async function ( ) {
1921 endToEndTestSetup ( this ) ;
@@ -32,42 +34,56 @@ suite("Performance", async function () {
3234
3335 test (
3436 "Remove token" ,
35- asyncSafety ( ( ) => removeToken ( textBasedThresholdMs ) ) ,
37+ asyncSafety ( ( ) => removeToken ( smallThresholdMs ) ) ,
3638 ) ;
3739
38- const fixtures : [ SimpleScopeTypeType | ScopeType , number ] [ ] = [
40+ const fixtures : (
41+ | [ SimpleScopeTypeType | ScopeType , number ]
42+ | [ SimpleScopeTypeType | ScopeType , number , ModifierType ]
43+ ) [ ] = [
3944 // Text based
40- [ "character" , textBasedThresholdMs ] ,
41- [ "word" , textBasedThresholdMs ] ,
42- [ "token" , textBasedThresholdMs ] ,
43- [ "identifier" , textBasedThresholdMs ] ,
44- [ "line" , textBasedThresholdMs ] ,
45- [ "sentence" , textBasedThresholdMs ] ,
46- [ "paragraph" , textBasedThresholdMs ] ,
47- [ "document" , textBasedThresholdMs ] ,
48- [ "nonWhitespaceSequence" , textBasedThresholdMs ] ,
49- // Parse tree based
50- [ "string" , parseTreeThresholdMs ] ,
51- [ "map" , parseTreeThresholdMs ] ,
52- [ "collectionKey" , parseTreeThresholdMs ] ,
53- [ "value" , parseTreeThresholdMs ] ,
45+ [ "character" , smallThresholdMs ] ,
46+ [ "word" , smallThresholdMs ] ,
47+ [ "token" , smallThresholdMs ] ,
48+ [ "identifier" , smallThresholdMs ] ,
49+ [ "line" , smallThresholdMs ] ,
50+ [ "sentence" , smallThresholdMs ] ,
51+ [ "paragraph" , smallThresholdMs ] ,
52+ [ "document" , smallThresholdMs ] ,
53+ [ "nonWhitespaceSequence" , smallThresholdMs ] ,
54+ // Parse tree based, containing/every scope
55+ [ "string" , smallThresholdMs ] ,
56+ [ "map" , smallThresholdMs ] ,
57+ [ "collectionKey" , smallThresholdMs ] ,
58+ [ "value" , smallThresholdMs ] ,
59+ [ "collectionKey" , smallThresholdMs , "every" ] ,
60+ [ "value" , smallThresholdMs , "every" ] ,
61+ // Parse tree based, relative scope
62+ [ "collectionKey" , largeThresholdMs , "previous" ] ,
63+ [ "value" , largeThresholdMs , "previous" ] ,
5464 // Text based, but utilizes surrounding pair
55- [ "boundedParagraph" , surroundingPairThresholdMs ] ,
56- [ "boundedNonWhitespaceSequence" , surroundingPairThresholdMs ] ,
57- [ "collectionItem" , surroundingPairThresholdMs ] ,
65+ [ "boundedParagraph" , largeThresholdMs ] ,
66+ [ "boundedNonWhitespaceSequence" , largeThresholdMs ] ,
67+ [ "collectionItem" , largeThresholdMs ] ,
5868 // Surrounding pair
59- [ { type : "surroundingPair" , delimiter : "any" } , surroundingPairThresholdMs ] ,
69+ [ { type : "surroundingPair" , delimiter : "any" } , largeThresholdMs ] ,
70+ [ { type : "surroundingPair" , delimiter : "curlyBrackets" } , largeThresholdMs ] ,
71+ [ { type : "surroundingPair" , delimiter : "any" } , largeThresholdMs , "every" ] ,
6072 [
61- { type : "surroundingPair" , delimiter : "curlyBrackets" } ,
62- surroundingPairThresholdMs ,
73+ { type : "surroundingPair" , delimiter : "any" } ,
74+ largeThresholdMs ,
75+ "previous" ,
6376 ] ,
6477 ] ;
6578
66- for ( const [ scope , threshold ] of fixtures ) {
67- const [ scopeType , title ] = getScopeTypeAndTitle ( scope ) ;
79+ for ( const [ scope , threshold , modifierType ] of fixtures ) {
80+ const [ scopeType , scopeTitle ] = getScopeTypeAndTitle ( scope ) ;
81+ const title = modifierType
82+ ? `${ modifierType } ${ scopeTitle } `
83+ : `${ scopeTitle } ` ;
6884 test (
6985 `Select ${ title } ` ,
70- asyncSafety ( ( ) => selectScopeType ( scopeType , threshold ) ) ,
86+ asyncSafety ( ( ) => selectScopeType ( scopeType , threshold , modifierType ) ) ,
7187 ) ;
7288 }
7389} ) ;
@@ -82,16 +98,40 @@ async function removeToken(thresholdMs: number) {
8298 } ) ;
8399}
84100
85- async function selectScopeType ( scopeType : ScopeType , thresholdMs : number ) {
101+ async function selectScopeType (
102+ scopeType : ScopeType ,
103+ thresholdMs : number ,
104+ modifierType ?: ModifierType ,
105+ ) {
86106 await testPerformance ( thresholdMs , {
87107 name : "setSelection" ,
88108 target : {
89109 type : "primitive" ,
90- modifiers : [ { type : "containingScope" , scopeType } ] ,
110+ modifiers : [ getModifier ( scopeType , modifierType ) ] ,
91111 } ,
92112 } ) ;
93113}
94114
115+ function getModifier (
116+ scopeType : ScopeType ,
117+ modifierType : ModifierType = "containing" ,
118+ ) : Modifier {
119+ switch ( modifierType ) {
120+ case "containing" :
121+ return { type : "containingScope" , scopeType } ;
122+ case "every" :
123+ return { type : "everyScope" , scopeType } ;
124+ case "previous" :
125+ return {
126+ type : "relativeScope" ,
127+ direction : "backward" ,
128+ offset : 1 ,
129+ length : 1 ,
130+ scopeType,
131+ } ;
132+ }
133+ }
134+
95135async function testPerformance ( thresholdMs : number , action : ActionDescriptor ) {
96136 const editor = await openNewEditor ( testData , { languageId : "json" } ) ;
97137 // This is the position of the last json key in the document
0 commit comments