]> git.proxmox.com Git - mirror_xterm.js.git/blobdiff - src/Buffer.ts
Merge pull request #926 from ficristo/search-fix
[mirror_xterm.js.git] / src / Buffer.ts
index 65e1d99d878bc91c4943d6b4fc8b66296655f0fd..d64a92bb193ebd448104dbde0a6a906da61f5dc3 100644 (file)
  * @license MIT
  */
 
-import { ITerminal } from './Interfaces';
+import { ITerminal, IBuffer } from './Interfaces';
 import { CircularList } from './utils/CircularList';
 
 /**
- * This class represents a terminal buffer (an internal state of the terminal)/
+ * This class represents a terminal buffer (an internal state of the terminal), where the
+ * following information is stored (in high-level):
+ *   - text content of this particular buffer
+ *   - cursor position
+ *   - scroll position
  */
-export class Buffer {
-  public lines: CircularList<string>;
+export class Buffer implements IBuffer {
+  private _lines: CircularList<[number, string, number][]>;
+
+  public ydisp: number;
+  public ybase: number;
+  public y: number;
+  public x: number;
+  public scrollBottom: number;
+  public scrollTop: number;
+  public tabs: any;
+  public savedY: number;
+  public savedX: number;
 
   /**
    * Create a new Buffer.
-   * @param {Terminal} terminal - The terminal the buffer will belong to
-   * @param {number} ydisp - The scroll position of the buffer in the viewport
-   * @param {number} ybase - The scroll position of the y cursor (ybase + y = the y position within the buffer)
+   * @param {Terminal} _terminal - The terminal the Buffer will belong to
+   * @param {number} ydisp - The scroll position of the Buffer in the viewport
+   * @param {number} ybase - The scroll position of the y cursor (ybase + y = the y position within the Buffer)
    * @param {number} y - The cursor's y position after ybase
    * @param {number} x - The cursor's x position after ybase
    */
   constructor(
-    private terminal: ITerminal,
-    public ydisp: number = 0,
-    public ybase: number = 0,
-    public y: number = 0,
-    public x: number = 0,
-    public scrollBottom: number = 0,
-    public scrollTop: number = 0,
-    public tabs: any = {},
+    private _terminal: ITerminal
   ) {
-    this.lines = new CircularList<[string, number, string]>(this.terminal.scrollback);
-    this.scrollBottom = this.terminal.rows - 1;
+    this.clear();
+  }
+
+  public get lines(): CircularList<[number, string, number][]> {
+    return this._lines;
+  }
+
+  /**
+   * Fills the buffer's viewport with blank lines.
+   */
+  public fillViewportRows(): void {
+    if (this._lines.length === 0) {
+      let i = this._terminal.rows;
+      while (i--) {
+        this.lines.push(this._terminal.blankLine());
+      }
+    }
+  }
+
+  /**
+   * Clears the buffer to it's initial state, discarding all previous data.
+   */
+  public clear(): void {
+    this.ydisp = 0;
+    this.ybase = 0;
+    this.y = 0;
+    this.x = 0;
+    this.scrollBottom = 0;
+    this.scrollTop = 0;
+    this.tabs = {};
+    this._lines = new CircularList<[number, string, number][]>(this._terminal.scrollback);
+    this.scrollBottom = this._terminal.rows - 1;
+  }
+
+  /**
+   * Resizes the buffer, adjusting its data accordingly.
+   * @param newCols The new number of columns.
+   * @param newRows The new number of rows.
+   */
+  public resize(newCols: number, newRows: number): void {
+    // Don't resize the buffer if it's empty and hasn't been used yet.
+    if (this._lines.length === 0) {
+      return;
+    }
+
+    // Deal with columns increasing (we don't do anything when columns reduce)
+    if (this._terminal.cols < newCols) {
+      const ch: [number, string, number] = [this._terminal.defAttr, ' ', 1]; // does xterm use the default attr?
+      for (let i = 0; i < this._lines.length; i++) {
+        // TODO: This should be removed, with tests setup for the case that was
+        // causing the underlying bug, see https://github.com/sourcelair/xterm.js/issues/824
+        if (this._lines.get(i) === undefined) {
+          this._lines.set(i, this._terminal.blankLine(undefined, undefined, newCols));
+        }
+        while (this._lines.get(i).length < newCols) {
+          this._lines.get(i).push(ch);
+        }
+      }
+    }
+
+    // Resize rows in both directions as needed
+    let addToY = 0;
+    if (this._terminal.rows < newRows) {
+      for (let y = this._terminal.rows; y < newRows; y++) {
+        if (this._lines.length < newRows + this.ybase) {
+          if (this.ybase > 0 && this._lines.length <= this.ybase + this.y + addToY + 1) {
+            // There is room above the buffer and there are no empty elements below the line,
+            // scroll up
+            this.ybase--;
+            addToY++;
+            if (this.ydisp > 0) {
+              // Viewport is at the top of the buffer, must increase downwards
+              this.ydisp--;
+            }
+          } else {
+            // Add a blank line if there is no buffer left at the top to scroll to, or if there
+            // are blank lines after the cursor
+            this._lines.push(this._terminal.blankLine(undefined, undefined, newCols));
+          }
+        }
+      }
+    } else { // (this._terminal.rows >= newRows)
+      for (let y = this._terminal.rows; y > newRows; y--) {
+        if (this._lines.length > newRows + this.ybase) {
+          if (this._lines.length > this.ybase + this.y + 1) {
+            // The line is a blank line below the cursor, remove it
+            this._lines.pop();
+          } else {
+            // The line is the cursor, scroll down
+            this.ybase++;
+            this.ydisp++;
+          }
+        }
+      }
+    }
+
+    // Make sure that the cursor stays on screen
+    if (this.y >= newRows) {
+      this.y = newRows - 1;
+    }
+    if (addToY) {
+      this.y += addToY;
+    }
+
+    if (this.x >= newCols) {
+      this.x = newCols - 1;
+    }
+
+    this.scrollTop = 0;
+    this.scrollBottom = newRows - 1;
   }
 }