terminal: selection and title handling for xterm.js
Bug: 236205389
Change-Id: I8087289bf66a3052c18d36b0038e6251182cf8e7
Reviewed-on: https://chromium-review.googlesource.com/c/apps/libapps/+/3855720
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Joel Hockey <joelhockey@chromium.org>
diff --git a/terminal/js/terminal_emulator.js b/terminal/js/terminal_emulator.js
index 1e9f9f2..b763c0e 100644
--- a/terminal/js/terminal_emulator.js
+++ b/terminal/js/terminal_emulator.js
@@ -9,9 +9,11 @@
// TODO(b/236205389): add tests. For example, we should enable the test in
// terminal_tests.js for XtermTerminal.
-import {Terminal, FitAddon, WebglAddon} from './xterm.js';
+import {LitElement, css, html} from './lit.js';
import {FontManager, ORIGINAL_URL, TERMINAL_EMULATORS, delayedScheduler,
fontManager, getOSInfo, sleep} from './terminal_common.js';
+import {ICON_COPY} from './terminal_icons.js';
+import {Terminal, FitAddon, WebglAddon} from './xterm.js';
const ANSI_COLOR_NAMES = [
'black',
@@ -120,15 +122,24 @@
this.installUnimplementedStubs_();
- this.observePrefs_();
-
this.term.onResize(({cols, rows}) => this.io.onTerminalResize(cols, rows));
// We could also use `this.io.sendString()` except for the nassh exit
// prompt, which only listens to onVTKeystroke().
this.term.onData((data) => this.io.onVTKeystroke(data));
+ this.term.onTitleChange((title) => document.title = title);
+ this.term.onSelectionChange(() => this.onSelectionChange_());
this.io = new XtermTerminalIO(this);
this.notificationCenter_ = null;
+
+ this.copyNotice_ = null;
+
+ this.term.options.theme = {
+ selection: 'rgba(174, 203, 250, .6)',
+ selectionForeground: 'black',
+ customGlyphs: true,
+ };
+ this.observePrefs_();
}
/**
@@ -368,6 +379,18 @@
}
}
+ onSelectionChange_() {
+ const selection = this.term.getSelection();
+ if (!selection) {
+ return;
+ }
+ navigator.clipboard?.writeText(selection);
+ if (!this.copyNotice_) {
+ this.copyNotice_ = document.createElement('terminal-copy-notice');
+ }
+ setTimeout(() => this.showOverlay(lib.notNull(this.copyNotice_), 500), 200);
+ }
+
/**
* Refresh xterm rendering for a font related event.
*/
@@ -388,28 +411,28 @@
* @param {string} cssFontFamily
*/
async updateFont_(cssFontFamily) {
- this.pendingFont_ = cssFontFamily;
- await this.fontManager_.loadFont(cssFontFamily);
- // Sleep a bit to wait for flushing fontloadingdone events. This is not
- // strictly necessary, but it should prevent `this.onFontLoadingDone_()`
- // to refresh font unnecessarily in some cases.
- await sleep(30);
+ this.pendingFont_ = cssFontFamily;
+ await this.fontManager_.loadFont(cssFontFamily);
+ // Sleep a bit to wait for flushing fontloadingdone events. This is not
+ // strictly necessary, but it should prevent `this.onFontLoadingDone_()`
+ // to refresh font unnecessarily in some cases.
+ await sleep(30);
- if (this.pendingFont_ !== cssFontFamily) {
- // `updateFont_()` probably is called again. Abort what we are doing.
- console.log(`pendingFont_ (${this.pendingFont_}) is changed` +
- ` (expecting ${cssFontFamily})`);
- return;
- }
+ if (this.pendingFont_ !== cssFontFamily) {
+ // `updateFont_()` probably is called again. Abort what we are doing.
+ console.log(`pendingFont_ (${this.pendingFont_}) is changed` +
+ ` (expecting ${cssFontFamily})`);
+ return;
+ }
- if (this.term.options.fontFamily !== cssFontFamily) {
- this.term.options.fontFamily = cssFontFamily;
- } else {
- // If the font is already the same, refresh font just to be safe.
- this.refreshFont_();
- }
- this.pendingFont_ = null;
- this.scheduleFit_();
+ if (this.term.options.fontFamily !== cssFontFamily) {
+ this.term.options.fontFamily = cssFontFamily;
+ } else {
+ // If the font is already the same, refresh font just to be safe.
+ this.refreshFont_();
+ }
+ this.pendingFont_ = null;
+ this.scheduleFit_();
}
}
@@ -474,3 +497,28 @@
}
}
+class TerminalCopyNotice extends LitElement {
+ /** @override */
+ static get styles() {
+ return css`
+ :host {
+ display: block;
+ text-align: center;
+ }
+
+ svg {
+ fill: currentColor;
+ }
+ `;
+ }
+
+ /** @override */
+ render() {
+ return html`
+ ${ICON_COPY}
+ <div>${hterm.messageManager.get('HTERM_NOTIFY_COPY')}</div>
+ `;
+ }
+}
+
+customElements.define('terminal-copy-notice', TerminalCopyNotice);