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 }