CodeMirror 6.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4767 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
2024-01-13 17:40:47 +00:00
parent 24e418344e
commit f72e8cbd91
28 changed files with 155 additions and 520 deletions

View File

@ -1,5 +1,6 @@
import {LitElement, html, css, svg} from '/static/lit/lit-all.min.js';
let cm6;
let gSocket;
let gCurrentFile;
@ -201,7 +202,7 @@ class TfFilesElement extends LitElement {
let buffer = await file.arrayBuffer();
let text = new TextDecoder('latin1').decode(buffer);
gFiles[file.name] = {
doc: new CodeMirror.Doc(text, guessMode(file.name)),
doc: new cm6.EditorState.create({doc: text, extensions: cm6.extensions}),
buffer: buffer,
generation: -1,
isNew: true,
@ -435,7 +436,7 @@ function is_edit_only() {
return window.location.search == '?editonly=1' || window.innerWidth < 1024;
}
function edit() {
async function edit() {
if (editing()) {
return;
}
@ -444,33 +445,15 @@ function edit() {
document.getElementById("editPane").style.display = 'flex';
document.getElementById('viewPane').style.display = is_edit_only() ? 'none' : 'flex';
ensureLoaded([
{tagName: "script", attributes: {src: "/codemirror/codemirror.min.js"}},
{tagName: "link", attributes: {rel: "stylesheet", href: "/codemirror/base16-dark.min.css"}},
{tagName: "link", attributes: {rel: "stylesheet", href: "/codemirror/matchesonscrollbar.min.css"}},
{tagName: "link", attributes: {rel: "stylesheet", href: "/codemirror/dialog.min.css"}},
{tagName: "link", attributes: {rel: "stylesheet", href: "/codemirror/codemirror.min.css"}},
{tagName: "link", attributes: {rel: "stylesheet", href: "/codemirror/lint.css"}},
{tagName: "script", attributes: {src: "/codemirror/trailingspace.min.js"}},
{tagName: "script", attributes: {src: "/codemirror/dialog.min.js"}},
{tagName: "script", attributes: {src: "/codemirror/search.min.js"}},
{tagName: "script", attributes: {src: "/codemirror/searchcursor.min.js"}},
{tagName: "script", attributes: {src: "/codemirror/jump-to-line.min.js"}},
{tagName: "script", attributes: {src: "/codemirror/matchesonscrollbar.min.js"}},
{tagName: "script", attributes: {src: "/codemirror/annotatescrollbar.min.js"}},
{tagName: "script", attributes: {src: "/codemirror/javascript.min.js"}},
{tagName: "script", attributes: {src: "/codemirror/css.min.js"}},
{tagName: "script", attributes: {src: "/codemirror/xml.min.js"}},
{tagName: "script", attributes: {src: "/codemirror/htmlmixed.min.js"}},
{tagName: "script", attributes: {src: "/codemirror/lint.js"}},
{tagName: "script", attributes: {src: "/codemirror/jshint.min.js"}},
{tagName: "script", attributes: {src: "/codemirror/javascript-lint.min.js"}},
], function() {
load().catch(function(error) {
alert(error);
closeEditor();
});
});
try {
cm6 = await import('/codemirror/cm6.js');
gEditor = cm6.TildeFriendsEditorView(document.getElementById("editor"));
gEditor.onDocChange = updateFiles;
await load();
} catch (error) {
alert(`${error.message}\n\n${error.stack}`);
closeEditor();
}
}
function trace() {
@ -491,73 +474,51 @@ function loadFile(name, id) {
}
return response.text();
}).then(function(text) {
gFiles[name].doc = new CodeMirror.Doc(text, guessMode(name));
gFiles[name].doc = cm6.EditorState.create({doc: text, extensions: cm6.extensions});
gFiles[name].original = gFiles[name].doc.doc.toString();
if (!Object.values(gFiles).some(x => !x.doc)) {
openFile(Object.keys(gFiles).sort()[0]);
}
});
}
function load(path) {
return fetch((path || url()) + 'view').then(function(response) {
if (!response.ok) {
if (response.status == 404) {
return null;
} else {
throw new Error(response.status + ' ' + response.statusText);
}
async function load(path) {
let response = await fetch((path || url()) + 'view');
if (!response.ok) {
if (response.status == 404) {
return null;
} else {
throw new Error(response.status + ' ' + response.statusText);
}
return response.json();
}).then(function(json) {
if (!gEditor) {
gEditor = CodeMirror.fromTextArea(document.getElementById("editor"), {
'theme': 'base16-dark',
'lineNumbers': true,
'tabSize': 4,
'indentUnit': 4,
'indentWithTabs': true,
'showTrailingSpace': true,
'gutters': ['CodeMirror-lint-markers'],
'mode': {'js': 'javascript'}[(path || url()).split('.').pop()],
'lint': {
'options': {
esversion: 2021,
varstmt: true,
},
},
});
gEditor.on('changes', function() {
updateFiles();
});
}
gFiles = {};
let isApp = false;
let promises = [];
}
let json = await response.json();
gFiles = {};
let isApp = false;
let promises = [];
if (json && json['type'] == 'tildefriends-app') {
isApp = true;
Object.keys(json['files']).forEach(function(name) {
gFiles[name] = {};
promises.push(loadFile(name, json['files'][name]));
});
if (Object.keys(json['files']).length == 0) {
document.getElementById("editPane").style.display = 'flex';
}
gApp = json;
gApp.emoji = gApp.emoji || '📦';
document.getElementById('icon').innerHTML = gApp.emoji;
}
if (!isApp) {
if (json && json['type'] == 'tildefriends-app') {
isApp = true;
Object.keys(json['files']).forEach(function(name) {
gFiles[name] = {};
promises.push(loadFile(name, json['files'][name]));
});
if (Object.keys(json['files']).length == 0) {
document.getElementById("editPane").style.display = 'flex';
let text = '// New script.\n';
gCurrentFile = 'app.js';
gFiles[gCurrentFile] = {
doc: new CodeMirror.Doc(text, guessMode(gCurrentFile)),
};
openFile(gCurrentFile);
}
return Promise.all(promises);
});
gApp = json;
gApp.emoji = gApp.emoji || '📦';
document.getElementById('icon').innerHTML = gApp.emoji;
}
if (!isApp) {
document.getElementById("editPane").style.display = 'flex';
let text = '// New script.\n';
gCurrentFile = 'app.js';
gFiles[gCurrentFile] = {
doc: cm6.EditorState.create({doc: text, extensions: cm6.extensions}),
};
openFile(gCurrentFile);
}
return Promise.all(promises);
}
function closeEditor() {
@ -573,8 +534,8 @@ function explodePath() {
function save(save_to) {
document.getElementById("save").disabled = true;
if (gCurrentFile) {
gFiles[gCurrentFile].doc = gEditor.getDoc();
if (!gFiles[gCurrentFile].isNew && !gFiles[gCurrentFile].doc.isClean(gFiles[gCurrentFile].doc.changeGeneration())) {
gFiles[gCurrentFile].doc = gEditor.state;
if (!gFiles[gCurrentFile].isNew && !gFiles[gCurrentFile].doc.doc.toString() == gFiles[gCurrentFile].original) {
delete gFiles[gCurrentFile].buffer;
}
}
@ -592,7 +553,7 @@ function save(save_to) {
let promises = [];
for (let name of Object.keys(gFiles)) {
let file = gFiles[name];
if (!file.isNew && file.doc.isClean(file.generation)) {
if (!file.isNew && file.doc.doc.toString() == file.original) {
continue;
}
@ -603,7 +564,7 @@ function save(save_to) {
headers: {
'Content-Type': 'application/binary',
},
body: file.buffer ?? file.doc.getValue(),
body: file.buffer ?? file.doc.doc.toString(),
}).then(function(response) {
if (!response.ok) {
throw new Error('Saving "' + name + '": ' + response.status + ' ' + response.statusText);
@ -648,7 +609,7 @@ function save(save_to) {
}).finally(function() {
document.getElementById("save").disabled = false;
Object.values(gFiles).forEach(function(file) {
file.generation = file.doc.changeGeneration();
file.original = file.doc.doc.toString();
});
updateFiles();
});
@ -1029,11 +990,13 @@ function connectSocket(path) {
}
function openFile(name) {
let newDoc = (name && gFiles[name]) ? gFiles[name].doc : new CodeMirror.Doc("", guessMode(name));
let oldDoc = gEditor.swapDoc(newDoc);
let newDoc = (name && gFiles[name]) ? gFiles[name].doc : cm6.EditorState.create({doc: "", extensions: cm6.extensions});
let oldDoc = gEditor.state;
gEditor.setState(newDoc);
if (gFiles[gCurrentFile]) {
gFiles[gCurrentFile].doc = oldDoc;
if (!gFiles[gCurrentFile].isNew && gFiles[gCurrentFile].doc.isClean(oldDoc.generation)) {
if (!gFiles[gCurrentFile].isNew && gFiles[gCurrentFile].doc.doc.toString() == oldDoc.doc.toString()) {
delete gFiles[gCurrentFile].buffer;
}
}
@ -1046,7 +1009,7 @@ function updateFiles() {
let files = document.getElementsByTagName("tf-files-pane")[0];
if (files) {
files.files = Object.fromEntries(Object.keys(gFiles).map(file => [file, {
clean: gFiles[file].doc.isClean(gFiles[file].generation),
clean: (file == gCurrentFile ? gEditor.state.doc.toString() : gFiles[file].doc.doc.toString()) == gFiles[file].original,
}]));
files.current = gCurrentFile;
}
@ -1055,7 +1018,7 @@ function updateFiles() {
function makeNewFile(name) {
gFiles[name] = {
doc: new CodeMirror.Doc("", guessMode(name)),
doc: cm6.EditorState.create({extensions: cm6.extensions}),
generation: -1,
};
openFile(name);

View File

@ -27,11 +27,7 @@
</div>
<div class="hbox" style="height: 100%">
<tf-files-pane></tf-files-pane>
<div id="docPane" style="display: flex; flex: 1 1 50%; flex-flow: column">
<div style="flex: 1 1 50%; position: relative">
<textarea id="editor" class="main"></textarea>
</div>
</div>
<div style="display: flex; flex: 1 1 50%; flex-flow: column" id="editor"></div>
</div>
</div>
<div id="viewPane" class="vbox" style="flex: 1 1; overflow: auto">

View File

@ -64,14 +64,8 @@ a:active {
color: #eee8d5;
}
.CodeMirror {
.cm-editor {
height: 100%;
padding: 0;
top: 0;
left: 0;
right: 0;
bottom: 0;
position: absolute;
}
.cm-tab {