mirror of
https://git.proxmox.com/git/mirror_xterm.js
synced 2025-10-26 01:30:43 +00:00
Get selection partially rendering
This commit is contained in:
parent
b594407cd5
commit
ad3ae67e70
@ -20,6 +20,8 @@ export interface IBrowser {
|
|||||||
export interface ITerminal {
|
export interface ITerminal {
|
||||||
element: HTMLElement;
|
element: HTMLElement;
|
||||||
rowContainer: HTMLElement;
|
rowContainer: HTMLElement;
|
||||||
|
selectionContainer: HTMLElement;
|
||||||
|
charMeasure: ICharMeasure;
|
||||||
textarea: HTMLTextAreaElement;
|
textarea: HTMLTextAreaElement;
|
||||||
ybase: number;
|
ybase: number;
|
||||||
ydisp: number;
|
ydisp: number;
|
||||||
|
|||||||
@ -321,6 +321,68 @@ export class Renderer {
|
|||||||
|
|
||||||
public refreshSelection(start: [number, number], end: [number, number]) {
|
public refreshSelection(start: [number, number], end: [number, number]) {
|
||||||
console.log('renderer, refresh:', start, end);
|
console.log('renderer, refresh:', start, end);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap the start and end if necessary
|
||||||
|
if (start[1] > end[1] || (start[1] === end[1] && start[0] > end[0])) {
|
||||||
|
const temp = start;
|
||||||
|
start = end;
|
||||||
|
end = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate from buffer position to viewport position
|
||||||
|
const viewportStartRow = start[1] - this._terminal.ydisp;
|
||||||
|
const viewportEndRow = end[1] - this._terminal.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('viewportStartRow', viewportCappedStartRow);
|
||||||
|
console.log('viewportEndRow', viewportCappedEndRow);
|
||||||
|
|
||||||
|
// TODO: Only redraw selections when necessary
|
||||||
|
|
||||||
|
// 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
|
||||||
|
for (let i = viewportCappedStartRow + 1; i < viewportCappedEndRow; i++) {
|
||||||
|
documentFragment.appendChild(this._createSelectionElement(i, 0, this._terminal.cols));
|
||||||
|
}
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createSelectionElement(row: number, colStart: number, colEnd: number): HTMLElement {
|
||||||
|
const element = document.createElement('div');
|
||||||
|
// TODO: Move into a generated <style> element
|
||||||
|
element.style.height = `${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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,25 +6,23 @@ import { CharMeasure } from './utils/CharMeasure';
|
|||||||
import { CircularList } from './utils/CircularList';
|
import { CircularList } from './utils/CircularList';
|
||||||
import { EventEmitter } from './EventEmitter';
|
import { EventEmitter } from './EventEmitter';
|
||||||
import * as Mouse from './utils/Mouse';
|
import * as Mouse from './utils/Mouse';
|
||||||
|
import { ITerminal } from './Interfaces';
|
||||||
|
|
||||||
export class SelectionManager extends EventEmitter {
|
export class SelectionManager extends EventEmitter {
|
||||||
// TODO: Create a SelectionModel
|
// TODO: Create a SelectionModel
|
||||||
private _selectionStart: [number, number];
|
private _selectionStart: [number, number];
|
||||||
private _selectionEnd: [number, number];
|
private _selectionEnd: [number, number];
|
||||||
|
|
||||||
private _buffer: CircularList<any>;
|
|
||||||
private _rowContainer: HTMLElement;
|
|
||||||
private _selectionContainer: HTMLElement;
|
|
||||||
private _charMeasure: CharMeasure;
|
|
||||||
|
|
||||||
private _mouseMoveListener: EventListener;
|
private _mouseMoveListener: EventListener;
|
||||||
|
|
||||||
constructor(buffer: CircularList<any>, rowContainer: HTMLElement, selectionContainer: HTMLElement, charMeasure: CharMeasure) {
|
constructor(
|
||||||
|
private _terminal: ITerminal,
|
||||||
|
private _buffer: CircularList<any>,
|
||||||
|
private _rowContainer: HTMLElement,
|
||||||
|
private _selectionContainer: HTMLElement,
|
||||||
|
private _charMeasure: CharMeasure
|
||||||
|
) {
|
||||||
super();
|
super();
|
||||||
this._rowContainer = rowContainer;
|
|
||||||
this._selectionContainer = selectionContainer;
|
|
||||||
this._buffer = buffer;
|
|
||||||
this._charMeasure = charMeasure;
|
|
||||||
this._attachListeners();
|
this._attachListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,8 +47,6 @@ export class SelectionManager extends EventEmitter {
|
|||||||
public refresh(): void {
|
public refresh(): void {
|
||||||
// TODO: Figure out when to refresh the selection vs when to refresh the viewport
|
// TODO: Figure out when to refresh the selection vs when to refresh the viewport
|
||||||
this.emit('refresh', { start: this._selectionStart, end: this._selectionEnd });
|
this.emit('refresh', { start: this._selectionStart, end: this._selectionEnd });
|
||||||
console.log(`Selection: Start: (${this._selectionStart[0]}, ${this._selectionStart[1]}), End: (${this._selectionEnd[0]}, ${this._selectionEnd[1]})`);
|
|
||||||
this._selectionContainer.innerHTML = `<div><br><br></div>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,14 +81,21 @@ export class SelectionManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _getMouseBufferCoords(event: MouseEvent) {
|
private _getMouseBufferCoords(event: MouseEvent) {
|
||||||
// TODO: Take into account the current terminal viewport when fetching coordinates
|
const coords = Mouse.getCoords(event, this._rowContainer, this._charMeasure);
|
||||||
return Mouse.getCoords(event, this._rowContainer, this._charMeasure);
|
// Convert to 0-based
|
||||||
|
coords[0]--;
|
||||||
|
coords[1]--;
|
||||||
|
// Convert viewport coords to buffer coords
|
||||||
|
coords[1] += this._terminal.ydisp;
|
||||||
|
return coords;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onMouseDown(event: MouseEvent) {
|
private _onMouseDown(event: MouseEvent) {
|
||||||
this._selectionStart = this._getMouseBufferCoords(event);
|
this._selectionStart = this._getMouseBufferCoords(event);
|
||||||
if (this._selectionStart) {
|
if (this._selectionStart) {
|
||||||
|
this._selectionEnd = null;
|
||||||
this._rowContainer.addEventListener('mousemove', this._mouseMoveListener);
|
this._rowContainer.addEventListener('mousemove', this._mouseMoveListener);
|
||||||
|
this.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -190,6 +190,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.terminal .xterm-selection div {
|
.terminal .xterm-selection div {
|
||||||
|
position: absolute;
|
||||||
background-color: #777;
|
background-color: #777;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -697,8 +697,12 @@ Terminal.prototype.open = function(parent, focus) {
|
|||||||
|
|
||||||
this.viewport = new Viewport(this, this.viewportElement, this.viewportScrollArea, this.charMeasure);
|
this.viewport = new Viewport(this, this.viewportElement, this.viewportScrollArea, this.charMeasure);
|
||||||
this.renderer = new Renderer(this);
|
this.renderer = new Renderer(this);
|
||||||
this.selectionManager = new SelectionManager(this.lines, this.rowContainer, this.selectionContainer, this.charMeasure);
|
this.selectionManager = new SelectionManager(this, this.lines, this.rowContainer, this.selectionContainer, this.charMeasure);
|
||||||
this.selectionManager.on('refresh', data => this.renderer.refreshSelection(data.start, data.end));
|
this.selectionManager.on('refresh', data => this.renderer.refreshSelection(data.start, data.end));
|
||||||
|
this.on('scroll', () => {
|
||||||
|
console.log('scroll');
|
||||||
|
this.selectionManager.refresh();
|
||||||
|
});
|
||||||
|
|
||||||
// Setup loop that draws to screen
|
// Setup loop that draws to screen
|
||||||
this.refresh(0, this.rows - 1);
|
this.refresh(0, this.rows - 1);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user