docs: function() {
      // A stack, latest task is the last item in the array
      this.tasks = [];
      this.currentLine = 0;
  
      // Keeping track of current line in the log
      // Shadow stdout.write and stderr.write
      newlines(process.stdout);
      newlines(process.stderr);
      process.stderr.on('newline', function() {
          this.currentLine++;
      }.bind(this));
      process.stdout.on('newline', function() {
          this.currentLine++;
      }.bind(this));
  
      // Functions to expose
      this.log = function() {
          // Similar to console.log, but nested appropriately
          const args = [].slice.call(arguments);
          log(console.log, args, this.tasks.length);
      };
  
      this.error = function() {
          // Similar to console.error, but nested appropriately
          const args = [].slice.call(arguments);
          log(console.error, args, this.tasks.length);
      };
  
      /**
       *  Task tracking, acts almost like a wrapper around Promise(func(resolve, reject))
       *  If the passed in function takes no arguments, then it is assumed to be a sync
       *  call that may throw (reject) or return a value (resolve)
       *
       *  @returns Promise that resolves/rejects as if the contents, but adds some
       *  logging logic around it
       */
      this.task = function(taskName, taskFunction) {
          const indentation = this.tasks.length;
          const lines = indentation === 0 ? 1 : 0;
  
          // Push a simple task object to the queue
          const task = {
              name: taskName,
              line: this.currentLine + lines,
              indentation: indentation
          };
  
          const introLine = `${_.repeat('\t', indentation)}${taskName}`;
  
          const finish = function(t, succeed, err) {
              const idx = _.findIndex(this.tasks, t);
              if (idx === -1) {
                  throw new Error('Task is not part of the logger');
              }
  
              // Remove from tasks
              this.tasks.splice(idx, 1);
  
              // Create message to write, then decide where to write
              let message;
              if (succeed) {
                  message = `${introLine} ${chalk.green('✔')}`;
              } else if (err) {
                  message = `${introLine} ${chalk.red('✖')} ${err.message}`;
              } else {
                  message = `${introLine} ${chalk.red('✖')}`;
              }
  
              // Simple check, if on next line of the task, append to previous line
              // otherwise add a new line
              if (this.currentLine === task.line + 1) {
                  cursor.up(1).eraseLine().write(message).down(1).horizontalAbsolute(0);
              } else {
                  cursor.write(message).write('\n\n');
              }
          }.bind(this);
  
          return new Promise(function(resolve, reject) {
              // If there are currently no tasks, add an empty line
              // (top-level or first tasks are separated by empty lines)
              if (this.tasks.length === 0) {
                  cursor.write('\n');
              }
  
              // Print out the task name
              cursor.write(`${introLine}\n`);
  
              // Add to the tasks array
              this.tasks.push(task);
  
              if (taskFunction.length === 0) {
                  // Sync task
                  try {
                      const result = taskFunction();
                      finish(task, true, null);
                      resolve(result);
                  } catch (err) {
                      finish(task, false, err);
                      reject(err);
                  }
              } else {
                  // Async task
                  const res = function(value) {
                      finish(task, true, null);
                      resolve(value);
                  };
  
                  const rej = function(err) {
                      finish(task, false, err);
                      reject(err);
                  };
  
                  taskFunction(res, rej);
              }
          }.bind(this));
      };
  
      return this;
  }