commandline apps

I wanted to create an app that could accept text input interactively from the terminal or have it piped:

1741030397.png

Note that I want Ctrl-D to close the input, or in dart terms that would be closing the subscription.

Naturally, input is modeled as a stream. Whether each keystroke is treated as an input event/data or whether each line is treated as the event/data depends on the following setting:

stdin.lineMode;

When stdin.lineMode is false ever keystroke appears as an event. When it is true, every the text appears as an event only after line break appears or Enter key is pressed.

Now, we only want stdin.lineMode to be false when entering text interactively, when Ctrl-d should terminate stream subscription. Therefore, our code will work in 2 different ways depending on whether stdin.hasTerminal returns true or false. Based on this logic, we've written:

import 'dart:convert';
import 'dart:io';

void main() {
  var subscription;
  if (stdin.hasTerminal) {
    stdin.lineMode = false;
    stdin.echoMode = true;
    List<int> input = [];
    subscription = stdin.listen((data) {
      if (data.contains(4)) {
        subscription.cancel();
        print("\n${utf8.decode(input)}");
      } else {
        input.add(data[0]);
      }
    });
  } else { // if there is no terminal
    stdin.map((data) => utf8.decode(data)).listen((data) {
      print(data);
    });
  }
}

Comments