]> git.proxmox.com Git - mirror_xterm.js.git/commitdiff
Resize both buffers on resize
authorDaniel Imms <daimms@microsoft.com>
Sun, 6 Aug 2017 01:59:42 +0000 (18:59 -0700)
committerDaniel Imms <daimms@microsoft.com>
Sun, 6 Aug 2017 01:59:44 +0000 (18:59 -0700)
This brings in proper support to resize both buffers (#510) and fixes an
exception that was caused by wrongfully not clearing the normal buffer when
resizing while the alt buffer is active.

There was an obscure bug in this that could have caused some great confusion
later on; When switching to the alt buffer, a hard terminal reset was performed
which tried to retain the buffers. However, because buffers was initialized in
the Terminal constructor to a new BufferSet, the Terminal.buffer convenience
pointer was pointing at a stale alt buffer which was the one actually being
used, not Terminal.buffers.alt.

Fixes #842
Fixes #510

src/Buffer.ts
src/BufferSet.ts
src/Interfaces.ts
src/xterm.js

index 12b2137d6cde201580ff3c94563933a3b05f638c..bd3645e7f85c9d80f3de50aeffdf11d984cf12d9 100644 (file)
@@ -13,21 +13,21 @@ import { CircularList } from './utils/CircularList';
  *   - scroll position
  */
 export class Buffer {
-  public lines: CircularList<[number, string, number][]>;
+  public readonly lines: CircularList<[number, string, number][]>;
 
   public savedY: number;
   public savedX: number;
 
   /**
    * Create a new Buffer.
-   * @param {Terminal} terminal - The terminal the Buffer will belong to
+   * @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,
+    private _terminal: ITerminal,
     public ydisp: number = 0,
     public ybase: number = 0,
     public y: number = 0,
@@ -36,7 +36,78 @@ export class Buffer {
     public scrollTop: number = 0,
     public tabs: any = {},
   ) {
-    this.lines = new CircularList<[number, string, number][]>(this.terminal.scrollback);
-    this.scrollBottom = this.terminal.rows - 1;
+    this.lines = new CircularList<[number, string, number][]>(this._terminal.scrollback);
+    this.scrollBottom = this._terminal.rows - 1;
+  }
+
+  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++) {
+        if (this.lines.get(i) === undefined) {
+          this.lines.set(i, this._terminal.blankLine());
+        }
+        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());
+          }
+        }
+      }
+    } 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;
   }
 }
index e86c098f5fb6b136ed736dee8b80aa85e26c1496..4a65dbfe16e984aa3da41e29da225dea681aa8c4 100644 (file)
@@ -65,4 +65,9 @@ export class BufferSet extends EventEmitter implements IBufferSet {
     this._activeBuffer = this._alt;
     this.emit('activate', this._alt);
   }
+
+  public resize(newCols: number, newRows: number): void {
+    this._normal.resize(newCols, newRows);
+    this._alt.resize(newCols, newRows);
+  }
 }
index f19a7f28f8f4af5337dfed4c99861c3e1e6787fa..d463fcb795dbccd388e8da60f07bcbc71750bdb2 100644 (file)
@@ -48,6 +48,7 @@ export interface ITerminal {
   emit(event: string, data: any);
   reset(): void;
   showCursor(): void;
+  blankLine(cur?: boolean, isWrapped?: boolean);
 }
 
 export interface IBuffer {
index 5aa069e796c688b291265b60ae1d1920291a772c..92fc0df83586c21c841e6497d076370d0edd7762 100644 (file)
@@ -221,7 +221,7 @@ function Terminal(options) {
   this.surrogate_high = '';
 
   // Create the terminal's buffers and set the current buffer
-  this.buffers = new BufferSet(this);
+  this.buffers = this.buffers || new BufferSet(this);
   this.buffer = this.buffers.active;  // Convenience shortcut;
   this.buffers.on('activate', function (buffer) {
     this._terminal.buffer = buffer;
@@ -1930,86 +1930,21 @@ Terminal.prototype.resize = function(x, y) {
   if (x < 1) x = 1;
   if (y < 1) y = 1;
 
-  // resize cols
-  j = this.cols;
-  if (j < x) {
-    ch = [this.defAttr, ' ', 1]; // does xterm use the default attr?
-    i = this.buffer.lines.length;
-    while (i--) {
-      if (this.buffer.lines.get(i) === undefined) {
-        this.buffer.lines.set(i, this.blankLine());
-      }
-      while (this.buffer.lines.get(i).length < x) {
-        this.buffer.lines.get(i).push(ch);
-      }
-    }
-  }
-
-  this.cols = x;
-  this.setupStops(this.cols);
+  this.buffers.resize(x, y);
 
-  // resize rows
-  j = this.rows;
-  addToY = 0;
-  if (j < y) {
-    el = this.element;
-    while (j++ < y) {
-      // y is rows, not this.buffer.y
-      if (this.buffer.lines.length < y + this.buffer.ybase) {
-        if (this.buffer.ybase > 0 && this.buffer.lines.length <= this.buffer.ybase + this.buffer.y + addToY + 1) {
-          // There is room above the buffer and there are no empty elements below the line,
-          // scroll up
-          this.buffer.ybase--;
-          addToY++;
-          if (this.buffer.ydisp > 0) {
-            // Viewport is at the top of the buffer, must increase downwards
-            this.buffer.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.buffer.lines.push(this.blankLine());
-        }
-      }
-      if (this.children.length < y) {
-        this.insertRow();
-      }
-    }
-  } else { // (j > y)
-    while (j-- > y) {
-      if (this.buffer.lines.length > y + this.buffer.ybase) {
-        if (this.buffer.lines.length > this.buffer.ybase + this.buffer.y + 1) {
-          // The line is a blank line below the cursor, remove it
-          this.buffer.lines.pop();
-        } else {
-          // The line is the cursor, scroll down
-          this.buffer.ybase++;
-          this.buffer.ydisp++;
-        }
-      }
-      if (this.children.length > y) {
-        el = this.children.shift();
-        if (!el) continue;
-        el.parentNode.removeChild(el);
-      }
-    }
-  }
-  this.rows = y;
-
-  // Make sure that the cursor stays on screen
-  if (this.buffer.y >= y) {
-    this.buffer.y = y - 1;
-  }
-  if (addToY) {
-    this.buffer.y += addToY;
+  // Adjust rows in the DOM to accurately reflect the new dimensions
+  while (this.children.length < y) {
+    this.insertRow();
   }
-
-  if (this.buffer.x >= x) {
-    this.buffer.x = x - 1;
+  while (this.children.length > y) {
+    el = this.children.shift();
+    if (!el) continue;
+    el.parentNode.removeChild(el);
   }
 
-  this.buffer.scrollTop = 0;
-  this.buffer.scrollBottom = y - 1;
+  this.cols = x;
+  this.rows = y;
+  this.setupStops(this.cols);
 
   this.charMeasure.measure();