xterm
[VSoRC/.git] / node_modules / xterm / src / browser / selection / SelectionModel.ts
diff --git a/node_modules/xterm/src/browser/selection/SelectionModel.ts b/node_modules/xterm/src/browser/selection/SelectionModel.ts
new file mode 100644 (file)
index 0000000..1420444
--- /dev/null
@@ -0,0 +1,135 @@
+/**
+ * Copyright (c) 2017 The xterm.js authors. All rights reserved.
+ * @license MIT
+ */
+
+import { IBufferService } from 'common/services/Services';
+
+/**
+ * Represents a selection within the buffer. This model only cares about column
+ * and row coordinates, not wide characters.
+ */
+export class SelectionModel {
+  /**
+   * Whether select all is currently active.
+   */
+  public isSelectAllActive: boolean = false;
+
+  /**
+   * The minimal length of the selection from the start position. When double
+   * clicking on a word, the word will be selected which makes the selection
+   * start at the start of the word and makes this variable the length.
+   */
+  public selectionStartLength: number = 0;
+
+  /**
+   * The [x, y] position the selection starts at.
+   */
+  public selectionStart: [number, number] | undefined;
+
+  /**
+   * The [x, y] position the selection ends at.
+   */
+  public selectionEnd: [number, number] | undefined;
+
+  constructor(
+    private _bufferService: IBufferService
+  ) {
+  }
+
+  /**
+   * Clears the current selection.
+   */
+  public clearSelection(): void {
+    this.selectionStart = undefined;
+    this.selectionEnd = undefined;
+    this.isSelectAllActive = false;
+    this.selectionStartLength = 0;
+  }
+
+  /**
+   * The final selection start, taking into consideration select all.
+   */
+  public get finalSelectionStart(): [number, number] | undefined {
+    if (this.isSelectAllActive) {
+      return [0, 0];
+    }
+
+    if (!this.selectionEnd || !this.selectionStart) {
+      return this.selectionStart;
+    }
+
+    return this.areSelectionValuesReversed() ? this.selectionEnd : this.selectionStart;
+  }
+
+  /**
+   * The final selection end, taking into consideration select all, double click
+   * word selection and triple click line selection.
+   */
+  public get finalSelectionEnd(): [number, number] | undefined {
+    if (this.isSelectAllActive) {
+      return [this._bufferService.cols, this._bufferService.buffer.ybase + this._bufferService.rows - 1];
+    }
+
+    if (!this.selectionStart) {
+      return undefined;
+    }
+
+    // Use the selection start + length if the end doesn't exist or they're reversed
+    if (!this.selectionEnd || this.areSelectionValuesReversed()) {
+      const startPlusLength = this.selectionStart[0] + this.selectionStartLength;
+      if (startPlusLength > this._bufferService.cols) {
+        return [startPlusLength % this._bufferService.cols, this.selectionStart[1] + Math.floor(startPlusLength / this._bufferService.cols)];
+      }
+      return [startPlusLength, this.selectionStart[1]];
+    }
+
+    // Ensure the the word/line is selected after a double/triple click
+    if (this.selectionStartLength) {
+      // Select the larger of the two when start and end are on the same line
+      if (this.selectionEnd[1] === this.selectionStart[1]) {
+        return [Math.max(this.selectionStart[0] + this.selectionStartLength, this.selectionEnd[0]), this.selectionEnd[1]];
+      }
+    }
+    return this.selectionEnd;
+  }
+
+  /**
+   * Returns whether the selection start and end are reversed.
+   */
+  public areSelectionValuesReversed(): boolean {
+    const start = this.selectionStart;
+    const end = this.selectionEnd;
+    if (!start || !end) {
+      return false;
+    }
+    return start[1] > end[1] || (start[1] === end[1] && start[0] > end[0]);
+  }
+
+  /**
+   * Handle the buffer being trimmed, adjust the selection position.
+   * @param amount The amount the buffer is being trimmed.
+   * @return Whether a refresh is necessary.
+   */
+  public onTrim(amount: number): boolean {
+    // Adjust the selection position based on the trimmed amount.
+    if (this.selectionStart) {
+      this.selectionStart[1] -= amount;
+    }
+    if (this.selectionEnd) {
+      this.selectionEnd[1] -= amount;
+    }
+
+    // The selection has moved off the buffer, clear it.
+    if (this.selectionEnd && this.selectionEnd[1] < 0) {
+      this.clearSelection();
+      return true;
+    }
+
+    // If the selection start is trimmed, ensure the start column is 0.
+    if (this.selectionStart && this.selectionStart[1] < 0) {
+      this.selectionStart[1] = 0;
+    }
+    return false;
+  }
+}