@ -1,9 +1,12 @@
'use strict' ;
import { commands , Disposable , ExtensionContext , QuickPickItem } from 'vscode' ;
import { commands , Disposable , QuickPickItem } from 'vscode' ;
import { CommandContext , setCommandContext } from '../commands' ;
import { CommandQuickPickItem , OpenFileCommandQuickPickItem } from '../quickPicks/quickPicks' ;
import { Logger } from '../logger' ;
const keyNoopCommand = Object . create ( null ) as QuickPickItem ;
export { keyNoopCommand as KeyNoopCommand } ;
export declare type Keys = 'left' | 'right' | ',' | '.' ;
export const keys : Keys [ ] = [
'left' ,
@ -12,16 +15,72 @@ export const keys: Keys[] = [
'.'
] ;
let scopeCount = 0 ;
let counters = {
left : 0 ,
right : 0 ,
',' : 0 ,
'.' : 0
} ;
export declare type KeyMapping = { [ id : string ] : ( QuickPickItem | ( ( ) = > Promise < QuickPickItem > ) ) } ;
let mappings : KeyMapping [ ] = [ ] ;
let _instance : Keyboard ;
export class KeyboardScope extends Disposable {
constructor ( private mapping : KeyMapping ) {
super ( ( ) = > this . dispose ( ) ) ;
for ( const key in mapping ) {
mapping [ key ] = mapping [ key ] || keyNoopCommand ;
}
}
async dispose() {
const index = mappings . indexOf ( this . mapping ) ;
Logger . log ( 'KeyboardScope.dispose' , mappings . length , index ) ;
if ( index === ( mappings . length - 1 ) ) {
mappings . pop ( ) ;
await this . updateKeyCommandsContext ( mappings [ mappings . length - 1 ] ) ;
}
else {
mappings . splice ( index , 1 ) ;
}
}
async begin() {
mappings . push ( this . mapping ) ;
await this . updateKeyCommandsContext ( this . mapping ) ;
return this ;
}
async clearKeyCommand ( key : Keys ) {
const mapping = mappings [ mappings . length - 1 ] ;
if ( mapping !== this . mapping || ! mapping [ key ] ) return ;
Logger . log ( 'KeyboardScope.clearKeyCommand' , mappings . length , key ) ;
mapping [ key ] = undefined ;
await setCommandContext ( ` ${ CommandContext . Key } : ${ key } ` , false ) ;
}
async setKeyCommand ( key : Keys , command : QuickPickItem | ( ( ) = > Promise < QuickPickItem > ) ) {
const mapping = mappings [ mappings . length - 1 ] ;
if ( mapping !== this . mapping ) return ;
Logger . log ( 'KeyboardScope.setKeyCommand' , mappings . length , key , ! ! mapping [ key ] ) ;
if ( ! mapping [ key ] ) {
mapping [ key ] = command ;
await setCommandContext ( ` ${ CommandContext . Key } : ${ key } ` , true ) ;
}
else {
mapping [ key ] = command ;
}
}
private async updateKeyCommandsContext ( mapping : KeyMapping ) {
const promises = [ ] ;
for ( const key of keys ) {
promises . push ( setCommandContext ( ` ${ CommandContext . Key } : ${ key } ` , ! ! ( mapping && mapping [ key ] ) ) ) ;
}
await Promise . all ( promises ) ;
}
}
export class Keyboard extends Disposable {
static get instance ( ) : Keyboard {
@ -30,7 +89,7 @@ export class Keyboard extends Disposable {
private _disposable : Disposable ;
constructor ( private context : ExtensionContext ) {
constructor ( ) {
super ( ( ) = > this . dispose ( ) ) ;
const subscriptions : Disposable [ ] = [ ] ;
@ -48,62 +107,35 @@ export class Keyboard extends Disposable {
this . _disposable && this . _disposable . dispose ( ) ;
}
async beginScope ( mapping? : KeyMapping ) : Promise < KeyboardScope > {
Logger . log ( 'Keyboard.beginScope' , mappings . length ) ;
return await new KeyboardScope ( mapping ? Object . assign ( Object . create ( null ) , mapping ) : Object . create ( null ) ) . begin ( ) ;
}
async execute ( key : Keys ) : Promise < { } > {
let command = this . context . globalState . get ( ` gitlens:key: ${ key } ` ) as CommandQuickPickItem | ( ( ) = > Promise < CommandQuickPickItem > ) ;
if ( typeof command === 'function' ) {
command = await command ( ) ;
}
if ( ! command || ! ( command instanceof CommandQuickPickItem ) ) return undefined ;
if ( ! mappings . length ) return undefined ;
Logger . log ( 'Keyboard.execute' , key ) ;
try {
const mapping = mappings [ mappings . length - 1 ] ;
if ( command instanceof OpenFileCommandQuickPickItem ) {
// Have to open this pinned right now, because vscode doesn't have a way to open a unpinned, but unfocused editor
return await command . execute ( true ) ;
}
let command = mapping [ key ] as CommandQuickPickItem | ( ( ) = > Promise < CommandQuickPickItem > ) ;
if ( typeof command === 'function' ) {
command = await command ( ) ;
}
if ( ! command || ! ( command instanceof CommandQuickPickItem ) ) return undefined ;
return await command . execute ( ) ;
}
Logger . log ( 'Keyboard.execute' , key ) ;
async enterScope ( . . . keyCommands : [ Keys , QuickPickItem | ( ( ) = > Promise < QuickPickItem > ) ] [ ] ) {
Logger . log ( 'Keyboard.enterScope' , scopeCount ) ;
scopeCount ++ ;
// await setCommandContext(CommandContext.Key, ++scopeCount);
if ( keyCommands && Array . isArray ( keyCommands ) && keyCommands . length ) {
for ( const [ key , command ] of keyCommands ) {
await setCommandContext ( ` ${ CommandContext . Key } : ${ key } ` , ++ counters [ key ] ) ;
await this . setKeyCommand ( key as Keys , command ) ;
if ( command instanceof OpenFileCommandQuickPickItem ) {
// Have to open this pinned right now, because vscode doesn't have a way to open a unpinned, but unfocused editor
return await command . execute ( true ) ;
}
}
}
async exitScope ( clear : boolean = true ) {
Logger . log ( 'Keyboard.exitScope' , scopeCount ) ;
if ( scopeCount ) {
scopeCount -- ;
// await setCommandContext(CommandContext.Key, --scopeCount);
return await command . execute ( ) ;
}
if ( clear && ! scopeCount ) {
for ( const key of keys ) {
if ( counters [ key ] ) {
await setCommandContext ( ` ${ CommandContext . Key } : ${ key } ` , -- counters [ key ] ) ;
}
await this . clearKeyCommand ( key ) ;
}
catch ( ex ) {
Logger . error ( 'Keyboard.execute' , ex ) ;
return undefined ;
}
}
async clearKeyCommand ( key : Keys ) {
Logger . log ( 'Keyboard.clearKeyCommand' , key ) ;
if ( counters [ key ] ) {
await setCommandContext ( ` ${ CommandContext . Key } : ${ key } ` , -- counters [ key ] ) ;
}
await this . context . globalState . update ( ` gitlens:key: ${ key } ` , undefined ) ;
}
async setKeyCommand ( key : Keys , command : QuickPickItem | ( ( ) = > Promise < QuickPickItem > ) ) {
Logger . log ( 'Keyboard.setKeyCommand' , key ) ;
await setCommandContext ( ` ${ CommandContext . Key } : ${ key } ` , ++ counters [ key ] ) ;
await this . context . globalState . update ( ` gitlens:key: ${ key } ` , command ) ;
}
}