Add autocomplete to editor [#4]
This commit is contained in:
parent
4d301adf31
commit
55b5232fa6
29
index.html
29
index.html
|
@ -8,6 +8,9 @@
|
|||
'self'
|
||||
'sha256-0SGl1PJNDyJwcV5T+weg2zpEMrh7xvlwO4oXgvZCeZk='
|
||||
'sha256-eue5ceZRwKVQ1OXOZSyU7MXCTZMlqsPi/TOIqh1Vlzo='
|
||||
'sha256-OvxDPyq6KQAoWh11DLJdBVlHHLkYYiy4EzqTjIEJbb4='
|
||||
'sha256-vnm8bzrI+krtz5228JDC2DoTv0e+sfnfTCiUnO2EBAM='
|
||||
'sha256-HYX1RusN7a369vYuOd1mGvxLcNL4z/MihkahAI2CH8k='
|
||||
;
|
||||
style-src 'self' https://cdnjs.cloudflare.com;
|
||||
img-src 'self' blob:;
|
||||
|
@ -23,6 +26,12 @@
|
|||
crossorigin="anonymous"
|
||||
>
|
||||
|
||||
<link rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.31.0/addon/hint/show-hint.min.css"
|
||||
integrity="sha256-Ng5EdzHS/CC37tR7tE75e4Th9+fBvOB4eYITOkXS22Q="
|
||||
crossorigin="anonymous"
|
||||
>
|
||||
|
||||
<link rel="stylesheet" href="styles/main.css">
|
||||
|
||||
<script src="scripts/requireConfig.js"></script>
|
||||
|
@ -35,11 +44,29 @@
|
|||
></script>
|
||||
|
||||
<meta
|
||||
name="cdn-codemirror"
|
||||
name="cdn-cm/lib/codemirror"
|
||||
content="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.31.0/codemirror.min.js"
|
||||
data-integrity="sha256-eue5ceZRwKVQ1OXOZSyU7MXCTZMlqsPi/TOIqh1Vlzo="
|
||||
>
|
||||
|
||||
<meta
|
||||
name="cdn-cm/addon/hint/show-hint"
|
||||
content="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.31.0/addon/hint/show-hint.min.js"
|
||||
data-integrity="sha256-OvxDPyq6KQAoWh11DLJdBVlHHLkYYiy4EzqTjIEJbb4="
|
||||
>
|
||||
|
||||
<meta
|
||||
name="cdn-cm/addon/edit/trailingspace"
|
||||
content="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.31.0/addon/edit/trailingspace.min.js"
|
||||
data-integrity="sha256-vnm8bzrI+krtz5228JDC2DoTv0e+sfnfTCiUnO2EBAM="
|
||||
>
|
||||
|
||||
<meta
|
||||
name="cdn-cm/addon/comment/comment"
|
||||
content="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.31.0/addon/comment/comment.min.js"
|
||||
data-integrity="sha256-HYX1RusN7a369vYuOd1mGvxLcNL4z/MihkahAI2CH8k="
|
||||
>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
define(['codemirror'], (CodeMirror) => {
|
||||
define([
|
||||
'cm/lib/codemirror',
|
||||
'cm/addon/hint/show-hint',
|
||||
'cm/addon/edit/trailingspace',
|
||||
'cm/addon/comment/comment',
|
||||
], (CodeMirror) => {
|
||||
'use strict';
|
||||
|
||||
const DELAY_AGENTCHANGE = 500;
|
||||
|
@ -82,27 +87,68 @@ define(['codemirror'], (CodeMirror) => {
|
|||
return options;
|
||||
}
|
||||
|
||||
build(container) {
|
||||
this.codePane = makeNode('div', {'class': 'pane-code'});
|
||||
this.viewPane = makeNode('div', {'class': 'pane-view'});
|
||||
this.viewPaneInner = makeNode('div', {'class': 'pane-view-inner'});
|
||||
|
||||
const options = this.buildOptions();
|
||||
this.viewPane.appendChild(this.viewPaneInner);
|
||||
this.viewPane.appendChild(options);
|
||||
|
||||
container.appendChild(this.codePane);
|
||||
container.appendChild(this.viewPane);
|
||||
|
||||
const code = this.loadCode() || this.defaultCode;
|
||||
buildEditor(container) {
|
||||
const value = this.loadCode() || this.defaultCode;
|
||||
CodeMirror.defineMode(
|
||||
'sequence',
|
||||
() => this.parser.getCodeMirrorMode()
|
||||
);
|
||||
this.code = new CodeMirror(this.codePane, {
|
||||
value: code,
|
||||
CodeMirror.registerHelper(
|
||||
'hint',
|
||||
'sequence',
|
||||
this.parser.getCodeMirrorHints()
|
||||
);
|
||||
const code = new CodeMirror(container, {
|
||||
value,
|
||||
mode: 'sequence',
|
||||
lineNumbers: true,
|
||||
showTrailingSpace: true,
|
||||
extraKeys: {
|
||||
'Tab': (cm) => cm.execCommand('indentMore'),
|
||||
'Shift-Tab': (cm) => cm.execCommand('indentLess'),
|
||||
'Cmd-/': (cm) => cm.toggleComment({padding: ''}),
|
||||
'Ctrl-/': (cm) => cm.toggleComment({padding: ''}),
|
||||
'Ctrl-Space': 'autocomplete',
|
||||
'Ctrl-Enter': 'autocomplete',
|
||||
'Cmd-Enter': 'autocomplete',
|
||||
},
|
||||
});
|
||||
let lastKey = 0;
|
||||
code.on('keydown', (cm, event) => {
|
||||
lastKey = event.keyCode;
|
||||
});
|
||||
code.on('endCompletion', () => {
|
||||
lastKey = 0;
|
||||
});
|
||||
code.on('change', (cm) => {
|
||||
if(cm.state.completionActive) {
|
||||
return;
|
||||
}
|
||||
if(lastKey === 13 || lastKey === 8) {
|
||||
return;
|
||||
}
|
||||
lastKey = 0;
|
||||
CodeMirror.commands.autocomplete(cm, null, {
|
||||
completeSingle: false,
|
||||
});
|
||||
});
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
build(container) {
|
||||
const codePane = makeNode('div', {'class': 'pane-code'});
|
||||
const viewPane = makeNode('div', {'class': 'pane-view'});
|
||||
this.viewPaneInner = makeNode('div', {'class': 'pane-view-inner'});
|
||||
|
||||
const options = this.buildOptions();
|
||||
viewPane.appendChild(this.viewPaneInner);
|
||||
viewPane.appendChild(options);
|
||||
|
||||
container.appendChild(codePane);
|
||||
container.appendChild(viewPane);
|
||||
|
||||
this.code = this.buildEditor(codePane);
|
||||
this.viewPaneInner.appendChild(this.renderer.svg());
|
||||
|
||||
this.code.on('change', () => this.update(false));
|
||||
|
|
|
@ -8,7 +8,11 @@ defineDescribe('Interface', ['./Interface'], (Interface) => {
|
|||
let ui = null;
|
||||
|
||||
beforeEach(() => {
|
||||
parser = jasmine.createSpyObj('parser', ['parse']);
|
||||
parser = jasmine.createSpyObj('parser', [
|
||||
'parse',
|
||||
'getCodeMirrorMode',
|
||||
'getCodeMirrorHints',
|
||||
]);
|
||||
parser.parse.and.returnValue({
|
||||
meta: {},
|
||||
stages: [],
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
define(() => {
|
||||
'use strict';
|
||||
|
||||
const TRIMMER = /^([ \t]*)(.*)$/;
|
||||
const SQUASH_START = /^[ \t\r\n:,]/;
|
||||
|
||||
function getHints(cm) {
|
||||
const cur = cm.getCursor();
|
||||
const token = cm.getTokenAt(cur);
|
||||
let partial = token.string;
|
||||
if(token.end > cur.ch) {
|
||||
partial = partial.substr(0, cur.ch - token.start);
|
||||
}
|
||||
const parts = TRIMMER.exec(partial);
|
||||
partial = parts[2];
|
||||
const from = token.start + parts[1].length;
|
||||
|
||||
const continuation = (cur.ch > 0 && token.state.line.length > 0);
|
||||
let comp = (continuation ?
|
||||
token.state.completions :
|
||||
token.state.beginCompletions
|
||||
);
|
||||
if(!continuation) {
|
||||
comp = comp.concat(token.state.knownAgent);
|
||||
}
|
||||
|
||||
const ln = cm.getLine(cur.line);
|
||||
const wordFrom = {line: cur.line, ch: from};
|
||||
const squashFrom = {line: cur.line, ch: from};
|
||||
if(from > 0 && ln[from - 1] === ' ') {
|
||||
squashFrom.ch --;
|
||||
}
|
||||
const wordTo = {line: cur.line, ch: token.end};
|
||||
const list = (comp
|
||||
.filter((opt) => opt.startsWith(partial))
|
||||
.map((opt) => {
|
||||
return {
|
||||
text: opt,
|
||||
displayText: (opt === '\n') ? '<END>' : opt.trim(),
|
||||
className: (opt === '\n') ? 'pick-virtual' : null,
|
||||
from: SQUASH_START.test(opt) ? squashFrom : wordFrom,
|
||||
to: wordTo,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
list,
|
||||
from: wordFrom,
|
||||
to: wordTo,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
getHints,
|
||||
};
|
||||
});
|
|
@ -1,114 +1,215 @@
|
|||
define(['core/ArrayUtilities'], (array) => {
|
||||
'use strict';
|
||||
|
||||
function makeCMCommaBlock(type, exits = {}) {
|
||||
return {type, then: Object.assign({
|
||||
const CM_END = {type: '', suggest: '\n', then: {}};
|
||||
const CM_ERROR = {type: 'error', then: {'': 0}};
|
||||
|
||||
function makeCMCommaBlock(type, suggest, exits = {}) {
|
||||
return {type, suggest, then: Object.assign({
|
||||
'': 0,
|
||||
',': {type: 'operator', then: {
|
||||
',': {type: 'operator', suggest: true, then: {
|
||||
'': 1,
|
||||
}},
|
||||
}, exits)};
|
||||
}
|
||||
|
||||
const CM_TEXT_TO_END = {type: 'string', then: {'': 0}};
|
||||
const CM_IDENT_LIST_TO_END = makeCMCommaBlock('variable');
|
||||
const CM_IDENT_LIST_TO_TEXT = makeCMCommaBlock('variable', {
|
||||
':': {type: 'operator', then: {'': CM_TEXT_TO_END}},
|
||||
const CM_TEXT_TO_END = {type: 'string', then: {'': 0, '\n': CM_END}};
|
||||
const CM_AGENT_LIST_TO_END = makeCMCommaBlock('variable', 'Agent', {
|
||||
'\n': CM_END,
|
||||
});
|
||||
const CM_AGENT_LIST_TO_TEXT = makeCMCommaBlock('variable', 'Agent', {
|
||||
':': {type: 'operator', suggest: true, then: {'': CM_TEXT_TO_END}},
|
||||
});
|
||||
const CM_AGENT_LIST_TO_OPTTEXT = makeCMCommaBlock('variable', 'Agent', {
|
||||
':': {type: 'operator', suggest: true, then: {'': CM_TEXT_TO_END}},
|
||||
'\n': CM_END,
|
||||
});
|
||||
|
||||
const CM_NOTE_SIDE = {type: 'keyword', then: {
|
||||
'of': {type: 'keyword', then: {'': CM_IDENT_LIST_TO_TEXT}},
|
||||
':': {type: 'operator', then: {'': CM_TEXT_TO_END}},
|
||||
'': CM_IDENT_LIST_TO_TEXT,
|
||||
}};
|
||||
const CM_NOTE_SIDE_THEN = {
|
||||
'of': {type: 'keyword', suggest: true, then: {
|
||||
'': CM_AGENT_LIST_TO_TEXT,
|
||||
}},
|
||||
':': {type: 'operator', suggest: true, then: {
|
||||
'': CM_TEXT_TO_END,
|
||||
}},
|
||||
'': CM_AGENT_LIST_TO_TEXT,
|
||||
};
|
||||
|
||||
const CM_CONNECT = {type: 'keyword', then: {
|
||||
'': CM_IDENT_LIST_TO_TEXT,
|
||||
const CM_NOTE_LSIDE = {
|
||||
type: 'keyword',
|
||||
suggest: ['left of ', 'left: '],
|
||||
then: CM_NOTE_SIDE_THEN,
|
||||
};
|
||||
|
||||
const CM_NOTE_RSIDE = {
|
||||
type: 'keyword',
|
||||
suggest: ['right of ', 'right: '],
|
||||
then: CM_NOTE_SIDE_THEN,
|
||||
};
|
||||
|
||||
const CM_CONNECT = {type: 'keyword', suggest: true, then: {
|
||||
'': CM_AGENT_LIST_TO_OPTTEXT,
|
||||
}};
|
||||
|
||||
const CM_COMMANDS = {type: 'error', then: {
|
||||
'title': {type: 'keyword', then: {'': CM_TEXT_TO_END}},
|
||||
'terminators': {type: 'keyword', then: {
|
||||
'none': {type: 'keyword', then: {}},
|
||||
'cross': {type: 'keyword', then: {}},
|
||||
'box': {type: 'keyword', then: {}},
|
||||
'bar': {type: 'keyword', then: {}},
|
||||
}},
|
||||
'define': {type: 'keyword', then: {'': CM_IDENT_LIST_TO_END}},
|
||||
'begin': {type: 'keyword', then: {'': CM_IDENT_LIST_TO_END}},
|
||||
'end': {type: 'keyword', then: {'': CM_IDENT_LIST_TO_END}},
|
||||
'if': {type: 'keyword', then: {
|
||||
'title': {type: 'keyword', suggest: true, then: {
|
||||
'': CM_TEXT_TO_END,
|
||||
':': {type: 'operator', then: {'': CM_TEXT_TO_END}},
|
||||
}},
|
||||
'else': {type: 'keyword', then: {
|
||||
'if': {type: 'keyword', then: {
|
||||
'terminators': {type: 'keyword', suggest: true, then: {
|
||||
'none': {type: 'keyword', suggest: true, then: {}},
|
||||
'cross': {type: 'keyword', suggest: true, then: {}},
|
||||
'box': {type: 'keyword', suggest: true, then: {}},
|
||||
'bar': {type: 'keyword', suggest: true, then: {}},
|
||||
}},
|
||||
'define': {type: 'keyword', suggest: true, then: {
|
||||
'': CM_AGENT_LIST_TO_END,
|
||||
}},
|
||||
'begin': {type: 'keyword', suggest: true, then: {
|
||||
'': CM_AGENT_LIST_TO_END,
|
||||
}},
|
||||
'end': {type: 'keyword', suggest: true, then: {
|
||||
'': CM_AGENT_LIST_TO_END,
|
||||
'\n': CM_END,
|
||||
}},
|
||||
'if': {type: 'keyword', suggest: true, then: {
|
||||
'': CM_TEXT_TO_END,
|
||||
':': {type: 'operator', suggest: true, then: {
|
||||
'': CM_TEXT_TO_END,
|
||||
':': {type: 'operator', then: {'': CM_TEXT_TO_END}},
|
||||
}},
|
||||
'\n': CM_END,
|
||||
}},
|
||||
'else': {type: 'keyword', suggest: ['else\n', 'else if: '], then: {
|
||||
'if': {type: 'keyword', suggest: 'if: ', then: {
|
||||
'': CM_TEXT_TO_END,
|
||||
':': {type: 'operator', suggest: true, then: {
|
||||
'': CM_TEXT_TO_END,
|
||||
}},
|
||||
}},
|
||||
'\n': CM_END,
|
||||
}},
|
||||
'repeat': {type: 'keyword', suggest: true, then: {
|
||||
'': CM_TEXT_TO_END,
|
||||
':': {type: 'operator', suggest: true, then: {
|
||||
'': CM_TEXT_TO_END,
|
||||
}},
|
||||
'\n': CM_END,
|
||||
}},
|
||||
'note': {type: 'keyword', suggest: true, then: {
|
||||
'over': {type: 'keyword', suggest: true, then: {
|
||||
'': CM_AGENT_LIST_TO_TEXT,
|
||||
}},
|
||||
'left': CM_NOTE_LSIDE,
|
||||
'right': CM_NOTE_RSIDE,
|
||||
'between': {type: 'keyword', suggest: true, then: {
|
||||
'': CM_AGENT_LIST_TO_TEXT,
|
||||
}},
|
||||
}},
|
||||
'repeat': {type: 'keyword', then: {
|
||||
'': CM_TEXT_TO_END,
|
||||
':': {type: 'operator', then: {'': CM_TEXT_TO_END}},
|
||||
'state': {type: 'keyword', suggest: 'state over ', then: {
|
||||
'over': {type: 'keyword', suggest: true, then: {
|
||||
'': CM_AGENT_LIST_TO_TEXT,
|
||||
}},
|
||||
}},
|
||||
'note': {type: 'keyword', then: {
|
||||
'over': {type: 'keyword', then: {'': CM_IDENT_LIST_TO_TEXT}},
|
||||
'left': CM_NOTE_SIDE,
|
||||
'right': CM_NOTE_SIDE,
|
||||
'between': {type: 'keyword', then: {'': CM_IDENT_LIST_TO_TEXT}},
|
||||
'text': {type: 'keyword', suggest: true, then: {
|
||||
'left': CM_NOTE_LSIDE,
|
||||
'right': CM_NOTE_RSIDE,
|
||||
}},
|
||||
'state': {type: 'keyword', then: {
|
||||
'over': {type: 'keyword', then: {'': CM_IDENT_LIST_TO_TEXT}},
|
||||
}},
|
||||
'text': {type: 'keyword', then: {
|
||||
'left': CM_NOTE_SIDE,
|
||||
'right': CM_NOTE_SIDE,
|
||||
}},
|
||||
'simultaneously': {type: 'keyword', then: {
|
||||
':': {type: 'operator', then: {}},
|
||||
'with': {type: 'keyword', then: {
|
||||
'': {type: 'variable', then: {
|
||||
'simultaneously': {type: 'keyword', suggest: true, then: {
|
||||
':': {type: 'operator', suggest: true, then: {}},
|
||||
'with': {type: 'keyword', suggest: true, then: {
|
||||
'': {type: 'variable', suggest: 'Label', then: {
|
||||
'': 0,
|
||||
':': {type: 'operator', then: {}},
|
||||
':': {type: 'operator', suggest: true, then: {}},
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
'': {type: 'variable', then: {
|
||||
'': {type: 'variable', suggest: 'Agent', then: {
|
||||
'->': CM_CONNECT,
|
||||
'-->': CM_CONNECT,
|
||||
'<-': CM_CONNECT,
|
||||
'<--': CM_CONNECT,
|
||||
'<->': CM_CONNECT,
|
||||
'<-->': CM_CONNECT,
|
||||
':': {type: 'operator', then: {}},
|
||||
':': {type: 'operator', suggest: true, override: 'Label', then: {}},
|
||||
'': 0,
|
||||
}},
|
||||
}};
|
||||
|
||||
function cmCheckToken(state, partial) {
|
||||
if(!partial && state.current === '\n') {
|
||||
// quoted newline is interpreted as a command separator;
|
||||
// probably not what the writer expected, so highlight it
|
||||
state.line.length = 0;
|
||||
return 'warning';
|
||||
function cmGetSuggestions(state, token, {suggest, then}) {
|
||||
if(token === '') {
|
||||
return state['known' + suggest];
|
||||
} else if(suggest === true) {
|
||||
if(Object.keys(then).length > 0) {
|
||||
return [token + ' '];
|
||||
} else {
|
||||
return [token + '\n'];
|
||||
}
|
||||
} else if(Array.isArray(suggest)) {
|
||||
return suggest;
|
||||
} else if(suggest) {
|
||||
return [suggest];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function cmMakeCompletions(state, path) {
|
||||
const comp = [];
|
||||
const {then} = array.last(path);
|
||||
Object.keys(then).forEach((token) => {
|
||||
let next = then[token];
|
||||
if(typeof next === 'number') {
|
||||
next = path[path.length - next - 1];
|
||||
}
|
||||
array.mergeSets(comp, cmGetSuggestions(state, token, next));
|
||||
});
|
||||
return comp;
|
||||
}
|
||||
|
||||
function updateSuggestion(state, locals, token, {suggest, override}) {
|
||||
if(locals.type) {
|
||||
if(suggest !== locals.type) {
|
||||
if(override) {
|
||||
locals.type = override;
|
||||
}
|
||||
array.mergeSets(
|
||||
state['known' + locals.type],
|
||||
[locals.value]
|
||||
);
|
||||
locals.type = '';
|
||||
} else {
|
||||
locals.value += token + ' ';
|
||||
}
|
||||
} else if(typeof suggest === 'string' && state['known' + suggest]) {
|
||||
locals.type = suggest;
|
||||
locals.value = token + ' ';
|
||||
}
|
||||
}
|
||||
|
||||
function cmCheckToken(state, eol) {
|
||||
const suggestions = {
|
||||
type: '',
|
||||
value: '',
|
||||
};
|
||||
let current = CM_COMMANDS;
|
||||
const path = [current];
|
||||
for(let i = 0; i < state.line.length; ++ i) {
|
||||
const token = state.line[i];
|
||||
let found = current.then[token] || current.then[''];
|
||||
if(found === undefined) {
|
||||
return 'error';
|
||||
|
||||
state.line.forEach((token, i) => {
|
||||
if(i === state.line.length - 1) {
|
||||
state.completions = cmMakeCompletions(state, path);
|
||||
}
|
||||
const found = current.then[token] || current.then[''];
|
||||
if(typeof found === 'number') {
|
||||
path.length -= found;
|
||||
current = array.last(path);
|
||||
} else {
|
||||
path.push(found);
|
||||
current = found;
|
||||
path.push(found || CM_ERROR);
|
||||
}
|
||||
current = array.last(path);
|
||||
updateSuggestion(state, suggestions, token, current);
|
||||
});
|
||||
if(eol) {
|
||||
updateSuggestion(state, suggestions, '', {});
|
||||
}
|
||||
state.nextCompletions = cmMakeCompletions(state, path);
|
||||
return current.type;
|
||||
}
|
||||
|
||||
|
@ -122,6 +223,11 @@ define(['core/ArrayUtilities'], (array) => {
|
|||
return {
|
||||
currentType: -1,
|
||||
current: '',
|
||||
knownAgent: [],
|
||||
knownLabel: [],
|
||||
beginCompletions: cmMakeCompletions({}, [CM_COMMANDS]),
|
||||
completions: [],
|
||||
nextCompletions: [],
|
||||
line: [],
|
||||
indent: 0,
|
||||
};
|
||||
|
@ -165,7 +271,13 @@ define(['core/ArrayUtilities'], (array) => {
|
|||
return 'comment';
|
||||
}
|
||||
state.line.push(state.current);
|
||||
return cmCheckToken(state, false);
|
||||
if(state.current === '\n') {
|
||||
// quoted newline is interpreted as a command separator;
|
||||
// probably not what the writer expected, so highlight it
|
||||
state.line.length = 0;
|
||||
return 'warning';
|
||||
}
|
||||
return cmCheckToken(state, stream.eol());
|
||||
}
|
||||
|
||||
_tokenEOLFound(stream, state, block) {
|
||||
|
@ -174,7 +286,7 @@ define(['core/ArrayUtilities'], (array) => {
|
|||
return 'comment';
|
||||
}
|
||||
state.line.push(state.current);
|
||||
const type = cmCheckToken(state, true);
|
||||
const type = cmCheckToken(state, false);
|
||||
state.line.pop();
|
||||
return type;
|
||||
}
|
||||
|
@ -194,6 +306,7 @@ define(['core/ArrayUtilities'], (array) => {
|
|||
}
|
||||
|
||||
token(stream, state) {
|
||||
state.completions = state.nextCompletions;
|
||||
if(stream.sol() && state.currentType === -1) {
|
||||
state.line.length = 0;
|
||||
}
|
||||
|
|
|
@ -247,7 +247,7 @@ define(['core/ArrayUtilities'], (array) => {
|
|||
meta: {
|
||||
title: meta.title,
|
||||
},
|
||||
agents: this.agents,
|
||||
agents: this.agents.slice(),
|
||||
stages: globals.stages,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
define(['core/ArrayUtilities', './CodeMirrorMode'], (array, CMMode) => {
|
||||
define([
|
||||
'core/ArrayUtilities',
|
||||
'./CodeMirrorMode',
|
||||
'./CodeMirrorHints',
|
||||
], (
|
||||
array,
|
||||
CMMode,
|
||||
CMHints
|
||||
) => {
|
||||
'use strict';
|
||||
|
||||
function execAt(str, reg, i) {
|
||||
|
@ -355,6 +363,10 @@ define(['core/ArrayUtilities', './CodeMirrorMode'], (array, CMMode) => {
|
|||
return new CMMode(TOKENS);
|
||||
}
|
||||
|
||||
getCodeMirrorHints() {
|
||||
return CMHints.getHints;
|
||||
}
|
||||
|
||||
splitLines(tokens) {
|
||||
const lines = [];
|
||||
let line = [];
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
define([], () => {
|
||||
'use strict';
|
||||
|
||||
return null;
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
define([], () => {
|
||||
'use strict';
|
||||
|
||||
return null;
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
define([], () => {
|
||||
'use strict';
|
||||
|
||||
return null;
|
||||
});
|
|
@ -13,6 +13,7 @@ define([], () => {
|
|||
}
|
||||
|
||||
CodeMirror.defineMode = () => null;
|
||||
CodeMirror.registerHelper = () => null;
|
||||
|
||||
return CodeMirror;
|
||||
});
|
||||
|
|
|
@ -24,6 +24,17 @@ html, body {
|
|||
.cm-s-default .cm-string {color: #221111;}
|
||||
.cm-s-default .cm-error {color: #FF0000;}
|
||||
|
||||
.cm-s-default .cm-warning {
|
||||
background: #FFFF00;
|
||||
}
|
||||
.cm-s-default .cm-trailingspace {
|
||||
background: rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.pick-virtual {
|
||||
color: #777777;
|
||||
}
|
||||
|
||||
.pane-view {
|
||||
position: absolute;
|
||||
left: 30%;
|
||||
|
|
5
test.htm
5
test.htm
|
@ -57,7 +57,10 @@
|
|||
data-integrity="sha256-Re9XxIL3x1flvE6WD58jWPdDzKYQLXwxS2HAVfmM6Z8="
|
||||
>
|
||||
|
||||
<meta name="cdn-codemirror" content="stubs/codemirror">
|
||||
<meta name="cdn-cm/lib/codemirror" content="stubs/codemirror">
|
||||
<meta name="cdn-cm/addon/hint/show-hint" content="stubs/codemirror-show-hint">
|
||||
<meta name="cdn-cm/addon/edit/trailingspace" content="stubs/codemirror-trailingspace">
|
||||
<meta name="cdn-cm/addon/comment/comment" content="stubs/codemirror-comment">
|
||||
|
||||
<!-- test files defined in scripts/specs.js -->
|
||||
|
||||
|
|
Loading…
Reference in New Issue