9
9
//
10
10
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND.
11
11
12
+ using System ;
12
13
using System . Linq ;
13
14
using System . Threading . Tasks ;
14
15
using CodeIngestLib ;
@@ -23,33 +24,43 @@ namespace CodeIngest.Desktop;
23
24
public class MainViewModel : ViewModelBase
24
25
{
25
26
private readonly IDialogService m_dialogService ;
26
- private FolderTreeRoot m_root = new FolderTreeRoot ( Settings . Instance . RootFolder ) ;
27
-
27
+ private readonly ActionConsolidator m_folderSelectionConsolidator ;
28
+ private FolderTreeRoot m_root ;
29
+ private ProgressToken m_backgroundRefreshProgress ;
28
30
private bool m_isCSharp = Settings . Instance . IsCSharp ;
29
31
private bool m_isCppNoHeaders = Settings . Instance . IsCppNoHeaders ;
30
32
private bool m_isCppWithHeaders = Settings . Instance . IsCppWithHeaders ;
31
33
private bool m_includeMarkdown = Settings . Instance . IncludeMarkdown ;
32
34
private bool m_excludeImports = Settings . Instance . ExcludeImports ;
33
35
private bool m_useFullPaths = Settings . Instance . UseFullPaths ;
34
36
private bool m_excludeComments = Settings . Instance . ExcludeComments ;
37
+ private int ? m_previewFileCount ;
38
+ private long ? m_previewFileSize ;
39
+ private bool m_isGeneratingPreview ;
35
40
36
41
public FolderTreeRoot Root
37
42
{
38
43
get => m_root ;
39
44
set
40
45
{
41
- if ( SetField ( ref m_root , value ) )
42
- Settings . Instance . RootFolder = value . Root . Clone ( ) ;
46
+ if ( ! SetField ( ref m_root , value ) || value == null )
47
+ return ;
48
+ Settings . Instance . RootFolder = m_root . Root . Clone ( ) ;
49
+ m_root . SelectionChanged += OnFolderSelectionChanged ;
50
+ InvalidatePreviewStats ( ) ;
43
51
}
44
52
}
45
-
53
+
46
54
public bool IsCSharp
47
55
{
48
56
get => m_isCSharp ;
49
57
set
50
58
{
51
59
if ( SetField ( ref m_isCSharp , value ) )
60
+ {
52
61
Settings . Instance . IsCSharp = value ;
62
+ InvalidatePreviewStats ( ) ;
63
+ }
53
64
}
54
65
}
55
66
@@ -59,7 +70,10 @@ public bool IsCppNoHeaders
59
70
set
60
71
{
61
72
if ( SetField ( ref m_isCppNoHeaders , value ) )
73
+ {
62
74
Settings . Instance . IsCppNoHeaders = value ;
75
+ InvalidatePreviewStats ( ) ;
76
+ }
63
77
}
64
78
}
65
79
@@ -69,7 +83,10 @@ public bool IsCppWithHeaders
69
83
set
70
84
{
71
85
if ( SetField ( ref m_isCppWithHeaders , value ) )
86
+ {
72
87
Settings . Instance . IsCppWithHeaders = value ;
88
+ InvalidatePreviewStats ( ) ;
89
+ }
73
90
}
74
91
}
75
92
@@ -79,7 +96,10 @@ public bool ExcludeImports
79
96
set
80
97
{
81
98
if ( SetField ( ref m_excludeImports , value ) )
99
+ {
82
100
Settings . Instance . ExcludeImports = value ;
101
+ InvalidatePreviewStats ( ) ;
102
+ }
83
103
}
84
104
}
85
105
@@ -89,7 +109,10 @@ public bool ExcludeComments
89
109
set
90
110
{
91
111
if ( SetField ( ref m_excludeComments , value ) )
112
+ {
92
113
Settings . Instance . ExcludeComments = value ;
114
+ InvalidatePreviewStats ( ) ;
115
+ }
93
116
}
94
117
}
95
118
@@ -99,7 +122,10 @@ public bool IncludeMarkdown
99
122
set
100
123
{
101
124
if ( SetField ( ref m_includeMarkdown , value ) )
125
+ {
102
126
Settings . Instance . IncludeMarkdown = value ;
127
+ InvalidatePreviewStats ( ) ;
128
+ }
103
129
}
104
130
}
105
131
@@ -109,10 +135,31 @@ public bool UseFullPaths
109
135
set
110
136
{
111
137
if ( SetField ( ref m_useFullPaths , value ) )
138
+ {
112
139
Settings . Instance . UseFullPaths = value ;
140
+ InvalidatePreviewStats ( ) ;
141
+ }
113
142
}
114
143
}
115
144
145
+ public int ? PreviewFileCount
146
+ {
147
+ get => m_previewFileCount ;
148
+ set => SetField ( ref m_previewFileCount , value ) ;
149
+ }
150
+
151
+ public long ? PreviewFileSize
152
+ {
153
+ get => m_previewFileSize ;
154
+ set => SetField ( ref m_previewFileSize , value ) ;
155
+ }
156
+
157
+ public bool IsGeneratingPreview
158
+ {
159
+ get => m_isGeneratingPreview ;
160
+ set => SetField ( ref m_isGeneratingPreview , value ) ;
161
+ }
162
+
116
163
public async Task SelectRoot ( )
117
164
{
118
165
var rootFolder = await m_dialogService . SelectFolderAsync ( "Select a folder to scan for code." ) ;
@@ -125,6 +172,9 @@ public async Task SelectRoot()
125
172
public MainViewModel ( IDialogService dialogService = null )
126
173
{
127
174
m_dialogService = dialogService ?? DialogService . Instance ;
175
+
176
+ m_folderSelectionConsolidator = new ActionConsolidator ( RefreshPredictedSize , 2.0 ) ;
177
+ Root = new FolderTreeRoot ( Settings . Instance . RootFolder ) ;
128
178
}
129
179
130
180
public async Task RunIngest ( )
@@ -146,6 +196,25 @@ public async Task RunIngest()
146
196
if ( outputFile == null )
147
197
return ; // User cancelled.
148
198
199
+ var progress = new ProgressToken ( true ) { IsCancelSupported = true } ;
200
+ ( int FileCount , long OutputBytes ) ? result ;
201
+ using ( m_dialogService . ShowBusy ( "Generating code..." , progress ) )
202
+ {
203
+ var options = GetIngestOptions ( ) ;
204
+ var ingester = new Ingester ( options ) ;
205
+ result = await Task . Run ( ( ) => ingester . Run ( selectedFolders , outputFile , progress ) ) ;
206
+ }
207
+ if ( ! result . HasValue )
208
+ {
209
+ m_dialogService . ShowMessage ( "Failed to generate code file." , "Please check your file permissions and try again." , MaterialIconKind . Error ) ;
210
+ return ;
211
+ }
212
+
213
+ m_dialogService . ShowMessage ( "Code file generated successfully." , $ "{ result . Value . FileCount : N0} files produced { result . Value . OutputBytes . ToSize ( ) } of output.") ;
214
+ }
215
+
216
+ private IngestOptions GetIngestOptions ( )
217
+ {
149
218
var options = new IngestOptions
150
219
{
151
220
ExcludeImports = ExcludeImports ,
@@ -168,20 +237,53 @@ public async Task RunIngest()
168
237
169
238
if ( IncludeMarkdown )
170
239
options . FilePatterns . Add ( "*.md" ) ;
240
+ return options ;
241
+ }
171
242
172
- var progress = new ProgressToken ( true ) { IsCancelSupported = true } ;
173
- ( int FileCount , long OutputBytes ) ? result ;
174
- using ( m_dialogService . ShowBusy ( "Generating code..." , progress ) )
243
+ private void OnFolderSelectionChanged ( object sender , EventArgs e ) =>
244
+ InvalidatePreviewStats ( ) ;
245
+
246
+ private void InvalidatePreviewStats ( ) =>
247
+ m_folderSelectionConsolidator . Invoke ( ) ;
248
+
249
+ private void RefreshPredictedSize ( )
250
+ {
251
+ m_backgroundRefreshProgress ? . Cancel ( ) ;
252
+
253
+ var selectedFolders = Root . GetSelectedItems ( ) . ToArray ( ) ;
254
+ if ( selectedFolders . Length == 0 )
175
255
{
176
- var ingester = new Ingester ( options ) ;
177
- result = await Task . Run ( ( ) => ingester . Run ( selectedFolders , outputFile , progress ) ) ;
256
+ PreviewFileCount = 0 ;
257
+ PreviewFileSize = 0 ;
258
+ return ; // Nothing to do.
178
259
}
179
- if ( ! result . HasValue )
260
+
261
+ var options = GetIngestOptions ( ) ;
262
+ if ( options . FilePatterns . Count == 0 )
180
263
{
181
- m_dialogService . ShowMessage ( "Failed to generate code file." , "Please check your file permissions and try again." , MaterialIconKind . Error ) ;
182
- return ;
264
+ PreviewFileCount = 0 ;
265
+ PreviewFileSize = 0 ;
266
+ return ; // Nothing search.
183
267
}
184
268
185
- m_dialogService . ShowMessage ( "Code file generated successfully." , $ "{ result . Value . FileCount : N0} files produced { result . Value . OutputBytes . ToSize ( ) } of output.") ;
269
+ var ingester = new Ingester ( options ) ;
270
+ m_backgroundRefreshProgress = new ProgressToken ( true ) ;
271
+
272
+ Task . Run ( ( ) =>
273
+ {
274
+ IsGeneratingPreview = true ;
275
+ try
276
+ {
277
+ var result = ingester . Run ( selectedFolders , progress : m_backgroundRefreshProgress ) ;
278
+ if ( ! result . HasValue || m_backgroundRefreshProgress . CancelRequested )
279
+ return ;
280
+ PreviewFileCount = result . Value . FileCount ;
281
+ PreviewFileSize = result . Value . OutputBytes ;
282
+ }
283
+ finally
284
+ {
285
+ IsGeneratingPreview = false ;
286
+ }
287
+ } ) ;
186
288
}
187
289
}
0 commit comments