@@ -62,18 +62,19 @@ interface SidebarNavigationItem {
6262 readonly tabId : string ;
6363}
6464
65+ function isNavigableCategory ( category : CategoryInfo , collapsedCategories : ReadonlySet < string > ) : boolean {
66+ return ! collapsedCategories . has ( category . name ) && category . type !== "files" ;
67+ }
68+
6569function buildSidebarNavigationItems (
6670 categories : ReadonlyArray < CategoryInfo > ,
6771 collapsedCategories : ReadonlySet < string > ,
6872) : readonly SidebarNavigationItem [ ] {
69- const items : SidebarNavigationItem [ ] = [ ] ;
70- for ( const category of categories ) {
71- if ( collapsedCategories . has ( category . name ) || category . type === "files" ) continue ;
72- for ( const tab of category . tabs ) {
73- items . push ( { categoryName : category . name , tabId : tab . id } ) ;
74- }
75- }
76- return items ;
73+ return categories
74+ . filter ( ( category ) => isNavigableCategory ( category , collapsedCategories ) )
75+ . flatMap ( ( category ) =>
76+ category . tabs . map ( ( tab ) => ( { categoryName : category . name , tabId : tab . id } ) ) ,
77+ ) ;
7778}
7879
7980function buildTabList ( activeCategory : CategoryInfo | undefined ) : Tab [ ] {
@@ -101,6 +102,69 @@ function toggleSetItem<T>(source: ReadonlySet<T>, item: T): Set<T> {
101102 return new Set ( [ ...source , item ] ) ;
102103}
103104
105+ function handleCommandPaletteKey (
106+ event : KeyboardEvent ,
107+ isModifierPressed : boolean ,
108+ commandPaletteOpen : boolean ,
109+ setCommandPaletteOpen : ( open : boolean | ( ( prev : boolean ) => boolean ) ) => void ,
110+ ) : boolean {
111+ if ( isModifierPressed && event . key === "k" ) { event . preventDefault ( ) ; setCommandPaletteOpen ( ( prev : boolean ) => ! prev ) ; return true ; }
112+ if ( event . key === "Escape" && commandPaletteOpen ) { setCommandPaletteOpen ( false ) ; return true ; }
113+ return false ;
114+ }
115+
116+ function handleCategorySwitchKey (
117+ event : KeyboardEvent ,
118+ isModifierPressed : boolean ,
119+ categories : ReadonlyArray < CategoryInfo > ,
120+ selectCategory : ( name : string ) => void ,
121+ ) : boolean {
122+ if ( ! isModifierPressed || event . key < "1" || event . key > "9" ) return false ;
123+ event . preventDefault ( ) ;
124+ const categoryIndex = parseInt ( event . key , 10 ) - 1 ;
125+ if ( categoryIndex < categories . length ) selectCategory ( categories [ categoryIndex ] ! . name ) ;
126+ return true ;
127+ }
128+
129+ function handleTabSwitchKey (
130+ event : KeyboardEvent ,
131+ isModifierPressed : boolean ,
132+ orderedTabs : readonly Tab [ ] ,
133+ activeTabId : string ,
134+ selectTab : ( id : string ) => void ,
135+ ) : boolean {
136+ if ( ! isModifierPressed || ( event . key !== "[" && event . key !== "]" ) ) return false ;
137+ event . preventDefault ( ) ;
138+ if ( orderedTabs . length === 0 ) return true ;
139+ const currentIndex = orderedTabs . findIndex ( ( t ) => t . id === activeTabId ) ;
140+ const nextIndex = event . key === "]"
141+ ? ( currentIndex + 1 ) % orderedTabs . length
142+ : ( currentIndex - 1 + orderedTabs . length ) % orderedTabs . length ;
143+ selectTab ( orderedTabs [ nextIndex ] ! . id ) ;
144+ return true ;
145+ }
146+
147+ function handleArrowNavigation (
148+ event : KeyboardEvent ,
149+ commandPaletteOpen : boolean ,
150+ sidebarItems : readonly SidebarNavigationItem [ ] ,
151+ activeTabId : string ,
152+ activeCategory : string ,
153+ selectCategory : ( name : string ) => void ,
154+ selectTab : ( id : string ) => void ,
155+ ) : boolean {
156+ const isArrowKey = event . key === "ArrowUp" || event . key === "ArrowDown" ;
157+ if ( ! isArrowKey || isTerminalFocused ( ) || commandPaletteOpen || sidebarItems . length === 0 ) return false ;
158+ event . preventDefault ( ) ;
159+ const currentIndex = sidebarItems . findIndex ( ( item ) => item . tabId === activeTabId ) ;
160+ const delta = event . key === "ArrowDown" ? 1 : - 1 ;
161+ const nextIndex = currentIndex === - 1 ? 0 : ( currentIndex + delta + sidebarItems . length ) % sidebarItems . length ;
162+ const nextItem = sidebarItems [ nextIndex ] ! ;
163+ if ( nextItem . categoryName !== activeCategory ) selectCategory ( nextItem . categoryName ) ;
164+ selectTab ( nextItem . tabId ) ;
165+ return true ;
166+ }
167+
104168function useKeyboardShortcuts ( {
105169 commandPaletteOpen,
106170 setCommandPaletteOpen,
@@ -125,43 +189,10 @@ function useKeyboardShortcuts({
125189 useEffect ( ( ) => {
126190 const handler = ( event : KeyboardEvent ) : void => {
127191 const isModifierPressed = event . metaKey || event . ctrlKey ;
128-
129- if ( isModifierPressed && event . key === "k" ) { event . preventDefault ( ) ; setCommandPaletteOpen ( ( prev : boolean ) => ! prev ) ; return ; }
130- if ( event . key === "Escape" && commandPaletteOpen ) { setCommandPaletteOpen ( false ) ; return ; }
131-
132- if ( isModifierPressed && event . key >= "1" && event . key <= "9" ) {
133- event . preventDefault ( ) ;
134- const categoryIndex = parseInt ( event . key , 10 ) - 1 ;
135- if ( categoryIndex < categories . length ) selectCategory ( categories [ categoryIndex ] ! . name ) ;
136- return ;
137- }
138-
139- if ( isModifierPressed && ( event . key === "[" || event . key === "]" ) ) {
140- event . preventDefault ( ) ;
141- if ( orderedTabs . length === 0 ) return ;
142- const currentIndex = orderedTabs . findIndex ( ( t ) => t . id === activeTabId ) ;
143- const nextIndex = event . key === "]"
144- ? ( currentIndex + 1 ) % orderedTabs . length
145- : ( currentIndex - 1 + orderedTabs . length ) % orderedTabs . length ;
146- selectTab ( orderedTabs [ nextIndex ] ! . id ) ;
147- return ;
148- }
149-
150- const isArrowNavigation = ( event . key === "ArrowUp" || event . key === "ArrowDown" )
151- && ! isTerminalFocused ( )
152- && ! commandPaletteOpen
153- && sidebarItems . length > 0 ;
154- if ( ! isArrowNavigation ) return ;
155-
156- event . preventDefault ( ) ;
157- const currentIndex = sidebarItems . findIndex ( ( item ) => item . tabId === activeTabId ) ;
158- const delta = event . key === "ArrowDown" ? 1 : - 1 ;
159- const nextIndex = currentIndex === - 1
160- ? 0
161- : ( currentIndex + delta + sidebarItems . length ) % sidebarItems . length ;
162- const nextItem = sidebarItems [ nextIndex ] ! ;
163- if ( nextItem . categoryName !== activeCategory ) selectCategory ( nextItem . categoryName ) ;
164- selectTab ( nextItem . tabId ) ;
192+ if ( handleCommandPaletteKey ( event , isModifierPressed , commandPaletteOpen , setCommandPaletteOpen ) ) return ;
193+ if ( handleCategorySwitchKey ( event , isModifierPressed , categories , selectCategory ) ) return ;
194+ if ( handleTabSwitchKey ( event , isModifierPressed , orderedTabs , activeTabId , selectTab ) ) return ;
195+ handleArrowNavigation ( event , commandPaletteOpen , sidebarItems , activeTabId , activeCategory , selectCategory , selectTab ) ;
165196 } ;
166197
167198 window . addEventListener ( "keydown" , handler ) ;
0 commit comments