Produce animated typing effect in the terminal

Viewed 214

There are libraries like typewriterjs and typeitjs for producing animated typing effect in the DOM. How can I produce a similar effect in the terminal. The closest option I found is terminal-kit, but it is causing problems for me when the cli app has to take an input just after the effect is completed. The next input is adding unwanted characters, and I cant seem to find a way to solve it (refer the gif below).

enter image description here

This is how I produced that effect using terminal kit. It would be helpful if someone can tell me why the next input is not being registered properly after the effect completes.

const repl = require('repl');
const socket = require('socket.io-client')('http://localhost:3000');
const term = require('terminal-kit').terminal;

socket.on('connect', function() {
  console.log('Server connected');
});

// typing effect on receiving a message
socket.on('msg', function(data) {
  term.slowTyping(
    data, {
      flashStyle: false,
      delay: 115,
      style: term.yellow
    },
    function() {
      return takeInput();
    }
  );
});

socket.on('disconnect', function() {
  console.log('Server disconnected');
});

function takeInput() {
  console.log('');
  repl.start({
    prompt: '> ',
    eval: (message) => {
      socket.emit('msg', message);
    }
  });
}

takeInput();
1 Answers

The problem occurs because at that point two calls to takeInput have been made (the one at the last line and the one from the callback of slowTyping), that means that two repl servers have been started and they both take input at the same time, that explains the duplication of the input. It will get worse because by the next message three repl servers will be active at the same time and more will be created after each message.

takeInput should keep track of the repl servers it creates, and should make sure that only one exists at any time. When takeInput is called, it should destroy any previous input fields and create a new one. I don't know how to cancel a repl server and I don't think you should be using it in the first place since terminal-kit already provides a better alternative: inputField.

let currentInput = null;                                  // the current prompt
function takeInput() {
  if(currentInput) {                                      // if there is already an input field
    currentInput.abort();                                 // cancel it
  }

  term('\n> ');
  currentInput = term.inputField((err, message) => {      // create a new input field and assign it to currentInput
    // handle err
    
    socket.emit('msg', message);                          // post the message (maybe check if it's not empty first)
    takeInput();                                          // and prompt for a new input
  });
}
Related