import CodeMirror from 'codemirror/lib/codemirror'; import { fuzzyMatch, getCurrentWord } from './helpers'; import { columns, functions, keywords } from './bql-grammar.json'; const functionCompletions = functions.map(f => `${f}(`); const commands = ['select']; CodeMirror.registerHelper('hint', 'beancount-query', (cm) => { const cursor = cm.getCursor(); const line = cm.getLine(cursor.line); const currentWord = getCurrentWord(cursor, line); // keywords at the start of the line if (currentWord === line) { return { list: commands.filter(d => d.startsWith(currentWord)), from: new CodeMirror.Pos(cursor.line, 0), to: cursor, }; } return fuzzyMatch(cursor, currentWord, columns.concat(functionCompletions, keywords)); });
let start, end; if (position.lineNumber && position.columnNumber) { start = CodeMirror.Pos(position.lineNumber - 1, position.columnNumber - 1); end = CodeMirror.Pos(position.lineNumber - 1, position.columnNumber); } else if (position.start && position.end) { if (position.end.offset < position.start.offset) { end = CodeMirror.Pos(position.start.line - 1, position.start.column); start = CodeMirror.Pos(position.end.line - 1, position.end.column); } else { start = CodeMirror.Pos(position.start.line - 1, position.start.column); end = CodeMirror.Pos(position.end.line - 1, position.end.column); } } if (start && end) { severity = severity ? severity : 'error'; this.annotations.push({message: message, severity: severity, from: start, to: end}); } } } CodeMirror.registerHelper('lint', 'php', function (text, options) { const linter = new Linter(text); linter.lint(); return linter.annotations; });
CodeMirror.registerHelper('fold', 'beancount', (cm, start) => { const maxDepth = 100; function isHeader(lineNo) { const tokentype = cm.getTokenTypeAt(new CodeMirror.Pos(lineNo, 0)); return tokentype && /\bsection\b/.test(tokentype); } function headerLevel(lineNo) { const line = cm.getLine(lineNo); const match = line && line.match(/^\*+/); if (match && isHeader(lineNo)) { return match[0].length; } return maxDepth; } const level = headerLevel(start.line); if (level === maxDepth) { return undefined; } const lastLineNo = cm.lastLine(); let end = start.line; while (end < lastLineNo) { if (headerLevel(end + 1) <= level) { break; } ++end; } return { from: new CodeMirror.Pos(start.line, cm.getLine(start.line).length), to: new CodeMirror.Pos(end, cm.getLine(end).length), }; });
CodeMirror.registerHelper('hint', 'beancount', (cm) => { const cursor = cm.getCursor(); const line = cm.getLine(cursor.line); const token = cm.getTokenAt(cursor); const currentCharacter = line[cursor.ch - 1]; const currentWord = getCurrentWord(cursor, line); // If '#' has just been typed, there won't be a tag token yet if (currentCharacter === '#') { return { list: completionSources.tags, from: cursor, to: cursor, }; } if (token.type === 'tag') { return { list: completionSources.tags.filter((d) => d.startsWith(currentWord.slice(1))), from: new CodeMirror.Pos(cursor.line, token.start + 1), to: new CodeMirror.Pos(cursor.line, token.end), }; } // directives at the start of the line if (currentWord === line && line.length > 0) { return { list: completionSources.undatedDirectives.filter((d) => d.startsWith(currentWord)), from: new CodeMirror.Pos(cursor.line, 0), to: cursor, }; } const lineTokens = cm.getLineTokens(cursor.line); if (lineTokens.length > 0) { const startCurrentWord = cursor.ch - currentWord.length; const previousTokens = lineTokens.filter((d) => d.end <= startCurrentWord); // complete accounts for indented lines if (lineTokens[0].type === 'whitespace') { if (previousTokens.length === 1) { return substringMatch(cursor, currentWord, completionSources.accounts); } } // dated directives if (lineTokens[0].type === 'date') { // date whitespace -> complete directives if (previousTokens.length === 2) { return { list: completionSources.datedDirectives.filter((d) => d.startsWith(currentWord)), from: new CodeMirror.Pos(cursor.line, cursor.ch - currentWord.length), to: cursor, }; } if (previousTokens.length % 2 === 0) { const directiveType = previousTokens[2].string; if (directiveType in directiveCompletions) { const completionType = directiveCompletions[directiveType][previousTokens.length / 2 - 2]; return substringMatch(cursor, currentWord, completionSources[completionType]); } } } } return { list: [], }; });