44 *--------------------------------------------------------------------------------------------*/
55
66import * as vscode from 'vscode' ;
7+ import { DirectoryTreeNode } from './directoryTreeNode' ;
78import { FileChangeNode } from './fileChangeNode' ;
89import { TreeNode } from './treeNode' ;
910
@@ -14,16 +15,26 @@ export namespace TreeUtils {
1415 const checkedNodes : FileChangeNode [ ] = [ ] ;
1516 const uncheckedNodes : FileChangeNode [ ] = [ ] ;
1617
18+ // The first item is the one the user actually clicked.
19+ // Only collect missing descendants if a directory was clicked directly.
20+ const firstNode = checkboxUpdates . items [ 0 ] ?. [ 0 ] ;
21+
22+ const eventNodes = new Set < TreeNode > ( checkboxUpdates . items . map ( ( [ node ] ) => node ) ) ;
23+
1724 checkboxUpdates . items . forEach ( checkboxUpdate => {
1825 const node = checkboxUpdate [ 0 ] ;
1926 const newState = checkboxUpdate [ 1 ] ;
2027
2128 if ( node instanceof FileChangeNode ) {
22- if ( newState == vscode . TreeItemCheckboxState . Checked ) {
29+ if ( newState === vscode . TreeItemCheckboxState . Checked ) {
2330 checkedNodes . push ( node ) ;
2431 } else {
2532 uncheckedNodes . push ( node ) ;
2633 }
34+ } else if ( firstNode instanceof DirectoryTreeNode && node === firstNode ) {
35+ // VS Code auto-propagates to rendered children, but unrendered children
36+ // (due to virtual scrolling) won't be in the event. Collect those missing ones.
37+ collectMissingDescendants ( firstNode , newState , checkedNodes , uncheckedNodes , eventNodes ) ;
2738 }
2839
2940 node . updateFromCheckboxChanged ( newState ) ;
@@ -56,4 +67,32 @@ export namespace TreeUtils {
5667 prModel . markFiles ( filenames , true , 'unviewed' ) ;
5768 }
5869 }
70+
71+ /**
72+ * Collect descendant FileChangeNodes that are NOT already in the event.
73+ * These are children VS Code missed because they weren't rendered (virtual scrolling).
74+ */
75+ function collectMissingDescendants (
76+ dirNode : DirectoryTreeNode ,
77+ newState : vscode . TreeItemCheckboxState ,
78+ checkedNodes : FileChangeNode [ ] ,
79+ uncheckedNodes : FileChangeNode [ ] ,
80+ eventNodes : Set < TreeNode >
81+ ) : void {
82+ for ( const child of dirNode . _children ) {
83+ if ( eventNodes . has ( child ) ) {
84+ continue ;
85+ }
86+ if ( child instanceof FileChangeNode ) {
87+ if ( newState === vscode . TreeItemCheckboxState . Checked ) {
88+ checkedNodes . push ( child ) ;
89+ } else {
90+ uncheckedNodes . push ( child ) ;
91+ }
92+ child . updateFromCheckboxChanged ( newState ) ;
93+ } else if ( child instanceof DirectoryTreeNode ) {
94+ collectMissingDescendants ( child , newState , checkedNodes , uncheckedNodes , eventNodes ) ;
95+ }
96+ }
97+ }
5998}
0 commit comments