1- import { exec } from 'child_process' ;
1+ import { exec , spawn } from 'child_process' ;
22import { join } from 'path' ;
3- import { ProviderResult , TreeDataProvider , TreeItem , TreeItemCollapsibleState , window } from 'vscode' ;
3+ import { Event , EventEmitter , ProviderResult , TreeDataProvider , TreeItem , TreeItemCollapsibleState , window } from 'vscode' ;
44import { state } from './extension' ;
55import { existsSync } from 'fs' ;
66
@@ -24,40 +24,89 @@ export interface Folder {
2424export async function setupSidebar ( ) {
2525 // TODO: Show welcome screens whilst we are starting Processing
2626 // TODO: Open examples as read-only or in a temporary location
27+ // TODO: Reload examples and sketchbook when Processing version changes
28+ // TODO: Add cache to results to speed up loading
2729
2830 setupExamples ( ) ;
2931 setupSketchbook ( ) ;
3032}
3133
3234async function setupExamples ( ) {
33- const examples = await new Promise < Folder [ ] > ( ( resolve ) => {
34- exec ( `${ state . selectedVersion . path } contributions examples list` , ( error , stdout , stderr ) => {
35- if ( error ) {
36- console . error ( `exec error: ${ error } ` ) ;
37- return ;
38- }
39- resolve ( JSON . parse ( stdout ) ) ;
40- } ) ;
41- } ) ;
42-
43- const examplesProvider = new ProcessingWindowDataProvider ( examples ) ;
35+ const examplesProvider = new ProcessingWindowDataProvider ( 'contributions examples list' ) ;
4436 window . createTreeView ( 'processingSidebarExamplesView' , { treeDataProvider : examplesProvider } ) ;
4537}
4638
4739async function setupSketchbook ( ) {
48- const sketchbook = await new Promise < Folder [ ] > ( ( resolve ) => {
49- exec ( `${ state . selectedVersion . path } sketchbook list` , ( error , stdout , stderr ) => {
50- if ( error ) {
51- console . error ( `exec error: ${ error } ` ) ;
52- return ;
53- }
54- resolve ( JSON . parse ( stdout ) ) ;
55- } ) ;
56- } ) ;
57- const sketchbookProvider = new ProcessingWindowDataProvider ( sketchbook ) ;
40+ const sketchbookProvider = new ProcessingWindowDataProvider ( 'sketchbook list' ) ;
5841 window . createTreeView ( 'processingSidebarSketchbookView' , { treeDataProvider : sketchbookProvider } ) ;
5942}
6043
44+
45+ class ProcessingWindowDataProvider implements TreeDataProvider < FolderTreeItem | SketchTreeItem > {
46+ constructor (
47+ public readonly command : string
48+ ) {
49+ this . _folders = [ ] ;
50+ this . populate ( ) ;
51+ }
52+ private _folders : Folder [ ] ;
53+
54+ private _onDidChangeTreeData : EventEmitter < any > = new EventEmitter < any > ( ) ;
55+ readonly onDidChangeTreeData : Event < any > = this . _onDidChangeTreeData . event ;
56+
57+ async populate ( ) {
58+ this . _folders = await this . grabSketchesWithCommand ( this . command ) ;
59+ this . _onDidChangeTreeData . fire ( null ) ;
60+ }
61+
62+
63+ getTreeItem ( element : FolderTreeItem ) : TreeItem | Thenable < TreeItem > {
64+ return element ;
65+ }
66+ getChildren ( element ?: FolderTreeItem ) : ProviderResult < ( FolderTreeItem | SketchTreeItem ) [ ] > {
67+ if ( element === undefined ) {
68+ return this . _folders . map ( ( folder ) => new FolderTreeItem ( folder ) ) ?? [ ] ;
69+ } else {
70+ const sketches = element . folder . sketches ?. map ( ( sketch ) => {
71+ return new SketchTreeItem ( sketch ) ;
72+ } ) ?? [ ] ;
73+ const folders = element . folder . children ?. map ( ( folder ) => {
74+ return new FolderTreeItem ( folder ) ;
75+ } ) ?? [ ] ;
76+
77+ // Sort sketches and folders
78+ sketches . sort ( ( a , b ) => a . sketch . name . localeCompare ( b . sketch . name ) ) ;
79+ folders . sort ( ( a , b ) => a . folder . name . localeCompare ( b . folder . name ) ) ;
80+
81+ return [ ...sketches , ...folders ] ;
82+ }
83+ }
84+
85+ grabSketchesWithCommand ( command : string ) : Promise < Folder [ ] > {
86+ return new Promise < Folder [ ] > ( ( resolve ) => {
87+ const process = spawn ( state . selectedVersion . path , command . split ( ' ' ) ) ;
88+ let data = '' ;
89+ process . stdout . on ( 'data' , ( chunk ) => {
90+ data += chunk ;
91+ } ) ;
92+ process . on ( 'close' , ( code ) => {
93+ if ( code !== 0 ) {
94+ console . error ( `Process exited with code ${ code } ` ) ;
95+ resolve ( [ ] ) ;
96+ return ;
97+ }
98+ try {
99+ const folders = JSON . parse ( data ) as Folder [ ] ;
100+ resolve ( folders ) ;
101+ } catch ( e ) {
102+ console . error ( `Error parsing JSON: ${ e } ` ) ;
103+ resolve ( [ ] ) ;
104+ }
105+ } ) ;
106+ } ) ;
107+ }
108+ }
109+
61110class FolderTreeItem extends TreeItem {
62111 constructor (
63112 public readonly folder : Folder
@@ -90,32 +139,4 @@ class SketchTreeItem extends TreeItem {
90139 }
91140}
92141
93- class ProcessingWindowDataProvider implements TreeDataProvider < FolderTreeItem | SketchTreeItem > {
94- constructor (
95- public readonly folders : Folder [ ] ,
96- ) {
97- }
98-
99- getTreeItem ( element : FolderTreeItem ) : TreeItem | Thenable < TreeItem > {
100- return element ;
101- }
102- getChildren ( element ?: FolderTreeItem ) : ProviderResult < ( FolderTreeItem | SketchTreeItem ) [ ] > {
103- if ( element === undefined ) {
104- return this . folders . map ( ( folder ) => new FolderTreeItem ( folder ) ) ?? [ ] ;
105- } else {
106- const sketches = element . folder . sketches ?. map ( ( sketch ) => {
107- return new SketchTreeItem ( sketch ) ;
108- } ) ?? [ ] ;
109- const folders = element . folder . children ?. map ( ( folder ) => {
110- return new FolderTreeItem ( folder ) ;
111- } ) ?? [ ] ;
112-
113- // Sort sketches and folders
114- sketches . sort ( ( a , b ) => a . sketch . name . localeCompare ( b . sketch . name ) ) ;
115- folders . sort ( ( a , b ) => a . folder . name . localeCompare ( b . folder . name ) ) ;
116-
117- return [ ...sketches , ...folders ] ;
118- }
119- }
120- }
121142
0 commit comments