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 }