How to stream output from an external child process to the UI
First we do some setup and spawn a child process. We get stdout/stderr async streams for output and create a future which will wait for the process to finish without blocking the VM:
proc := (GtExternalProcessBuilder new: 'bash')
arguments: { '-c'.
'sleep 2 # hour
echo "1MB to stderr" >&2
for i in {1..200}
do
sleep 0.1
date
done' };
pipeStdout;
pipeStderr;
spawn.
stdout := proc stdoutStream.
stderr := proc stderrStream.
statusFuture := [ proc waitAsyncWithOutput ] asAsyncForkedFuture
Then create the UI and forward the streams created above:
editorStencil := [ BrEditor new
aptitude: BrGlamorousCodeEditorAptitude + BrGlamorousFocusableShadowAptitude;
background: Color white;
matchParent;
withAsyncSinkDo: [ :anElementSink |
anElementSink
sink: (AsyncFoldSink inject: '' asRopedText into: [ :text :each |
text
append: each asRopedText;
append: String cr asRopedText;
yourself ]);
whenUpdate: [ :aLabel :aSink | aLabel text: aSink value copy ] ] ] asStencil.
stdoutElement := editorStencil asElement.
stdoutElement asyncSink forwardStream: stdout lines.
stderrElement := editorStencil asElement.
stderrElement asyncSink forwardStream: stderr lines.
outputContainer := BrHorizontalPane new
matchParent;
cellSpacing: 20;
padding: (BlInsets top: 20 bottom: 20);
addChildren: { stdoutElement . stderrElement }.
statusLabel := BrLabel new
aptitude: BrGlamorousLabelAptitude new;
margin: (BlInsets left: 20);
withAsyncFutureDo: [ :anElementFuture |
anElementFuture
whenPending: [ :aLabel | aLabel text: 'Running..' ];
whenSuccess: [ :aLabel :anOutput | aLabel text: 'Finished' ];
whenError: [ :aLabel :anError | aLabel text: anError description ];
future: statusFuture ].
BrVerticalPane new
matchParent;
addChildren: { statusLabel . outputContainer }