Chromium Code Reviews| Index: sky/examples/terminal/terminal.sky |
| diff --git a/sky/examples/terminal/terminal.sky b/sky/examples/terminal/terminal.sky |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..74cd1d6e91d83ab0006f7a1b32e6ac272aa5647d |
| --- /dev/null |
| +++ b/sky/examples/terminal/terminal.sky |
| @@ -0,0 +1,114 @@ |
| +<!-- |
| +// Copyright 2015 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. |
| +--> |
| +<import src="/sky/framework/sky-element.sky" /> |
| +<import src="/sky/framework/sky-scrollable.sky" /> |
| +<sky-element> |
| +<template> |
| + <style> |
| + #control { |
| + height: -webkit-fill-available; |
| + background-color: black; |
| + color: rgb(255, 191, 0); |
| + font-family: 'Courier', 'monospace'; |
| + } |
| + span { |
| + white-space: nowrap; |
| + } |
| + </style> |
| + <sky-scrollable id="control" contenteditable /> |
| +</template> |
| +<script> |
| +import 'dart:async'; |
| +import 'dart:core'; |
| +import 'dart:sky'; |
| +import 'package:examples/echo_terminal/terminal_client.mojom.dart' as terminal; |
| +import '/sky/framework/embedder.dart'; |
| +import 'terminal_display.dart'; |
| +import 'terminal_file_impl.dart'; |
| + |
| +// Implements the <terminal> element, which implements a "terminal display". Has |
| +// an |url| attribute, whose value should be a Mojo app that provides the |
| +// |terminal.TerminalClient| service. |
| +@Tagname('terminal') |
| +class TerminalDisplayImpl extends SkyElement implements TerminalDisplay { |
| + Element _control; |
| + |
| + // Queue of unconsumed input (keystrokes), with the head at index 0. |
| + // Keystrokes end up here if there's no reader (i.e., |getChar()|) pending, |
| + // i.e., if |_readerQueue| is empty. Invariant: At most one of |_inputQueue| |
| + // and |_readerQueue| may be nonempty at any given time. |
| + List<int> _inputQueue; |
| + |
| + // Queue of things waiting for input, with the head at index 0. If a keystroke |
| + // is received and this is nonempty, the head is given that keystroke (and |
| + // dequeued). |
| + List<Completer<int>> _readerQueue; |
| + |
| + TerminalDisplayImpl() |
| + : _inputQueue = new List<int>(), |
| + _readerQueue = new List<Completer<int>>() { |
| + } |
| + |
| + void shadowRootReady() { |
| + _control = shadowRoot.getElementById('control'); |
| + _control.addEventListener('keypress', _handleKeyPress); |
| + |
| + // Initialize with the first line. |
| + _newLine(); |
| + |
| + _connect(getAttribute('url')); |
| + } |
| + |
| + void _handleKeyPress(KeyboardEvent event) { |
| + // TODO(vtl): Add "echo" mode; do |putChar(event.charCode);| if echo is on. |
| + |
| + if (_readerQueue.isEmpty) { |
| + _inputQueue.add(event.charCode); |
| + } else { |
| + _readerQueue.removeAt(0).complete(event.charCode); |
| + } |
|
Elliot Glaysher
2015/03/11 20:55:43
I look...forward...to seeing how well this perform
viettrungluu
2015/03/11 21:25:18
I think it already performs better than a connecti
Elliot Glaysher
2015/03/11 21:29:05
This is not actually reassuring.
|
| + |
| + event.preventDefault(); |
| + } |
| + |
| + void _newLine() { |
| + _control.appendChild(document.createElement('span')); |
| + } |
| + |
| + // TODO(vtl): Should we always auto-connect? Should there be facilities for |
| + // programmatically connecting? (What if the |url| attribute isn't set?) |
| + void _connect(String url) { |
| + var terminalClient = new terminal.TerminalClientProxy.unbound(); |
| + embedder.connectToService(url, terminalClient); |
| + terminalClient.ptr.connectToTerminal(new TerminalFileImpl(this).stub); |
| + terminalClient.close(); |
| + } |
| + |
| + // |TerminalDisplay| implementation: |
| + |
| + @override |
| + void putChar(int byte) { |
| + if (byte == 10 || byte == 13) { |
| + _newLine(); |
| + } |
| + _control.lastChild.textContent += new String.fromCharCode(byte); |
|
Elliot Glaysher
2015/03/11 20:55:43
Doesn't this mean that there's now a newline chara
viettrungluu
2015/03/11 21:25:18
Oops, I meant to put a return above. Fixed.
|
| + } |
| + |
| + @override |
| + Future<int> getChar() async { |
| + if (_inputQueue.isNotEmpty) { |
| + return new Future.value(_inputQueue.removeAt(0)); |
| + } |
| + |
| + var completer = new Completer<int>(); |
| + _readerQueue.add(completer); |
| + return completer.future; |
| + } |
| +} |
| + |
| +_init(script) => register(script, TerminalDisplayImpl); |
| +</script> |
| +</sky-element> |