<commit_before>/*
 * Copyright 2018 <NAME> <<EMAIL>>
 *
 * This source code is licensed under the MIT license which is detailed in the LICENSE.txt file.
 */
import {EventEmitter} from 'extraterm-event-emitter';
import {Event, BufferSizeChange, Pty, Logger, EnvironmentMap} from 'extraterm-extension-api';
import * as pty from 'node-pty';
import * as _ from 'lodash';


const MAXIMUM_WRITE_BUFFER_SIZE = 64 * 1024;

export interface PtyOptions {
  exe?: string;
  args?: string[];
  cols?: number;
  rows?: number;
  cwd?: string;
  env?: EnvironmentMap;
  preMessage?: string;
}

export class UnixPty implements Pty {

  private realPty: pty.IPty;
  private _permittedDataSize = 0; 
  private _paused = true;
  private _onDataEventEmitter = new EventEmitter<string>();
  private _onExitEventEmitter = new EventEmitter<void>();
  private _onAvailableWriteBufferSizeChangeEventEmitter = new EventEmitter<BufferSizeChange>();
  private _outstandingWriteDataCount = 0;
  private _emitBufferSizeLater: (() => void) & _.Cancelable = null;

  // Amount of data which went directly to the OS but still needs to 'announced' via an event.
  private _directWrittenDataCount = 0;

  onData: Event<string>;
  onExit: Event<void>;
  onAvailableWriteBufferSizeChange: Event<BufferSizeChange>;

  constructor(private _log: Logger, options: PtyOptions) {
    this.onData = this._onDataEventEmitter.event;
    this.onExit = this._onExitEventEmitter.event;
    this.onAvailableWriteBufferSizeChange = this._onAvailableWriteBufferSizeChangeEventEmitter.event;

    this.realPty = pty.spawn(options.exe, options.args, options);

    this.realPty.on('data', (data: any): void => {
      this._onDataEventEmitter.fire(data);
      this.permittedDataSize(this._permittedDataSize - data.length);
    });

    this.realPty.on('exit', () => {
      this._onExitEventEmitter.fire(undefined);
    });

    this.realPty.on("drain", () => {
      this._onAvailableWriteBufferSizeChangeEventEmitter.fire({
        totalBufferSize: MAXIMUM_WRITE_BUFFER_SIZE,
        availableDelta: this._outstandingWriteDataCount + this._directWrittenDataCount
      });
      this._directWrittenDataCount = 0;
      this._outstandingWriteDataCount = 0;
    });

    this._emitBufferSizeLater = _.throttle(this._emitAvailableWriteBufferSizeChange.bind(this), 0, {leading: false});

    this.realPty.pause();

    if (options.preMessage != null && options.preMessage !== "") {
      process.nextTick(() => {
        this._onDataEventEmitter.fire(options.preMessage);
      });
    }
  }
  
  write(data: string): void {
    if (this.realPty._socket.write(data)) { // FIXME try to avoid using _socket directly. Upgraded node-pty is needed.
      this._directWrittenDataCount += data.length;
      this._emitBufferSizeLater();
    } else {
      this._outstandingWriteDataCount += data.length;
    }
  }

  private _emitAvailableWriteBufferSizeChange(): void {
    if (this._directWrittenDataCount !== 0) {
      const writtenCount = this._directWrittenDataCount;
      this._directWrittenDataCount = 0;
      this._onAvailableWriteBufferSizeChangeEventEmitter.fire({
        totalBufferSize: MAXIMUM_WRITE_BUFFER_SIZE,
        availableDelta: writtenCount
      });
    }
  }

  getAvailableWriteBufferSize(): number {
    return MAXIMUM_WRITE_BUFFER_SIZE - this._outstandingWriteDataCount - this._directWrittenDataCount;
  }

  resize(cols: number, rows: number): void {
    this.realPty.resize(cols, rows);
  }
  
  destroy(): void {
    this._emitBufferSizeLater.cancel();
    this.realPty.destroy();
  }

