mirror of https://github.com/sveltejs/svelte
parent
1ac5b51f39
commit
4f6ffc4612
@ -0,0 +1,290 @@
|
|||||||
|
<script context="module">
|
||||||
|
let codemirror_promise;
|
||||||
|
let _CodeMirror;
|
||||||
|
|
||||||
|
if (process.browser) {
|
||||||
|
codemirror_promise = import(/* webpackChunkName: "codemirror" */ './_codemirror.js');
|
||||||
|
|
||||||
|
codemirror_promise.then(mod => {
|
||||||
|
_CodeMirror = mod.default;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { onMount, beforeUpdate, createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
export let mode;
|
||||||
|
export let code;
|
||||||
|
export let readonly = false;
|
||||||
|
export let error = null;
|
||||||
|
export let errorLoc = null;
|
||||||
|
export let warningCount = 0;
|
||||||
|
export let flex = false;
|
||||||
|
export let lineNumbers = true;
|
||||||
|
export let tab = true;
|
||||||
|
|
||||||
|
let w;
|
||||||
|
let h;
|
||||||
|
|
||||||
|
export function resize() {
|
||||||
|
editor.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
const modes = {
|
||||||
|
json: {
|
||||||
|
name: 'javascript',
|
||||||
|
json: true
|
||||||
|
},
|
||||||
|
handlebars: {
|
||||||
|
name: 'handlebars',
|
||||||
|
base: 'text/html'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const refs = {};
|
||||||
|
let editor;
|
||||||
|
let updating = false;
|
||||||
|
let marker;
|
||||||
|
let error_line;
|
||||||
|
let destroyed = false;
|
||||||
|
let CodeMirror;
|
||||||
|
|
||||||
|
$: if (CodeMirror) {
|
||||||
|
createEditor(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
$: if (editor && !updating && code != null) {
|
||||||
|
updating = true;
|
||||||
|
editor.setValue(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
$: if (editor && w && h) {
|
||||||
|
editor.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if (marker) marker.clear();
|
||||||
|
|
||||||
|
if (errorLoc) {
|
||||||
|
const line = errorLoc.line - 1;
|
||||||
|
const ch = errorLoc.column;
|
||||||
|
|
||||||
|
marker = editor.markText({ line, ch }, { line, ch: ch + 1 }, {
|
||||||
|
className: 'error-loc'
|
||||||
|
});
|
||||||
|
|
||||||
|
error_line = line;
|
||||||
|
} else {
|
||||||
|
error_line = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let previous_error_line;
|
||||||
|
$: if (editor) {
|
||||||
|
if (previous_error_line != null) {
|
||||||
|
editor.removeLineClass(previous_error_line, 'wrap', 'error-line')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error_line && (error_line !== previous_error_line)) {
|
||||||
|
editor.addLineClass(error_line, 'wrap', 'error-line');
|
||||||
|
previous_error_line = error_line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if (_CodeMirror) {
|
||||||
|
CodeMirror = _CodeMirror;
|
||||||
|
} else {
|
||||||
|
codemirror_promise.then(mod => {
|
||||||
|
CodeMirror = mod.default;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
destroyed = true;
|
||||||
|
if (editor) editor.toTextArea();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeUpdate(() => {
|
||||||
|
updating = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
function createEditor(mode) {
|
||||||
|
if (destroyed) return;
|
||||||
|
|
||||||
|
if (editor) {
|
||||||
|
editor.toTextArea();
|
||||||
|
}
|
||||||
|
|
||||||
|
const opts = {
|
||||||
|
lineNumbers,
|
||||||
|
lineWrapping: true,
|
||||||
|
indentWithTabs: true,
|
||||||
|
indentUnit: 2,
|
||||||
|
tabSize: 2,
|
||||||
|
value: code,
|
||||||
|
mode: modes[mode] || {
|
||||||
|
name: mode
|
||||||
|
},
|
||||||
|
readOnly: readonly
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!tab) opts.extraKeys = {
|
||||||
|
Tab: tab,
|
||||||
|
'Shift-Tab': tab
|
||||||
|
};
|
||||||
|
|
||||||
|
editor = CodeMirror.fromTextArea(refs.editor, opts);
|
||||||
|
|
||||||
|
editor.on('change', instance => {
|
||||||
|
if (!updating) {
|
||||||
|
updating = true;
|
||||||
|
code = instance.getValue();
|
||||||
|
dispatch('change', { value: code });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
editor.refresh();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.codemirror-container {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codemirror-container :global(.CodeMirror) {
|
||||||
|
height: 100%;
|
||||||
|
/* background: var(--background); */
|
||||||
|
background: transparent;
|
||||||
|
font: 400 var(--code-fs)/1.7 var(--font-mono);
|
||||||
|
color: var(--base);
|
||||||
|
}
|
||||||
|
|
||||||
|
.codemirror-container.flex :global(.CodeMirror) {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codemirror-container.flex :global(.CodeMirror-lines) {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codemirror-container :global(.CodeMirror-gutters) {
|
||||||
|
padding: 0 1.6rem 0 .8rem;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codemirror-container .message {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 2.4rem;
|
||||||
|
left: 2.4rem;
|
||||||
|
z-index: 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codemirror-container :global(.error-loc) {
|
||||||
|
position: relative;
|
||||||
|
border-bottom: 2px solid #da106e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codemirror-container :global(.error-line) {
|
||||||
|
background-color: rgba(200, 0, 0, .05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading,
|
||||||
|
.error {
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
font-weight: 400;
|
||||||
|
margin: 2.4rem 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
background-color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
border: none;
|
||||||
|
padding: 4px 4px 4px 57px;
|
||||||
|
resize: none;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 1.3rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
user-select: none;
|
||||||
|
pointer-events: none;
|
||||||
|
color: #ccc;
|
||||||
|
tab-size: 2;
|
||||||
|
-moz-tab-size: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex pre {
|
||||||
|
padding: 0 0 0 4px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex .loading {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
-----------------------------------------------
|
||||||
|
syntax-highlighting [prism]
|
||||||
|
NOTE
|
||||||
|
- just started to transfer colors from prism to codemirror
|
||||||
|
-----------------------------------------------
|
||||||
|
-->
|
||||||
|
<div class='codemirror-container' class:flex bind:offsetWidth={w} bind:offsetHeight={h}>
|
||||||
|
<textarea
|
||||||
|
tabindex='2'
|
||||||
|
bind:this={refs.editor}
|
||||||
|
readonly
|
||||||
|
value={code}
|
||||||
|
></textarea>
|
||||||
|
|
||||||
|
{#if error}
|
||||||
|
<p class='error message'>
|
||||||
|
{#if error.loc}
|
||||||
|
<strong>
|
||||||
|
{#if error.filename}
|
||||||
|
<span
|
||||||
|
class='filename'
|
||||||
|
on:click="{() => dispatch('navigate', { filename: error.filename })}"
|
||||||
|
>{error.filename}</span>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
({error.loc.line}:{error.loc.column})
|
||||||
|
</strong>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{error.message}
|
||||||
|
</p>
|
||||||
|
{:else if warningCount > 0}
|
||||||
|
<p class='warning message'>
|
||||||
|
Compiled, but with {warningCount} {warningCount === 1 ? 'warning' : 'warnings'} — check the console for details
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if !CodeMirror}
|
||||||
|
<pre style="position: absolute; left: 0; top: 0"
|
||||||
|
>{code}</pre>
|
||||||
|
|
||||||
|
<p class='loading message'>loading editor...</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
Loading…
Reference in new issue