<commit_before>import Cell from './Cell';
import Color from './Color';
import {encodeToVT100} from './util/encodeToVT100';

/**
 * Cursor implements low-level API to terminal control codes.
 *
 * @see http://www.termsys.demon.co.uk/vtansi.htm
 * @see http://misc.flogisoft.com/bash/tip_colors_and_formatting
 * @see http://man7.org/linux/man-pages/man4/console_codes.4.html
 * @see http://www.x.org/docs/xterm/ctlseqs.pdf
 * @see http://wiki.bash-hackers.org/scripting/terminalcodes
 * @since 1.0.0
 */
export default class Cursor {
  /**
   * Creates cursor that writes direct to `stdout`.
   * You can override target stream with another one.
   * Also, you can specify custom width and height of viewport where cursor will render the frame.
   *
   * @constructor
   * @param {Object} [options] Object with options
   * @param {Stream} [options.stream=process.stdout] Writable stream
   * @param {Number} [options.width=stream.columns] Number of columns (width)
   * @param {Number} [options.height=stream.rows] Number of rows (height)
   */
  constructor(options = {}) {
    const {stream = process.stdout, width = stream.columns, height = stream.rows} = options;

    this._stream = stream;
    this._width = width;
    this._height = height;

    this._x = 0;
    this._y = 0;
    this._background = {r: -1, g: -1, b: -1};
    this._foreground = {r: -1, g: -1, b: -1};
    this._display = {bold: false, dim: false, underlined: false, blink: false, reverse: false, hidden: false};

    this._cells = Array.from({length: width * height}).map(() => new Cell());
  }

  /**
   * Write to the stream.
   * It doesn't applies immediately but stores in virtual terminal that represented as array of {@link Cell} instances.
   * For applying changes you need to {@link flush} changes.
   *
   * @param {String} data Data to write to the terminal
   * @returns {Cursor}
   */
  write(data) {
    data.split('').forEach(char => {
      if (0 <= this._x && this._x < this._width && 0 <= this._y && this._y < this._height) {
        this._cells[this.getPointerFromXY(this._x, this._y)]
          .setChar(char)
          .setX(this._x)
          .setY(this._y)
          .setBackground(this._background.r, this._background.g, this._background.b)
          .setForeground(this._foreground.r, this._foreground.g, this._foreground.b)
          .setDisplay(this._display.bold, this._display.dim, this._display.underlined, this._display.blink, this._display.reverse, this._display.hidden)
          .setModified();
      }

      this._x++;
    });

    return this;
  }

  /**
   * Takes only modified cells from virtual terminal and flush changes to the real terminal.
   * There is no requirements to build diff or something, we have the markers for each cell that has been modified.
   *
   * @returns {Cursor}
   */
  flush() {
    var seq = '';

    for (var i = 0; i < this._cells.length; i++) {
      if (this._cells[i].isModified()) seq += this._cells[i].setModified(false).toString();
    }

    this._stream.write(seq);

    return this;
  }

  /**
   * Get index of the virtual terminal representation from (x, y) coordinates.
   *
   * @param {Number} [x] X coordinate on the terminal
   * @param {Number} [y] Y coordinate on the terminal
   * @returns {Number} Returns index in the buffer array
   */
  getPointerFromXY(x = this._x, y = this._y) {
    return y * this._width + x;
  }

  /**
   * Get (x, y) coordinate from the virtual terminal pointer.
   *
   * @param {Number} index Index in the buffer
   * @returns {Array} Returns an array [x, y]
   */
  getXYFromPointer(index) {
    return [index - (Math.floor(index / this._width) * this._width), Math.floor(index / this._width)];
  }

  /**<commit_msg>perf(cursor): Remove deopt on flush()<commit_after>import Cell from './Cell';
import Color from './Color';
import {encodeToVT100} from './util/encodeToVT100';

/**
 * Cursor implements low-level API to terminal control codes.
 *
 * @see http://www.termsys.demon.co.uk/vtansi.htm
 * @see http://misc.flogisoft.com/bash/tip_colors_and_formatting
 * @see http://man7.org/linux/man-pages/man4/console_codes.4.html
 * @see http://www.x.org/docs/xterm/ctlseqs.pdf
 * @see http://wiki.bash-hackers.org/scripting/terminalcodes
 * @since 1.0.0
 */
export default class Cursor {
  /**
   * Creates cursor that writes direct to `stdout`.
   * You can override target stream with another one.
   * Also, you can specify custom width and height of viewport where cursor will render the frame.
   *
   * @constructor
   * @param {Object} [options] Object with options
   * @param {Stream} [options.stream=process.stdout] Writable stream
   * @param {Number} [options.width=stream.columns] Number of columns (width)
   * @param {Number} [options.height=stream.rows] Number of rows (height)
   */
  constructor(options = {}) {
    const {stream = process.stdout, width = stream.columns, height = stream.rows} = options;

    this._stream = stream;
    this._width = width;
    this._height = height;

    this._x = 0;
    this._y = 0;
    this._background = {r: -1, g: -1, b: -1};
    this._foreground = {r: -1, g: -1, b: -1};
    this._display = {bold: false, dim: false, underlined: false, blink: false, reverse: false, hidden: false};

    this._cells = Array.from({length: width * height}).map(() => new Cell());
  }

  /**
   * Write to the stream.
   * It doesn't applies immediately but stores in virtual terminal that represented as array of {@link Cell} instances.
   * For applying changes you need to {@link flush} changes.
   *
   * @param {String} data Data to write to the terminal
   * @returns {Cursor}
   */
  write(data) {
    data.split('').forEach(char => {
      if (0 <= this._x && this._x < this._width && 0 <= this._y && this._y < this._height) {
        this._cells[this.getPointerFromXY(this._x, this._y)]
          .setChar(char)
          .setX(this._x)
          .setY(this._y)
          .setBackground(this._background.r, this._background.g, this._background.b)
          .setForeground(this._foreground.r, this._foreground.g, this._foreground.b)
          .setDisplay(this._display.bold, this._display.dim, this._display.underlined, this._display.blink, this._display.reverse, this._display.hidden)
          .setModified();
      }

      this._x++;
    });

    return this;
  }

  /**
   * Takes only modified cells from virtual terminal and flush changes to the real terminal.
   * There is no requirements to build diff or something, we have the markers for each cell that has been modified.
   *
   * @returns {Cursor}
   */
  flush() {
    for (var i = 0; i < this._cells.length; i++) {
      if (this._cells[i].isModified()) {
        this._stream.write(this._cells[i].setModified(false).toString());
      }
    }

    return this;
  }

  /**
   * Get index of the virtual terminal representation from (x, y) coordinates.
   *
   * @param {Number} [x] X coordinate on the terminal
   * @param {Number} [y] Y coordinate on the terminal
   * @returns {Number} Returns index in the buffer array
   */
  getPointerFromXY(x = this._x, y = this._y) {
    return y * this._width + x;
  }

  /**
   * Get (x, y) coordinate from the virtual terminal pointer.
   *
   * @param {Number} index Index in the buffer
   * @returns {Array} Returns an array [x, y]
   */
  getXYFromPointer(index) {
    return [index - (Math.floor(index / this._width) * this._width), Math.floor(index / this._width)];
  }

  /**
{'fraction_non_alphanumeric': 0.14101184068891282, 'fraction_numerical': 0.006189451022604951, 'mean_word_length': 2.9079915878023135, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2041227', 'n_tokens_mistral': 2394, 'n_tokens_neox': 2325, 'n_words': 690}