@@ -4,17 +4,53 @@ import { passthroughExposedApiCommands, TriggerCharacterCommand } from '../types
44import { sendCommand } from './sendCommand'
55
66export default ( ) => {
7- const sharedRequest = ( type : TriggerCharacterCommand , { offset, relativeOffset = 0 } : RequestOptions ) => {
7+ /** @unique */
8+ const cacheableCommands : Set < ( typeof passthroughExposedApiCommands ) [ number ] > = new Set ( [ 'getNodePath' , 'getSpanOfEnclosingComment' , 'getNodeAtPosition' ] )
9+ const operationsCache = new Map < string , { key : string ; data } > ( )
10+ const sharedRequest = async ( type : TriggerCharacterCommand , { offset, relativeOffset = 0 , document, position } : RequestOptions ) => {
11+ if ( position && offset ) throw new Error ( 'Only position or offset parameter can be provided' )
12+ if ( document && ! offset && ! position ) throw new Error ( 'When custom document is provided, offset or position must be provided' )
13+
814 const { activeTextEditor } = vscode . window
9- if ( ! activeTextEditor ) return
10- const { document, selection } = activeTextEditor
11- offset ??= document . offsetAt ( selection . active ) + relativeOffset
12- return sendCommand ( type , { document, position : document . positionAt ( offset ) } )
15+ document ??= activeTextEditor ?. document
16+ if ( ! document ) return
17+ if ( ! position ) offset ??= document . offsetAt ( activeTextEditor ! . selection . active ) + relativeOffset
18+ const requestOffset = offset ?? document . offsetAt ( position ! )
19+ const requestPos = position ?? document . positionAt ( offset ! )
20+ const getData = async ( ) => sendCommand ( type , { document : document ! , position : requestPos } )
21+ if ( cacheableCommands . has ( type as any ) ) {
22+ const cacheEntry = operationsCache . get ( type )
23+ const operationKey = `${ document . uri . toString ( ) } :${ document . version } :${ requestOffset } `
24+ if ( cacheEntry ?. key === operationKey ) {
25+ return cacheEntry . data
26+ }
27+
28+ const data = getData ( )
29+ // intentionally storing data only per one offset because it was created for this specific case:
30+ // extension 1 completion provider requests API data
31+ // at the same time:
32+ // extension 2 completion provider requests API data at the same document and position
33+ // and so on
34+ operationsCache . set ( type , { key : operationKey , data } )
35+ if ( type === 'getNodePath' ) {
36+ operationsCache . set ( 'getNodeAtPosition' , { key : operationKey , data : data . then ( ( path : any ) => path [ path . length - 1 ] ) } )
37+ }
38+
39+ return data
40+ }
41+
42+ return getData ( )
1343 }
1444
1545 type RequestOptions = Partial < {
46+ /**
47+ * Should be rarely overrided, this document must be part of opened project
48+ * If specificed, offset or position must be provided too
49+ */
50+ document : vscode . TextDocument
1651 offset : number
1752 relativeOffset : number
53+ position : vscode . Position
1854 } >
1955 for ( const cmd of passthroughExposedApiCommands )
2056 vscode . commands . registerCommand ( getExtensionCommandId ( cmd as never ) , async ( options : RequestOptions = { } ) => sharedRequest ( cmd , options ) )
0 commit comments