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 = "previous" ;
1719
1820suite ( "Performance" , async function ( ) {
1921 endToEndTestSetup ( this ) ;
@@ -32,42 +34,53 @@ 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 scope
55+ [ "string" , smallThresholdMs ] ,
56+ [ "map" , smallThresholdMs ] ,
57+ [ "collectionKey" , smallThresholdMs ] ,
58+ [ "value" , smallThresholdMs ] ,
59+ // Parse tree based, relative scope
60+ [ "collectionKey" , largeThresholdMs , "previous" ] ,
61+ [ "value" , largeThresholdMs , "previous" ] ,
5462 // Text based, but utilizes surrounding pair
55- [ "boundedParagraph" , surroundingPairThresholdMs ] ,
56- [ "boundedNonWhitespaceSequence" , surroundingPairThresholdMs ] ,
57- [ "collectionItem" , surroundingPairThresholdMs ] ,
63+ [ "boundedParagraph" , largeThresholdMs ] ,
64+ [ "boundedNonWhitespaceSequence" , largeThresholdMs ] ,
65+ [ "collectionItem" , largeThresholdMs ] ,
5866 // Surrounding pair
59- [ { type : "surroundingPair" , delimiter : "any" } , surroundingPairThresholdMs ] ,
67+ [ { type : "surroundingPair" , delimiter : "any" } , largeThresholdMs ] ,
68+ [ { type : "surroundingPair" , delimiter : "curlyBrackets" } , largeThresholdMs ] ,
6069 [
61- { type : "surroundingPair" , delimiter : "curlyBrackets" } ,
62- surroundingPairThresholdMs ,
70+ { type : "surroundingPair" , delimiter : "any" } ,
71+ largeThresholdMs ,
72+ "previous" ,
6373 ] ,
6474 ] ;
6575
66- for ( const [ scope , threshold ] of fixtures ) {
67- const [ scopeType , title ] = getScopeTypeAndTitle ( scope ) ;
76+ for ( const [ scope , threshold , modifierType ] of fixtures ) {
77+ const [ scopeType , scopeTitle ] = getScopeTypeAndTitle ( scope ) ;
78+ const title = modifierType
79+ ? `${ modifierType } ${ scopeTitle } `
80+ : `${ scopeTitle } ` ;
6881 test (
6982 `Select ${ title } ` ,
70- asyncSafety ( ( ) => selectScopeType ( scopeType , threshold ) ) ,
83+ asyncSafety ( ( ) => selectScopeType ( scopeType , threshold , modifierType ) ) ,
7184 ) ;
7285 }
7386} ) ;
@@ -82,16 +95,38 @@ async function removeToken(thresholdMs: number) {
8295 } ) ;
8396}
8497
85- async function selectScopeType ( scopeType : ScopeType , thresholdMs : number ) {
98+ async function selectScopeType (
99+ scopeType : ScopeType ,
100+ thresholdMs : number ,
101+ modifierType ?: ModifierType ,
102+ ) {
86103 await testPerformance ( thresholdMs , {
87104 name : "setSelection" ,
88105 target : {
89106 type : "primitive" ,
90- modifiers : [ { type : "containingScope" , scopeType } ] ,
107+ modifiers : [ getModifier ( scopeType , modifierType ) ] ,
91108 } ,
92109 } ) ;
93110}
94111
112+ function getModifier (
113+ scopeType : ScopeType ,
114+ modifierType ?: ModifierType ,
115+ ) : Modifier {
116+ switch ( modifierType ) {
117+ case "previous" :
118+ return {
119+ type : "relativeScope" ,
120+ direction : "backward" ,
121+ offset : 1 ,
122+ length : 1 ,
123+ scopeType,
124+ } ;
125+ default :
126+ return { type : "containingScope" , scopeType } ;
127+ }
128+ }
129+
95130async function testPerformance ( thresholdMs : number , action : ActionDescriptor ) {
96131 const editor = await openNewEditor ( testData , { languageId : "json" } ) ;
97132 // This is the position of the last json key in the document
0 commit comments