mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Merge remote-tracking branch 'origin/master' into 1118_dpi_change
This commit is contained in:
@@ -19,45 +19,63 @@ Bill Church <billchurch@users.noreply.github.com>
|
||||
Bob Reid <bobreid@Bobs-MacBook-Pro.local>
|
||||
bottleofwater <nison.mael+bottleofwater@gmail.com>
|
||||
Brian Mock <brian@mockbrian.com>
|
||||
Bruno Ribeito <b.m.fernandes.ribeiro@gmail.com>
|
||||
Carson Anderson <carson@betterservers.com>
|
||||
CHaBou <chabup@delean.fr>
|
||||
Christian Budde Christensen <budde377@gmail.com>
|
||||
Christof Marti <chrmarti@microsoft.com>
|
||||
Christopher Jeffrey <chjjeffrey@gmail.com>
|
||||
coderaiser <mnemonic.enemy@gmail.com>
|
||||
Dan Brown <jdanbrown@gmail.com>
|
||||
Daniel Griffen <daniel@griffen.io>
|
||||
Daniel Imms <daimms@microsoft.com>
|
||||
Daniel Risacher <drisacher@gmail.com>
|
||||
Dan Kaplun <dbkaplun@twitch.tv>
|
||||
Darin Morrison <freebroccolo@users.noreply.github.com>
|
||||
dcylabs <dcylabs@gmail.com>
|
||||
Dominik Csapak <d.csapak@proxmox.com>
|
||||
Edgar Andrés Margffoy Tuay <andfoy@gmail.com>
|
||||
Elliot Saba <staticfloat@gmail.com>
|
||||
Exile <exile@chamber.ee>
|
||||
Felipe Gasper <felipe@felipegasper.com>
|
||||
ficristo <ficristo.work@gmail.com>
|
||||
Gary Ritchie <gary@rstudio.com>
|
||||
hiro-su <h.sugipon@gmail.com>
|
||||
Ian Lewis <ianlewis@google.com>
|
||||
imoses <ido@twiggle.com>
|
||||
InDieTasten <indietasten@gmail.com>
|
||||
irokas <akasidiari@inf.uth.gr>
|
||||
Jakob Gillich <jakob@gillich.me>
|
||||
Jean Bruenn <himself@jeanbruenn.info>
|
||||
Jeremy Danyow <jedanyow@microsoft.com>
|
||||
Joao Moreno <jomo@microsoft.com>
|
||||
Joao Moreno <mail@joaomoreno.com>
|
||||
Johannes Zellner <johannes@nebulon.de>
|
||||
Jon Masters <jon.masters@sky.com>
|
||||
Jörg Breitbart <jerch@rockborn.de>
|
||||
Justin Mecham <justin@mecham.me>
|
||||
Kirill Merkushev <lanwen@yandex.ru>
|
||||
Luca <LucaT1@users.noreply.github.com>
|
||||
Lucian Buzzo <lucian.buzzo@gmail.com>
|
||||
Lukas Drgon <lukas.drgon@gmail.com>
|
||||
Maël Nison <nison.mael@gmail.com>
|
||||
Marc Dumais <marc.dumais@ericsson.com>
|
||||
Martin Chloride <i@martincl2.me>
|
||||
Martin Koppehel <martin.koppehel@st.ovgu.de>
|
||||
Martin Wang <jiahaow@ca.ibm.com>
|
||||
Matt Bierner <matb@microsoft.com>
|
||||
Michael Irwin <mikesir87@gmail.com>
|
||||
Mikko Karvonen <mikko.karvonen@arm.com>
|
||||
mofux <t.zilz@mofux.org>
|
||||
Nicolas Ramz <nicolas.ramz@gmail.com>
|
||||
npezza93 <npezza93@gmail.com>
|
||||
Oleksandr Andriienko <oandriie@redhat.com>
|
||||
Paris Kasidiaris <pariskasidiaris@gmail.com>
|
||||
Paris Kasidiaris <paris@sourcelair.com>
|
||||
Peter Baumgarten <me@peterbaumgarten.com>
|
||||
Rick Baker <rick@ricktbaker.com>
|
||||
runarberg <runar@greenqloud.com>
|
||||
Samuel Williams <samuel.williams@oriontransfer.co.nz>
|
||||
Saswat Das <saswatds@users.noreply.github.com>
|
||||
Saul Costa <saul@codevolve.com>
|
||||
Shuanglei Tao <tsl0922@gmail.com>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# [](https://xtermjs.org)
|
||||
|
||||
[](https://travis-ci.org/sourcelair/xterm.js) [](https://coveralls.io/github/sourcelair/xterm.js) [](https://gitter.im/sourcelair/xterm.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [](https://www.jsdelivr.com/package/npm/xterm)
|
||||
[](https://travis-ci.org/xtermjs/xterm.js) [](https://coveralls.io/github/sourcelair/xterm.js) [](https://gitter.im/sourcelair/xterm.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [](https://www.jsdelivr.com/package/npm/xterm)
|
||||
|
||||
Xterm.js is a terminal front-end component written in JavaScript that works in the browser.
|
||||
|
||||
@@ -115,6 +115,11 @@ computational environment for Jupyter, supporting interactive data science and s
|
||||
- [**Theia**](https://github.com/theia-ide/theia): Theia is a cloud & desktop IDE framework implemented in TypeScript.
|
||||
- [**Opshell**](https://github.com/ricktbaker/opshell) Ops Helper tool to make life easier working with AWS instances across multiple organizations.
|
||||
- [**Proxmox VE**](https://www.proxmox.com/en/proxmox-ve): Proxmox VE is a complete open-source platform for enterprise virtualization. It uses xterm.js for container terminals and the host shell.
|
||||
- [**Script Runner**](https://github.com/ioquatix/script-runner): Run scripts (or a shell) in Atom.
|
||||
- [**Whack Whack Terminal**](https://github.com/Microsoft/WhackWhackTerminal): Terminal emulator for Visual Studio 2017.
|
||||
- [**VTerm**](https://github.com/vterm/vterm): Extensible terminal emulator based on Electron and React.
|
||||
- [**electerm**](http://electerm.html5beta.com): electerm is a terminal/ssh/sftp client(mac, win, linux) based on electron/node-pty/xterm.
|
||||
- [**Kubebox**](https://github.com/astefanutti/kubebox): Terminal console for Kubernetes clusters.
|
||||
|
||||
Do you use xterm.js in your application as well? Please [open a Pull Request](https://github.com/sourcelair/xterm.js/pulls) to include it here. We would love to have it in our list.
|
||||
|
||||
|
||||
+4
-3
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "xterm",
|
||||
"description": "Full xterm terminal, in your browser",
|
||||
"version": "2.9.1",
|
||||
"version": "3.0.0",
|
||||
"ignore": [
|
||||
"demo",
|
||||
"test",
|
||||
@@ -9,7 +9,7 @@
|
||||
],
|
||||
"main": "lib/Terminal.js",
|
||||
"types": "typings/xterm.d.ts",
|
||||
"repository": "https://github.com/sourcelair/xterm.js",
|
||||
"repository": "https://github.com/xtermjs/xterm.js",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"*.js",
|
||||
@@ -35,7 +35,8 @@
|
||||
"src/*.ts",
|
||||
"src/**/*.js",
|
||||
"src/**/*.js.map",
|
||||
"src/**/*.ts"
|
||||
"src/**/*.ts",
|
||||
"typings/*.d.ts"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/chai": "^3.4.34",
|
||||
|
||||
@@ -286,36 +286,43 @@ export class Parser {
|
||||
// Single Shift Select of G2 Character Set
|
||||
// ( SS2 is 0x8e). This affects next character only.
|
||||
case 'N':
|
||||
this._state = ParserState.NORMAL;
|
||||
break;
|
||||
// ESC O
|
||||
// Single Shift Select of G3 Character Set
|
||||
// ( SS3 is 0x8f). This affects next character only.
|
||||
case 'O':
|
||||
this._state = ParserState.NORMAL;
|
||||
break;
|
||||
// ESC n
|
||||
// Invoke the G2 Character Set as GL (LS2).
|
||||
case 'n':
|
||||
this._terminal.setgLevel(2);
|
||||
this._state = ParserState.NORMAL;
|
||||
break;
|
||||
// ESC o
|
||||
// Invoke the G3 Character Set as GL (LS3).
|
||||
case 'o':
|
||||
this._terminal.setgLevel(3);
|
||||
this._state = ParserState.NORMAL;
|
||||
break;
|
||||
// ESC |
|
||||
// Invoke the G3 Character Set as GR (LS3R).
|
||||
case '|':
|
||||
this._terminal.setgLevel(3);
|
||||
this._state = ParserState.NORMAL;
|
||||
break;
|
||||
// ESC }
|
||||
// Invoke the G2 Character Set as GR (LS2R).
|
||||
case '}':
|
||||
this._terminal.setgLevel(2);
|
||||
this._state = ParserState.NORMAL;
|
||||
break;
|
||||
// ESC ~
|
||||
// Invoke the G1 Character Set as GR (LS1R).
|
||||
case '~':
|
||||
this._terminal.setgLevel(1);
|
||||
this._state = ParserState.NORMAL;
|
||||
break;
|
||||
|
||||
// ESC 7 Save Cursor (DECSC).
|
||||
|
||||
@@ -14,6 +14,10 @@ import { BufferSet } from './BufferSet';
|
||||
import { MockTerminal } from './utils/TestUtils.test';
|
||||
import { LineData, CharData } from './Types';
|
||||
|
||||
class TestMockTerminal extends MockTerminal {
|
||||
emit(event: string, data: any): void {}
|
||||
}
|
||||
|
||||
class TestSelectionManager extends SelectionManager {
|
||||
constructor(
|
||||
terminal: ITerminal,
|
||||
@@ -48,7 +52,7 @@ describe('SelectionManager', () => {
|
||||
dom = new jsdom.JSDOM('');
|
||||
window = dom.window;
|
||||
document = window.document;
|
||||
terminal = new MockTerminal();
|
||||
terminal = new TestMockTerminal();
|
||||
terminal.cols = 80;
|
||||
terminal.rows = 2;
|
||||
terminal.options.scrollback = 100;
|
||||
|
||||
@@ -255,7 +255,7 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
|
||||
public selectAll(): void {
|
||||
this._model.isSelectAllActive = true;
|
||||
this.refresh();
|
||||
this.emit('selection');
|
||||
this._terminal.emit('selection');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -528,7 +528,7 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
|
||||
this._terminal.scrollLines(this._dragScrollAmount, false);
|
||||
// Re-evaluate selection
|
||||
if (this._dragScrollAmount > 0) {
|
||||
this._model.selectionEnd = [this._terminal.cols - 1, this._terminal.buffer.ydisp + this._terminal.rows];
|
||||
this._model.selectionEnd = [this._terminal.cols - 1, Math.min(this._terminal.buffer.ydisp + this._terminal.rows, this._terminal.buffer.lines.length - 1)];
|
||||
} else {
|
||||
this._model.selectionEnd = [0, this._terminal.buffer.ydisp];
|
||||
}
|
||||
@@ -544,7 +544,7 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
|
||||
this._removeMouseDownListeners();
|
||||
|
||||
if (this.hasSelection)
|
||||
this.emit('selection');
|
||||
this._terminal.emit('selection');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1448,6 +1448,9 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
|
||||
if (ev.shiftKey) {
|
||||
result.key = C0.BS; // ^H
|
||||
break;
|
||||
} else if (ev.altKey) {
|
||||
result.key = C0.ESC + C0.DEL; // \e ^?
|
||||
break;
|
||||
}
|
||||
result.key = C0.DEL; // ^?
|
||||
break;
|
||||
|
||||
@@ -59,6 +59,9 @@ export function attach(term, socket, bidirectional, buffered) {
|
||||
};
|
||||
|
||||
term._sendData = function(data) {
|
||||
if (socket.readyState !== 1) {
|
||||
return;
|
||||
}
|
||||
socket.send(data);
|
||||
};
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ export function proposeGeometry(term) {
|
||||
};
|
||||
|
||||
export function fit(term) {
|
||||
var geometry = exports.proposeGeometry(term);
|
||||
var geometry = proposeGeometry(term);
|
||||
if (geometry) {
|
||||
// Force a full render
|
||||
if (term.rows !== geometry.rows || term.cols !== geometry.cols) {
|
||||
|
||||
@@ -23,6 +23,8 @@ export class Renderer extends EventEmitter implements IRenderer {
|
||||
private _renderLayers: IRenderLayer[];
|
||||
private _devicePixelRatio: number;
|
||||
private _screenDprMonitor: ScreenDprMonitor;
|
||||
private _isPaused: boolean = false;
|
||||
private _needsFullRefresh: boolean = false;
|
||||
|
||||
public colorManager: ColorManager;
|
||||
public dimensions: IRenderDimensions;
|
||||
@@ -58,6 +60,20 @@ export class Renderer extends EventEmitter implements IRenderer {
|
||||
|
||||
this._screenDprMonitor = new ScreenDprMonitor();
|
||||
this._screenDprMonitor.setListener(() => this.onWindowResize(window.devicePixelRatio));
|
||||
|
||||
// Detect whether IntersectionObserver is detected and enable renderer pause
|
||||
// and resume based on terminal visibility if so
|
||||
if ('IntersectionObserver' in window) {
|
||||
const observer = new IntersectionObserver(e => this.onIntersectionChange(e[0]), {threshold: 0});
|
||||
observer.observe(this._terminal.element);
|
||||
}
|
||||
}
|
||||
|
||||
public onIntersectionChange(entry: IntersectionObserverEntry): void {
|
||||
this._isPaused = entry.intersectionRatio === 0;
|
||||
if (!this._isPaused && this._needsFullRefresh) {
|
||||
this._terminal.refresh(0, this._terminal.rows - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public onWindowResize(devicePixelRatio: number): void {
|
||||
@@ -78,7 +94,11 @@ export class Renderer extends EventEmitter implements IRenderer {
|
||||
l.reset(this._terminal);
|
||||
});
|
||||
|
||||
this._terminal.refresh(0, this._terminal.rows - 1);
|
||||
if (this._isPaused) {
|
||||
this._needsFullRefresh = true;
|
||||
} else {
|
||||
this._terminal.refresh(0, this._terminal.rows - 1);
|
||||
}
|
||||
|
||||
return this.colorManager.colors;
|
||||
}
|
||||
@@ -91,7 +111,11 @@ export class Renderer extends EventEmitter implements IRenderer {
|
||||
this._renderLayers.forEach(l => l.resize(this._terminal, this.dimensions, didCharSizeChange));
|
||||
|
||||
// Force a refresh
|
||||
this._terminal.refresh(0, this._terminal.rows - 1);
|
||||
if (this._isPaused) {
|
||||
this._needsFullRefresh = true;
|
||||
} else {
|
||||
this._terminal.refresh(0, this._terminal.rows - 1);
|
||||
}
|
||||
|
||||
this.emit('resize', {
|
||||
width: this.dimensions.canvasWidth,
|
||||
@@ -104,27 +128,35 @@ export class Renderer extends EventEmitter implements IRenderer {
|
||||
}
|
||||
|
||||
public onBlur(): void {
|
||||
this._renderLayers.forEach(l => l.onBlur(this._terminal));
|
||||
this._runOperation(l => l.onBlur(this._terminal));
|
||||
}
|
||||
|
||||
public onFocus(): void {
|
||||
this._renderLayers.forEach(l => l.onFocus(this._terminal));
|
||||
this._runOperation(l => l.onFocus(this._terminal));
|
||||
}
|
||||
|
||||
public onSelectionChanged(start: [number, number], end: [number, number]): void {
|
||||
this._renderLayers.forEach(l => l.onSelectionChanged(this._terminal, start, end));
|
||||
this._runOperation(l => l.onSelectionChanged(this._terminal, start, end));
|
||||
}
|
||||
|
||||
public onCursorMove(): void {
|
||||
this._renderLayers.forEach(l => l.onCursorMove(this._terminal));
|
||||
this._runOperation(l => l.onCursorMove(this._terminal));
|
||||
}
|
||||
|
||||
public onOptionsChanged(): void {
|
||||
this._renderLayers.forEach(l => l.onOptionsChanged(this._terminal));
|
||||
this._runOperation(l => l.onOptionsChanged(this._terminal));
|
||||
}
|
||||
|
||||
public clear(): void {
|
||||
this._renderLayers.forEach(l => l.reset(this._terminal));
|
||||
this._runOperation(l => l.reset(this._terminal));
|
||||
}
|
||||
|
||||
private _runOperation(operation: (layer: IRenderLayer) => void): void {
|
||||
if (this._isPaused) {
|
||||
this._needsFullRefresh = true;
|
||||
} else {
|
||||
this._renderLayers.forEach(l => operation(l));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,6 +166,10 @@ export class Renderer extends EventEmitter implements IRenderer {
|
||||
* @param {number} end The end row.
|
||||
*/
|
||||
public queueRefresh(start: number, end: number): void {
|
||||
if (this._isPaused) {
|
||||
this._needsFullRefresh = true;
|
||||
return;
|
||||
}
|
||||
this._refreshRowsQueue.push({ start: start, end: end });
|
||||
if (!this._refreshAnimationFrame) {
|
||||
this._refreshAnimationFrame = window.requestAnimationFrame(this._refreshLoop.bind(this));
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
/* On OS X this is required in order for the scroll bar to appear fully opaque */
|
||||
background-color: #000;
|
||||
overflow-y: scroll;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.xterm canvas {
|
||||
|
||||
Reference in New Issue
Block a user