mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Merge branch 'master' into mouse_services
This commit is contained in:
@@ -224,6 +224,31 @@ describe('Terminal', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('paste', () => {
|
||||
it('should fire data event', done => {
|
||||
term.onData(e => {
|
||||
assert.equal(e, 'foo');
|
||||
done();
|
||||
});
|
||||
term.paste('foo');
|
||||
});
|
||||
it('should sanitize \n chars', done => {
|
||||
term.onData(e => {
|
||||
assert.equal(e, '\rfoo\rbar\r');
|
||||
done();
|
||||
});
|
||||
term.paste('\r\nfoo\nbar\r');
|
||||
});
|
||||
it('should respect bracketed paste mode', done => {
|
||||
term.onData(e => {
|
||||
assert.equal(e, '\x1b[200~foo\x1b[201~');
|
||||
done();
|
||||
});
|
||||
term.write('\x1b[?2004h');
|
||||
term.paste('foo');
|
||||
});
|
||||
});
|
||||
|
||||
describe('scroll', () => {
|
||||
describe('scrollLines', () => {
|
||||
let startYDisp: number;
|
||||
|
||||
+12
-6
@@ -25,7 +25,7 @@ import { IInputHandlingTerminal, ICompositionHelper, ITerminalOptions, ITerminal
|
||||
import { IRenderer, CharacterJoinerHandler } from 'browser/renderer/Types';
|
||||
import { CompositionHelper } from 'browser/input/CompositionHelper';
|
||||
import { Viewport } from 'browser/Viewport';
|
||||
import { rightClickHandler, moveTextAreaUnderMouseCursor, pasteHandler, copyHandler } from 'browser/Clipboard';
|
||||
import { rightClickHandler, moveTextAreaUnderMouseCursor, handlePasteEvent, copyHandler, paste } from 'browser/Clipboard';
|
||||
import { C0 } from 'common/data/EscapeSequences';
|
||||
import { InputHandler } from './InputHandler';
|
||||
import { Renderer } from './renderer/Renderer';
|
||||
@@ -494,7 +494,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp
|
||||
}
|
||||
copyHandler(event, this._selectionService);
|
||||
}));
|
||||
const pasteHandlerWrapper = (event: ClipboardEvent) => pasteHandler(event, this.textarea, this.bracketedPasteMode, e => this._coreService.triggerDataEvent(e, true));
|
||||
const pasteHandlerWrapper = (event: ClipboardEvent) => handlePasteEvent(event, this.textarea, this.bracketedPasteMode, this._coreService);
|
||||
this.register(addDisposableDomListener(this.textarea, 'paste', pasteHandlerWrapper));
|
||||
this.register(addDisposableDomListener(this.element, 'paste', pasteHandlerWrapper));
|
||||
|
||||
@@ -953,8 +953,9 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp
|
||||
// the shell for example
|
||||
this.register(addDisposableDomListener(el, 'wheel', (ev: WheelEvent) => {
|
||||
if (requestedEvents.wheel) return;
|
||||
this.viewport.onWheel(ev);
|
||||
return this.cancel(ev);
|
||||
if (!this.viewport.onWheel(ev)) {
|
||||
return this.cancel(ev);
|
||||
}
|
||||
}));
|
||||
|
||||
this.register(addDisposableDomListener(el, 'touchstart', (ev: TouchEvent) => {
|
||||
@@ -965,8 +966,9 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp
|
||||
|
||||
this.register(addDisposableDomListener(el, 'touchmove', (ev: TouchEvent) => {
|
||||
if (this.mouseEvents) return;
|
||||
this.viewport.onTouchMove(ev);
|
||||
return this.cancel(ev);
|
||||
if (!this.viewport.onTouchMove(ev)) {
|
||||
return this.cancel(ev);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -1304,6 +1306,10 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp
|
||||
this.write(data + '\r\n');
|
||||
}
|
||||
|
||||
public paste(data: string): void {
|
||||
paste(data, this.textarea, this.bracketedPasteMode, this._coreService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a custom key event handler which is run before keys are processed,
|
||||
* giving consumers of xterm.js ultimate control as to what keys should be
|
||||
|
||||
@@ -68,6 +68,9 @@ export class MockTerminal implements ITerminal {
|
||||
writeln(data: string): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
paste(data: string): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
open(parent: HTMLElement): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
@@ -407,13 +410,13 @@ export class MockViewport implements IViewport {
|
||||
onThemeChange(colors: IColorSet): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
onWheel(ev: WheelEvent): void {
|
||||
onWheel(ev: WheelEvent): boolean {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
onTouchStart(ev: TouchEvent): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
onTouchMove(ev: TouchEvent): void {
|
||||
onTouchMove(ev: TouchEvent): boolean {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
syncScrollArea(): void { }
|
||||
|
||||
Vendored
+1
@@ -220,6 +220,7 @@ export interface IPublicTerminal extends IDisposable {
|
||||
clear(): void;
|
||||
write(data: string): void;
|
||||
writeUtf8(data: Uint8Array): void;
|
||||
paste(data: string): void;
|
||||
refresh(start: number, end: number): void;
|
||||
reset(): void;
|
||||
}
|
||||
|
||||
+11
-13
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import { ISelectionService } from 'browser/services/Services';
|
||||
import { ICoreService } from 'common/services/Services';
|
||||
|
||||
/**
|
||||
* Prepares text to be pasted into the terminal by normalizing the line endings
|
||||
@@ -41,24 +42,21 @@ export function copyHandler(ev: ClipboardEvent, selectionService: ISelectionServ
|
||||
* @param ev The original paste event to be handled
|
||||
* @param term The terminal on which to apply the handled paste event
|
||||
*/
|
||||
export function pasteHandler(ev: ClipboardEvent, textarea: HTMLTextAreaElement, bracketedPasteMode: boolean, triggerUserInput: (data: string) => void): void {
|
||||
export function handlePasteEvent(ev: ClipboardEvent, textarea: HTMLTextAreaElement, bracketedPasteMode: boolean, coreService: ICoreService): void {
|
||||
ev.stopPropagation();
|
||||
|
||||
let text: string;
|
||||
|
||||
const dispatchPaste = function(text: string): void {
|
||||
text = prepareTextForTerminal(text);
|
||||
text = bracketTextForPaste(text, bracketedPasteMode);
|
||||
triggerUserInput(text);
|
||||
textarea.value = '';
|
||||
};
|
||||
|
||||
if (ev.clipboardData) {
|
||||
text = ev.clipboardData.getData('text/plain');
|
||||
dispatchPaste(text);
|
||||
const text = ev.clipboardData.getData('text/plain');
|
||||
paste(text, textarea, bracketedPasteMode, coreService);
|
||||
}
|
||||
}
|
||||
|
||||
export function paste(text: string, textarea: HTMLTextAreaElement, bracketedPasteMode: boolean, coreService: ICoreService): void {
|
||||
text = prepareTextForTerminal(text);
|
||||
text = bracketTextForPaste(text, bracketedPasteMode);
|
||||
coreService.triggerDataEvent(text, true);
|
||||
textarea.value = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the textarea under the mouse cursor and focuses it.
|
||||
* @param ev The original right click event to be handled.
|
||||
|
||||
Vendored
+2
-2
@@ -37,9 +37,9 @@ export interface IViewport extends IDisposable {
|
||||
scrollBarWidth: number;
|
||||
syncScrollArea(): void;
|
||||
getLinesScrolled(ev: WheelEvent): number;
|
||||
onWheel(ev: WheelEvent): void;
|
||||
onWheel(ev: WheelEvent): boolean;
|
||||
onTouchStart(ev: TouchEvent): void;
|
||||
onTouchMove(ev: TouchEvent): void;
|
||||
onTouchMove(ev: TouchEvent): boolean;
|
||||
onThemeChange(colors: IColorSet): void;
|
||||
}
|
||||
|
||||
|
||||
+23
-7
@@ -152,20 +152,36 @@ export class Viewport extends Disposable implements IViewport {
|
||||
this._scrollLines(diff, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles bubbling of scroll event in case the viewport has reached top or bottom
|
||||
* @param ev The scroll event.
|
||||
* @param amount The amount scrolled
|
||||
*/
|
||||
private _bubbleScroll(ev: Event, amount: number): boolean {
|
||||
const scrollPosFromTop = this._viewportElement.scrollTop + this._lastRecordedViewportHeight;
|
||||
if ((amount < 0 && this._viewportElement.scrollTop !== 0) ||
|
||||
(amount > 0 && scrollPosFromTop < this._lastRecordedBufferHeight)) {
|
||||
if (ev.cancelable) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles mouse wheel events by adjusting the viewport's scrollTop and delegating the actual
|
||||
* scrolling to `onScroll`, this event needs to be attached manually by the consumer of
|
||||
* `Viewport`.
|
||||
* @param ev The mouse wheel event.
|
||||
*/
|
||||
public onWheel(ev: WheelEvent): void {
|
||||
public onWheel(ev: WheelEvent): boolean {
|
||||
const amount = this._getPixelsScrolled(ev);
|
||||
if (amount === 0) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
this._viewportElement.scrollTop += amount;
|
||||
// Prevent the page from scrolling when the terminal scrolls
|
||||
ev.preventDefault();
|
||||
return this._bubbleScroll(ev, amount);
|
||||
}
|
||||
|
||||
private _getPixelsScrolled(ev: WheelEvent): number {
|
||||
@@ -220,13 +236,13 @@ export class Viewport extends Disposable implements IViewport {
|
||||
* Handles the touchmove event, scrolling the viewport if the position shifted.
|
||||
* @param ev The touch event.
|
||||
*/
|
||||
public onTouchMove(ev: TouchEvent): void {
|
||||
public onTouchMove(ev: TouchEvent): boolean {
|
||||
const deltaY = this._lastTouchY - ev.touches[0].pageY;
|
||||
this._lastTouchY = ev.touches[0].pageY;
|
||||
if (deltaY === 0) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
this._viewportElement.scrollTop += deltaY;
|
||||
ev.preventDefault();
|
||||
return this._bubbleScroll(ev, deltaY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +134,9 @@ export class Terminal implements ITerminalApi {
|
||||
public writeUtf8(data: Uint8Array): void {
|
||||
this._core.writeUtf8(data);
|
||||
}
|
||||
public paste(data: string): void {
|
||||
this._core.paste(data);
|
||||
}
|
||||
public getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'fontWeight' | 'fontWeightBold' | 'logLevel' | 'rendererType' | 'termName' | 'wordSeparator'): string;
|
||||
public getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'disableStdin' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell'): boolean;
|
||||
public getOption(key: 'colors'): string[];
|
||||
|
||||
@@ -76,6 +76,22 @@ describe('API Integration Tests', function(): void {
|
||||
assert.equal(await page.evaluate(`window.term.buffer.getLine(0).translateToString(true)`), 'foobar文');
|
||||
});
|
||||
|
||||
it('paste', async function(): Promise<any> {
|
||||
await openTerminal();
|
||||
await page.evaluate(`
|
||||
window.calls = [];
|
||||
window.term.onData(e => calls.push(e));
|
||||
window.term.paste('foo');
|
||||
window.term.paste('\\r\\nfoo\\nbar\\r');
|
||||
window.term.write('\\x1b[?2004h');
|
||||
// TODO: Use promise/callback for write when we support that
|
||||
// Force sync write
|
||||
window.term._core._innerWrite();
|
||||
window.term.paste('foo');
|
||||
`);
|
||||
assert.deepEqual(await page.evaluate(`window.calls`), ['foo', '\rfoo\rbar\r', '\x1b[200~foo\x1b[201~']);
|
||||
});
|
||||
|
||||
it('clear', async function(): Promise<any> {
|
||||
await openTerminal({ rows: 5 });
|
||||
await page.evaluate(`
|
||||
|
||||
Vendored
+6
@@ -669,6 +669,12 @@ declare module 'xterm' {
|
||||
*/
|
||||
writeUtf8(data: Uint8Array): void;
|
||||
|
||||
/**
|
||||
* Writes text to the terminal, performing the necessary transformations for pasted text.
|
||||
* @param data The text to write to the terminal.
|
||||
*/
|
||||
paste(data: string): void;
|
||||
|
||||
/**
|
||||
* Retrieves an option's value from the terminal.
|
||||
* @param key The option key.
|
||||
|
||||
Reference in New Issue
Block a user