dashboard/plugins/codemirror.js

170 lines
4.5 KiB
JavaScript

/*
* NOTE: This isn't actually a real plugin anymore, it's is dynamically loaded in components/CodeMirror.vue
* so that it doesn't all get loaded put into vendor.js
*/
import Vue from 'vue';
import VueCodemirror from 'vue-codemirror';
import CodeMirror from 'codemirror';
import 'codemirror/lib/codemirror.css';
import 'codemirror/mode/yaml/yaml.js';
import 'codemirror/mode/javascript/javascript.js';
// import 'codemirror/mode/dockerfile/dockerfile.js';
// import 'codemirror/mode/shell/shell.js';
// import 'codemirror/mode/markdown/markdown.js';
import 'codemirror/theme/base16-light.css';
import 'codemirror/theme/base16-dark.css';
import 'codemirror/keymap/vim.js';
import 'codemirror/keymap/emacs.js';
import 'codemirror/keymap/sublime.js';
import 'codemirror/addon/lint/lint.css';
import 'codemirror/addon/lint/lint.js';
import 'codemirror/addon/lint/yaml-lint.js';
import 'codemirror/addon/fold/foldgutter.css';
import 'codemirror/addon/fold/foldgutter.js';
import 'codemirror/addon/hint/show-hint.css';
import 'codemirror/addon/hint/show-hint.js';
import 'codemirror/addon/hint/anyword-hint.js';
import { strPad } from '@/utils/string';
Vue.use(VueCodemirror);
export default VueCodemirror;
function isLineComment(cm, lineNo) {
return /\bcomment\b/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0)));
}
function commentIndent(cm, lineNo) {
const text = cm.getLine(lineNo).substr(1);
const spaceTo = text.search(/\S/);
if (spaceTo === -1 ) {
return -1;
}
const out = CodeMirror.countColumn(text, null, cm.getOption('tabSize'));
return out;
}
// Like the regular indent in codemirror, but treat a YAML array
// item that's at the same level as the parent key as intented on level more
//
// foo:
// - a
// - b
function lineIndent(cm, lineNo) {
let text = cm.getLine(lineNo);
const match = text.match(/(\s*(-\s+)?)(\S.*)/);
if ( !match ) {
return -1;
}
const spaceTo = match[1].length;
text = strPad('', spaceTo) + match[3];
if ( /\bcomment\b/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo, spaceTo + 1)))) {
return -1;
}
return CodeMirror.countColumn(text, null, cm.getOption('tabSize'));
}
// https://github.com/codemirror/CodeMirror/blob/master/addon/fold/indent-fold.js
CodeMirror.registerHelper('fold', 'indent', (cm, start) => {
const myIndent = lineIndent(cm, start.line);
if (myIndent < 0) {
return;
}
let lastLineInFold = null;
// Go through lines until we find a line that definitely doesn't belong in
// the block we're folding, or to the end.
for (let i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
const indent = lineIndent(cm, i);
if (indent === -1) {
} else if (indent > myIndent) {
// Lines with a greater indent are considered part of the block.
lastLineInFold = i;
} else {
// If this line has non-space, non-comment content, and is
// indented less or equal to the start line, it is the start of
// another block.
break;
}
}
if (lastLineInFold) {
return {
from: CodeMirror.Pos(start.line, cm.getLine(start.line).length),
to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
};
}
});
CodeMirror.defineExtension('foldLinesMatching', function(regex) {
this.operation(() => {
for (let i = this.firstLine(), e = this.lastLine(); i <= e; i++) {
const line = this.getLine(i);
if ( line.match(regex) ) {
this.foldCode(CodeMirror.Pos(i, 0), null, 'fold');
}
}
});
});
CodeMirror.registerHelper('fold', 'yamlcomments', (cm, start) => {
if ( !isLineComment(cm, start.line) ) {
return;
}
const myIndent = commentIndent(cm, start.line);
if (myIndent < 0) {
return;
}
let lastLineInFold = null;
// Go through lines until we find a line that definitely doesn't belong in
// the block we're folding, or to the end.
for (let i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
if ( !isLineComment(cm, i) ) {
break;
}
const indent = commentIndent(cm, i);
if (indent === -1) {
// empty?
} else if (indent > myIndent) {
// Lines with a greater indent are considered part of the block.
lastLineInFold = i;
} else {
// If this line has non-space, non-comment content, and is
// indented less or equal to the start line, it is the start of
// another block.
break;
}
}
if (lastLineInFold) {
return {
from: CodeMirror.Pos(start.line, cm.getLine(start.line).length),
to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
};
}
});