]> git.proxmox.com Git - mirror_xterm.js.git/blobdiff - src/Renderer.ts
Merge branch 'master' into faster_wcwidth
[mirror_xterm.js.git] / src / Renderer.ts
index 78ca3574323df95c33b4408b5f6cf02f77105e51..db4d6a63b5cd4502fa6e8b226b95f15d8004e2ca 100644 (file)
@@ -139,28 +139,28 @@ export class Renderer {
     }
 
     for (; y <= end; y++) {
-      let row = y + this._terminal.ydisp;
+      let row = y + this._terminal.buffer.ydisp;
 
-      let line = this._terminal.lines.get(row);
+      let line = this._terminal.buffer.lines.get(row);
 
       let x;
-      if (this._terminal.y === y - (this._terminal.ybase - this._terminal.ydisp) &&
+      if (this._terminal.buffer.y === y - (this._terminal.buffer.ybase - this._terminal.buffer.ydisp) &&
           this._terminal.cursorState &&
           !this._terminal.cursorHidden) {
-        x = this._terminal.x;
+        x = this._terminal.buffer.x;
       } else {
         x = -1;
       }
 
       let attr = this._terminal.defAttr;
 
-      var documentFragment = document.createDocumentFragment();
-      var innerHTML = '';
-      var currentElement;
+      const documentFragment = document.createDocumentFragment();
+      let innerHTML = '';
+      let currentElement;
 
       // Return the row's spans to the pool
       while (this._terminal.children[y].children.length) {
-        var child = this._terminal.children[y].children[0];
+        const child = this._terminal.children[y].children[0];
         this._terminal.children[y].removeChild(child);
         this._spanElementObjectPool.release(<HTMLElement>child);
       }
@@ -168,8 +168,8 @@ export class Renderer {
       for (let i = 0; i < width; i++) {
         // TODO: Could data be a more specific type?
         let data: any = line[i][0];
-        let ch = line[i][1];
-        let ch_width: any = line[i][2];
+        const ch = line[i][1];
+        const ch_width: any = line[i][2];
         if (!ch_width) {
           continue;
         }
@@ -200,7 +200,8 @@ export class Renderer {
             }
             currentElement = this._spanElementObjectPool.acquire();
             if (data === -1) {
-              currentElement.classList.add('reverse-video', 'terminal-cursor');
+              currentElement.classList.add('reverse-video');
+              currentElement.classList.add('terminal-cursor');
             } else {
               let bg = data & 0x1ff;
               let fg = (data >> 9) & 0x1ff;
@@ -247,27 +248,28 @@ export class Renderer {
                * Source: https://github.com/sourcelair/xterm.js/issues/57
                */
               if (flags & FLAGS.INVERSE) {
-                if (bg == 257) {
+                if (bg === 257) {
                   bg = 15;
                 }
-                if (fg == 256) {
+                if (fg === 256) {
                   fg = 0;
                 }
               }
 
               if (bg < 256) {
-                currentElement.classList.add('xterm-bg-color-' + bg);
+                currentElement.classList.add(`xterm-bg-color-${bg}`);
               }
 
               if (fg < 256) {
-                currentElement.classList.add('xterm-color-' + fg);
+                currentElement.classList.add(`xterm-color-${fg}`);
               }
             }
           }
         }
 
         if (ch_width === 2) {
-          // Wrap wide characters so they're sized correctly
+          // Wrap wide characters so they're sized correctly. It's more difficult to release these
+          // from the object pool so just create new ones via innerHTML.
           innerHTML += `<span class="xterm-wide-char">${ch}</span>`;
         } else if (ch.charCodeAt(0) > 255) {
           // Wrap any non-wide unicode character as some fonts size them badly
@@ -308,7 +310,7 @@ export class Renderer {
         currentElement = null;
       }
 
-      this._terminal.children[y].appendChild(documentFragment)
+      this._terminal.children[y].appendChild(documentFragment);
     }
 
     if (parent) {
@@ -317,11 +319,70 @@ export class Renderer {
 
     this._terminal.emit('refresh', {element: this._terminal.element, start: start, end: end});
   };
+
+  /**
+   * Refreshes the selection in the DOM.
+   * @param start The selection start.
+   * @param end The selection end.
+   */
+  public refreshSelection(start: [number, number], end: [number, number]) {
+    // Remove all selections
+    while (this._terminal.selectionContainer.children.length) {
+      this._terminal.selectionContainer.removeChild(this._terminal.selectionContainer.children[0]);
+    }
+
+    // Selection does not exist
+    if (!start || !end) {
+      return;
+    }
+
+    // Translate from buffer position to viewport position
+    const viewportStartRow = start[1] - this._terminal.buffer.ydisp;
+    const viewportEndRow = end[1] - this._terminal.buffer.ydisp;
+    const viewportCappedStartRow = Math.max(viewportStartRow, 0);
+    const viewportCappedEndRow = Math.min(viewportEndRow, this._terminal.rows - 1);
+
+    // No need to draw the selection
+    if (viewportCappedStartRow >= this._terminal.rows || viewportCappedEndRow < 0) {
+      return;
+    }
+
+    // Create the selections
+    const documentFragment = document.createDocumentFragment();
+    // Draw first row
+    const startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0;
+    const endCol = viewportCappedStartRow === viewportCappedEndRow ? end[0] : this._terminal.cols;
+    documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow, startCol, endCol));
+    // Draw middle rows
+    const middleRowsCount = viewportCappedEndRow - viewportCappedStartRow - 1;
+    documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow + 1, 0, this._terminal.cols, middleRowsCount));
+    // Draw final row
+    if (viewportCappedStartRow !== viewportCappedEndRow) {
+      // Only draw viewportEndRow if it's not the same as viewporttartRow
+      const endCol = viewportEndRow === viewportCappedEndRow ? end[0] : this._terminal.cols;
+      documentFragment.appendChild(this._createSelectionElement(viewportCappedEndRow, 0, endCol));
+    }
+    this._terminal.selectionContainer.appendChild(documentFragment);
+  }
+
+  /**
+   * Creates a selection element at the specified position.
+   * @param row The row of the selection.
+   * @param colStart The start column.
+   * @param colEnd The end columns.
+   */
+  private _createSelectionElement(row: number, colStart: number, colEnd: number, rowCount: number = 1): HTMLElement {
+    const element = document.createElement('div');
+    element.style.height = `${rowCount * this._terminal.charMeasure.height}px`;
+    element.style.top = `${row * this._terminal.charMeasure.height}px`;
+    element.style.left = `${colStart * this._terminal.charMeasure.width}px`;
+    element.style.width = `${this._terminal.charMeasure.width * (colEnd - colStart)}px`;
+    return element;
+  }
 }
 
 
-// if bold is broken, we can't
-// use it in the terminal.
+// If bold is broken, we can't use it in the terminal.
 function checkBoldBroken(terminal) {
   const document = terminal.ownerDocument;
   const el = document.createElement('span');