  permittedDataSize(size: number): void {
    this._permittedDataSize = size;
    if (size > 0) {<commit_msg>Wait for the user when a unix session exits.<commit_after>/*
 * Copyright 2018 <NAME> <<EMAIL>>
 *
 * This source code is licensed under the MIT license which is detailed in the LICENSE.txt file.
 */
import {EventEmitter} from 'extraterm-event-emitter';
import {Event, BufferSizeChange, Pty, Logger, EnvironmentMap} from 'extraterm-extension-api';
import * as pty from 'node-pty';
import * as _ from 'lodash';


const MAXIMUM_WRITE_BUFFER_SIZE = 64 * 1024;

export interface PtyOptions {
  exe?: string;
  args?: string[];
  cols?: number;
  rows?: number;
  cwd?: string;
  env?: EnvironmentMap;
  preMessage?: string;
}

export class UnixPty implements Pty {

  private realPty: pty.IPty;
  private _permittedDataSize = 0;
  private _paused = true;
  private _waitingExitConfirmation = false;
  private _onDataEventEmitter = new EventEmitter<string>();
  private _onExitEventEmitter = new EventEmitter<void>();
  private _onAvailableWriteBufferSizeChangeEventEmitter = new EventEmitter<BufferSizeChange>();
  private _outstandingWriteDataCount = 0;
  private _emitBufferSizeLater: (() => void) & _.Cancelable = null;

  // Amount of data which went directly to the OS but still needs to 'announced' via an event.
  private _directWrittenDataCount = 0;

  onData: Event<string>;
  onExit: Event<void>;
  onAvailableWriteBufferSizeChange: Event<BufferSizeChange>;

  constructor(private _log: Logger, options: PtyOptions) {
    this.onData = this._onDataEventEmitter.event;
    this.onExit = this._onExitEventEmitter.event;
    this.onAvailableWriteBufferSizeChange = this._onAvailableWriteBufferSizeChangeEventEmitter.event;

    this.realPty = pty.spawn(options.exe, options.args, options);

    this.realPty.on('data', (data: any): void => {
      this._onDataEventEmitter.fire(data);
      this.permittedDataSize(this._permittedDataSize - data.length);
    });

    this.realPty.on('exit', () => {
      this._waitingExitConfirmation = true;
      this._onDataEventEmitter.fire("\n\n[Process exited. Press Enter to close terminal.]");
    });

    this.realPty.on("drain", () => {
      this._onAvailableWriteBufferSizeChangeEventEmitter.fire({
        totalBufferSize: MAXIMUM_WRITE_BUFFER_SIZE,
        availableDelta: this._outstandingWriteDataCount + this._directWrittenDataCount
      });
      this._directWrittenDataCount = 0;
      this._outstandingWriteDataCount = 0;
    });

    this._emitBufferSizeLater = _.throttle(this._emitAvailableWriteBufferSizeChange.bind(this), 0, {leading: false});

    this.realPty.pause();

    if (options.preMessage != null && options.preMessage !== "") {
      process.nextTick(() => {
        this._onDataEventEmitter.fire(options.preMessage);
      });
    }
  }

  write(data: string): void {
    if ( ! this._waitingExitConfirmation) {
      if (this.realPty._socket.write(data)) { // FIXME try to avoid using _socket directly. Upgraded node-pty is needed.
        this._directWrittenDataCount += data.length;
        this._emitBufferSizeLater();
      } else {
        this._outstandingWriteDataCount += data.length;
      }
    } else {
      // See if the user hit the Enter key to fully close the terminal.
      if (data.indexOf("\r") !== -1) {
        this._onExitEventEmitter.fire(undefined);
      }
    }
  }

  private _emitAvailableWriteBufferSizeChange(): void {
    if (this._directWrittenDataCount !== 0) {
      const writtenCount = this._directWrittenDataCount;
      this._directWrittenDataCount = 0;
      this._onAvailableWriteBufferSizeChangeEventEmitter.fire({
        totalBufferSize: MAXIMUM_WRITE_BUFFER_SIZE,
        availableDelta: writtenCount
      });
    }
  }

  getAvailableWriteBufferSize(): number {
    return MAXIMUM_WRITE_BUFFER_SIZE - this._outstandingWriteDataCount - this._directWrittenDataCount;
  }

  resize(cols: number, rows: number): void {
    this.realPty.resize(cols, rows);
  }

  destroy(): void {
    this._emitBufferSizeLater.cancel();
    this.realPty.destroy();
  }

  permittedDataSize(size: number): void {
    this._permittedDataSize = size;
    if (size > 0) {
{'fraction_non_alphanumeric': 0.11164233105052332, 'fraction_numerical': 0.005039410776586122, 'mean_word_length': 3.8557089084065246, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '664631', 'n_tokens_mistral': 2391, 'n_tokens_neox': 2316, 'n_words': 505}