mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +00:00
...
This commit is contained in:
parent
d3a851fb46
commit
ca459f6b65
@ -7,4 +7,8 @@ mkdir web/lib
|
|||||||
|
|
||||||
SRC=$(find src/ -name "*.c")
|
SRC=$(find src/ -name "*.c")
|
||||||
|
|
||||||
emcc $SRC -Iinclude/ -s -Os -sEXPORTED_FUNCTIONS=_py_initialize,_py_finalize,_py_exec,_py_replinput -sEXPORTED_RUNTIME_METHODS=ccall -o web/lib/pocketpy.js
|
emcc $SRC -Iinclude/ -s -Os \
|
||||||
|
-sEXPORTED_FUNCTIONS=_py_initialize,_py_exec,_py_finalize,_py_printexc,_py_clearexc \
|
||||||
|
-sEXPORTED_RUNTIME_METHODS=ccall \
|
||||||
|
-sALLOW_MEMORY_GROWTH=1 \
|
||||||
|
-o web/lib/pocketpy.js
|
||||||
|
271
web/index.html
271
web/index.html
@ -1,15 +1,256 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
<!--
|
||||||
<head>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
Note:
|
||||||
<title>pocketpy demo</title>
|
This site was created by modifying code pen https://codepen.io/antonmedv/pen/PoPoGwg
|
||||||
<link rel="stylesheet" href="xterm/xterm.css" />
|
written by 'Anton Medvedev' the license can be found bellow.
|
||||||
<script src="xterm/xterm.js"></script>
|
|
||||||
<script src="index.js" ></script>
|
LICENSE
|
||||||
</head>
|
-------
|
||||||
<body>
|
Copyright (c) 2022 by Anton Medvedev (https://codepen.io/antonmedv/pen/PoPoGwg)
|
||||||
<div id="terminal"></div>
|
|
||||||
<script>term_init();</script>
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
<script src="./lib/pocketpy.js"></script>
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
</body>
|
the Software without restriction, including without limitation the rights to
|
||||||
</html>
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<script src="static/codejar/codejar.js"></script>
|
||||||
|
<script src="static/codejar/linenumbers.js"></script>
|
||||||
|
<script src="static/highlight.js/highlight.min.js"></script>
|
||||||
|
<link rel="stylesheet" href="static/highlight.js/github-dark-dimmed.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import url("https://fonts.googleapis.com/css2?family=Lato:wght@300&family=PT+Mono&display=swap");
|
||||||
|
|
||||||
|
.hljs{display:block;overflow-x:auto;padding:.5em;background:#282a36}
|
||||||
|
.hljs-keyword,.hljs-selector-tag,.hljs-literal,.hljs-section,.hljs-link{color:#73cbde}
|
||||||
|
.hljs,.hljs-subst{color:#f8f8f2}
|
||||||
|
.hljs-string,.hljs-title,.hljs-name,.hljs-type,.hljs-attribute,.hljs-symbol,
|
||||||
|
.hljs-bullet,.hljs-addition,.hljs-variable,.hljs-template-tag,.hljs-template-variable{color:#f1fa8c}
|
||||||
|
.hljs-comment,.hljs-quote,.hljs-deletion,.hljs-meta{color:#6272a4}
|
||||||
|
.hljs-keyword,.hljs-selector-tag,.hljs-literal,.hljs-title,.hljs-section,.hljs-doctag,
|
||||||
|
.hljs-type,.hljs-name,.hljs-strong{font-weight:bold}.hljs-emphasis{font-style:italic}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--window-width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #778abb;
|
||||||
|
font-family: Lato, sans-serif;
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 15px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
*,
|
||||||
|
*:before,
|
||||||
|
*:after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
*:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
a,
|
||||||
|
a:visited,
|
||||||
|
a:active {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 34px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.window {
|
||||||
|
width: var(--window-width);
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.window .window-header {
|
||||||
|
height: 25px;
|
||||||
|
background: Gainsboro;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.window .window-header .action-buttons {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 10px;
|
||||||
|
margin-top: -5px;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background: Crimson;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 15px 0 0 Orange, 30px 0 0 LimeGreen;
|
||||||
|
}
|
||||||
|
#code-editor {
|
||||||
|
border-bottom-left-radius: 6px;
|
||||||
|
border-bottom-right-radius: 6px;
|
||||||
|
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12),
|
||||||
|
0 3px 1px -2px rgba(0, 0, 0, 0.2);
|
||||||
|
font-family: "PT Mono", monospace;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
min-height: 300px;
|
||||||
|
letter-spacing: normal;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
resize: none !important;
|
||||||
|
tab-size: 4;
|
||||||
|
}
|
||||||
|
#run-button {
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
#code-editor.hljs {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
#output-wrapper {
|
||||||
|
font-family: "PT Mono", monospace;
|
||||||
|
width: var(--window-width);
|
||||||
|
min-height: 50px;
|
||||||
|
background-color: #282a36;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 10px;
|
||||||
|
color: white;
|
||||||
|
margin:0 !important;
|
||||||
|
}
|
||||||
|
#code-output span.error-line {
|
||||||
|
color: #ec5424;
|
||||||
|
}
|
||||||
|
.controls {
|
||||||
|
font-size: 14px;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: 10px;
|
||||||
|
margin-top: -10px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.controls > div:first-child > a {
|
||||||
|
display: inline-block;
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
.features {
|
||||||
|
width: 547px;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<title>Try Online</title>
|
||||||
|
</head>
|
||||||
|
<body id="tryonline-body">
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<br>
|
||||||
|
<div class="window">
|
||||||
|
<div class="window-header">
|
||||||
|
<div class="action-buttons"></div>
|
||||||
|
<div class="controls">
|
||||||
|
<div id="run-button">Run</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="window-body">
|
||||||
|
<div id="code-editor" class="language-python" data-gramm="false"># A recursive fibonacci function.
|
||||||
|
def fib(n):
|
||||||
|
if n < 2:
|
||||||
|
return n
|
||||||
|
return fib(n-1) + fib(n-2)
|
||||||
|
|
||||||
|
# Prints all fibonacci from 0 to 10 exclusive.
|
||||||
|
for i in range(10):
|
||||||
|
print(f"fib({i}) = {fib(i)}")
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<pre id="output-wrapper"><div id="code-output">...</div></pre>
|
||||||
|
<br>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
let code_editor = document.querySelector('#code-editor');
|
||||||
|
let code_output = document.querySelector('#code-output');
|
||||||
|
let run_button = document.querySelector('#run-button');
|
||||||
|
|
||||||
|
let highlight = withLineNumbers(function(editor) {
|
||||||
|
editor.textContent = editor.textContent;
|
||||||
|
hljs.highlightElement(editor);
|
||||||
|
});
|
||||||
|
|
||||||
|
highlight(code_editor);
|
||||||
|
|
||||||
|
CodeJar(code_editor, highlight); //, { indentOn: /[(\[{:]$/});
|
||||||
|
|
||||||
|
|
||||||
|
var Module = {
|
||||||
|
onRuntimeInitialized: function() {
|
||||||
|
Module.ccall('py_initialize', null, [], []);
|
||||||
|
},
|
||||||
|
print: function(text) {
|
||||||
|
console.log(text);
|
||||||
|
code_output.innerText += text + '\n';
|
||||||
|
},
|
||||||
|
onabort: function(what) {
|
||||||
|
code_output.innerText += 'Aborted: ' + what + '\n';
|
||||||
|
Module.ccall('py_finalize', null, [], []);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onload = function() {
|
||||||
|
var script = document.createElement('script');
|
||||||
|
script.src = 'lib/pocketpy.js';
|
||||||
|
document.head.appendChild(script);
|
||||||
|
|
||||||
|
run_button.onclick = function() {
|
||||||
|
code_output.innerText = '';
|
||||||
|
const source = code_editor.textContent;
|
||||||
|
var ok = Module.ccall(
|
||||||
|
'py_exec', 'boolean', ['string', 'string', 'number', 'number'],
|
||||||
|
[source, 'main.py', 0, 0]
|
||||||
|
);
|
||||||
|
if (!ok) {
|
||||||
|
Module.ccall('py_printexc', null, [], []);
|
||||||
|
Module.ccall('py_clearexc', null, ['number'], [0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
163
web/index.js
163
web/index.js
@ -1,163 +0,0 @@
|
|||||||
const MINIMUM_COLS = 2
|
|
||||||
const MINIMUM_ROWS = 1
|
|
||||||
|
|
||||||
class FitAddon {
|
|
||||||
constructor() {}
|
|
||||||
|
|
||||||
activate(terminal) {
|
|
||||||
this._terminal = terminal
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose() {}
|
|
||||||
|
|
||||||
fit() {
|
|
||||||
const dims = this.proposeDimensions()
|
|
||||||
if (!dims || !this._terminal || isNaN(dims.cols) || isNaN(dims.rows)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Remove reliance on private API
|
|
||||||
const core = this._terminal._core
|
|
||||||
|
|
||||||
// Force a full render
|
|
||||||
if (
|
|
||||||
this._terminal.rows !== dims.rows ||
|
|
||||||
this._terminal.cols !== dims.cols
|
|
||||||
) {
|
|
||||||
core._renderService.clear()
|
|
||||||
this._terminal.resize(dims.cols, dims.rows)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
proposeDimensions() {
|
|
||||||
if (!this._terminal) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._terminal.element || !this._terminal.element.parentElement) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Remove reliance on private API
|
|
||||||
const core = this._terminal._core
|
|
||||||
const dims = core._renderService.dimensions
|
|
||||||
|
|
||||||
if (dims.actualCellWidth === 0 || dims.actualCellHeight === 0) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
const scrollbarWidth =
|
|
||||||
this._terminal.options.scrollback === 0 ? 0 : core.viewport.scrollBarWidth
|
|
||||||
|
|
||||||
const parentElementStyle = window.getComputedStyle(
|
|
||||||
this._terminal.element.parentElement
|
|
||||||
)
|
|
||||||
const parentElementHeight = parseInt(
|
|
||||||
parentElementStyle.getPropertyValue("height")
|
|
||||||
)
|
|
||||||
const parentElementWidth = Math.max(
|
|
||||||
0,
|
|
||||||
parseInt(parentElementStyle.getPropertyValue("width"))
|
|
||||||
)
|
|
||||||
const elementStyle = window.getComputedStyle(this._terminal.element)
|
|
||||||
const elementPadding = {
|
|
||||||
top: parseInt(elementStyle.getPropertyValue("padding-top")),
|
|
||||||
bottom: parseInt(elementStyle.getPropertyValue("padding-bottom")),
|
|
||||||
right: parseInt(elementStyle.getPropertyValue("padding-right")),
|
|
||||||
left: parseInt(elementStyle.getPropertyValue("padding-left"))
|
|
||||||
}
|
|
||||||
const elementPaddingVer = elementPadding.top + elementPadding.bottom
|
|
||||||
const elementPaddingHor = elementPadding.right + elementPadding.left
|
|
||||||
const availableHeight = parentElementHeight - elementPaddingVer
|
|
||||||
const availableWidth =
|
|
||||||
parentElementWidth - elementPaddingHor - scrollbarWidth
|
|
||||||
const geometry = {
|
|
||||||
cols: Math.max(
|
|
||||||
MINIMUM_COLS,
|
|
||||||
Math.floor(availableWidth / dims.actualCellWidth)
|
|
||||||
),
|
|
||||||
rows: Math.max(
|
|
||||||
MINIMUM_ROWS,
|
|
||||||
Math.floor(availableHeight / dims.actualCellHeight)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return geometry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************/
|
|
||||||
|
|
||||||
const term = new Terminal(
|
|
||||||
{
|
|
||||||
cursorBlink: true,
|
|
||||||
fontSize: 16,
|
|
||||||
theme: {
|
|
||||||
background: '#282C34',
|
|
||||||
foreground: '#ffffff',
|
|
||||||
cursor: '#ffffff',
|
|
||||||
cursorAccent: '#282C34',
|
|
||||||
selection: '#41454E',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
var command = "";
|
|
||||||
var need_more_lines = false;
|
|
||||||
var stopped = false;
|
|
||||||
var repl = 0;
|
|
||||||
|
|
||||||
var Module = {
|
|
||||||
'print': function(text) {
|
|
||||||
term.write(text + "\r\n");
|
|
||||||
},
|
|
||||||
'printErr': function(text) {
|
|
||||||
term.write(text + "\r\n");
|
|
||||||
},
|
|
||||||
'onRuntimeInitialized': function(text) {
|
|
||||||
var vm = Module.ccall('pkpy_new_vm', 'number', ['boolean'], [true]);
|
|
||||||
repl = Module.ccall('pkpy_new_repl', 'number', ['number'], [vm]);
|
|
||||||
term.write(need_more_lines ? "... " : ">>> ");
|
|
||||||
},
|
|
||||||
'onAbort': function(text) {
|
|
||||||
stopped = true;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function term_init() {
|
|
||||||
term.open(document.getElementById('terminal'));
|
|
||||||
const addon = new FitAddon();
|
|
||||||
term.loadAddon(addon);
|
|
||||||
addon.fit();
|
|
||||||
|
|
||||||
// refit when window is resized
|
|
||||||
window.addEventListener('resize', () => {
|
|
||||||
addon.fit();
|
|
||||||
});
|
|
||||||
|
|
||||||
term.onData(e => {
|
|
||||||
if (stopped) return;
|
|
||||||
switch (e) {
|
|
||||||
case '\r': // Enter
|
|
||||||
term.write("\r\n");
|
|
||||||
need_more_lines = Module.ccall('pkpy_repl_input', 'bool', ['number', 'string'], [repl, command]);
|
|
||||||
command = '';
|
|
||||||
term.write(need_more_lines ? "... " : ">>> ");
|
|
||||||
break;
|
|
||||||
case '\u007F': // Backspace (DEL)
|
|
||||||
var cnt = term._core.buffer.x-4;
|
|
||||||
if(cnt<=0 || command.length==0) break;
|
|
||||||
// delete the last unicode char
|
|
||||||
command = command.replace(/.$/u, "");
|
|
||||||
// clear the whole line
|
|
||||||
term.write('\b \b'.repeat(cnt));
|
|
||||||
// re-write the command
|
|
||||||
term.write(command);
|
|
||||||
break;
|
|
||||||
default: // Print all other characters for demo
|
|
||||||
if (e >= String.fromCharCode(0x20) && e <= String.fromCharCode(0x7E) || e >= '\u00a0') {
|
|
||||||
command += e;
|
|
||||||
term.write(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
423
web/static/codejar/codejar.js
Normal file
423
web/static/codejar/codejar.js
Normal file
@ -0,0 +1,423 @@
|
|||||||
|
const globalWindow = window;
|
||||||
|
function CodeJar(editor, highlight, opt = {}) {
|
||||||
|
const options = Object.assign({ tab: '\t', indentOn: /{$/, spellcheck: false, catchTab: true, preserveIdent: true, addClosing: true, history: true, window: globalWindow }, opt);
|
||||||
|
const window = options.window;
|
||||||
|
const document = window.document;
|
||||||
|
let listeners = [];
|
||||||
|
let history = [];
|
||||||
|
let at = -1;
|
||||||
|
let focus = false;
|
||||||
|
let callback;
|
||||||
|
let prev; // code content prior keydown event
|
||||||
|
let isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||||
|
editor.setAttribute('contentEditable', isFirefox ? 'true' : 'plaintext-only');
|
||||||
|
editor.setAttribute('spellcheck', options.spellcheck ? 'true' : 'false');
|
||||||
|
editor.style.outline = 'none';
|
||||||
|
editor.style.overflowWrap = 'break-word';
|
||||||
|
editor.style.overflowY = 'auto';
|
||||||
|
editor.style.resize = 'vertical';
|
||||||
|
editor.style.whiteSpace = 'pre-wrap';
|
||||||
|
highlight(editor);
|
||||||
|
const debounceHighlight = debounce(() => {
|
||||||
|
const pos = save();
|
||||||
|
highlight(editor, pos);
|
||||||
|
restore(pos);
|
||||||
|
}, 30);
|
||||||
|
let recording = false;
|
||||||
|
const shouldRecord = (event) => {
|
||||||
|
return !isUndo(event) && !isRedo(event)
|
||||||
|
&& event.key !== 'Meta'
|
||||||
|
&& event.key !== 'Control'
|
||||||
|
&& event.key !== 'Alt'
|
||||||
|
&& !event.key.startsWith('Arrow');
|
||||||
|
};
|
||||||
|
const debounceRecordHistory = debounce((event) => {
|
||||||
|
if (shouldRecord(event)) {
|
||||||
|
recordHistory();
|
||||||
|
recording = false;
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
const on = (type, fn) => {
|
||||||
|
listeners.push([type, fn]);
|
||||||
|
editor.addEventListener(type, fn);
|
||||||
|
};
|
||||||
|
on('keydown', event => {
|
||||||
|
if (event.defaultPrevented)
|
||||||
|
return;
|
||||||
|
prev = toString();
|
||||||
|
if (options.preserveIdent)
|
||||||
|
handleNewLine(event);
|
||||||
|
else
|
||||||
|
firefoxNewLineFix(event);
|
||||||
|
if (options.catchTab)
|
||||||
|
handleTabCharacters(event);
|
||||||
|
if (options.addClosing)
|
||||||
|
handleSelfClosingCharacters(event);
|
||||||
|
if (options.history) {
|
||||||
|
handleUndoRedo(event);
|
||||||
|
if (shouldRecord(event) && !recording) {
|
||||||
|
recordHistory();
|
||||||
|
recording = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
on('keyup', event => {
|
||||||
|
if (event.defaultPrevented)
|
||||||
|
return;
|
||||||
|
if (event.isComposing)
|
||||||
|
return;
|
||||||
|
if (prev !== toString())
|
||||||
|
debounceHighlight();
|
||||||
|
debounceRecordHistory(event);
|
||||||
|
if (callback)
|
||||||
|
callback(toString());
|
||||||
|
});
|
||||||
|
on('focus', _event => {
|
||||||
|
focus = true;
|
||||||
|
});
|
||||||
|
on('blur', _event => {
|
||||||
|
focus = false;
|
||||||
|
});
|
||||||
|
on('paste', event => {
|
||||||
|
recordHistory();
|
||||||
|
handlePaste(event);
|
||||||
|
recordHistory();
|
||||||
|
if (callback)
|
||||||
|
callback(toString());
|
||||||
|
});
|
||||||
|
function save() {
|
||||||
|
const s = getSelection();
|
||||||
|
const pos = { start: 0, end: 0, dir: undefined };
|
||||||
|
visit(editor, el => {
|
||||||
|
if (el === s.anchorNode && el === s.focusNode) {
|
||||||
|
pos.start += s.anchorOffset;
|
||||||
|
pos.end += s.focusOffset;
|
||||||
|
pos.dir = s.anchorOffset <= s.focusOffset ? '->' : '<-';
|
||||||
|
return 'stop';
|
||||||
|
}
|
||||||
|
if (el === s.anchorNode) {
|
||||||
|
pos.start += s.anchorOffset;
|
||||||
|
if (!pos.dir) {
|
||||||
|
pos.dir = '->';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'stop';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (el === s.focusNode) {
|
||||||
|
pos.end += s.focusOffset;
|
||||||
|
if (!pos.dir) {
|
||||||
|
pos.dir = '<-';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'stop';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (el.nodeType === Node.TEXT_NODE) {
|
||||||
|
if (pos.dir != '->')
|
||||||
|
pos.start += el.nodeValue.length;
|
||||||
|
if (pos.dir != '<-')
|
||||||
|
pos.end += el.nodeValue.length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
function restore(pos) {
|
||||||
|
const s = getSelection();
|
||||||
|
let startNode, startOffset = 0;
|
||||||
|
let endNode, endOffset = 0;
|
||||||
|
if (!pos.dir)
|
||||||
|
pos.dir = '->';
|
||||||
|
if (pos.start < 0)
|
||||||
|
pos.start = 0;
|
||||||
|
if (pos.end < 0)
|
||||||
|
pos.end = 0;
|
||||||
|
// Flip start and end if the direction reversed
|
||||||
|
if (pos.dir == '<-') {
|
||||||
|
const { start, end } = pos;
|
||||||
|
pos.start = end;
|
||||||
|
pos.end = start;
|
||||||
|
}
|
||||||
|
let current = 0;
|
||||||
|
visit(editor, el => {
|
||||||
|
if (el.nodeType !== Node.TEXT_NODE)
|
||||||
|
return;
|
||||||
|
const len = (el.nodeValue || '').length;
|
||||||
|
if (current + len >= pos.start) {
|
||||||
|
if (!startNode) {
|
||||||
|
startNode = el;
|
||||||
|
startOffset = pos.start - current;
|
||||||
|
}
|
||||||
|
if (current + len >= pos.end) {
|
||||||
|
endNode = el;
|
||||||
|
endOffset = pos.end - current;
|
||||||
|
return 'stop';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current += len;
|
||||||
|
});
|
||||||
|
// If everything deleted place cursor at editor
|
||||||
|
if (!startNode)
|
||||||
|
startNode = editor;
|
||||||
|
if (!endNode)
|
||||||
|
endNode = editor;
|
||||||
|
// Flip back the selection
|
||||||
|
if (pos.dir == '<-') {
|
||||||
|
[startNode, startOffset, endNode, endOffset] = [endNode, endOffset, startNode, startOffset];
|
||||||
|
}
|
||||||
|
s.setBaseAndExtent(startNode, startOffset, endNode, endOffset);
|
||||||
|
}
|
||||||
|
function beforeCursor() {
|
||||||
|
const s = getSelection();
|
||||||
|
const r0 = s.getRangeAt(0);
|
||||||
|
const r = document.createRange();
|
||||||
|
r.selectNodeContents(editor);
|
||||||
|
r.setEnd(r0.startContainer, r0.startOffset);
|
||||||
|
return r.toString();
|
||||||
|
}
|
||||||
|
function afterCursor() {
|
||||||
|
const s = getSelection();
|
||||||
|
const r0 = s.getRangeAt(0);
|
||||||
|
const r = document.createRange();
|
||||||
|
r.selectNodeContents(editor);
|
||||||
|
r.setStart(r0.endContainer, r0.endOffset);
|
||||||
|
return r.toString();
|
||||||
|
}
|
||||||
|
function handleNewLine(event) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
const before = beforeCursor();
|
||||||
|
const after = afterCursor();
|
||||||
|
let [padding] = findPadding(before);
|
||||||
|
let newLinePadding = padding;
|
||||||
|
// If last symbol is "{" ident new line
|
||||||
|
// Allow user defines indent rule
|
||||||
|
if (options.indentOn.test(before)) {
|
||||||
|
newLinePadding += options.tab;
|
||||||
|
}
|
||||||
|
// Preserve padding
|
||||||
|
if (newLinePadding.length > 0) {
|
||||||
|
preventDefault(event);
|
||||||
|
event.stopPropagation();
|
||||||
|
insert('\n' + newLinePadding);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
firefoxNewLineFix(event);
|
||||||
|
}
|
||||||
|
// Place adjacent "}" on next line
|
||||||
|
if (newLinePadding !== padding && after[0] === '}') {
|
||||||
|
const pos = save();
|
||||||
|
insert('\n' + padding);
|
||||||
|
restore(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function firefoxNewLineFix(event) {
|
||||||
|
// Firefox does not support plaintext-only mode
|
||||||
|
// and puts <div><br></div> on Enter. Let's help.
|
||||||
|
if (isFirefox && event.key === 'Enter') {
|
||||||
|
preventDefault(event);
|
||||||
|
event.stopPropagation();
|
||||||
|
if (afterCursor() == '') {
|
||||||
|
insert('\n ');
|
||||||
|
const pos = save();
|
||||||
|
pos.start = --pos.end;
|
||||||
|
restore(pos);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
insert('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleSelfClosingCharacters(event) {
|
||||||
|
const open = `([{'"`;
|
||||||
|
const close = `)]}'"`;
|
||||||
|
const codeAfter = afterCursor();
|
||||||
|
const codeBefore = beforeCursor();
|
||||||
|
const escapeCharacter = codeBefore.substr(codeBefore.length - 1) === '\\';
|
||||||
|
const charAfter = codeAfter.substr(0, 1);
|
||||||
|
if (close.includes(event.key) && !escapeCharacter && charAfter === event.key) {
|
||||||
|
// We already have closing char next to cursor.
|
||||||
|
// Move one char to right.
|
||||||
|
const pos = save();
|
||||||
|
preventDefault(event);
|
||||||
|
pos.start = ++pos.end;
|
||||||
|
restore(pos);
|
||||||
|
}
|
||||||
|
else if (open.includes(event.key)
|
||||||
|
&& !escapeCharacter
|
||||||
|
&& (`"'`.includes(event.key) || ['', ' ', '\n'].includes(charAfter))) {
|
||||||
|
preventDefault(event);
|
||||||
|
const pos = save();
|
||||||
|
const wrapText = pos.start == pos.end ? '' : getSelection().toString();
|
||||||
|
const text = event.key + wrapText + close[open.indexOf(event.key)];
|
||||||
|
insert(text);
|
||||||
|
pos.start++;
|
||||||
|
pos.end++;
|
||||||
|
restore(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleTabCharacters(event) {
|
||||||
|
if (event.key === 'Tab') {
|
||||||
|
preventDefault(event);
|
||||||
|
if (event.shiftKey) {
|
||||||
|
const before = beforeCursor();
|
||||||
|
let [padding, start,] = findPadding(before);
|
||||||
|
if (padding.length > 0) {
|
||||||
|
const pos = save();
|
||||||
|
// Remove full length tab or just remaining padding
|
||||||
|
const len = Math.min(options.tab.length, padding.length);
|
||||||
|
restore({ start, end: start + len });
|
||||||
|
document.execCommand('delete');
|
||||||
|
pos.start -= len;
|
||||||
|
pos.end -= len;
|
||||||
|
restore(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
insert(options.tab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleUndoRedo(event) {
|
||||||
|
if (isUndo(event)) {
|
||||||
|
preventDefault(event);
|
||||||
|
at--;
|
||||||
|
const record = history[at];
|
||||||
|
if (record) {
|
||||||
|
editor.innerHTML = record.html;
|
||||||
|
restore(record.pos);
|
||||||
|
}
|
||||||
|
if (at < 0)
|
||||||
|
at = 0;
|
||||||
|
}
|
||||||
|
if (isRedo(event)) {
|
||||||
|
preventDefault(event);
|
||||||
|
at++;
|
||||||
|
const record = history[at];
|
||||||
|
if (record) {
|
||||||
|
editor.innerHTML = record.html;
|
||||||
|
restore(record.pos);
|
||||||
|
}
|
||||||
|
if (at >= history.length)
|
||||||
|
at--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function recordHistory() {
|
||||||
|
if (!focus)
|
||||||
|
return;
|
||||||
|
const html = editor.innerHTML;
|
||||||
|
const pos = save();
|
||||||
|
const lastRecord = history[at];
|
||||||
|
if (lastRecord) {
|
||||||
|
if (lastRecord.html === html
|
||||||
|
&& lastRecord.pos.start === pos.start
|
||||||
|
&& lastRecord.pos.end === pos.end)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
at++;
|
||||||
|
history[at] = { html, pos };
|
||||||
|
history.splice(at + 1);
|
||||||
|
const maxHistory = 300;
|
||||||
|
if (at > maxHistory) {
|
||||||
|
at = maxHistory;
|
||||||
|
history.splice(0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handlePaste(event) {
|
||||||
|
preventDefault(event);
|
||||||
|
const text = (event.originalEvent || event)
|
||||||
|
.clipboardData
|
||||||
|
.getData('text/plain')
|
||||||
|
.replace(/\r/g, '');
|
||||||
|
const pos = save();
|
||||||
|
insert(text);
|
||||||
|
highlight(editor);
|
||||||
|
restore({ start: pos.start + text.length, end: pos.start + text.length });
|
||||||
|
}
|
||||||
|
function visit(editor, visitor) {
|
||||||
|
const queue = [];
|
||||||
|
if (editor.firstChild)
|
||||||
|
queue.push(editor.firstChild);
|
||||||
|
let el = queue.pop();
|
||||||
|
while (el) {
|
||||||
|
if (visitor(el) === 'stop')
|
||||||
|
break;
|
||||||
|
if (el.nextSibling)
|
||||||
|
queue.push(el.nextSibling);
|
||||||
|
if (el.firstChild)
|
||||||
|
queue.push(el.firstChild);
|
||||||
|
el = queue.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function isCtrl(event) {
|
||||||
|
return event.metaKey || event.ctrlKey;
|
||||||
|
}
|
||||||
|
function isUndo(event) {
|
||||||
|
return isCtrl(event) && !event.shiftKey && event.key === 'z';
|
||||||
|
}
|
||||||
|
function isRedo(event) {
|
||||||
|
return isCtrl(event) && event.shiftKey && event.key === 'z';
|
||||||
|
}
|
||||||
|
function insert(text) {
|
||||||
|
text = text
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''');
|
||||||
|
document.execCommand('insertHTML', false, text);
|
||||||
|
}
|
||||||
|
function debounce(cb, wait) {
|
||||||
|
let timeout = 0;
|
||||||
|
return (...args) => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = window.setTimeout(() => cb(...args), wait);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function findPadding(text) {
|
||||||
|
// Find beginning of previous line.
|
||||||
|
let i = text.length - 1;
|
||||||
|
while (i >= 0 && text[i] !== '\n')
|
||||||
|
i--;
|
||||||
|
i++;
|
||||||
|
// Find padding of the line.
|
||||||
|
let j = i;
|
||||||
|
while (j < text.length && /[ \t]/.test(text[j]))
|
||||||
|
j++;
|
||||||
|
return [text.substring(i, j) || '', i, j];
|
||||||
|
}
|
||||||
|
function toString() {
|
||||||
|
return editor.textContent || '';
|
||||||
|
}
|
||||||
|
function preventDefault(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
function getSelection() {
|
||||||
|
var _a;
|
||||||
|
if (((_a = editor.parentNode) === null || _a === void 0 ? void 0 : _a.nodeType) == Node.DOCUMENT_FRAGMENT_NODE) {
|
||||||
|
return editor.parentNode.getSelection();
|
||||||
|
}
|
||||||
|
return window.getSelection();
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
updateOptions(options) {
|
||||||
|
options = Object.assign(Object.assign({}, options), options);
|
||||||
|
},
|
||||||
|
updateCode(code) {
|
||||||
|
editor.textContent = code;
|
||||||
|
highlight(editor);
|
||||||
|
},
|
||||||
|
onUpdate(cb) {
|
||||||
|
callback = cb;
|
||||||
|
},
|
||||||
|
toString,
|
||||||
|
save,
|
||||||
|
restore,
|
||||||
|
recordHistory,
|
||||||
|
destroy() {
|
||||||
|
for (let [type, fn] of listeners) {
|
||||||
|
editor.removeEventListener(type, fn);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
60
web/static/codejar/linenumbers.js
Normal file
60
web/static/codejar/linenumbers.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
function withLineNumbers(highlight, options = {}) {
|
||||||
|
const opts = Object.assign({ class: "codejar-linenumbers", wrapClass: "codejar-wrap", width: "35px", backgroundColor: "rgba(128, 128, 128, 0.15)", color: "" }, options);
|
||||||
|
let lineNumbers;
|
||||||
|
return function (editor) {
|
||||||
|
highlight(editor);
|
||||||
|
if (!lineNumbers) {
|
||||||
|
lineNumbers = init(editor, opts);
|
||||||
|
editor.addEventListener("scroll", () => lineNumbers.style.top = `-${editor.scrollTop}px`);
|
||||||
|
}
|
||||||
|
const code = editor.textContent || "";
|
||||||
|
|
||||||
|
//const linesCount = code.replace(/\n+$/, "\n").split("\n").length + 1;
|
||||||
|
const linesCount = code.split("\n").length;
|
||||||
|
|
||||||
|
let text = "";
|
||||||
|
for (let i = 1; i < linesCount; i++) {
|
||||||
|
text += `${i}\n`;
|
||||||
|
}
|
||||||
|
lineNumbers.innerText = text;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function init(editor, opts) {
|
||||||
|
const css = getComputedStyle(editor);
|
||||||
|
const wrap = document.createElement("div");
|
||||||
|
wrap.className = opts.wrapClass;
|
||||||
|
wrap.style.position = "relative";
|
||||||
|
const gutter = document.createElement("div");
|
||||||
|
gutter.className = opts.class;
|
||||||
|
wrap.appendChild(gutter);
|
||||||
|
// Add own styles
|
||||||
|
gutter.style.position = "absolute";
|
||||||
|
gutter.style.top = "0px";
|
||||||
|
gutter.style.left = "0px";
|
||||||
|
gutter.style.bottom = "0px";
|
||||||
|
gutter.style.width = opts.width;
|
||||||
|
gutter.style.overflow = "hidden";
|
||||||
|
gutter.style.backgroundColor = opts.backgroundColor;
|
||||||
|
gutter.style.color = opts.color || css.color;
|
||||||
|
gutter.style.setProperty("mix-blend-mode", "difference");
|
||||||
|
// Copy editor styles
|
||||||
|
gutter.style.fontFamily = css.fontFamily;
|
||||||
|
gutter.style.fontSize = css.fontSize;
|
||||||
|
gutter.style.lineHeight = css.lineHeight;
|
||||||
|
gutter.style.paddingTop = css.paddingTop;
|
||||||
|
gutter.style.paddingLeft = css.paddingLeft;
|
||||||
|
gutter.style.borderTopLeftRadius = css.borderTopLeftRadius;
|
||||||
|
gutter.style.borderBottomLeftRadius = css.borderBottomLeftRadius;
|
||||||
|
// Add line numbers
|
||||||
|
const lineNumbers = document.createElement("div");
|
||||||
|
lineNumbers.style.position = "relative";
|
||||||
|
lineNumbers.style.top = "0px";
|
||||||
|
gutter.appendChild(lineNumbers);
|
||||||
|
// Tweak editor styles
|
||||||
|
editor.style.paddingLeft = `calc(${opts.width} + ${gutter.style.paddingLeft})`;
|
||||||
|
editor.style.whiteSpace = "pre";
|
||||||
|
// Swap editor with a wrap
|
||||||
|
editor.parentNode.insertBefore(wrap, editor);
|
||||||
|
wrap.appendChild(editor);
|
||||||
|
return lineNumbers;
|
||||||
|
}
|
11
web/static/highlight.js/github-dark-dimmed.min.css
vendored
Normal file
11
web/static/highlight.js/github-dark-dimmed.min.css
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
|
||||||
|
Theme: GitHub Dark Dimmed
|
||||||
|
Description: Dark dimmed theme as seen on github.com
|
||||||
|
Author: github.com
|
||||||
|
Maintainer: @Hirse
|
||||||
|
Updated: 2021-05-15
|
||||||
|
|
||||||
|
Colors taken from GitHub's CSS
|
||||||
|
*/
|
||||||
|
|
||||||
|
.hljs{color:#adbac7;background:#22272e}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#f47067}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#dcbdfb}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#6cb6ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#96d0ff}.hljs-built_in,.hljs-symbol{color:#f69d50}.hljs-code,.hljs-comment,.hljs-formula{color:#768390}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#8ddb8c}.hljs-subst{color:#adbac7}.hljs-section{color:#316dca;font-weight:700}.hljs-bullet{color:#eac55f}.hljs-emphasis{color:#adbac7;font-style:italic}.hljs-strong{color:#adbac7;font-weight:700}.hljs-addition{color:#b4f1b4;background-color:#1b4721}.hljs-deletion{color:#ffd8d3;background-color:#78191b}
|
1152
web/static/highlight.js/highlight.min.js
vendored
Normal file
1152
web/static/highlight.js/highlight.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1,174 +0,0 @@
|
|||||||
.xterm {
|
|
||||||
cursor: text;
|
|
||||||
position: relative;
|
|
||||||
user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm.focus,
|
|
||||||
.xterm:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm .xterm-helpers {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
/**
|
|
||||||
* The z-index of the helpers must be higher than the canvases in order for
|
|
||||||
* IMEs to appear on top.
|
|
||||||
*/
|
|
||||||
z-index: 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm .xterm-helper-textarea {
|
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
margin: 0;
|
|
||||||
/* Move textarea out of the screen to the far left, so that the cursor is not visible */
|
|
||||||
position: absolute;
|
|
||||||
opacity: 0;
|
|
||||||
left: -9999em;
|
|
||||||
top: 0;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
z-index: -5;
|
|
||||||
/** Prevent wrapping so the IME appears against the textarea at the correct position */
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
resize: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm .composition-view {
|
|
||||||
/* TODO: Composition position got messed up somewhere */
|
|
||||||
background: #000;
|
|
||||||
color: #FFF;
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
white-space: nowrap;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm .composition-view.active {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#terminal {
|
|
||||||
border: #FFF;
|
|
||||||
border-style: solid;
|
|
||||||
border-width: 1px;
|
|
||||||
padding: 4px;
|
|
||||||
/* zoom: 1.2 !important; */
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0px;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
background-color: #282C34;
|
|
||||||
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm .xterm-viewport {
|
|
||||||
/* On OS X this is required in order for the scroll bar to appear fully opaque */
|
|
||||||
/* background-color: rgb(13,17,23) !important; */
|
|
||||||
|
|
||||||
/*overflow-y: scroll;*/
|
|
||||||
overflow: hidden;
|
|
||||||
cursor: default;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm .xterm-screen {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm .xterm-screen canvas {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm .xterm-scroll-area {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm-char-measure-element {
|
|
||||||
display: inline-block;
|
|
||||||
visibility: hidden;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: -9999em;
|
|
||||||
line-height: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm.enable-mouse-events {
|
|
||||||
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm.xterm-cursor-pointer,
|
|
||||||
.xterm .xterm-cursor-pointer {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm.column-select.focus {
|
|
||||||
/* Column selection mode */
|
|
||||||
cursor: crosshair;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm .xterm-accessibility,
|
|
||||||
.xterm .xterm-message {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: 10;
|
|
||||||
color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm .live-region {
|
|
||||||
position: absolute;
|
|
||||||
left: -9999px;
|
|
||||||
width: 1px;
|
|
||||||
height: 1px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm-dim {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm-underline-1 { text-decoration: underline; }
|
|
||||||
.xterm-underline-2 { text-decoration: double underline; }
|
|
||||||
.xterm-underline-3 { text-decoration: wavy underline; }
|
|
||||||
.xterm-underline-4 { text-decoration: dotted underline; }
|
|
||||||
.xterm-underline-5 { text-decoration: dashed underline; }
|
|
||||||
|
|
||||||
.xterm-strikethrough {
|
|
||||||
text-decoration: line-through;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm-screen .xterm-decoration-container .xterm-decoration {
|
|
||||||
z-index: 6;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm-decoration-overview-ruler {
|
|
||||||
z-index: 7;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm-decoration-top {
|
|
||||||
z-index: 2;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user