Commit da5f866f authored by Tim van der Lippe's avatar Tim van der Lippe Committed by Commit Bot

Remove terminal/ and the corresponding experiment

The terminal experiment was initially proposed in 2016 [1]. Since then,
no maintenance work was performed on promoting the experiment to a
stable feature.

Closer inspection of the feature shows that it does not work. After
enabling the experiment, issueing the command "Show Terminal" results in
an internal error in xterm.

If we want to reconsider this experiment, we should re-evaluate the
approach and come up with a proper design for the feature. For now, I
would propose on removing the dead code.

[1]: https://codereview.chromium.org/2372303003

Bug: 1006759,1011466
Change-Id: Ib433b44924d9ccb1f5665afba9affcccd04c2bd8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1855923
Commit-Queue: Yang Guo <yangguo@chromium.org>
Auto-Submit: Tim van der Lippe <tvanderlippe@chromium.org>
Reviewed-by: default avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#705165}
parent 5570e999
......@@ -12,7 +12,6 @@ front_end/cm_modes/
front_end/cm_web_modes/
front_end/diff/diff_match_patch.js
front_end/formatter_worker/acorn/
front_end/terminal/xterm.js/
front_end/protocol_externs.js
front_end/javascript_metadata/NativeFunctions.js
scripts/
\ No newline at end of file
......@@ -639,12 +639,6 @@ if (!external_devtools_frontend) {
"front_end/sources_test_runner/SearchTestRunner.js",
"front_end/sources_test_runner/SourcesTestRunner.js",
"front_end/sources_test_runner/module.json",
"front_end/terminal/module.json",
"front_end/terminal/terminal.css",
"front_end/terminal/TerminalWidget.js",
"front_end/terminal/xterm.js/addons/fit/fit.js",
"front_end/terminal/xterm.js/build/xterm.css",
"front_end/terminal/xterm.js/build/xterm.js",
"front_end/test_runner/module.json",
"front_end/test_runner/TestRunner.js",
"front_end/text_editor/autocompleteTooltip.css",
......
......@@ -63,7 +63,6 @@
<part file="../snippets/snippets_strings.grdp" />
<part file="../source_frame/source_frame_strings.grdp" />
<part file="../sources/sources_strings.grdp" />
<part file="../terminal/terminal_strings.grdp" />
<part file="../text_editor/text_editor_strings.grdp" />
<part file="../timeline/timeline_strings.grdp" />
<part file="../timeline_model/timeline_model_strings.grdp" />
......
......@@ -138,7 +138,6 @@ Main.Main = class {
Root.Runtime.experiments.register('sourceDiff', 'Source diff');
Root.Runtime.experiments.register('splitInDrawer', 'Split in drawer', true);
Root.Runtime.experiments.register('spotlight', 'Spotlight', true);
Root.Runtime.experiments.register('terminalInDrawer', 'Terminal in drawer', true);
// Timeline
Root.Runtime.experiments.register('timelineEventInitiators', 'Timeline: event initiators');
......
......@@ -41,7 +41,6 @@
{ "name": "snippets" },
{ "name": "source_frame" },
{ "name": "sources" },
{ "name": "terminal", "type": "remote" },
{ "name": "text_editor" },
{ "name": "workspace_diff" },
{ "name": "protocol_monitor"}
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @unrestricted
*/
Terminal.TerminalWidget = class extends UI.VBox {
constructor() {
super(true);
this.registerRequiredCSS('terminal/xterm.js/build/xterm.css');
this.registerRequiredCSS('terminal/terminal.css');
this.element.classList.add('terminal-root');
this._init();
this._linkifier = new Components.Linkifier();
this._config = {attributes: true, childList: true, characterData: true, subtree: true};
}
async _init() {
const backend = await Services.serviceManager.createRemoteService('Terminal');
this._initialized(backend);
}
/**
* @param {?Services.ServiceManager.Service} backend
*/
_initialized(backend) {
if (!backend) {
if (!this._unavailableLabel) {
this._unavailableLabel = this.contentElement.createChild('div', 'terminal-error-message fill');
this._unavailableLabel.createChild('div').textContent = Common.UIString('Terminal service is not available');
}
setTimeout(this._init.bind(this), 2000);
return;
}
if (this._unavailableLabel) {
this._unavailableLabel.remove();
delete this._unavailableLabel;
}
this._backend = backend;
if (!this._term) {
this._term = new Terminal({cursorBlink: true});
this._term.open(this.contentElement);
this._mutationObserver = new MutationObserver(this._linkify.bind(this));
this._mutationObserver.observe(this.contentElement, this._config);
this._term.on('data', data => {
this._backend.send('write', {data: data});
});
this._term.fit();
this._term.on('resize', size => {
this._backend.send('resize', {cols: size.cols, rows: size.rows});
});
}
this._backend.send('init', {cols: this._term.cols, rows: this._term.rows});
this._backend.on('data', result => {
this._term.write(result.data);
});
this._backend.on('disposed', this._disposed.bind(this));
}
/**
* @override
*/
onResize() {
if (this._term) {
this._term.fit();
}
}
_disposed() {
this._initialized(null);
}
/**
* @override
*/
ownerViewDisposed() {
if (this._backend) {
this._backend.dispose();
}
}
_linkify() {
this._mutationObserver.takeRecords();
this._mutationObserver.disconnect();
this._linkifier.reset();
const rows = this._term['rowContainer'].children;
for (let i = 0; i < rows.length; i++) {
this._linkifyTerminalLine(rows[i]);
}
this._mutationObserver.observe(this.contentElement, this._config);
}
/**
* @param {string} string
*/
_linkifyText(string) {
const regex1 = /([/\w\.-]*)+\:([\d]+)(?:\:([\d]+))?/;
const regex2 = /([/\w\.-]*)+\(([\d]+),([\d]+)\)/;
const container = createDocumentFragment();
while (string) {
const linkString = regex1.exec(string) || regex2.exec(string);
if (!linkString) {
break;
}
const text = linkString[0];
const path = linkString[1];
const lineNumber = parseInt(linkString[2], 10) - 1 || 0;
const columnNumber = parseInt(linkString[3], 10) - 1 || 0;
const uiSourceCode = Workspace.workspace.uiSourceCodes().find(uisc => uisc.url().endsWith(path));
const linkIndex = string.indexOf(text);
const nonLink = string.substring(0, linkIndex);
container.appendChild(createTextNode(nonLink));
if (uiSourceCode) {
container.appendChild(Components.Linkifier.linkifyURL(
uiSourceCode.url(),
{text, lineNumber, columnNumber, maxLengh: Number.MAX_VALUE, className: 'terminal-link'}));
} else {
container.appendChild(createTextNode(text));
}
string = string.substring(linkIndex + text.length);
}
if (string) {
container.appendChild(createTextNode(string));
}
return container;
}
/**
* @param {!Node} line
*/
_linkifyTerminalLine(line) {
let node = line.firstChild;
while (node) {
if (node.nodeType !== Node.TEXT_NODE) {
node = node.nextSibling;
continue;
}
const nextNode = node.nextSibling;
node.remove();
const linkified = this._linkifyText(node.textContent);
line.insertBefore(linkified, nextNode);
node = nextNode;
}
}
};
{
"extensions": [
{
"type": "view",
"location": "drawer-sidebar",
"id": "drawer.xterm",
"title": "Terminal",
"order": 10,
"factoryName": "Terminal.TerminalWidget"
}
],
"dependencies": [
"components",
"ui",
"services"
],
"experiment": "terminalInDrawer",
"scripts": [
"xterm.js/build/xterm.js",
"xterm.js/addons/fit/fit.js",
"TerminalWidget.js"
],
"skip_compilation": [
"xterm.js/build/xterm.js",
"xterm.js/addons/fit/fit.js"
],
"resources": [
"terminal.css",
"xterm.js/build/xterm.css"
]
}
/*
* Copyright 2016 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
.terminal-root {
background-color: #111;
color: #fafafa;
padding: 2px;
-webkit-user-select: text;
white-space: nowrap;
}
.terminal-error-message {
display: flex;
align-items: center;
padding: 10px;
background-color: rgba(255, 255, 255, 0.8);
justify-content: center;
font-size: 16px;
color: #222;
}
.terminal-error-message div {
padding-right: 10px;
}
.terminal-link {
color: inherit;
text-decoration: inherit;
}
.terminal-link:hover {
text-decoration: underline;
cursor: pointer;
}
<?xml version="1.0" encoding="utf-8"?>
<grit-part>
<message name="IDS_DEVTOOLS_514d8a494f087c0d549b9536c2ef3bd9" desc="Title of the 'Terminal' tool in the sidebar of the drawer tool">
Terminal
</message>
<message name="IDS_DEVTOOLS_69685b2a57646d0d0bc125b5f94f3931" desc="Text in Terminal Widget of the web version terminal">
Terminal service is not available
</message>
</grit-part>
\ No newline at end of file
Copyright (c) 2014, sourceLair Limited (https://github.com/sourcelair/)
Copyright (c) 2012-2013, Christopher Jeffrey (https://github.com/chjj/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Name: Xterm.js is a terminal front-end component written in JavaScript that works in the browser.
Short Name: xterm.js
URL: https://github.com/sourcelair/xterm.js
License: MIT
Security Critical: no
This directory contains Chrome's version of xterm.js with tests, demo and some addons folders removed.
/**
* Fit terminal columns and rows to the dimensions of its DOM element.
*
* ## Approach
* - Rows: Truncate the division of the terminal parent element height by the terminal row height.
*
* - Columns: Truncate the division of the terminal parent element width by the terminal character
* width (apply display: inline at the terminal row and truncate its width with the current
* number of columns).
* @module xterm/addons/fit/fit
* @license MIT
*/
(function (fit) {
if (typeof exports === 'object' && typeof module === 'object') {
/*
* CommonJS environment
*/
module.exports = fit(require('../../xterm'));
} else if (typeof define == 'function') {
/*
* Require.js is available
*/
define(['../../xterm'], fit);
} else {
/*
* Plain browser environment
*/
fit(window.Terminal);
}
})(function (Xterm) {
var exports = {};
exports.proposeGeometry = function (term) {
if (!term.element.parentElement) {
return null;
}
var parentElementStyle = window.getComputedStyle(term.element.parentElement),
parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')),
parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17),
elementStyle = window.getComputedStyle(term.element),
elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom')),
elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left')),
availableHeight = parentElementHeight - elementPaddingVer,
availableWidth = parentElementWidth - elementPaddingHor,
container = term.rowContainer,
subjectRow = term.rowContainer.firstElementChild,
contentBuffer = subjectRow.innerHTML,
characterHeight,
rows,
characterWidth,
cols,
geometry;
subjectRow.style.display = 'inline';
subjectRow.innerHTML = 'W'; // Common character for measuring width, although on monospace
characterWidth = subjectRow.getBoundingClientRect().width;
subjectRow.style.display = ''; // Revert style before calculating height, since they differ.
characterHeight = subjectRow.getBoundingClientRect().height;
subjectRow.innerHTML = contentBuffer;
rows = parseInt(availableHeight / characterHeight);
cols = parseInt(availableWidth / characterWidth);
geometry = {cols: cols, rows: rows};
return geometry;
};
exports.fit = function (term) {
var geometry = exports.proposeGeometry(term);
if (geometry) {
term.resize(geometry.cols, geometry.rows);
}
};
Xterm.prototype.proposeGeometry = function () {
return exports.proposeGeometry(this);
};
Xterm.prototype.fit = function () {
return exports.fit(this);
};
return exports;
});
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var dispatcher = require("./dispatcher.js");
var terminal = require("./terminal.js");
var d = new dispatcher.Dispatcher();
d.registerObject("Terminal", terminal.Terminal);
d.start(9022);
console.log("Run chrome as `chrome --devtools-flags='service-backend=ws://localhost:9022/endpoint'`");
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var http = require("http");
var ws = require("ws");
function Dispatcher()
{
this._constructors = new Map();
this._connections = new Set();
}
Dispatcher.prototype = {
start: function(port)
{
var http_server = http.createServer();
http_server.listen(port);
var WebSocketServer = ws.Server;
var options = { server: http_server, path: "/endpoint" };
var wss = new WebSocketServer(options);
wss.on("connection", (socket) => {
var connection = new Connection(this, socket);
this._connections.add(connection);
});
},
registerObject: function(name, constructor)
{
this._constructors.set(name, constructor);
},
_connectionClosed: function(connection)
{
this._connections.delete(connection);
}
}
exports.Dispatcher = Dispatcher;
function Connection(dispatcher, socket)
{
this._dispatcher = dispatcher;
this._objects = new Map();
this._lastObjectId = 1;
this._socket = socket;
this._socket.on("message", this._dispatchMessageWrapped.bind(this));
this._socket.on("close", this._connectionClosed.bind(this));
}
Connection.prototype = {
_dispatchMessageWrapped: function(data)
{
try {
var message = JSON.parse(data);
this._dispatchMessage(message);
} catch(e) {
this._sendErrorResponse(message.id, e.toString());
}
},
_dispatchMessage: function(message)
{
var [objectName, method] = message.method.split(".");
var result = JSON.stringify({id: message.id});
var constructor = this._dispatcher._constructors.get(objectName);
if (!constructor) {
this._sendErrorResponse(message.id, "Could not resolve service '" + objectName + "'");
return;
}
if (method === "create") {
var id = String(this._lastObjectId++);
var object = new constructor(this._notify.bind(this, id, objectName));
this._objects.set(id, object);
this._sendResponse(message.id, { id: id });
} else if (method === "dispose") {
var object = this._objects.get(message.params.id);
if (!object) {
console.error("Could not look up object with id for " + JSON.stringify(message));
return;
}
this._objects.delete(message.params.id);
object.dispose().then(() => this._sendResponse(message.id));
} else {
if (!message.params) {
console.error("No params in the message: " + JSON.stringify(message));
return;
}
var object = this._objects.get(message.params.id);
if (!object) {
console.error("Could not look up object with id for " + JSON.stringify(message));
return;
}
var handler = object[method];
if (!(handler instanceof Function)) {
console.error("Handler for '" + method + "' is missing.");
return;
}
object[method](message.params).then(result => this._sendResponse(message.id, result));
}
},
_connectionClosed: function()
{
for (var object of this._objects.values())
object.dispose();
this._objects.clear();
this._dispatcher._connectionClosed(this);
},
_notify: function(objectId, objectName, method, params)
{
params["id"] = objectId;
var message = { method: objectName + "." + method, params: params };
this._socket.send(JSON.stringify(message));
},
_sendResponse: function(messageId, result)
{
var message = { id: messageId, result: result };
this._socket.send(JSON.stringify(message));
},
_sendErrorResponse: function(messageId, error)
{
var message = { id: messageId, error: error };
this._socket.send(JSON.stringify(message));
},
}
{
"name": "devtools-backend",
"version": "1.0.0",
"ignore": [
".gitignore"
],
"dependencies": {
"pty.js": "0.3.1",
"ws": "^1.1.1"
}
}
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var pty = require("pty.js");
function Terminal(notify)
{
this._notify = notify;
}
Terminal.prototype = {
init: function(params)
{
this._term = pty.spawn(process.platform === "win32" ? "cmd.exe" : "bash", [], {
name: "xterm-color",
cols: params.cols || 80,
rows: params.rows || 24,
cwd: process.env.PWD,
env: process.env
});
this._term.on("data", data => {
if (this._notify)
this._notify("data", { data: data });
});
return Promise.resolve({});
},
resize: function(params)
{
if (this._term)
this._term.resize(params.cols, params.rows);
return Promise.resolve({});
},
write: function(params)
{
this._term.write(params.data);
return Promise.resolve({});
},
dispose: function(params)
{
this._notify = null;
if (this._term)
process.kill(this._term.pid);
return Promise.resolve({});
},
}
exports.Terminal = Terminal;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment