/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin */ var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // main.ts var main_exports = {}; __export(main_exports, { OrgmodeSettingTab: () => OrgmodeSettingTab, default: () => OrgmodePlugin }); module.exports = __toCommonJS(main_exports); var import_view3 = require("@codemirror/view"); var import_commands2 = require("@codemirror/commands"); var import_language5 = require("@codemirror/language"); var import_state3 = require("@codemirror/state"); // node_modules/@replit/codemirror-vim/dist/index.js var import_state = require("@codemirror/state"); var import_language = require("@codemirror/language"); var View = __toESM(require("@codemirror/view"), 1); var import_view = require("@codemirror/view"); var import_search = require("@codemirror/search"); var import_commands = require("@codemirror/commands"); function initVim(CodeMirror2) { var Pos3 = CodeMirror2.Pos; function updateSelectionForSurrogateCharacters(cm, curStart, curEnd) { if (curStart.line === curEnd.line && curStart.ch >= curEnd.ch - 1) { var text = cm.getLine(curStart.line); var charCode = text.charCodeAt(curStart.ch); if (55296 <= charCode && charCode <= 55551) { curEnd.ch += 1; } } return { start: curStart, end: curEnd }; } var defaultKeymap2 = [ // Key to key mapping. This goes first to make it possible to override // existing mappings. { keys: "", type: "keyToKey", toKeys: "h" }, { keys: "", type: "keyToKey", toKeys: "l" }, { keys: "", type: "keyToKey", toKeys: "k" }, { keys: "", type: "keyToKey", toKeys: "j" }, { keys: "g", type: "keyToKey", toKeys: "gk" }, { keys: "g", type: "keyToKey", toKeys: "gj" }, { keys: "", type: "keyToKey", toKeys: "l" }, { keys: "", type: "keyToKey", toKeys: "h" }, { keys: "", type: "keyToKey", toKeys: "x" }, { keys: "", type: "keyToKey", toKeys: "W" }, { keys: "", type: "keyToKey", toKeys: "B" }, { keys: "", type: "keyToKey", toKeys: "w" }, { keys: "", type: "keyToKey", toKeys: "b" }, { keys: "", type: "keyToKey", toKeys: "j" }, { keys: "", type: "keyToKey", toKeys: "k" }, { keys: "", type: "keyToKey", toKeys: "" }, { keys: "", type: "keyToKey", toKeys: "" }, { keys: "", type: "keyToKey", toKeys: "", context: "insert" }, { keys: "", type: "keyToKey", toKeys: "", context: "insert" }, { keys: "", type: "keyToKey", toKeys: "" }, // ipad keyboard sends C-Esc instead of C-[ { keys: "", type: "keyToKey", toKeys: "", context: "insert" }, { keys: "s", type: "keyToKey", toKeys: "cl", context: "normal" }, { keys: "s", type: "keyToKey", toKeys: "c", context: "visual" }, { keys: "S", type: "keyToKey", toKeys: "cc", context: "normal" }, { keys: "S", type: "keyToKey", toKeys: "VdO", context: "visual" }, { keys: "", type: "keyToKey", toKeys: "0" }, { keys: "", type: "keyToKey", toKeys: "$" }, { keys: "", type: "keyToKey", toKeys: "" }, { keys: "", type: "keyToKey", toKeys: "" }, { keys: "", type: "keyToKey", toKeys: "j^", context: "normal" }, { keys: "", type: "keyToKey", toKeys: "i", context: "normal" }, { keys: "", type: "action", action: "toggleOverwrite", context: "insert" }, // Motions { keys: "H", type: "motion", motion: "moveToTopLine", motionArgs: { linewise: true, toJumplist: true } }, { keys: "M", type: "motion", motion: "moveToMiddleLine", motionArgs: { linewise: true, toJumplist: true } }, { keys: "L", type: "motion", motion: "moveToBottomLine", motionArgs: { linewise: true, toJumplist: true } }, { keys: "h", type: "motion", motion: "moveByCharacters", motionArgs: { forward: false } }, { keys: "l", type: "motion", motion: "moveByCharacters", motionArgs: { forward: true } }, { keys: "j", type: "motion", motion: "moveByLines", motionArgs: { forward: true, linewise: true } }, { keys: "k", type: "motion", motion: "moveByLines", motionArgs: { forward: false, linewise: true } }, { keys: "gj", type: "motion", motion: "moveByDisplayLines", motionArgs: { forward: true } }, { keys: "gk", type: "motion", motion: "moveByDisplayLines", motionArgs: { forward: false } }, { keys: "w", type: "motion", motion: "moveByWords", motionArgs: { forward: true, wordEnd: false } }, { keys: "W", type: "motion", motion: "moveByWords", motionArgs: { forward: true, wordEnd: false, bigWord: true } }, { keys: "e", type: "motion", motion: "moveByWords", motionArgs: { forward: true, wordEnd: true, inclusive: true } }, { keys: "E", type: "motion", motion: "moveByWords", motionArgs: { forward: true, wordEnd: true, bigWord: true, inclusive: true } }, { keys: "b", type: "motion", motion: "moveByWords", motionArgs: { forward: false, wordEnd: false } }, { keys: "B", type: "motion", motion: "moveByWords", motionArgs: { forward: false, wordEnd: false, bigWord: true } }, { keys: "ge", type: "motion", motion: "moveByWords", motionArgs: { forward: false, wordEnd: true, inclusive: true } }, { keys: "gE", type: "motion", motion: "moveByWords", motionArgs: { forward: false, wordEnd: true, bigWord: true, inclusive: true } }, { keys: "{", type: "motion", motion: "moveByParagraph", motionArgs: { forward: false, toJumplist: true } }, { keys: "}", type: "motion", motion: "moveByParagraph", motionArgs: { forward: true, toJumplist: true } }, { keys: "(", type: "motion", motion: "moveBySentence", motionArgs: { forward: false } }, { keys: ")", type: "motion", motion: "moveBySentence", motionArgs: { forward: true } }, { keys: "", type: "motion", motion: "moveByPage", motionArgs: { forward: true } }, { keys: "", type: "motion", motion: "moveByPage", motionArgs: { forward: false } }, { keys: "", type: "motion", motion: "moveByScroll", motionArgs: { forward: true, explicitRepeat: true } }, { keys: "", type: "motion", motion: "moveByScroll", motionArgs: { forward: false, explicitRepeat: true } }, { keys: "gg", type: "motion", motion: "moveToLineOrEdgeOfDocument", motionArgs: { forward: false, explicitRepeat: true, linewise: true, toJumplist: true } }, { keys: "G", type: "motion", motion: "moveToLineOrEdgeOfDocument", motionArgs: { forward: true, explicitRepeat: true, linewise: true, toJumplist: true } }, { keys: "g$", type: "motion", motion: "moveToEndOfDisplayLine" }, { keys: "g^", type: "motion", motion: "moveToStartOfDisplayLine" }, { keys: "g0", type: "motion", motion: "moveToStartOfDisplayLine" }, { keys: "0", type: "motion", motion: "moveToStartOfLine" }, { keys: "^", type: "motion", motion: "moveToFirstNonWhiteSpaceCharacter" }, { keys: "+", type: "motion", motion: "moveByLines", motionArgs: { forward: true, toFirstChar: true } }, { keys: "-", type: "motion", motion: "moveByLines", motionArgs: { forward: false, toFirstChar: true } }, { keys: "_", type: "motion", motion: "moveByLines", motionArgs: { forward: true, toFirstChar: true, repeatOffset: -1 } }, { keys: "$", type: "motion", motion: "moveToEol", motionArgs: { inclusive: true } }, { keys: "%", type: "motion", motion: "moveToMatchedSymbol", motionArgs: { inclusive: true, toJumplist: true } }, { keys: "f", type: "motion", motion: "moveToCharacter", motionArgs: { forward: true, inclusive: true } }, { keys: "F", type: "motion", motion: "moveToCharacter", motionArgs: { forward: false } }, { keys: "t", type: "motion", motion: "moveTillCharacter", motionArgs: { forward: true, inclusive: true } }, { keys: "T", type: "motion", motion: "moveTillCharacter", motionArgs: { forward: false } }, { keys: ";", type: "motion", motion: "repeatLastCharacterSearch", motionArgs: { forward: true } }, { keys: ",", type: "motion", motion: "repeatLastCharacterSearch", motionArgs: { forward: false } }, { keys: "'", type: "motion", motion: "goToMark", motionArgs: { toJumplist: true, linewise: true } }, { keys: "`", type: "motion", motion: "goToMark", motionArgs: { toJumplist: true } }, { keys: "]`", type: "motion", motion: "jumpToMark", motionArgs: { forward: true } }, { keys: "[`", type: "motion", motion: "jumpToMark", motionArgs: { forward: false } }, { keys: "]'", type: "motion", motion: "jumpToMark", motionArgs: { forward: true, linewise: true } }, { keys: "['", type: "motion", motion: "jumpToMark", motionArgs: { forward: false, linewise: true } }, // the next two aren't motions but must come before more general motion declarations { keys: "]p", type: "action", action: "paste", isEdit: true, actionArgs: { after: true, isEdit: true, matchIndent: true } }, { keys: "[p", type: "action", action: "paste", isEdit: true, actionArgs: { after: false, isEdit: true, matchIndent: true } }, { keys: "]", type: "motion", motion: "moveToSymbol", motionArgs: { forward: true, toJumplist: true } }, { keys: "[", type: "motion", motion: "moveToSymbol", motionArgs: { forward: false, toJumplist: true } }, { keys: "|", type: "motion", motion: "moveToColumn" }, { keys: "o", type: "motion", motion: "moveToOtherHighlightedEnd", context: "visual" }, { keys: "O", type: "motion", motion: "moveToOtherHighlightedEnd", motionArgs: { sameLine: true }, context: "visual" }, // Operators { keys: "d", type: "operator", operator: "delete" }, { keys: "y", type: "operator", operator: "yank" }, { keys: "c", type: "operator", operator: "change" }, { keys: "=", type: "operator", operator: "indentAuto" }, { keys: ">", type: "operator", operator: "indent", operatorArgs: { indentRight: true } }, { keys: "<", type: "operator", operator: "indent", operatorArgs: { indentRight: false } }, { keys: "g~", type: "operator", operator: "changeCase" }, { keys: "gu", type: "operator", operator: "changeCase", operatorArgs: { toLower: true }, isEdit: true }, { keys: "gU", type: "operator", operator: "changeCase", operatorArgs: { toLower: false }, isEdit: true }, { keys: "n", type: "motion", motion: "findNext", motionArgs: { forward: true, toJumplist: true } }, { keys: "N", type: "motion", motion: "findNext", motionArgs: { forward: false, toJumplist: true } }, { keys: "gn", type: "motion", motion: "findAndSelectNextInclusive", motionArgs: { forward: true } }, { keys: "gN", type: "motion", motion: "findAndSelectNextInclusive", motionArgs: { forward: false } }, { keys: "gq", type: "operator", operator: "hardWrap" }, { keys: "gw", type: "operator", operator: "hardWrap", operatorArgs: { keepCursor: true } }, // Operator-Motion dual commands { keys: "x", type: "operatorMotion", operator: "delete", motion: "moveByCharacters", motionArgs: { forward: true }, operatorMotionArgs: { visualLine: false } }, { keys: "X", type: "operatorMotion", operator: "delete", motion: "moveByCharacters", motionArgs: { forward: false }, operatorMotionArgs: { visualLine: true } }, { keys: "D", type: "operatorMotion", operator: "delete", motion: "moveToEol", motionArgs: { inclusive: true }, context: "normal" }, { keys: "D", type: "operator", operator: "delete", operatorArgs: { linewise: true }, context: "visual" }, { keys: "Y", type: "operatorMotion", operator: "yank", motion: "expandToLine", motionArgs: { linewise: true }, context: "normal" }, { keys: "Y", type: "operator", operator: "yank", operatorArgs: { linewise: true }, context: "visual" }, { keys: "C", type: "operatorMotion", operator: "change", motion: "moveToEol", motionArgs: { inclusive: true }, context: "normal" }, { keys: "C", type: "operator", operator: "change", operatorArgs: { linewise: true }, context: "visual" }, { keys: "~", type: "operatorMotion", operator: "changeCase", motion: "moveByCharacters", motionArgs: { forward: true }, operatorArgs: { shouldMoveCursor: true }, context: "normal" }, { keys: "~", type: "operator", operator: "changeCase", context: "visual" }, { keys: "", type: "operatorMotion", operator: "delete", motion: "moveToStartOfLine", context: "insert" }, { keys: "", type: "operatorMotion", operator: "delete", motion: "moveByWords", motionArgs: { forward: false, wordEnd: false }, context: "insert" }, //ignore C-w in normal mode { keys: "", type: "idle", context: "normal" }, // Actions { keys: "", type: "action", action: "jumpListWalk", actionArgs: { forward: true } }, { keys: "", type: "action", action: "jumpListWalk", actionArgs: { forward: false } }, { keys: "", type: "action", action: "scroll", actionArgs: { forward: true, linewise: true } }, { keys: "", type: "action", action: "scroll", actionArgs: { forward: false, linewise: true } }, { keys: "a", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "charAfter" }, context: "normal" }, { keys: "A", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "eol" }, context: "normal" }, { keys: "A", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "endOfSelectedArea" }, context: "visual" }, { keys: "i", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "inplace" }, context: "normal" }, { keys: "gi", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "lastEdit" }, context: "normal" }, { keys: "I", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "firstNonBlank" }, context: "normal" }, { keys: "gI", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "bol" }, context: "normal" }, { keys: "I", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "startOfSelectedArea" }, context: "visual" }, { keys: "o", type: "action", action: "newLineAndEnterInsertMode", isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: true }, context: "normal" }, { keys: "O", type: "action", action: "newLineAndEnterInsertMode", isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: false }, context: "normal" }, { keys: "v", type: "action", action: "toggleVisualMode" }, { keys: "V", type: "action", action: "toggleVisualMode", actionArgs: { linewise: true } }, { keys: "", type: "action", action: "toggleVisualMode", actionArgs: { blockwise: true } }, { keys: "", type: "action", action: "toggleVisualMode", actionArgs: { blockwise: true } }, { keys: "gv", type: "action", action: "reselectLastSelection" }, { keys: "J", type: "action", action: "joinLines", isEdit: true }, { keys: "gJ", type: "action", action: "joinLines", actionArgs: { keepSpaces: true }, isEdit: true }, { keys: "p", type: "action", action: "paste", isEdit: true, actionArgs: { after: true, isEdit: true } }, { keys: "P", type: "action", action: "paste", isEdit: true, actionArgs: { after: false, isEdit: true } }, { keys: "r", type: "action", action: "replace", isEdit: true }, { keys: "@", type: "action", action: "replayMacro" }, { keys: "q", type: "action", action: "enterMacroRecordMode" }, // Handle Replace-mode as a special case of insert mode. { keys: "R", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { replace: true }, context: "normal" }, { keys: "R", type: "operator", operator: "change", operatorArgs: { linewise: true, fullLine: true }, context: "visual", exitVisualBlock: true }, { keys: "u", type: "action", action: "undo", context: "normal" }, { keys: "u", type: "operator", operator: "changeCase", operatorArgs: { toLower: true }, context: "visual", isEdit: true }, { keys: "U", type: "operator", operator: "changeCase", operatorArgs: { toLower: false }, context: "visual", isEdit: true }, { keys: "", type: "action", action: "redo" }, { keys: "m", type: "action", action: "setMark" }, { keys: '"', type: "action", action: "setRegister" }, { keys: "", type: "action", action: "insertRegister", context: "insert", isEdit: true }, { keys: "", type: "action", action: "oneNormalCommand", context: "insert" }, { keys: "zz", type: "action", action: "scrollToCursor", actionArgs: { position: "center" } }, { keys: "z.", type: "action", action: "scrollToCursor", actionArgs: { position: "center" }, motion: "moveToFirstNonWhiteSpaceCharacter" }, { keys: "zt", type: "action", action: "scrollToCursor", actionArgs: { position: "top" } }, { keys: "z", type: "action", action: "scrollToCursor", actionArgs: { position: "top" }, motion: "moveToFirstNonWhiteSpaceCharacter" }, { keys: "zb", type: "action", action: "scrollToCursor", actionArgs: { position: "bottom" } }, { keys: "z-", type: "action", action: "scrollToCursor", actionArgs: { position: "bottom" }, motion: "moveToFirstNonWhiteSpaceCharacter" }, { keys: ".", type: "action", action: "repeatLastEdit" }, { keys: "", type: "action", action: "incrementNumberToken", isEdit: true, actionArgs: { increase: true, backtrack: false } }, { keys: "", type: "action", action: "incrementNumberToken", isEdit: true, actionArgs: { increase: false, backtrack: false } }, { keys: "", type: "action", action: "indent", actionArgs: { indentRight: true }, context: "insert" }, { keys: "", type: "action", action: "indent", actionArgs: { indentRight: false }, context: "insert" }, // Text object motions { keys: "a", type: "motion", motion: "textObjectManipulation" }, { keys: "i", type: "motion", motion: "textObjectManipulation", motionArgs: { textObjectInner: true } }, // Search { keys: "/", type: "search", searchArgs: { forward: true, querySrc: "prompt", toJumplist: true } }, { keys: "?", type: "search", searchArgs: { forward: false, querySrc: "prompt", toJumplist: true } }, { keys: "*", type: "search", searchArgs: { forward: true, querySrc: "wordUnderCursor", wholeWordOnly: true, toJumplist: true } }, { keys: "#", type: "search", searchArgs: { forward: false, querySrc: "wordUnderCursor", wholeWordOnly: true, toJumplist: true } }, { keys: "g*", type: "search", searchArgs: { forward: true, querySrc: "wordUnderCursor", toJumplist: true } }, { keys: "g#", type: "search", searchArgs: { forward: false, querySrc: "wordUnderCursor", toJumplist: true } }, // Ex command { keys: ":", type: "ex" } ]; var defaultKeymapLength = defaultKeymap2.length; var defaultExCommandMap = [ { name: "colorscheme", shortName: "colo" }, { name: "map" }, { name: "imap", shortName: "im" }, { name: "nmap", shortName: "nm" }, { name: "vmap", shortName: "vm" }, { name: "omap", shortName: "om" }, { name: "noremap", shortName: "no" }, { name: "nnoremap", shortName: "nn" }, { name: "vnoremap", shortName: "vn" }, { name: "inoremap", shortName: "ino" }, { name: "onoremap", shortName: "ono" }, { name: "unmap" }, { name: "mapclear", shortName: "mapc" }, { name: "nmapclear", shortName: "nmapc" }, { name: "vmapclear", shortName: "vmapc" }, { name: "imapclear", shortName: "imapc" }, { name: "omapclear", shortName: "omapc" }, { name: "write", shortName: "w" }, { name: "undo", shortName: "u" }, { name: "redo", shortName: "red" }, { name: "set", shortName: "se" }, { name: "setlocal", shortName: "setl" }, { name: "setglobal", shortName: "setg" }, { name: "sort", shortName: "sor" }, { name: "substitute", shortName: "s", possiblyAsync: true }, { name: "startinsert", shortName: "start" }, { name: "nohlsearch", shortName: "noh" }, { name: "yank", shortName: "y" }, { name: "delmarks", shortName: "delm" }, { name: "registers", shortName: "reg", excludeFromCommandHistory: true }, { name: "vglobal", shortName: "v" }, { name: "delete", shortName: "d" }, { name: "join", shortName: "j" }, { name: "normal", shortName: "norm" }, { name: "global", shortName: "g" } ]; var langmap = parseLangmap(""); function enterVimMode(cm) { cm.setOption("disableInput", true); cm.setOption("showCursorWhenSelecting", false); CodeMirror2.signal(cm, "vim-mode-change", { mode: "normal" }); cm.on("cursorActivity", onCursorActivity); maybeInitVimState(cm); CodeMirror2.on(cm.getInputField(), "paste", getOnPasteFn(cm)); } function leaveVimMode(cm) { cm.setOption("disableInput", false); cm.off("cursorActivity", onCursorActivity); CodeMirror2.off(cm.getInputField(), "paste", getOnPasteFn(cm)); cm.state.vim = null; if (highlightTimeout) clearTimeout(highlightTimeout); } function getOnPasteFn(cm) { var vim2 = cm.state.vim; if (!vim2.onPasteFn) { vim2.onPasteFn = function() { if (!vim2.insertMode) { cm.setCursor(offsetCursor(cm.getCursor(), 0, 1)); actions.enterInsertMode(cm, {}, vim2); } }; } return vim2.onPasteFn; } var numberRegex = /[\d]/; var wordCharTest = [CodeMirror2.isWordChar, function(ch) { return ch && !CodeMirror2.isWordChar(ch) && !/\s/.test(ch); }], bigWordCharTest = [function(ch) { return /\S/.test(ch); }]; var validMarks = ["<", ">"]; var validRegisters = ["-", '"', ".", ":", "_", "/", "+"]; var latinCharRegex = /^\w$/; var upperCaseChars; try { upperCaseChars = new RegExp("^[\\p{Lu}]$", "u"); } catch (_) { upperCaseChars = /^[A-Z]$/; } function isLine(cm, line) { return line >= cm.firstLine() && line <= cm.lastLine(); } function isLowerCase(k) { return /^[a-z]$/.test(k); } function isMatchableSymbol(k) { return "()[]{}".indexOf(k) != -1; } function isNumber(k) { return numberRegex.test(k); } function isUpperCase(k) { return upperCaseChars.test(k); } function isWhiteSpaceString(k) { return /^\s*$/.test(k); } function isEndOfSentenceSymbol(k) { return ".?!".indexOf(k) != -1; } function inArray(val, arr) { for (var i = 0; i < arr.length; i++) { if (arr[i] == val) { return true; } } return false; } var options = {}; function defineOption(name, defaultValue, type, aliases, callback) { if (defaultValue === void 0 && !callback) { throw Error("defaultValue is required unless callback is provided"); } if (!type) { type = "string"; } options[name] = { type, defaultValue, callback }; if (aliases) { for (var i = 0; i < aliases.length; i++) { options[aliases[i]] = options[name]; } } if (defaultValue) { setOption(name, defaultValue); } } function setOption(name, value, cm, cfg) { var option = options[name]; cfg = cfg || {}; var scope = cfg.scope; if (!option) { return new Error("Unknown option: " + name); } if (option.type == "boolean") { if (value && value !== true) { return new Error("Invalid argument: " + name + "=" + value); } else if (value !== false) { value = true; } } if (option.callback) { if (scope !== "local") { option.callback(value, void 0); } if (scope !== "global" && cm) { option.callback(value, cm); } } else { if (scope !== "local") { option.value = option.type == "boolean" ? !!value : value; } if (scope !== "global" && cm) { cm.state.vim.options[name] = { value }; } } } function getOption(name, cm, cfg) { var option = options[name]; cfg = cfg || {}; var scope = cfg.scope; if (!option) { return new Error("Unknown option: " + name); } if (option.callback) { let local = cm && option.callback(void 0, cm); if (scope !== "global" && local !== void 0) { return local; } if (scope !== "local") { return option.callback(); } return; } else { let local = scope !== "global" && (cm && cm.state.vim.options[name]); return (local || scope !== "local" && option || {}).value; } } defineOption("filetype", void 0, "string", ["ft"], function(name, cm) { if (cm === void 0) { return; } if (name === void 0) { let mode = cm.getOption("mode"); return mode == "null" ? "" : mode; } else { let mode = name == "" ? "null" : name; cm.setOption("mode", mode); } }); defineOption("textwidth", 80, "number", ["tw"], function(width, cm) { if (cm === void 0) { return; } if (width === void 0) { var value = cm.getOption("textwidth"); return value; } else { var column = Math.round( /**@type {any}*/ width ); if (column > 1) { cm.setOption("textwidth", column); } } }); var createCircularJumpList = function() { var size = 100; var pointer = -1; var head = 0; var tail = 0; var buffer = new Array(size); function add(cm, oldCur, newCur) { var current = pointer % size; var curMark = buffer[current]; function useNextSlot(cursor) { var next = ++pointer % size; var trashMark = buffer[next]; if (trashMark) { trashMark.clear(); } buffer[next] = cm.setBookmark(cursor); } if (curMark) { var markPos = curMark.find(); if (markPos && !cursorEqual(markPos, oldCur)) { useNextSlot(oldCur); } } else { useNextSlot(oldCur); } useNextSlot(newCur); head = pointer; tail = pointer - size + 1; if (tail < 0) { tail = 0; } } function move(cm, offset) { pointer += offset; if (pointer > head) { pointer = head; } else if (pointer < tail) { pointer = tail; } var mark = buffer[(size + pointer) % size]; if (mark && !mark.find()) { var inc = offset > 0 ? 1 : -1; var newCur; var oldCur = cm.getCursor(); do { pointer += inc; mark = buffer[(size + pointer) % size]; if (mark && (newCur = mark.find()) && !cursorEqual(oldCur, newCur)) { break; } } while (pointer < head && pointer > tail); } return mark; } function find(cm, offset) { var oldPointer = pointer; var mark = move(cm, offset); pointer = oldPointer; return mark && mark.find(); } return { cachedCursor: void 0, //used for # and * jumps add, find, move }; }; var createInsertModeChanges = function(c) { if (c) { return { changes: c.changes, expectCursorActivityForChange: c.expectCursorActivityForChange }; } return { // Change list changes: [], // Set to true on change, false on cursorActivity. expectCursorActivityForChange: false }; }; class MacroModeState { constructor() { this.latestRegister = void 0; this.isPlaying = false; this.isRecording = false; this.replaySearchQueries = []; this.onRecordingDone = void 0; this.lastInsertModeChanges = createInsertModeChanges(); } exitMacroRecordMode() { var macroModeState = vimGlobalState.macroModeState; if (macroModeState.onRecordingDone) { macroModeState.onRecordingDone(); } macroModeState.onRecordingDone = void 0; macroModeState.isRecording = false; } enterMacroRecordMode(cm, registerName) { var register = vimGlobalState.registerController.getRegister(registerName); if (register) { register.clear(); this.latestRegister = registerName; if (cm.openDialog) { var template = dom("span", { class: "cm-vim-message" }, "recording @" + registerName); this.onRecordingDone = cm.openDialog(template, null, { bottom: true }); } this.isRecording = true; } } } function maybeInitVimState(cm) { if (!cm.state.vim) { cm.state.vim = { inputState: new InputState(), // Vim's input state that triggered the last edit, used to repeat // motions and operators with '.'. lastEditInputState: void 0, // Vim's action command before the last edit, used to repeat actions // with '.' and insert mode repeat. lastEditActionCommand: void 0, // When using jk for navigation, if you move from a longer line to a // shorter line, the cursor may clip to the end of the shorter line. // If j is pressed again and cursor goes to the next line, the // cursor should go back to its horizontal position on the longer // line if it can. This is to keep track of the horizontal position. lastHPos: -1, // Doing the same with screen-position for gj/gk lastHSPos: -1, // The last motion command run. Cleared if a non-motion command gets // executed in between. lastMotion: null, marks: {}, insertMode: false, insertModeReturn: false, // Repeat count for changes made in insert mode, triggered by key // sequences like 3,i. Only exists when insertMode is true. insertModeRepeat: void 0, visualMode: false, // If we are in visual line mode. No effect if visualMode is false. visualLine: false, visualBlock: false, lastSelection: null, lastPastedText: null, sel: {}, // Buffer-local/window-local values of vim options. options: {}, // Whether the next character should be interpreted literally // Necassary for correct implementation of f, r etc. // in terms of langmaps. expectLiteralNext: false }; } return cm.state.vim; } var vimGlobalState; function resetVimGlobalState() { vimGlobalState = { // The current search query. searchQuery: null, // Whether we are searching backwards. searchIsReversed: false, // Replace part of the last substituted pattern lastSubstituteReplacePart: void 0, jumpList: createCircularJumpList(), macroModeState: new MacroModeState(), // Recording latest f, t, F or T motion command. lastCharacterSearch: { increment: 0, forward: true, selectedCharacter: "" }, registerController: new RegisterController({}), // search history buffer searchHistoryController: new HistoryController(), // ex Command history buffer exCommandHistoryController: new HistoryController() }; for (var optionName in options) { var option = options[optionName]; option.value = option.defaultValue; } } var lastInsertModeKeyTimer; var vimApi = { enterVimMode, leaveVimMode, buildKeyMap: function() { }, // Testing hook, though it might be useful to expose the register // controller anyway. getRegisterController: function() { return vimGlobalState.registerController; }, // Testing hook. resetVimGlobalState_: resetVimGlobalState, // Testing hook. getVimGlobalState_: function() { return vimGlobalState; }, // Testing hook. maybeInitVimState_: maybeInitVimState, suppressErrorLogging: false, InsertModeKey, /**@type {(lhs: string, rhs: string, ctx: string) => void} */ map: function(lhs, rhs, ctx) { exCommandDispatcher.map(lhs, rhs, ctx); }, /**@type {(lhs: string, ctx: string) => any} */ unmap: function(lhs, ctx) { return exCommandDispatcher.unmap(lhs, ctx); }, // Non-recursive map function. // NOTE: This will not create mappings to key maps that aren't present // in the default key map. See TODO at bottom of function. /**@type {(lhs: string, rhs: string, ctx: string) => void} */ noremap: function(lhs, rhs, ctx) { exCommandDispatcher.map(lhs, rhs, ctx, true); }, // Remove all user-defined mappings for the provided context. /**@arg {string} [ctx]} */ mapclear: function(ctx) { var actualLength = defaultKeymap2.length, origLength = defaultKeymapLength; var userKeymap = defaultKeymap2.slice(0, actualLength - origLength); defaultKeymap2 = defaultKeymap2.slice(actualLength - origLength); if (ctx) { for (var i = userKeymap.length - 1; i >= 0; i--) { var mapping = userKeymap[i]; if (ctx !== mapping.context) { if (mapping.context) { this._mapCommand(mapping); } else { var contexts = ["normal", "insert", "visual"]; for (var j in contexts) { if (contexts[j] !== ctx) { var newMapping = Object.assign({}, mapping); newMapping.context = contexts[j]; this._mapCommand(newMapping); } } } } } } }, langmap: updateLangmap, vimKeyFromEvent, // TODO: Expose setOption and getOption as instance methods. Need to decide how to namespace // them, or somehow make them work with the existing CodeMirror setOption/getOption API. setOption, getOption, defineOption, /**@type {(name: string, prefix: string|undefined, func: ExFn) => void} */ defineEx: function(name, prefix, func) { if (!prefix) { prefix = name; } else if (name.indexOf(prefix) !== 0) { throw new Error('(Vim.defineEx) "' + prefix + '" is not a prefix of "' + name + '", command not registered'); } exCommands[name] = func; exCommandDispatcher.commandMap_[prefix] = { name, shortName: prefix, type: "api" }; }, /**@type {(cm: CodeMirror, key: string, origin: string) => undefined | boolean} */ handleKey: function(cm, key, origin) { var command = this.findKey(cm, key, origin); if (typeof command === "function") { return command(); } }, multiSelectHandleKey, /** * This is the outermost function called by CodeMirror, after keys have * been mapped to their Vim equivalents. * * Finds a command based on the key (and cached keys if there is a * multi-key sequence). Returns `undefined` if no key is matched, a noop * function if a partial match is found (multi-key), and a function to * execute the bound command if a a key is matched. The function always * returns true. */ /**@type {(cm_: CodeMirror, key: string, origin?: string| undefined) => (() => boolean) | undefined} */ findKey: function(cm_, key, origin) { var vim2 = maybeInitVimState(cm_); var cm = ( /**@type {CodeMirrorV}*/ cm_ ); function handleMacroRecording() { var macroModeState = vimGlobalState.macroModeState; if (macroModeState.isRecording) { if (key == "q") { macroModeState.exitMacroRecordMode(); clearInputState(cm); return true; } if (origin != "mapping") { logKey(macroModeState, key); } } } function handleEsc() { if (key == "") { if (vim2.visualMode) { exitVisualMode(cm); } else if (vim2.insertMode) { exitInsertMode(cm); } else { return; } clearInputState(cm); return true; } } function handleKeyInsertMode() { if (handleEsc()) { return true; } vim2.inputState.keyBuffer.push(key); var keys2 = vim2.inputState.keyBuffer.join(""); var keysAreChars = key.length == 1; var match = commandDispatcher.matchCommand(keys2, defaultKeymap2, vim2.inputState, "insert"); var changeQueue = vim2.inputState.changeQueue; if (match.type == "none") { clearInputState(cm); return false; } else if (match.type == "partial") { if (match.expectLiteralNext) vim2.expectLiteralNext = true; if (lastInsertModeKeyTimer) { window.clearTimeout(lastInsertModeKeyTimer); } lastInsertModeKeyTimer = keysAreChars && window.setTimeout( function() { if (vim2.insertMode && vim2.inputState.keyBuffer.length) { clearInputState(cm); } }, getOption("insertModeEscKeysTimeout") ); if (keysAreChars) { var selections = cm.listSelections(); if (!changeQueue || changeQueue.removed.length != selections.length) changeQueue = vim2.inputState.changeQueue = new ChangeQueue(); changeQueue.inserted += key; for (var i = 0; i < selections.length; i++) { var from = cursorMin(selections[i].anchor, selections[i].head); var to = cursorMax(selections[i].anchor, selections[i].head); var text = cm.getRange(from, cm.state.overwrite ? offsetCursor(to, 0, 1) : to); changeQueue.removed[i] = (changeQueue.removed[i] || "") + text; } } return !keysAreChars; } vim2.expectLiteralNext = false; if (lastInsertModeKeyTimer) { window.clearTimeout(lastInsertModeKeyTimer); } if (match.command && changeQueue) { var selections = cm.listSelections(); for (var i = 0; i < selections.length; i++) { var here = selections[i].head; cm.replaceRange( changeQueue.removed[i] || "", offsetCursor(here, 0, -changeQueue.inserted.length), here, "+input" ); } vimGlobalState.macroModeState.lastInsertModeChanges.changes.pop(); } if (!match.command) clearInputState(cm); return match.command; } function handleKeyNonInsertMode() { if (handleMacroRecording() || handleEsc()) { return true; } vim2.inputState.keyBuffer.push(key); var keys2 = vim2.inputState.keyBuffer.join(""); if (/^[1-9]\d*$/.test(keys2)) { return true; } var keysMatcher = /^(\d*)(.*)$/.exec(keys2); if (!keysMatcher) { clearInputState(cm); return false; } var context = vim2.visualMode ? "visual" : "normal"; var mainKey = keysMatcher[2] || keysMatcher[1]; if (vim2.inputState.operatorShortcut && vim2.inputState.operatorShortcut.slice(-1) == mainKey) { mainKey = vim2.inputState.operatorShortcut; } var match = commandDispatcher.matchCommand(mainKey, defaultKeymap2, vim2.inputState, context); if (match.type == "none") { clearInputState(cm); return false; } else if (match.type == "partial") { if (match.expectLiteralNext) vim2.expectLiteralNext = true; return true; } else if (match.type == "clear") { clearInputState(cm); return true; } vim2.expectLiteralNext = false; vim2.inputState.keyBuffer.length = 0; keysMatcher = /^(\d*)(.*)$/.exec(keys2); if (keysMatcher && keysMatcher[1] && keysMatcher[1] != "0") { vim2.inputState.pushRepeatDigit(keysMatcher[1]); } return match.command; } var command; if (vim2.insertMode) { command = handleKeyInsertMode(); } else { command = handleKeyNonInsertMode(); } if (command === false) { return !vim2.insertMode && key.length === 1 ? function() { return true; } : void 0; } else if (command === true) { return function() { return true; }; } else { return function() { return cm.operation(function() { cm.curOp.isVimOp = true; try { if (command.type == "keyToKey") { doKeyToKey(cm, command.toKeys, command); } else { commandDispatcher.processCommand(cm, vim2, command); } } catch (e) { cm.state.vim = void 0; maybeInitVimState(cm); if (!vimApi.suppressErrorLogging) { console["log"](e); } throw e; } return true; }); }; } }, handleEx: function(cm, input) { exCommandDispatcher.processCommand(cm, input); }, defineMotion, defineAction, defineOperator, mapCommand, _mapCommand, defineRegister, exitVisualMode, exitInsertMode }; var keyToKeyStack = []; var noremap = false; var virtualPrompt; function sendKeyToPrompt(key) { if (key[0] == "<") { var lowerKey = key.toLowerCase().slice(1, -1); var parts = lowerKey.split("-"); lowerKey = parts.pop() || ""; if (lowerKey == "lt") key = "<"; else if (lowerKey == "space") key = " "; else if (lowerKey == "cr") key = "\n"; else if (vimToCmKeyMap[lowerKey]) { var value = virtualPrompt.value; var event = { key: vimToCmKeyMap[lowerKey], target: { value, selectionEnd: value.length, selectionStart: value.length } }; if (virtualPrompt.onKeyDown) { virtualPrompt.onKeyDown(event, virtualPrompt.value, close); } if (virtualPrompt && virtualPrompt.onKeyUp) { virtualPrompt.onKeyUp(event, virtualPrompt.value, close); } return; } } if (key == "\n") { var prompt2 = virtualPrompt; virtualPrompt = null; prompt2.onClose && prompt2.onClose(prompt2.value); } else { virtualPrompt.value = (virtualPrompt.value || "") + key; } function close(value2) { if (typeof value2 == "string") { virtualPrompt.value = value2; } else { virtualPrompt = null; } } } function doKeyToKey(cm, keys2, fromKey) { var noremapBefore = noremap; if (fromKey) { if (keyToKeyStack.indexOf(fromKey) != -1) return; keyToKeyStack.push(fromKey); noremap = fromKey.noremap != false; } try { var vim2 = maybeInitVimState(cm); var keyRe = /<(?:[CSMA]-)*\w+>|./gi; var match; while (match = keyRe.exec(keys2)) { var key = match[0]; var wasInsert = vim2.insertMode; if (virtualPrompt) { sendKeyToPrompt(key); continue; } var result = vimApi.handleKey(cm, key, "mapping"); if (!result && wasInsert && vim2.insertMode) { if (key[0] == "<") { var lowerKey = key.toLowerCase().slice(1, -1); var parts = lowerKey.split("-"); lowerKey = parts.pop() || ""; if (lowerKey == "lt") key = "<"; else if (lowerKey == "space") key = " "; else if (lowerKey == "cr") key = "\n"; else if (vimToCmKeyMap.hasOwnProperty(lowerKey)) { key = vimToCmKeyMap[lowerKey]; sendCmKey(cm, key); continue; } else { key = key[0]; keyRe.lastIndex = match.index + 1; } } cm.replaceSelection(key); } } } finally { keyToKeyStack.pop(); noremap = keyToKeyStack.length ? noremapBefore : false; if (!keyToKeyStack.length && virtualPrompt) { var promptOptions = virtualPrompt; virtualPrompt = null; showPrompt(cm, promptOptions); } } } var specialKey = { Return: "CR", Backspace: "BS", "Delete": "Del", Escape: "Esc", Insert: "Ins", ArrowLeft: "Left", ArrowRight: "Right", ArrowUp: "Up", ArrowDown: "Down", Enter: "CR", " ": "Space" }; var ignoredKeys = { Shift: 1, Alt: 1, Command: 1, Control: 1, CapsLock: 1, AltGraph: 1, Dead: 1, Unidentified: 1 }; var vimToCmKeyMap = {}; "Left|Right|Up|Down|End|Home".split("|").concat(Object.keys(specialKey)).forEach(function(x) { vimToCmKeyMap[(specialKey[x] || "").toLowerCase()] = vimToCmKeyMap[x.toLowerCase()] = x; }); function vimKeyFromEvent(e, vim2) { var _a; var key = e.key; if (ignoredKeys[key]) return; if (key.length > 1 && key[0] == "n") { key = key.replace("Numpad", ""); } key = specialKey[key] || key; var name = ""; if (e.ctrlKey) { name += "C-"; } if (e.altKey) { name += "A-"; } if (e.metaKey) { name += "M-"; } if (CodeMirror2.isMac && e.altKey && !e.metaKey && !e.ctrlKey) { name = name.slice(2); } if ((name || key.length > 1) && e.shiftKey) { name += "S-"; } if (vim2 && !vim2.expectLiteralNext && key.length == 1) { if (langmap.keymap && key in langmap.keymap) { if (langmap.remapCtrl != false || !name) key = langmap.keymap[key]; } else if (key.charCodeAt(0) > 255) { var code = ((_a = e.code) == null ? void 0 : _a.slice(-1)) || ""; if (!e.shiftKey) code = code.toLowerCase(); if (code) key = code; } } name += key; if (name.length > 1) { name = "<" + name + ">"; } return name; } function updateLangmap(langmapString, remapCtrl) { if (langmap.string !== langmapString) { langmap = parseLangmap(langmapString); } langmap.remapCtrl = remapCtrl; } function parseLangmap(langmapString) { let keymap2 = {}; if (!langmapString) return { keymap: keymap2, string: "" }; function getEscaped(list) { return list.split(/\\?(.)/).filter(Boolean); } langmapString.split(/((?:[^\\,]|\\.)+),/).map((part) => { if (!part) return; const semicolon = part.split(/((?:[^\\;]|\\.)+);/); if (semicolon.length == 3) { const from = getEscaped(semicolon[1]); const to = getEscaped(semicolon[2]); if (from.length !== to.length) return; for (let i = 0; i < from.length; ++i) keymap2[from[i]] = to[i]; } else if (semicolon.length == 1) { const pairs = getEscaped(part); if (pairs.length % 2 !== 0) return; for (let i = 0; i < pairs.length; i += 2) keymap2[pairs[i]] = pairs[i + 1]; } }); return { keymap: keymap2, string: langmapString }; } defineOption("langmap", void 0, "string", ["lmap"], function(name, cm) { if (name === void 0) { return langmap.string; } else { updateLangmap(name); } }); class InputState { constructor() { this.prefixRepeat = []; this.motionRepeat = []; this.operator = null; this.operatorArgs = null; this.motion = null; this.motionArgs = null; this.keyBuffer = []; this.registerName = null; this.changeQueue = null; } pushRepeatDigit(n) { if (!this.operator) { this.prefixRepeat = this.prefixRepeat.concat(n); } else { this.motionRepeat = this.motionRepeat.concat(n); } } getRepeat() { var repeat = 0; if (this.prefixRepeat.length > 0 || this.motionRepeat.length > 0) { repeat = 1; if (this.prefixRepeat.length > 0) { repeat *= parseInt(this.prefixRepeat.join(""), 10); } if (this.motionRepeat.length > 0) { repeat *= parseInt(this.motionRepeat.join(""), 10); } } return repeat; } } function clearInputState(cm, reason) { cm.state.vim.inputState = new InputState(); cm.state.vim.expectLiteralNext = false; CodeMirror2.signal(cm, "vim-command-done", reason); } function ChangeQueue() { this.removed = []; this.inserted = ""; } class Register { constructor(text, linewise, blockwise) { this.clear(); this.keyBuffer = [text || ""]; this.insertModeChanges = []; this.searchQueries = []; this.linewise = !!linewise; this.blockwise = !!blockwise; } setText(text, linewise, blockwise) { this.keyBuffer = [text || ""]; this.linewise = !!linewise; this.blockwise = !!blockwise; } pushText(text, linewise) { if (linewise) { if (!this.linewise) { this.keyBuffer.push("\n"); } this.linewise = true; } this.keyBuffer.push(text); } pushInsertModeChanges(changes) { this.insertModeChanges.push(createInsertModeChanges(changes)); } pushSearchQuery(query) { this.searchQueries.push(query); } clear() { this.keyBuffer = []; this.insertModeChanges = []; this.searchQueries = []; this.linewise = false; } toString() { return this.keyBuffer.join(""); } } function defineRegister(name, register) { var registers = vimGlobalState.registerController.registers; if (!name || name.length != 1) { throw Error("Register name must be 1 character"); } if (registers[name]) { throw Error("Register already defined " + name); } registers[name] = register; validRegisters.push(name); } class RegisterController { /** @arg {Object} registers */ constructor(registers) { this.registers = registers; this.unnamedRegister = registers['"'] = new Register(); registers["."] = new Register(); registers[":"] = new Register(); registers["/"] = new Register(); registers["+"] = new Register(); } pushText(registerName, operator, text, linewise, blockwise) { if (registerName === "_") return; if (linewise && text.charAt(text.length - 1) !== "\n") { text += "\n"; } var register = this.isValidRegister(registerName) ? this.getRegister(registerName) : null; if (!register) { switch (operator) { case "yank": this.registers["0"] = new Register(text, linewise, blockwise); break; case "delete": case "change": if (text.indexOf("\n") == -1) { this.registers["-"] = new Register(text, linewise); } else { this.shiftNumericRegisters_(); this.registers["1"] = new Register(text, linewise); } break; } this.unnamedRegister.setText(text, linewise, blockwise); return; } var append = isUpperCase(registerName); if (append) { register.pushText(text, linewise); } else { register.setText(text, linewise, blockwise); } if (registerName === "+") { navigator.clipboard.writeText(text); } this.unnamedRegister.setText(register.toString(), linewise); } /** * Gets the register named @name. If one of @name doesn't already exist, * create it. If @name is invalid, return the unnamedRegister. * @arg {string} [name] */ getRegister(name) { if (!this.isValidRegister(name)) { return this.unnamedRegister; } name = name.toLowerCase(); if (!this.registers[name]) { this.registers[name] = new Register(); } return this.registers[name]; } /**@type {{(name: any): name is string}} */ isValidRegister(name) { return name && (inArray(name, validRegisters) || latinCharRegex.test(name)); } shiftNumericRegisters_() { for (var i = 9; i >= 2; i--) { this.registers[i] = this.getRegister("" + (i - 1)); } } } class HistoryController { constructor() { this.historyBuffer = []; this.iterator = 0; this.initialPrefix = null; } // the input argument here acts a user entered prefix for a small time // until we start autocompletion in which case it is the autocompleted. nextMatch(input, up) { var historyBuffer = this.historyBuffer; var dir = up ? -1 : 1; if (this.initialPrefix === null) this.initialPrefix = input; for (var i = this.iterator + dir; up ? i >= 0 : i < historyBuffer.length; i += dir) { var element = historyBuffer[i]; for (var j = 0; j <= element.length; j++) { if (this.initialPrefix == element.substring(0, j)) { this.iterator = i; return element; } } } if (i >= historyBuffer.length) { this.iterator = historyBuffer.length; return this.initialPrefix; } if (i < 0) return input; } pushInput(input) { var index = this.historyBuffer.indexOf(input); if (index > -1) this.historyBuffer.splice(index, 1); if (input.length) this.historyBuffer.push(input); } reset() { this.initialPrefix = null; this.iterator = this.historyBuffer.length; } } var commandDispatcher = { matchCommand: function(keys2, keyMap, inputState, context) { var matches = commandMatches(keys2, keyMap, context, inputState); if (!matches.full && !matches.partial) { return { type: "none" }; } else if (!matches.full && matches.partial) { return { type: "partial", expectLiteralNext: matches.partial.length == 1 && matches.partial[0].keys.slice(-11) == "" // langmap literal logic }; } var bestMatch; for (var i = 0; i < matches.full.length; i++) { var match = matches.full[i]; if (!bestMatch) { bestMatch = match; } } if (bestMatch.keys.slice(-11) == "" || bestMatch.keys.slice(-10) == "") { var character = lastChar(keys2); if (!character || character.length > 1) return { type: "clear" }; inputState.selectedCharacter = character; } return { type: "full", command: bestMatch }; }, /** * @arg {CodeMirrorV} cm * @arg {vimState} vim * @arg {vimKey} command */ processCommand: function(cm, vim2, command) { vim2.inputState.repeatOverride = command.repeatOverride; switch (command.type) { case "motion": this.processMotion(cm, vim2, command); break; case "operator": this.processOperator(cm, vim2, command); break; case "operatorMotion": this.processOperatorMotion(cm, vim2, command); break; case "action": this.processAction(cm, vim2, command); break; case "search": this.processSearch(cm, vim2, command); break; case "ex": case "keyToEx": this.processEx(cm, vim2, command); break; } }, /** * @arg {CodeMirrorV} cm * @arg {vimState} vim * @arg {import("./types").motionCommand|import("./types").operatorMotionCommand} command */ processMotion: function(cm, vim2, command) { vim2.inputState.motion = command.motion; vim2.inputState.motionArgs = /**@type {MotionArgs}*/ copyArgs(command.motionArgs); this.evalInput(cm, vim2); }, /** * @arg {CodeMirrorV} cm * @arg {vimState} vim * @arg {import("./types").operatorCommand|import("./types").operatorMotionCommand} command */ processOperator: function(cm, vim2, command) { var inputState = vim2.inputState; if (inputState.operator) { if (inputState.operator == command.operator) { inputState.motion = "expandToLine"; inputState.motionArgs = { linewise: true, repeat: 1 }; this.evalInput(cm, vim2); return; } else { clearInputState(cm); } } inputState.operator = command.operator; inputState.operatorArgs = copyArgs(command.operatorArgs); if (command.keys.length > 1) { inputState.operatorShortcut = command.keys; } if (command.exitVisualBlock) { vim2.visualBlock = false; updateCmSelection(cm); } if (vim2.visualMode) { this.evalInput(cm, vim2); } }, /** * @arg {CodeMirrorV} cm * @arg {vimState} vim * @arg {import("./types").operatorMotionCommand} command */ processOperatorMotion: function(cm, vim2, command) { var visualMode = vim2.visualMode; var operatorMotionArgs = copyArgs(command.operatorMotionArgs); if (operatorMotionArgs) { if (visualMode && operatorMotionArgs.visualLine) { vim2.visualLine = true; } } this.processOperator(cm, vim2, command); if (!visualMode) { this.processMotion(cm, vim2, command); } }, /** * @arg {CodeMirrorV} cm * @arg {vimState} vim * @arg {import("./types").actionCommand} command */ processAction: function(cm, vim2, command) { var inputState = vim2.inputState; var repeat = inputState.getRepeat(); var repeatIsExplicit = !!repeat; var actionArgs = ( /**@type {ActionArgs}*/ copyArgs(command.actionArgs) || { repeat: 1 } ); if (inputState.selectedCharacter) { actionArgs.selectedCharacter = inputState.selectedCharacter; } if (command.operator) { this.processOperator(cm, vim2, command); } if (command.motion) { this.processMotion(cm, vim2, command); } if (command.motion || command.operator) { this.evalInput(cm, vim2); } actionArgs.repeat = repeat || 1; actionArgs.repeatIsExplicit = repeatIsExplicit; actionArgs.registerName = inputState.registerName; clearInputState(cm); vim2.lastMotion = null; if (command.isEdit) { this.recordLastEdit(vim2, inputState, command); } actions[command.action](cm, actionArgs, vim2); }, /** @arg {CodeMirrorV} cm @arg {vimState} vim @arg {import("./types").searchCommand} command*/ processSearch: function(cm, vim2, command) { if (!cm.getSearchCursor) { return; } var forward = command.searchArgs.forward; var wholeWordOnly = command.searchArgs.wholeWordOnly; getSearchState(cm).setReversed(!forward); var promptPrefix = forward ? "/" : "?"; var originalQuery = getSearchState(cm).getQuery(); var originalScrollPos = cm.getScrollInfo(); function handleQuery(query, ignoreCase, smartCase) { vimGlobalState.searchHistoryController.pushInput(query); vimGlobalState.searchHistoryController.reset(); try { updateSearchQuery(cm, query, ignoreCase, smartCase); } catch (e) { showConfirm(cm, "Invalid regex: " + query); clearInputState(cm); return; } commandDispatcher.processMotion(cm, vim2, { keys: "", type: "motion", motion: "findNext", motionArgs: { forward: true, toJumplist: command.searchArgs.toJumplist } }); } function onPromptClose(query) { cm.scrollTo(originalScrollPos.left, originalScrollPos.top); handleQuery( query, true, true /** smartCase */ ); var macroModeState2 = vimGlobalState.macroModeState; if (macroModeState2.isRecording) { logSearchQuery(macroModeState2, query); } } function onPromptKeyUp(e, query, close) { var keyName = vimKeyFromEvent(e), up, offset; if (keyName == "" || keyName == "") { up = keyName == "" ? true : false; offset = e.target ? e.target.selectionEnd : 0; query = vimGlobalState.searchHistoryController.nextMatch(query, up) || ""; close(query); if (offset && e.target) e.target.selectionEnd = e.target.selectionStart = Math.min(offset, e.target.value.length); } else if (keyName && keyName != "" && keyName != "") { vimGlobalState.searchHistoryController.reset(); } var parsedQuery; try { parsedQuery = updateSearchQuery( cm, query, true, true /** smartCase */ ); } catch (e2) { } if (parsedQuery) { cm.scrollIntoView(findNext(cm, !forward, parsedQuery), 30); } else { clearSearchHighlight(cm); cm.scrollTo(originalScrollPos.left, originalScrollPos.top); } } function onPromptKeyDown(e, query, close) { var keyName = vimKeyFromEvent(e); if (keyName == "" || keyName == "" || keyName == "" || keyName == "" && query == "") { vimGlobalState.searchHistoryController.pushInput(query); vimGlobalState.searchHistoryController.reset(); updateSearchQuery(cm, originalQuery); clearSearchHighlight(cm); cm.scrollTo(originalScrollPos.left, originalScrollPos.top); CodeMirror2.e_stop(e); clearInputState(cm); close(); cm.focus(); } else if (keyName == "" || keyName == "") { CodeMirror2.e_stop(e); } else if (keyName == "") { CodeMirror2.e_stop(e); close(""); } } switch (command.searchArgs.querySrc) { case "prompt": var macroModeState = vimGlobalState.macroModeState; if (macroModeState.isPlaying) { let query2 = macroModeState.replaySearchQueries.shift(); handleQuery( query2, true, false /** smartCase */ ); } else { showPrompt(cm, { onClose: onPromptClose, prefix: promptPrefix, desc: "(JavaScript regexp)", onKeyUp: onPromptKeyUp, onKeyDown: onPromptKeyDown }); } break; case "wordUnderCursor": var word2 = expandWordUnderCursor(cm, { noSymbol: true }); var isKeyword = true; if (!word2) { word2 = expandWordUnderCursor(cm, { noSymbol: false }); isKeyword = false; } if (!word2) { showConfirm(cm, "No word under cursor"); clearInputState(cm); return; } let query = cm.getLine(word2.start.line).substring( word2.start.ch, word2.end.ch ); if (isKeyword && wholeWordOnly) { query = "\\b" + query + "\\b"; } else { query = escapeRegex(query); } vimGlobalState.jumpList.cachedCursor = cm.getCursor(); cm.setCursor(word2.start); handleQuery( query, true, false /** smartCase */ ); break; } }, /** * @arg {CodeMirrorV} cm * @arg {vimState} vim * @arg {import("./types").exCommand | import("./types").keyToExCommand} command */ processEx: function(cm, vim2, command) { function onPromptClose(input) { vimGlobalState.exCommandHistoryController.pushInput(input); vimGlobalState.exCommandHistoryController.reset(); exCommandDispatcher.processCommand(cm, input); if (cm.state.vim) clearInputState(cm); } function onPromptKeyDown(e, input, close) { var keyName = vimKeyFromEvent(e), up, offset; if (keyName == "" || keyName == "" || keyName == "" || keyName == "" && input == "") { vimGlobalState.exCommandHistoryController.pushInput(input); vimGlobalState.exCommandHistoryController.reset(); CodeMirror2.e_stop(e); clearInputState(cm); close(); cm.focus(); } if (keyName == "" || keyName == "") { CodeMirror2.e_stop(e); up = keyName == "" ? true : false; offset = e.target ? e.target.selectionEnd : 0; input = vimGlobalState.exCommandHistoryController.nextMatch(input, up) || ""; close(input); if (offset && e.target) e.target.selectionEnd = e.target.selectionStart = Math.min(offset, e.target.value.length); } else if (keyName == "") { CodeMirror2.e_stop(e); close(""); } else if (keyName && keyName != "" && keyName != "") { vimGlobalState.exCommandHistoryController.reset(); } } if (command.type == "keyToEx") { exCommandDispatcher.processCommand(cm, command.exArgs.input); } else { if (vim2.visualMode) { showPrompt(cm, { onClose: onPromptClose, prefix: ":", value: "'<,'>", onKeyDown: onPromptKeyDown, selectValueOnOpen: false }); } else { showPrompt(cm, { onClose: onPromptClose, prefix: ":", onKeyDown: onPromptKeyDown }); } } }, /**@arg {CodeMirrorV} cm @arg {vimState} vim */ evalInput: function(cm, vim2) { var inputState = vim2.inputState; var motion = inputState.motion; var motionArgs = inputState.motionArgs || { repeat: 1 }; var operator = inputState.operator; var operatorArgs = inputState.operatorArgs || {}; var registerName = inputState.registerName; var sel = vim2.sel; var origHead = copyCursor(vim2.visualMode ? clipCursorToContent(cm, sel.head) : cm.getCursor("head")); var origAnchor = copyCursor(vim2.visualMode ? clipCursorToContent(cm, sel.anchor) : cm.getCursor("anchor")); var oldHead = copyCursor(origHead); var oldAnchor = copyCursor(origAnchor); var newHead, newAnchor; var repeat; if (operator) { this.recordLastEdit(vim2, inputState); } if (inputState.repeatOverride !== void 0) { repeat = inputState.repeatOverride; } else { repeat = inputState.getRepeat(); } if (repeat > 0 && motionArgs.explicitRepeat) { motionArgs.repeatIsExplicit = true; } else if (motionArgs.noRepeat || !motionArgs.explicitRepeat && repeat === 0) { repeat = 1; motionArgs.repeatIsExplicit = false; } if (inputState.selectedCharacter) { motionArgs.selectedCharacter = operatorArgs.selectedCharacter = inputState.selectedCharacter; } motionArgs.repeat = repeat; clearInputState(cm); if (motion) { var motionResult = motions[motion](cm, origHead, motionArgs, vim2, inputState); vim2.lastMotion = motions[motion]; if (!motionResult) { return; } if (motionArgs.toJumplist) { var jumpList = vimGlobalState.jumpList; var cachedCursor = jumpList.cachedCursor; if (cachedCursor) { recordJumpPosition(cm, cachedCursor, motionResult); delete jumpList.cachedCursor; } else { recordJumpPosition(cm, origHead, motionResult); } } if (motionResult instanceof Array) { newAnchor = motionResult[0]; newHead = motionResult[1]; } else { newHead = motionResult; } if (!newHead) { newHead = copyCursor(origHead); } if (vim2.visualMode) { if (!(vim2.visualBlock && newHead.ch === Infinity)) { newHead = clipCursorToContent(cm, newHead, oldHead); } if (newAnchor) { newAnchor = clipCursorToContent(cm, newAnchor); } newAnchor = newAnchor || oldAnchor; sel.anchor = newAnchor; sel.head = newHead; updateCmSelection(cm); updateMark( cm, vim2, "<", cursorIsBefore(newAnchor, newHead) ? newAnchor : newHead ); updateMark( cm, vim2, ">", cursorIsBefore(newAnchor, newHead) ? newHead : newAnchor ); } else if (!operator) { newHead = clipCursorToContent(cm, newHead, oldHead); cm.setCursor(newHead.line, newHead.ch); } } if (operator) { if (operatorArgs.lastSel) { newAnchor = oldAnchor; var lastSel = operatorArgs.lastSel; var lineOffset = Math.abs(lastSel.head.line - lastSel.anchor.line); var chOffset = Math.abs(lastSel.head.ch - lastSel.anchor.ch); if (lastSel.visualLine) { newHead = new Pos3(oldAnchor.line + lineOffset, oldAnchor.ch); } else if (lastSel.visualBlock) { newHead = new Pos3(oldAnchor.line + lineOffset, oldAnchor.ch + chOffset); } else if (lastSel.head.line == lastSel.anchor.line) { newHead = new Pos3(oldAnchor.line, oldAnchor.ch + chOffset); } else { newHead = new Pos3(oldAnchor.line + lineOffset, oldAnchor.ch); } vim2.visualMode = true; vim2.visualLine = lastSel.visualLine; vim2.visualBlock = lastSel.visualBlock; sel = vim2.sel = { anchor: newAnchor, head: newHead }; updateCmSelection(cm); } else if (vim2.visualMode) { operatorArgs.lastSel = { anchor: copyCursor(sel.anchor), head: copyCursor(sel.head), visualBlock: vim2.visualBlock, visualLine: vim2.visualLine }; } var curStart, curEnd, linewise; var mode; var cmSel; if (vim2.visualMode) { curStart = cursorMin(sel.head, sel.anchor); curEnd = cursorMax(sel.head, sel.anchor); linewise = vim2.visualLine || operatorArgs.linewise; mode = vim2.visualBlock ? "block" : linewise ? "line" : "char"; var newPositions = updateSelectionForSurrogateCharacters(cm, curStart, curEnd); cmSel = makeCmSelection(cm, { anchor: newPositions.start, head: newPositions.end }, mode); if (linewise) { var ranges = cmSel.ranges; if (mode == "block") { for (var i = 0; i < ranges.length; i++) { ranges[i].head.ch = lineLength(cm, ranges[i].head.line); } } else if (mode == "line") { ranges[0].head = new Pos3(ranges[0].head.line + 1, 0); } } } else { curStart = copyCursor(newAnchor || oldAnchor); curEnd = copyCursor(newHead || oldHead); if (cursorIsBefore(curEnd, curStart)) { var tmp = curStart; curStart = curEnd; curEnd = tmp; } linewise = motionArgs.linewise || operatorArgs.linewise; if (linewise) { expandSelectionToLine(cm, curStart, curEnd); } else if (motionArgs.forward) { clipToLine(cm, curStart, curEnd); } mode = "char"; var exclusive = !motionArgs.inclusive || linewise; var newPositions = updateSelectionForSurrogateCharacters(cm, curStart, curEnd); cmSel = makeCmSelection(cm, { anchor: newPositions.start, head: newPositions.end }, mode, exclusive); } cm.setSelections(cmSel.ranges, cmSel.primary); vim2.lastMotion = null; operatorArgs.repeat = repeat; operatorArgs.registerName = registerName; operatorArgs.linewise = linewise; var operatorMoveTo = operators[operator]( cm, operatorArgs, cmSel.ranges, oldAnchor, newHead ); if (vim2.visualMode) { exitVisualMode(cm, operatorMoveTo != null); } if (operatorMoveTo) { cm.setCursor(operatorMoveTo); } } }, /**@arg {vimState} vim @arg {InputStateInterface} inputState, @arg {import("./types").actionCommand} [actionCommand] */ recordLastEdit: function(vim2, inputState, actionCommand) { var macroModeState = vimGlobalState.macroModeState; if (macroModeState.isPlaying) { return; } vim2.lastEditInputState = inputState; vim2.lastEditActionCommand = actionCommand; macroModeState.lastInsertModeChanges.changes = []; macroModeState.lastInsertModeChanges.expectCursorActivityForChange = false; macroModeState.lastInsertModeChanges.visualBlock = vim2.visualBlock ? vim2.sel.head.line - vim2.sel.anchor.line : 0; } }; var motions = { moveToTopLine: function(cm, _head, motionArgs) { var line = getUserVisibleLines(cm).top + motionArgs.repeat - 1; return new Pos3(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); }, moveToMiddleLine: function(cm) { var range = getUserVisibleLines(cm); var line = Math.floor((range.top + range.bottom) * 0.5); return new Pos3(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); }, moveToBottomLine: function(cm, _head, motionArgs) { var line = getUserVisibleLines(cm).bottom - motionArgs.repeat + 1; return new Pos3(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); }, expandToLine: function(_cm, head, motionArgs) { var cur = head; return new Pos3(cur.line + motionArgs.repeat - 1, Infinity); }, findNext: function(cm, _head, motionArgs) { var state = getSearchState(cm); var query = state.getQuery(); if (!query) { return; } var prev = !motionArgs.forward; prev = state.isReversed() ? !prev : prev; highlightSearchMatches(cm, query); return findNext(cm, prev, query, motionArgs.repeat); }, /** * Find and select the next occurrence of the search query. If the cursor is currently * within a match, then find and select the current match. Otherwise, find the next occurrence in the * appropriate direction. * * This differs from `findNext` in the following ways: * * 1. Instead of only returning the "from", this returns a "from", "to" range. * 2. If the cursor is currently inside a search match, this selects the current match * instead of the next match. * 3. If there is no associated operator, this will turn on visual mode. */ findAndSelectNextInclusive: function(cm, _head, motionArgs, vim2, prevInputState) { var state = getSearchState(cm); var query = state.getQuery(); if (!query) { return; } var prev = !motionArgs.forward; prev = state.isReversed() ? !prev : prev; var next = findNextFromAndToInclusive(cm, prev, query, motionArgs.repeat, vim2); if (!next) { return; } if (prevInputState.operator) { return next; } var from = next[0]; var to = new Pos3(next[1].line, next[1].ch - 1); if (vim2.visualMode) { if (vim2.visualLine || vim2.visualBlock) { vim2.visualLine = false; vim2.visualBlock = false; CodeMirror2.signal(cm, "vim-mode-change", { mode: "visual", subMode: "" }); } var anchor = vim2.sel.anchor; if (anchor) { if (state.isReversed()) { if (motionArgs.forward) { return [anchor, from]; } return [anchor, to]; } else { if (motionArgs.forward) { return [anchor, to]; } return [anchor, from]; } } } else { vim2.visualMode = true; vim2.visualLine = false; vim2.visualBlock = false; CodeMirror2.signal(cm, "vim-mode-change", { mode: "visual", subMode: "" }); } return prev ? [to, from] : [from, to]; }, goToMark: function(cm, _head, motionArgs, vim2) { var pos = getMarkPos(cm, vim2, motionArgs.selectedCharacter || ""); if (pos) { return motionArgs.linewise ? { line: pos.line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(pos.line)) } : pos; } return null; }, moveToOtherHighlightedEnd: function(cm, _head, motionArgs, vim2) { if (vim2.visualBlock && motionArgs.sameLine) { var sel = vim2.sel; return [ clipCursorToContent(cm, new Pos3(sel.anchor.line, sel.head.ch)), clipCursorToContent(cm, new Pos3(sel.head.line, sel.anchor.ch)) ]; } else { return [vim2.sel.head, vim2.sel.anchor]; } }, jumpToMark: function(cm, head, motionArgs, vim2) { var best = head; for (var i = 0; i < motionArgs.repeat; i++) { var cursor = best; for (var key in vim2.marks) { if (!isLowerCase(key)) { continue; } var mark = vim2.marks[key].find(); var isWrongDirection = motionArgs.forward ? ( // @ts-ignore cursorIsBefore(mark, cursor) ) : cursorIsBefore(cursor, mark); if (isWrongDirection) { continue; } if (motionArgs.linewise && mark.line == cursor.line) { continue; } var equal = cursorEqual(cursor, best); var between = motionArgs.forward ? ( // @ts-ignore cursorIsBetween(cursor, mark, best) ) : ( // @ts-ignore cursorIsBetween(best, mark, cursor) ); if (equal || between) { best = mark; } } } if (motionArgs.linewise) { best = new Pos3(best.line, findFirstNonWhiteSpaceCharacter(cm.getLine(best.line))); } return best; }, moveByCharacters: function(_cm, head, motionArgs) { var cur = head; var repeat = motionArgs.repeat; var ch = motionArgs.forward ? cur.ch + repeat : cur.ch - repeat; return new Pos3(cur.line, ch); }, moveByLines: function(cm, head, motionArgs, vim2) { var cur = head; var endCh = cur.ch; switch (vim2.lastMotion) { case this.moveByLines: case this.moveByDisplayLines: case this.moveByScroll: case this.moveToColumn: case this.moveToEol: endCh = vim2.lastHPos; break; default: vim2.lastHPos = endCh; } var repeat = motionArgs.repeat + (motionArgs.repeatOffset || 0); var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat; var first = cm.firstLine(); var last = cm.lastLine(); var posV = cm.findPosV(cur, motionArgs.forward ? repeat : -repeat, "line", vim2.lastHSPos); var hasMarkedText = motionArgs.forward ? posV.line > line : posV.line < line; if (hasMarkedText) { line = posV.line; endCh = posV.ch; } if (line < first && cur.line == first) { return this.moveToStartOfLine(cm, head, motionArgs, vim2); } else if (line > last && cur.line == last) { return moveToEol(cm, head, motionArgs, vim2, true); } if (motionArgs.toFirstChar) { endCh = findFirstNonWhiteSpaceCharacter(cm.getLine(line)); vim2.lastHPos = endCh; } vim2.lastHSPos = cm.charCoords(new Pos3(line, endCh), "div").left; return new Pos3(line, endCh); }, moveByDisplayLines: function(cm, head, motionArgs, vim2) { var cur = head; switch (vim2.lastMotion) { case this.moveByDisplayLines: case this.moveByScroll: case this.moveByLines: case this.moveToColumn: case this.moveToEol: break; default: vim2.lastHSPos = cm.charCoords(cur, "div").left; } var repeat = motionArgs.repeat; var res = cm.findPosV(cur, motionArgs.forward ? repeat : -repeat, "line", vim2.lastHSPos); if (res.hitSide) { if (motionArgs.forward) { var lastCharCoords = cm.charCoords(res, "div"); var goalCoords = { top: lastCharCoords.top + 8, left: vim2.lastHSPos }; res = cm.coordsChar(goalCoords, "div"); } else { var resCoords = cm.charCoords(new Pos3(cm.firstLine(), 0), "div"); resCoords.left = vim2.lastHSPos; res = cm.coordsChar(resCoords, "div"); } } vim2.lastHPos = res.ch; return res; }, moveByPage: function(cm, head, motionArgs) { var curStart = head; var repeat = motionArgs.repeat; return cm.findPosV(curStart, motionArgs.forward ? repeat : -repeat, "page"); }, moveByParagraph: function(cm, head, motionArgs) { var dir = motionArgs.forward ? 1 : -1; return findParagraph(cm, head, motionArgs.repeat, dir).start; }, moveBySentence: function(cm, head, motionArgs) { var dir = motionArgs.forward ? 1 : -1; return findSentence(cm, head, motionArgs.repeat, dir); }, moveByScroll: function(cm, head, motionArgs, vim2) { var scrollbox = cm.getScrollInfo(); var curEnd = null; var repeat = motionArgs.repeat; if (!repeat) { repeat = scrollbox.clientHeight / (2 * cm.defaultTextHeight()); } var orig = cm.charCoords(head, "local"); motionArgs.repeat = repeat; curEnd = motions.moveByDisplayLines(cm, head, motionArgs, vim2); if (!curEnd) { return null; } var dest = cm.charCoords(curEnd, "local"); cm.scrollTo(null, scrollbox.top + dest.top - orig.top); return curEnd; }, moveByWords: function(cm, head, motionArgs) { return moveToWord( cm, head, motionArgs.repeat, !!motionArgs.forward, !!motionArgs.wordEnd, !!motionArgs.bigWord ); }, moveTillCharacter: function(cm, head, motionArgs) { var repeat = motionArgs.repeat; var curEnd = moveToCharacter( cm, repeat, motionArgs.forward, motionArgs.selectedCharacter, head ); var increment = motionArgs.forward ? -1 : 1; recordLastCharacterSearch(increment, motionArgs); if (!curEnd) return null; curEnd.ch += increment; return curEnd; }, moveToCharacter: function(cm, head, motionArgs) { var repeat = motionArgs.repeat; recordLastCharacterSearch(0, motionArgs); return moveToCharacter( cm, repeat, motionArgs.forward, motionArgs.selectedCharacter, head ) || head; }, moveToSymbol: function(cm, head, motionArgs) { var repeat = motionArgs.repeat; return motionArgs.selectedCharacter && findSymbol( cm, repeat, motionArgs.forward, motionArgs.selectedCharacter ) || head; }, moveToColumn: function(cm, head, motionArgs, vim2) { var repeat = motionArgs.repeat; vim2.lastHPos = repeat - 1; vim2.lastHSPos = cm.charCoords(head, "div").left; return moveToColumn(cm, repeat); }, moveToEol: function(cm, head, motionArgs, vim2) { return moveToEol(cm, head, motionArgs, vim2, false); }, moveToFirstNonWhiteSpaceCharacter: function(cm, head) { var cursor = head; return new Pos3( cursor.line, findFirstNonWhiteSpaceCharacter(cm.getLine(cursor.line)) ); }, moveToMatchedSymbol: function(cm, head) { var cursor = head; var line = cursor.line; var ch = cursor.ch; var lineText = cm.getLine(line); var symbol; for (; ch < lineText.length; ch++) { symbol = lineText.charAt(ch); if (symbol && isMatchableSymbol(symbol)) { var style = cm.getTokenTypeAt(new Pos3(line, ch + 1)); if (style !== "string" && style !== "comment") { break; } } } if (ch < lineText.length) { var re = symbol === "<" || symbol === ">" ? /[(){}[\]<>]/ : /[(){}[\]]/; var matched = cm.findMatchingBracket(new Pos3(line, ch), { bracketRegex: re }); return matched.to; } else { return cursor; } }, moveToStartOfLine: function(_cm, head) { return new Pos3(head.line, 0); }, moveToLineOrEdgeOfDocument: function(cm, _head, motionArgs) { var lineNum = motionArgs.forward ? cm.lastLine() : cm.firstLine(); if (motionArgs.repeatIsExplicit) { lineNum = motionArgs.repeat - cm.getOption("firstLineNumber"); } return new Pos3( lineNum, findFirstNonWhiteSpaceCharacter(cm.getLine(lineNum)) ); }, moveToStartOfDisplayLine: function(cm) { cm.execCommand("goLineLeft"); return cm.getCursor(); }, moveToEndOfDisplayLine: function(cm) { cm.execCommand("goLineRight"); var head = cm.getCursor(); if (head.sticky == "before") head.ch--; return head; }, textObjectManipulation: function(cm, head, motionArgs, vim2) { var mirroredPairs = { "(": ")", ")": "(", "{": "}", "}": "{", "[": "]", "]": "[", "<": ">", ">": "<" }; var selfPaired = { "'": true, '"': true, "`": true }; var character = motionArgs.selectedCharacter || ""; if (character == "b") { character = "("; } else if (character == "B") { character = "{"; } var inclusive = !motionArgs.textObjectInner; var tmp, move; if (mirroredPairs[character]) { move = true; tmp = selectCompanionObject(cm, head, character, inclusive); if (!tmp) { var sc = cm.getSearchCursor(new RegExp("\\" + character, "g"), head); if (sc.find()) { tmp = selectCompanionObject(cm, sc.from(), character, inclusive); } } } else if (selfPaired[character]) { move = true; tmp = findBeginningAndEnd(cm, head, character, inclusive); } else if (character === "W" || character === "w") { var repeat = motionArgs.repeat || 1; while (repeat-- > 0) { var repeated = expandWordUnderCursor(cm, { inclusive, innerWord: !inclusive, bigWord: character === "W", noSymbol: character === "W", multiline: true }, tmp && tmp.end); if (repeated) { if (!tmp) tmp = repeated; tmp.end = repeated.end; } } } else if (character === "p") { tmp = findParagraph(cm, head, motionArgs.repeat, 0, inclusive); motionArgs.linewise = true; if (vim2.visualMode) { if (!vim2.visualLine) { vim2.visualLine = true; } } else { var operatorArgs = vim2.inputState.operatorArgs; if (operatorArgs) { operatorArgs.linewise = true; } tmp.end.line--; } } else if (character === "t") { tmp = expandTagUnderCursor(cm, head, inclusive); } else if (character === "s") { var content = cm.getLine(head.line); if (head.ch > 0 && isEndOfSentenceSymbol(content[head.ch])) { head.ch -= 1; } var end = getSentence(cm, head, motionArgs.repeat, 1, inclusive); var start = getSentence(cm, head, motionArgs.repeat, -1, inclusive); if (isWhiteSpaceString(cm.getLine(start.line)[start.ch]) && isWhiteSpaceString(cm.getLine(end.line)[end.ch - 1])) { start = { line: start.line, ch: start.ch + 1 }; } tmp = { start, end }; } if (!tmp) { return null; } if (!cm.state.vim.visualMode) { return [tmp.start, tmp.end]; } else { return expandSelection(cm, tmp.start, tmp.end, move); } }, repeatLastCharacterSearch: function(cm, head, motionArgs) { var lastSearch = vimGlobalState.lastCharacterSearch; var repeat = motionArgs.repeat; var forward = motionArgs.forward === lastSearch.forward; var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1); cm.moveH(-increment, "char"); motionArgs.inclusive = forward ? true : false; var curEnd = moveToCharacter(cm, repeat, forward, lastSearch.selectedCharacter); if (!curEnd) { cm.moveH(increment, "char"); return head; } curEnd.ch += increment; return curEnd; } }; function defineMotion(name, fn) { motions[name] = fn; } function fillArray(val, times) { var arr = []; for (var i = 0; i < times; i++) { arr.push(val); } return arr; } var operators = { change: function(cm, args, ranges) { var finalHead, text; var vim2 = cm.state.vim; var anchor = ranges[0].anchor, head = ranges[0].head; if (!vim2.visualMode) { text = cm.getRange(anchor, head); var lastState = vim2.lastEditInputState; if ((lastState == null ? void 0 : lastState.motion) == "moveByWords" && !isWhiteSpaceString(text)) { var match = /\s+$/.exec(text); if (match && lastState.motionArgs && lastState.motionArgs.forward) { head = offsetCursor(head, 0, -match[0].length); text = text.slice(0, -match[0].length); } } if (args.linewise) { anchor = new Pos3(anchor.line, findFirstNonWhiteSpaceCharacter(cm.getLine(anchor.line))); if (head.line > anchor.line) { head = new Pos3(head.line - 1, Number.MAX_VALUE); } } cm.replaceRange("", anchor, head); finalHead = anchor; } else if (args.fullLine) { head.ch = Number.MAX_VALUE; head.line--; cm.setSelection(anchor, head); text = cm.getSelection(); cm.replaceSelection(""); finalHead = anchor; } else { text = cm.getSelection(); var replacement = fillArray("", ranges.length); cm.replaceSelections(replacement); finalHead = cursorMin(ranges[0].head, ranges[0].anchor); } vimGlobalState.registerController.pushText( args.registerName, "change", text, args.linewise, ranges.length > 1 ); actions.enterInsertMode(cm, { head: finalHead }, cm.state.vim); }, delete: function(cm, args, ranges) { var finalHead, text; var vim2 = cm.state.vim; if (!vim2.visualBlock) { var anchor = ranges[0].anchor, head = ranges[0].head; if (args.linewise && head.line != cm.firstLine() && anchor.line == cm.lastLine() && anchor.line == head.line - 1) { if (anchor.line == cm.firstLine()) { anchor.ch = 0; } else { anchor = new Pos3(anchor.line - 1, lineLength(cm, anchor.line - 1)); } } text = cm.getRange(anchor, head); cm.replaceRange("", anchor, head); finalHead = anchor; if (args.linewise) { finalHead = motions.moveToFirstNonWhiteSpaceCharacter(cm, anchor); } } else { text = cm.getSelection(); var replacement = fillArray("", ranges.length); cm.replaceSelections(replacement); finalHead = cursorMin(ranges[0].head, ranges[0].anchor); } vimGlobalState.registerController.pushText( args.registerName, "delete", text, args.linewise, vim2.visualBlock ); return clipCursorToContent(cm, finalHead); }, indent: function(cm, args, ranges) { var vim2 = cm.state.vim; var repeat = vim2.visualMode ? args.repeat || 0 : 1; if (cm.indentMore) { for (var j = 0; j < repeat; j++) { if (args.indentRight) cm.indentMore(); else cm.indentLess(); } } else { var startLine = ranges[0].anchor.line; var endLine = vim2.visualBlock ? ranges[ranges.length - 1].anchor.line : ranges[0].head.line; if (args.linewise) { endLine--; } for (var i = startLine; i <= endLine; i++) { for (var j = 0; j < repeat; j++) { cm.indentLine(i, args.indentRight); } } } return motions.moveToFirstNonWhiteSpaceCharacter(cm, ranges[0].anchor); }, indentAuto: function(cm, _args, ranges) { cm.execCommand("indentAuto"); return motions.moveToFirstNonWhiteSpaceCharacter(cm, ranges[0].anchor); }, hardWrap: function(cm, operatorArgs, ranges, oldAnchor) { if (!cm.hardWrap) return; var from = ranges[0].anchor.line; var to = ranges[0].head.line; if (operatorArgs.linewise) to--; var endRow = cm.hardWrap({ from, to }); if (endRow > from && operatorArgs.linewise) endRow--; return operatorArgs.keepCursor ? oldAnchor : new Pos3(endRow, 0); }, changeCase: function(cm, args, ranges, oldAnchor, newHead) { var selections = cm.getSelections(); var swapped = []; var toLower = args.toLower; for (var j = 0; j < selections.length; j++) { var toSwap = selections[j]; var text = ""; if (toLower === true) { text = toSwap.toLowerCase(); } else if (toLower === false) { text = toSwap.toUpperCase(); } else { for (var i = 0; i < toSwap.length; i++) { var character = toSwap.charAt(i); text += isUpperCase(character) ? character.toLowerCase() : character.toUpperCase(); } } swapped.push(text); } cm.replaceSelections(swapped); if (args.shouldMoveCursor) { return newHead; } else if (!cm.state.vim.visualMode && args.linewise && ranges[0].anchor.line + 1 == ranges[0].head.line) { return motions.moveToFirstNonWhiteSpaceCharacter(cm, oldAnchor); } else if (args.linewise) { return oldAnchor; } else { return cursorMin(ranges[0].anchor, ranges[0].head); } }, yank: function(cm, args, ranges, oldAnchor) { var vim2 = cm.state.vim; var text = cm.getSelection(); var endPos = vim2.visualMode ? cursorMin(vim2.sel.anchor, vim2.sel.head, ranges[0].head, ranges[0].anchor) : oldAnchor; vimGlobalState.registerController.pushText( args.registerName, "yank", text, args.linewise, vim2.visualBlock ); return endPos; } }; function defineOperator(name, fn) { operators[name] = fn; } var actions = { jumpListWalk: function(cm, actionArgs, vim2) { if (vim2.visualMode) { return; } var repeat = actionArgs.repeat || 1; var forward = actionArgs.forward; var jumpList = vimGlobalState.jumpList; var mark = jumpList.move(cm, forward ? repeat : -repeat); var markPos = mark ? mark.find() : void 0; markPos = markPos ? markPos : cm.getCursor(); cm.setCursor(markPos); }, scroll: function(cm, actionArgs, vim2) { if (vim2.visualMode) { return; } var repeat = actionArgs.repeat || 1; var lineHeight = cm.defaultTextHeight(); var top = cm.getScrollInfo().top; var delta = lineHeight * repeat; var newPos = actionArgs.forward ? top + delta : top - delta; var cursor = copyCursor(cm.getCursor()); var cursorCoords = cm.charCoords(cursor, "local"); if (actionArgs.forward) { if (newPos > cursorCoords.top) { cursor.line += (newPos - cursorCoords.top) / lineHeight; cursor.line = Math.ceil(cursor.line); cm.setCursor(cursor); cursorCoords = cm.charCoords(cursor, "local"); cm.scrollTo(null, cursorCoords.top); } else { cm.scrollTo(null, newPos); } } else { var newBottom = newPos + cm.getScrollInfo().clientHeight; if (newBottom < cursorCoords.bottom) { cursor.line -= (cursorCoords.bottom - newBottom) / lineHeight; cursor.line = Math.floor(cursor.line); cm.setCursor(cursor); cursorCoords = cm.charCoords(cursor, "local"); cm.scrollTo( null, cursorCoords.bottom - cm.getScrollInfo().clientHeight ); } else { cm.scrollTo(null, newPos); } } }, scrollToCursor: function(cm, actionArgs) { var lineNum = cm.getCursor().line; var charCoords = cm.charCoords(new Pos3(lineNum, 0), "local"); var height = cm.getScrollInfo().clientHeight; var y = charCoords.top; switch (actionArgs.position) { case "center": y = charCoords.bottom - height / 2; break; case "bottom": var lineLastCharPos = new Pos3(lineNum, cm.getLine(lineNum).length - 1); var lineLastCharCoords = cm.charCoords(lineLastCharPos, "local"); var lineHeight = lineLastCharCoords.bottom - y; y = y - height + lineHeight; break; } cm.scrollTo(null, y); }, replayMacro: function(cm, actionArgs, vim2) { var registerName = actionArgs.selectedCharacter || ""; var repeat = actionArgs.repeat || 1; var macroModeState = vimGlobalState.macroModeState; if (registerName == "@") { registerName = macroModeState.latestRegister; } else { macroModeState.latestRegister = registerName; } while (repeat--) { executeMacroRegister(cm, vim2, macroModeState, registerName); } }, enterMacroRecordMode: function(cm, actionArgs) { var macroModeState = vimGlobalState.macroModeState; var registerName = actionArgs.selectedCharacter; if (vimGlobalState.registerController.isValidRegister(registerName)) { macroModeState.enterMacroRecordMode(cm, registerName); } }, toggleOverwrite: function(cm) { if (!cm.state.overwrite) { cm.toggleOverwrite(true); cm.setOption("keyMap", "vim-replace"); CodeMirror2.signal(cm, "vim-mode-change", { mode: "replace" }); } else { cm.toggleOverwrite(false); cm.setOption("keyMap", "vim-insert"); CodeMirror2.signal(cm, "vim-mode-change", { mode: "insert" }); } }, enterInsertMode: function(cm, actionArgs, vim2) { if (cm.getOption("readOnly")) { return; } vim2.insertMode = true; vim2.insertModeRepeat = actionArgs && actionArgs.repeat || 1; var insertAt = actionArgs ? actionArgs.insertAt : null; var sel = vim2.sel; var head = actionArgs.head || cm.getCursor("head"); var height = cm.listSelections().length; if (insertAt == "eol") { head = new Pos3(head.line, lineLength(cm, head.line)); } else if (insertAt == "bol") { head = new Pos3(head.line, 0); } else if (insertAt == "charAfter") { var newPosition = updateSelectionForSurrogateCharacters(cm, head, offsetCursor(head, 0, 1)); head = newPosition.end; } else if (insertAt == "firstNonBlank") { var newPosition = updateSelectionForSurrogateCharacters(cm, head, motions.moveToFirstNonWhiteSpaceCharacter(cm, head)); head = newPosition.end; } else if (insertAt == "startOfSelectedArea") { if (!vim2.visualMode) return; if (!vim2.visualBlock) { if (sel.head.line < sel.anchor.line) { head = sel.head; } else { head = new Pos3(sel.anchor.line, 0); } } else { head = new Pos3( Math.min(sel.head.line, sel.anchor.line), Math.min(sel.head.ch, sel.anchor.ch) ); height = Math.abs(sel.head.line - sel.anchor.line) + 1; } } else if (insertAt == "endOfSelectedArea") { if (!vim2.visualMode) return; if (!vim2.visualBlock) { if (sel.head.line >= sel.anchor.line) { head = offsetCursor(sel.head, 0, 1); } else { head = new Pos3(sel.anchor.line, 0); } } else { head = new Pos3( Math.min(sel.head.line, sel.anchor.line), Math.max(sel.head.ch, sel.anchor.ch) + 1 ); height = Math.abs(sel.head.line - sel.anchor.line) + 1; } } else if (insertAt == "inplace") { if (vim2.visualMode) { return; } } else if (insertAt == "lastEdit") { head = getLastEditPos(cm) || head; } cm.setOption("disableInput", false); if (actionArgs && actionArgs.replace) { cm.toggleOverwrite(true); cm.setOption("keyMap", "vim-replace"); CodeMirror2.signal(cm, "vim-mode-change", { mode: "replace" }); } else { cm.toggleOverwrite(false); cm.setOption("keyMap", "vim-insert"); CodeMirror2.signal(cm, "vim-mode-change", { mode: "insert" }); } if (!vimGlobalState.macroModeState.isPlaying) { cm.on("change", onChange); if (vim2.insertEnd) vim2.insertEnd.clear(); vim2.insertEnd = cm.setBookmark(head, { insertLeft: true }); CodeMirror2.on(cm.getInputField(), "keydown", onKeyEventTargetKeyDown); } if (vim2.visualMode) { exitVisualMode(cm); } selectForInsert(cm, head, height); }, toggleVisualMode: function(cm, actionArgs, vim2) { var repeat = actionArgs.repeat; var anchor = cm.getCursor(); var head; if (!vim2.visualMode) { vim2.visualMode = true; vim2.visualLine = !!actionArgs.linewise; vim2.visualBlock = !!actionArgs.blockwise; head = clipCursorToContent( cm, new Pos3(anchor.line, anchor.ch + repeat - 1) ); var newPosition = updateSelectionForSurrogateCharacters(cm, anchor, head); vim2.sel = { anchor: newPosition.start, head: newPosition.end }; CodeMirror2.signal(cm, "vim-mode-change", { mode: "visual", subMode: vim2.visualLine ? "linewise" : vim2.visualBlock ? "blockwise" : "" }); updateCmSelection(cm); updateMark(cm, vim2, "<", cursorMin(anchor, head)); updateMark(cm, vim2, ">", cursorMax(anchor, head)); } else if (vim2.visualLine != !!actionArgs.linewise || vim2.visualBlock != !!actionArgs.blockwise) { vim2.visualLine = !!actionArgs.linewise; vim2.visualBlock = !!actionArgs.blockwise; CodeMirror2.signal(cm, "vim-mode-change", { mode: "visual", subMode: vim2.visualLine ? "linewise" : vim2.visualBlock ? "blockwise" : "" }); updateCmSelection(cm); } else { exitVisualMode(cm); } }, reselectLastSelection: function(cm, _actionArgs, vim2) { var lastSelection = vim2.lastSelection; if (vim2.visualMode) { updateLastSelection(cm, vim2); } if (lastSelection) { var anchor = lastSelection.anchorMark.find(); var head = lastSelection.headMark.find(); if (!anchor || !head) { return; } vim2.sel = { anchor, head }; vim2.visualMode = true; vim2.visualLine = lastSelection.visualLine; vim2.visualBlock = lastSelection.visualBlock; updateCmSelection(cm); updateMark(cm, vim2, "<", cursorMin(anchor, head)); updateMark(cm, vim2, ">", cursorMax(anchor, head)); CodeMirror2.signal(cm, "vim-mode-change", { mode: "visual", subMode: vim2.visualLine ? "linewise" : vim2.visualBlock ? "blockwise" : "" }); } }, joinLines: function(cm, actionArgs, vim2) { var curStart, curEnd; if (vim2.visualMode) { curStart = cm.getCursor("anchor"); curEnd = cm.getCursor("head"); if (cursorIsBefore(curEnd, curStart)) { var tmp = curEnd; curEnd = curStart; curStart = tmp; } curEnd.ch = lineLength(cm, curEnd.line) - 1; } else { var repeat = Math.max(actionArgs.repeat, 2); curStart = cm.getCursor(); curEnd = clipCursorToContent(cm, new Pos3( curStart.line + repeat - 1, Infinity )); } var finalCh = 0; for (var i = curStart.line; i < curEnd.line; i++) { finalCh = lineLength(cm, curStart.line); var text = ""; var nextStartCh = 0; if (!actionArgs.keepSpaces) { var nextLine = cm.getLine(curStart.line + 1); nextStartCh = nextLine.search(/\S/); if (nextStartCh == -1) { nextStartCh = nextLine.length; } else { text = " "; } } cm.replaceRange( text, new Pos3(curStart.line, finalCh), new Pos3(curStart.line + 1, nextStartCh) ); } var curFinalPos = clipCursorToContent(cm, new Pos3(curStart.line, finalCh)); if (vim2.visualMode) { exitVisualMode(cm, false); } cm.setCursor(curFinalPos); }, newLineAndEnterInsertMode: function(cm, actionArgs, vim2) { vim2.insertMode = true; var insertAt = copyCursor(cm.getCursor()); if (insertAt.line === cm.firstLine() && !actionArgs.after) { cm.replaceRange("\n", new Pos3(cm.firstLine(), 0)); cm.setCursor(cm.firstLine(), 0); } else { insertAt.line = actionArgs.after ? insertAt.line : insertAt.line - 1; insertAt.ch = lineLength(cm, insertAt.line); cm.setCursor(insertAt); var newlineFn = CodeMirror2.commands.newlineAndIndentContinueComment || CodeMirror2.commands.newlineAndIndent; newlineFn(cm); } this.enterInsertMode(cm, { repeat: actionArgs.repeat }, vim2); }, paste: function(cm, actionArgs, vim2) { var register = vimGlobalState.registerController.getRegister( actionArgs.registerName ); if (actionArgs.registerName === "+") { navigator.clipboard.readText().then((value) => { this.continuePaste(cm, actionArgs, vim2, value, register); }); } else { var text = register.toString(); this.continuePaste(cm, actionArgs, vim2, text, register); } }, continuePaste: function(cm, actionArgs, vim2, text, register) { var cur = copyCursor(cm.getCursor()); if (!text) { return; } if (actionArgs.matchIndent) { var tabSize = cm.getOption("tabSize"); var whitespaceLength = function(str) { var tabs = str.split(" ").length - 1; var spaces = str.split(" ").length - 1; return tabs * tabSize + spaces * 1; }; var currentLine = cm.getLine(cm.getCursor().line); var indent = whitespaceLength(currentLine.match(/^\s*/)[0]); var chompedText = text.replace(/\n$/, ""); var wasChomped = text !== chompedText; var firstIndent = whitespaceLength(text.match(/^\s*/)[0]); var text = chompedText.replace(/^\s*/gm, function(wspace) { var newIndent = indent + (whitespaceLength(wspace) - firstIndent); if (newIndent < 0) { return ""; } else if (cm.getOption("indentWithTabs")) { var quotient = Math.floor(newIndent / tabSize); return Array(quotient + 1).join(" "); } else { return Array(newIndent + 1).join(" "); } }); text += wasChomped ? "\n" : ""; } if (actionArgs.repeat > 1) { var text = Array(actionArgs.repeat + 1).join(text); } var linewise = register.linewise; var blockwise = register.blockwise; if (blockwise) { text = text.split("\n"); if (linewise) { text.pop(); } for (var i = 0; i < text.length; i++) { text[i] = text[i] == "" ? " " : text[i]; } cur.ch += actionArgs.after ? 1 : 0; cur.ch = Math.min(lineLength(cm, cur.line), cur.ch); } else if (linewise) { if (vim2.visualMode) { text = vim2.visualLine ? text.slice(0, -1) : "\n" + text.slice(0, text.length - 1) + "\n"; } else if (actionArgs.after) { text = "\n" + text.slice(0, text.length - 1); cur.ch = lineLength(cm, cur.line); } else { cur.ch = 0; } } else { cur.ch += actionArgs.after ? 1 : 0; } var curPosFinal; if (vim2.visualMode) { vim2.lastPastedText = text; var lastSelectionCurEnd; var selectedArea = getSelectedAreaRange(cm, vim2); var selectionStart = selectedArea[0]; var selectionEnd = selectedArea[1]; var selectedText = cm.getSelection(); var selections = cm.listSelections(); var emptyStrings = new Array(selections.length).join("1").split("1"); if (vim2.lastSelection) { lastSelectionCurEnd = vim2.lastSelection.headMark.find(); } vimGlobalState.registerController.unnamedRegister.setText(selectedText); if (blockwise) { cm.replaceSelections(emptyStrings); selectionEnd = new Pos3(selectionStart.line + text.length - 1, selectionStart.ch); cm.setCursor(selectionStart); selectBlock(cm, selectionEnd); cm.replaceSelections(text); curPosFinal = selectionStart; } else if (vim2.visualBlock) { cm.replaceSelections(emptyStrings); cm.setCursor(selectionStart); cm.replaceRange(text, selectionStart, selectionStart); curPosFinal = selectionStart; } else { cm.replaceRange(text, selectionStart, selectionEnd); curPosFinal = cm.posFromIndex(cm.indexFromPos(selectionStart) + text.length - 1); } if (lastSelectionCurEnd) { vim2.lastSelection.headMark = cm.setBookmark(lastSelectionCurEnd); } if (linewise) { curPosFinal.ch = 0; } } else { if (blockwise) { cm.setCursor(cur); for (var i = 0; i < text.length; i++) { var line = cur.line + i; if (line > cm.lastLine()) { cm.replaceRange("\n", new Pos3(line, 0)); } var lastCh = lineLength(cm, line); if (lastCh < cur.ch) { extendLineToColumn(cm, line, cur.ch); } } cm.setCursor(cur); selectBlock(cm, new Pos3(cur.line + text.length - 1, cur.ch)); cm.replaceSelections(text); curPosFinal = cur; } else { cm.replaceRange(text, cur); if (linewise) { var line = actionArgs.after ? cur.line + 1 : cur.line; curPosFinal = new Pos3(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); } else { curPosFinal = copyCursor(cur); if (!/\n/.test(text)) { curPosFinal.ch += text.length - (actionArgs.after ? 1 : 0); } } } } if (vim2.visualMode) { exitVisualMode(cm, false); } cm.setCursor(curPosFinal); }, undo: function(cm, actionArgs) { cm.operation(function() { repeatFn(cm, CodeMirror2.commands.undo, actionArgs.repeat)(); cm.setCursor(clipCursorToContent(cm, cm.getCursor("start"))); }); }, redo: function(cm, actionArgs) { repeatFn(cm, CodeMirror2.commands.redo, actionArgs.repeat)(); }, setRegister: function(_cm, actionArgs, vim2) { vim2.inputState.registerName = actionArgs.selectedCharacter; }, insertRegister: function(cm, actionArgs, vim2) { var registerName = actionArgs.selectedCharacter; var register = vimGlobalState.registerController.getRegister(registerName); var text = register && register.toString(); if (text) { cm.replaceSelection(text); } }, oneNormalCommand: function(cm, actionArgs, vim2) { exitInsertMode(cm, true); vim2.insertModeReturn = true; CodeMirror2.on(cm, "vim-command-done", function handler() { if (vim2.visualMode) return; if (vim2.insertModeReturn) { vim2.insertModeReturn = false; if (!vim2.insertMode) { actions.enterInsertMode(cm, {}, vim2); } } CodeMirror2.off(cm, "vim-command-done", handler); }); }, setMark: function(cm, actionArgs, vim2) { var markName = actionArgs.selectedCharacter; if (markName) updateMark(cm, vim2, markName, cm.getCursor()); }, replace: function(cm, actionArgs, vim2) { var replaceWith = actionArgs.selectedCharacter || ""; var curStart = cm.getCursor(); var replaceTo; var curEnd; var selections = cm.listSelections(); if (vim2.visualMode) { curStart = cm.getCursor("start"); curEnd = cm.getCursor("end"); } else { var line = cm.getLine(curStart.line); replaceTo = curStart.ch + actionArgs.repeat; if (replaceTo > line.length) { replaceTo = line.length; } curEnd = new Pos3(curStart.line, replaceTo); } var newPositions = updateSelectionForSurrogateCharacters(cm, curStart, curEnd); curStart = newPositions.start; curEnd = newPositions.end; if (replaceWith == "\n") { if (!vim2.visualMode) cm.replaceRange("", curStart, curEnd); (CodeMirror2.commands.newlineAndIndentContinueComment || CodeMirror2.commands.newlineAndIndent)(cm); } else { var replaceWithStr = cm.getRange(curStart, curEnd); replaceWithStr = replaceWithStr.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, replaceWith); replaceWithStr = replaceWithStr.replace(/[^\n]/g, replaceWith); if (vim2.visualBlock) { var spaces = new Array(cm.getOption("tabSize") + 1).join(" "); replaceWithStr = cm.getSelection(); replaceWithStr = replaceWithStr.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, replaceWith); var replaceWithStrings = replaceWithStr.replace(/\t/g, spaces).replace(/[^\n]/g, replaceWith).split("\n"); cm.replaceSelections(replaceWithStrings); } else { cm.replaceRange(replaceWithStr, curStart, curEnd); } if (vim2.visualMode) { curStart = cursorIsBefore(selections[0].anchor, selections[0].head) ? selections[0].anchor : selections[0].head; cm.setCursor(curStart); exitVisualMode(cm, false); } else { cm.setCursor(offsetCursor(curEnd, 0, -1)); } } }, incrementNumberToken: function(cm, actionArgs) { var cur = cm.getCursor(); var lineStr = cm.getLine(cur.line); var re = /(-?)(?:(0x)([\da-f]+)|(0b|0|)(\d+))/gi; var match; var start; var end; var numberStr; while ((match = re.exec(lineStr)) !== null) { start = match.index; end = start + match[0].length; if (cur.ch < end) break; } if (!actionArgs.backtrack && end <= cur.ch) return; if (match) { var baseStr = match[2] || match[4]; var digits = match[3] || match[5]; var increment = actionArgs.increase ? 1 : -1; var base = { "0b": 2, "0": 8, "": 10, "0x": 16 }[baseStr.toLowerCase()]; var number = parseInt(match[1] + digits, base) + increment * actionArgs.repeat; numberStr = number.toString(base); var zeroPadding = baseStr ? new Array(digits.length - numberStr.length + 1 + match[1].length).join("0") : ""; if (numberStr.charAt(0) === "-") { numberStr = "-" + baseStr + zeroPadding + numberStr.substr(1); } else { numberStr = baseStr + zeroPadding + numberStr; } var from = new Pos3(cur.line, start); var to = new Pos3(cur.line, end); cm.replaceRange(numberStr, from, to); } else { return; } cm.setCursor(new Pos3(cur.line, start + numberStr.length - 1)); }, repeatLastEdit: function(cm, actionArgs, vim2) { var lastEditInputState = vim2.lastEditInputState; if (!lastEditInputState) { return; } var repeat = actionArgs.repeat; if (repeat && actionArgs.repeatIsExplicit) { lastEditInputState.repeatOverride = repeat; } else { repeat = lastEditInputState.repeatOverride || repeat; } repeatLastEdit( cm, vim2, repeat, false /** repeatForInsert */ ); }, indent: function(cm, actionArgs) { cm.indentLine(cm.getCursor().line, actionArgs.indentRight); }, exitInsertMode: function(cm, actionArgs) { exitInsertMode(cm); } }; function defineAction(name, fn) { actions[name] = fn; } function clipCursorToContent(cm, cur, oldCur) { var vim2 = cm.state.vim; var includeLineBreak = vim2.insertMode || vim2.visualMode; var line = Math.min(Math.max(cm.firstLine(), cur.line), cm.lastLine()); var text = cm.getLine(line); var maxCh = text.length - 1 + Number(!!includeLineBreak); var ch = Math.min(Math.max(0, cur.ch), maxCh); var charCode = text.charCodeAt(ch); if (56320 <= charCode && charCode <= 57343) { var direction = 1; if (oldCur && oldCur.line == line && oldCur.ch > ch) { direction = -1; } ch += direction; if (ch > maxCh) ch -= 2; } return new Pos3(line, ch); } function copyArgs(args) { var ret = {}; for (var prop in args) { if (args.hasOwnProperty(prop)) { ret[prop] = args[prop]; } } return ret; } function offsetCursor(cur, offsetLine, offsetCh) { if (typeof offsetLine === "object") { offsetCh = offsetLine.ch; offsetLine = offsetLine.line; } return new Pos3(cur.line + offsetLine, cur.ch + offsetCh); } function commandMatches(keys2, keyMap, context, inputState) { if (inputState.operator) context = "operatorPending"; var match, partial = [], full = []; var startIndex = noremap ? keyMap.length - defaultKeymapLength : 0; for (var i = startIndex; i < keyMap.length; i++) { var command = keyMap[i]; if (context == "insert" && command.context != "insert" || command.context && command.context != context || inputState.operator && command.type == "action" || !(match = commandMatch(keys2, command.keys))) { continue; } if (match == "partial") { partial.push(command); } if (match == "full") { full.push(command); } } return { partial: partial.length && partial, full: full.length && full }; } function commandMatch(pressed, mapped) { const isLastCharacter = mapped.slice(-11) == ""; const isLastRegister = mapped.slice(-10) == ""; if (isLastCharacter || isLastRegister) { var prefixLen = mapped.length - (isLastCharacter ? 11 : 10); var pressedPrefix = pressed.slice(0, prefixLen); var mappedPrefix = mapped.slice(0, prefixLen); return pressedPrefix == mappedPrefix && pressed.length > prefixLen ? "full" : mappedPrefix.indexOf(pressedPrefix) == 0 ? "partial" : false; } else { return pressed == mapped ? "full" : mapped.indexOf(pressed) == 0 ? "partial" : false; } } function lastChar(keys2) { var match = /^.*(<[^>]+>)$/.exec(keys2); var selectedCharacter = match ? match[1] : keys2.slice(-1); if (selectedCharacter.length > 1) { switch (selectedCharacter) { case "": case "": selectedCharacter = "\n"; break; case "": case "": selectedCharacter = " "; break; default: selectedCharacter = ""; break; } } return selectedCharacter; } function repeatFn(cm, fn, repeat) { return function() { for (var i = 0; i < repeat; i++) { fn(cm); } }; } function copyCursor(cur) { return new Pos3(cur.line, cur.ch); } function cursorEqual(cur1, cur2) { return cur1.ch == cur2.ch && cur1.line == cur2.line; } function cursorIsBefore(cur1, cur2) { if (cur1.line < cur2.line) { return true; } if (cur1.line == cur2.line && cur1.ch < cur2.ch) { return true; } return false; } function cursorMin(cur1, cur2) { if (arguments.length > 2) { cur2 = cursorMin.apply(void 0, Array.prototype.slice.call(arguments, 1)); } return cursorIsBefore(cur1, cur2) ? cur1 : cur2; } function cursorMax(cur1, cur2) { if (arguments.length > 2) { cur2 = cursorMax.apply(void 0, Array.prototype.slice.call(arguments, 1)); } return cursorIsBefore(cur1, cur2) ? cur2 : cur1; } function cursorIsBetween(cur1, cur2, cur3) { var cur1before2 = cursorIsBefore(cur1, cur2); var cur2before3 = cursorIsBefore(cur2, cur3); return cur1before2 && cur2before3; } function lineLength(cm, lineNum) { return cm.getLine(lineNum).length; } function trim(s) { if (s.trim) { return s.trim(); } return s.replace(/^\s+|\s+$/g, ""); } function escapeRegex(s) { return s.replace(/([.?*+$\[\]\/\\(){}|\-])/g, "\\$1"); } function extendLineToColumn(cm, lineNum, column) { var endCh = lineLength(cm, lineNum); var spaces = new Array(column - endCh + 1).join(" "); cm.setCursor(new Pos3(lineNum, endCh)); cm.replaceRange(spaces, cm.getCursor()); } function selectBlock(cm, selectionEnd) { var selections = [], ranges = cm.listSelections(); var head = copyCursor(cm.clipPos(selectionEnd)); var isClipped = !cursorEqual(selectionEnd, head); var curHead = cm.getCursor("head"); var primIndex = getIndex(ranges, curHead); var wasClipped = cursorEqual(ranges[primIndex].head, ranges[primIndex].anchor); var max = ranges.length - 1; var index = max - primIndex > primIndex ? max : 0; var base = ranges[index].anchor; var firstLine = Math.min(base.line, head.line); var lastLine = Math.max(base.line, head.line); var baseCh = base.ch, headCh = head.ch; var dir = ranges[index].head.ch - baseCh; var newDir = headCh - baseCh; if (dir > 0 && newDir <= 0) { baseCh++; if (!isClipped) { headCh--; } } else if (dir < 0 && newDir >= 0) { baseCh--; if (!wasClipped) { headCh++; } } else if (dir < 0 && newDir == -1) { baseCh--; headCh++; } for (var line = firstLine; line <= lastLine; line++) { var range = { anchor: new Pos3(line, baseCh), head: new Pos3(line, headCh) }; selections.push(range); } cm.setSelections(selections); selectionEnd.ch = headCh; base.ch = baseCh; return base; } function selectForInsert(cm, head, height) { var sel = []; for (var i = 0; i < height; i++) { var lineHead = offsetCursor(head, i, 0); sel.push({ anchor: lineHead, head: lineHead }); } cm.setSelections(sel, 0); } function getIndex(ranges, cursor, end) { for (var i = 0; i < ranges.length; i++) { var atAnchor = end != "head" && cursorEqual(ranges[i].anchor, cursor); var atHead = end != "anchor" && cursorEqual(ranges[i].head, cursor); if (atAnchor || atHead) { return i; } } return -1; } function getSelectedAreaRange(cm, vim2) { var lastSelection = vim2.lastSelection; var getCurrentSelectedAreaRange = function() { var selections = cm.listSelections(); var start = selections[0]; var end = selections[selections.length - 1]; var selectionStart = cursorIsBefore(start.anchor, start.head) ? start.anchor : start.head; var selectionEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor; return [selectionStart, selectionEnd]; }; var getLastSelectedAreaRange = function() { var selectionStart = cm.getCursor(); var selectionEnd = cm.getCursor(); var block = lastSelection.visualBlock; if (block) { var width = block.width; var height = block.height; selectionEnd = new Pos3(selectionStart.line + height, selectionStart.ch + width); var selections = []; for (var i = selectionStart.line; i < selectionEnd.line; i++) { var anchor = new Pos3(i, selectionStart.ch); var head = new Pos3(i, selectionEnd.ch); var range = { anchor, head }; selections.push(range); } cm.setSelections(selections); } else { var start = lastSelection.anchorMark.find(); var end = lastSelection.headMark.find(); var line = end.line - start.line; var ch = end.ch - start.ch; selectionEnd = { line: selectionEnd.line + line, ch: line ? selectionEnd.ch : ch + selectionEnd.ch }; if (lastSelection.visualLine) { selectionStart = new Pos3(selectionStart.line, 0); selectionEnd = new Pos3(selectionEnd.line, lineLength(cm, selectionEnd.line)); } cm.setSelection(selectionStart, selectionEnd); } return [selectionStart, selectionEnd]; }; if (!vim2.visualMode) { return getLastSelectedAreaRange(); } else { return getCurrentSelectedAreaRange(); } } function updateLastSelection(cm, vim2) { var anchor = vim2.sel.anchor; var head = vim2.sel.head; if (vim2.lastPastedText) { head = cm.posFromIndex(cm.indexFromPos(anchor) + vim2.lastPastedText.length); vim2.lastPastedText = null; } vim2.lastSelection = { "anchorMark": cm.setBookmark(anchor), "headMark": cm.setBookmark(head), "anchor": copyCursor(anchor), "head": copyCursor(head), "visualMode": vim2.visualMode, "visualLine": vim2.visualLine, "visualBlock": vim2.visualBlock }; } function expandSelection(cm, start, end, move) { var sel = cm.state.vim.sel; var head = move ? start : sel.head; var anchor = move ? start : sel.anchor; var tmp; if (cursorIsBefore(end, start)) { tmp = end; end = start; start = tmp; } if (cursorIsBefore(head, anchor)) { head = cursorMin(start, head); anchor = cursorMax(anchor, end); } else { anchor = cursorMin(start, anchor); head = cursorMax(head, end); head = offsetCursor(head, 0, -1); if (head.ch == -1 && head.line != cm.firstLine()) { head = new Pos3(head.line - 1, lineLength(cm, head.line - 1)); } } return [anchor, head]; } function updateCmSelection(cm, sel, mode) { var vim2 = cm.state.vim; sel = sel || vim2.sel; if (!mode) { mode = vim2.visualLine ? "line" : vim2.visualBlock ? "block" : "char"; } var cmSel = makeCmSelection(cm, sel, mode); cm.setSelections(cmSel.ranges, cmSel.primary); } function makeCmSelection(cm, sel, mode, exclusive) { var head = copyCursor(sel.head); var anchor = copyCursor(sel.anchor); if (mode == "char") { var headOffset = !exclusive && !cursorIsBefore(sel.head, sel.anchor) ? 1 : 0; var anchorOffset = cursorIsBefore(sel.head, sel.anchor) ? 1 : 0; head = offsetCursor(sel.head, 0, headOffset); anchor = offsetCursor(sel.anchor, 0, anchorOffset); return { ranges: [{ anchor, head }], primary: 0 }; } else if (mode == "line") { if (!cursorIsBefore(sel.head, sel.anchor)) { anchor.ch = 0; var lastLine = cm.lastLine(); if (head.line > lastLine) { head.line = lastLine; } head.ch = lineLength(cm, head.line); } else { head.ch = 0; anchor.ch = lineLength(cm, anchor.line); } return { ranges: [{ anchor, head }], primary: 0 }; } else if (mode == "block") { var top = Math.min(anchor.line, head.line), fromCh = anchor.ch, bottom = Math.max(anchor.line, head.line), toCh = head.ch; if (fromCh < toCh) { toCh += 1; } else { fromCh += 1; } var height = bottom - top + 1; var primary = head.line == top ? 0 : height - 1; var ranges = []; for (var i = 0; i < height; i++) { ranges.push({ anchor: new Pos3(top + i, fromCh), head: new Pos3(top + i, toCh) }); } return { ranges, primary }; } throw "never happens"; } function getHead(cm) { var cur = cm.getCursor("head"); if (cm.getSelection().length == 1) { cur = cursorMin(cur, cm.getCursor("anchor")); } return cur; } function exitVisualMode(cm, moveHead) { var vim2 = cm.state.vim; if (moveHead !== false) { cm.setCursor(clipCursorToContent(cm, vim2.sel.head)); } updateLastSelection(cm, vim2); vim2.visualMode = false; vim2.visualLine = false; vim2.visualBlock = false; if (!vim2.insertMode) CodeMirror2.signal(cm, "vim-mode-change", { mode: "normal" }); } function clipToLine(cm, curStart, curEnd) { var selection = cm.getRange(curStart, curEnd); if (/\n\s*$/.test(selection)) { var lines = selection.split("\n"); lines.pop(); for (var line = lines.pop(); lines.length > 0 && line && isWhiteSpaceString(line); line = lines.pop()) { curEnd.line--; curEnd.ch = 0; } if (line) { curEnd.line--; curEnd.ch = lineLength(cm, curEnd.line); } else { curEnd.ch = 0; } } } function expandSelectionToLine(_cm, curStart, curEnd) { curStart.ch = 0; curEnd.ch = 0; curEnd.line++; } function findFirstNonWhiteSpaceCharacter(text) { if (!text) { return 0; } var firstNonWS = text.search(/\S/); return firstNonWS == -1 ? text.length : firstNonWS; } function expandWordUnderCursor(cm, { inclusive, innerWord, bigWord, noSymbol, multiline }, cursor) { var cur = cursor || getHead(cm); var line = cm.getLine(cur.line); var endLine = line; var startLineNumber = cur.line; var endLineNumber = startLineNumber; var idx = cur.ch; var wordOnNextLine; var test = noSymbol ? wordCharTest[0] : bigWordCharTest[0]; if (innerWord && /\s/.test(line.charAt(idx))) { test = function(ch) { return /\s/.test(ch); }; } else { while (!test(line.charAt(idx))) { idx++; if (idx >= line.length) { if (!multiline) return null; idx--; wordOnNextLine = findWord(cm, cur, true, bigWord, true); break; } } if (bigWord) { test = bigWordCharTest[0]; } else { test = wordCharTest[0]; if (!test(line.charAt(idx))) { test = wordCharTest[1]; } } } var end = idx, start = idx; while (test(line.charAt(start)) && start >= 0) { start--; } start++; if (wordOnNextLine) { end = wordOnNextLine.to; endLineNumber = wordOnNextLine.line; endLine = cm.getLine(endLineNumber); if (!endLine && end == 0) end++; } else { while (test(line.charAt(end)) && end < line.length) { end++; } } if (inclusive) { var wordEnd = end; var startsWithSpace = cur.ch <= start && /\s/.test(line.charAt(cur.ch)); if (!startsWithSpace) { while (/\s/.test(endLine.charAt(end)) && end < endLine.length) { end++; } } if (wordEnd == end || startsWithSpace) { var wordStart = start; while (/\s/.test(line.charAt(start - 1)) && start > 0) { start--; } if (!start && !startsWithSpace) { start = wordStart; } } } return { start: new Pos3(startLineNumber, start), end: new Pos3(endLineNumber, end) }; } function expandTagUnderCursor(cm, head, inclusive) { var cur = head; if (!CodeMirror2.findMatchingTag || !CodeMirror2.findEnclosingTag) { return { start: cur, end: cur }; } var tags2 = CodeMirror2.findMatchingTag(cm, head) || CodeMirror2.findEnclosingTag(cm, head); if (!tags2 || !tags2.open || !tags2.close) { return { start: cur, end: cur }; } if (inclusive) { return { start: tags2.open.from, end: tags2.close.to }; } return { start: tags2.open.to, end: tags2.close.from }; } function recordJumpPosition(cm, oldCur, newCur) { if (!cursorEqual(oldCur, newCur)) { vimGlobalState.jumpList.add(cm, oldCur, newCur); } } function recordLastCharacterSearch(increment, args) { vimGlobalState.lastCharacterSearch.increment = increment; vimGlobalState.lastCharacterSearch.forward = args.forward; vimGlobalState.lastCharacterSearch.selectedCharacter = args.selectedCharacter; } var symbolToMode = { "(": "bracket", ")": "bracket", "{": "bracket", "}": "bracket", "[": "section", "]": "section", "*": "comment", "/": "comment", "m": "method", "M": "method", "#": "preprocess" }; var findSymbolModes = { bracket: { isComplete: function(state) { if (state.nextCh === state.symb) { state.depth++; if (state.depth >= 1) return true; } else if (state.nextCh === state.reverseSymb) { state.depth--; } return false; } }, section: { init: function(state) { state.curMoveThrough = true; state.symb = (state.forward ? "]" : "[") === state.symb ? "{" : "}"; }, isComplete: function(state) { return state.index === 0 && state.nextCh === state.symb; } }, comment: { isComplete: function(state) { var found = state.lastCh === "*" && state.nextCh === "/"; state.lastCh = state.nextCh; return found; } }, // TODO: The original Vim implementation only operates on level 1 and 2. // The current implementation doesn't check for code block level and // therefore it operates on any levels. method: { init: function(state) { state.symb = state.symb === "m" ? "{" : "}"; state.reverseSymb = state.symb === "{" ? "}" : "{"; }, isComplete: function(state) { if (state.nextCh === state.symb) return true; return false; } }, preprocess: { init: function(state) { state.index = 0; }, isComplete: function(state) { if (state.nextCh === "#") { var token = state.lineText.match(/^#(\w+)/)[1]; if (token === "endif") { if (state.forward && state.depth === 0) { return true; } state.depth++; } else if (token === "if") { if (!state.forward && state.depth === 0) { return true; } state.depth--; } if (token === "else" && state.depth === 0) return true; } return false; } } }; function findSymbol(cm, repeat, forward, symb) { var cur = copyCursor(cm.getCursor()); var increment = forward ? 1 : -1; var endLine = forward ? cm.lineCount() : -1; var curCh = cur.ch; var line = cur.line; var lineText = cm.getLine(line); var state = { lineText, nextCh: lineText.charAt(curCh), lastCh: null, index: curCh, symb, reverseSymb: (forward ? { ")": "(", "}": "{" } : { "(": ")", "{": "}" })[symb], forward, depth: 0, curMoveThrough: false }; var mode = symbolToMode[symb]; if (!mode) return cur; var init = findSymbolModes[mode].init; var isComplete = findSymbolModes[mode].isComplete; if (init) { init(state); } while (line !== endLine && repeat) { state.index += increment; state.nextCh = state.lineText.charAt(state.index); if (!state.nextCh) { line += increment; state.lineText = cm.getLine(line) || ""; if (increment > 0) { state.index = 0; } else { var lineLen = state.lineText.length; state.index = lineLen > 0 ? lineLen - 1 : 0; } state.nextCh = state.lineText.charAt(state.index); } if (isComplete(state)) { cur.line = line; cur.ch = state.index; repeat--; } } if (state.nextCh || state.curMoveThrough) { return new Pos3(line, state.index); } return cur; } function findWord(cm, cur, forward, bigWord, emptyLineIsWord) { var lineNum = cur.line; var pos = cur.ch; var line = cm.getLine(lineNum); var dir = forward ? 1 : -1; var charTests = bigWord ? bigWordCharTest : wordCharTest; if (emptyLineIsWord && line == "") { lineNum += dir; line = cm.getLine(lineNum); if (!isLine(cm, lineNum)) { return null; } pos = forward ? 0 : line.length; } while (true) { if (emptyLineIsWord && line == "") { return { from: 0, to: 0, line: lineNum }; } var stop = dir > 0 ? line.length : -1; var wordStart = stop, wordEnd = stop; while (pos != stop) { var foundWord = false; for (var i = 0; i < charTests.length && !foundWord; ++i) { if (charTests[i](line.charAt(pos))) { wordStart = pos; while (pos != stop && charTests[i](line.charAt(pos))) { pos += dir; } wordEnd = pos; foundWord = wordStart != wordEnd; if (wordStart == cur.ch && lineNum == cur.line && wordEnd == wordStart + dir) { continue; } else { return { from: Math.min(wordStart, wordEnd + 1), to: Math.max(wordStart, wordEnd), line: lineNum }; } } } if (!foundWord) { pos += dir; } } lineNum += dir; if (!isLine(cm, lineNum)) { return null; } line = cm.getLine(lineNum); pos = dir > 0 ? 0 : line.length; } } function moveToWord(cm, cur, repeat, forward, wordEnd, bigWord) { var curStart = copyCursor(cur); var words = []; if (forward && !wordEnd || !forward && wordEnd) { repeat++; } var emptyLineIsWord = !(forward && wordEnd); for (var i = 0; i < repeat; i++) { var word2 = findWord(cm, cur, forward, bigWord, emptyLineIsWord); if (!word2) { var eodCh = lineLength(cm, cm.lastLine()); words.push(forward ? { line: cm.lastLine(), from: eodCh, to: eodCh } : { line: 0, from: 0, to: 0 }); break; } words.push(word2); cur = new Pos3(word2.line, forward ? word2.to - 1 : word2.from); } var shortCircuit = words.length != repeat; var firstWord = words[0]; var lastWord = words.pop(); if (forward && !wordEnd) { if (!shortCircuit && (firstWord.from != curStart.ch || firstWord.line != curStart.line)) { lastWord = words.pop(); } return lastWord && new Pos3(lastWord.line, lastWord.from); } else if (forward && wordEnd) { return lastWord && new Pos3(lastWord.line, lastWord.to - 1); } else if (!forward && wordEnd) { if (!shortCircuit && (firstWord.to != curStart.ch || firstWord.line != curStart.line)) { lastWord = words.pop(); } return lastWord && new Pos3(lastWord.line, lastWord.to); } else { return lastWord && new Pos3(lastWord.line, lastWord.from); } } function moveToEol(cm, head, motionArgs, vim2, keepHPos) { var cur = head; var retval = new Pos3(cur.line + motionArgs.repeat - 1, Infinity); var end = cm.clipPos(retval); end.ch--; if (!keepHPos) { vim2.lastHPos = Infinity; vim2.lastHSPos = cm.charCoords(end, "div").left; } return retval; } function moveToCharacter(cm, repeat, forward, character, head) { if (!character) return; var cur = head || cm.getCursor(); var start = cur.ch; var idx; for (var i = 0; i < repeat; i++) { var line = cm.getLine(cur.line); idx = charIdxInLine(start, line, character, forward, true); if (idx == -1) { return void 0; } start = idx; } if (idx != void 0) return new Pos3(cm.getCursor().line, idx); } function moveToColumn(cm, repeat) { var line = cm.getCursor().line; return clipCursorToContent(cm, new Pos3(line, repeat - 1)); } function updateMark(cm, vim2, markName, pos) { if (!inArray(markName, validMarks) && !latinCharRegex.test(markName)) { return; } if (vim2.marks[markName]) { vim2.marks[markName].clear(); } vim2.marks[markName] = cm.setBookmark(pos); } function charIdxInLine(start, line, character, forward, includeChar) { var idx; if (forward) { idx = line.indexOf(character, start + 1); if (idx != -1 && !includeChar) { idx -= 1; } } else { idx = line.lastIndexOf(character, start - 1); if (idx != -1 && !includeChar) { idx += 1; } } return idx; } function findParagraph(cm, head, repeat, dir, inclusive) { var line = head.line; var min = cm.firstLine(); var max = cm.lastLine(); var start, end, i = line; function isEmpty2(i2) { return !cm.getLine(i2); } function isBoundary(i2, dir2, any) { if (any) { return isEmpty2(i2) != isEmpty2(i2 + dir2); } return !isEmpty2(i2) && isEmpty2(i2 + dir2); } if (dir) { while (min <= i && i <= max && repeat > 0) { if (isBoundary(i, dir)) { repeat--; } i += dir; } return { start: new Pos3(i, 0), end: head }; } var vim2 = cm.state.vim; if (vim2.visualLine && isBoundary(line, 1, true)) { var anchor = vim2.sel.anchor; if (isBoundary(anchor.line, -1, true)) { if (!inclusive || anchor.line != line) { line += 1; } } } var startState = isEmpty2(line); for (i = line; i <= max && repeat; i++) { if (isBoundary(i, 1, true)) { if (!inclusive || isEmpty2(i) != startState) { repeat--; } } } end = new Pos3(i, 0); if (i > max && !startState) { startState = true; } else { inclusive = false; } for (i = line; i > min; i--) { if (!inclusive || isEmpty2(i) == startState || i == line) { if (isBoundary(i, -1, true)) { break; } } } start = new Pos3(i, 0); return { start, end }; } function getSentence(cm, cur, repeat, dir, inclusive) { function nextChar(curr) { if (curr.pos + curr.dir < 0 || curr.pos + curr.dir >= curr.line.length) { curr.line = null; } else { curr.pos += curr.dir; } } function forward(cm2, ln, pos, dir2) { var line = cm2.getLine(ln); var curr = { line, ln, pos, dir: dir2 }; if (curr.line === "") { return { ln: curr.ln, pos: curr.pos }; } var lastSentencePos = curr.pos; nextChar(curr); while (curr.line !== null) { lastSentencePos = curr.pos; if (isEndOfSentenceSymbol(curr.line[curr.pos])) { if (!inclusive) { return { ln: curr.ln, pos: curr.pos + 1 }; } else { nextChar(curr); while (curr.line !== null) { if (isWhiteSpaceString(curr.line[curr.pos])) { lastSentencePos = curr.pos; nextChar(curr); } else { break; } } return { ln: curr.ln, pos: lastSentencePos + 1 }; } } nextChar(curr); } return { ln: curr.ln, pos: lastSentencePos + 1 }; } function reverse(cm2, ln, pos, dir2) { var line = cm2.getLine(ln); var curr = { line, ln, pos, dir: dir2 }; if (curr.line === "") { return { ln: curr.ln, pos: curr.pos }; } var lastSentencePos = curr.pos; nextChar(curr); while (curr.line !== null) { if (!isWhiteSpaceString(curr.line[curr.pos]) && !isEndOfSentenceSymbol(curr.line[curr.pos])) { lastSentencePos = curr.pos; } else if (isEndOfSentenceSymbol(curr.line[curr.pos])) { if (!inclusive) { return { ln: curr.ln, pos: lastSentencePos }; } else { if (isWhiteSpaceString(curr.line[curr.pos + 1])) { return { ln: curr.ln, pos: curr.pos + 1 }; } else { return { ln: curr.ln, pos: lastSentencePos }; } } } nextChar(curr); } curr.line = line; if (inclusive && isWhiteSpaceString(curr.line[curr.pos])) { return { ln: curr.ln, pos: curr.pos }; } else { return { ln: curr.ln, pos: lastSentencePos }; } } var curr_index = { ln: cur.line, pos: cur.ch }; while (repeat > 0) { if (dir < 0) { curr_index = reverse(cm, curr_index.ln, curr_index.pos, dir); } else { curr_index = forward(cm, curr_index.ln, curr_index.pos, dir); } repeat--; } return new Pos3(curr_index.ln, curr_index.pos); } function findSentence(cm, cur, repeat, dir) { function nextChar(cm2, idx) { if (idx.pos + idx.dir < 0 || idx.pos + idx.dir >= idx.line.length) { idx.ln += idx.dir; if (!isLine(cm2, idx.ln)) { idx.line = null; idx.ln = null; idx.pos = null; return; } idx.line = cm2.getLine(idx.ln); idx.pos = idx.dir > 0 ? 0 : idx.line.length - 1; } else { idx.pos += idx.dir; } } function forward(cm2, ln, pos, dir2) { var line = cm2.getLine(ln); var stop = line === ""; var curr = { line, ln, pos, dir: dir2 }; var last_valid = { ln: curr.ln, pos: curr.pos }; var skip_empty_lines = curr.line === ""; nextChar(cm2, curr); while (curr.line !== null) { last_valid.ln = curr.ln; last_valid.pos = curr.pos; if (curr.line === "" && !skip_empty_lines) { return { ln: curr.ln, pos: curr.pos }; } else if (stop && curr.line !== "" && !isWhiteSpaceString(curr.line[curr.pos])) { return { ln: curr.ln, pos: curr.pos }; } else if (isEndOfSentenceSymbol(curr.line[curr.pos]) && !stop && (curr.pos === curr.line.length - 1 || isWhiteSpaceString(curr.line[curr.pos + 1]))) { stop = true; } nextChar(cm2, curr); } var line = cm2.getLine(last_valid.ln); last_valid.pos = 0; for (var i = line.length - 1; i >= 0; --i) { if (!isWhiteSpaceString(line[i])) { last_valid.pos = i; break; } } return last_valid; } function reverse(cm2, ln, pos, dir2) { var line = cm2.getLine(ln); var curr = { line, ln, pos, dir: dir2 }; var last_valid = { ln: curr.ln, pos: null }; var skip_empty_lines = curr.line === ""; nextChar(cm2, curr); while (curr.line !== null) { if (curr.line === "" && !skip_empty_lines) { if (last_valid.pos !== null) { return last_valid; } else { return { ln: curr.ln, pos: curr.pos }; } } else if (isEndOfSentenceSymbol(curr.line[curr.pos]) && last_valid.pos !== null && !(curr.ln === last_valid.ln && curr.pos + 1 === last_valid.pos)) { return last_valid; } else if (curr.line !== "" && !isWhiteSpaceString(curr.line[curr.pos])) { skip_empty_lines = false; last_valid = { ln: curr.ln, pos: curr.pos }; } nextChar(cm2, curr); } var line = cm2.getLine(last_valid.ln); last_valid.pos = 0; for (var i = 0; i < line.length; ++i) { if (!isWhiteSpaceString(line[i])) { last_valid.pos = i; break; } } return last_valid; } var curr_index = { ln: cur.line, pos: cur.ch }; while (repeat > 0) { if (dir < 0) { curr_index = reverse(cm, curr_index.ln, curr_index.pos, dir); } else { curr_index = forward(cm, curr_index.ln, curr_index.pos, dir); } repeat--; } return new Pos3(curr_index.ln, curr_index.pos); } function selectCompanionObject(cm, head, symb, inclusive) { var cur = head; var bracketRegexp = { "(": /[()]/, ")": /[()]/, "[": /[[\]]/, "]": /[[\]]/, "{": /[{}]/, "}": /[{}]/, "<": /[<>]/, ">": /[<>]/ }[symb]; var openSym = { "(": "(", ")": "(", "[": "[", "]": "[", "{": "{", "}": "{", "<": "<", ">": "<" }[symb]; var curChar = cm.getLine(cur.line).charAt(cur.ch); var offset = curChar === openSym ? 1 : 0; var startBracket = cm.scanForBracket(new Pos3(cur.line, cur.ch + offset), -1, void 0, { "bracketRegex": bracketRegexp }); var endBracket = cm.scanForBracket(new Pos3(cur.line, cur.ch + offset), 1, void 0, { "bracketRegex": bracketRegexp }); if (!startBracket || !endBracket) return null; var start = startBracket.pos; var end = endBracket.pos; if (start.line == end.line && start.ch > end.ch || start.line > end.line) { var tmp = start; start = end; end = tmp; } if (inclusive) { end.ch += 1; } else { start.ch += 1; } return { start, end }; } function findBeginningAndEnd(cm, head, symb, inclusive) { var cur = copyCursor(head); var line = cm.getLine(cur.line); var chars = line.split(""); var start, end, i, len; var firstIndex = chars.indexOf(symb); if (cur.ch < firstIndex) { cur.ch = firstIndex; } else if (firstIndex < cur.ch && chars[cur.ch] == symb) { var stringAfter = /string/.test(cm.getTokenTypeAt(offsetCursor(head, 0, 1))); var stringBefore = /string/.test(cm.getTokenTypeAt(head)); var isStringStart = stringAfter && !stringBefore; if (!isStringStart) { end = cur.ch; --cur.ch; } } if (chars[cur.ch] == symb && !end) { start = cur.ch + 1; } else { for (i = cur.ch; i > -1 && !start; i--) { if (chars[i] == symb) { start = i + 1; } } } if (start && !end) { for (i = start, len = chars.length; i < len && !end; i++) { if (chars[i] == symb) { end = i; } } } if (!start || !end) { return { start: cur, end: cur }; } if (inclusive) { --start; ++end; } return { start: new Pos3(cur.line, start), end: new Pos3(cur.line, end) }; } defineOption("pcre", true, "boolean"); class SearchState { getQuery() { return vimGlobalState.query; } setQuery(query) { vimGlobalState.query = query; } getOverlay() { return this.searchOverlay; } setOverlay(overlay) { this.searchOverlay = overlay; } isReversed() { return vimGlobalState.isReversed; } setReversed(reversed) { vimGlobalState.isReversed = reversed; } getScrollbarAnnotate() { return this.annotate; } setScrollbarAnnotate(annotate) { this.annotate = annotate; } } function getSearchState(cm) { var vim2 = cm.state.vim; return vim2.searchState_ || (vim2.searchState_ = new SearchState()); } function splitBySlash(argString) { return splitBySeparator(argString, "/"); } function findUnescapedSlashes(argString) { return findUnescapedSeparators(argString, "/"); } function splitBySeparator(argString, separator) { var slashes = findUnescapedSeparators(argString, separator) || []; if (!slashes.length) return []; var tokens = []; if (slashes[0] !== 0) return; for (var i = 0; i < slashes.length; i++) { if (typeof slashes[i] == "number") tokens.push(argString.substring(slashes[i] + 1, slashes[i + 1])); } return tokens; } function findUnescapedSeparators(str, separator) { if (!separator) separator = "/"; var escapeNextChar = false; var slashes = []; for (var i = 0; i < str.length; i++) { var c = str.charAt(i); if (!escapeNextChar && c == separator) { slashes.push(i); } escapeNextChar = !escapeNextChar && c == "\\"; } return slashes; } function translateRegex(str) { var specials = "|(){"; var unescape = "}"; var escapeNextChar = false; var out = []; for (var i = -1; i < str.length; i++) { var c = str.charAt(i) || ""; var n = str.charAt(i + 1) || ""; var specialComesNext = n && specials.indexOf(n) != -1; if (escapeNextChar) { if (c !== "\\" || !specialComesNext) { out.push(c); } escapeNextChar = false; } else { if (c === "\\") { escapeNextChar = true; if (n && unescape.indexOf(n) != -1) { specialComesNext = true; } if (!specialComesNext || n === "\\") { out.push(c); } } else { out.push(c); if (specialComesNext && n !== "\\") { out.push("\\"); } } } } return out.join(""); } var charUnescapes = { "\\n": "\n", "\\r": "\r", "\\t": " " }; function translateRegexReplace(str) { var escapeNextChar = false; var out = []; for (var i = -1; i < str.length; i++) { var c = str.charAt(i) || ""; var n = str.charAt(i + 1) || ""; if (charUnescapes[c + n]) { out.push(charUnescapes[c + n]); i++; } else if (escapeNextChar) { out.push(c); escapeNextChar = false; } else { if (c === "\\") { escapeNextChar = true; if (isNumber(n) || n === "$") { out.push("$"); } else if (n !== "/" && n !== "\\") { out.push("\\"); } } else { if (c === "$") { out.push("$"); } out.push(c); if (n === "/") { out.push("\\"); } } } } return out.join(""); } var unescapes = { "\\/": "/", "\\\\": "\\", "\\n": "\n", "\\r": "\r", "\\t": " ", "\\&": "&" }; function unescapeRegexReplace(str) { var stream = new CodeMirror2.StringStream(str); var output = []; while (!stream.eol()) { while (stream.peek() && stream.peek() != "\\") { output.push(stream.next()); } var matched = false; for (var matcher in unescapes) { if (stream.match(matcher, true)) { matched = true; output.push(unescapes[matcher]); break; } } if (!matched) { output.push(stream.next()); } } return output.join(""); } function parseQuery(query, ignoreCase, smartCase) { var lastSearchRegister = vimGlobalState.registerController.getRegister("/"); lastSearchRegister.setText(query); if (query instanceof RegExp) { return query; } var slashes = findUnescapedSlashes(query); var regexPart; var forceIgnoreCase; if (!slashes.length) { regexPart = query; } else { regexPart = query.substring(0, slashes[0]); var flagsPart = query.substring(slashes[0]); forceIgnoreCase = flagsPart.indexOf("i") != -1; } if (!regexPart) { return null; } if (!getOption("pcre")) { regexPart = translateRegex(regexPart); } if (smartCase) { ignoreCase = /^[^A-Z]*$/.test(regexPart); } var regexp = new RegExp( regexPart, ignoreCase || forceIgnoreCase ? "im" : "m" ); return regexp; } function dom(n) { if (typeof n === "string") n = document.createElement(n); for (var a, i = 1; i < arguments.length; i++) { if (!(a = arguments[i])) continue; if (typeof a !== "object") a = document.createTextNode(a); if (a.nodeType) n.appendChild(a); else for (var key in a) { if (!Object.prototype.hasOwnProperty.call(a, key)) continue; if (key[0] === "$") n.style[key.slice(1)] = a[key]; else n.setAttribute(key, a[key]); } } return n; } function showConfirm(cm, template) { var pre = dom("div", { $color: "red", $whiteSpace: "pre", class: "cm-vim-message" }, template); if (cm.openNotification) { cm.openNotification(pre, { bottom: true, duration: 5e3 }); } else { alert(pre.innerText); } } function makePrompt(prefix, desc) { return dom( "div", { $display: "flex" }, dom( "span", { $fontFamily: "monospace", $whiteSpace: "pre", $flex: 1 }, prefix, dom("input", { type: "text", autocorrect: "off", autocapitalize: "off", spellcheck: "false", $width: "100%" }) ), desc && dom("span", { $color: "#888" }, desc) ); } function showPrompt(cm, options2) { if (keyToKeyStack.length) { if (!options2.value) options2.value = ""; virtualPrompt = options2; return; } var template = makePrompt(options2.prefix, options2.desc); if (cm.openDialog) { cm.openDialog(template, options2.onClose, { onKeyDown: options2.onKeyDown, onKeyUp: options2.onKeyUp, bottom: true, selectValueOnOpen: false, value: options2.value }); } else { var shortText = ""; if (typeof options2.prefix != "string" && options2.prefix) shortText += options2.prefix.textContent; if (options2.desc) shortText += " " + options2.desc; options2.onClose(prompt(shortText, "")); } } function regexEqual(r1, r2) { if (r1 instanceof RegExp && r2 instanceof RegExp) { var props = ["global", "multiline", "ignoreCase", "source"]; for (var i = 0; i < props.length; i++) { var prop = props[i]; if (r1[prop] !== r2[prop]) { return false; } } return true; } return false; } function updateSearchQuery(cm, rawQuery, ignoreCase, smartCase) { if (!rawQuery) { return; } var state = getSearchState(cm); var query = parseQuery(rawQuery, !!ignoreCase, !!smartCase); if (!query) { return; } highlightSearchMatches(cm, query); if (regexEqual(query, state.getQuery())) { return query; } state.setQuery(query); return query; } function searchOverlay(query) { if (query.source.charAt(0) == "^") { var matchSol = true; } return { token: function(stream) { if (matchSol && !stream.sol()) { stream.skipToEnd(); return; } var match = stream.match(query, false); if (match) { if (match[0].length == 0) { stream.next(); return "searching"; } if (!stream.sol()) { stream.backUp(1); if (!query.exec(stream.next() + match[0])) { stream.next(); return null; } } stream.match(query); return "searching"; } while (!stream.eol()) { stream.next(); if (stream.match(query, false)) break; } }, query }; } var highlightTimeout = 0; function highlightSearchMatches(cm, query) { clearTimeout(highlightTimeout); var searchState = getSearchState(cm); searchState.highlightTimeout = highlightTimeout; highlightTimeout = setTimeout(function() { if (!cm.state.vim) return; var searchState2 = getSearchState(cm); searchState2.highlightTimeout = null; var overlay = searchState2.getOverlay(); if (!overlay || query != overlay.query) { if (overlay) { cm.removeOverlay(overlay); } overlay = searchOverlay(query); cm.addOverlay(overlay); if (cm.showMatchesOnScrollbar) { if (searchState2.getScrollbarAnnotate()) { searchState2.getScrollbarAnnotate().clear(); } searchState2.setScrollbarAnnotate(cm.showMatchesOnScrollbar(query)); } searchState2.setOverlay(overlay); } }, 50); } function findNext(cm, prev, query, repeat) { return cm.operation(function() { if (repeat === void 0) { repeat = 1; } var pos = cm.getCursor(); var cursor = cm.getSearchCursor(query, pos); for (var i = 0; i < repeat; i++) { var found = cursor.find(prev); if (i == 0 && found && cursorEqual(cursor.from(), pos)) { var lastEndPos = prev ? cursor.from() : cursor.to(); found = cursor.find(prev); if (found && !found[0] && cursorEqual(cursor.from(), lastEndPos)) { if (cm.getLine(lastEndPos.line).length == lastEndPos.ch) found = cursor.find(prev); } } if (!found) { cursor = cm.getSearchCursor( query, // @ts-ignore prev ? new Pos3(cm.lastLine()) : new Pos3(cm.firstLine(), 0) ); if (!cursor.find(prev)) { return; } } } return cursor.from(); }); } function findNextFromAndToInclusive(cm, prev, query, repeat, vim2) { return cm.operation(function() { if (repeat === void 0) { repeat = 1; } var pos = cm.getCursor(); var cursor = cm.getSearchCursor(query, pos); var found = cursor.find(!prev); if (!vim2.visualMode && found && cursorEqual(cursor.from(), pos)) { cursor.find(!prev); } for (var i = 0; i < repeat; i++) { found = cursor.find(prev); if (!found) { cursor = cm.getSearchCursor( query, // @ts-ignore prev ? new Pos3(cm.lastLine()) : new Pos3(cm.firstLine(), 0) ); if (!cursor.find(prev)) { return; } } } return [cursor.from(), cursor.to()]; }); } function clearSearchHighlight(cm) { var state = getSearchState(cm); if (state.highlightTimeout) { clearTimeout(state.highlightTimeout); state.highlightTimeout = null; } cm.removeOverlay(getSearchState(cm).getOverlay()); state.setOverlay(null); if (state.getScrollbarAnnotate()) { state.getScrollbarAnnotate().clear(); state.setScrollbarAnnotate(null); } } function isInRange(pos, start, end) { if (typeof pos != "number") { pos = pos.line; } if (start instanceof Array) { return inArray(pos, start); } else { if (typeof end == "number") { return pos >= start && pos <= end; } else { return pos == start; } } } function getUserVisibleLines(cm) { var scrollInfo = cm.getScrollInfo(); var occludeToleranceTop = 6; var occludeToleranceBottom = 10; var from = cm.coordsChar({ left: 0, top: occludeToleranceTop + scrollInfo.top }, "local"); var bottomY = scrollInfo.clientHeight - occludeToleranceBottom + scrollInfo.top; var to = cm.coordsChar({ left: 0, top: bottomY }, "local"); return { top: from.line, bottom: to.line }; } function getMarkPos(cm, vim2, markName) { if (markName == "'" || markName == "`") { return vimGlobalState.jumpList.find(cm, -1) || new Pos3(0, 0); } else if (markName == ".") { return getLastEditPos(cm); } var mark = vim2.marks[markName]; return mark && mark.find(); } function getLastEditPos(cm) { if (cm.getLastEditEnd) { return cm.getLastEditEnd(); } var done = ( /**@type{any}*/ cm.doc.history.done ); for (var i = done.length; i--; ) { if (done[i].changes) { return copyCursor(done[i].changes[0].to); } } } class ExCommandDispatcher { constructor() { this.commandMap_; this.buildCommandMap_(); } processCommand(cm, input, opt_params) { var that = this; cm.operation(function() { cm.curOp.isVimOp = true; that._processCommand(cm, input, opt_params); }); } _processCommand(cm, input, opt_params) { var vim2 = cm.state.vim; var commandHistoryRegister = vimGlobalState.registerController.getRegister(":"); var previousCommand = commandHistoryRegister.toString(); var inputStream = new CodeMirror2.StringStream(input); commandHistoryRegister.setText(input); var params = opt_params || {}; params.input = input; try { this.parseInput_(cm, inputStream, params); } catch (e) { showConfirm(cm, e + ""); throw e; } if (vim2.visualMode) { exitVisualMode(cm); } var command; var commandName; if (!params.commandName) { if (params.line !== void 0) { commandName = "move"; } } else { command = this.matchCommand_(params.commandName); if (command) { commandName = command.name; if (command.excludeFromCommandHistory) { commandHistoryRegister.setText(previousCommand); } this.parseCommandArgs_(inputStream, params, command); if (command.type == "exToKey") { doKeyToKey(cm, command.toKeys, command); return; } else if (command.type == "exToEx") { this.processCommand(cm, command.toInput); return; } } } if (!commandName) { showConfirm(cm, 'Not an editor command ":' + input + '"'); return; } try { exCommands[commandName](cm, params); if ((!command || !command.possiblyAsync) && params.callback) { params.callback(); } } catch (e) { showConfirm(cm, e + ""); throw e; } } parseInput_(cm, inputStream, result) { var _a, _b; inputStream.eatWhile(":"); if (inputStream.eat("%")) { result.line = cm.firstLine(); result.lineEnd = cm.lastLine(); } else { result.line = this.parseLineSpec_(cm, inputStream); if (result.line !== void 0 && inputStream.eat(",")) { result.lineEnd = this.parseLineSpec_(cm, inputStream); } } if (result.line == void 0) { if (cm.state.vim.visualMode) { result.selectionLine = (_a = getMarkPos(cm, cm.state.vim, "<")) == null ? void 0 : _a.line; result.selectionLineEnd = (_b = getMarkPos(cm, cm.state.vim, ">")) == null ? void 0 : _b.line; } else { result.selectionLine = cm.getCursor().line; } } else { result.selectionLine = result.line; result.selectionLineEnd = result.lineEnd; } var commandMatch2 = inputStream.match(/^(\w+|!!|@@|[!#&*<=>@~])/); if (commandMatch2) { result.commandName = commandMatch2[1]; } else { result.commandName = inputStream.match(/.*/)[0]; } return result; } parseLineSpec_(cm, inputStream) { var numberMatch = inputStream.match(/^(\d+)/); if (numberMatch) { return parseInt(numberMatch[1], 10) - 1; } switch (inputStream.next()) { case ".": return this.parseLineSpecOffset_(inputStream, cm.getCursor().line); case "$": return this.parseLineSpecOffset_(inputStream, cm.lastLine()); case "'": var markName = inputStream.next(); var markPos = getMarkPos(cm, cm.state.vim, markName); if (!markPos) throw new Error("Mark not set"); return this.parseLineSpecOffset_(inputStream, markPos.line); case "-": case "+": inputStream.backUp(1); return this.parseLineSpecOffset_(inputStream, cm.getCursor().line); default: inputStream.backUp(1); return void 0; } } parseLineSpecOffset_(inputStream, line) { var offsetMatch = inputStream.match(/^([+-])?(\d+)/); if (offsetMatch) { var offset = parseInt(offsetMatch[2], 10); if (offsetMatch[1] == "-") { line -= offset; } else { line += offset; } } return line; } parseCommandArgs_(inputStream, params, command) { if (inputStream.eol()) { return; } params.argString = inputStream.match(/.*/)[0]; var delim = command.argDelimiter || /\s+/; var args = trim(params.argString).split(delim); if (args.length && args[0]) { params.args = args; } } matchCommand_(commandName) { for (var i = commandName.length; i > 0; i--) { var prefix = commandName.substring(0, i); if (this.commandMap_[prefix]) { var command = this.commandMap_[prefix]; if (command.name.indexOf(commandName) === 0) { return command; } } } return null; } buildCommandMap_() { this.commandMap_ = {}; for (var i = 0; i < defaultExCommandMap.length; i++) { var command = defaultExCommandMap[i]; var key = command.shortName || command.name; this.commandMap_[key] = command; } } /**@type {(lhs: string, rhs: string, ctx: string, noremap?: boolean) => void} */ map(lhs, rhs, ctx, noremap2) { if (lhs != ":" && lhs.charAt(0) == ":") { if (ctx) { throw Error("Mode not supported for ex mappings"); } var commandName = lhs.substring(1); if (rhs != ":" && rhs.charAt(0) == ":") { this.commandMap_[commandName] = { name: commandName, type: "exToEx", toInput: rhs.substring(1), user: true }; } else { this.commandMap_[commandName] = { name: commandName, type: "exToKey", toKeys: rhs, user: true }; } } else { var mapping = { keys: lhs, type: "keyToKey", toKeys: rhs, noremap: !!noremap2 }; if (ctx) { mapping.context = ctx; } defaultKeymap2.unshift(mapping); } } /**@type {(lhs: string, ctx: string) => boolean|void} */ unmap(lhs, ctx) { if (lhs != ":" && lhs.charAt(0) == ":") { if (ctx) { throw Error("Mode not supported for ex mappings"); } var commandName = lhs.substring(1); if (this.commandMap_[commandName] && this.commandMap_[commandName].user) { delete this.commandMap_[commandName]; return true; } } else { var keys2 = lhs; for (var i = 0; i < defaultKeymap2.length; i++) { if (keys2 == defaultKeymap2[i].keys && defaultKeymap2[i].context === ctx) { defaultKeymap2.splice(i, 1); return true; } } } } } var exCommands = { /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ colorscheme: function(cm, params) { if (!params.args || params.args.length < 1) { showConfirm(cm, cm.getOption("theme")); return; } cm.setOption("theme", params.args[0]); }, map: function(cm, params, ctx, defaultOnly) { var mapArgs = params.args; if (!mapArgs || mapArgs.length < 2) { if (cm) { showConfirm(cm, "Invalid mapping: " + params.input); } return; } exCommandDispatcher.map(mapArgs[0], mapArgs[1], ctx, defaultOnly); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ imap: function(cm, params) { this.map(cm, params, "insert"); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ nmap: function(cm, params) { this.map(cm, params, "normal"); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ vmap: function(cm, params) { this.map(cm, params, "visual"); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ omap: function(cm, params) { this.map(cm, params, "operatorPending"); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ noremap: function(cm, params) { this.map(cm, params, void 0, true); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ inoremap: function(cm, params) { this.map(cm, params, "insert", true); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ nnoremap: function(cm, params) { this.map(cm, params, "normal", true); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ vnoremap: function(cm, params) { this.map(cm, params, "visual", true); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ onoremap: function(cm, params) { this.map(cm, params, "operatorPending", true); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params @arg {string} ctx*/ unmap: function(cm, params, ctx) { var mapArgs = params.args; if (!mapArgs || mapArgs.length < 1 || !exCommandDispatcher.unmap(mapArgs[0], ctx)) { if (cm) { showConfirm(cm, "No such mapping: " + params.input); } } }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ mapclear: function(cm, params) { vimApi.mapclear(); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ imapclear: function(cm, params) { vimApi.mapclear("insert"); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ nmapclear: function(cm, params) { vimApi.mapclear("normal"); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ vmapclear: function(cm, params) { vimApi.mapclear("visual"); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ omapclear: function(cm, params) { vimApi.mapclear("operatorPending"); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ move: function(cm, params) { commandDispatcher.processCommand(cm, cm.state.vim, { keys: "", type: "motion", motion: "moveToLineOrEdgeOfDocument", motionArgs: { forward: false, explicitRepeat: true, linewise: true }, repeatOverride: params.line + 1 }); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ set: function(cm, params) { var setArgs = params.args; var setCfg = params.setCfg || {}; if (!setArgs || setArgs.length < 1) { if (cm) { showConfirm(cm, "Invalid mapping: " + params.input); } return; } var expr = setArgs[0].split("="); var optionName = expr.shift() || ""; var value = expr.length > 0 ? expr.join("=") : void 0; var forceGet = false; var forceToggle = false; if (optionName.charAt(optionName.length - 1) == "?") { if (value) { throw Error("Trailing characters: " + params.argString); } optionName = optionName.substring(0, optionName.length - 1); forceGet = true; } else if (optionName.charAt(optionName.length - 1) == "!") { optionName = optionName.substring(0, optionName.length - 1); forceToggle = true; } if (value === void 0 && optionName.substring(0, 2) == "no") { optionName = optionName.substring(2); value = false; } var optionIsBoolean = options[optionName] && options[optionName].type == "boolean"; if (optionIsBoolean) { if (forceToggle) { value = !getOption(optionName, cm, setCfg); } else if (value == void 0) { value = true; } } if (!optionIsBoolean && value === void 0 || forceGet) { var oldValue = getOption(optionName, cm, setCfg); if (oldValue instanceof Error) { showConfirm(cm, oldValue.message); } else if (oldValue === true || oldValue === false) { showConfirm(cm, " " + (oldValue ? "" : "no") + optionName); } else { showConfirm(cm, " " + optionName + "=" + oldValue); } } else { var setOptionReturn = setOption(optionName, value, cm, setCfg); if (setOptionReturn instanceof Error) { showConfirm(cm, setOptionReturn.message); } } }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ setlocal: function(cm, params) { params.setCfg = { scope: "local" }; this.set(cm, params); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ setglobal: function(cm, params) { params.setCfg = { scope: "global" }; this.set(cm, params); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ registers: function(cm, params) { var regArgs = params.args; var registers = vimGlobalState.registerController.registers; var regInfo = "----------Registers----------\n\n"; if (!regArgs) { for (var registerName in registers) { var text = registers[registerName].toString(); if (text.length) { regInfo += '"' + registerName + " " + text + "\n"; } } } else { var registerNames = regArgs.join(""); for (var i = 0; i < registerNames.length; i++) { var registerName = registerNames.charAt(i); if (!vimGlobalState.registerController.isValidRegister(registerName)) { continue; } var register = registers[registerName] || new Register(); regInfo += '"' + registerName + " " + register.toString() + "\n"; } } showConfirm(cm, regInfo); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ sort: function(cm, params) { var reverse, ignoreCase, unique, number, pattern; function parseArgs2() { if (params.argString) { var args = new CodeMirror2.StringStream(params.argString); if (args.eat("!")) { reverse = true; } if (args.eol()) { return; } if (!args.eatSpace()) { return "Invalid arguments"; } var opts = args.match(/([dinuox]+)?\s*(\/.+\/)?\s*/); if (!opts || !args.eol()) { return "Invalid arguments"; } if (opts[1]) { ignoreCase = opts[1].indexOf("i") != -1; unique = opts[1].indexOf("u") != -1; var decimal = opts[1].indexOf("d") != -1 || opts[1].indexOf("n") != -1; var hex = opts[1].indexOf("x") != -1; var octal = opts[1].indexOf("o") != -1; if (Number(decimal) + Number(hex) + Number(octal) > 1) { return "Invalid arguments"; } number = decimal && "decimal" || hex && "hex" || octal && "octal"; } if (opts[2]) { pattern = new RegExp(opts[2].substr(1, opts[2].length - 2), ignoreCase ? "i" : ""); } } } var err = parseArgs2(); if (err) { showConfirm(cm, err + ": " + params.argString); return; } var lineStart = params.line || cm.firstLine(); var lineEnd = params.lineEnd || params.line || cm.lastLine(); if (lineStart == lineEnd) { return; } var curStart = new Pos3(lineStart, 0); var curEnd = new Pos3(lineEnd, lineLength(cm, lineEnd)); var text = cm.getRange(curStart, curEnd).split("\n"); var numberRegex2 = number == "decimal" ? /(-?)([\d]+)/ : number == "hex" ? /(-?)(?:0x)?([0-9a-f]+)/i : number == "octal" ? /([0-7]+)/ : null; var radix = number == "decimal" ? 10 : number == "hex" ? 16 : number == "octal" ? 8 : void 0; var numPart = [], textPart = []; if (number || pattern) { for (var i = 0; i < text.length; i++) { var matchPart = pattern ? text[i].match(pattern) : null; if (matchPart && matchPart[0] != "") { numPart.push(matchPart); } else if (numberRegex2 && numberRegex2.exec(text[i])) { numPart.push(text[i]); } else { textPart.push(text[i]); } } } else { textPart = text; } function compareFn(a, b) { if (reverse) { var tmp; tmp = a; a = b; b = tmp; } if (ignoreCase) { a = a.toLowerCase(); b = b.toLowerCase(); } var amatch = numberRegex2 && numberRegex2.exec(a); var bmatch = numberRegex2 && numberRegex2.exec(b); if (!amatch || !bmatch) { return a < b ? -1 : 1; } var anum = parseInt((amatch[1] + amatch[2]).toLowerCase(), radix); var bnum = parseInt((bmatch[1] + bmatch[2]).toLowerCase(), radix); return anum - bnum; } function comparePatternFn(a, b) { if (reverse) { var tmp; tmp = a; a = b; b = tmp; } if (ignoreCase) { a[0] = a[0].toLowerCase(); b[0] = b[0].toLowerCase(); } return a[0] < b[0] ? -1 : 1; } numPart.sort(pattern ? comparePatternFn : compareFn); if (pattern) { for (var i = 0; i < numPart.length; i++) { numPart[i] = numPart[i].input; } } else if (!number) { textPart.sort(compareFn); } text = !reverse ? textPart.concat(numPart) : numPart.concat(textPart); if (unique) { var textOld = text; var lastLine; text = []; for (var i = 0; i < textOld.length; i++) { if (textOld[i] != lastLine) { text.push(textOld[i]); } lastLine = textOld[i]; } } cm.replaceRange(text.join("\n"), curStart, curEnd); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ vglobal: function(cm, params) { this.global(cm, params); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ normal: function(cm, params) { var argString = params.argString; if (argString && argString[0] == "!") { argString = argString.slice(1); noremap = true; } argString = argString.trimStart(); if (!argString) { showConfirm(cm, "Argument is required."); return; } var line = params.line; if (typeof line == "number") { var lineEnd = isNaN(params.lineEnd) ? line : params.lineEnd; for (var i = line; i <= lineEnd; i++) { cm.setCursor(i, 0); doKeyToKey(cm, params.argString.trimStart()); if (cm.state.vim.insertMode) { exitInsertMode(cm, true); } } } else { doKeyToKey(cm, params.argString.trimStart()); if (cm.state.vim.insertMode) { exitInsertMode(cm, true); } } }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ global: function(cm, params) { var argString = params.argString; if (!argString) { showConfirm(cm, "Regular Expression missing from global"); return; } var inverted = params.commandName[0] === "v"; if (argString[0] === "!" && params.commandName[0] === "g") { inverted = true; argString = argString.slice(1); } var lineStart = params.line !== void 0 ? params.line : cm.firstLine(); var lineEnd = params.lineEnd || params.line || cm.lastLine(); var tokens = splitBySlash(argString); var regexPart = argString, cmd = ""; if (tokens && tokens.length) { regexPart = tokens[0]; cmd = tokens.slice(1, tokens.length).join("/"); } if (regexPart) { try { updateSearchQuery( cm, regexPart, true, true /** smartCase */ ); } catch (e) { showConfirm(cm, "Invalid regex: " + regexPart); return; } } var query = getSearchState(cm).getQuery(); var matchedLines = []; for (var i = lineStart; i <= lineEnd; i++) { var line = cm.getLine(i); var matched = query.test(line); if (matched !== inverted) { matchedLines.push(cmd ? cm.getLineHandle(i) : line); } } if (!cmd) { showConfirm(cm, matchedLines.join("\n")); return; } var index = 0; var nextCommand = function() { if (index < matchedLines.length) { var lineHandle = matchedLines[index++]; var lineNum = cm.getLineNumber(lineHandle); if (lineNum == null) { nextCommand(); return; } var command = lineNum + 1 + cmd; exCommandDispatcher.processCommand(cm, command, { callback: nextCommand }); } else if (cm.releaseLineHandles) { cm.releaseLineHandles(); } }; nextCommand(); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ substitute: function(cm, params) { if (!cm.getSearchCursor) { throw new Error("Search feature not available. Requires searchcursor.js or any other getSearchCursor implementation."); } var argString = params.argString; var tokens = argString ? splitBySeparator(argString, argString[0]) : []; var regexPart = "", replacePart = "", trailing, flagsPart, count; var confirm = false; var global = false; if (tokens && tokens.length) { regexPart = tokens[0]; if (getOption("pcre") && regexPart !== "") { regexPart = new RegExp(regexPart).source; } replacePart = tokens[1]; if (replacePart !== void 0) { if (getOption("pcre")) { replacePart = unescapeRegexReplace(replacePart.replace(/([^\\])&/g, "$1$$&")); } else { replacePart = translateRegexReplace(replacePart); } vimGlobalState.lastSubstituteReplacePart = replacePart; } trailing = tokens[2] ? tokens[2].split(" ") : []; } else { if (argString && argString.length) { showConfirm(cm, "Substitutions should be of the form :s/pattern/replace/"); return; } } if (trailing) { flagsPart = trailing[0]; count = parseInt(trailing[1]); if (flagsPart) { if (flagsPart.indexOf("c") != -1) { confirm = true; } if (flagsPart.indexOf("g") != -1) { global = true; } if (getOption("pcre")) { regexPart = regexPart + "/" + flagsPart; } else { regexPart = regexPart.replace(/\//g, "\\/") + "/" + flagsPart; } } } if (regexPart) { try { updateSearchQuery( cm, regexPart, true, true /** smartCase */ ); } catch (e) { showConfirm(cm, "Invalid regex: " + regexPart); return; } } replacePart = replacePart || vimGlobalState.lastSubstituteReplacePart; if (replacePart === void 0) { showConfirm(cm, "No previous substitute regular expression"); return; } var state = getSearchState(cm); var query = state.getQuery(); var lineStart = params.line !== void 0 ? params.line : cm.getCursor().line; var lineEnd = params.lineEnd || lineStart; if (lineStart == cm.firstLine() && lineEnd == cm.lastLine()) { lineEnd = Infinity; } if (count) { lineStart = lineEnd; lineEnd = lineStart + count - 1; } var startPos = clipCursorToContent(cm, new Pos3(lineStart, 0)); var cursor = cm.getSearchCursor(query, startPos); doReplace(cm, confirm, global, lineStart, lineEnd, cursor, query, replacePart, params.callback); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ startinsert: function(cm, params) { doKeyToKey(cm, params.argString == "!" ? "A" : "i", {}); }, redo: CodeMirror2.commands.redo, undo: CodeMirror2.commands.undo, /** @arg {CodeMirrorV} cm */ write: function(cm) { if (CodeMirror2.commands.save) { CodeMirror2.commands.save(cm); } else if (cm.save) { cm.save(); } }, /** @arg {CodeMirrorV} cm */ nohlsearch: function(cm) { clearSearchHighlight(cm); }, /** @arg {CodeMirrorV} cm */ yank: function(cm) { var cur = copyCursor(cm.getCursor()); var line = cur.line; var lineText = cm.getLine(line); vimGlobalState.registerController.pushText( "0", "yank", lineText, true, true ); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ delete: function(cm, params) { var line = params.selectionLine; var lineEnd = isNaN(params.selectionLineEnd) ? line : params.selectionLineEnd; operators.delete(cm, { linewise: true }, [ { anchor: new Pos3(line, 0), head: new Pos3(lineEnd + 1, 0) } ]); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ join: function(cm, params) { var line = params.selectionLine; var lineEnd = isNaN(params.selectionLineEnd) ? line : params.selectionLineEnd; cm.setCursor(new Pos3(line, 0)); actions.joinLines(cm, { repeat: lineEnd - line }, cm.state.vim); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ delmarks: function(cm, params) { if (!params.argString || !trim(params.argString)) { showConfirm(cm, "Argument required"); return; } var state = cm.state.vim; var stream = new CodeMirror2.StringStream(trim(params.argString)); while (!stream.eol()) { stream.eatSpace(); var count = stream.pos; if (!stream.match(/[a-zA-Z]/, false)) { showConfirm(cm, "Invalid argument: " + params.argString.substring(count)); return; } var sym = stream.next(); if (stream.match("-", true)) { if (!stream.match(/[a-zA-Z]/, false)) { showConfirm(cm, "Invalid argument: " + params.argString.substring(count)); return; } var startMark = sym; var finishMark = stream.next(); if (startMark && finishMark && isLowerCase(startMark) == isLowerCase(finishMark)) { var start = startMark.charCodeAt(0); var finish = finishMark.charCodeAt(0); if (start >= finish) { showConfirm(cm, "Invalid argument: " + params.argString.substring(count)); return; } for (var j = 0; j <= finish - start; j++) { var mark = String.fromCharCode(start + j); delete state.marks[mark]; } } else { showConfirm(cm, "Invalid argument: " + startMark + "-"); return; } } else if (sym) { delete state.marks[sym]; } } } }; var exCommandDispatcher = new ExCommandDispatcher(); function doReplace(cm, confirm, global, lineStart, lineEnd, searchCursor, query, replaceWith, callback) { cm.state.vim.exMode = true; var done = false; var lastPos; var modifiedLineNumber; var joined; function replaceAll() { cm.operation(function() { while (!done) { replace(); next(); } stop(); }); } function replace() { var text = cm.getRange(searchCursor.from(), searchCursor.to()); var newText = text.replace(query, replaceWith); var unmodifiedLineNumber = searchCursor.to().line; searchCursor.replace(newText); modifiedLineNumber = searchCursor.to().line; lineEnd += modifiedLineNumber - unmodifiedLineNumber; joined = modifiedLineNumber < unmodifiedLineNumber; } function findNextValidMatch() { var lastMatchTo = lastPos && copyCursor(searchCursor.to()); var match = searchCursor.findNext(); if (match && !match[0] && lastMatchTo && cursorEqual(searchCursor.from(), lastMatchTo)) { match = searchCursor.findNext(); } return match; } function next() { while (findNextValidMatch() && isInRange(searchCursor.from(), lineStart, lineEnd)) { if (!global && searchCursor.from().line == modifiedLineNumber && !joined) { continue; } cm.scrollIntoView(searchCursor.from(), 30); cm.setSelection(searchCursor.from(), searchCursor.to()); lastPos = searchCursor.from(); done = false; return; } done = true; } function stop(close) { if (close) { close(); } cm.focus(); if (lastPos) { cm.setCursor(lastPos); var vim2 = cm.state.vim; vim2.exMode = false; vim2.lastHPos = vim2.lastHSPos = lastPos.ch; } if (callback) { callback(); } } function onPromptKeyDown(e, _value, close) { CodeMirror2.e_stop(e); var keyName = vimKeyFromEvent(e); switch (keyName) { case "y": replace(); next(); break; case "n": next(); break; case "a": var savedCallback = callback; callback = void 0; cm.operation(replaceAll); callback = savedCallback; break; case "l": replace(); case "q": case "": case "": case "": stop(close); break; } if (done) { stop(close); } return true; } next(); if (done) { showConfirm(cm, "No matches for " + query.source); return; } if (!confirm) { replaceAll(); if (callback) { callback(); } return; } showPrompt(cm, { prefix: dom("span", "replace with ", dom("strong", replaceWith), " (y/n/a/q/l)"), onKeyDown: onPromptKeyDown }); } function exitInsertMode(cm, keepCursor) { var vim2 = cm.state.vim; var macroModeState = vimGlobalState.macroModeState; var insertModeChangeRegister = vimGlobalState.registerController.getRegister("."); var isPlaying = macroModeState.isPlaying; var lastChange = macroModeState.lastInsertModeChanges; if (!isPlaying) { cm.off("change", onChange); if (vim2.insertEnd) vim2.insertEnd.clear(); vim2.insertEnd = void 0; CodeMirror2.off(cm.getInputField(), "keydown", onKeyEventTargetKeyDown); } if (!isPlaying && vim2.insertModeRepeat > 1) { repeatLastEdit( cm, vim2, vim2.insertModeRepeat - 1, true /** repeatForInsert */ ); vim2.lastEditInputState.repeatOverride = vim2.insertModeRepeat; } delete vim2.insertModeRepeat; vim2.insertMode = false; if (!keepCursor) { cm.setCursor(cm.getCursor().line, cm.getCursor().ch - 1); } cm.setOption("keyMap", "vim"); cm.setOption("disableInput", true); cm.toggleOverwrite(false); insertModeChangeRegister.setText(lastChange.changes.join("")); CodeMirror2.signal(cm, "vim-mode-change", { mode: "normal" }); if (macroModeState.isRecording) { logInsertModeChange(macroModeState); } } function _mapCommand(command) { defaultKeymap2.unshift(command); } function mapCommand(keys2, type, name, args, extra) { var command = { keys: keys2, type }; command[type] = name; command[type + "Args"] = args; for (var key in extra) command[key] = extra[key]; _mapCommand(command); } defineOption("insertModeEscKeysTimeout", 200, "number"); function executeMacroRegister(cm, vim2, macroModeState, registerName) { var register = vimGlobalState.registerController.getRegister(registerName); if (registerName == ":") { if (register.keyBuffer[0]) { exCommandDispatcher.processCommand(cm, register.keyBuffer[0]); } macroModeState.isPlaying = false; return; } var keyBuffer = register.keyBuffer; var imc = 0; macroModeState.isPlaying = true; macroModeState.replaySearchQueries = register.searchQueries.slice(0); for (var i = 0; i < keyBuffer.length; i++) { var text = keyBuffer[i]; var match, key; var keyRe = /<(?:[CSMA]-)*\w+>|./gi; while (match = keyRe.exec(text)) { key = match[0]; vimApi.handleKey(cm, key, "macro"); if (vim2.insertMode) { var changes = register.insertModeChanges[imc++].changes; vimGlobalState.macroModeState.lastInsertModeChanges.changes = changes; repeatInsertModeChanges(cm, changes, 1); exitInsertMode(cm); } } } macroModeState.isPlaying = false; } function logKey(macroModeState, key) { if (macroModeState.isPlaying) { return; } var registerName = macroModeState.latestRegister; var register = vimGlobalState.registerController.getRegister(registerName); if (register) { register.pushText(key); } } function logInsertModeChange(macroModeState) { if (macroModeState.isPlaying) { return; } var registerName = macroModeState.latestRegister; var register = vimGlobalState.registerController.getRegister(registerName); if (register && register.pushInsertModeChanges) { register.pushInsertModeChanges(macroModeState.lastInsertModeChanges); } } function logSearchQuery(macroModeState, query) { if (macroModeState.isPlaying) { return; } var registerName = macroModeState.latestRegister; var register = vimGlobalState.registerController.getRegister(registerName); if (register && register.pushSearchQuery) { register.pushSearchQuery(query); } } function onChange(cm, changeObj) { var macroModeState = vimGlobalState.macroModeState; var lastChange = macroModeState.lastInsertModeChanges; if (!macroModeState.isPlaying) { var vim2 = cm.state.vim; while (changeObj) { lastChange.expectCursorActivityForChange = true; if (lastChange.ignoreCount > 1) { lastChange.ignoreCount--; } else if (changeObj.origin == "+input" || changeObj.origin == "paste" || changeObj.origin === void 0) { var selectionCount = cm.listSelections().length; if (selectionCount > 1) lastChange.ignoreCount = selectionCount; var text = changeObj.text.join("\n"); if (lastChange.maybeReset) { lastChange.changes = []; lastChange.maybeReset = false; } if (text) { if (cm.state.overwrite && !/\n/.test(text)) { lastChange.changes.push([text]); } else { if (text.length > 1) { var insertEnd = vim2 && vim2.insertEnd && vim2.insertEnd.find(); var cursor = cm.getCursor(); if (insertEnd && insertEnd.line == cursor.line) { var offset = insertEnd.ch - cursor.ch; if (offset > 0 && offset < text.length) { lastChange.changes.push([text, offset]); text = ""; } } } if (text) lastChange.changes.push(text); } } } changeObj = changeObj.next; } } } function onCursorActivity(cm) { var _a; var vim2 = cm.state.vim; if (vim2.insertMode) { var macroModeState = vimGlobalState.macroModeState; if (macroModeState.isPlaying) { return; } var lastChange = macroModeState.lastInsertModeChanges; if (lastChange.expectCursorActivityForChange) { lastChange.expectCursorActivityForChange = false; } else { lastChange.maybeReset = true; if (vim2.insertEnd) vim2.insertEnd.clear(); vim2.insertEnd = cm.setBookmark(cm.getCursor(), { insertLeft: true }); } } else if (!((_a = cm.curOp) == null ? void 0 : _a.isVimOp)) { handleExternalSelection(cm, vim2); } } function handleExternalSelection(cm, vim2) { var anchor = cm.getCursor("anchor"); var head = cm.getCursor("head"); if (vim2.visualMode && !cm.somethingSelected()) { exitVisualMode(cm, false); } else if (!vim2.visualMode && !vim2.insertMode && cm.somethingSelected()) { vim2.visualMode = true; vim2.visualLine = false; CodeMirror2.signal(cm, "vim-mode-change", { mode: "visual" }); } if (vim2.visualMode) { var headOffset = !cursorIsBefore(head, anchor) ? -1 : 0; var anchorOffset = cursorIsBefore(head, anchor) ? -1 : 0; head = offsetCursor(head, 0, headOffset); anchor = offsetCursor(anchor, 0, anchorOffset); vim2.sel = { anchor, head }; updateMark(cm, vim2, "<", cursorMin(head, anchor)); updateMark(cm, vim2, ">", cursorMax(head, anchor)); } else if (!vim2.insertMode) { vim2.lastHPos = cm.getCursor().ch; } } function InsertModeKey(keyName, e) { this.keyName = keyName; this.key = e.key; this.ctrlKey = e.ctrlKey; this.altKey = e.altKey; this.metaKey = e.metaKey; this.shiftKey = e.shiftKey; } function onKeyEventTargetKeyDown(e) { var macroModeState = vimGlobalState.macroModeState; var lastChange = macroModeState.lastInsertModeChanges; var keyName = CodeMirror2.keyName ? CodeMirror2.keyName(e) : e.key; if (!keyName) { return; } if (keyName.indexOf("Delete") != -1 || keyName.indexOf("Backspace") != -1) { if (lastChange.maybeReset) { lastChange.changes = []; lastChange.maybeReset = false; } lastChange.changes.push(new InsertModeKey(keyName, e)); } } function repeatLastEdit(cm, vim2, repeat, repeatForInsert) { var macroModeState = vimGlobalState.macroModeState; macroModeState.isPlaying = true; var lastAction = vim2.lastEditActionCommand; var cachedInputState = vim2.inputState; function repeatCommand() { if (lastAction) { commandDispatcher.processAction(cm, vim2, lastAction); } else { commandDispatcher.evalInput(cm, vim2); } } function repeatInsert(repeat2) { if (macroModeState.lastInsertModeChanges.changes.length > 0) { repeat2 = !vim2.lastEditActionCommand ? 1 : repeat2; var changeObject = macroModeState.lastInsertModeChanges; repeatInsertModeChanges(cm, changeObject.changes, repeat2); } } vim2.inputState = vim2.lastEditInputState; if (lastAction && lastAction.interlaceInsertRepeat) { for (var i = 0; i < repeat; i++) { repeatCommand(); repeatInsert(1); } } else { if (!repeatForInsert) { repeatCommand(); } repeatInsert(repeat); } vim2.inputState = cachedInputState; if (vim2.insertMode && !repeatForInsert) { exitInsertMode(cm); } macroModeState.isPlaying = false; } function sendCmKey(cm, key) { CodeMirror2.lookupKey(key, "vim-insert", function keyHandler(binding) { if (typeof binding == "string") { CodeMirror2.commands[binding](cm); } else { binding(cm); } return true; }); } function repeatInsertModeChanges(cm, changes, repeat) { var head = cm.getCursor("head"); var visualBlock = vimGlobalState.macroModeState.lastInsertModeChanges.visualBlock; if (visualBlock) { selectForInsert(cm, head, visualBlock + 1); repeat = cm.listSelections().length; cm.setCursor(head); } for (var i = 0; i < repeat; i++) { if (visualBlock) { cm.setCursor(offsetCursor(head, i, 0)); } for (var j = 0; j < changes.length; j++) { var change = changes[j]; if (change instanceof InsertModeKey) { sendCmKey(cm, change.keyName); } else if (typeof change == "string") { cm.replaceSelection(change); } else { var start = cm.getCursor(); var end = offsetCursor(start, 0, change[0].length - (change[1] || 0)); cm.replaceRange(change[0], start, change[1] ? start : end); cm.setCursor(end); } } } if (visualBlock) { cm.setCursor(offsetCursor(head, 0, 1)); } } function cloneVimState(state) { var n = new state.constructor(); Object.keys(state).forEach(function(key) { if (key == "insertEnd") return; var o = state[key]; if (Array.isArray(o)) o = o.slice(); else if (o && typeof o == "object" && o.constructor != Object) o = cloneVimState(o); n[key] = o; }); if (state.sel) { n.sel = { head: state.sel.head && copyCursor(state.sel.head), anchor: state.sel.anchor && copyCursor(state.sel.anchor) }; } return n; } function multiSelectHandleKey(cm_, key, origin) { var vim2 = maybeInitVimState(cm_); var cm = ( /**@type {CodeMirrorV}*/ cm_ ); var isHandled = false; var vim2 = vimApi.maybeInitVimState_(cm); var visualBlock = vim2.visualBlock || vim2.wasInVisualBlock; var wasMultiselect = cm.isInMultiSelectMode(); if (vim2.wasInVisualBlock && !wasMultiselect) { vim2.wasInVisualBlock = false; } else if (wasMultiselect && vim2.visualBlock) { vim2.wasInVisualBlock = true; } if (key == "" && !vim2.insertMode && !vim2.visualMode && wasMultiselect && vim2.status == "") { clearInputState(cm); } else if (visualBlock || !wasMultiselect || cm.inVirtualSelectionMode) { isHandled = vimApi.handleKey(cm, key, origin); } else { var old = cloneVimState(vim2); var changeQueueList = vim2.inputState.changeQueueList || []; cm.operation(function() { var _a; if (cm.curOp) cm.curOp.isVimOp = true; var index = 0; cm.forEachSelection(function() { cm.state.vim.inputState.changeQueue = changeQueueList[index]; var head = cm.getCursor("head"); var anchor = cm.getCursor("anchor"); var headOffset = !cursorIsBefore(head, anchor) ? -1 : 0; var anchorOffset = cursorIsBefore(head, anchor) ? -1 : 0; head = offsetCursor(head, 0, headOffset); anchor = offsetCursor(anchor, 0, anchorOffset); cm.state.vim.sel.head = head; cm.state.vim.sel.anchor = anchor; isHandled = vimApi.handleKey(cm, key, origin); if (cm.virtualSelection) { changeQueueList[index] = cm.state.vim.inputState.changeQueue; cm.state.vim = cloneVimState(old); } index++; }); if (((_a = cm.curOp) == null ? void 0 : _a.cursorActivity) && !isHandled) cm.curOp.cursorActivity = false; cm.state.vim = vim2; vim2.inputState.changeQueueList = changeQueueList; vim2.inputState.changeQueue = null; }, true); } if (isHandled && !vim2.visualMode && !vim2.insert && vim2.visualMode != cm.somethingSelected()) { handleExternalSelection(cm, vim2); } return isHandled; } resetVimGlobalState(); return vimApi; } function indexFromPos(doc, pos) { var ch = pos.ch; var lineNumber = pos.line + 1; if (lineNumber < 1) { lineNumber = 1; ch = 0; } if (lineNumber > doc.lines) { lineNumber = doc.lines; ch = Number.MAX_VALUE; } var line = doc.line(lineNumber); return Math.min(line.from + Math.max(0, ch), line.to); } function posFromIndex(doc, offset) { let line = doc.lineAt(offset); return { line: line.number - 1, ch: offset - line.from }; } var Pos = class { constructor(line, ch) { this.line = line; this.ch = ch; } }; function on(emitter, type, f) { if (emitter.addEventListener) { emitter.addEventListener(type, f, false); } else { var map = emitter._handlers || (emitter._handlers = {}); map[type] = (map[type] || []).concat(f); } } function off(emitter, type, f) { if (emitter.removeEventListener) { emitter.removeEventListener(type, f, false); } else { var map = emitter._handlers, arr = map && map[type]; if (arr) { var index = arr.indexOf(f); if (index > -1) { map[type] = arr.slice(0, index).concat(arr.slice(index + 1)); } } } } function signal(emitter, type, ...args) { var _a; var handlers = (_a = emitter._handlers) === null || _a === void 0 ? void 0 : _a[type]; if (!handlers) return; for (var i = 0; i < handlers.length; ++i) { handlers[i](...args); } } function signalTo(handlers, ...args) { if (!handlers) return; for (var i = 0; i < handlers.length; ++i) { handlers[i](...args); } } var wordChar; try { wordChar = /* @__PURE__ */ new RegExp("[\\w\\p{Alphabetic}\\p{Number}_]", "u"); } catch (_) { wordChar = /[\w]/; } function dispatchChange(cm, transaction) { var view = cm.cm6; if (view.state.readOnly) return; var type = "input.type.compose"; if (cm.curOp) { if (!cm.curOp.lastChange) type = "input.type.compose.start"; } if (transaction.annotations) { try { transaction.annotations.some(function(note) { if (note.value == "input") note.value = type; }); } catch (e) { console.error(e); } } else { transaction.userEvent = type; } return view.dispatch(transaction); } function runHistoryCommand(cm, revert) { var _a; if (cm.curOp) { cm.curOp.$changeStart = void 0; } (revert ? import_commands.undo : import_commands.redo)(cm.cm6); let changeStartIndex = (_a = cm.curOp) === null || _a === void 0 ? void 0 : _a.$changeStart; if (changeStartIndex != null) { cm.cm6.dispatch({ selection: { anchor: changeStartIndex } }); } } var keys = {}; var CodeMirror = class { constructor(cm6) { this.state = {}; this.marks = /* @__PURE__ */ Object.create(null); this.$mid = 0; this.options = {}; this._handlers = {}; this.$lastChangeEndOffset = 0; this.virtualSelection = null; this.cm6 = cm6; this.onChange = this.onChange.bind(this); this.onSelectionChange = this.onSelectionChange.bind(this); } // -------------------------- openDialog(template, callback, options) { return openDialog(this, template, callback, options); } openNotification(template, options) { return openNotification(this, template, options); } on(type, f) { on(this, type, f); } off(type, f) { off(this, type, f); } signal(type, e, handlers) { signal(this, type, e, handlers); } indexFromPos(pos) { return indexFromPos(this.cm6.state.doc, pos); } posFromIndex(offset) { return posFromIndex(this.cm6.state.doc, offset); } foldCode(pos) { let view = this.cm6; let ranges = view.state.selection.ranges; let doc = this.cm6.state.doc; let index = indexFromPos(doc, pos); let tmpRanges = import_state.EditorSelection.create([import_state.EditorSelection.range(index, index)], 0).ranges; view.state.selection.ranges = tmpRanges; (0, import_language.foldCode)(view); view.state.selection.ranges = ranges; } firstLine() { return 0; } lastLine() { return this.cm6.state.doc.lines - 1; } lineCount() { return this.cm6.state.doc.lines; } setCursor(line, ch) { if (typeof line === "object") { ch = line.ch; line = line.line; } var offset = indexFromPos(this.cm6.state.doc, { line, ch: ch || 0 }); this.cm6.dispatch({ selection: { anchor: offset } }, { scrollIntoView: !this.curOp }); if (this.curOp && !this.curOp.isVimOp) this.onBeforeEndOperation(); } getCursor(p2) { var sel = this.cm6.state.selection.main; var offset = p2 == "head" || !p2 ? sel.head : p2 == "anchor" ? sel.anchor : p2 == "start" ? sel.from : p2 == "end" ? sel.to : null; if (offset == null) throw new Error("Invalid cursor type"); return this.posFromIndex(offset); } listSelections() { var doc = this.cm6.state.doc; return this.cm6.state.selection.ranges.map((r) => { return { anchor: posFromIndex(doc, r.anchor), head: posFromIndex(doc, r.head) }; }); } setSelections(p2, primIndex) { var doc = this.cm6.state.doc; var ranges = p2.map((x) => { var head = indexFromPos(doc, x.head); var anchor = indexFromPos(doc, x.anchor); if (head == anchor) return import_state.EditorSelection.cursor(head, 1); return import_state.EditorSelection.range(anchor, head); }); this.cm6.dispatch({ selection: import_state.EditorSelection.create(ranges, primIndex) }); } setSelection(anchor, head, options) { this.setSelections([{ anchor, head }], 0); if (options && options.origin == "*mouse") { this.onBeforeEndOperation(); } } getLine(row) { var doc = this.cm6.state.doc; if (row < 0 || row >= doc.lines) return ""; return this.cm6.state.doc.line(row + 1).text; } getLineHandle(row) { if (!this.$lineHandleChanges) this.$lineHandleChanges = []; return { row, index: this.indexFromPos(new Pos(row, 0)) }; } getLineNumber(handle) { var updates = this.$lineHandleChanges; if (!updates) return null; var offset = handle.index; for (var i = 0; i < updates.length; i++) { offset = updates[i].changes.mapPos(offset, 1, import_state.MapMode.TrackAfter); if (offset == null) return null; } var pos = this.posFromIndex(offset); return pos.ch == 0 ? pos.line : null; } releaseLineHandles() { this.$lineHandleChanges = void 0; } getRange(s, e) { var doc = this.cm6.state.doc; return this.cm6.state.sliceDoc(indexFromPos(doc, s), indexFromPos(doc, e)); } replaceRange(text, s, e, source) { if (!e) e = s; var doc = this.cm6.state.doc; var from = indexFromPos(doc, s); var to = indexFromPos(doc, e); dispatchChange(this, { changes: { from, to, insert: text } }); } replaceSelection(text) { dispatchChange(this, this.cm6.state.replaceSelection(text)); } replaceSelections(replacements) { var ranges = this.cm6.state.selection.ranges; var changes = ranges.map((r, i) => { return { from: r.from, to: r.to, insert: replacements[i] || "" }; }); dispatchChange(this, { changes }); } getSelection() { return this.getSelections().join("\n"); } getSelections() { var cm = this.cm6; return cm.state.selection.ranges.map((r) => cm.state.sliceDoc(r.from, r.to)); } somethingSelected() { return this.cm6.state.selection.ranges.some((r) => !r.empty); } getInputField() { return this.cm6.contentDOM; } clipPos(p2) { var doc = this.cm6.state.doc; var ch = p2.ch; var lineNumber = p2.line + 1; if (lineNumber < 1) { lineNumber = 1; ch = 0; } if (lineNumber > doc.lines) { lineNumber = doc.lines; ch = Number.MAX_VALUE; } var line = doc.line(lineNumber); ch = Math.min(Math.max(0, ch), line.to - line.from); return new Pos(lineNumber - 1, ch); } getValue() { return this.cm6.state.doc.toString(); } setValue(text) { var cm = this.cm6; return cm.dispatch({ changes: { from: 0, to: cm.state.doc.length, insert: text }, selection: import_state.EditorSelection.range(0, 0) }); } focus() { return this.cm6.focus(); } blur() { return this.cm6.contentDOM.blur(); } defaultTextHeight() { return this.cm6.defaultLineHeight; } findMatchingBracket(pos, _options) { var state = this.cm6.state; var offset = indexFromPos(state.doc, pos); var m = (0, import_language.matchBrackets)(state, offset + 1, -1); if (m && m.end) { return { to: posFromIndex(state.doc, m.end.from) }; } m = (0, import_language.matchBrackets)(state, offset, 1); if (m && m.end) { return { to: posFromIndex(state.doc, m.end.from) }; } return { to: void 0 }; } scanForBracket(pos, dir, style, config) { return scanForBracket(this, pos, dir, style, config); } indentLine(line, more) { if (more) this.indentMore(); else this.indentLess(); } indentMore() { (0, import_commands.indentMore)(this.cm6); } indentLess() { (0, import_commands.indentLess)(this.cm6); } execCommand(name) { if (name == "indentAuto") CodeMirror.commands.indentAuto(this); else if (name == "goLineLeft") (0, import_commands.cursorLineBoundaryBackward)(this.cm6); else if (name == "goLineRight") { (0, import_commands.cursorLineBoundaryForward)(this.cm6); let state = this.cm6.state; let cur = state.selection.main.head; if (cur < state.doc.length && state.sliceDoc(cur, cur + 1) !== "\n") { (0, import_commands.cursorCharBackward)(this.cm6); } } else console.log(name + " is not implemented"); } setBookmark(cursor, options) { var assoc = (options === null || options === void 0 ? void 0 : options.insertLeft) ? 1 : -1; var offset = this.indexFromPos(cursor); var bm = new Marker(this, offset, assoc); return bm; } addOverlay({ query }) { let cm6Query = new import_search.SearchQuery({ regexp: true, search: query.source, caseSensitive: !/i/.test(query.flags) }); if (cm6Query.valid) { cm6Query.forVim = true; this.cm6Query = cm6Query; let effect = import_search.setSearchQuery.of(cm6Query); this.cm6.dispatch({ effects: effect }); return cm6Query; } } removeOverlay(overlay) { if (!this.cm6Query) return; this.cm6Query.forVim = false; let effect = import_search.setSearchQuery.of(this.cm6Query); this.cm6.dispatch({ effects: effect }); } getSearchCursor(query, pos) { var cm = this; var last = null; var lastCM5Result = null; if (pos.ch == void 0) pos.ch = Number.MAX_VALUE; var firstOffset = indexFromPos(cm.cm6.state.doc, pos); var source = query.source.replace(/(\\.|{(?:\d+(?:,\d*)?|,\d+)})|[{}]/g, function(a, b) { if (!b) return "\\" + a; return b; }); function rCursor(doc, from = 0, to = doc.length) { return new import_search.RegExpCursor(doc, source, { ignoreCase: query.ignoreCase }, from, to); } function nextMatch(from) { var doc = cm.cm6.state.doc; if (from > doc.length) return null; let res = rCursor(doc, from).next(); return res.done ? null : res.value; } var ChunkSize = 1e4; function prevMatchInRange(from, to) { var doc = cm.cm6.state.doc; for (let size = 1; ; size++) { let start = Math.max(from, to - size * ChunkSize); let cursor = rCursor(doc, start, to), range = null; while (!cursor.next().done) range = cursor.value; if (range && (start == from || range.from > start + 10)) return range; if (start == from) return null; } } return { findNext: function() { return this.find(false); }, findPrevious: function() { return this.find(true); }, find: function(back) { var doc = cm.cm6.state.doc; if (back) { let endAt = last ? last.from == last.to ? last.to - 1 : last.from : firstOffset; last = prevMatchInRange(0, endAt); } else { let startFrom = last ? last.from == last.to ? last.to + 1 : last.to : firstOffset; last = nextMatch(startFrom); } lastCM5Result = last && { from: posFromIndex(doc, last.from), to: posFromIndex(doc, last.to), match: last.match }; return last && last.match; }, from: function() { return lastCM5Result === null || lastCM5Result === void 0 ? void 0 : lastCM5Result.from; }, to: function() { return lastCM5Result === null || lastCM5Result === void 0 ? void 0 : lastCM5Result.to; }, replace: function(text) { if (last) { dispatchChange(cm, { changes: { from: last.from, to: last.to, insert: text } }); last.to = last.from + text.length; if (lastCM5Result) { lastCM5Result.to = posFromIndex(cm.cm6.state.doc, last.to); } } } }; } findPosV(start, amount, unit, goalColumn) { let { cm6 } = this; const doc = cm6.state.doc; let pixels = unit == "page" ? cm6.dom.clientHeight : 0; const startOffset = indexFromPos(doc, start); let range = import_state.EditorSelection.cursor(startOffset, 1, void 0, goalColumn); let count = Math.round(Math.abs(amount)); for (let i = 0; i < count; i++) { if (unit == "page") { range = cm6.moveVertically(range, amount > 0, pixels); } else if (unit == "line") { range = cm6.moveVertically(range, amount > 0); } } let pos = posFromIndex(doc, range.head); if (amount < 0 && range.head == 0 && goalColumn != 0 && start.line == 0 && start.ch != 0 || amount > 0 && range.head == doc.length && pos.ch != goalColumn && start.line == pos.line) { pos.hitSide = true; } return pos; } charCoords(pos, mode) { var rect = this.cm6.contentDOM.getBoundingClientRect(); var offset = indexFromPos(this.cm6.state.doc, pos); var coords = this.cm6.coordsAtPos(offset); var d = -rect.top; return { left: ((coords === null || coords === void 0 ? void 0 : coords.left) || 0) - rect.left, top: ((coords === null || coords === void 0 ? void 0 : coords.top) || 0) + d, bottom: ((coords === null || coords === void 0 ? void 0 : coords.bottom) || 0) + d }; } coordsChar(coords, mode) { var rect = this.cm6.contentDOM.getBoundingClientRect(); var offset = this.cm6.posAtCoords({ x: coords.left + rect.left, y: coords.top + rect.top }) || 0; return posFromIndex(this.cm6.state.doc, offset); } getScrollInfo() { var scroller = this.cm6.scrollDOM; return { left: scroller.scrollLeft, top: scroller.scrollTop, height: scroller.scrollHeight, width: scroller.scrollWidth, clientHeight: scroller.clientHeight, clientWidth: scroller.clientWidth }; } scrollTo(x, y) { if (x != null) this.cm6.scrollDOM.scrollLeft = x; if (y != null) this.cm6.scrollDOM.scrollTop = y; } scrollIntoView(pos, margin) { if (pos) { var offset = this.indexFromPos(pos); this.cm6.dispatch({ effects: import_view.EditorView.scrollIntoView(offset) }); } else { this.cm6.dispatch({ scrollIntoView: true, userEvent: "scroll" }); } } getWrapperElement() { return this.cm6.dom; } // for tests getMode() { return { name: this.getOption("mode") }; } setSize(w, h) { this.cm6.dom.style.width = w + 4 + "px"; this.cm6.dom.style.height = h + "px"; this.refresh(); } refresh() { this.cm6.measure(); } // event listeners destroy() { this.removeOverlay(); } getLastEditEnd() { return this.posFromIndex(this.$lastChangeEndOffset); } onChange(update) { if (this.$lineHandleChanges) { this.$lineHandleChanges.push(update); } for (let i in this.marks) { let m = this.marks[i]; m.update(update.changes); } if (this.virtualSelection) { this.virtualSelection.ranges = this.virtualSelection.ranges.map((range) => range.map(update.changes)); } var curOp = this.curOp = this.curOp || {}; update.changes.iterChanges((fromA, toA, fromB, toB, text) => { if (curOp.$changeStart == null || curOp.$changeStart > fromB) curOp.$changeStart = fromB; this.$lastChangeEndOffset = toB; var change = { text: text.toJSON() }; if (!curOp.lastChange) { curOp.lastChange = curOp.change = change; } else { curOp.lastChange.next = curOp.lastChange = change; } }, true); if (!curOp.changeHandlers) curOp.changeHandlers = this._handlers["change"] && this._handlers["change"].slice(); } onSelectionChange() { var curOp = this.curOp = this.curOp || {}; if (!curOp.cursorActivityHandlers) curOp.cursorActivityHandlers = this._handlers["cursorActivity"] && this._handlers["cursorActivity"].slice(); this.curOp.cursorActivity = true; } operation(fn, force) { if (!this.curOp) this.curOp = { $d: 0 }; this.curOp.$d++; try { var result = fn(); } finally { if (this.curOp) { this.curOp.$d--; if (!this.curOp.$d) this.onBeforeEndOperation(); } } return result; } onBeforeEndOperation() { var op = this.curOp; var scrollIntoView = false; if (op) { if (op.change) { signalTo(op.changeHandlers, this, op.change); } if (op && op.cursorActivity) { signalTo(op.cursorActivityHandlers, this, null); if (op.isVimOp) scrollIntoView = true; } this.curOp = null; } if (scrollIntoView) this.scrollIntoView(); } moveH(increment, unit) { if (unit == "char") { var cur = this.getCursor(); this.setCursor(cur.line, cur.ch + increment); } } setOption(name, val) { switch (name) { case "keyMap": this.state.keyMap = val; break; case "textwidth": this.state.textwidth = val; break; } } getOption(name) { switch (name) { case "firstLineNumber": return 1; case "tabSize": return this.cm6.state.tabSize || 4; case "readOnly": return this.cm6.state.readOnly; case "indentWithTabs": return this.cm6.state.facet(import_language.indentUnit) == " "; case "indentUnit": return this.cm6.state.facet(import_language.indentUnit).length || 2; case "textwidth": return this.state.textwidth; case "keyMap": return this.state.keyMap || "vim"; } } toggleOverwrite(on2) { this.state.overwrite = on2; } getTokenTypeAt(pos) { var _a; var offset = this.indexFromPos(pos); var tree = (0, import_language.ensureSyntaxTree)(this.cm6.state, offset); var node = tree === null || tree === void 0 ? void 0 : tree.resolve(offset); var type = ((_a = node === null || node === void 0 ? void 0 : node.type) === null || _a === void 0 ? void 0 : _a.name) || ""; if (/comment/i.test(type)) return "comment"; if (/string/i.test(type)) return "string"; return ""; } overWriteSelection(text) { var doc = this.cm6.state.doc; var sel = this.cm6.state.selection; var ranges = sel.ranges.map((x) => { if (x.empty) { var ch = x.to < doc.length ? doc.sliceString(x.from, x.to + 1) : ""; if (ch && !/\n/.test(ch)) return import_state.EditorSelection.range(x.from, x.to + 1); } return x; }); this.cm6.dispatch({ selection: import_state.EditorSelection.create(ranges, sel.mainIndex) }); this.replaceSelection(text); } /*** multiselect ****/ isInMultiSelectMode() { return this.cm6.state.selection.ranges.length > 1; } virtualSelectionMode() { return !!this.virtualSelection; } forEachSelection(command) { var selection = this.cm6.state.selection; this.virtualSelection = import_state.EditorSelection.create(selection.ranges, selection.mainIndex); for (var i = 0; i < this.virtualSelection.ranges.length; i++) { var range = this.virtualSelection.ranges[i]; if (!range) continue; this.cm6.dispatch({ selection: import_state.EditorSelection.create([range]) }); command(); this.virtualSelection.ranges[i] = this.cm6.state.selection.ranges[0]; } this.cm6.dispatch({ selection: this.virtualSelection }); this.virtualSelection = null; } hardWrap(options) { return hardWrap(this, options); } }; CodeMirror.isMac = typeof navigator != "undefined" && /* @__PURE__ */ /Mac/.test(navigator.platform); CodeMirror.Pos = Pos; CodeMirror.StringStream = import_language.StringStream; CodeMirror.commands = { cursorCharLeft: function(cm) { (0, import_commands.cursorCharLeft)(cm.cm6); }, redo: function(cm) { runHistoryCommand(cm, false); }, undo: function(cm) { runHistoryCommand(cm, true); }, newlineAndIndent: function(cm) { (0, import_commands.insertNewlineAndIndent)({ state: cm.cm6.state, dispatch: (tr) => { return dispatchChange(cm, tr); } }); }, indentAuto: function(cm) { (0, import_commands.indentSelection)(cm.cm6); }, newlineAndIndentContinueComment: void 0, save: void 0 }; CodeMirror.isWordChar = function(ch) { return wordChar.test(ch); }; CodeMirror.keys = keys; CodeMirror.addClass = function(el, str) { }; CodeMirror.rmClass = function(el, str) { }; CodeMirror.e_preventDefault = function(e) { e.preventDefault(); }; CodeMirror.e_stop = function(e) { var _a, _b; (_a = e === null || e === void 0 ? void 0 : e.stopPropagation) === null || _a === void 0 ? void 0 : _a.call(e); (_b = e === null || e === void 0 ? void 0 : e.preventDefault) === null || _b === void 0 ? void 0 : _b.call(e); }; CodeMirror.lookupKey = function lookupKey(key, map, handle) { var result = CodeMirror.keys[key]; if (result) handle(result); }; CodeMirror.on = on; CodeMirror.off = off; CodeMirror.signal = signal; CodeMirror.findMatchingTag = findMatchingTag; CodeMirror.findEnclosingTag = findEnclosingTag; CodeMirror.keyName = void 0; function dialogDiv(cm, template, bottom) { var dialog = document.createElement("div"); dialog.appendChild(template); return dialog; } function closeNotification(cm, newVal) { if (cm.state.currentNotificationClose) cm.state.currentNotificationClose(); cm.state.currentNotificationClose = newVal; } function openNotification(cm, template, options) { closeNotification(cm, close); var dialog = dialogDiv(cm, template, options && options.bottom); var closed = false; var doneTimer; var duration = options && typeof options.duration !== "undefined" ? options.duration : 5e3; function close() { if (closed) return; closed = true; clearTimeout(doneTimer); dialog.remove(); hideDialog(cm, dialog); } dialog.onclick = function(e) { e.preventDefault(); close(); }; showDialog(cm, dialog); if (duration) doneTimer = setTimeout(close, duration); return close; } function showDialog(cm, dialog) { var oldDialog = cm.state.dialog; cm.state.dialog = dialog; if (dialog && oldDialog !== dialog) { if (oldDialog && oldDialog.contains(document.activeElement)) cm.focus(); if (oldDialog && oldDialog.parentElement) { oldDialog.parentElement.replaceChild(dialog, oldDialog); } else if (oldDialog) { oldDialog.remove(); } CodeMirror.signal(cm, "dialog"); } } function hideDialog(cm, dialog) { if (cm.state.dialog == dialog) { cm.state.dialog = null; CodeMirror.signal(cm, "dialog"); } } function openDialog(me, template, callback, options) { if (!options) options = {}; closeNotification(me, void 0); var dialog = dialogDiv(me, template, options.bottom); var closed = false; showDialog(me, dialog); function close(newVal) { if (typeof newVal == "string") { inp.value = newVal; } else { if (closed) return; closed = true; hideDialog(me, dialog); if (!me.state.dialog) me.focus(); if (options.onClose) options.onClose(dialog); } } var inp = dialog.getElementsByTagName("input")[0]; if (inp) { if (options.value) { inp.value = options.value; if (options.selectValueOnOpen !== false) inp.select(); } if (options.onInput) CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close); }); if (options.onKeyUp) CodeMirror.on(inp, "keyup", function(e) { options.onKeyUp(e, inp.value, close); }); CodeMirror.on(inp, "keydown", function(e) { if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; } if (e.keyCode == 13) callback(inp.value); if (e.keyCode == 27 || options.closeOnEnter !== false && e.keyCode == 13) { inp.blur(); CodeMirror.e_stop(e); close(); } }); if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", function() { setTimeout(function() { if (document.activeElement === inp) return; close(); }); }); inp.focus(); } return close; } var matching = { "(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<", "<": ">>", ">": "<<" }; function bracketRegex(config) { return config && config.bracketRegex || /[(){}[\]]/; } function scanForBracket(cm, where, dir, style, config) { var maxScanLen = config && config.maxScanLineLength || 1e4; var maxScanLines = config && config.maxScanLines || 1e3; var stack = []; var re = bracketRegex(config); var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1) : Math.max(cm.firstLine() - 1, where.line - maxScanLines); for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) { var line = cm.getLine(lineNo); if (!line) continue; var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1; if (line.length > maxScanLen) continue; if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0); for (; pos != end; pos += dir) { var ch = line.charAt(pos); if (re.test(ch)) { var match = matching[ch]; if (match && match.charAt(1) == ">" == dir > 0) stack.push(ch); else if (!stack.length) return { pos: new Pos(lineNo, pos), ch }; else stack.pop(); } } } return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null; } function findMatchingTag(cm, pos) { } function findEnclosingTag(cm, pos) { var _a, _b; var state = cm.cm6.state; var offset = cm.indexFromPos(pos); if (offset < state.doc.length) { var text = state.sliceDoc(offset, offset + 1); if (text == "<") offset++; } var tree = (0, import_language.ensureSyntaxTree)(state, offset); var node = (tree === null || tree === void 0 ? void 0 : tree.resolve(offset)) || null; while (node) { if (((_a = node.firstChild) === null || _a === void 0 ? void 0 : _a.type.name) == "OpenTag" && ((_b = node.lastChild) === null || _b === void 0 ? void 0 : _b.type.name) == "CloseTag") { return { open: convertRange(state.doc, node.firstChild), close: convertRange(state.doc, node.lastChild) }; } node = node.parent; } } function convertRange(doc, cm6Range) { return { from: posFromIndex(doc, cm6Range.from), to: posFromIndex(doc, cm6Range.to) }; } var Marker = class { constructor(cm, offset, assoc) { this.cm = cm; this.id = cm.$mid++; this.offset = offset; this.assoc = assoc; cm.marks[this.id] = this; } clear() { delete this.cm.marks[this.id]; } find() { if (this.offset == null) return null; return this.cm.posFromIndex(this.offset); } update(change) { if (this.offset != null) this.offset = change.mapPos(this.offset, this.assoc, import_state.MapMode.TrackDel); } }; function hardWrap(cm, options) { var _a; var max = options.column || cm.getOption("textwidth") || 80; var allowMerge = options.allowMerge != false; var row = Math.min(options.from, options.to); var endRow = Math.max(options.from, options.to); while (row <= endRow) { var line = cm.getLine(row); if (line.length > max) { var space = findSpace(line, max, 5); if (space) { var indentation = (_a = /^\s*/.exec(line)) === null || _a === void 0 ? void 0 : _a[0]; cm.replaceRange("\n" + indentation, new Pos(row, space.start), new Pos(row, space.end)); } endRow++; } else if (allowMerge && /\S/.test(line) && row != endRow) { var nextLine = cm.getLine(row + 1); if (nextLine && /\S/.test(nextLine)) { var trimmedLine = line.replace(/\s+$/, ""); var trimmedNextLine = nextLine.replace(/^\s+/, ""); var mergedLine = trimmedLine + " " + trimmedNextLine; var space = findSpace(mergedLine, max, 5); if (space && space.start > trimmedLine.length || mergedLine.length < max) { cm.replaceRange(" ", new Pos(row, trimmedLine.length), new Pos(row + 1, nextLine.length - trimmedNextLine.length)); row--; endRow--; } else if (trimmedLine.length < line.length) { cm.replaceRange("", new Pos(row, trimmedLine.length), new Pos(row, line.length)); } } } row++; } return row; function findSpace(line2, max2, min) { if (line2.length < max2) return; var before = line2.slice(0, max2); var after = line2.slice(max2); var spaceAfter = /^(?:(\s+)|(\S+)(\s+))/.exec(after); var spaceBefore = /(?:(\s+)|(\s+)(\S+))$/.exec(before); var start = 0; var end = 0; if (spaceBefore && !spaceBefore[2]) { start = max2 - spaceBefore[1].length; end = max2; } if (spaceAfter && !spaceAfter[2]) { if (!start) start = max2; end = max2 + spaceAfter[1].length; } if (start) { return { start, end }; } if (spaceBefore && spaceBefore[2] && spaceBefore.index > min) { return { start: spaceBefore.index, end: spaceBefore.index + spaceBefore[2].length }; } if (spaceAfter && spaceAfter[2]) { start = max2 + spaceAfter[2].length; return { start, end: start + spaceAfter[3].length }; } } } var getDrawSelectionConfig2 = View.getDrawSelectionConfig || /* @__PURE__ */ function() { let defaultConfig = { cursorBlinkRate: 1200 }; return function() { return defaultConfig; }; }(); var Piece = class { constructor(left, top, height, fontFamily, fontSize, fontWeight, color, className, letter, partial) { this.left = left; this.top = top; this.height = height; this.fontFamily = fontFamily; this.fontSize = fontSize; this.fontWeight = fontWeight; this.color = color; this.className = className; this.letter = letter; this.partial = partial; } draw() { let elt = document.createElement("div"); elt.className = this.className; this.adjust(elt); return elt; } adjust(elt) { elt.style.left = this.left + "px"; elt.style.top = this.top + "px"; elt.style.height = this.height + "px"; elt.style.lineHeight = this.height + "px"; elt.style.fontFamily = this.fontFamily; elt.style.fontSize = this.fontSize; elt.style.fontWeight = this.fontWeight; elt.style.color = this.partial ? "transparent" : this.color; elt.className = this.className; elt.textContent = this.letter; } eq(p2) { return this.left == p2.left && this.top == p2.top && this.height == p2.height && this.fontFamily == p2.fontFamily && this.fontSize == p2.fontSize && this.fontWeight == p2.fontWeight && this.color == p2.color && this.className == p2.className && this.letter == p2.letter; } }; var BlockCursorPlugin = class { constructor(view, cm) { this.view = view; this.rangePieces = []; this.cursors = []; this.cm = cm; this.measureReq = { read: this.readPos.bind(this), write: this.drawSel.bind(this) }; this.cursorLayer = view.scrollDOM.appendChild(document.createElement("div")); this.cursorLayer.className = "cm-cursorLayer cm-vimCursorLayer"; this.cursorLayer.setAttribute("aria-hidden", "true"); view.requestMeasure(this.measureReq); this.setBlinkRate(); } setBlinkRate() { let config = getDrawSelectionConfig2(this.cm.cm6.state); let blinkRate = config.cursorBlinkRate; this.cursorLayer.style.animationDuration = blinkRate + "ms"; } update(update) { if (update.selectionSet || update.geometryChanged || update.viewportChanged) { this.view.requestMeasure(this.measureReq); this.cursorLayer.style.animationName = this.cursorLayer.style.animationName == "cm-blink" ? "cm-blink2" : "cm-blink"; } if (configChanged(update)) this.setBlinkRate(); } scheduleRedraw() { this.view.requestMeasure(this.measureReq); } readPos() { let { state } = this.view; let cursors = []; for (let r of state.selection.ranges) { let prim = r == state.selection.main; let piece = measureCursor(this.cm, this.view, r, prim); if (piece) cursors.push(piece); } return { cursors }; } drawSel({ cursors }) { if (cursors.length != this.cursors.length || cursors.some((c, i) => !c.eq(this.cursors[i]))) { let oldCursors = this.cursorLayer.children; if (oldCursors.length !== cursors.length) { this.cursorLayer.textContent = ""; for (const c of cursors) this.cursorLayer.appendChild(c.draw()); } else { cursors.forEach((c, idx) => c.adjust(oldCursors[idx])); } this.cursors = cursors; } } destroy() { this.cursorLayer.remove(); } }; function configChanged(update) { return getDrawSelectionConfig2(update.startState) != getDrawSelectionConfig2(update.state); } var themeSpec = { ".cm-vimMode .cm-line": { "& ::selection": { backgroundColor: "transparent !important" }, "&::selection": { backgroundColor: "transparent !important" }, caretColor: "transparent !important" }, ".cm-fat-cursor": { position: "absolute", background: "#ff9696", border: "none", whiteSpace: "pre" }, "&:not(.cm-focused) .cm-fat-cursor": { background: "none", outline: "solid 1px #ff9696", color: "transparent !important" } }; var hideNativeSelection = /* @__PURE__ */ import_state.Prec.highest(/* @__PURE__ */ import_view.EditorView.theme(themeSpec)); function getBase(view) { let rect = view.scrollDOM.getBoundingClientRect(); let left = view.textDirection == import_view.Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth; return { left: left - view.scrollDOM.scrollLeft, top: rect.top - view.scrollDOM.scrollTop }; } function measureCursor(cm, view, cursor, primary) { var _a, _b; let head = cursor.head; let fatCursor = false; let hCoeff = 1; let vim2 = cm.state.vim; if (vim2 && (!vim2.insertMode || cm.state.overwrite)) { fatCursor = true; if (vim2.visualBlock && !primary) return null; if (cursor.anchor < cursor.head) head--; if (cm.state.overwrite) hCoeff = 0.2; else if (vim2.status) hCoeff = 0.5; } if (fatCursor) { let letter = head < view.state.doc.length && view.state.sliceDoc(head, head + 1); if (letter && (/[\uDC00-\uDFFF]/.test(letter) && head > 1)) { head--; letter = view.state.sliceDoc(head, head + 1); } let pos = view.coordsAtPos(head, 1); if (!pos) return null; let base = getBase(view); let domAtPos = view.domAtPos(head); let node = domAtPos ? domAtPos.node : view.contentDOM; while (domAtPos && domAtPos.node instanceof HTMLElement) { node = domAtPos.node; domAtPos = { node: domAtPos.node.childNodes[domAtPos.offset], offset: 0 }; } if (!(node instanceof HTMLElement)) { if (!node.parentNode) return null; node = node.parentNode; } let style = getComputedStyle(node); let left = pos.left; let charCoords = (_b = (_a = view).coordsForChar) === null || _b === void 0 ? void 0 : _b.call(_a, head); if (charCoords) { left = charCoords.left; } if (!letter || letter == "\n" || letter == "\r") { letter = "\xA0"; } else if (letter == " ") { letter = "\xA0"; var nextPos = view.coordsAtPos(head + 1, -1); if (nextPos) { left = nextPos.left - (nextPos.left - pos.left) / parseInt(style.tabSize); } } else if (/[\uD800-\uDBFF]/.test(letter) && head < view.state.doc.length - 1) { letter += view.state.sliceDoc(head + 1, head + 2); } let h = pos.bottom - pos.top; return new Piece(left - base.left, pos.top - base.top + h * (1 - hCoeff), h * hCoeff, style.fontFamily, style.fontSize, style.fontWeight, style.color, primary ? "cm-fat-cursor cm-cursor-primary" : "cm-fat-cursor cm-cursor-secondary", letter, hCoeff != 1); } else { return null; } } var FIREFOX_LINUX = typeof navigator != "undefined" && /* @__PURE__ */ /linux/i.test(navigator.platform) && /* @__PURE__ */ / Gecko\/\d+/.exec(navigator.userAgent); var Vim = /* @__PURE__ */ initVim(CodeMirror); var HighlightMargin = 250; var vimStyle = /* @__PURE__ */ import_view.EditorView.baseTheme({ ".cm-vimMode .cm-cursorLayer:not(.cm-vimCursorLayer)": { display: "none" }, ".cm-vim-panel": { padding: "0px 10px", fontFamily: "monospace", minHeight: "1.3em" }, ".cm-vim-panel input": { border: "none", outline: "none", backgroundColor: "inherit" }, "&light .cm-searchMatch": { backgroundColor: "#ffff0054" }, "&dark .cm-searchMatch": { backgroundColor: "#00ffff8a" } }); var vimPlugin = /* @__PURE__ */ import_view.ViewPlugin.fromClass(class { constructor(view) { this.status = ""; this.query = null; this.decorations = import_view.Decoration.none; this.waitForCopy = false; this.lastKeydown = ""; this.useNextTextInput = false; this.compositionText = ""; this.view = view; const cm = this.cm = new CodeMirror(view); Vim.enterVimMode(this.cm); this.view.cm = this.cm; this.cm.state.vimPlugin = this; this.blockCursor = new BlockCursorPlugin(view, cm); this.updateClass(); this.cm.on("vim-command-done", () => { if (cm.state.vim) cm.state.vim.status = ""; this.blockCursor.scheduleRedraw(); this.updateStatus(); }); this.cm.on("vim-mode-change", (e) => { if (!cm.state.vim) return; cm.state.vim.mode = e.mode; if (e.subMode) { cm.state.vim.mode += " block"; } cm.state.vim.status = ""; this.blockCursor.scheduleRedraw(); this.updateClass(); this.updateStatus(); }); this.cm.on("dialog", () => { if (this.cm.state.statusbar) { this.updateStatus(); } else { view.dispatch({ effects: showVimPanel.of(!!this.cm.state.dialog) }); } }); this.dom = document.createElement("span"); this.dom.style.cssText = "position: absolute; right: 10px; top: 1px"; this.statusButton = document.createElement("span"); this.statusButton.onclick = (e) => { Vim.handleKey(this.cm, "", "user"); this.cm.focus(); }; this.statusButton.style.cssText = "cursor: pointer"; } update(update) { var _a; if ((update.viewportChanged || update.docChanged) && this.query) { this.highlight(this.query); } if (update.docChanged) { this.cm.onChange(update); } if (update.selectionSet) { this.cm.onSelectionChange(); } if (update.viewportChanged) ; if (this.cm.curOp && !this.cm.curOp.isVimOp) { this.cm.onBeforeEndOperation(); } if (update.transactions) { for (let tr of update.transactions) for (let effect of tr.effects) { if (effect.is(import_search.setSearchQuery)) { let forVim = (_a = effect.value) === null || _a === void 0 ? void 0 : _a.forVim; if (!forVim) { this.highlight(null); } else { let query = effect.value.create(); this.highlight(query); } } } } this.blockCursor.update(update); } updateClass() { const state = this.cm.state; if (!state.vim || state.vim.insertMode && !state.overwrite) this.view.scrollDOM.classList.remove("cm-vimMode"); else this.view.scrollDOM.classList.add("cm-vimMode"); } updateStatus() { let dom = this.cm.state.statusbar; let vim2 = this.cm.state.vim; if (!dom || !vim2) return; let dialog = this.cm.state.dialog; if (dialog) { if (dialog.parentElement != dom) { dom.textContent = ""; dom.appendChild(dialog); } } else { dom.textContent = ""; var status = (vim2.mode || "normal").toUpperCase(); if (vim2.insertModeReturn) status += "(C-O)"; this.statusButton.textContent = `--${status}--`; dom.appendChild(this.statusButton); } this.dom.textContent = vim2.status; dom.appendChild(this.dom); } destroy() { Vim.leaveVimMode(this.cm); this.updateClass(); this.blockCursor.destroy(); delete this.view.cm; } highlight(query) { this.query = query; if (!query) return this.decorations = import_view.Decoration.none; let { view } = this; let builder = new import_state.RangeSetBuilder(); for (let i = 0, ranges = view.visibleRanges, l = ranges.length; i < l; i++) { let { from, to } = ranges[i]; while (i < l - 1 && to > ranges[i + 1].from - 2 * HighlightMargin) to = ranges[++i].to; query.highlight(view.state, from, to, (from2, to2) => { builder.add(from2, to2, matchMark); }); } return this.decorations = builder.finish(); } handleKey(e, view) { const cm = this.cm; let vim2 = cm.state.vim; if (!vim2) return; const key = Vim.vimKeyFromEvent(e, vim2); CodeMirror.signal(this.cm, "inputEvent", { type: "handleKey", key }); if (!key) return; if (key == "" && !vim2.insertMode && !vim2.visualMode && this.query) { const searchState = vim2.searchState_; if (searchState) { cm.removeOverlay(searchState.getOverlay()); searchState.setOverlay(null); } } let isCopy = key === "" && !CodeMirror.isMac; if (isCopy && cm.somethingSelected()) { this.waitForCopy = true; return true; } vim2.status = (vim2.status || "") + key; let result = Vim.multiSelectHandleKey(cm, key, "user"); vim2 = Vim.maybeInitVimState_(cm); if (!result && vim2.insertMode && cm.state.overwrite) { if (e.key && e.key.length == 1 && !/\n/.test(e.key)) { result = true; cm.overWriteSelection(e.key); } else if (e.key == "Backspace") { result = true; CodeMirror.commands.cursorCharLeft(cm); } } if (result) { CodeMirror.signal(this.cm, "vim-keypress", key); e.preventDefault(); e.stopPropagation(); this.blockCursor.scheduleRedraw(); } this.updateStatus(); return !!result; } }, { eventHandlers: { copy: function(e, view) { if (!this.waitForCopy) return; this.waitForCopy = false; Promise.resolve().then(() => { var cm = this.cm; var vim2 = cm.state.vim; if (!vim2) return; if (vim2.insertMode) { cm.setSelection(cm.getCursor(), cm.getCursor()); } else { cm.operation(() => { if (cm.curOp) cm.curOp.isVimOp = true; Vim.handleKey(cm, "", "user"); }); } }); }, compositionstart: function(e, view) { this.useNextTextInput = true; CodeMirror.signal(this.cm, "inputEvent", e); }, compositionupdate: function(e, view) { CodeMirror.signal(this.cm, "inputEvent", e); }, compositionend: function(e, view) { CodeMirror.signal(this.cm, "inputEvent", e); }, keypress: function(e, view) { CodeMirror.signal(this.cm, "inputEvent", e); if (this.lastKeydown == "Dead") this.handleKey(e, view); }, keydown: function(e, view) { CodeMirror.signal(this.cm, "inputEvent", e); this.lastKeydown = e.key; if (this.lastKeydown == "Unidentified" || this.lastKeydown == "Process" || this.lastKeydown == "Dead") { this.useNextTextInput = true; } else { this.useNextTextInput = false; this.handleKey(e, view); } } }, provide: () => { return [ import_view.EditorView.inputHandler.of((view, from, to, text) => { var _a, _b; var cm = getCM(view); if (!cm) return false; var vim2 = (_a = cm.state) === null || _a === void 0 ? void 0 : _a.vim; var vimPlugin2 = cm.state.vimPlugin; if (vim2 && !vim2.insertMode && !((_b = cm.curOp) === null || _b === void 0 ? void 0 : _b.isVimOp)) { if (text === "\0\0") { return true; } CodeMirror.signal(cm, "inputEvent", { type: "text", text, from, to }); if (text.length == 1 && vimPlugin2.useNextTextInput) { if (vim2.expectLiteralNext && view.composing) { vimPlugin2.compositionText = text; return false; } if (vimPlugin2.compositionText) { var toRemove = vimPlugin2.compositionText; vimPlugin2.compositionText = ""; var head = view.state.selection.main.head; var textInDoc = view.state.sliceDoc(head - toRemove.length, head); if (toRemove === textInDoc) { var pos = cm.getCursor(); cm.replaceRange("", cm.posFromIndex(head - toRemove.length), pos); } } vimPlugin2.handleKey({ key: text, preventDefault: () => { }, stopPropagation: () => { } }); forceEndComposition(view); return true; } } return false; }) ]; }, decorations: (v) => v.decorations }); function forceEndComposition(view) { var parent = view.scrollDOM.parentElement; if (!parent) return; if (FIREFOX_LINUX) { view.contentDOM.textContent = "\0\0"; view.contentDOM.dispatchEvent(new CustomEvent("compositionend")); return; } var sibling = view.scrollDOM.nextSibling; var selection = window.getSelection(); var savedSelection = selection && { anchorNode: selection.anchorNode, anchorOffset: selection.anchorOffset, focusNode: selection.focusNode, focusOffset: selection.focusOffset }; view.scrollDOM.remove(); parent.insertBefore(view.scrollDOM, sibling); try { if (savedSelection && selection) { selection.setPosition(savedSelection.anchorNode, savedSelection.anchorOffset); if (savedSelection.focusNode) { selection.extend(savedSelection.focusNode, savedSelection.focusOffset); } } } catch (e) { console.error(e); } view.focus(); view.contentDOM.dispatchEvent(new CustomEvent("compositionend")); } var matchMark = /* @__PURE__ */ import_view.Decoration.mark({ class: "cm-searchMatch" }); var showVimPanel = /* @__PURE__ */ import_state.StateEffect.define(); var vimPanelState = /* @__PURE__ */ import_state.StateField.define({ create: () => false, update(value, tr) { for (let e of tr.effects) if (e.is(showVimPanel)) value = e.value; return value; }, provide: (f) => { return import_view.showPanel.from(f, (on2) => on2 ? createVimPanel : null); } }); function createVimPanel(view) { let dom = document.createElement("div"); dom.className = "cm-vim-panel"; let cm = view.cm; if (cm.state.dialog) { dom.appendChild(cm.state.dialog); } return { top: false, dom }; } function statusPanel(view) { let dom = document.createElement("div"); dom.className = "cm-vim-panel"; let cm = view.cm; cm.state.statusbar = dom; cm.state.vimPlugin.updateStatus(); return { dom }; } function vim(options = {}) { return [ vimStyle, vimPlugin, hideNativeSelection, options.status ? import_view.showPanel.of(statusPanel) : vimPanelState ]; } function getCM(view) { return view.cm || null; } // main.ts var import_obsidian = require("obsidian"); // codemirror-lang-orgmode/src/index.ts var import_language2 = require("@codemirror/language"); var import_highlight = require("@lezer/highlight"); // node_modules/@lezer/generator/dist/index.js var import_common = require("@lezer/common"); var import_lr = require("@lezer/lr"); var Node = class { constructor(start) { this.start = start; } }; var GrammarDeclaration = class extends Node { constructor(start, rules, topRules, tokens, localTokens, context, externalTokens, externalSpecializers, externalPropSources, precedences, mainSkip, scopedSkip, dialects, externalProps, autoDelim) { super(start); this.rules = rules; this.topRules = topRules; this.tokens = tokens; this.localTokens = localTokens; this.context = context; this.externalTokens = externalTokens; this.externalSpecializers = externalSpecializers; this.externalPropSources = externalPropSources; this.precedences = precedences; this.mainSkip = mainSkip; this.scopedSkip = scopedSkip; this.dialects = dialects; this.externalProps = externalProps; this.autoDelim = autoDelim; } toString() { return Object.values(this.rules).join("\n"); } }; var RuleDeclaration = class extends Node { constructor(start, id, props, params, expr) { super(start); this.id = id; this.props = props; this.params = params; this.expr = expr; } toString() { return this.id.name + (this.params.length ? `<${this.params.join()}>` : "") + " -> " + this.expr; } }; var PrecDeclaration = class extends Node { constructor(start, items) { super(start); this.items = items; } }; var TokenPrecDeclaration = class extends Node { constructor(start, items) { super(start); this.items = items; } }; var TokenConflictDeclaration = class extends Node { constructor(start, a, b) { super(start); this.a = a; this.b = b; } }; var TokenDeclaration = class extends Node { constructor(start, precedences, conflicts, rules, literals) { super(start); this.precedences = precedences; this.conflicts = conflicts; this.rules = rules; this.literals = literals; } }; var LocalTokenDeclaration = class extends Node { constructor(start, precedences, rules, fallback) { super(start); this.precedences = precedences; this.rules = rules; this.fallback = fallback; } }; var LiteralDeclaration = class extends Node { constructor(start, literal, props) { super(start); this.literal = literal; this.props = props; } }; var ContextDeclaration = class extends Node { constructor(start, id, source) { super(start); this.id = id; this.source = source; } }; var ExternalTokenDeclaration = class extends Node { constructor(start, id, source, tokens) { super(start); this.id = id; this.source = source; this.tokens = tokens; } }; var ExternalSpecializeDeclaration = class extends Node { constructor(start, type, token, id, source, tokens) { super(start); this.type = type; this.token = token; this.id = id; this.source = source; this.tokens = tokens; } }; var ExternalPropSourceDeclaration = class extends Node { constructor(start, id, source) { super(start); this.id = id; this.source = source; } }; var ExternalPropDeclaration = class extends Node { constructor(start, id, externalID, source) { super(start); this.id = id; this.externalID = externalID; this.source = source; } }; var Identifier = class extends Node { constructor(start, name) { super(start); this.name = name; } toString() { return this.name; } }; var Expression = class extends Node { walk(f) { return f(this); } eq(_other) { return false; } }; Expression.prototype.prec = 10; var NameExpression = class extends Expression { constructor(start, id, args) { super(start); this.id = id; this.args = args; } toString() { return this.id.name + (this.args.length ? `<${this.args.join()}>` : ""); } eq(other) { return this.id.name == other.id.name && exprsEq(this.args, other.args); } walk(f) { let args = walkExprs(this.args, f); return f(args == this.args ? this : new NameExpression(this.start, this.id, args)); } }; var SpecializeExpression = class extends Expression { constructor(start, type, props, token, content) { super(start); this.type = type; this.props = props; this.token = token; this.content = content; } toString() { return `@${this.type}[${this.props.join(",")}]<${this.token}, ${this.content}>`; } eq(other) { return this.type == other.type && Prop.eqProps(this.props, other.props) && exprEq(this.token, other.token) && exprEq(this.content, other.content); } walk(f) { let token = this.token.walk(f), content = this.content.walk(f); return f(token == this.token && content == this.content ? this : new SpecializeExpression(this.start, this.type, this.props, token, content)); } }; var InlineRuleExpression = class extends Expression { constructor(start, rule) { super(start); this.rule = rule; } toString() { let rule = this.rule; return `${rule.id}${rule.props.length ? `[${rule.props.join(",")}]` : ""} { ${rule.expr} }`; } eq(other) { let rule = this.rule, oRule = other.rule; return exprEq(rule.expr, oRule.expr) && rule.id.name == oRule.id.name && Prop.eqProps(rule.props, oRule.props); } walk(f) { let rule = this.rule, expr = rule.expr.walk(f); return f(expr == rule.expr ? this : new InlineRuleExpression(this.start, new RuleDeclaration(rule.start, rule.id, rule.props, [], expr))); } }; var ChoiceExpression = class extends Expression { constructor(start, exprs) { super(start); this.exprs = exprs; } toString() { return this.exprs.map((e) => maybeParens(e, this)).join(" | "); } eq(other) { return exprsEq(this.exprs, other.exprs); } walk(f) { let exprs = walkExprs(this.exprs, f); return f(exprs == this.exprs ? this : new ChoiceExpression(this.start, exprs)); } }; ChoiceExpression.prototype.prec = 1; var SequenceExpression = class extends Expression { constructor(start, exprs, markers, empty = false) { super(start); this.exprs = exprs; this.markers = markers; this.empty = empty; } toString() { return this.empty ? "()" : this.exprs.map((e) => maybeParens(e, this)).join(" "); } eq(other) { return exprsEq(this.exprs, other.exprs) && this.markers.every((m, i) => { let om = other.markers[i]; return m.length == om.length && m.every((x, i2) => x.eq(om[i2])); }); } walk(f) { let exprs = walkExprs(this.exprs, f); return f(exprs == this.exprs ? this : new SequenceExpression(this.start, exprs, this.markers, this.empty && !exprs.length)); } }; SequenceExpression.prototype.prec = 2; var ConflictMarker = class extends Node { constructor(start, id, type) { super(start); this.id = id; this.type = type; } toString() { return (this.type == "ambig" ? "~" : "!") + this.id.name; } eq(other) { return this.id.name == other.id.name && this.type == other.type; } }; var RepeatExpression = class extends Expression { constructor(start, expr, kind) { super(start); this.expr = expr; this.kind = kind; } toString() { return maybeParens(this.expr, this) + this.kind; } eq(other) { return exprEq(this.expr, other.expr) && this.kind == other.kind; } walk(f) { let expr = this.expr.walk(f); return f(expr == this.expr ? this : new RepeatExpression(this.start, expr, this.kind)); } }; RepeatExpression.prototype.prec = 3; var LiteralExpression = class extends Expression { // value.length is always > 0 constructor(start, value) { super(start); this.value = value; } toString() { return JSON.stringify(this.value); } eq(other) { return this.value == other.value; } }; var SetExpression = class extends Expression { constructor(start, ranges, inverted) { super(start); this.ranges = ranges; this.inverted = inverted; } toString() { return `[${this.inverted ? "^" : ""}${this.ranges.map(([a, b]) => { return String.fromCodePoint(a) + (b == a + 1 ? "" : "-" + String.fromCodePoint(b)); })}]`; } eq(other) { return this.inverted == other.inverted && this.ranges.length == other.ranges.length && this.ranges.every(([a, b], i) => { let [x, y] = other.ranges[i]; return a == x && b == y; }); } }; var AnyExpression = class extends Expression { constructor(start) { super(start); } toString() { return "_"; } eq() { return true; } }; function walkExprs(exprs, f) { let result = null; for (let i = 0; i < exprs.length; i++) { let expr = exprs[i].walk(f); if (expr != exprs[i] && !result) result = exprs.slice(0, i); if (result) result.push(expr); } return result || exprs; } var CharClasses = { asciiLetter: [[65, 91], [97, 123]], asciiLowercase: [[97, 123]], asciiUppercase: [[65, 91]], digit: [[48, 58]], whitespace: [ [9, 14], [32, 33], [133, 134], [160, 161], [5760, 5761], [8192, 8203], [8232, 8234], [8239, 8240], [8287, 8288], [12288, 12289] ], eof: [[65535, 65535]] }; var CharClass = class extends Expression { constructor(start, type) { super(start); this.type = type; } toString() { return "@" + this.type; } eq(expr) { return this.type == expr.type; } }; function exprEq(a, b) { return a.constructor == b.constructor && a.eq(b); } function exprsEq(a, b) { return a.length == b.length && a.every((e, i) => exprEq(e, b[i])); } var Prop = class extends Node { constructor(start, at, name, value) { super(start); this.at = at; this.name = name; this.value = value; } eq(other) { return this.name == other.name && this.value.length == other.value.length && this.value.every((v, i) => v.value == other.value[i].value && v.name == other.value[i].name); } toString() { let result = (this.at ? "@" : "") + this.name; if (this.value.length) { result += "="; for (let { name, value } of this.value) result += name ? `{${name}}` : /[^\w-]/.test(value) ? JSON.stringify(value) : value; } return result; } static eqProps(a, b) { return a.length == b.length && a.every((p2, i) => p2.eq(b[i])); } }; var PropPart = class extends Node { constructor(start, value, name) { super(start); this.value = value; this.name = name; } }; function maybeParens(node, parent) { return node.prec < parent.prec ? "(" + node.toString() + ")" : node.toString(); } var GenError = class extends Error { }; function hasProps(props) { for (let _p in props) return true; return false; } var termHash = 0; var Term = class { constructor(name, flags, nodeName, props = {}) { this.name = name; this.flags = flags; this.nodeName = nodeName; this.props = props; this.hash = ++termHash; this.id = -1; this.rules = []; } toString() { return this.name; } get nodeType() { return this.top || this.nodeName != null || hasProps(this.props) || this.repeated; } get terminal() { return (this.flags & 1) > 0; } get eof() { return (this.flags & 4) > 0; } get error() { return "error" in this.props; } get top() { return (this.flags & 2) > 0; } get interesting() { return this.flags > 0 || this.nodeName != null; } get repeated() { return (this.flags & 16) > 0; } set preserve(value) { this.flags = value ? this.flags | 8 : this.flags & ~8; } get preserve() { return (this.flags & 8) > 0; } set inline(value) { this.flags = value ? this.flags | 32 : this.flags & ~32; } get inline() { return (this.flags & 32) > 0; } cmp(other) { return this.hash - other.hash; } }; var TermSet = class { constructor() { this.terms = []; this.names = /* @__PURE__ */ Object.create(null); this.tops = []; this.eof = this.term( "\u2404", null, 1 | 4 /* TermFlag.Eof */ ); this.error = this.term( "\u26A0", "\u26A0", 8 /* TermFlag.Preserve */ ); } term(name, nodeName, flags = 0, props = {}) { let term = new Term(name, flags, nodeName, props); this.terms.push(term); this.names[name] = term; return term; } makeTop(nodeName, props) { const term = this.term("@top", nodeName, 2, props); this.tops.push(term); return term; } makeTerminal(name, nodeName, props = {}) { return this.term(name, nodeName, 1, props); } makeNonTerminal(name, nodeName, props = {}) { return this.term(name, nodeName, 0, props); } makeRepeat(name) { return this.term( name, null, 16 /* TermFlag.Repeated */ ); } uniqueName(name) { for (let i = 0; ; i++) { let cur = i ? `${name}-${i}` : name; if (!this.names[cur]) return cur; } } finish(rules) { for (let rule of rules) rule.name.rules.push(rule); this.terms = this.terms.filter((t) => t.terminal || t.preserve || rules.some((r) => r.name == t || r.parts.includes(t))); let names = {}; let nodeTypes = [this.error]; this.error.id = 0; let nextID = 0 + 1; for (let term of this.terms) if (term.id < 0 && term.nodeType && !term.repeated) { term.id = nextID++; nodeTypes.push(term); } let minRepeatTerm = nextID; for (let term of this.terms) if (term.repeated) { term.id = nextID++; nodeTypes.push(term); } this.eof.id = nextID++; for (let term of this.terms) { if (term.id < 0) term.id = nextID++; if (term.name) names[term.id] = term.name; } if (nextID >= 65534) throw new GenError("Too many terms"); return { nodeTypes, names, minRepeatTerm, maxTerm: nextID - 1 }; } }; function cmpSet(a, b, cmp) { if (a.length != b.length) return a.length - b.length; for (let i = 0; i < a.length; i++) { let diff = cmp(a[i], b[i]); if (diff) return diff; } return 0; } var none$3 = []; var Conflicts = class { constructor(precedence, ambigGroups = none$3, cut = 0) { this.precedence = precedence; this.ambigGroups = ambigGroups; this.cut = cut; } join(other) { if (this == Conflicts.none || this == other) return other; if (other == Conflicts.none) return this; return new Conflicts(Math.max(this.precedence, other.precedence), union(this.ambigGroups, other.ambigGroups), Math.max(this.cut, other.cut)); } cmp(other) { return this.precedence - other.precedence || cmpSet(this.ambigGroups, other.ambigGroups, (a, b) => a < b ? -1 : a > b ? 1 : 0) || this.cut - other.cut; } }; Conflicts.none = new Conflicts(0); function union(a, b) { if (a.length == 0 || a == b) return b; if (b.length == 0) return a; let result = a.slice(); for (let value of b) if (!a.includes(value)) result.push(value); return result.sort(); } var ruleID = 0; var Rule = class { constructor(name, parts, conflicts, skip) { this.name = name; this.parts = parts; this.conflicts = conflicts; this.skip = skip; this.id = ruleID++; } cmp(rule) { return this.id - rule.id; } cmpNoName(rule) { return this.parts.length - rule.parts.length || this.skip.hash - rule.skip.hash || this.parts.reduce((r, s, i) => r || s.cmp(rule.parts[i]), 0) || cmpSet(this.conflicts, rule.conflicts, (a, b) => a.cmp(b)); } toString() { return this.name + " -> " + this.parts.join(" "); } get isRepeatWrap() { return this.name.repeated && this.parts.length == 2 && this.parts[0] == this.name; } sameReduce(other) { return this.name == other.name && this.parts.length == other.parts.length && this.isRepeatWrap == other.isRepeatWrap; } }; var MAX_CHAR = 65535; var Edge = class { constructor(from, to, target) { this.from = from; this.to = to; this.target = target; } toString() { return `-> ${this.target.id}[label=${JSON.stringify(this.from < 0 ? "\u03B5" : charFor(this.from) + (this.to > this.from + 1 ? "-" + charFor(this.to - 1) : ""))}]`; } }; function charFor(n) { return n > MAX_CHAR ? "\u221E" : n == 10 ? "\\n" : n == 13 ? "\\r" : n < 32 || n >= 55296 && n < 57343 ? "\\u{" + n.toString(16) + "}" : String.fromCharCode(n); } function minimize(states, start) { let partition = /* @__PURE__ */ Object.create(null); let byAccepting = /* @__PURE__ */ Object.create(null); for (let state of states) { let id = ids(state.accepting); let group = byAccepting[id] || (byAccepting[id] = []); group.push(state); partition[state.id] = group; } for (; ; ) { let split = false, newPartition = /* @__PURE__ */ Object.create(null); for (let state of states) { if (newPartition[state.id]) continue; let group = partition[state.id]; if (group.length == 1) { newPartition[group[0].id] = group; continue; } let parts = []; groups: for (let state2 of group) { for (let p2 of parts) { if (isEquivalent(state2, p2[0], partition)) { p2.push(state2); continue groups; } } parts.push([state2]); } if (parts.length > 1) split = true; for (let p2 of parts) for (let s of p2) newPartition[s.id] = p2; } if (!split) return applyMinimization(states, start, partition); partition = newPartition; } } function isEquivalent(a, b, partition) { if (a.edges.length != b.edges.length) return false; for (let i = 0; i < a.edges.length; i++) { let eA = a.edges[i], eB = b.edges[i]; if (eA.from != eB.from || eA.to != eB.to || partition[eA.target.id] != partition[eB.target.id]) return false; } return true; } function applyMinimization(states, start, partition) { for (let state of states) { for (let i = 0; i < state.edges.length; i++) { let edge = state.edges[i], target = partition[edge.target.id][0]; if (target != edge.target) state.edges[i] = new Edge(edge.from, edge.to, target); } } return partition[start.id][0]; } var stateID = 1; var State$1 = class State { constructor(accepting = [], id = stateID++) { this.accepting = accepting; this.id = id; this.edges = []; } edge(from, to, target) { this.edges.push(new Edge(from, to, target)); } nullEdge(target) { this.edge(-1, -1, target); } compile() { let labeled = /* @__PURE__ */ Object.create(null), localID = 0; let startState = explore(this.closure().sort((a, b) => a.id - b.id)); return minimize(Object.values(labeled), startState); function explore(states) { let newState = labeled[ids(states)] = new State(states.reduce((a, s) => union(a, s.accepting), []), localID++); let out = []; for (let state of states) for (let edge of state.edges) { if (edge.from >= 0) out.push(edge); } let transitions = mergeEdges(out); for (let merged of transitions) { let targets = merged.targets.sort((a, b) => a.id - b.id); newState.edge(merged.from, merged.to, labeled[ids(targets)] || explore(targets)); } return newState; } } closure() { let result = [], seen = /* @__PURE__ */ Object.create(null); function explore(state) { if (seen[state.id]) return; seen[state.id] = true; if (state.edges.some((e) => e.from >= 0) || state.accepting.length > 0 && !state.edges.some((e) => sameSet$1(state.accepting, e.target.accepting))) result.push(state); for (let edge of state.edges) if (edge.from < 0) explore(edge.target); } explore(this); return result; } findConflicts(occurTogether) { let conflicts = [], cycleTerms = this.cycleTerms(); function add(a, b, soft, aEdges, bEdges) { if (a.id < b.id) { [a, b] = [b, a]; soft = -soft; } let found = conflicts.find((c) => c.a == a && c.b == b); if (!found) conflicts.push(new Conflict$1(a, b, soft, exampleFromEdges(aEdges), bEdges && exampleFromEdges(bEdges))); else if (found.soft != soft) found.soft = 0; } this.reachable((state, edges) => { if (state.accepting.length == 0) return; for (let i = 0; i < state.accepting.length; i++) for (let j = i + 1; j < state.accepting.length; j++) add(state.accepting[i], state.accepting[j], 0, edges); state.reachable((s, es) => { if (s != state) for (let term of s.accepting) { let hasCycle = cycleTerms.includes(term); for (let orig of state.accepting) if (term != orig) add(term, orig, hasCycle || cycleTerms.includes(orig) || !occurTogether(term, orig) ? 0 : 1, edges, edges.concat(es)); } }); }); return conflicts; } cycleTerms() { let work = []; this.reachable((state) => { for (let { target } of state.edges) work.push(state, target); }); let table = /* @__PURE__ */ new Map(); let haveCycle = []; for (let i = 0; i < work.length; ) { let from = work[i++], to = work[i++]; let entry = table.get(from); if (!entry) table.set(from, entry = []); if (entry.includes(to)) continue; if (from == to) { if (!haveCycle.includes(from)) haveCycle.push(from); } else { for (let next of entry) work.push(from, next); entry.push(to); } } let result = []; for (let state of haveCycle) { for (let term of state.accepting) { if (!result.includes(term)) result.push(term); } } return result; } reachable(f) { let seen = [], edges = []; (function explore(s) { f(s, edges); seen.push(s); for (let edge of s.edges) if (!seen.includes(edge.target)) { edges.push(edge); explore(edge.target); edges.pop(); } })(this); } toString() { let out = "digraph {\n"; this.reachable((state) => { if (state.accepting.length) out += ` ${state.id} [label=${JSON.stringify(state.accepting.join())}]; `; for (let edge of state.edges) out += ` ${state.id} ${edge}; `; }); return out + "}"; } // Tokenizer data is represented as a single flat array. This // contains regions for each tokenizer state. Region offsets are // used to identify states. // // Each state is laid out as: // - Token group mask // - Offset of the end of the accepting data // - Number of outgoing edges in the state // - Pairs of token masks and term ids that indicate the accepting // states, sorted by precedence // - Triples for the edges: each with a low and high bound and the // offset of the next state. toArray(groupMasks, precedence) { let offsets = []; let data = []; this.reachable((state) => { let start = data.length; let acceptEnd = start + 3 + state.accepting.length * 2; offsets[state.id] = start; data.push(state.stateMask(groupMasks), acceptEnd, state.edges.length); state.accepting.sort((a, b) => precedence.indexOf(a.id) - precedence.indexOf(b.id)); for (let term of state.accepting) data.push(term.id, groupMasks[term.id] || 65535); for (let edge of state.edges) data.push(edge.from, edge.to, -edge.target.id - 1); }); for (let i = 0; i < data.length; i++) if (data[i] < 0) data[i] = offsets[-data[i] - 1]; if (data.length > Math.pow(2, 16)) throw new GenError("Tokenizer tables too big to represent with 16-bit offsets."); return Uint16Array.from(data); } stateMask(groupMasks) { let mask = 0; this.reachable((state) => { for (let term of state.accepting) mask |= groupMasks[term.id] || 65535; }); return mask; } }; var Conflict$1 = class Conflict { constructor(a, b, soft, exampleA, exampleB) { this.a = a; this.b = b; this.soft = soft; this.exampleA = exampleA; this.exampleB = exampleB; } }; function exampleFromEdges(edges) { let str = ""; for (let i = 0; i < edges.length; i++) str += String.fromCharCode(edges[i].from); return str; } function ids(elts) { let result = ""; for (let elt of elts) { if (result.length) result += "-"; result += elt.id; } return result; } function sameSet$1(a, b) { if (a.length != b.length) return false; for (let i = 0; i < a.length; i++) if (a[i] != b[i]) return false; return true; } var MergedEdge = class { constructor(from, to, targets) { this.from = from; this.to = to; this.targets = targets; } }; function mergeEdges(edges) { let separate = [], result = []; for (let edge of edges) { if (!separate.includes(edge.from)) separate.push(edge.from); if (!separate.includes(edge.to)) separate.push(edge.to); } separate.sort((a, b) => a - b); for (let i = 1; i < separate.length; i++) { let from = separate[i - 1], to = separate[i]; let found = []; for (let edge of edges) if (edge.to > from && edge.from < to) { for (let target of edge.target.closure()) if (!found.includes(target)) found.push(target); } if (found.length) result.push(new MergedEdge(from, to, found)); } let eof = edges.filter( (e) => e.from == 65535 && e.to == 65535 /* Seq.End */ ); if (eof.length) { let found = []; for (let edge of eof) for (let target of edge.target.closure()) if (!found.includes(target)) found.push(target); if (found.length) result.push(new MergedEdge(65535, 65535, found)); } return result; } var word = /[\w_-]+/gy; try { word = /[\p{Alphabetic}\d_-]+/ugy; } catch (_) { } var none$2 = []; var Input = class { constructor(string, fileName = null) { this.string = string; this.fileName = fileName; this.type = "sof"; this.value = null; this.start = 0; this.end = 0; this.next(); } lineInfo(pos) { for (let line = 1, cur = 0; ; ) { let next = this.string.indexOf("\n", cur); if (next > -1 && next < pos) { ++line; cur = next + 1; } else { return { line, ch: pos - cur }; } } } message(msg, pos = -1) { let posInfo = this.fileName || ""; if (pos > -1) { let info = this.lineInfo(pos); posInfo += (posInfo ? " " : "") + info.line + ":" + info.ch; } return posInfo ? msg + ` (${posInfo})` : msg; } raise(msg, pos = -1) { throw new GenError(this.message(msg, pos)); } match(pos, re) { let match = re.exec(this.string.slice(pos)); return match ? pos + match[0].length : -1; } next() { let start = this.match(this.end, /^(\s|\/\/.*|\/\*[^]*?\*\/)*/); if (start == this.string.length) return this.set("eof", null, start, start); let next = this.string[start]; if (next == '"') { let end = this.match(start + 1, /^(\\.|[^"\\])*"/); if (end == -1) this.raise("Unterminated string literal", start); return this.set("string", readString(this.string.slice(start + 1, end - 1)), start, end); } else if (next == "'") { let end = this.match(start + 1, /^(\\.|[^'\\])*'/); if (end == -1) this.raise("Unterminated string literal", start); return this.set("string", readString(this.string.slice(start + 1, end - 1)), start, end); } else if (next == "@") { word.lastIndex = start + 1; let m = word.exec(this.string); if (!m) return this.raise("@ without a name", start); return this.set("at", m[0], start, start + 1 + m[0].length); } else if ((next == "$" || next == "!") && this.string[start + 1] == "[") { let end = this.match(start + 2, /^(?:\\.|[^\]\\])*\]/); if (end == -1) this.raise("Unterminated character set", start); return this.set("set", this.string.slice(start + 2, end - 1), start, end); } else if (/[\[\]()!~+*?{}<>\.,|:$=]/.test(next)) { return this.set(next, null, start, start + 1); } else { word.lastIndex = start; let m = word.exec(this.string); if (!m) return this.raise("Unexpected character " + JSON.stringify(next), start); return this.set("id", m[0], start, start + m[0].length); } } set(type, value, start, end) { this.type = type; this.value = value; this.start = start; this.end = end; } eat(type, value = null) { if (this.type == type && (value == null || this.value === value)) { this.next(); return true; } else { return false; } } unexpected() { return this.raise(`Unexpected token '${this.string.slice(this.start, this.end)}'`, this.start); } expect(type, value = null) { let val = this.value; if (this.type != type || !(value == null || val === value)) this.unexpected(); this.next(); return val; } parse() { return parseGrammar(this); } }; function parseGrammar(input) { let start = input.start; let rules = []; let prec = null; let tokens = null; let localTokens = []; let mainSkip = null; let scopedSkip = []; let dialects = []; let context = null; let external = []; let specialized = []; let props = []; let propSources = []; let tops = []; let sawTop = false; let autoDelim = false; while (input.type != "eof") { let start2 = input.start; if (input.eat("at", "top")) { if (input.type != "id") input.raise(`Top rules must have a name`, input.start); tops.push(parseRule(input, parseIdent(input))); sawTop = true; } else if (input.type == "at" && input.value == "tokens") { if (tokens) input.raise(`Multiple @tokens declaractions`, input.start); else tokens = parseTokens(input); } else if (input.eat("at", "local")) { input.expect("id", "tokens"); localTokens.push(parseLocalTokens(input, start2)); } else if (input.eat("at", "context")) { if (context) input.raise(`Multiple @context declarations`, start2); let id = parseIdent(input); input.expect("id", "from"); let source = input.expect("string"); context = new ContextDeclaration(start2, id, source); } else if (input.eat("at", "external")) { if (input.eat("id", "tokens")) external.push(parseExternalTokens(input, start2)); else if (input.eat("id", "prop")) props.push(parseExternalProp(input, start2)); else if (input.eat("id", "extend")) specialized.push(parseExternalSpecialize(input, "extend", start2)); else if (input.eat("id", "specialize")) specialized.push(parseExternalSpecialize(input, "specialize", start2)); else if (input.eat("id", "propSource")) propSources.push(parseExternalPropSource(input, start2)); else input.unexpected(); } else if (input.eat("at", "dialects")) { input.expect("{"); for (let first = true; !input.eat("}"); first = false) { if (!first) input.eat(","); dialects.push(parseIdent(input)); } } else if (input.type == "at" && input.value == "precedence") { if (prec) input.raise(`Multiple precedence declarations`, input.start); prec = parsePrecedence(input); } else if (input.eat("at", "detectDelim")) { autoDelim = true; } else if (input.eat("at", "skip")) { let skip = parseBracedExpr(input); if (input.type == "{") { input.next(); let rules2 = [], topRules = []; while (!input.eat("}")) { if (input.eat("at", "top")) { topRules.push(parseRule(input, parseIdent(input))); sawTop = true; } else { rules2.push(parseRule(input)); } } scopedSkip.push({ expr: skip, topRules, rules: rules2 }); } else { if (mainSkip) input.raise(`Multiple top-level skip declarations`, input.start); mainSkip = skip; } } else { rules.push(parseRule(input)); } } if (!sawTop) return input.raise(`Missing @top declaration`); return new GrammarDeclaration(start, rules, tops, tokens, localTokens, context, external, specialized, propSources, prec, mainSkip, scopedSkip, dialects, props, autoDelim); } function parseRule(input, named) { let start = named ? named.start : input.start; let id = named || parseIdent(input); let props = parseProps(input); let params = []; if (input.eat("<")) while (!input.eat(">")) { if (params.length) input.expect(","); params.push(parseIdent(input)); } let expr = parseBracedExpr(input); return new RuleDeclaration(start, id, props, params, expr); } function parseProps(input) { if (input.type != "[") return none$2; let props = []; input.expect("["); while (!input.eat("]")) { if (props.length) input.expect(","); props.push(parseProp(input)); } return props; } function parseProp(input) { let start = input.start, value = [], name = input.value, at = input.type == "at"; if (!input.eat("at") && !input.eat("id")) input.unexpected(); if (input.eat("=")) for (; ; ) { if (input.type == "string" || input.type == "id") { value.push(new PropPart(input.start, input.value, null)); input.next(); } else if (input.eat(".")) { value.push(new PropPart(input.start, ".", null)); } else if (input.eat("{")) { value.push(new PropPart(input.start, null, input.expect("id"))); input.expect("}"); } else { break; } } return new Prop(start, at, name, value); } function parseBracedExpr(input) { input.expect("{"); let expr = parseExprChoice(input); input.expect("}"); return expr; } var SET_MARKER = "\uFDDA"; function parseExprInner(input) { let start = input.start; if (input.eat("(")) { if (input.eat(")")) return new SequenceExpression(start, none$2, [none$2, none$2]); let expr = parseExprChoice(input); input.expect(")"); return expr; } else if (input.type == "string") { let value = input.value; input.next(); if (value.length == 0) return new SequenceExpression(start, none$2, [none$2, none$2]); return new LiteralExpression(start, value); } else if (input.eat("id", "_")) { return new AnyExpression(start); } else if (input.type == "set") { let content = input.value, invert = input.string[input.start] == "!"; let unescaped = readString(content.replace(/\\.|-|"/g, (m) => { return m == "-" ? SET_MARKER : m == '"' ? '\\"' : m; })); let ranges = []; for (let pos = 0; pos < unescaped.length; ) { let code = unescaped.codePointAt(pos); pos += code > 65535 ? 2 : 1; if (pos < unescaped.length - 1 && unescaped[pos] == SET_MARKER) { let end = unescaped.codePointAt(pos + 1); pos += end > 65535 ? 3 : 2; if (end < code) input.raise("Invalid character range", input.start); addRange(input, ranges, code, end + 1); } else { if (code == SET_MARKER.charCodeAt(0)) code = 45; addRange(input, ranges, code, code + 1); } } input.next(); return new SetExpression(start, ranges.sort((a, b) => a[0] - b[0]), invert); } else if (input.type == "at" && (input.value == "specialize" || input.value == "extend")) { let { start: start2, value } = input; input.next(); let props = parseProps(input); input.expect("<"); let token = parseExprChoice(input), content; if (input.eat(",")) { content = parseExprChoice(input); } else if (token instanceof LiteralExpression) { content = token; } else { input.raise(`@${value} requires two arguments when its first argument isn't a literal string`); } input.expect(">"); return new SpecializeExpression(start2, value, props, token, content); } else if (input.type == "at" && CharClasses.hasOwnProperty(input.value)) { let cls = new CharClass(input.start, input.value); input.next(); return cls; } else if (input.type == "[") { let rule = parseRule(input, new Identifier(start, "_anon")); if (rule.params.length) input.raise(`Inline rules can't have parameters`, rule.start); return new InlineRuleExpression(start, rule); } else { let id = parseIdent(input); if (input.type == "[" || input.type == "{") { let rule = parseRule(input, id); if (rule.params.length) input.raise(`Inline rules can't have parameters`, rule.start); return new InlineRuleExpression(start, rule); } else { if (input.eat(".") && id.name == "std" && CharClasses.hasOwnProperty(input.value)) { let cls = new CharClass(start, input.value); input.next(); return cls; } return new NameExpression(start, id, parseArgs(input)); } } } function parseArgs(input) { let args = []; if (input.eat("<")) while (!input.eat(">")) { if (args.length) input.expect(","); args.push(parseExprChoice(input)); } return args; } function addRange(input, ranges, from, to) { if (!ranges.every(([a, b]) => b <= from || a >= to)) input.raise("Overlapping character range", input.start); ranges.push([from, to]); } function parseExprSuffix(input) { let start = input.start; let expr = parseExprInner(input); for (; ; ) { let kind = input.type; if (input.eat("*") || input.eat("?") || input.eat("+")) expr = new RepeatExpression(start, expr, kind); else return expr; } } function endOfSequence(input) { return input.type == "}" || input.type == ")" || input.type == "|" || input.type == "/" || input.type == "/\\" || input.type == "{" || input.type == "," || input.type == ">"; } function parseExprSequence(input) { let start = input.start, exprs = [], markers = [none$2]; do { for (; ; ) { let localStart = input.start, markerType; if (input.eat("~")) markerType = "ambig"; else if (input.eat("!")) markerType = "prec"; else break; markers[markers.length - 1] = markers[markers.length - 1].concat(new ConflictMarker(localStart, parseIdent(input), markerType)); } if (endOfSequence(input)) break; exprs.push(parseExprSuffix(input)); markers.push(none$2); } while (!endOfSequence(input)); if (exprs.length == 1 && markers.every((ms) => ms.length == 0)) return exprs[0]; return new SequenceExpression(start, exprs, markers, !exprs.length); } function parseExprChoice(input) { let start = input.start, left = parseExprSequence(input); if (!input.eat("|")) return left; let exprs = [left]; do { exprs.push(parseExprSequence(input)); } while (input.eat("|")); let empty = exprs.find((s) => s instanceof SequenceExpression && s.empty); if (empty) input.raise("Empty expression in choice operator. If this is intentional, use () to make it explicit.", empty.start); return new ChoiceExpression(start, exprs); } function parseIdent(input) { if (input.type != "id") input.unexpected(); let start = input.start, name = input.value; input.next(); return new Identifier(start, name); } function parsePrecedence(input) { let start = input.start; input.next(); input.expect("{"); let items = []; while (!input.eat("}")) { if (items.length) input.eat(","); items.push({ id: parseIdent(input), type: input.eat("at", "left") ? "left" : input.eat("at", "right") ? "right" : input.eat("at", "cut") ? "cut" : null }); } return new PrecDeclaration(start, items); } function parseTokens(input) { let start = input.start; input.next(); input.expect("{"); let tokenRules = []; let literals = []; let precedences = []; let conflicts = []; while (!input.eat("}")) { if (input.type == "at" && input.value == "precedence") { precedences.push(parseTokenPrecedence(input)); } else if (input.type == "at" && input.value == "conflict") { conflicts.push(parseTokenConflict(input)); } else if (input.type == "string") { literals.push(new LiteralDeclaration(input.start, input.expect("string"), parseProps(input))); } else { tokenRules.push(parseRule(input)); } } return new TokenDeclaration(start, precedences, conflicts, tokenRules, literals); } function parseLocalTokens(input, start) { input.expect("{"); let tokenRules = []; let precedences = []; let fallback = null; while (!input.eat("}")) { if (input.type == "at" && input.value == "precedence") { precedences.push(parseTokenPrecedence(input)); } else if (input.eat("at", "else") && !fallback) { fallback = { id: parseIdent(input), props: parseProps(input) }; } else { tokenRules.push(parseRule(input)); } } return new LocalTokenDeclaration(start, precedences, tokenRules, fallback); } function parseTokenPrecedence(input) { let start = input.start; input.next(); input.expect("{"); let tokens = []; while (!input.eat("}")) { if (tokens.length) input.eat(","); let expr = parseExprInner(input); if (expr instanceof LiteralExpression || expr instanceof NameExpression) tokens.push(expr); else input.raise(`Invalid expression in token precedences`, expr.start); } return new TokenPrecDeclaration(start, tokens); } function parseTokenConflict(input) { let start = input.start; input.next(); input.expect("{"); let a = parseExprInner(input); if (!(a instanceof LiteralExpression || a instanceof NameExpression)) input.raise(`Invalid expression in token conflict`, a.start); input.eat(","); let b = parseExprInner(input); if (!(b instanceof LiteralExpression || b instanceof NameExpression)) input.raise(`Invalid expression in token conflict`, b.start); input.expect("}"); return new TokenConflictDeclaration(start, a, b); } function parseExternalTokenSet(input) { let tokens = []; input.expect("{"); while (!input.eat("}")) { if (tokens.length) input.eat(","); let id = parseIdent(input); let props = parseProps(input); tokens.push({ id, props }); } return tokens; } function parseExternalTokens(input, start) { let id = parseIdent(input); input.expect("id", "from"); let from = input.expect("string"); return new ExternalTokenDeclaration(start, id, from, parseExternalTokenSet(input)); } function parseExternalSpecialize(input, type, start) { let token = parseBracedExpr(input); let id = parseIdent(input); input.expect("id", "from"); let from = input.expect("string"); return new ExternalSpecializeDeclaration(start, type, token, id, from, parseExternalTokenSet(input)); } function parseExternalPropSource(input, start) { let id = parseIdent(input); input.expect("id", "from"); return new ExternalPropSourceDeclaration(start, id, input.expect("string")); } function parseExternalProp(input, start) { let externalID = parseIdent(input); let id = input.eat("id", "as") ? parseIdent(input) : externalID; input.expect("id", "from"); let from = input.expect("string"); return new ExternalPropDeclaration(start, id, externalID, from); } function readString(string) { let point = /\\(?:u\{([\da-f]+)\}|u([\da-f]{4})|x([\da-f]{2})|([ntbrf0])|(.))|[^]/yig; let out = "", m; while (m = point.exec(string)) { let [all, u1, u2, u3, single, unknown] = m; if (u1 || u2 || u3) out += String.fromCodePoint(parseInt(u1 || u2 || u3, 16)); else if (single) out += single == "n" ? "\n" : single == "t" ? " " : single == "0" ? "\0" : single == "r" ? "\r" : single == "f" ? "\f" : "\b"; else if (unknown) out += unknown; else out += all; } return out; } function hash(a, b) { return (a << 5) + a + b; } function hashString(h, s) { for (let i = 0; i < s.length; i++) h = hash(h, s.charCodeAt(i)); return h; } var verbose = typeof process != "undefined" && process.env.LOG || ""; var timing = /\btime\b/.test(verbose); var time = timing ? (label, f) => { let t0 = Date.now(); let result = f(); console.log(`${label} (${((Date.now() - t0) / 1e3).toFixed(2)}s)`); return result; } : (_label, f) => f(); var Pos2 = class { constructor(rule, pos, ahead, ambigAhead, skipAhead, via) { this.rule = rule; this.pos = pos; this.ahead = ahead; this.ambigAhead = ambigAhead; this.skipAhead = skipAhead; this.via = via; this.hash = 0; } finish() { let h = hash(hash(this.rule.id, this.pos), this.skipAhead.hash); for (let a of this.ahead) h = hash(h, a.hash); for (let group of this.ambigAhead) h = hashString(h, group); this.hash = h; return this; } get next() { return this.pos < this.rule.parts.length ? this.rule.parts[this.pos] : null; } advance() { return new Pos2(this.rule, this.pos + 1, this.ahead, this.ambigAhead, this.skipAhead, this.via).finish(); } get skip() { return this.pos == this.rule.parts.length ? this.skipAhead : this.rule.skip; } cmp(pos) { return this.rule.cmp(pos.rule) || this.pos - pos.pos || this.skipAhead.hash - pos.skipAhead.hash || cmpSet(this.ahead, pos.ahead, (a, b) => a.cmp(b)) || cmpSet(this.ambigAhead, pos.ambigAhead, cmpStr); } eqSimple(pos) { return pos.rule == this.rule && pos.pos == this.pos; } toString() { let parts = this.rule.parts.map((t) => t.name); parts.splice(this.pos, 0, "\xB7"); return `${this.rule.name} -> ${parts.join(" ")}`; } eq(other) { return this == other || this.hash == other.hash && this.rule == other.rule && this.pos == other.pos && this.skipAhead == other.skipAhead && sameSet(this.ahead, other.ahead) && sameSet(this.ambigAhead, other.ambigAhead); } trail(maxLen = 60) { let result = []; for (let pos = this; pos; pos = pos.via) { for (let i = pos.pos - 1; i >= 0; i--) result.push(pos.rule.parts[i]); } let value = result.reverse().join(" "); if (value.length > maxLen) value = value.slice(value.length - maxLen).replace(/.*? /, "\u2026 "); return value; } conflicts(pos = this.pos) { let result = this.rule.conflicts[pos]; if (pos == this.rule.parts.length && this.ambigAhead.length) result = result.join(new Conflicts(0, this.ambigAhead)); return result; } static addOrigins(group, context) { let result = group.slice(); for (let i = 0; i < result.length; i++) { let next = result[i]; if (next.pos == 0) for (let pos of context) { if (pos.next == next.rule.name && !result.includes(pos)) result.push(pos); } } return result; } }; function conflictsAt(group) { let result = Conflicts.none; for (let pos of group) result = result.join(pos.conflicts()); return result; } function compareRepeatPrec(a, b) { for (let pos of a) if (pos.rule.name.repeated) { for (let posB of b) if (posB.rule.name == pos.rule.name) { if (pos.rule.isRepeatWrap && pos.pos == 2) return 1; if (posB.rule.isRepeatWrap && posB.pos == 2) return -1; } } return 0; } function cmpStr(a, b) { return a < b ? -1 : a > b ? 1 : 0; } function termsAhead(rule, pos, after, first) { let found = []; for (let i = pos + 1; i < rule.parts.length; i++) { let next = rule.parts[i], cont = false; if (next.terminal) { addTo(next, found); } else for (let term of first[next.name]) { if (term == null) cont = true; else addTo(term, found); } if (!cont) return found; } for (let a of after) addTo(a, found); return found; } function eqSet(a, b) { if (a.length != b.length) return false; for (let i = 0; i < a.length; i++) if (!a[i].eq(b[i])) return false; return true; } function sameSet(a, b) { if (a.length != b.length) return false; for (let i = 0; i < a.length; i++) if (a[i] != b[i]) return false; return true; } var Shift = class { constructor(term, target) { this.term = term; this.target = target; } eq(other) { return other instanceof Shift && this.term == other.term && other.target.id == this.target.id; } cmp(other) { return other instanceof Reduce ? -1 : this.term.id - other.term.id || this.target.id - other.target.id; } matches(other, mapping) { return other instanceof Shift && mapping[other.target.id] == mapping[this.target.id]; } toString() { return "s" + this.target.id; } map(mapping, states) { let mapped = states[mapping[this.target.id]]; return mapped == this.target ? this : new Shift(this.term, mapped); } }; var Reduce = class { constructor(term, rule) { this.term = term; this.rule = rule; } eq(other) { return other instanceof Reduce && this.term == other.term && other.rule.sameReduce(this.rule); } cmp(other) { return other instanceof Shift ? 1 : this.term.id - other.term.id || this.rule.name.id - other.rule.name.id || this.rule.parts.length - other.rule.parts.length; } matches(other, mapping) { return other instanceof Reduce && other.rule.sameReduce(this.rule); } toString() { return `${this.rule.name.name}(${this.rule.parts.length})`; } map() { return this; } }; function hashPositions(set) { let h = 5381; for (let pos of set) h = hash(h, pos.hash); return h; } var ConflictContext = class { constructor(first) { this.first = first; this.conflicts = []; } }; var State2 = class { constructor(id, set, flags = 0, skip, hash2 = hashPositions(set), startRule = null) { this.id = id; this.set = set; this.flags = flags; this.skip = skip; this.hash = hash2; this.startRule = startRule; this.actions = []; this.actionPositions = []; this.goto = []; this.tokenGroup = -1; this.defaultReduce = null; this._actionsByTerm = null; } toString() { let actions = this.actions.map((t) => t.term + "=" + t).join(",") + (this.goto.length ? " | " + this.goto.map((g) => g.term + "=" + g).join(",") : ""); return this.id + ": " + this.set.filter((p2) => p2.pos > 0).join() + (this.defaultReduce ? ` always ${this.defaultReduce.name}(${this.defaultReduce.parts.length})` : actions.length ? "\n " + actions : ""); } addActionInner(value, positions) { check: for (let i = 0; i < this.actions.length; i++) { let action = this.actions[i]; if (action.term == value.term) { if (action.eq(value)) return null; let fullPos = Pos2.addOrigins(positions, this.set), actionFullPos = Pos2.addOrigins(this.actionPositions[i], this.set); let conflicts = conflictsAt(fullPos), actionConflicts = conflictsAt(actionFullPos); let diff = compareRepeatPrec(fullPos, actionFullPos) || conflicts.precedence - actionConflicts.precedence; if (diff > 0) { this.actions.splice(i, 1); this.actionPositions.splice(i, 1); i--; continue check; } else if (diff < 0) { return null; } else if (conflicts.ambigGroups.some((g) => actionConflicts.ambigGroups.includes(g))) { continue check; } else { return action; } } } this.actions.push(value); this.actionPositions.push(positions); return null; } addAction(value, positions, context) { let conflict = this.addActionInner(value, positions); if (conflict) { let conflictPos = this.actionPositions[this.actions.indexOf(conflict)][0]; let rules = [positions[0].rule.name, conflictPos.rule.name]; if (context.conflicts.some((c) => c.rules.some((r) => rules.includes(r)))) return; let error; if (conflict instanceof Shift) error = `shift/reduce conflict between ${conflictPos} and ${positions[0].rule}`; else error = `reduce/reduce conflict between ${conflictPos.rule} and ${positions[0].rule}`; error += ` With input: ${positions[0].trail(70)} \xB7 ${value.term} \u2026`; if (conflict instanceof Shift) error += findConflictShiftSource(positions[0], conflict.term, context.first); error += findConflictOrigin(conflictPos, positions[0]); context.conflicts.push(new Conflict2(error, rules)); } } getGoto(term) { return this.goto.find((a) => a.term == term); } hasSet(set) { return eqSet(this.set, set); } actionsByTerm() { let result = this._actionsByTerm; if (!result) { this._actionsByTerm = result = /* @__PURE__ */ Object.create(null); for (let action of this.actions) (result[action.term.id] || (result[action.term.id] = [])).push(action); } return result; } finish() { if (this.actions.length) { let first = this.actions[0]; if (first instanceof Reduce) { let { rule } = first; if (this.actions.every((a) => a instanceof Reduce && a.rule.sameReduce(rule))) this.defaultReduce = rule; } } this.actions.sort((a, b) => a.cmp(b)); this.goto.sort((a, b) => a.cmp(b)); } eq(other) { let dThis = this.defaultReduce, dOther = other.defaultReduce; if (dThis || dOther) return dThis && dOther ? dThis.sameReduce(dOther) : false; return this.skip == other.skip && this.tokenGroup == other.tokenGroup && eqSet(this.actions, other.actions) && eqSet(this.goto, other.goto); } }; function closure(set, first) { let added = [], redo2 = []; function addFor(name, ahead, ambigAhead, skipAhead, via) { for (let rule of name.rules) { let add = added.find((a) => a.rule == rule); if (!add) { let existing = set.find((p2) => p2.pos == 0 && p2.rule == rule); add = existing ? new Pos2(rule, 0, existing.ahead.slice(), existing.ambigAhead, existing.skipAhead, existing.via) : new Pos2(rule, 0, [], none$1, skipAhead, via); added.push(add); } if (add.skipAhead != skipAhead) throw new GenError("Inconsistent skip sets after " + via.trail()); add.ambigAhead = union(add.ambigAhead, ambigAhead); for (let term of ahead) if (!add.ahead.includes(term)) { add.ahead.push(term); if (add.rule.parts.length && !add.rule.parts[0].terminal) addTo(add, redo2); } } } for (let pos of set) { let next = pos.next; if (next && !next.terminal) addFor(next, termsAhead(pos.rule, pos.pos, pos.ahead, first), pos.conflicts(pos.pos + 1).ambigGroups, pos.pos == pos.rule.parts.length - 1 ? pos.skipAhead : pos.rule.skip, pos); } while (redo2.length) { let add = redo2.pop(); addFor(add.rule.parts[0], termsAhead(add.rule, 0, add.ahead, first), union(add.rule.conflicts[1].ambigGroups, add.rule.parts.length == 1 ? add.ambigAhead : none$1), add.rule.parts.length == 1 ? add.skipAhead : add.rule.skip, add); } let result = set.slice(); for (let add of added) { add.ahead.sort((a, b) => a.hash - b.hash); add.finish(); let origIndex = set.findIndex((p2) => p2.pos == 0 && p2.rule == add.rule); if (origIndex > -1) result[origIndex] = add; else result.push(add); } return result.sort((a, b) => a.cmp(b)); } function addTo(value, array) { if (!array.includes(value)) array.push(value); } function computeFirstSets(terms) { let table = /* @__PURE__ */ Object.create(null); for (let t of terms.terms) if (!t.terminal) table[t.name] = []; for (; ; ) { let change = false; for (let nt of terms.terms) if (!nt.terminal) for (let rule of nt.rules) { let set = table[nt.name]; let found = false, startLen = set.length; for (let part of rule.parts) { found = true; if (part.terminal) { addTo(part, set); } else { for (let t of table[part.name]) { if (t == null) found = false; else addTo(t, set); } } if (found) break; } if (!found) addTo(null, set); if (set.length > startLen) change = true; } if (!change) return table; } } var Core = class { constructor(set, state) { this.set = set; this.state = state; } }; var Conflict2 = class { constructor(error, rules) { this.error = error; this.rules = rules; } }; function findConflictOrigin(a, b) { if (a.eqSimple(b)) return ""; function via(root, start) { let hist = []; for (let p2 = start.via; !p2.eqSimple(root); p2 = p2.via) hist.push(p2); if (!hist.length) return ""; hist.unshift(start); return hist.reverse().map((p2, i) => "\n" + " ".repeat(i + 1) + (p2 == start ? "" : "via ") + p2).join(""); } for (let p2 = a; p2; p2 = p2.via) for (let p22 = b; p22; p22 = p22.via) { if (p2.eqSimple(p22)) return "\nShared origin: " + p2 + via(p2, a) + via(p2, b); } return ""; } function findConflictShiftSource(conflictPos, termAfter, first) { let pos = conflictPos, path = []; for (; ; ) { for (let i = pos.pos - 1; i >= 0; i--) path.push(pos.rule.parts[i]); if (!pos.via) break; pos = pos.via; } path.reverse(); let seen = /* @__PURE__ */ new Set(); function explore(pos2, i, hasMatch) { if (i == path.length && hasMatch && !pos2.next) return ` The reduction of ${conflictPos.rule.name} is allowed before ${termAfter} because of this rule: ${hasMatch}`; for (let next; next = pos2.next; ) { if (i < path.length && next == path[i]) { let inner = explore(pos2.advance(), i + 1, hasMatch); if (inner) return inner; } let after = pos2.rule.parts[pos2.pos + 1], match = pos2.pos + 1 == pos2.rule.parts.length ? hasMatch : null; if (after && (after.terminal ? after == termAfter : first[after.name].includes(termAfter))) match = pos2.advance(); for (let rule of next.rules) { let hash2 = (rule.id << 5) + i + (match ? 555 : 0); if (!seen.has(hash2)) { seen.add(hash2); let inner = explore(new Pos2(rule, 0, [], [], next, pos2), i, match); if (inner) return inner; } } if (!next.terminal && first[next.name].includes(null)) pos2 = pos2.advance(); else break; } return ""; } return explore(pos, 0, null); } function buildFullAutomaton(terms, startTerms, first) { let states = [], statesBySetHash = {}; let cores = {}; let t0 = Date.now(); function getState(core, top) { if (core.length == 0) return null; let coreHash = hashPositions(core), byHash = cores[coreHash]; let skip; for (let pos of core) { if (!skip) skip = pos.skip; else if (skip != pos.skip) throw new GenError("Inconsistent skip sets after " + pos.trail()); } if (byHash) { for (let known of byHash) if (eqSet(core, known.set)) { if (known.state.skip != skip) throw new GenError("Inconsistent skip sets after " + known.set[0].trail()); return known.state; } } let set = closure(core, first); let hash2 = hashPositions(set), forHash = statesBySetHash[hash2] || (statesBySetHash[hash2] = []); let found; if (!top) { for (let state of forHash) if (state.hasSet(set)) found = state; } if (!found) { found = new State2(states.length, set, 0, skip, hash2, top); forHash.push(found); states.push(found); if (timing && states.length % 500 == 0) console.log(`${states.length} states after ${((Date.now() - t0) / 1e3).toFixed(2)}s`); } (cores[coreHash] || (cores[coreHash] = [])).push(new Core(core, found)); return found; } for (const startTerm of startTerms) { const startSkip = startTerm.rules.length ? startTerm.rules[0].skip : terms.names["%noskip"]; getState(startTerm.rules.map((rule) => new Pos2(rule, 0, [terms.eof], none$1, startSkip, null).finish()), startTerm); } let conflicts = new ConflictContext(first); for (let filled = 0; filled < states.length; filled++) { let state = states[filled]; let byTerm = [], byTermPos = [], atEnd = []; for (let pos of state.set) { if (pos.pos == pos.rule.parts.length) { if (!pos.rule.name.top) atEnd.push(pos); } else { let next = pos.rule.parts[pos.pos]; let index = byTerm.indexOf(next); if (index < 0) { byTerm.push(next); byTermPos.push([pos]); } else { byTermPos[index].push(pos); } } } for (let i = 0; i < byTerm.length; i++) { let term = byTerm[i], positions = byTermPos[i].map((p2) => p2.advance()); if (term.terminal) { let set = applyCut(positions); let next = getState(set); if (next) state.addAction(new Shift(term, next), byTermPos[i], conflicts); } else { let goto = getState(positions); if (goto) state.goto.push(new Shift(term, goto)); } } let replaced = false; for (let pos of atEnd) for (let ahead of pos.ahead) { let count = state.actions.length; state.addAction(new Reduce(ahead, pos.rule), [pos], conflicts); if (state.actions.length == count) replaced = true; } if (replaced) for (let i = 0; i < state.goto.length; i++) { let start = first[state.goto[i].term.name]; if (!start.some((term) => state.actions.some((a) => a.term == term && a instanceof Shift))) state.goto.splice(i--, 1); } } if (conflicts.conflicts.length) throw new GenError(conflicts.conflicts.map((c) => c.error).join("\n\n")); for (let state of states) state.finish(); if (timing) console.log(`${states.length} states total.`); return states; } function applyCut(set) { let found = null, cut = 1; for (let pos of set) { let value = pos.rule.conflicts[pos.pos - 1].cut; if (value < cut) continue; if (!found || value > cut) { cut = value; found = []; } found.push(pos); } return found || set; } function canMerge(a, b, mapping) { for (let goto of a.goto) for (let other of b.goto) { if (goto.term == other.term && mapping[goto.target.id] != mapping[other.target.id]) return false; } let byTerm = b.actionsByTerm(); for (let action of a.actions) { let setB = byTerm[action.term.id]; if (setB && setB.some((other) => !other.matches(action, mapping))) { if (setB.length == 1) return false; let setA = a.actionsByTerm()[action.term.id]; if (setA.length != setB.length || setA.some((a1) => !setB.some((a2) => a1.matches(a2, mapping)))) return false; } } return true; } function mergeStates(states, mapping) { let newStates = []; for (let state of states) { let newID = mapping[state.id]; if (!newStates[newID]) { newStates[newID] = new State2(newID, state.set, 0, state.skip, state.hash, state.startRule); newStates[newID].tokenGroup = state.tokenGroup; newStates[newID].defaultReduce = state.defaultReduce; } } for (let state of states) { let newID = mapping[state.id], target = newStates[newID]; target.flags |= state.flags; for (let i = 0; i < state.actions.length; i++) { let action = state.actions[i].map(mapping, newStates); if (!target.actions.some((a) => a.eq(action))) { target.actions.push(action); target.actionPositions.push(state.actionPositions[i]); } } for (let goto of state.goto) { let mapped = goto.map(mapping, newStates); if (!target.goto.some((g) => g.eq(mapped))) target.goto.push(mapped); } } return newStates; } var Group = class { constructor(origin, member) { this.origin = origin; this.members = [member]; } }; function samePosSet(a, b) { if (a.length != b.length) return false; for (let i = 0; i < a.length; i++) if (!a[i].eqSimple(b[i])) return false; return true; } function collapseAutomaton(states) { let mapping = [], groups = []; assignGroups: for (let i = 0; i < states.length; i++) { let state = states[i]; if (!state.startRule) for (let j = 0; j < groups.length; j++) { let group = groups[j], other = states[group.members[0]]; if (state.tokenGroup == other.tokenGroup && state.skip == other.skip && !other.startRule && samePosSet(state.set, other.set)) { group.members.push(i); mapping.push(j); continue assignGroups; } } mapping.push(groups.length); groups.push(new Group(groups.length, i)); } function spill(groupIndex, index) { let group = groups[groupIndex], state = states[group.members[index]]; let pop = group.members.pop(); if (index != group.members.length) group.members[index] = pop; for (let i = groupIndex + 1; i < groups.length; i++) { mapping[state.id] = i; if (groups[i].origin == group.origin && groups[i].members.every((id) => canMerge(state, states[id], mapping))) { groups[i].members.push(state.id); return; } } mapping[state.id] = groups.length; groups.push(new Group(group.origin, state.id)); } for (let pass = 1; ; pass++) { let conflicts = false, t0 = Date.now(); for (let g = 0, startLen = groups.length; g < startLen; g++) { let group = groups[g]; for (let i = 0; i < group.members.length - 1; i++) { for (let j = i + 1; j < group.members.length; j++) { let idA = group.members[i], idB = group.members[j]; if (!canMerge(states[idA], states[idB], mapping)) { conflicts = true; spill(g, j--); } } } } if (timing) console.log(`Collapse pass ${pass}${conflicts ? `` : `, done`} (${((Date.now() - t0) / 1e3).toFixed(2)}s)`); if (!conflicts) return mergeStates(states, mapping); } } function mergeIdentical(states) { for (let pass = 1; ; pass++) { let mapping = [], didMerge = false, t0 = Date.now(); let newStates = []; for (let i = 0; i < states.length; i++) { let state = states[i]; let match = newStates.findIndex((s) => state.eq(s)); if (match < 0) { mapping[i] = newStates.length; newStates.push(state); } else { mapping[i] = match; didMerge = true; let other = newStates[match], add = null; for (let pos of state.set) if (!other.set.some((p2) => p2.eqSimple(pos))) (add || (add = [])).push(pos); if (add) other.set = add.concat(other.set).sort((a, b) => a.cmp(b)); } } if (timing) console.log(`Merge identical pass ${pass}${didMerge ? "" : ", done"} (${((Date.now() - t0) / 1e3).toFixed(2)}s)`); if (!didMerge) return states; for (let state of newStates) if (!state.defaultReduce) { state.actions = state.actions.map((a) => a.map(mapping, newStates)); state.goto = state.goto.map((a) => a.map(mapping, newStates)); } for (let i = 0; i < newStates.length; i++) newStates[i].id = i; states = newStates; } } var none$1 = []; function finishAutomaton(full) { return mergeIdentical(collapseAutomaton(full)); } function digitToChar(digit) { let ch = digit + 32; if (ch >= 34) ch++; if (ch >= 92) ch++; return String.fromCharCode(ch); } function encode(value, max = 65535) { if (value > max) throw new Error("Trying to encode a number that's too big: " + value); if (value == 65535) return String.fromCharCode( 126 /* Encode.BigValCode */ ); let result = ""; for (let first = 46; ; first = 0) { let low = value % 46, rest = value - low; result = digitToChar(low + first) + result; if (rest == 0) break; value = rest / 46; } return result; } function encodeArray(values, max = 65535) { let result = '"' + encode(values.length, 4294967295); for (let i = 0; i < values.length; i++) result += encode(values[i], max); result += '"'; return result; } var none = []; var Parts = class { constructor(terms, conflicts) { this.terms = terms; this.conflicts = conflicts; } concat(other) { if (this == Parts.none) return other; if (other == Parts.none) return this; let conflicts = null; if (this.conflicts || other.conflicts) { conflicts = this.conflicts ? this.conflicts.slice() : this.ensureConflicts(); let otherConflicts = other.ensureConflicts(); conflicts[conflicts.length - 1] = conflicts[conflicts.length - 1].join(otherConflicts[0]); for (let i = 1; i < otherConflicts.length; i++) conflicts.push(otherConflicts[i]); } return new Parts(this.terms.concat(other.terms), conflicts); } withConflicts(pos, conflicts) { if (conflicts == Conflicts.none) return this; let array = this.conflicts ? this.conflicts.slice() : this.ensureConflicts(); array[pos] = array[pos].join(conflicts); return new Parts(this.terms, array); } ensureConflicts() { if (this.conflicts) return this.conflicts; let empty = []; for (let i = 0; i <= this.terms.length; i++) empty.push(Conflicts.none); return empty; } }; Parts.none = new Parts(none, null); function p(...terms) { return new Parts(terms, null); } var BuiltRule = class { constructor(id, args, term) { this.id = id; this.args = args; this.term = term; } matches(expr) { return this.id == expr.id.name && exprsEq(expr.args, this.args); } matchesRepeat(expr) { return this.id == "+" && exprEq(expr.expr, this.args[0]); } }; var Builder = class { constructor(text, options) { this.options = options; this.terms = new TermSet(); this.specialized = /* @__PURE__ */ Object.create(null); this.tokenOrigins = /* @__PURE__ */ Object.create(null); this.rules = []; this.built = []; this.ruleNames = /* @__PURE__ */ Object.create(null); this.namespaces = /* @__PURE__ */ Object.create(null); this.namedTerms = /* @__PURE__ */ Object.create(null); this.termTable = /* @__PURE__ */ Object.create(null); this.knownProps = /* @__PURE__ */ Object.create(null); this.dynamicRulePrecedences = []; this.definedGroups = []; this.astRules = []; this.currentSkip = []; time("Parse", () => { this.input = new Input(text, options.fileName); this.ast = this.input.parse(); }); let NP = import_common.NodeProp; for (let prop in NP) { if (NP[prop] instanceof import_common.NodeProp && !NP[prop].perNode) this.knownProps[prop] = { prop: NP[prop], source: { name: prop, from: null } }; } for (let prop of this.ast.externalProps) { this.knownProps[prop.id.name] = { prop: this.options.externalProp ? this.options.externalProp(prop.id.name) : new import_common.NodeProp(), source: { name: prop.externalID.name, from: prop.source } }; } this.dialects = this.ast.dialects.map((d) => d.name); this.tokens = new MainTokenSet(this, this.ast.tokens); this.localTokens = this.ast.localTokens.map((g) => new LocalTokenSet(this, g)); this.externalTokens = this.ast.externalTokens.map((ext) => new ExternalTokenSet(this, ext)); this.externalSpecializers = this.ast.externalSpecializers.map((decl) => new ExternalSpecializer(this, decl)); time("Build rules", () => { let noSkip = this.newName("%noskip", true); this.defineRule(noSkip, []); let mainSkip = this.ast.mainSkip ? this.newName("%mainskip", true) : noSkip; let scopedSkip = [], topRules = []; for (let rule of this.ast.rules) this.astRules.push({ skip: mainSkip, rule }); for (let rule of this.ast.topRules) topRules.push({ skip: mainSkip, rule }); for (let scoped of this.ast.scopedSkip) { let skip = noSkip, found = this.ast.scopedSkip.findIndex((sc, i) => i < scopedSkip.length && exprEq(sc.expr, scoped.expr)); if (found > -1) skip = scopedSkip[found]; else if (this.ast.mainSkip && exprEq(scoped.expr, this.ast.mainSkip)) skip = mainSkip; else if (!isEmpty(scoped.expr)) skip = this.newName("%skip", true); scopedSkip.push(skip); for (let rule of scoped.rules) this.astRules.push({ skip, rule }); for (let rule of scoped.topRules) topRules.push({ skip, rule }); } for (let { rule } of this.astRules) { this.unique(rule.id); } this.currentSkip.push(noSkip); this.skipRules = mainSkip == noSkip ? [mainSkip] : [noSkip, mainSkip]; if (mainSkip != noSkip) this.defineRule(mainSkip, this.normalizeExpr(this.ast.mainSkip)); for (let i = 0; i < this.ast.scopedSkip.length; i++) { let skip = scopedSkip[i]; if (!this.skipRules.includes(skip)) { this.skipRules.push(skip); if (skip != noSkip) this.defineRule(skip, this.normalizeExpr(this.ast.scopedSkip[i].expr)); } } this.currentSkip.pop(); for (let { rule, skip } of topRules.sort((a, b) => a.rule.start - b.rule.start)) { this.unique(rule.id); this.used(rule.id.name); this.currentSkip.push(skip); let { name, props } = this.nodeInfo(rule.props, "a", rule.id.name, none, none, rule.expr); let term = this.terms.makeTop(name, props); this.namedTerms[name] = term; this.defineRule(term, this.normalizeExpr(rule.expr)); this.currentSkip.pop(); } for (let ext of this.externalSpecializers) ext.finish(); for (let { skip, rule } of this.astRules) { if (this.ruleNames[rule.id.name] && isExported(rule) && !rule.params.length) { this.buildRule(rule, [], skip, false); if (rule.expr instanceof SequenceExpression && rule.expr.exprs.length == 0) this.used(rule.id.name); } } }); for (let name in this.ruleNames) { let value = this.ruleNames[name]; if (value) this.warn(`Unused rule '${value.name}'`, value.start); } this.tokens.takePrecedences(); this.tokens.takeConflicts(); for (let lt of this.localTokens) lt.takePrecedences(); for (let { name, group, rule } of this.definedGroups) this.defineGroup(name, group, rule); this.checkGroups(); } unique(id) { if (id.name in this.ruleNames) this.raise(`Duplicate definition of rule '${id.name}'`, id.start); this.ruleNames[id.name] = id; } used(name) { this.ruleNames[name] = null; } newName(base, nodeName = null, props = {}) { for (let i = nodeName ? 0 : 1; ; i++) { let name = i ? `${base}-${i}` : base; if (!this.terms.names[name]) return this.terms.makeNonTerminal(name, nodeName === true ? null : nodeName, props); } } prepareParser() { let rules = time("Simplify rules", () => simplifyRules(this.rules, [ ...this.skipRules, ...this.terms.tops ])); let { nodeTypes, names: termNames, minRepeatTerm, maxTerm } = this.terms.finish(rules); for (let prop in this.namedTerms) this.termTable[prop] = this.namedTerms[prop].id; if (/\bgrammar\b/.test(verbose)) console.log(rules.join("\n")); let startTerms = this.terms.tops.slice(); let first = computeFirstSets(this.terms); let skipInfo = this.skipRules.map((name, id) => { let skip = [], startTokens = [], rules2 = []; for (let rule of name.rules) { if (!rule.parts.length) continue; let start = rule.parts[0]; for (let t of start.terminal ? [start] : first[start.name] || []) if (t && !startTokens.includes(t)) startTokens.push(t); if (start.terminal && rule.parts.length == 1 && !rules2.some((r) => r != rule && r.parts[0] == start)) skip.push(start); else rules2.push(rule); } name.rules = rules2; if (rules2.length) startTerms.push(name); return { skip, rule: rules2.length ? name : null, startTokens, id }; }); let fullTable = time("Build full automaton", () => buildFullAutomaton(this.terms, startTerms, first)); let localTokens = this.localTokens.map((grp, i) => grp.buildLocalGroup(fullTable, skipInfo, i)); let { tokenGroups, tokenPrec, tokenData } = time("Build token groups", () => this.tokens.buildTokenGroups(fullTable, skipInfo, localTokens.length)); let table = time("Finish automaton", () => finishAutomaton(fullTable)); let skipState = findSkipStates(table, this.terms.tops); if (/\blr\b/.test(verbose)) console.log(table.join("\n")); let specialized = []; for (let ext of this.externalSpecializers) specialized.push(ext); for (let name in this.specialized) specialized.push({ token: this.terms.names[name], table: buildSpecializeTable(this.specialized[name]) }); let tokStart = (tokenizer) => { if (tokenizer instanceof ExternalTokenSet) return tokenizer.ast.start; return this.tokens.ast ? this.tokens.ast.start : -1; }; let tokenizers = tokenGroups.concat(this.externalTokens).sort((a, b) => tokStart(a) - tokStart(b)).concat(localTokens); let data = new DataBuilder(); let skipData = skipInfo.map((info) => { let actions = []; for (let term of info.skip) actions.push(term.id, 0, 262144 >> 16); if (info.rule) { let state = table.find((s) => s.startRule == info.rule); for (let action of state.actions) actions.push(action.term.id, state.id, 131072 >> 16); } actions.push( 65535, 0 /* Seq.Done */ ); return data.storeArray(actions); }); let states = time("Finish states", () => { let states2 = new Uint32Array( table.length * 6 /* ParseState.Size */ ); let forceReductions = this.computeForceReductions(table, skipInfo); let finishCx = new FinishStateContext(tokenizers, data, states2, skipData, skipInfo, table, this); for (let s of table) finishCx.finish(s, skipState(s.id), forceReductions[s.id]); return states2; }); let dialects = /* @__PURE__ */ Object.create(null); for (let i = 0; i < this.dialects.length; i++) dialects[this.dialects[i]] = data.storeArray((this.tokens.byDialect[i] || none).map((t) => t.id).concat( 65535 /* Seq.End */ )); let dynamicPrecedences = null; if (this.dynamicRulePrecedences.length) { dynamicPrecedences = /* @__PURE__ */ Object.create(null); for (let { rule, prec } of this.dynamicRulePrecedences) dynamicPrecedences[rule.id] = prec; } let topRules = /* @__PURE__ */ Object.create(null); for (let term of this.terms.tops) topRules[term.nodeName] = [table.find((state) => state.startRule == term).id, term.id]; let precTable = data.storeArray(tokenPrec.concat( 65535 /* Seq.End */ )); let { nodeProps, skippedTypes } = this.gatherNodeProps(nodeTypes); return { states, stateData: data.finish(), goto: computeGotoTable(table), nodeNames: nodeTypes.filter((t) => t.id < minRepeatTerm).map((t) => t.nodeName).join(" "), nodeProps, skippedTypes, maxTerm, repeatNodeCount: nodeTypes.length - minRepeatTerm, tokenizers, tokenData, topRules, dialects, dynamicPrecedences, specialized, tokenPrec: precTable, termNames }; } getParser() { let { states, stateData, goto, nodeNames, nodeProps: rawNodeProps, skippedTypes, maxTerm, repeatNodeCount, tokenizers, tokenData, topRules, dialects, dynamicPrecedences, specialized: rawSpecialized, tokenPrec, termNames } = this.prepareParser(); let specialized = rawSpecialized.map((v) => { if (v instanceof ExternalSpecializer) { let ext = this.options.externalSpecializer(v.ast.id.name, this.termTable); return { term: v.term.id, get: (value, stack) => ext(value, stack) << 1 | (v.ast.type == "extend" ? 1 : 0), external: ext, extend: v.ast.type == "extend" }; } else { return { term: v.token.id, get: (value) => v.table[value] || -1 }; } }); return import_lr.LRParser.deserialize({ version: 14, states, stateData, goto, nodeNames, maxTerm, repeatNodeCount, nodeProps: rawNodeProps.map(({ prop, terms }) => [this.knownProps[prop].prop, ...terms]), propSources: !this.options.externalPropSource ? void 0 : this.ast.externalPropSources.map((s) => this.options.externalPropSource(s.id.name)), skippedNodes: skippedTypes, tokenData, tokenizers: tokenizers.map((tok) => tok.create()), context: !this.ast.context ? void 0 : typeof this.options.contextTracker == "function" ? this.options.contextTracker(this.termTable) : this.options.contextTracker, topRules, dialects, dynamicPrecedences, specialized, tokenPrec, termNames }); } getParserFile() { let { states, stateData, goto, nodeNames, nodeProps: rawNodeProps, skippedTypes, maxTerm, repeatNodeCount, tokenizers: rawTokenizers, tokenData, topRules, dialects: rawDialects, dynamicPrecedences, specialized: rawSpecialized, tokenPrec, termNames } = this.prepareParser(); let mod = this.options.moduleStyle || "es"; let gen = "// This file was generated by lezer-generator. You probably shouldn't edit it.\n", head = gen; let imports = {}, imported = /* @__PURE__ */ Object.create(null); let defined = /* @__PURE__ */ Object.create(null); for (let word2 of KEYWORDS) defined[word2] = true; let exportName = this.options.exportName || "parser"; defined[exportName] = true; let getName = (prefix) => { for (let i = 0; ; i++) { let id = prefix + (i ? "_" + i : ""); if (!defined[id]) return id; } }; let importName = (name, source, prefix = name) => { let spec = name + " from " + source; if (imported[spec]) return imported[spec]; let src = JSON.stringify(source), varName = name; if (name in defined) { varName = getName(prefix); name += `${mod == "cjs" ? ":" : " as"} ${varName}`; } defined[varName] = true; (imports[src] || (imports[src] = [])).push(name); return imported[spec] = varName; }; let lrParser = importName("LRParser", "@lezer/lr"); let tokenizers = rawTokenizers.map((tok) => tok.createSource(importName)); let context = this.ast.context ? importName(this.ast.context.id.name, this.ast.context.source) : null; let nodeProps = rawNodeProps.map(({ prop, terms: terms2 }) => { let { source } = this.knownProps[prop]; let propID = source.from ? importName(source.name, source.from) : JSON.stringify(source.name); return `[${propID}, ${terms2.map(serializePropValue).join(",")}]`; }); function specializationTableString(table) { return "{__proto__:null," + Object.keys(table).map((key) => `${/^(\d+|[a-zA-Z_]\w*)$/.test(key) ? key : JSON.stringify(key)}:${table[key]}`).join(", ") + "}"; } let specHead = ""; let specialized = rawSpecialized.map((v) => { if (v instanceof ExternalSpecializer) { let name = importName(v.ast.id.name, v.ast.source); let ts = this.options.typeScript ? ": any" : ""; return `{term: ${v.term.id}, get: (value${ts}, stack${ts}) => (${name}(value, stack) << 1)${v.ast.type == "extend" ? ` | ${1}` : ""}, external: ${name}${v.ast.type == "extend" ? ", extend: true" : ""}}`; } else { let tableName = getName("spec_" + v.token.name.replace(/\W/g, "")); defined[tableName] = true; specHead += `const ${tableName} = ${specializationTableString(v.table)} `; let ts = this.options.typeScript ? `: keyof typeof ${tableName}` : ""; return `{term: ${v.token.id}, get: (value${ts}) => ${tableName}[value] || -1}`; } }); let propSources = this.ast.externalPropSources.map((s) => importName(s.id.name, s.source)); for (let source in imports) { if (mod == "cjs") head += `const {${imports[source].join(", ")}} = require(${source}) `; else head += `import {${imports[source].join(", ")}} from ${source} `; } head += specHead; function serializePropValue(value) { return typeof value != "string" || /^(true|false|\d+(\.\d+)?|\.\d+)$/.test(value) ? value : JSON.stringify(value); } let dialects = Object.keys(rawDialects).map((d) => `${d}: ${rawDialects[d]}`); let parserStr = `${lrParser}.deserialize({ version: ${14}, states: ${encodeArray(states, 4294967295)}, stateData: ${encodeArray(stateData)}, goto: ${encodeArray(goto)}, nodeNames: ${JSON.stringify(nodeNames)}, maxTerm: ${maxTerm}${context ? `, context: ${context}` : ""}${nodeProps.length ? `, nodeProps: [ ${nodeProps.join(",\n ")} ]` : ""}${propSources.length ? `, propSources: [${propSources.join()}]` : ""}${skippedTypes.length ? `, skippedNodes: ${JSON.stringify(skippedTypes)}` : ""}, repeatNodeCount: ${repeatNodeCount}, tokenData: ${encodeArray(tokenData)}, tokenizers: [${tokenizers.join(", ")}], topRules: ${JSON.stringify(topRules)}${dialects.length ? `, dialects: {${dialects.join(", ")}}` : ""}${dynamicPrecedences ? `, dynamicPrecedences: ${JSON.stringify(dynamicPrecedences)}` : ""}${specialized.length ? `, specialized: [${specialized.join(",")}]` : ""}, tokenPrec: ${tokenPrec}${this.options.includeNames ? `, termNames: ${JSON.stringify(termNames)}` : ""} })`; let terms = []; for (let name in this.termTable) { let id = name; if (KEYWORDS.includes(id)) for (let i = 1; ; i++) { id = "_".repeat(i) + name; if (!(id in this.termTable)) break; } else if (!/^[\w$]+$/.test(name)) { continue; } terms.push(`${id}${mod == "cjs" ? ":" : " ="} ${this.termTable[name]}`); } for (let id = 0; id < this.dialects.length; id++) terms.push(`Dialect_${this.dialects[id]}${mod == "cjs" ? ":" : " ="} ${id}`); return { parser: head + (mod == "cjs" ? `exports.${exportName} = ${parserStr} ` : `export const ${exportName} = ${parserStr} `), terms: mod == "cjs" ? `${gen}module.exports = { ${terms.join(",\n ")} }` : `${gen}export const ${terms.join(",\n ")} ` }; } gatherNonSkippedNodes() { let seen = /* @__PURE__ */ Object.create(null); let work = []; let add = (term) => { if (!seen[term.id]) { seen[term.id] = true; work.push(term); } }; this.terms.tops.forEach(add); for (let i = 0; i < work.length; i++) { for (let rule of work[i].rules) for (let part of rule.parts) add(part); } return seen; } gatherNodeProps(nodeTypes) { let notSkipped = this.gatherNonSkippedNodes(), skippedTypes = []; let nodeProps = []; for (let type of nodeTypes) { if (!notSkipped[type.id] && !type.error) skippedTypes.push(type.id); for (let prop in type.props) { let known = this.knownProps[prop]; if (!known) throw new GenError("No known prop type for " + prop); if (known.source.from == null && (known.source.name == "repeated" || known.source.name == "error")) continue; let rec = nodeProps.find((r) => r.prop == prop); if (!rec) nodeProps.push(rec = { prop, values: {} }); (rec.values[type.props[prop]] || (rec.values[type.props[prop]] = [])).push(type.id); } } return { nodeProps: nodeProps.map(({ prop, values }) => { let terms = []; for (let val in values) { let ids2 = values[val]; if (ids2.length == 1) { terms.push(ids2[0], val); } else { terms.push(-ids2.length); for (let id of ids2) terms.push(id); terms.push(val); } } return { prop, terms }; }), skippedTypes }; } makeTerminal(name, tag, props) { return this.terms.makeTerminal(this.terms.uniqueName(name), tag, props); } computeForceReductions(states, skipInfo) { let reductions = []; let candidates = []; let gotoEdges = /* @__PURE__ */ Object.create(null); for (let state of states) { reductions.push(0); for (let edge of state.goto) { let array = gotoEdges[edge.term.id] || (gotoEdges[edge.term.id] = []); let found = array.find((o) => o.target == edge.target.id); if (found) found.parents.push(state.id); else array.push({ parents: [state.id], target: edge.target.id }); } candidates[state.id] = state.set.filter((pos) => pos.pos > 0 && !pos.rule.name.top).sort((a, b) => b.pos - a.pos || a.rule.parts.length - b.rule.parts.length); } let length1Reductions = /* @__PURE__ */ Object.create(null); function createsCycle(term, startState, parents = null) { let edges = gotoEdges[term]; if (!edges) return false; return edges.some((val) => { let parentIntersection = parents ? parents.filter((id) => val.parents.includes(id)) : val.parents; if (parentIntersection.length == 0) return false; if (val.target == startState) return true; let found = length1Reductions[val.target]; return found != null && createsCycle(found, startState, parentIntersection); }); } for (let state of states) { if (state.defaultReduce && state.defaultReduce.parts.length > 0) { reductions[state.id] = reduceAction(state.defaultReduce, skipInfo); if (state.defaultReduce.parts.length == 1) length1Reductions[state.id] = state.defaultReduce.name.id; } } for (let setSize = 1; ; setSize++) { let done = true; for (let state of states) { if (state.defaultReduce) continue; let set = candidates[state.id]; if (set.length != setSize) { if (set.length > setSize) done = false; continue; } for (let pos of set) { if (pos.pos != 1 || !createsCycle(pos.rule.name.id, state.id)) { reductions[state.id] = reduceAction(pos.rule, skipInfo, pos.pos); if (pos.pos == 1) length1Reductions[state.id] = pos.rule.name.id; break; } } } if (done) break; } return reductions; } substituteArgs(expr, args, params) { if (args.length == 0) return expr; return expr.walk((expr2) => { let found; if (expr2 instanceof NameExpression && (found = params.findIndex((p2) => p2.name == expr2.id.name)) > -1) { let arg = args[found]; if (expr2.args.length) { if (arg instanceof NameExpression && !arg.args.length) return new NameExpression(expr2.start, arg.id, expr2.args); this.raise(`Passing arguments to a parameter that already has arguments`, expr2.start); } return arg; } else if (expr2 instanceof InlineRuleExpression) { let r = expr2.rule, props = this.substituteArgsInProps(r.props, args, params); return props == r.props ? expr2 : new InlineRuleExpression(expr2.start, new RuleDeclaration(r.start, r.id, props, r.params, r.expr)); } else if (expr2 instanceof SpecializeExpression) { let props = this.substituteArgsInProps(expr2.props, args, params); return props == expr2.props ? expr2 : new SpecializeExpression(expr2.start, expr2.type, props, expr2.token, expr2.content); } return expr2; }); } substituteArgsInProps(props, args, params) { let substituteInValue = (value) => { let result2 = value; for (let i = 0; i < value.length; i++) { let part = value[i]; if (!part.name) continue; let found = params.findIndex((p2) => p2.name == part.name); if (found < 0) continue; if (result2 == value) result2 = value.slice(); let expr = args[found]; if (expr instanceof NameExpression && !expr.args.length) result2[i] = new PropPart(part.start, expr.id.name, null); else if (expr instanceof LiteralExpression) result2[i] = new PropPart(part.start, expr.value, null); else this.raise(`Trying to interpolate expression '${expr}' into a prop`, part.start); } return result2; }; let result = props; for (let i = 0; i < props.length; i++) { let prop = props[i], value = substituteInValue(prop.value); if (value != prop.value) { if (result == props) result = props.slice(); result[i] = new Prop(prop.start, prop.at, prop.name, value); } } return result; } conflictsFor(markers) { let here = Conflicts.none, atEnd = Conflicts.none; for (let marker of markers) { if (marker.type == "ambig") { here = here.join(new Conflicts(0, [marker.id.name])); } else { let precs = this.ast.precedences; let index = precs ? precs.items.findIndex((item) => item.id.name == marker.id.name) : -1; if (index < 0) this.raise(`Reference to unknown precedence: '${marker.id.name}'`, marker.id.start); let prec = precs.items[index], value = precs.items.length - index; if (prec.type == "cut") { here = here.join(new Conflicts(0, none, value)); } else { here = here.join(new Conflicts(value << 2)); atEnd = atEnd.join(new Conflicts((value << 2) + (prec.type == "left" ? 1 : prec.type == "right" ? -1 : 0))); } } } return { here, atEnd }; } raise(message, pos = 1) { return this.input.raise(message, pos); } warn(message, pos = -1) { let msg = this.input.message(message, pos); if (this.options.warn) this.options.warn(msg); else console.warn(msg); } defineRule(name, choices) { let skip = this.currentSkip[this.currentSkip.length - 1]; for (let choice of choices) this.rules.push(new Rule(name, choice.terms, choice.ensureConflicts(), skip)); } resolve(expr) { for (let built of this.built) if (built.matches(expr)) return [p(built.term)]; let found = this.tokens.getToken(expr); if (found) return [p(found)]; for (let grp of this.localTokens) { let found2 = grp.getToken(expr); if (found2) return [p(found2)]; } for (let ext of this.externalTokens) { let found2 = ext.getToken(expr); if (found2) return [p(found2)]; } for (let ext of this.externalSpecializers) { let found2 = ext.getToken(expr); if (found2) return [p(found2)]; } let known = this.astRules.find((r) => r.rule.id.name == expr.id.name); if (!known) return this.raise(`Reference to undefined rule '${expr.id.name}'`, expr.start); if (known.rule.params.length != expr.args.length) this.raise(`Wrong number or arguments for '${expr.id.name}'`, expr.start); this.used(known.rule.id.name); return [p(this.buildRule(known.rule, expr.args, known.skip))]; } // For tree-balancing reasons, repeat expressions X+ have to be // normalized to something like // // R -> X | R R // // Returns the `R` term. normalizeRepeat(expr) { let known = this.built.find((b) => b.matchesRepeat(expr)); if (known) return p(known.term); let name = expr.expr.prec < expr.prec ? `(${expr.expr})+` : `${expr.expr}+`; let term = this.terms.makeRepeat(this.terms.uniqueName(name)); this.built.push(new BuiltRule("+", [expr.expr], term)); this.defineRule(term, this.normalizeExpr(expr.expr).concat(p(term, term))); return p(term); } normalizeSequence(expr) { let result = expr.exprs.map((e) => this.normalizeExpr(e)); let builder = this; function complete(start, from, endConflicts) { let { here, atEnd } = builder.conflictsFor(expr.markers[from]); if (from == result.length) return [start.withConflicts(start.terms.length, here.join(endConflicts))]; let choices = []; for (let choice of result[from]) { for (let full of complete(start.concat(choice).withConflicts(start.terms.length, here), from + 1, endConflicts.join(atEnd))) choices.push(full); } return choices; } return complete(Parts.none, 0, Conflicts.none); } normalizeExpr(expr) { if (expr instanceof RepeatExpression && expr.kind == "?") { return [Parts.none, ...this.normalizeExpr(expr.expr)]; } else if (expr instanceof RepeatExpression) { let repeated = this.normalizeRepeat(expr); return expr.kind == "+" ? [repeated] : [Parts.none, repeated]; } else if (expr instanceof ChoiceExpression) { return expr.exprs.reduce((o, e) => o.concat(this.normalizeExpr(e)), []); } else if (expr instanceof SequenceExpression) { return this.normalizeSequence(expr); } else if (expr instanceof LiteralExpression) { return [p(this.tokens.getLiteral(expr))]; } else if (expr instanceof NameExpression) { return this.resolve(expr); } else if (expr instanceof SpecializeExpression) { return [p(this.resolveSpecialization(expr))]; } else if (expr instanceof InlineRuleExpression) { return [p(this.buildRule(expr.rule, none, this.currentSkip[this.currentSkip.length - 1], true))]; } else { return this.raise(`This type of expression ('${expr}') may not occur in non-token rules`, expr.start); } } buildRule(rule, args, skip, inline = false) { let expr = this.substituteArgs(rule.expr, args, rule.params); let { name: nodeName, props, dynamicPrec, inline: explicitInline, group, exported } = this.nodeInfo(rule.props || none, inline ? "pg" : "pgi", rule.id.name, args, rule.params, rule.expr); if (exported && rule.params.length) this.warn(`Can't export parameterized rules`, rule.start); if (exported && inline) this.warn(`Can't export inline rule`, rule.start); let name = this.newName(rule.id.name + (args.length ? "<" + args.join(",") + ">" : ""), nodeName || true, props); if (explicitInline) name.inline = true; if (dynamicPrec) this.registerDynamicPrec(name, dynamicPrec); if ((name.nodeType || exported) && rule.params.length == 0) { if (!nodeName) name.preserve = true; if (!inline) this.namedTerms[exported || rule.id.name] = name; } if (!inline) this.built.push(new BuiltRule(rule.id.name, args, name)); this.currentSkip.push(skip); let parts = this.normalizeExpr(expr); if (parts.length > 100 * (expr instanceof ChoiceExpression ? expr.exprs.length : 1)) this.warn(`Rule ${rule.id.name} is generating a lot (${parts.length}) of choices. Consider splitting it up or reducing the amount of ? or | operator uses.`, rule.start); if (/\brulesize\b/.test(verbose) && parts.length > 10) console.log(`Rule ${rule.id.name}: ${parts.length} variants`); this.defineRule(name, parts); this.currentSkip.pop(); if (group) this.definedGroups.push({ name, group, rule }); return name; } nodeInfo(props, allow, defaultName = null, args = none, params = none, expr, defaultProps) { let result = {}; let name = defaultName && (allow.indexOf("a") > -1 || !ignored(defaultName)) && !/ /.test(defaultName) ? defaultName : null; let dialect = null, dynamicPrec = 0, inline = false, group = null, exported = null; for (let prop of props) { if (!prop.at) { if (!this.knownProps[prop.name]) { let builtin = ["name", "dialect", "dynamicPrecedence", "export", "isGroup"].includes(prop.name) ? ` (did you mean '@${prop.name}'?)` : ""; this.raise(`Unknown prop name '${prop.name}'${builtin}`, prop.start); } result[prop.name] = this.finishProp(prop, args, params); } else if (prop.name == "name") { name = this.finishProp(prop, args, params); if (/ /.test(name)) this.raise(`Node names cannot have spaces ('${name}')`, prop.start); } else if (prop.name == "dialect") { if (allow.indexOf("d") < 0) this.raise("Can't specify a dialect on non-token rules", props[0].start); if (prop.value.length != 1 && !prop.value[0].value) this.raise("The '@dialect' rule prop must hold a plain string value"); let dialectID = this.dialects.indexOf(prop.value[0].value); if (dialectID < 0) this.raise(`Unknown dialect '${prop.value[0].value}'`, prop.value[0].start); dialect = dialectID; } else if (prop.name == "dynamicPrecedence") { if (allow.indexOf("p") < 0) this.raise("Dynamic precedence can only be specified on nonterminals"); if (prop.value.length != 1 || !/^-?(?:10|\d)$/.test(prop.value[0].value)) this.raise("The '@dynamicPrecedence' rule prop must hold an integer between -10 and 10"); dynamicPrec = +prop.value[0].value; } else if (prop.name == "inline") { if (prop.value.length) this.raise("'@inline' doesn't take a value", prop.value[0].start); if (allow.indexOf("i") < 0) this.raise("Inline can only be specified on nonterminals"); inline = true; } else if (prop.name == "isGroup") { if (allow.indexOf("g") < 0) this.raise("'@isGroup' can only be specified on nonterminals"); group = prop.value.length ? this.finishProp(prop, args, params) : defaultName; } else if (prop.name == "export") { if (prop.value.length) exported = this.finishProp(prop, args, params); else exported = defaultName; } else { this.raise(`Unknown built-in prop name '@${prop.name}'`, prop.start); } } if (expr && this.ast.autoDelim && (name || hasProps(result))) { let delim = this.findDelimiters(expr); if (delim) { addToProp(delim[0], "closedBy", delim[1].nodeName); addToProp(delim[1], "openedBy", delim[0].nodeName); } } if (defaultProps && hasProps(defaultProps)) { for (let prop in defaultProps) if (!(prop in result)) result[prop] = defaultProps[prop]; } if (hasProps(result) && !name) this.raise(`Node has properties but no name`, props.length ? props[0].start : expr.start); if (inline && (hasProps(result) || dialect || dynamicPrec)) this.raise(`Inline nodes can't have props, dynamic precedence, or a dialect`, props[0].start); if (inline && name) name = null; return { name, props: result, dialect, dynamicPrec, inline, group, exported }; } finishProp(prop, args, params) { return prop.value.map((part) => { if (part.value) return part.value; let pos = params.findIndex((param) => param.name == part.name); if (pos < 0) this.raise(`Property refers to '${part.name}', but no parameter by that name is in scope`, part.start); let expr = args[pos]; if (expr instanceof NameExpression && !expr.args.length) return expr.id.name; if (expr instanceof LiteralExpression) return expr.value; return this.raise(`Expression '${expr}' can not be used as part of a property value`, part.start); }).join(""); } resolveSpecialization(expr) { let type = expr.type; let { name, props, dialect, exported } = this.nodeInfo(expr.props, "d"); let terminal = this.normalizeExpr(expr.token); if (terminal.length != 1 || terminal[0].terms.length != 1 || !terminal[0].terms[0].terminal) this.raise(`The first argument to '${type}' must resolve to a token`, expr.token.start); let values; if (expr.content instanceof LiteralExpression) values = [expr.content.value]; else if (expr.content instanceof ChoiceExpression && expr.content.exprs.every((e) => e instanceof LiteralExpression)) values = expr.content.exprs.map((expr2) => expr2.value); else return this.raise(`The second argument to '${expr.type}' must be a literal or choice of literals`, expr.content.start); let term = terminal[0].terms[0], token = null; let table = this.specialized[term.name] || (this.specialized[term.name] = []); for (let value of values) { let known = table.find((sp) => sp.value == value); if (known == null) { if (!token) { token = this.makeTerminal(term.name + "/" + JSON.stringify(value), name, props); if (dialect != null) (this.tokens.byDialect[dialect] || (this.tokens.byDialect[dialect] = [])).push(token); } table.push({ value, term: token, type, dialect, name }); this.tokenOrigins[token.name] = { spec: term }; if (name || exported) { if (!name) token.preserve = true; this.namedTerms[exported || name] = token; } } else { if (known.type != type) this.raise(`Conflicting specialization types for ${JSON.stringify(value)} of ${term.name} (${type} vs ${known.type})`, expr.start); if (known.dialect != dialect) this.raise(`Conflicting dialects for specialization ${JSON.stringify(value)} of ${term.name}`, expr.start); if (known.name != name) this.raise(`Conflicting names for specialization ${JSON.stringify(value)} of ${term.name}`, expr.start); if (token && known.term != token) this.raise(`Conflicting specialization tokens for ${JSON.stringify(value)} of ${term.name}`, expr.start); token = known.term; } } return token; } findDelimiters(expr) { if (!(expr instanceof SequenceExpression) || expr.exprs.length < 2) return null; let findToken = (expr2) => { if (expr2 instanceof LiteralExpression) return { term: this.tokens.getLiteral(expr2), str: expr2.value }; if (expr2 instanceof NameExpression && expr2.args.length == 0) { let rule = this.ast.rules.find((r) => r.id.name == expr2.id.name); if (rule) return findToken(rule.expr); let token = this.tokens.rules.find((r) => r.id.name == expr2.id.name); if (token && token.expr instanceof LiteralExpression) return { term: this.tokens.getToken(expr2), str: token.expr.value }; } return null; }; let lastToken = findToken(expr.exprs[expr.exprs.length - 1]); if (!lastToken || !lastToken.term.nodeName) return null; const brackets = ["()", "[]", "{}", "<>"]; let bracket = brackets.find((b) => lastToken.str.indexOf(b[1]) > -1 && lastToken.str.indexOf(b[0]) < 0); if (!bracket) return null; let firstToken = findToken(expr.exprs[0]); if (!firstToken || !firstToken.term.nodeName || firstToken.str.indexOf(bracket[0]) < 0 || firstToken.str.indexOf(bracket[1]) > -1) return null; return [firstToken.term, lastToken.term]; } registerDynamicPrec(term, prec) { this.dynamicRulePrecedences.push({ rule: term, prec }); term.preserve = true; } defineGroup(rule, group, ast) { var _a; let recur = []; let getNamed = (rule2) => { if (rule2.nodeName) return [rule2]; if (recur.includes(rule2)) this.raise(`Rule '${ast.id.name}' cannot define a group because it contains a non-named recursive rule ('${rule2.name}')`, ast.start); let result = []; recur.push(rule2); for (let r of this.rules) if (r.name == rule2) { let names = r.parts.map(getNamed).filter((x) => x.length); if (names.length > 1) this.raise(`Rule '${ast.id.name}' cannot define a group because some choices produce multiple named nodes`, ast.start); if (names.length == 1) for (let n of names[0]) result.push(n); } recur.pop(); return result; }; for (let name of getNamed(rule)) name.props["group"] = (((_a = name.props["group"]) === null || _a === void 0 ? void 0 : _a.split(" ")) || []).concat(group).sort().join(" "); } checkGroups() { let groups = /* @__PURE__ */ Object.create(null), nodeNames = /* @__PURE__ */ Object.create(null); for (let term of this.terms.terms) if (term.nodeName) { nodeNames[term.nodeName] = true; if (term.props["group"]) for (let group of term.props["group"].split(" ")) { (groups[group] || (groups[group] = [])).push(term); } } let names = Object.keys(groups); for (let i = 0; i < names.length; i++) { let name = names[i], terms = groups[name]; if (nodeNames[name]) this.warn(`Group name '${name}' conflicts with a node of the same name`); for (let j = i + 1; j < names.length; j++) { let other = groups[names[j]]; if (terms.some((t) => other.includes(t)) && (terms.length > other.length ? other.some((t) => !terms.includes(t)) : terms.some((t) => !other.includes(t)))) this.warn(`Groups '${name}' and '${names[j]}' overlap without one being a superset of the other`); } } } }; var MinSharedActions = 5; var FinishStateContext = class { constructor(tokenizers, data, stateArray, skipData, skipInfo, states, builder) { this.tokenizers = tokenizers; this.data = data; this.stateArray = stateArray; this.skipData = skipData; this.skipInfo = skipInfo; this.states = states; this.builder = builder; this.sharedActions = []; } findSharedActions(state) { if (state.actions.length < MinSharedActions) return null; let found = null; for (let shared of this.sharedActions) { if ((!found || shared.actions.length > found.actions.length) && shared.actions.every((a) => state.actions.some((b) => b.eq(a)))) found = shared; } if (found) return found; let max = null, scratch = []; for (let i = state.id + 1; i < this.states.length; i++) { let other = this.states[i], fill = 0; if (other.defaultReduce || other.actions.length < MinSharedActions) continue; for (let a of state.actions) for (let b of other.actions) if (a.eq(b)) scratch[fill++] = a; if (fill >= MinSharedActions && (!max || max.length < fill)) { max = scratch; scratch = []; } } if (!max) return null; let result = { actions: max, addr: this.storeActions(max, -1, null) }; this.sharedActions.push(result); return result; } storeActions(actions, skipReduce, shared) { if (skipReduce < 0 && shared && shared.actions.length == actions.length) return shared.addr; let data = []; for (let action of actions) { if (shared && shared.actions.some((a) => a.eq(action))) continue; if (action instanceof Shift) { data.push(action.term.id, action.target.id, 0); } else { let code = reduceAction(action.rule, this.skipInfo); if (code != skipReduce) data.push(action.term.id, code & 65535, code >> 16); } } data.push( 65535 /* Seq.End */ ); if (skipReduce > -1) data.push(2, skipReduce & 65535, skipReduce >> 16); else if (shared) data.push(1, shared.addr & 65535, shared.addr >> 16); else data.push( 0 /* Seq.Done */ ); return this.data.storeArray(data); } finish(state, isSkip, forcedReduce) { let b = this.builder; let skipID = b.skipRules.indexOf(state.skip); let skipTable = this.skipData[skipID], skipTerms = this.skipInfo[skipID].startTokens; let defaultReduce = state.defaultReduce ? reduceAction(state.defaultReduce, this.skipInfo) : 0; let flags = isSkip ? 1 : 0; let skipReduce = -1, shared = null; if (defaultReduce == 0) { if (isSkip) { for (const action of state.actions) if (action instanceof Reduce && action.term.eof) skipReduce = reduceAction(action.rule, this.skipInfo); } if (skipReduce < 0) shared = this.findSharedActions(state); } if (state.set.some((p2) => p2.rule.name.top && p2.pos == p2.rule.parts.length)) flags |= 2; let external = []; for (let i = 0; i < state.actions.length + skipTerms.length; i++) { let term = i < state.actions.length ? state.actions[i].term : skipTerms[i - state.actions.length]; for (; ; ) { let orig = b.tokenOrigins[term.name]; if (orig && orig.spec) { term = orig.spec; continue; } if (orig && orig.external instanceof ExternalTokenSet) addToSet(external, orig.external); break; } } let tokenizerMask = 0; for (let i = 0; i < this.tokenizers.length; i++) { let tok = this.tokenizers[i]; if (external.includes(tok) || tok.groupID == state.tokenGroup) tokenizerMask |= 1 << i; } let base = state.id * 6; this.stateArray[ base + 0 /* ParseState.Flags */ ] = flags; this.stateArray[ base + 1 /* ParseState.Actions */ ] = this.storeActions(defaultReduce ? none : state.actions, skipReduce, shared); this.stateArray[ base + 2 /* ParseState.Skip */ ] = skipTable; this.stateArray[ base + 3 /* ParseState.TokenizerMask */ ] = tokenizerMask; this.stateArray[ base + 4 /* ParseState.DefaultReduce */ ] = defaultReduce; this.stateArray[ base + 5 /* ParseState.ForcedReduce */ ] = forcedReduce; } }; function addToProp(term, prop, value) { let cur = term.props[prop]; if (!cur || cur.split(" ").indexOf(value) < 0) term.props[prop] = cur ? cur + " " + value : value; } function buildSpecializeTable(spec) { let table = /* @__PURE__ */ Object.create(null); for (let { value, term, type } of spec) { let code = type == "specialize" ? 0 : 1; table[value] = term.id << 1 | code; } return table; } function reduceAction(rule, skipInfo, depth = rule.parts.length) { return rule.name.id | 65536 | (rule.isRepeatWrap && depth == rule.parts.length ? 131072 : 0) | (skipInfo.some((i) => i.rule == rule.name) ? 262144 : 0) | depth << 19; } function findArray(data, value) { search: for (let i = 0; ; ) { let next = data.indexOf(value[0], i); if (next == -1 || next + value.length > data.length) break; for (let j = 1; j < value.length; j++) { if (value[j] != data[next + j]) { i = next + 1; continue search; } } return next; } return -1; } function findSkipStates(table, startRules) { let nonSkip = /* @__PURE__ */ Object.create(null); let work = []; let add = (state) => { if (!nonSkip[state.id]) { nonSkip[state.id] = true; work.push(state); } }; for (let state of table) if (state.startRule && startRules.includes(state.startRule)) add(state); for (let i = 0; i < work.length; i++) { for (let a of work[i].actions) if (a instanceof Shift) add(a.target); for (let a of work[i].goto) add(a.target); } return (id) => !nonSkip[id]; } var DataBuilder = class { constructor() { this.data = []; } storeArray(data) { let found = findArray(this.data, data); if (found > -1) return found; let pos = this.data.length; for (let num of data) this.data.push(num); return pos; } finish() { return Uint16Array.from(this.data); } }; function computeGotoTable(states) { let goto = {}; let maxTerm = 0; for (let state of states) { for (let entry of state.goto) { maxTerm = Math.max(entry.term.id, maxTerm); let set = goto[entry.term.id] || (goto[entry.term.id] = {}); (set[entry.target.id] || (set[entry.target.id] = [])).push(state.id); } } let data = new DataBuilder(); let index = []; let offset = maxTerm + 2; for (let term = 0; term <= maxTerm; term++) { let entries = goto[term]; if (!entries) { index.push(1); continue; } let termTable = []; let keys2 = Object.keys(entries); for (let target of keys2) { let list = entries[target]; termTable.push((target == keys2[keys2.length - 1] ? 1 : 0) + (list.length << 1)); termTable.push(+target); for (let source of list) termTable.push(source); } index.push(data.storeArray(termTable) + offset); } if (index.some((n) => n > 65535)) throw new GenError("Goto table too large"); return Uint16Array.from([maxTerm + 1, ...index, ...data.data]); } var TokenGroup = class { constructor(tokens, groupID) { this.tokens = tokens; this.groupID = groupID; } create() { return this.groupID; } createSource() { return String(this.groupID); } }; function addToSet(set, value) { if (!set.includes(value)) set.push(value); } function buildTokenMasks(groups) { let masks = /* @__PURE__ */ Object.create(null); for (let group of groups) { let groupMask = 1 << group.groupID; for (let term of group.tokens) { masks[term.id] = (masks[term.id] || 0) | groupMask; } } return masks; } var TokenArg = class { constructor(name, expr, scope) { this.name = name; this.expr = expr; this.scope = scope; } }; var BuildingRule = class { constructor(name, start, to, args) { this.name = name; this.start = start; this.to = to; this.args = args; } }; var TokenSet = class { constructor(b, ast) { this.b = b; this.ast = ast; this.startState = new State$1(); this.built = []; this.building = []; this.byDialect = /* @__PURE__ */ Object.create(null); this.precedenceRelations = []; this.rules = ast ? ast.rules : none; for (let rule of this.rules) b.unique(rule.id); } getToken(expr) { for (let built of this.built) if (built.matches(expr)) return built.term; let name = expr.id.name; let rule = this.rules.find((r) => r.id.name == name); if (!rule) return null; let { name: nodeName, props, dialect, exported } = this.b.nodeInfo(rule.props, "d", name, expr.args, rule.params.length != expr.args.length ? none : rule.params); let term = this.b.makeTerminal(expr.toString(), nodeName, props); if (dialect != null) (this.byDialect[dialect] || (this.byDialect[dialect] = [])).push(term); if ((term.nodeType || exported) && rule.params.length == 0) { if (!term.nodeType) term.preserve = true; this.b.namedTerms[exported || name] = term; } this.buildRule(rule, expr, this.startState, new State$1([term])); this.built.push(new BuiltRule(name, expr.args, term)); return term; } buildRule(rule, expr, from, to, args = none) { let name = expr.id.name; if (rule.params.length != expr.args.length) this.b.raise(`Incorrect number of arguments for token '${name}'`, expr.start); let building = this.building.find((b) => b.name == name && exprsEq(expr.args, b.args)); if (building) { if (building.to == to) { from.nullEdge(building.start); return; } let lastIndex = this.building.length - 1; while (this.building[lastIndex].name != name) lastIndex--; this.b.raise(`Invalid (non-tail) recursion in token rules: ${this.building.slice(lastIndex).map((b) => b.name).join(" -> ")}`, expr.start); } this.b.used(rule.id.name); let start = new State$1(); from.nullEdge(start); this.building.push(new BuildingRule(name, start, to, expr.args)); this.build(this.b.substituteArgs(rule.expr, expr.args, rule.params), start, to, expr.args.map((e, i) => new TokenArg(rule.params[i].name, e, args))); this.building.pop(); } build(expr, from, to, args) { if (expr instanceof NameExpression) { let name = expr.id.name, arg = args.find((a) => a.name == name); if (arg) return this.build(arg.expr, from, to, arg.scope); let rule; for (let i = 0, lt = this.b.localTokens; i <= lt.length; i++) { let set = i == lt.length ? this.b.tokens : lt[i]; rule = set.rules.find((r) => r.id.name == name); if (rule) break; } if (!rule) return this.b.raise(`Reference to token rule '${name}', which isn't found`, expr.start); this.buildRule(rule, expr, from, to, args); } else if (expr instanceof CharClass) { for (let [a, b] of CharClasses[expr.type]) from.edge(a, b, to); } else if (expr instanceof ChoiceExpression) { for (let choice of expr.exprs) this.build(choice, from, to, args); } else if (isEmpty(expr)) { from.nullEdge(to); } else if (expr instanceof SequenceExpression) { let conflict = expr.markers.find((c) => c.length > 0); if (conflict) this.b.raise("Conflict marker in token expression", conflict[0].start); for (let i = 0; i < expr.exprs.length; i++) { let next = i == expr.exprs.length - 1 ? to : new State$1(); this.build(expr.exprs[i], from, next, args); from = next; } } else if (expr instanceof RepeatExpression) { if (expr.kind == "*") { let loop = new State$1(); from.nullEdge(loop); this.build(expr.expr, loop, loop, args); loop.nullEdge(to); } else if (expr.kind == "+") { let loop = new State$1(); this.build(expr.expr, from, loop, args); this.build(expr.expr, loop, loop, args); loop.nullEdge(to); } else { from.nullEdge(to); this.build(expr.expr, from, to, args); } } else if (expr instanceof SetExpression) { for (let [a, b] of expr.inverted ? invertRanges(expr.ranges) : expr.ranges) rangeEdges(from, to, a, b); } else if (expr instanceof LiteralExpression) { for (let i = 0; i < expr.value.length; i++) { let ch = expr.value.charCodeAt(i); let next = i == expr.value.length - 1 ? to : new State$1(); from.edge(ch, ch + 1, next); from = next; } } else if (expr instanceof AnyExpression) { let mid = new State$1(); from.edge(0, 56320, to); from.edge(56320, MAX_CHAR + 1, to); from.edge(55296, 56320, mid); mid.edge(56320, 57344, to); } else { return this.b.raise(`Unrecognized expression type in token`, expr.start); } } takePrecedences() { let rel = this.precedenceRelations = []; if (this.ast) for (let group of this.ast.precedences) { let prev = []; for (let item of group.items) { let level = []; if (item instanceof NameExpression) { for (let built of this.built) if (item.args.length ? built.matches(item) : built.id == item.id.name) level.push(built.term); } else { let id = JSON.stringify(item.value), found = this.built.find((b) => b.id == id); if (found) level.push(found.term); } if (!level.length) this.b.warn(`Precedence specified for unknown token ${item}`, item.start); for (let term of level) addRel(rel, term, prev); prev = prev.concat(level); } } } precededBy(a, b) { let found = this.precedenceRelations.find((r) => r.term == a); return found && found.after.includes(b); } buildPrecTable(softConflicts) { let precTable = [], rel = this.precedenceRelations.slice(); for (let { a, b, soft } of softConflicts) if (soft) { if (!rel.some((r) => r.term == a) || !rel.some((r) => r.term == b)) continue; if (soft < 0) [a, b] = [b, a]; addRel(rel, b, [a]); addRel(rel, a, []); } add: while (rel.length) { for (let i = 0; i < rel.length; i++) { let record = rel[i]; if (record.after.every((t) => precTable.includes(t.id))) { precTable.push(record.term.id); if (rel.length == 1) break add; rel[i] = rel.pop(); continue add; } } this.b.raise(`Cyclic token precedence relation between ${rel.map((r) => r.term).join(", ")}`); } return precTable; } }; var MainTokenSet = class extends TokenSet { constructor() { super(...arguments); this.explicitConflicts = []; } getLiteral(expr) { let id = JSON.stringify(expr.value); for (let built of this.built) if (built.id == id) return built.term; let name = null, props = {}, dialect = null, exported = null; let decl = this.ast ? this.ast.literals.find((l) => l.literal == expr.value) : null; if (decl) ({ name, props, dialect, exported } = this.b.nodeInfo(decl.props, "da", expr.value)); let term = this.b.makeTerminal(id, name, props); if (dialect != null) (this.byDialect[dialect] || (this.byDialect[dialect] = [])).push(term); if (exported) this.b.namedTerms[exported] = term; this.build(expr, this.startState, new State$1([term]), none); this.built.push(new BuiltRule(id, none, term)); return term; } takeConflicts() { var _a; let resolve = (expr) => { if (expr instanceof NameExpression) { for (let built of this.built) if (built.matches(expr)) return built.term; } else { let id = JSON.stringify(expr.value), found = this.built.find((b) => b.id == id); if (found) return found.term; } this.b.warn(`Precedence specified for unknown token ${expr}`, expr.start); return null; }; for (let c of ((_a = this.ast) === null || _a === void 0 ? void 0 : _a.conflicts) || []) { let a = resolve(c.a), b = resolve(c.b); if (a && b) { if (a.id < b.id) [a, b] = [b, a]; this.explicitConflicts.push({ a, b }); } } } // Token groups are a mechanism for allowing conflicting (matching // overlapping input, without an explicit precedence being given) // tokens to exist in a grammar _if_ they don't occur in the same // place (aren't used in the same states). // // States that use tokens that conflict will raise an error when any // of the conflicting pairs of tokens both occur in that state. // Otherwise, they are assigned a token group, which includes all // the potentially-conflicting tokens they use. If there's already a // group that doesn't have any conflicts with those tokens, that is // reused, otherwise a new group is created. // // So each state has zero or one token groups, and each conflicting // token may belong to one or more groups. Tokens get assigned a // 16-bit bitmask with the groups they belong to set to 1 (all-1s // for non-conflicting tokens). When tokenizing, that mask is // compared to the current state's group (again using all-1s for // group-less states) to determine whether a token is applicable for // this state. // // Extended/specialized tokens are treated as their parent token for // this purpose. buildTokenGroups(states, skipInfo, startID) { let tokens = this.startState.compile(); if (tokens.accepting.length) this.b.raise(`Grammar contains zero-length tokens (in '${tokens.accepting[0].name}')`, this.rules.find((r) => r.id.name == tokens.accepting[0].name).start); if (/\btokens\b/.test(verbose)) console.log(tokens.toString()); let allConflicts = tokens.findConflicts(checkTogether(states, this.b, skipInfo)).filter(({ a, b }) => !this.precededBy(a, b) && !this.precededBy(b, a)); for (let { a, b } of this.explicitConflicts) { if (!allConflicts.some((c) => c.a == a && c.b == b)) allConflicts.push(new Conflict$1(a, b, 0, "", "")); } let softConflicts = allConflicts.filter((c) => c.soft), conflicts = allConflicts.filter((c) => !c.soft); let errors = []; let groups = []; for (let state of states) { if (state.defaultReduce || state.tokenGroup > -1) continue; let terms = [], incompatible = []; let skip = skipInfo[this.b.skipRules.indexOf(state.skip)].startTokens; for (let term of skip) if (state.actions.some((a) => a.term == term)) this.b.raise(`Use of token ${term.name} conflicts with skip rule`); let stateTerms = []; for (let i = 0; i < state.actions.length + (skip ? skip.length : 0); i++) { let term = i < state.actions.length ? state.actions[i].term : skip[i - state.actions.length]; let orig = this.b.tokenOrigins[term.name]; if (orig && orig.spec) term = orig.spec; else if (orig && orig.external) continue; addToSet(stateTerms, term); } if (stateTerms.length == 0) continue; for (let term of stateTerms) { for (let conflict of conflicts) { let conflicting = conflict.a == term ? conflict.b : conflict.b == term ? conflict.a : null; if (!conflicting) continue; if (stateTerms.includes(conflicting) && !errors.some((e) => e.conflict == conflict)) { let example = conflict.exampleA ? ` (example: ${JSON.stringify(conflict.exampleA)}${conflict.exampleB ? ` vs ${JSON.stringify(conflict.exampleB)}` : ""})` : ""; errors.push({ error: `Overlapping tokens ${term.name} and ${conflicting.name} used in same context${example} After: ${state.set[0].trail()}`, conflict }); } addToSet(terms, term); addToSet(incompatible, conflicting); } } let tokenGroup = null; for (let group of groups) { if (incompatible.some((term) => group.tokens.includes(term))) continue; for (let term of terms) addToSet(group.tokens, term); tokenGroup = group; break; } if (!tokenGroup) { tokenGroup = new TokenGroup(terms, groups.length + startID); groups.push(tokenGroup); } state.tokenGroup = tokenGroup.groupID; } if (errors.length) this.b.raise(errors.map((e) => e.error).join("\n\n")); if (groups.length + startID > 16) this.b.raise(`Too many different token groups (${groups.length}) to represent them as a 16-bit bitfield`); let precTable = this.buildPrecTable(softConflicts); return { tokenGroups: groups, tokenPrec: precTable, tokenData: tokens.toArray(buildTokenMasks(groups), precTable) }; } }; var LocalTokenSet = class extends TokenSet { constructor(b, ast) { super(b, ast); this.fallback = null; if (ast.fallback) b.unique(ast.fallback.id); } getToken(expr) { let term = null; if (this.ast.fallback && this.ast.fallback.id.name == expr.id.name) { if (expr.args.length) this.b.raise(`Incorrect number of arguments for ${expr.id.name}`, expr.start); if (!this.fallback) { let { name: nodeName, props, exported } = this.b.nodeInfo(this.ast.fallback.props, "", expr.id.name, none, none); let term2 = this.fallback = this.b.makeTerminal(expr.id.name, nodeName, props); if (term2.nodeType || exported) { if (!term2.nodeType) term2.preserve = true; this.b.namedTerms[exported || expr.id.name] = term2; } this.b.used(expr.id.name); } term = this.fallback; } else { term = super.getToken(expr); } if (term && !this.b.tokenOrigins[term.name]) this.b.tokenOrigins[term.name] = { group: this }; return term; } buildLocalGroup(states, skipInfo, id) { let tokens = this.startState.compile(); if (tokens.accepting.length) this.b.raise(`Grammar contains zero-length tokens (in '${tokens.accepting[0].name}')`, this.rules.find((r) => r.id.name == tokens.accepting[0].name).start); for (let { a, b, exampleA } of tokens.findConflicts(() => true)) { if (!this.precededBy(a, b) && !this.precededBy(b, a)) this.b.raise(`Overlapping tokens ${a.name} and ${b.name} in local token group${exampleA ? ` (example: ${JSON.stringify(exampleA)})` : ""}`); } for (let state of states) { if (state.defaultReduce) continue; let usesThis = null; let usesOther = skipInfo[this.b.skipRules.indexOf(state.skip)].startTokens[0]; for (let { term } of state.actions) { let orig = this.b.tokenOrigins[term.name]; if ((orig === null || orig === void 0 ? void 0 : orig.group) == this) usesThis = term; else usesOther = term; } if (usesThis) { if (usesOther) this.b.raise(`Tokens from a local token group used together with other tokens (${usesThis.name} with ${usesOther.name})`); state.tokenGroup = id; } } let precTable = this.buildPrecTable(none); let tokenData = tokens.toArray({ [id]: 65535 /* Seq.End */ }, precTable); let precOffset = tokenData.length; let fullData = new Uint16Array(tokenData.length + precTable.length + 1); fullData.set(tokenData, 0); fullData.set(precTable, precOffset); fullData[fullData.length - 1] = 65535; return { groupID: id, create: () => new import_lr.LocalTokenGroup(fullData, precOffset, this.fallback ? this.fallback.id : void 0), createSource: (importName) => `new ${importName("LocalTokenGroup", "@lezer/lr")}(${encodeArray(fullData)}, ${precOffset}${this.fallback ? `, ${this.fallback.id}` : ""})` }; } }; function checkTogether(states, b, skipInfo) { let cache = /* @__PURE__ */ Object.create(null); function hasTerm(state, term) { return state.actions.some((a) => a.term == term) || skipInfo[b.skipRules.indexOf(state.skip)].startTokens.includes(term); } return (a, b2) => { if (a.id < b2.id) [a, b2] = [b2, a]; let key = a.id | b2.id << 16, cached = cache[key]; if (cached != null) return cached; return cache[key] = states.some((state) => hasTerm(state, a) && hasTerm(state, b2)); }; } function invertRanges(ranges) { let pos = 0, result = []; for (let [a, b] of ranges) { if (a > pos) result.push([pos, a]); pos = b; } if (pos <= MAX_CODE) result.push([pos, MAX_CODE + 1]); return result; } var ASTRAL = 65536; var GAP_START = 55296; var GAP_END = 57344; var MAX_CODE = 1114111; var LOW_SURR_B = 56320; var HIGH_SURR_B = 57343; function rangeEdges(from, to, low, hi) { if (low < ASTRAL) { if (low < GAP_START) from.edge(low, Math.min(hi, GAP_START), to); if (hi > GAP_END) from.edge(Math.max(low, GAP_END), Math.min(hi, MAX_CHAR + 1), to); low = ASTRAL; } if (hi <= ASTRAL) return; let lowStr = String.fromCodePoint(low), hiStr = String.fromCodePoint(hi - 1); let lowA = lowStr.charCodeAt(0), lowB = lowStr.charCodeAt(1); let hiA = hiStr.charCodeAt(0), hiB = hiStr.charCodeAt(1); if (lowA == hiA) { let hop = new State$1(); from.edge(lowA, lowA + 1, hop); hop.edge(lowB, hiB + 1, to); } else { let midStart = lowA, midEnd = hiA; if (lowB > LOW_SURR_B) { midStart++; let hop = new State$1(); from.edge(lowA, lowA + 1, hop); hop.edge(lowB, HIGH_SURR_B + 1, to); } if (hiB < HIGH_SURR_B) { midEnd--; let hop = new State$1(); from.edge(hiA, hiA + 1, hop); hop.edge(LOW_SURR_B, hiB + 1, to); } if (midStart <= midEnd) { let hop = new State$1(); from.edge(midStart, midEnd + 1, hop); hop.edge(LOW_SURR_B, HIGH_SURR_B + 1, to); } } } function isEmpty(expr) { return expr instanceof SequenceExpression && expr.exprs.length == 0; } function gatherExtTokens(b, tokens) { let result = /* @__PURE__ */ Object.create(null); for (let token of tokens) { b.unique(token.id); let { name, props, dialect } = b.nodeInfo(token.props, "d", token.id.name); let term = b.makeTerminal(token.id.name, name, props); if (dialect != null) (b.tokens.byDialect[dialect] || (b.tokens.byDialect[dialect] = [])).push(term); b.namedTerms[token.id.name] = result[token.id.name] = term; } return result; } function findExtToken(b, tokens, expr) { let found = tokens[expr.id.name]; if (!found) return null; if (expr.args.length) b.raise("External tokens cannot take arguments", expr.args[0].start); b.used(expr.id.name); return found; } function addRel(rel, term, after) { let found = rel.findIndex((r) => r.term == term); if (found < 0) rel.push({ term, after }); else rel[found] = { term, after: rel[found].after.concat(after) }; } var ExternalTokenSet = class { constructor(b, ast) { this.b = b; this.ast = ast; this.tokens = gatherExtTokens(b, ast.tokens); for (let name in this.tokens) this.b.tokenOrigins[this.tokens[name].name] = { external: this }; } getToken(expr) { return findExtToken(this.b, this.tokens, expr); } create() { return this.b.options.externalTokenizer(this.ast.id.name, this.b.termTable); } createSource(importName) { let { source, id: { name } } = this.ast; return importName(name, source); } }; var ExternalSpecializer = class { constructor(b, ast) { this.b = b; this.ast = ast; this.term = null; this.tokens = gatherExtTokens(b, ast.tokens); } finish() { let terms = this.b.normalizeExpr(this.ast.token); if (terms.length != 1 || terms[0].terms.length != 1 || !terms[0].terms[0].terminal) this.b.raise(`The token expression to '@external ${this.ast.type}' must resolve to a token`, this.ast.token.start); this.term = terms[0].terms[0]; for (let name in this.tokens) this.b.tokenOrigins[this.tokens[name].name] = { spec: this.term, external: this }; } getToken(expr) { return findExtToken(this.b, this.tokens, expr); } }; function inlineRules(rules, preserve) { for (let pass = 0; ; pass++) { let inlinable = /* @__PURE__ */ Object.create(null), found; if (pass == 0) for (let rule of rules) { if (rule.name.inline && !inlinable[rule.name.name]) { let group = rules.filter((r) => r.name == rule.name); if (group.some((r) => r.parts.includes(rule.name))) continue; found = inlinable[rule.name.name] = group; } } for (let i = 0; i < rules.length; i++) { let rule = rules[i]; if (!rule.name.interesting && !rule.parts.includes(rule.name) && rule.parts.length < 3 && !preserve.includes(rule.name) && (rule.parts.length == 1 || rules.every((other) => other.skip == rule.skip || !other.parts.includes(rule.name))) && !rule.parts.some((p2) => !!inlinable[p2.name]) && !rules.some((r, j) => j != i && r.name == rule.name)) found = inlinable[rule.name.name] = [rule]; } if (!found) return rules; let newRules = []; for (let rule of rules) { let expand = function(at, conflicts, parts) { if (at == rule.parts.length) { newRules.push(new Rule(rule.name, parts, conflicts, rule.skip)); return; } let next = rule.parts[at], replace = inlinable[next.name]; if (!replace) { expand(at + 1, conflicts.concat(rule.conflicts[at + 1]), parts.concat(next)); return; } for (let r of replace) expand(at + 1, conflicts.slice(0, conflicts.length - 1).concat(conflicts[at].join(r.conflicts[0])).concat(r.conflicts.slice(1, r.conflicts.length - 1)).concat(rule.conflicts[at + 1].join(r.conflicts[r.conflicts.length - 1])), parts.concat(r.parts)); }; if (inlinable[rule.name.name]) continue; if (!rule.parts.some((p2) => !!inlinable[p2.name])) { newRules.push(rule); continue; } expand(0, [rule.conflicts[0]], []); } rules = newRules; } } function mergeRules(rules) { let merged = /* @__PURE__ */ Object.create(null), found; for (let i = 0; i < rules.length; ) { let groupStart = i; let name = rules[i++].name; while (i < rules.length && rules[i].name == name) i++; let size = i - groupStart; if (name.interesting) continue; for (let j = i; j < rules.length; ) { let otherStart = j, otherName = rules[j++].name; while (j < rules.length && rules[j].name == otherName) j++; if (j - otherStart != size || otherName.interesting) continue; let match = true; for (let k = 0; k < size && match; k++) { let a = rules[groupStart + k], b = rules[otherStart + k]; if (a.cmpNoName(b) != 0) match = false; } if (match) found = merged[name.name] = otherName; } } if (!found) return rules; let newRules = []; for (let rule of rules) if (!merged[rule.name.name]) { newRules.push(rule.parts.every((p2) => !merged[p2.name]) ? rule : new Rule(rule.name, rule.parts.map((p2) => merged[p2.name] || p2), rule.conflicts, rule.skip)); } return newRules; } function simplifyRules(rules, preserve) { return mergeRules(inlineRules(rules, preserve)); } function buildParser(text, options = {}) { let builder = new Builder(text, options), parser = builder.getParser(); parser.termTable = builder.termTable; return parser; } var KEYWORDS = [ "await", "break", "case", "catch", "continue", "debugger", "default", "do", "else", "finally", "for", "function", "if", "return", "switch", "throw", "try", "var", "while", "with", "null", "true", "false", "instanceof", "typeof", "void", "delete", "new", "in", "this", "const", "class", "extends", "export", "import", "super", "enum", "implements", "interface", "let", "package", "private", "protected", "public", "static", "yield", "require" ]; function ignored(name) { let first = name[0]; return first == "_" || first.toUpperCase() != first; } function isExported(rule) { return rule.props.some((p2) => p2.at && p2.name == "export"); } // codemirror-lang-orgmode/src/external-tokens.ts var external_tokens_exports = {}; __export(external_tokens_exports, { blockContent_tokenizer: () => blockContent_tokenizer, block_tokenizer: () => block_tokenizer, context_tracker: () => context_tracker, dedentHeading_lookaround: () => dedentHeading_lookaround, endofline_tokenizer: () => endofline_tokenizer, exitAngleLink_tokenizer: () => exitAngleLink_tokenizer, exitRegularLink_tokenizer: () => exitRegularLink_tokenizer, indentHeading_lookaround: () => indentHeading_lookaround, isEndOfTextMarkup_tokenizer: () => isEndOfTextMarkup_tokenizer, isStartOfAngleLink_lookaround: () => isStartOfAngleLink_lookaround, isStartOfPlanningLine_lookaround: () => isStartOfPlanningLine_lookaround, isStartOfRegularLink_lookaround: () => isStartOfRegularLink_lookaround, isStartOfTextMarkup_lookaround: () => isStartOfTextMarkup_lookaround, notStartOfComment_lookaround: () => notStartOfComment_lookaround, notStartOfPlanning_lookaround: () => notStartOfPlanning_lookaround, notStartOfPropertyDrawer_lookaround: () => notStartOfPropertyDrawer_lookaround, object_tokenizer: () => object_tokenizer, plainLink_tokenizer: () => plainLink_tokenizer, planningKeyword_tokenizer: () => planningKeyword_tokenizer, planningValue_tokenizer: () => planningValue_tokenizer, priority_tokenizer: () => priority_tokenizer, propertydrawer_tokenizer: () => propertydrawer_tokenizer, stars_tokenizer: () => stars_tokenizer, startOfComment_lookaround: () => startOfComment_lookaround, startOfHeading_lookaround: () => startOfHeading_lookaround, startOfKeywordComment_lookaround: () => startOfKeywordComment_lookaround, tags_tokenizer: () => tags_tokenizer, title_tokenizer: () => title_tokenizer, todokeyword_tokenizer: () => todokeyword_tokenizer }); var import_lr2 = require("@lezer/lr"); // codemirror-lang-orgmode/src/parser.terms.ts var parser_terms_exports = {}; __export(parser_terms_exports, { AngleLink: () => AngleLink, Block: () => Block, BlockContentCenter: () => BlockContentCenter, BlockContentComment: () => BlockContentComment, BlockContentDynamic: () => BlockContentDynamic, BlockContentExample: () => BlockContentExample, BlockContentExport: () => BlockContentExport, BlockContentQuote: () => BlockContentQuote, BlockContentSpecial: () => BlockContentSpecial, BlockContentSrc: () => BlockContentSrc, BlockContentVerse: () => BlockContentVerse, BlockFooter: () => BlockFooter, BlockHeader: () => BlockHeader, CommentLine: () => CommentLine, Heading: () => Heading, KeywordComment: () => KeywordComment, PlainLink: () => PlainLink, PlanningClosed: () => PlanningClosed, PlanningDeadline: () => PlanningDeadline, PlanningScheduled: () => PlanningScheduled, PlanningValue: () => PlanningValue, Priority: () => Priority, Program: () => Program, PropertyDrawer: () => PropertyDrawer, RegularLink: () => RegularLink, Section: () => Section, Tags: () => Tags, TextBold: () => TextBold, TextCode: () => TextCode, TextItalic: () => TextItalic, TextStrikeThrough: () => TextStrikeThrough, TextUnderline: () => TextUnderline, TextVerbatim: () => TextVerbatim, Title: () => Title, TodoKeyword: () => TodoKeyword, ZerothSection: () => ZerothSection, dedentHeading: () => dedentHeading, endofline: () => endofline, exitAngleLink: () => exitAngleLink, exitRegularLink: () => exitRegularLink, indentHeading: () => indentHeading, isEndOfTextBold: () => isEndOfTextBold, isEndOfTextCode: () => isEndOfTextCode, isEndOfTextItalic: () => isEndOfTextItalic, isEndOfTextStrikeThrough: () => isEndOfTextStrikeThrough, isEndOfTextUnderline: () => isEndOfTextUnderline, isEndOfTextVerbatim: () => isEndOfTextVerbatim, isStartOfAngleLink: () => isStartOfAngleLink, isStartOfPlanningLine: () => isStartOfPlanningLine, isStartOfRegularLink: () => isStartOfRegularLink, isStartOfTextBold: () => isStartOfTextBold, isStartOfTextCode: () => isStartOfTextCode, isStartOfTextItalic: () => isStartOfTextItalic, isStartOfTextStrikeThrough: () => isStartOfTextStrikeThrough, isStartOfTextUnderline: () => isStartOfTextUnderline, isStartOfTextVerbatim: () => isStartOfTextVerbatim, notStartOfABlock: () => notStartOfABlock, notStartOfComment: () => notStartOfComment, notStartOfHeading: () => notStartOfHeading, notStartOfPlanning: () => notStartOfPlanning, notStartOfPropertyDrawer: () => notStartOfPropertyDrawer, objectToken: () => objectToken, shouldDedentHeading: () => shouldDedentHeading, shouldIndentHeading: () => shouldIndentHeading, stars: () => stars, startOfComment: () => startOfComment, startOfKeywordComment: () => startOfKeywordComment }); var exitRegularLink = 44; var exitAngleLink = 45; var isEndOfTextBold = 46; var isEndOfTextItalic = 47; var isEndOfTextUnderline = 48; var isEndOfTextVerbatim = 49; var isEndOfTextCode = 50; var isEndOfTextStrikeThrough = 51; var notStartOfABlock = 52; var BlockHeader = 1; var BlockFooter = 2; var BlockContentDynamic = 3; var BlockContentCenter = 4; var BlockContentQuote = 5; var BlockContentComment = 6; var BlockContentExample = 7; var BlockContentExport = 8; var BlockContentSrc = 9; var BlockContentVerse = 10; var BlockContentSpecial = 11; var startOfComment = 53; var startOfKeywordComment = 54; var isStartOfRegularLink = 55; var isStartOfAngleLink = 56; var PlainLink = 12; var isStartOfTextBold = 57; var isStartOfTextItalic = 58; var isStartOfTextUnderline = 59; var isStartOfTextVerbatim = 60; var isStartOfTextCode = 61; var isStartOfTextStrikeThrough = 62; var PropertyDrawer = 13; var TodoKeyword = 14; var Priority = 15; var isStartOfPlanningLine = 63; var notStartOfPlanning = 64; var notStartOfPropertyDrawer = 65; var notStartOfComment = 66; var notStartOfHeading = 67; var shouldIndentHeading = 68; var shouldDedentHeading = 69; var indentHeading = 70; var dedentHeading = 71; var stars = 72; var PlanningDeadline = 16; var PlanningScheduled = 17; var PlanningClosed = 18; var PlanningValue = 19; var Tags = 20; var endofline = 73; var objectToken = 74; var Program = 21; var ZerothSection = 22; var CommentLine = 23; var Block = 24; var RegularLink = 25; var AngleLink = 26; var TextBold = 27; var TextItalic = 28; var TextUnderline = 29; var TextVerbatim = 30; var TextCode = 31; var TextStrikeThrough = 32; var KeywordComment = 33; var Heading = 34; var Title = 35; var Section = 36; // codemirror-lang-orgmode/src/external-tokens.ts var NEW_LINE = "\n".charCodeAt(0); var STAR = "*".charCodeAt(0); var COLON = ":".charCodeAt(0); var HASH = "#".charCodeAt(0); var TAB = " ".charCodeAt(0); var SPACE = " ".charCodeAt(0); var EOF = -1; var SOF = -1; var ENABLE_LOGGING = false; function log(msg) { if (ENABLE_LOGGING) { console.log(msg); } } function stringifyCodeLogString(charCode) { let char = String.fromCharCode(charCode); if (charCode == NEW_LINE) { char = String.raw`\n`; } else if (charCode == TAB) { char = String.raw`\t`; } else if (charCode == SPACE) { char = ""; } else if (charCode == EOF || charCode == SOF) { char = ""; } return char; } function inputStreamBeginString(input) { return `at ${input.pos}:"${stringifyCodeLogString(input.peek(0))}"`; } function inputStreamEndString(input, stack) { if (stack.pos === input.pos) { return `at ]${input.pos - 1}:${stack.pos}[ between "${stringifyCodeLogString(input.peek(-1))}" and "${stringifyCodeLogString(input.peek(0))}"`; } return `at ${input.pos - 1}:"${stringifyCodeLogString(input.peek(-1))}"`; } function inputStreamAccept(input, stack) { if (stack.pos === input.pos) { return `]${input.pos - 1}:${stack.pos}[ between "${stringifyCodeLogString(input.peek(-1))}" and "${stringifyCodeLogString(input.peek(0))}"`; } return `[${stack.pos}-${input.pos - 1}] until "${stringifyCodeLogString(input.peek(-1))}"`; } function isWhiteSpace(charCode) { return charCode === SPACE || charCode === TAB; } function isEndOfLine(charCode) { return charCode === NEW_LINE || charCode === SOF || charCode === EOF; } function isAlphaNum(charCode) { if (charCode >= "0".charCodeAt(0) && charCode <= "9".charCodeAt(0)) { return true; } if (charCode >= "A".charCodeAt(0) && charCode <= "Z".charCodeAt(0)) { return true; } if (charCode >= "a".charCodeAt(0) && charCode <= "z".charCodeAt(0)) { return true; } return false; } function checkPriority(s) { const matched = s.match(/^[ \t]*\[#[a-zA-Z0-9]\][ \t]*$/); if (matched) { log(`matched ${s} for Priority`); } return matched; } function checkTodoKeyword(s, input, words) { let matched = false; words.forEach((word2) => { if (s === word2) { matched = true; } }); return matched; } function checkPreviousWord(input, words, anti_peek_distance = -1) { let previous = input.peek(anti_peek_distance); let matched = null; if (!isEndOfLine(previous)) { while (isWhiteSpace(previous)) { anti_peek_distance -= 1; previous = input.peek(anti_peek_distance); } let p_s = ""; while (!isWhiteSpace(previous) && !isEndOfLine(previous)) { p_s = String.fromCharCode(previous) + p_s; log(`previous word ${p_s}`); if (checkPriority(p_s)) { log(`previous word matched priority`); matched = Priority; } if (checkTodoKeyword(p_s, input, words)) { log(`previous word matched todokeyword`); matched = TodoKeyword; } anti_peek_distance -= 1; previous = input.peek(anti_peek_distance); } } return { "matched": matched, "anti_peek_distance": anti_peek_distance }; } function checkMarkupPRE(codeUnit) { return isEndOfLine(codeUnit) || isWhiteSpace(codeUnit) || String.fromCharCode(codeUnit) === "-" || String.fromCharCode(codeUnit) === "(" || String.fromCharCode(codeUnit) === "{" || String.fromCharCode(codeUnit) === "'" || String.fromCharCode(codeUnit) === '"'; } function checkMarkupPOST(codeUnit) { return isEndOfLine(codeUnit) || isWhiteSpace(codeUnit) || String.fromCharCode(codeUnit) === "-" || String.fromCharCode(codeUnit) === "." || String.fromCharCode(codeUnit) === "," || String.fromCharCode(codeUnit) === ";" || String.fromCharCode(codeUnit) === ":" || String.fromCharCode(codeUnit) === "!" || String.fromCharCode(codeUnit) === "?" || String.fromCharCode(codeUnit) === ")" || String.fromCharCode(codeUnit) === "}" || String.fromCharCode(codeUnit) === "[" || String.fromCharCode(codeUnit) === '"' || String.fromCharCode(codeUnit) === "'" || String.fromCharCode(codeUnit) === "\\"; } function checkTags(input, advanceInput) { log(`start checkTags ${inputStreamBeginString(input)}`); let c = input.peek(0); if (c !== COLON) { return false; } let peek_distance = 0; while (true) { peek_distance += 1; c = input.peek(peek_distance); log(`peeking a: ${stringifyCodeLogString(c)}`); if (isEndOfLine(c)) { log(`case 1`); return false; } if (!String.fromCharCode(c).match(/[a-zA-Z0-9_@#%:]/)) { log(`case 2`); return false; } if (c == COLON) { log(`case 3`); let extra_peek_distance = 1; c = input.peek(peek_distance + extra_peek_distance); log(`peeking c: ${stringifyCodeLogString(c)}`); if (isEndOfLine(c)) { if (advanceInput) { input.advance(peek_distance + extra_peek_distance); } return true; } else if (isWhiteSpace(c)) { while (isWhiteSpace(c)) { extra_peek_distance += 1; c = input.peek(peek_distance + extra_peek_distance); log(`peeking d: ${stringifyCodeLogString(c)}`); } if (isEndOfLine(c)) { if (advanceInput) { input.advance(peek_distance + extra_peek_distance); } return true; } else { return false; } } else if (String.fromCharCode(c).match(/[a-zA-Z0-9_@#%:]/)) { } else { return false; } } } } var getBlockContentTerm = (s) => { s = s.toLowerCase(); if (s === ":") { return BlockContentDynamic; } else if (s === "_center") { return BlockContentCenter; } else if (s === "_quote") { return BlockContentQuote; } else if (s === "_comment") { return BlockContentComment; } else if (s === "_example") { return BlockContentExample; } else if (s === "_export") { return BlockContentExport; } else if (s === "_src") { return BlockContentSrc; } else if (s === "_verse") { return BlockContentVerse; } else if (s.startsWith("_") && s.length > 1) { return BlockContentSpecial; } return null; }; function checkBlockStart(input, stack) { log(`start checkBlockStart ${inputStreamBeginString(input)}`); let previous = input.peek(-1); if (!isEndOfLine(previous)) { log(`XX REFUSE checkBlockStart, previous not sof or newline ${inputStreamAccept(input, stack)}`); return [0, null]; } let peek_distance = 0; let c = input.peek(peek_distance); let blockPrefix = String.fromCharCode(c); for (let i = 0; i < "#+BEGIN".length - 1; ++i) { peek_distance += 1; c = input.peek(peek_distance); blockPrefix += String.fromCharCode(c); } if (blockPrefix.toUpperCase() !== "#+BEGIN") { log(`XX REFUSE checkBlockStart, line not starting with #+BEGIN ${inputStreamEndString(input, stack)}`); return [0, null]; } peek_distance += 1; c = input.peek(peek_distance); let blockSuffix = String.fromCharCode(c); while (!isEndOfLine(c) && !isWhiteSpace(c)) { peek_distance += 1; c = input.peek(peek_distance); if (!isEndOfLine(c) && !isWhiteSpace(c)) { blockSuffix += String.fromCharCode(c); } } const term = getBlockContentTerm(blockSuffix); if (term) { input.peek(peek_distance); while (!isEndOfLine(c)) { peek_distance += 1; c = input.peek(peek_distance); } if (c === NEW_LINE) { peek_distance += 1; } return [peek_distance, blockSuffix]; } log(`XX REFUSE checkBlockStart, reached endofline or 7 chars ${inputStreamEndString(input, stack)}`); return [0, null]; } function checkBlockEnd(input, stack, blockSuffix, start_peek_distance = 0) { log(`start checkBlockEnd ${inputStreamBeginString(input)} + ${start_peek_distance}`); let peek_distance = start_peek_distance; let previous = input.peek(peek_distance - 1); if (!isEndOfLine(previous)) { log(`XX REFUSE checkBlockEnd, previous not sof or newline ${inputStreamAccept(input, stack)}`); return null; } let c = input.peek(peek_distance); let blockPrefix = String.fromCharCode(c); for (let i = 0; i < "#+END".length - 1; ++i) { peek_distance += 1; c = input.peek(peek_distance); blockPrefix += String.fromCharCode(c); } if (blockPrefix.toUpperCase() !== "#+END") { log(`XX REFUSE checkBlockEnd, line not starting with #+END_ ${inputStreamEndString(input, stack)}`); return null; } peek_distance += 1; c = input.peek(peek_distance); let blockSuffixCandidate = String.fromCharCode(c); while (!isEndOfLine(c) && blockSuffixCandidate.length <= blockSuffix.length) { peek_distance += 1; c = input.peek(peek_distance); blockSuffixCandidate += String.fromCharCode(c); if (blockSuffixCandidate.toLowerCase() === blockSuffix.toLowerCase()) { while (!isEndOfLine(c)) { peek_distance += 1; c = input.peek(peek_distance); } if (c === NEW_LINE) { peek_distance += 1; } return peek_distance; } } log(`XX REFUSE checkBlockEnd, reaching endofline or char 7 ${inputStreamEndString(input, stack)}`); return null; } function checkMatchingBlockFooter(input, stack, blockSuffix, peek_distance = 0) { if (!blockSuffix) { log(`XX REFUSE checkMatchingBlockFooter, checkBlockStart failed ${inputStreamEndString(input, stack)}`); return false; } let c = input.peek(peek_distance); if (c === EOF) { log(`XX REFUSE checkMatchingBlockFooter, reached EOF ${inputStreamEndString(input, stack)}`); return false; } while (true) { peek_distance += 1; c = input.peek(peek_distance); const peek_distance_block_end = checkBlockEnd(input, stack, blockSuffix, peek_distance); if (peek_distance_block_end) { return true; } while (!isEndOfLine(c)) { peek_distance += 1; c = input.peek(peek_distance); } if (c === EOF) { log(`XX REFUSE checkMatchingBlockFooter, reached EOF ${inputStreamEndString(input, stack)}`); return false; } } } function checkBlock(input, stack) { let [peek_distance, blockSuffix] = checkBlockStart(input, stack); if (!blockSuffix) { log(`XX REFUSE checkBlock, checkBlockStart failed ${inputStreamEndString(input, stack)}`); return false; } if (checkMatchingBlockFooter(input, stack, blockSuffix, peek_distance)) { log(`== ACCEPT checkBlock ${inputStreamAccept(input, stack)}`); return true; } log(`XX REFUSE checkBlock, no matching block footer ${inputStreamEndString(input, stack)}`); return false; } var block_tokenizer = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START block_tokenizer ${inputStreamBeginString(input)}`); const context = stack.context; let previous = input.peek(-1); if (!isEndOfLine(previous)) { log(`XX REFUSE block_tokenizer, not start of a line ${inputStreamEndString(input, stack)}`); return; } if (!context.parentObjects.includes(ParentObject.Block)) { let [peek_distance, blockSuffix] = checkBlockStart(input, stack); if (blockSuffix) { context.currentBlockContext = blockSuffix; const term = getBlockContentTerm(blockSuffix); if (checkMatchingBlockFooter(input, stack, blockSuffix, peek_distance)) { log(`== ACCEPT BlockHeader term=${term} ${inputStreamAccept(input, stack)}`); input.acceptToken(BlockHeader, peek_distance); return; } } log(`== ACCEPT notStartOfABlock ${inputStreamAccept(input, stack)}`); input.acceptToken(notStartOfABlock, -(input.pos - stack.pos)); return; } if (context.parentObjects.includes(ParentObject.Block)) { const peek_distance_block_end = checkBlockEnd(input, stack, context.currentBlockContext); if (peek_distance_block_end) { input.advance(peek_distance_block_end); log(`== ACCEPT BlockFooter ${inputStreamAccept(input, stack)}`); input.acceptToken(BlockFooter); return; } } log(`XX REFUSE block_tokenizer, still inside content ${inputStreamEndString(input, stack)}`); return; }); var blockContent_tokenizer = new import_lr2.ExternalTokenizer((input, stack) => { log(`start blockContent_tokenizer ${inputStreamBeginString(input)}`); const context = stack.context; let previous = input.peek(-1); if (!isEndOfLine(previous)) { log(`XX REFUSE blockContent_tokenizer, previous not sof or newline ${inputStreamAccept(input, stack)}`); return; } let c = input.peek(0); while (c !== EOF) { if (checkBlockEnd(input, stack, context.currentBlockContext)) { const term = getBlockContentTerm(context.currentBlockContext); log(`== ACCEPT blockContent_tokenizer term=${term} ${inputStreamAccept(input, stack)}`); input.acceptToken(term); return; } while (!isEndOfLine(c)) { c = input.advance(); } c = input.advance(); } log(`XX REFUSE blockContent_tokenizer, reached EOF ${inputStreamAccept(input, stack)}`); return; }); function checkComment(input, stack) { let previous = input.peek(-1); if (!isEndOfLine(previous)) { log(`XX REFUSE checkComment, not at the start of a line ${inputStreamEndString(input, stack)}`); return; } let first = input.peek(0); if (first !== HASH) { log(`XX REFUSE checkComment, not starting with # ${inputStreamEndString(input, stack)}`); return; } let second = input.peek(1); if (isEndOfLine(second) || second === SPACE) { return true; } log(`XX REFUSE checkComment, second char is not space nor endofline ${inputStreamEndString(input, stack)}`); return; } var startOfComment_lookaround = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START startOfComment_lookaround ${inputStreamBeginString(input)}`); if (checkComment(input, stack)) { log(`== ACCEPT startOfComment_lookaround ${inputStreamAccept(input, stack)}`); input.acceptToken(startOfComment); return; } log(`XX REFUSE startOfComment_lookaround ${inputStreamEndString(input, stack)}`); return; }); function checkKeywordComment(input, stack) { log(`-- START checkKeywordComment ${inputStreamBeginString(input)}`); let previous = input.peek(-1); if (!isEndOfLine(previous)) { log(`XX REFUSE checkKeywordComment, not at the start of a line ${inputStreamEndString(input, stack)}`); return; } let first = input.peek(0); if (first !== HASH) { log(`XX REFUSE checkKeywordComment, not starting with # ${inputStreamEndString(input, stack)}`); return; } let second = input.peek(1); if (second !== "+".charCodeAt(0)) { log(`XX REFUSE checkKeywordComment, not starting with #+ ${inputStreamEndString(input, stack)}`); return; } let peek_distance = 2; let c = input.peek(peek_distance); while (true) { if (isEndOfLine(c) || c === SPACE) { log(`XX REFUSE checkKeywordComment, keyword stops without : ${inputStreamEndString(input, stack)}`); return; } else if (c === COLON) { return true; } peek_distance += 1; c = input.peek(peek_distance); } } var startOfKeywordComment_lookaround = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START startOfKeywordComment_lookaround ${inputStreamBeginString(input)}`); if (checkKeywordComment(input, stack)) { log(`== ACCEPT startOfKeywordComment_lookaround ${inputStreamAccept(input, stack)}`); input.acceptToken(startOfKeywordComment); return; } log(`XX REFUSE startOfKeywordComment_lookaround ${inputStreamEndString(input, stack)}`); return; }); var title_tokenizer = (words) => { return new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START Title ${inputStreamBeginString(input)}`); let priority_already_matched = false; let todo_keyword_already_matched = false; const previous_checker = checkPreviousWord(input, words); if (previous_checker["matched"] == Priority) { priority_already_matched = true; const previous_checker2 = checkPreviousWord(input, words, previous_checker["anti_peek_distance"]); if (previous_checker2["matched"] == TodoKeyword) { todo_keyword_already_matched = true; } } else if (previous_checker["matched"] == TodoKeyword) { todo_keyword_already_matched = true; } let c = input.peek(0); let s = String.fromCharCode(c); log(`first ${stringifyCodeLogString(c)}`); if (isEndOfLine(c)) { log(`== ACCEPT Title empty ${inputStreamAccept(input, stack)}`); input.acceptToken(Title); return; } while (!isEndOfLine(c)) { while (c != COLON && !isEndOfLine(c)) { c = input.advance(); s += String.fromCharCode(c); log(`${stringifyCodeLogString(c)}`); if (!priority_already_matched && checkPriority(s)) { log(`XX REFUSE Title, is priority ${inputStreamEndString(input, stack)}`); return; } if (!todo_keyword_already_matched && checkTodoKeyword(s, input, words)) { if (isWhiteSpace(input.peek(1))) { log(`XX REFUSE Title, is TodoKeyword ${inputStreamEndString(input, stack)}`); return; } } } if (isEndOfLine(c)) { input.acceptToken(Title); log(`== ACCEPT Title 1 ${inputStreamAccept(input, stack)}`); return; } if (c == COLON) { if (checkTags(input, false)) { input.acceptToken(Title); log(`== ACCEPT Title before Tags ${inputStreamAccept(input, stack)}`); return; } c = input.advance(); s += String.fromCharCode(c); log(`${stringifyCodeLogString(c)}`); } } input.acceptToken(Title); log(`== ACCEPT Title 4 ${inputStreamAccept(input, stack)}`); return; }); }; var todokeyword_tokenizer = (words) => { return new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START TodoKeyword ${inputStreamBeginString(input)}`); const max_length = Math.max(...words.map((el) => el.length)); let c = input.peek(0); let i = 0; let s = String.fromCharCode(c); log(`first ${stringifyCodeLogString(c)}`); while (i < max_length && c != EOF) { if (checkTodoKeyword(s, input, words)) { const next = input.peek(1); if (isEndOfLine(next) || isWhiteSpace(next)) { input.advance(); log(`== ACCEPT TodoKeyword ${inputStreamAccept(input, stack)}`); input.acceptToken(TodoKeyword); return; } } i += 1; c = input.advance(); log(`${stringifyCodeLogString(c)}`); s += String.fromCharCode(c); } log(`XX REFUSE TodoKeyword ${inputStreamEndString(input, stack)}`); return; }); }; var priority_tokenizer = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START Priority ${inputStreamBeginString(input)}`); let c = input.peek(0); log(stringifyCodeLogString(c)); while (isWhiteSpace(c)) { c = input.advance(); log(stringifyCodeLogString(c)); } const OPENING_BRACKET = "[".charCodeAt(0); const CLOSING_BRACKET = "]".charCodeAt(0); if (c !== OPENING_BRACKET) { log(`XX REFUSE Priority, expecting [ ${inputStreamEndString(input, stack)}`); return; } c = input.advance(); log(stringifyCodeLogString(c)); if (c !== HASH) { log(`XX REFUSE Priority, expecting # ${inputStreamEndString(input, stack)}`); return; } c = input.advance(); log(stringifyCodeLogString(c)); if (!isAlphaNum(c)) { log(`XX REFUSE Priority, expecting alphanum char ${inputStreamEndString(input, stack)}`); return; } c = input.advance(); log(stringifyCodeLogString(c)); if (c !== CLOSING_BRACKET) { log(`XX REFUSE Priority, expecting ] ${inputStreamEndString(input, stack)}`); return; } c = input.advance(); log(stringifyCodeLogString(c)); while (isWhiteSpace(c)) { c = input.advance(); log(stringifyCodeLogString(c)); } log(`== ACCEPT Priority ${inputStreamAccept(input, stack)}`); input.acceptToken(Priority); return; }); var endofline_tokenizer = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START endofline ${inputStreamBeginString(input)}`); let previous = input.peek(-1); if (isEndOfLine(previous)) { log(`XX REFUSE endofline, previous already endofline ${inputStreamEndString(input, stack)}`); return; } let c = input.peek(0); log(stringifyCodeLogString(c)); while (true) { if (checkTags(input, false)) { log(`XX REFUSE endofline, found Tags ${inputStreamEndString(input, stack)}`); return; } else if (c === EOF) { log(`== ACCEPT endofline EOF ${inputStreamAccept(input, stack)}`); input.acceptToken(endofline); return; } else if (c === NEW_LINE) { input.advance(); log(`== ACCEPT endofline NEWLINE ${inputStreamAccept(input, stack)}`); input.acceptToken(endofline); return; } else if (!isWhiteSpace(c)) { log(`XX REFUSE endofline, not whitespace ${inputStreamEndString(input, stack)}`); return; } c = input.advance(); log(stringifyCodeLogString(c)); } }); var notStartOfPlanning_lookaround = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START notStartOfPlanning ${inputStreamBeginString(input)}`); const previous = input.peek(-1); log(`previous ${stringifyCodeLogString(previous)}`); if (!isEndOfLine(previous)) { log(`XX REFUSE notStartOfPlanning, previous not endofline ${inputStreamEndString(input, stack)}`); return; } let c = input.peek(0); let planning_word = String.fromCharCode(c); log(stringifyCodeLogString(c)); if (c === EOF) { log(`XX REFUSE notStartOfPlanning, only EOF left ${inputStreamEndString(input, stack)}`); return; } else if (c === COLON) { planning_word = ""; } else if (c === HASH && !checkBlock(input, stack)) { log(`XX REFUSE notStartOfPlanning, start of comment ${inputStreamEndString(input, stack)}`); return; } else if (c === STAR) { let peek_distance = 1; let peek_c = input.peek(peek_distance); while (peek_c == STAR) { peek_distance += 1; peek_c = input.peek(peek_distance); } if (isWhiteSpace(peek_c)) { log(`XX REFUSE notStartOfPlanning, start of heading ${inputStreamEndString(input, stack)}`); return; } } if (c === HASH && !checkBlock(input, stack)) { log(`XX REFUSE notStartOfPlanning, start of comment ${inputStreamEndString(input, stack)}`); return; } let primary_peek_distance = 0; while (!isEndOfLine(c)) { primary_peek_distance += 1; c = input.peek(primary_peek_distance); log(stringifyCodeLogString(c)); if (c === COLON) { if (planning_word.toUpperCase() === "DEADLINE" || planning_word.toUpperCase() === "SCHEDULED" || planning_word.toUpperCase() === "CLOSED") { log(`XX REFUSE notStartOfPlanning, start of Planning ${inputStreamEndString(input, stack)}`); return; } } planning_word += String.fromCharCode(c); log(`word [${planning_word}]`); } if (c === EOF) { log(`== ACCEPT notStartOfPlanning before eof ${inputStreamAccept(input, stack)}`); input.acceptToken(notStartOfPlanning); return; } else if (c === NEW_LINE && input.peek(primary_peek_distance + 1) === EOF) { primary_peek_distance += 1; input.acceptToken(notStartOfPlanning); log(`== ACCEPT last notStartOfPlanning before EOF with a trailing newline ${inputStreamAccept(input, stack)}`); return; } else if (c === NEW_LINE) { primary_peek_distance += 1; log(`== ACCEPT notStartOfPlanning before newline ${inputStreamAccept(input, stack)}`); input.acceptToken(notStartOfPlanning); return; } log(`== ACCEPT notStartOfPlanning by default ${inputStreamAccept(input, stack)}`); input.acceptToken(notStartOfPlanning); return; }); function checkPropertyDrawer(input, stack, peek_distance = 0) { log(`-- START checkPropertyDrawer ${inputStreamBeginString(input)}`); const previous = input.peek(-1); log(`previous ${stringifyCodeLogString(previous)}`); if (!isEndOfLine(previous)) { log(`XX REFUSE checkPropertyDrawer, previous not endofline ${inputStreamEndString(input, stack)}`); return; } let c = input.peek(peek_distance); log(stringifyCodeLogString(c)); const matchedPropertiesStart = matchWords(input, [":PROPERTIES:"]); if (!matchedPropertiesStart) { log(`XX REFUSE checkPropertyDrawer, not starting with :PROPERTIES: ${inputStreamEndString(input, stack)}`); return; } peek_distance += matchedPropertiesStart.length; c = input.peek(peek_distance); while (c !== NEW_LINE) { peek_distance += 1; c = input.peek(peek_distance); log(stringifyCodeLogString(c)); } peek_distance += 1; c = input.peek(peek_distance); log(stringifyCodeLogString(c)); while (c !== EOF) { while (!isEndOfLine(c)) { peek_distance += 1; c = input.peek(peek_distance); log(stringifyCodeLogString(c)); } peek_distance += 1; c = input.peek(peek_distance); const matchedPropertiesEnd = matchWords(input, [":END:"], peek_distance); if (matchedPropertiesEnd) { peek_distance += matchedPropertiesEnd.length; c = input.peek(peek_distance); while (!isEndOfLine(c)) { peek_distance += matchedPropertiesEnd.length; c = input.peek(peek_distance); } peek_distance += 1; log(`== ACCEPT checkPropertyDrawer by default ${inputStreamAccept(input, stack)}`); return peek_distance; } } log(`XX REFUSE checkPropertyDrawer, reached eof ${inputStreamEndString(input, stack)}`); return; } var notStartOfPropertyDrawer_lookaround = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START notStartOfPropertyDrawer ${inputStreamBeginString(input)}`); const previous = input.peek(-1); log(`previous ${stringifyCodeLogString(previous)}`); if (!isEndOfLine(previous)) { log(`XX REFUSE notStartOfPropertyDrawer, previous not endofline ${inputStreamEndString(input, stack)}`); return; } if (checkPropertyDrawer(input, stack)) { log(`XX REFUSE notStartOfPropertyDrawer, start of PropertyDrawer ${inputStreamEndString(input, stack)}`); return; } log(`== ACCEPT notStartOfPropertyDrawer ${inputStreamAccept(input, stack)}`); input.acceptToken(notStartOfPropertyDrawer); return; }); var propertydrawer_tokenizer = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START PropertyDrawer ${inputStreamBeginString(input)}`); let peek_distance = checkPropertyDrawer(input, stack); if (peek_distance) { input.advance(peek_distance); log(`== ACCEPT PropertyDrawer ${inputStreamAccept(input, stack)}`); input.acceptToken(PropertyDrawer); return; } log(`XX REFUSE PropertyDrawer ${inputStreamEndString(input, stack)}`); return; }); var notStartOfComment_lookaround = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START notStartOfComment_lookaround ${inputStreamBeginString(input)}`); if (checkComment(input, stack)) { log(`XX REFUSE notStartOfComment_lookaround, start of comment ${inputStreamEndString(input, stack)}`); return; } if (checkKeywordComment(input, stack)) { log(`XX REFUSE notStartOfComment_lookaround, start of keyword comment ${inputStreamEndString(input, stack)}`); return; } log(`== ACCEPT notStartOfComment_lookaround ${inputStreamAccept(input, stack)}`); input.acceptToken(notStartOfComment); return; }); function checkValidEndOfTextMarkup(input, stack, marker, peek_distance = 0) { const MARKER = marker; const previous = input.peek(peek_distance - 1); const current = input.peek(peek_distance); if (isWhiteSpace(previous) || isEndOfLine(previous)) { log(`previous is whitespace ${stringifyCodeLogString(previous)}`); return false; } log(`current ${stringifyCodeLogString(current)}`); if (current !== MARKER) { log(`not MARKER ${inputStreamEndString(input, stack)}`); return false; } const next = input.peek(peek_distance + 1); log(`next ${stringifyCodeLogString(next)}`); if (!checkMarkupPOST(next)) { log(`no POST ${inputStreamEndString(input, stack)}`); return false; } return true; } var isStartOfTextMarkup_lookaround = (orgLinkParameters2) => { return new import_lr2.ExternalTokenizer((input, stack) => { const context = stack.context; log(`-- START isStartOfTextMarkup_lookaround ${inputStreamBeginString(input)}`); const termsByMarker = /* @__PURE__ */ new Map([ [STAR, isStartOfTextBold], ["/".charCodeAt(0), isStartOfTextItalic], ["_".charCodeAt(0), isStartOfTextUnderline], ["=".charCodeAt(0), isStartOfTextVerbatim], ["~".charCodeAt(0), isStartOfTextCode], ["+".charCodeAt(0), isStartOfTextStrikeThrough] ]); const term = isStartOfTextMarkup(input, stack, termsByMarker, false, orgLinkParameters2); if (!term) { log(`XX REFUSE isStartOfTextMarkup_lookaround ${inputStreamEndString(input, stack)}`); return; } if (term === isStartOfTextBold && !context.parentObjects.includes(ParentObject.TextBold) || term === isStartOfTextItalic && !context.parentObjects.includes(ParentObject.TextItalic) || term === isStartOfTextUnderline && !context.parentObjects.includes(ParentObject.TextUnderline) || term === isStartOfTextVerbatim && !context.parentObjects.includes(ParentObject.TextVerbatim) || term === isStartOfTextCode && !context.parentObjects.includes(ParentObject.TextCode) || term === isStartOfTextStrikeThrough && !context.parentObjects.includes(ParentObject.TextStrikeThrough)) { log(`== ACCEPT isStartOfTextMarkup_lookaround term=${term} ${inputStreamAccept(input, stack)}`); input.acceptToken(term, -(input.pos - stack.pos)); return; } log(`XX REFUSE isStartOfTextMarkup_lookaround term=${term} already inside this markupu ${inputStreamEndString(input, stack)}`); return; }); }; var isEndOfTextMarkup_tokenizer = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START isEndOfTextMarkup_tokenizer ${inputStreamBeginString(input)}`); const termsByMarker = /* @__PURE__ */ new Map([ [STAR, isEndOfTextBold], ["/".charCodeAt(0), isEndOfTextItalic], ["_".charCodeAt(0), isEndOfTextUnderline], ["=".charCodeAt(0), isEndOfTextVerbatim], ["~".charCodeAt(0), isEndOfTextCode], ["+".charCodeAt(0), isEndOfTextStrikeThrough] ]); const MARKER = input.peek(0); if (!termsByMarker.has(MARKER)) { log(`XX REFUSE isEndOfTextMarkup, MARKER=${MARKER} unknown ${inputStreamEndString(input, stack)}`); return; } if (checkValidEndOfTextMarkup(input, stack, MARKER)) { input.advance(); log(`== ACCEPT isEndOfTextMarkup ${inputStreamAccept(input, stack)}`); input.acceptToken(termsByMarker.get(MARKER)); return; } log(`XX REFUSE isEndOfTextMarkup ${inputStreamEndString(input, stack)}`); return; }); function checkValidStartOfTextMarkup(input, stack, termsByMarker) { const previous = input.peek(-1); log(`previous ${stringifyCodeLogString(previous)}`); if (!checkMarkupPRE(previous)) { log(`XX REFUSE checkValidStartOfTextMarkup, not preceded by PRE ${inputStreamEndString(input, stack)}`); return; } let peek_distance = 0; let c = input.peek(peek_distance); log(stringifyCodeLogString(c)); if (!termsByMarker.has(c)) { log(`XX REFUSE checkValidStartOfTextMarkup, not starting with a textmarkup marker ${inputStreamEndString(input, stack)}`); return; } const MARKER = c; if (checkStartOfHeading(input)) { log(`XX REFUSE checkValidStartOfTextMarkup, start of heading ${inputStreamEndString(input, stack)}`); return; } peek_distance += 1; c = input.peek(peek_distance); if (isWhiteSpace(c)) { log(`XX REFUSE checkValidStartOfTextMarkup, ${stringifyCodeLogString(MARKER)} followed by whitespace ${inputStreamEndString(input, stack)}`); return; } else if (isEndOfLine(c)) { log(`XX REFUSE checkValidStartOfTextMarkup, ${stringifyCodeLogString(MARKER)} followed by endofline ${inputStreamEndString(input, stack)}`); return; } else if (c === MARKER && checkValidEndOfTextMarkup(input, stack, MARKER, peek_distance)) { log(`== REFUSE checkValidStartOfTextMarkup double marker ${inputStreamEndString(input, stack)}`); return; } return true; } function isStartOfTextMarkup(input, stack, termsByMarker, noEndOfLine, orgLinkParameters2) { const context = stack.context; if (!checkValidStartOfTextMarkup(input, stack, termsByMarker)) { log(`XX REFUSE isStartOfTextMarkup, not valid start ${inputStreamEndString(input, stack)}`); return; } let peek_distance = 0; const MARKER = input.peek(peek_distance); const term = termsByMarker.get(MARKER); peek_distance += 1; let c = input.peek(peek_distance); while (true) { if (context.parentObjects.includes(ParentObject.RegularLink) && matchWords(input, ["]]"], peek_distance)) { log(`== REFUSE isStartOfTextMarkup unfinished markup before end of link ]] ${inputStreamEndString(input, stack)}`); return; } else if (!context.parentObjects.includes(ParentObject.RegularLink) && checkRegularLink(input, stack, orgLinkParameters2, peek_distance)) { log(`skipping regularLink inside markup`); const end_of_link_peek_distance = checkRegularLink(input, stack, orgLinkParameters2, peek_distance); peek_distance = end_of_link_peek_distance - 1; c = input.peek(peek_distance); } else if (context.parentObjects.includes(ParentObject.AngleLink) && matchWords(input, [">"], peek_distance)) { log(`== REFUSE isStartOfTextMarkup unfinished markup before end of link > ${inputStreamEndString(input, stack)}`); return; } else if (!context.parentObjects.includes(ParentObject.AngleLink) && checkAngleLink(input, stack, orgLinkParameters2, peek_distance)) { log(`skipping angleLink inside markup ${inputStreamEndString(input, stack)} + ${peek_distance}`); const end_of_link_peek_distance = checkAngleLink(input, stack, orgLinkParameters2, peek_distance); peek_distance = end_of_link_peek_distance - 1; c = input.peek(peek_distance); } else if (c === EOF) { log(`== REFUSE isStartOfTextMarkup unfinished EOF ${inputStreamEndString(input, stack)}`); return; } else if (c === MARKER) { while (input.peek(peek_distance + 1) === MARKER) { peek_distance += 1; c = input.peek(peek_distance); log(stringifyCodeLogString(c)); } if (checkValidEndOfTextMarkup(input, stack, MARKER, peek_distance)) { peek_distance += 1; c = input.peek(peek_distance); log(`== ACCEPT isStartOfTextMarkup ${inputStreamAccept(input, stack)}`); return term; } } else if (context.parentObjects.includes(ParentObject.TextBold) && checkValidEndOfTextMarkup(input, stack, STAR, peek_distance)) { log(`XX REFUSE isStartOfTextMarkup, reached end of current TextBold ${inputStreamEndString(input, stack)}`); return; } else if (context.parentObjects.includes(ParentObject.TextItalic) && checkValidEndOfTextMarkup(input, stack, "/".charCodeAt(0), peek_distance)) { log(`XX REFUSE isStartOfTextMarkup, reached end of current TextItalic ${inputStreamEndString(input, stack)}`); return; } else if (context.parentObjects.includes(ParentObject.TextUnderline) && checkValidEndOfTextMarkup(input, stack, "_".charCodeAt(0), peek_distance)) { log(`XX REFUSE isStartOfTextMarkup, reached end of current TextUnderline ${inputStreamEndString(input, stack)}`); return; } else if (context.parentObjects.includes(ParentObject.TextVerbatim) && checkValidEndOfTextMarkup(input, stack, "=".charCodeAt(0), peek_distance)) { log(`XX REFUSE isStartOfTextMarkup, reached end of current TextVerbatim ${inputStreamEndString(input, stack)}`); return; } else if (context.parentObjects.includes(ParentObject.TextCode) && checkValidEndOfTextMarkup(input, stack, "~".charCodeAt(0), peek_distance)) { log(`XX REFUSE isStartOfTextMarkup, reached end of current TextCode ${inputStreamEndString(input, stack)}`); return; } else if (context.parentObjects.includes(ParentObject.TextStrikeThrough) && checkValidEndOfTextMarkup(input, stack, "+".charCodeAt(0), peek_distance)) { log(`XX REFUSE isStartOfTextMarkup, reached end of current TextStrikeThrough ${inputStreamEndString(input, stack)}`); return; } else if (c === NEW_LINE) { if (noEndOfLine) { log(`XX REFUSE isStartOfTextMarkup reached endofline ${inputStreamEndString(input, stack)}`); return; } if (isWhiteSpace(input.peek(peek_distance + 1)) || isEndOfLine(input.peek(peek_distance + 1))) { let extra_peek_distance = 1; while (isWhiteSpace(input.peek(peek_distance + extra_peek_distance))) { extra_peek_distance += 1; } if (isEndOfLine(input.peek(peek_distance + extra_peek_distance))) { log(`XX REFUSE isStartOfTextMarkup unfinished blank line ${inputStreamEndString(input, stack)}`); return; } } else if (input.peek(peek_distance + 1) == STAR) { let extra_peek_distance = 1; c = input.peek(peek_distance + extra_peek_distance); while (c === STAR) { extra_peek_distance += 1; c = input.peek(peek_distance + extra_peek_distance); } if (isWhiteSpace(c)) { log(`XX REFUSE isStartOfTextMarkup, start of heading ${inputStreamEndString(input, stack)}`); return; } } else if (input.peek(peek_distance + 1) == HASH) { log(`XX REFUSE isStartOfTextMarkup, start of comment ${inputStreamEndString(input, stack)}`); return; } else { } } peek_distance += 1; c = input.peek(peek_distance); log(stringifyCodeLogString(c)); } } var tags_tokenizer = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START Tags ${inputStreamBeginString(input)}`); if (checkTags(input, true)) { log(`== ACCEPT Tags ${inputStreamAccept(input, stack)}`); input.acceptToken(Tags); return; } log(`XX REFUSE Tags ${inputStreamEndString(input, stack)}`); return; }); var stars_tokenizer = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START stars ${inputStreamBeginString(input)}`); let previous = input.peek(-1); log(`previous ${stringifyCodeLogString(previous)}`); if (!isEndOfLine(previous)) { log(`XX REFUSE stars, previous not endofline ${inputStreamEndString(input, stack)}`); return; } let c = input.peek(0); log(stringifyCodeLogString(c)); if (c !== STAR) { log(`XX REFUSE stars, first char not * ${inputStreamEndString(input, stack)}`); return; } let headingLevel = 0; while (input.peek(0) === STAR) { headingLevel += 1; c = input.advance(); log(stringifyCodeLogString(c)); } if (!isWhiteSpace(c)) { log(`XX REFUSE stars, no whitespaces at the end ${inputStreamEndString(input, stack)}`); return; } while (isWhiteSpace(input.peek(0))) { c = input.advance(); log(stringifyCodeLogString(c)); } log(`== ACCEPT stars ${inputStreamAccept(input, stack)}`); input.acceptToken(stars); return; }); function checkStartOfHeading(input) { const previous = input.peek(-1); log(`previous ${stringifyCodeLogString(previous)}`); if (!isEndOfLine(previous)) { return; } let c = input.peek(0); log(stringifyCodeLogString(c)); let headingLevel = null; if (c === STAR) { headingLevel = 1; let peek_c = input.peek(headingLevel); while (peek_c == STAR) { headingLevel += 1; peek_c = input.peek(headingLevel); } if (isWhiteSpace(peek_c)) { return headingLevel; } } return null; } var startOfHeading_lookaround = new import_lr2.ExternalTokenizer((input, stack) => { const context = stack.context; log(`-- START startOfHeading_lookaround ${inputStreamBeginString(input)}`); if (input.peek(0) === EOF) { if (Array.isArray(context.headingLevelStack) && context.headingLevelStack.length > 0) { log(`== ACCEPT shouldDedentHeading before EOF ${inputStreamAccept(input, stack)}`); input.acceptToken(shouldDedentHeading); return; } log(`XX REFUSE startOfHeading_lookaround, EOF ${inputStreamEndString(input, stack)}`); return; } if (!isEndOfLine(input.peek(-1))) { log(`XX REFUSE startOfHeading_lookaround, previous not endofline ${inputStreamEndString(input, stack)}`); return; } let nextHeadingLevel = checkStartOfHeading(input); if (!nextHeadingLevel) { log(`== ACCEPT notStartOfHeading ${inputStreamAccept(input, stack)}`); input.acceptToken(notStartOfHeading); return; } if (context.headingLevelStack.length === 0) { log(`== ACCEPT shouldIndentHeading top level ${inputStreamAccept(input, stack)}`); input.acceptToken(shouldIndentHeading); return; } const currentHeadingLevel = context.headingLevelStack[context.headingLevelStack.length - 1]; if (nextHeadingLevel > currentHeadingLevel) { log(`== ACCEPT shouldIndentHeading ${inputStreamAccept(input, stack)}`); input.acceptToken(shouldIndentHeading); return; } else { log(`== ACCEPT shouldDedentHeading before next heading ${inputStreamAccept(input, stack)}`); input.acceptToken(shouldDedentHeading); return; } }); var indentHeading_lookaround = new import_lr2.ExternalTokenizer((input, stack) => { const context = stack.context; log(`-- START indentHeading_lookaround ${inputStreamBeginString(input)}`); let nextHeadingLevel = checkStartOfHeading(input); if (!nextHeadingLevel) { log(`XX REFUSE indentHeading_lookaround ${inputStreamEndString(input, stack)}`); return; } context.levelHeadingToPush = nextHeadingLevel; log(`== ACCEPT indentHeading_lookaround ${inputStreamAccept(input, stack)}`); input.acceptToken(indentHeading); return; }); var dedentHeading_lookaround = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START dedentHeading_lookaround ${inputStreamBeginString(input)}`); log(`== ACCEPT dedentHeading_lookaround ${inputStreamAccept(input, stack)}`); input.acceptToken(dedentHeading); return; }); function checkPlainLink(input, stack, orgLinkParameters2, lookaround) { const L_PAREN = "(".charCodeAt(0); const R_PAREN = ")".charCodeAt(0); function checkPlainLinkPRE(codeUnit) { return isEndOfLine(codeUnit) || isWhiteSpace(codeUnit) || String.fromCharCode(codeUnit) === "-" || String.fromCharCode(codeUnit) === "(" || String.fromCharCode(codeUnit) === "{" || String.fromCharCode(codeUnit) === "'" || String.fromCharCode(codeUnit) === '"' || String.fromCharCode(codeUnit) === ":"; } const isForbiddenChar = (codeUnit) => { return isEndOfLine(codeUnit) || isWhiteSpace(codeUnit) || String.fromCharCode(codeUnit) === "[" || String.fromCharCode(codeUnit) === "]" || String.fromCharCode(codeUnit) === "<" || String.fromCharCode(codeUnit) === ">"; }; const linkMarkupMarkers = ["*", "/", "_", "=", "~", "+"]; const previous = input.peek(-1); if (!checkPlainLinkPRE(previous) && !isEndOfLine(previous) && !isWhiteSpace(previous) && !linkMarkupMarkers.includes(String.fromCharCode(previous))) { log(`XX REFUSE checkPlainLink, previous not PRE, eof, whitespace, markup marker ${inputStreamEndString(input, stack)}`); return; } let peek_distance = 0; let c = input.peek(peek_distance); if (c === EOF) { log(`XX REFUSE checkPlainLink, only EOF left ${inputStreamEndString(input, stack)}`); return; } log(stringifyCodeLogString(c)); if (isWhiteSpace(c) || isEndOfLine(c)) { log(`XX REFUSE checkPlainLink, whitespace ${inputStreamEndString(input, stack)}`); return; } let s = String.fromCharCode(c); while (!isForbiddenChar(c)) { peek_distance += 1; c = input.peek(peek_distance); s += String.fromCharCode(c); log(stringifyCodeLogString(c)); if (c === R_PAREN) { break; } else if (c === L_PAREN) { let depth = 1; let beforeParen_peek_distance = peek_distance; while (depth > 0) { peek_distance += 1; c = input.peek(peek_distance); s += String.fromCharCode(c); log(stringifyCodeLogString(c)); if (isForbiddenChar(c)) { peek_distance = beforeParen_peek_distance; break; } else if (c === L_PAREN) { depth += 1; if (depth > 2) { log(`XX REFUSE checkPlainLink, too many '(' ${inputStreamEndString(input, stack)}`); return; } } else if (c === R_PAREN) { depth -= 1; if (depth < 0) { log(`XX REFUSE checkPlainLink, too many ')' ${inputStreamEndString(input, stack)}`); return; } } } } } const POSTcandidate = input.peek(peek_distance - 1); if (linkMarkupMarkers.includes(String.fromCharCode(POSTcandidate)) || checkMarkupPOST(POSTcandidate) && POSTcandidate !== R_PAREN) { peek_distance -= 1; s = s.slice(0, s.length - 1); } s = s.slice(0, s.length - 1); const [linkType, ...pathPlainSplit] = s.split(":"); const pathPlain = pathPlainSplit.join(":"); if (!orgLinkParameters2.includes(linkType)) { log(`XX REFUSE checkPlainLink, not correct linkType ${inputStreamEndString(input, stack)}`); return; } if (pathPlain.length <= 1) { log(`XX REFUSE checkPlainLink, one char ${inputStreamEndString(input, stack)}`); return; } if (!lookaround) { input.advance(peek_distance); } return true; } var plainLink_tokenizer = (orgLinkParameters2) => { return new import_lr2.ExternalTokenizer((input, stack) => { const context = stack.context; log(`-- START plainLink_tokenizer ${inputStreamBeginString(input)}`); const isInsideLink = context.parentObjects.includes(ParentObject.RegularLink) || context.parentObjects.includes(ParentObject.AngleLink); if (isInsideLink) { log(`XX REFUSE plainLink_tokenizer, already inside link ${inputStreamEndString(input, stack)}`); return; } if (checkPlainLink(input, stack, orgLinkParameters2, false)) { log(`== ACCEPT plainLink ${inputStreamAccept(input, stack)}`); input.acceptToken(PlainLink); return; } log(`XX REFUSE plainLink_tokenizer ${inputStreamEndString(input, stack)}`); return; }); }; var checkInnerRegularLink = (innerBracketText) => { const split = innerBracketText.split("]["); if (split.length > 2) { return false; } if (split.length === 1) { const pathreg2 = innerBracketText; if (/\[/.test(pathreg2) || /\]/.test(pathreg2)) { return false; } return true; } const [pathreg, description] = split; if (/\[/.test(pathreg) || /\]/.test(pathreg)) { return false; } return true; }; function checkRegularLink(input, stack, orgLinkParameters2, peek_distance = 0) { const L_SQUARE_BRACKET = "[".charCodeAt(0); const R_SQUARE_BRACKET = "]".charCodeAt(0); if (input.peek(peek_distance) !== L_SQUARE_BRACKET || input.peek(peek_distance + 1) !== L_SQUARE_BRACKET) { log(`XX REFUSE checkRegularLink ${inputStreamEndString(input, stack)}`); return; } peek_distance += 1; peek_distance += 1; let c = input.peek(peek_distance); let s = ""; while (true) { while (c !== R_SQUARE_BRACKET && !isEndOfLine(c)) { s += String.fromCharCode(c); peek_distance += 1; c = input.peek(peek_distance); } if (isEndOfLine(c)) { log(`XX REFUSE checkRegularLink, EOL ${inputStreamEndString(input, stack)}`); return; } else if (input.peek(peek_distance) === R_SQUARE_BRACKET && input.peek(peek_distance + 1) === R_SQUARE_BRACKET) { if (checkInnerRegularLink(s)) { peek_distance += 1; peek_distance += 1; return peek_distance; } log(`XX REFUSE checkRegularLink ${inputStreamEndString(input, stack)}`); return; } s += String.fromCharCode(c); peek_distance += 1; c = input.peek(peek_distance); } } var isStartOfRegularLink_lookaround = (orgLinkParameters2) => { return new import_lr2.ExternalTokenizer((input, stack) => { const context = stack.context; log(`-- START isStartOfRegularLink_lookaround ${inputStreamBeginString(input)}`); const isInsideLink = context.parentObjects.includes(ParentObject.RegularLink) || context.parentObjects.includes(ParentObject.AngleLink); if (isInsideLink) { log(`XX REFUSE isStartOfRegularLink_lookaround, already inside link ${inputStreamEndString(input, stack)}`); return; } if (checkRegularLink(input, stack, orgLinkParameters2)) { log(`== ACCEPT isStartOfRegularLink_lookaround, EOL ${inputStreamAccept(input, stack)}`); input.acceptToken(isStartOfRegularLink); return; } log(`XX REFUSE isStartOfRegularLink_lookaround ${inputStreamEndString(input, stack)}`); return; }); }; function checkAngleLink(input, stack, orgLinkParameters2, peek_distance = 0) { const L_ANGLE_BRACKET = "<".charCodeAt(0); const R_ANGLE_BRACKET = ">".charCodeAt(0); let c = input.peek(peek_distance); if (c !== L_ANGLE_BRACKET) { return; } let linkTypeMatched = false; let linkTypeCandidate = ""; const maxLength = orgLinkParameters2.reduce((acc, v) => Math.max(acc, v.length), 0); while (true) { peek_distance += 1; c = input.peek(peek_distance); while (c !== COLON && !isEndOfLine(c) && c !== R_ANGLE_BRACKET) { if (!linkTypeMatched && linkTypeCandidate.length < maxLength) { linkTypeCandidate += String.fromCharCode(c); } peek_distance += 1; c = input.peek(peek_distance); } if (c === COLON) { if (!linkTypeMatched && orgLinkParameters2.includes(linkTypeCandidate)) { linkTypeMatched = true; } } else if (c === EOF) { return; } else if (c === NEW_LINE) { let extra_peek_distance = 1; while (isWhiteSpace(input.peek(peek_distance + extra_peek_distance))) { extra_peek_distance += 1; } if (isEndOfLine(input.peek(peek_distance + extra_peek_distance))) { log(`XX REFUSE checkAngleLink unfinished blank line ${inputStreamEndString(input, stack)}`); return; } } else if (c === R_ANGLE_BRACKET) { if (linkTypeMatched) { peek_distance += 1; return peek_distance; } return; } } } var isStartOfAngleLink_lookaround = (orgLinkParameters2) => { return new import_lr2.ExternalTokenizer((input, stack) => { const context = stack.context; log(`-- START isStartOfAngleLink ${inputStreamBeginString(input)}`); const isInsideLink = context.parentObjects.includes(ParentObject.RegularLink) || context.parentObjects.includes(ParentObject.AngleLink); if (isInsideLink) { log(`XX REFUSE isStartOfAngleLink, already inside link ${inputStreamEndString(input, stack)}`); return; } if (checkAngleLink(input, stack, orgLinkParameters2)) { log(`== ACCEPT isStartOfAngleLink ${inputStreamAccept(input, stack)}`); input.acceptToken(isStartOfAngleLink); return; } log(`XX REFUSE isStartOfAngleLink ${inputStreamEndString(input, stack)}`); return; }); }; var exitRegularLink_tokenizer = new import_lr2.ExternalTokenizer((input, stack) => { const context = stack.context; log(`-- START exitRegularLink_tokenizer ${inputStreamBeginString(input)}`); const isInsideLink = context.parentObjects.includes(ParentObject.RegularLink) || context.parentObjects.includes(ParentObject.AngleLink); if (isInsideLink && matchWords(input, ["]]"])) { input.advance(); input.advance(); log(`== ACCEPT exitRegularLink_tokenizer ${inputStreamAccept(input, stack)}`); input.acceptToken(exitRegularLink); return; } log(`XX REFUSE exitRegularLink_tokenizer ${inputStreamEndString(input, stack)}`); return; }); var exitAngleLink_tokenizer = new import_lr2.ExternalTokenizer((input, stack) => { const context = stack.context; log(`-- START exitAngleLink_tokenizer ${inputStreamBeginString(input)}`); const isInsideLink = context.parentObjects.includes(ParentObject.RegularLink) || context.parentObjects.includes(ParentObject.AngleLink); if (isInsideLink && matchWords(input, [">"])) { input.advance(); log(`== ACCEPT exitAngleLink_tokenizer ${inputStreamAccept(input, stack)}`); input.acceptToken(exitAngleLink); return; } log(`XX REFUSE exitAngleLink_tokenizer ${inputStreamEndString(input, stack)}`); return; }); function matchWords(input, words, peek_distance = 0) { const maxLength = Math.max(...words.map((x) => x.length)); let c = null; let s = ""; while (s.length <= maxLength) { c = input.peek(peek_distance); s += String.fromCharCode(c); for (let word2 of words) { if (s === word2) { return word2; } } peek_distance += 1; } return; } var isStartOfPlanningLine_lookaround = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START isStartOfPlanningLine_lookaround ${inputStreamBeginString(input)}`); const previous = input.peek(-1); if (!isEndOfLine(previous)) { log(`XX REFUSE isStartOfPlanningLine_lookaround, not start of line ${inputStreamEndString(input, stack)}`); return; } let peek_distance = 0; let c = input.peek(peek_distance); while (c === SPACE && !isEndOfLine(c)) { peek_distance += 1; c = input.peek(peek_distance); } if (isEndOfLine(c)) { log(`XX REFUSE isStartOfPlanningLine_lookaround, reached eol ${inputStreamEndString(input, stack)}`); return; } const expectedPlanningWords = ["SCHEDULED:", "DEADLINE:", "CLOSED:"]; let hasMatched = false; while (c !== SPACE && !isEndOfLine(c)) { const matchedWord = matchWords(input, expectedPlanningWords, peek_distance); if (matchedWord && (input.peek(peek_distance - 1) === SPACE || isEndOfLine(input.peek(peek_distance - 1)))) { hasMatched = true; peek_distance += matchedWord.length; c = input.peek(peek_distance); break; } peek_distance += 1; c = input.peek(peek_distance); } if (hasMatched) { log(`== ACCEPT isStartOfPlanningLine_lookaround ${inputStreamAccept(input, stack)}`); input.acceptToken(isStartOfPlanningLine); return; } log(`XX REFUSE isStartOfPlanningLine_lookaround ${inputStreamEndString(input, stack)}`); return; }); var planningKeyword_tokenizer = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START planningKeyword_tokenizer ${inputStreamBeginString(input)}`); let peek_distance = 0; let c = input.peek(peek_distance); while (c === SPACE && !isEndOfLine(c)) { peek_distance += 1; c = input.peek(peek_distance); } if (isEndOfLine(c)) { log(`XX REFUSE planningKeyword_tokenizer, reached eol ${inputStreamEndString(input, stack)}`); return; } const expectedPlanningWords = ["SCHEDULED:", "DEADLINE:", "CLOSED:"]; let hasMatched = false; let matchedWord = null; while (c !== SPACE && !isEndOfLine(c)) { matchedWord = matchWords(input, expectedPlanningWords, peek_distance); if (matchedWord && (input.peek(peek_distance - 1) === SPACE || isEndOfLine(input.peek(peek_distance - 1)))) { hasMatched = true; peek_distance += matchedWord.length; c = input.peek(peek_distance); break; } peek_distance += 1; c = input.peek(peek_distance); } if (!hasMatched) { log(`XX REFUSE planningKeyword_tokenizer, found word that was not a planning part ${inputStreamEndString(input, stack)}`); return; } while (c === SPACE && !isEndOfLine(c)) { peek_distance += 1; c = input.peek(peek_distance); } input.advance(peek_distance); if (matchedWord === "DEADLINE:") { log(`== ACCEPT planningKeyword_tokenizer, deadline ${inputStreamAccept(input, stack)}`); input.acceptToken(PlanningDeadline); } else if (matchedWord === "SCHEDULED:") { log(`== ACCEPT planningKeyword_tokenizer, scheduled ${inputStreamAccept(input, stack)}`); input.acceptToken(PlanningScheduled); } else if (matchedWord === "CLOSED:") { log(`== ACCEPT planningKeyword_tokenizer, closed ${inputStreamAccept(input, stack)}`); input.acceptToken(PlanningClosed); } log(`XX REFUSE planningKeyword_tokenizer ${inputStreamEndString(input, stack)}`); return; }); var planningValue_tokenizer = new import_lr2.ExternalTokenizer((input, stack) => { log(`-- START planningValue_tokenizer ${inputStreamBeginString(input)}`); let peek_distance = 0; let c = input.peek(peek_distance); const expectedPlanningWords = ["SCHEDULED:", "DEADLINE:", "CLOSED:"]; while (!isEndOfLine(c)) { const matchedNextWord = matchWords(input, expectedPlanningWords, peek_distance); if (matchedNextWord && (input.peek(peek_distance - 1) === SPACE || isEndOfLine(input.peek(peek_distance - 1)))) { break; } peek_distance += 1; c = input.peek(peek_distance); } input.advance(peek_distance); if (isEndOfLine(c)) { input.advance(); } log(`== ACCEPT PlanningValue ${inputStreamAccept(input, stack)}`); input.acceptToken(PlanningValue); return; }); var object_tokenizer = (orgLinkParameters2) => { return new import_lr2.ExternalTokenizer((input, stack) => { const context = stack.context; const innerMostParent = context.parentObjects[context.parentObjects.length - 1]; let MARKER = null; if (innerMostParent === ParentObject.TextBold) { MARKER = STAR; } else if (innerMostParent === ParentObject.TextItalic) { MARKER = "/".charCodeAt(0); } else if (innerMostParent === ParentObject.TextUnderline) { MARKER = "_".charCodeAt(0); } else if (innerMostParent === ParentObject.TextVerbatim) { MARKER = "=".charCodeAt(0); } else if (innerMostParent === ParentObject.TextCode) { MARKER = "~".charCodeAt(0); } else if (innerMostParent === ParentObject.TextStrikeThrough) { MARKER = "+".charCodeAt(0); } const termsByMarker = /* @__PURE__ */ new Map([ [STAR, isStartOfTextBold], ["/".charCodeAt(0), isStartOfTextItalic], ["_".charCodeAt(0), isStartOfTextUnderline], ["=".charCodeAt(0), isStartOfTextVerbatim], ["~".charCodeAt(0), isStartOfTextCode], ["+".charCodeAt(0), isStartOfTextStrikeThrough] ]); log(`-- START object_tokenizer innermostParent=${innerMostParent} ${inputStreamBeginString(input)}`); let c = input.peek(0); log(stringifyCodeLogString(c)); while (true) { if (input.pos === stack.pos && c === EOF) { log(`XX REFUSE object_tokenizer, reached EOF ${inputStreamAccept(input, stack)}`); return; } else if (context.parentObjects.includes(ParentObject.Title) && isEndOfLine(c)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before endofline in title ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (context.parentObjects.includes(ParentObject.Title) && checkTags(input, false)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before Tags in title ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (input.pos === stack.pos) { } else if (c === EOF) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before eof ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (checkStartOfHeading(input)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before Heading ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (checkPropertyDrawer(input, stack)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before PropertyDrawer ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (checkBlock(input, stack)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before Block ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (checkComment(input, stack)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before comment ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (checkKeywordComment(input, stack)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before keywordComment ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (!context.parentObjects.includes(ParentObject.RegularLink) && !context.parentObjects.includes(ParentObject.AngleLink) && (checkRegularLink(input, stack, orgLinkParameters2) || checkAngleLink(input, stack, orgLinkParameters2) || checkPlainLink(input, stack, orgLinkParameters2, true))) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before start of link ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (context.parentObjects.includes(ParentObject.RegularLink) && matchWords(input, ["]]"])) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before end of RegularLink ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (context.parentObjects.includes(ParentObject.AngleLink) && matchWords(input, [">"])) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before end of AngleLink ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (MARKER && c === MARKER && checkValidEndOfTextMarkup(input, stack, MARKER)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before end of markup ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (c === STAR && !context.parentObjects.includes(ParentObject.TextBold) && context.parentObjects.includes(ParentObject.Title) && isStartOfTextMarkup(input, stack, termsByMarker, true, orgLinkParameters2)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before TextBold ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (c === "/".charCodeAt(0) && !context.parentObjects.includes(ParentObject.TextItalic) && context.parentObjects.includes(ParentObject.Title) && isStartOfTextMarkup(input, stack, termsByMarker, true, orgLinkParameters2)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before TextItalic ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (c === "_".charCodeAt(0) && !context.parentObjects.includes(ParentObject.TextUnderline) && context.parentObjects.includes(ParentObject.Title) && isStartOfTextMarkup(input, stack, termsByMarker, true, orgLinkParameters2)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before TextUnderline ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (c === "=".charCodeAt(0) && !context.parentObjects.includes(ParentObject.TextVerbatim) && context.parentObjects.includes(ParentObject.Title) && isStartOfTextMarkup(input, stack, termsByMarker, true, orgLinkParameters2)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before TextVerbatim ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (c === "~".charCodeAt(0) && !context.parentObjects.includes(ParentObject.TextCode) && context.parentObjects.includes(ParentObject.Title) && isStartOfTextMarkup(input, stack, termsByMarker, true, orgLinkParameters2)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before TextCode ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (c === "+".charCodeAt(0) && !context.parentObjects.includes(ParentObject.TextStrikeThrough) && context.parentObjects.includes(ParentObject.Title) && isStartOfTextMarkup(input, stack, termsByMarker, true, orgLinkParameters2)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before TextStrikeThrough ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (c === STAR && !context.parentObjects.includes(ParentObject.TextBold) && !context.parentObjects.includes(ParentObject.Title) && isStartOfTextMarkup(input, stack, termsByMarker, false, orgLinkParameters2)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before TextBold ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (c === "/".charCodeAt(0) && !context.parentObjects.includes(ParentObject.TextItalic) && !context.parentObjects.includes(ParentObject.Title) && isStartOfTextMarkup(input, stack, termsByMarker, false, orgLinkParameters2)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before TextItalic ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (c === "_".charCodeAt(0) && !context.parentObjects.includes(ParentObject.TextUnderline) && !context.parentObjects.includes(ParentObject.Title) && isStartOfTextMarkup(input, stack, termsByMarker, false, orgLinkParameters2)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before TextUnderline ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (c === "=".charCodeAt(0) && !context.parentObjects.includes(ParentObject.TextVerbatim) && !context.parentObjects.includes(ParentObject.Title) && isStartOfTextMarkup(input, stack, termsByMarker, false, orgLinkParameters2)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before TextVerbatim ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (c === "~".charCodeAt(0) && !context.parentObjects.includes(ParentObject.TextCode) && !context.parentObjects.includes(ParentObject.Title) && isStartOfTextMarkup(input, stack, termsByMarker, false, orgLinkParameters2)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before TextCode ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } else if (c === "+".charCodeAt(0) && !context.parentObjects.includes(ParentObject.TextStrikeThrough) && !context.parentObjects.includes(ParentObject.Title) && isStartOfTextMarkup(input, stack, termsByMarker, false, orgLinkParameters2)) { log(`== ACCEPT object_tokenizer innermostParent=${innerMostParent} before TextStrikeThrough ${inputStreamAccept(input, stack)}`); input.acceptToken(objectToken); return; } c = input.advance(); log(stringifyCodeLogString(c)); } }); }; var ParentObject = /* @__PURE__ */ ((ParentObject2) => { ParentObject2[ParentObject2["Title"] = 0] = "Title"; ParentObject2[ParentObject2["TextBold"] = 1] = "TextBold"; ParentObject2[ParentObject2["TextItalic"] = 2] = "TextItalic"; ParentObject2[ParentObject2["TextUnderline"] = 3] = "TextUnderline"; ParentObject2[ParentObject2["TextVerbatim"] = 4] = "TextVerbatim"; ParentObject2[ParentObject2["TextCode"] = 5] = "TextCode"; ParentObject2[ParentObject2["TextStrikeThrough"] = 6] = "TextStrikeThrough"; ParentObject2[ParentObject2["RegularLink"] = 7] = "RegularLink"; ParentObject2[ParentObject2["AngleLink"] = 8] = "AngleLink"; ParentObject2[ParentObject2["Block"] = 9] = "Block"; return ParentObject2; })(ParentObject || {}); var OrgContext = class { constructor(headingLevelStack, levelHeadingToPush, parentObjects, currentBlockContext) { this.headingLevelStack = headingLevelStack; this.levelHeadingToPush = levelHeadingToPush; this.parentObjects = parentObjects; this.currentBlockContext = currentBlockContext, this.hash = this.hashCompute(); } hashCompute() { let hash2 = 0; let bitmask = 0; for (let headingLevel of this.headingLevelStack) { hash2 += headingLevel << (bitmask = bitmask + 10); } hash2 += this.levelHeadingToPush << (bitmask = bitmask + 10); for (let parent of this.parentObjects) { hash2 += parent + 1 << (bitmask = bitmask + 10); } if (this.currentBlockContext) { for (let char of this.currentBlockContext) { hash2 += char.charCodeAt(0) << (bitmask = bitmask + 1); } } return hash2; } }; var context_tracker = new import_lr2.ContextTracker({ start: new OrgContext([], null, [], null), shift(context, term, stack, input) { let headingLevelStack = [...context.headingLevelStack]; let levelHeadingToPush = context.levelHeadingToPush; let parentObjects = [...context.parentObjects]; let currentBlockContext = context.currentBlockContext; if (term === indentHeading) { const toPush = levelHeadingToPush; levelHeadingToPush = null; headingLevelStack.push(toPush); } if (term === dedentHeading) { const toPop = headingLevelStack[headingLevelStack.length - 1]; headingLevelStack.pop(); } if (term === isStartOfTextBold) { parentObjects.push(1 /* TextBold */); } if (term === isStartOfTextItalic) { parentObjects.push(2 /* TextItalic */); } if (term === isStartOfTextUnderline) { parentObjects.push(3 /* TextUnderline */); } if (term === isStartOfTextVerbatim) { parentObjects.push(4 /* TextVerbatim */); } if (term === isStartOfTextCode) { parentObjects.push(5 /* TextCode */); } if (term === isStartOfTextStrikeThrough) { parentObjects.push(6 /* TextStrikeThrough */); } if (term === isEndOfTextBold || term === isEndOfTextItalic || term === isEndOfTextUnderline || term === isEndOfTextVerbatim || term === isEndOfTextCode || term === isEndOfTextStrikeThrough) { parentObjects.pop(); } if (term === isStartOfRegularLink) { parentObjects.push(7 /* RegularLink */); } if (term === exitRegularLink) { parentObjects.pop(); } if (term === isStartOfAngleLink) { parentObjects.push(8 /* AngleLink */); } if (term === exitAngleLink) { parentObjects.pop(); } if (term === stars) { parentObjects.push(0 /* Title */); } if (term === endofline) { parentObjects.pop(); } if (term === BlockHeader) { parentObjects.push(9 /* Block */); } if (term === BlockFooter) { parentObjects.pop(); currentBlockContext = null; } return new OrgContext(headingLevelStack, levelHeadingToPush, parentObjects, currentBlockContext); }, hash: (context) => context.hash }); // codemirror-lang-orgmode/src/generated_grammar.ts var grammarFile = `@top Program { ZerothSection? Heading* } ZerothSection { notStartOfHeading (startOfComment CommentLine)* PropertyDrawer? ( notStartOfPropertyDrawer ( notStartOfHeading lesserElement )+ )? } // https://orgmode.org/worg/org-syntax.html#Headings Heading { shouldIndentHeading indentHeading stars TodoKeyword? Priority? Title? Tags? endofline Section? Heading* shouldDedentHeading dedentHeading } Title { object+ } Section { notStartOfHeading ((startOfComment CommentLine) | (isStartOfPlanningLine planningLine))* PropertyDrawer? ( notStartOfPlanning notStartOfPropertyDrawer ( notStartOfHeading lesserElement )+ )? } lesserElement { // excluding Planning and Comment Block | ( notStartOfABlock ( (startOfComment CommentLine) | ( notStartOfComment paragraph { object+ } ) | ( startOfKeywordComment KeywordComment ) ) ) } Block { BlockHeader ( BlockContentDynamic | BlockContentCenter | BlockContentQuote | BlockContentComment | BlockContentExample | BlockContentExport | BlockContentSrc | BlockContentVerse | BlockContentSpecial ) BlockFooter } // https://orgmode.org/worg/org-syntax.html#Planning planningLine { ((PlanningDeadline | PlanningScheduled | PlanningClosed) PlanningValue)+ } object { link | textMarkup | objectToken } link { RegularLink | AngleLink | PlainLink } RegularLink { isStartOfRegularLink "[[" object+ exitRegularLink // ]] } AngleLink { isStartOfAngleLink "<" object+ exitAngleLink // > } textMarkup { (isStartOfTextBold TextBold) | (isStartOfTextItalic TextItalic) | (isStartOfTextUnderline TextUnderline) | (isStartOfTextVerbatim TextVerbatim) | (isStartOfTextCode TextCode) | (isStartOfTextStrikeThrough TextStrikeThrough) } TextBold { "*" object+ isEndOfTextBold // * } TextItalic { "/" object+ isEndOfTextItalic // / } TextUnderline { "_" object+ isEndOfTextUnderline // _ } TextVerbatim { "=" object+ isEndOfTextVerbatim // = } TextCode { "~" object+ isEndOfTextCode // ~ } TextStrikeThrough { "+" object+ isEndOfTextStrikeThrough // + } @context context_tracker from "./external-tokens" // Exit tokens are always true so they must be the // first ones to be tested so that other tokens are not accepted before them @external tokens exitRegularLink_tokenizer from "./external-tokens" { exitRegularLink } @external tokens exitAngleLink_tokenizer from "./external-tokens" { exitAngleLink } @external tokens isEndOfTextMarkup_tokenizer from "./external-tokens" { isEndOfTextBold, isEndOfTextItalic, isEndOfTextUnderline, isEndOfTextVerbatim, isEndOfTextCode, isEndOfTextStrikeThrough } @external tokens block_tokenizer from "./external-tokens" { notStartOfABlock, BlockHeader, BlockFooter } @external tokens blockContent_tokenizer from "./external-tokens" { BlockContentDynamic, BlockContentCenter, BlockContentQuote, BlockContentComment, BlockContentExample, BlockContentExport, BlockContentSrc, BlockContentVerse, BlockContentSpecial } @external tokens startOfComment_lookaround from "./external-tokens" { startOfComment } @external tokens startOfKeywordComment_lookaround from "./external-tokens" { startOfKeywordComment } @external tokens isStartOfRegularLink_lookaround from "./external-tokens" { isStartOfRegularLink } @external tokens isStartOfAngleLink_lookaround from "./external-tokens" { isStartOfAngleLink } @external tokens plainLink_tokenizer from "./external-tokens" { PlainLink } @external tokens isStartOfTextMarkup_lookaround from "./external-tokens" { isStartOfTextBold, isStartOfTextItalic, isStartOfTextUnderline, isStartOfTextVerbatim, isStartOfTextCode, isStartOfTextStrikeThrough } // https://orgmode.org/worg/org-syntax.html#Property_Drawers @external tokens propertydrawer_tokenizer from "./external-tokens" { PropertyDrawer } @external tokens todokeyword_tokenizer from "./external-tokens" { TodoKeyword } @external tokens priority_tokenizer from "./external-tokens" { Priority } @external tokens isStartOfPlanningLine_lookaround from "./external-tokens" { isStartOfPlanningLine } @external tokens notStartOfPlanning_lookaround from "./external-tokens" { notStartOfPlanning } @external tokens notStartOfPropertyDrawer_lookaround from "./external-tokens" { notStartOfPropertyDrawer } @external tokens notStartOfComment_lookaround from "./external-tokens" { notStartOfComment } @external tokens startOfHeading_lookaround from "./external-tokens" { notStartOfHeading, shouldIndentHeading, shouldDedentHeading } @external tokens indentHeading_lookaround from "./external-tokens" { indentHeading } @external tokens dedentHeading_lookaround from "./external-tokens" { dedentHeading } @external tokens stars_tokenizer from "./external-tokens" { stars } @external tokens planningKeyword_tokenizer from "./external-tokens" { PlanningDeadline PlanningScheduled PlanningClosed } @external tokens planningValue_tokenizer from "./external-tokens" { PlanningValue } @external tokens tags_tokenizer from "./external-tokens" { Tags } @external tokens endofline_tokenizer from "./external-tokens" { endofline } @external tokens object_tokenizer from "./external-tokens" { objectToken } @tokens { CommentLine { "#" (" " | @eof | (" " ![ ]* (" " | @eof))) } KeywordComment { "#+" ![ ]* (" " | @eof) } }`; // codemirror-lang-orgmode/src/index.ts var orgLinkParameters = [ // "shell", // "news", "mailto", "https", "http", // "ftp", // "help", "file", // "elisp", "id" ]; var configurableExternalTokenizer = (words) => { return (name, terms) => { if (name == "title_tokenizer") { return title_tokenizer(words); } if (name == "todokeyword_tokenizer") { return todokeyword_tokenizer(words); } if (name == "isStartOfRegularLink_lookaround") { return isStartOfRegularLink_lookaround(orgLinkParameters); } if (name == "isStartOfAngleLink_lookaround") { return isStartOfAngleLink_lookaround(orgLinkParameters); } if (name == "plainLink_tokenizer") { return plainLink_tokenizer(orgLinkParameters); } if (name == "isStartOfTextMarkup_lookaround") { return isStartOfTextMarkup_lookaround(orgLinkParameters); } if (name == "object_tokenizer") { return object_tokenizer(orgLinkParameters); } return external_tokens_exports[name]; }; }; var OrgmodeParser = (words) => { const options = { externalTokenizer: configurableExternalTokenizer(words), contextTracker: context_tracker }; return buildParser(grammarFile.toString(), options); }; var OrgmodeLanguage = (parser) => { return import_language2.LRLanguage.define({ parser: parser.configure({ props: [ (0, import_highlight.styleTags)({ "Heading": import_highlight.tags.heading, "PlanningDeadline": import_highlight.tags.annotation, "PlanningClosed": import_highlight.tags.annotation, "PlanningScheduled": import_highlight.tags.annotation, "PropertyDrawer": import_highlight.tags.meta, "ZerothSection": import_highlight.tags.content, "Section": import_highlight.tags.content, "CommentLine": import_highlight.tags.lineComment, "KeywordComment": import_highlight.tags.lineComment, "TodoKeyword": import_highlight.tags.keyword, "Title": import_highlight.tags.contentSeparator, "Priority": import_highlight.tags.unit, "Tags": import_highlight.tags.tagName, "TextBold": import_highlight.tags.strong, "TextItalic": import_highlight.tags.emphasis, "TextUnderline": import_highlight.tags.modifier, "TextVerbatim": import_highlight.tags.literal, "TextCode": import_highlight.tags.monospace, "TextStrikeThrough": import_highlight.tags.strikethrough, "PlainLink": import_highlight.tags.link, "RegularLink": import_highlight.tags.link, "AngleLink": import_highlight.tags.link }) ] }), languageData: { commentTokens: { line: "#" } } }); }; // settings.ts var DEFAULT_SETTINGS = { todoKeywords: ["TODO", "DOING", "WAITING", "NEXT", "PENDING"], doneKeywords: ["DONE", "CANCELLED", "CANCELED", "CANCEL", "REJECTED", "STOP", "STOPPED"], hideStars: false }; // org-tasks.ts function cycleOrgmodeTaskStatusContent(orgmode_task, orgmode_content) { const pos = orgmode_task.taskLocation.status; const new_keyword = orgmode_task.statusType === "DONE" /* DONE */ ? "TODO" : "DONE"; const replaced_content = orgmode_content.substring(0, pos[0]) + new_keyword + orgmode_content.substring(pos[1]); return replaced_content; } function parseOrgmodeHeading(headingNode, orgmode_content, settings) { const children = headingNode.getChildren(parser_terms_exports.Heading); const orgHeading = extractOrgHeadingFromHeadingNode(headingNode, orgmode_content, settings); if (children && children.length !== 0) { const orgHeadingChildren = children.map((heading) => parseOrgmodeHeading(heading, orgmode_content, settings)); orgHeading.children = orgHeadingChildren.filter((task) => task !== null); } return orgHeading; } function iterateTasks(heading) { if (heading.status !== null) { const task = { status: heading.status, statusType: heading.statusType, description: heading.description, taskLocation: heading.taskLocation, priority: heading.priority }; return [task, ...heading.children.map((x) => iterateTasks(x)).flat()]; } else { return [...heading.children.map((x) => iterateTasks(x)).flat()]; } } function parseOrgmodeTasks(orgmode_content, settings, orgmodeParser) { const headings = parseOrgmodeContent(orgmode_content, settings, orgmodeParser); return headings.map((x) => iterateTasks(x)).flat(); } function parseOrgmodeContent(orgmode_content, settings, orgmodeParser) { const parsed = orgmodeParser.parse(orgmode_content); const topNode = parsed.topNode; const children = topNode.getChildren(parser_terms_exports.Heading); const orgmode_headings = children.map((heading) => { return parseOrgmodeHeading(heading, orgmode_content, settings); }).filter((x) => x !== null); return orgmode_headings; } function extractOrgHeadingFromHeadingNode(headingNode, orgmode_content, settings) { var _a, _b, _c, _d; const item = /* @__PURE__ */ new Map(); item.set("taskLocation", /* @__PURE__ */ new Map()); const TodoKeywordNode = headingNode.getChild(parser_terms_exports.TodoKeyword); const TitleNode = headingNode.getChild(parser_terms_exports.Title); const PriorityNode = headingNode.getChild(parser_terms_exports.Priority); if (TodoKeywordNode) { item.set("status", orgmode_content.slice(TodoKeywordNode.from, TodoKeywordNode.to)); item.get("taskLocation").set("status", [TodoKeywordNode.from, TodoKeywordNode.to]); } if (TitleNode) { item.set("description", orgmode_content.slice(TitleNode.from, TitleNode.to).trim()); } if (PriorityNode) { const priority_match = orgmode_content.slice(PriorityNode.from, PriorityNode.to).match(new RegExp("\\[#(.)\\]")); item.set("priority", priority_match[1]); item.get("taskLocation").set("priority", [PriorityNode.from + priority_match.index + 2, PriorityNode.from + priority_match.index + 3]); } const taskLocation = { status: (_a = item.get("taskLocation").get("status")) != null ? _a : null, priority: (_b = item.get("taskLocation").get("priority")) != null ? _b : null }; const status = (_c = item.get("status")) != null ? _c : null; const statusType = settings.doneKeywords.includes(status) ? "DONE" /* DONE */ : "TODO" /* TODO */; const task = { status, statusType, description: item.get("description"), priority: (_d = item.get("priority")) != null ? _d : null, taskLocation, children: [] // will be set later }; return task; } // org-tasks-file-sync.ts var OrgTasksSync = class { constructor(settings, orgmodeParser, vault) { this.settings = settings; this.orgmodeParser = orgmodeParser; this.vault = vault; this.vault = vault; this.settings = settings; this.onModifiedRef = null; this.unloaded = false; this.orgmodeParser = orgmodeParser; } onunload() { if (!this.unloaded) { if (this.onModifiedRef !== null) { this.vault.offref(this.onModifiedRef); } this.unloaded = true; } } onmodified(tfile, callback) { if (this.unloaded) { return; } if (this.onModifiedRef !== null) { this.vault.offref(this.onModifiedRef); } this.onModifiedRef = this.vault.on("modify", async (file) => { if (file !== tfile) { return; } const newest_orgmode_content = await this.vault.read(tfile); const orgmode_tasks = parseOrgmodeTasks(newest_orgmode_content, this.settings, this.orgmodeParser); callback(orgmode_tasks); }); } async updateTaskStatus(tfile, orgmode_task) { if (this.unloaded) { return; } await this.vault.process(tfile, (newest_orgmode_content) => { const replaced_content = cycleOrgmodeTaskStatusContent(orgmode_task, newest_orgmode_content); return replaced_content; }); } async getTasks(tfile) { if (this.unloaded) { return; } const orgmode_tasks = parseOrgmodeTasks(await this.vault.read(tfile), this.settings, this.orgmodeParser); return orgmode_tasks; } }; // language-extensions.ts var import_language3 = require("@codemirror/language"); function nodeTypeClass(node_type_id) { if (node_type_id === parser_terms_exports.TextBold) { return "org-text-bold"; } else if (node_type_id === parser_terms_exports.TextItalic) { return "org-text-italic"; } else if (node_type_id === parser_terms_exports.TextUnderline) { return "org-text-underline"; } else if (node_type_id === parser_terms_exports.TextVerbatim) { return "org-text-verbatim"; } else if (node_type_id === parser_terms_exports.TextCode) { return "org-text-code"; } else if (node_type_id === parser_terms_exports.TextStrikeThrough) { return "org-text-strikethrough"; } else if (node_type_id === parser_terms_exports.Block) { return "org-block"; } else if (node_type_id === parser_terms_exports.RegularLink || node_type_id === parser_terms_exports.AngleLink || node_type_id === parser_terms_exports.PlainLink) { return "org-link"; } else if (node_type_id === parser_terms_exports.Heading) { return "org-heading"; } else if (node_type_id === parser_terms_exports.Title) { return "org-title"; } else if (node_type_id === parser_terms_exports.PlanningDeadline || node_type_id === parser_terms_exports.PlanningScheduled || node_type_id === parser_terms_exports.PlanningClosed) { return "org-planning"; } else if (node_type_id === parser_terms_exports.PropertyDrawer) { return "org-propertydrawer"; } else if (node_type_id === parser_terms_exports.ZerothSection || node_type_id === parser_terms_exports.Section) { return "org-section"; } else if (node_type_id === parser_terms_exports.CommentLine || node_type_id === parser_terms_exports.KeywordComment) { return "org-comment"; } else if (node_type_id === parser_terms_exports.TodoKeyword) { return "org-keyword"; } else if (node_type_id === parser_terms_exports.Priority) { return "org-priority"; } else if (node_type_id === parser_terms_exports.Tags) { return "org-tags"; } throw Error("Not a markup node"); } var OrgFoldCompute = (state, from, to) => { let currentLineNode = (0, import_language3.syntaxTree)(state).topNode.resolve(from, 1).node; const onFirstLine = state.doc.lineAt(from).number === state.doc.lineAt(currentLineNode.from).number; if (currentLineNode.type.id === parser_terms_exports.Heading) { const heading = currentLineNode; const hasSection = currentLineNode.getChild(parser_terms_exports.Section); const hasHeading = currentLineNode.getChild(parser_terms_exports.Heading); if (!hasSection && !hasHeading) { return null; } let block_to = heading.to; if (state.doc.sliceString(block_to - 1, block_to) === "\n") { block_to = block_to - 1; } return { from: to, to: block_to }; } else if (currentLineNode.type.id === parser_terms_exports.PropertyDrawer) { if (!onFirstLine) { return null; } const propertyDrawer = currentLineNode; let block_to = propertyDrawer.to; if (state.doc.sliceString(block_to - 1, block_to) === "\n") { block_to = block_to - 1; } return { from: to, to: block_to }; } else if (currentLineNode.type.id === parser_terms_exports.Block) { if (!onFirstLine) { return null; } const blockNode = currentLineNode; let block_to = blockNode.to; if (state.doc.sliceString(block_to - 1, block_to) === "\n") { block_to = block_to - 1; } return { from: to, to: block_to }; } return null; }; var makeHeadingsFoldable = import_language3.foldService.of(OrgFoldCompute); function linkIsImage(linkText) { if (!linkText.includes(".")) { return false; } const ext = linkText.slice(linkText.lastIndexOf(".")); const imageExtensions = [".apng", ".avif", ".gif", ".jpeg", ".jpg", ".png", ".svg", ".webp"]; return imageExtensions.includes(ext); } function parseLinkText(linkText) { const idx = linkText.indexOf(":"); let linkPath = null; let linkHandler = null; let linkType = null; if (idx === -1) { linkHandler = "internal-file"; linkPath = linkText; } else if (/:\/\//.test(linkText)) { linkPath = linkText; linkHandler = "external"; } else { linkType = linkText.slice(0, idx); linkPath = linkText.slice(idx + 1); if (linkType === "file") { linkHandler = "internal-file"; } else if (linkType === "id") { linkHandler = "internal-id"; } else { linkHandler = "internal-file"; } } return [linkPath, linkHandler]; } var extractLinkFromNode = (node, linkText) => { let linkHandler = null; let linkPath = null; let displayText = null; let hasLinkDescription = false; let displayTextFromOffset = null; let displayTextToOffset = null; if (node === parser_terms_exports.PlainLink) { linkPath = linkText; displayTextFromOffset = 0; displayTextToOffset = 0; linkHandler = "external"; let [linkPathDetected, linkHandlerDetected] = parseLinkText(linkText); if (linkHandlerDetected == "internal-id") { linkHandler = "internal-id"; linkPath = linkPathDetected; } } else if (node === parser_terms_exports.RegularLink) { let innerLinkText; if (/\]\[/.test(linkText)) { const idx = linkText.search(/\]\[/); innerLinkText = linkText.slice(2, idx); displayTextFromOffset = idx + 2; displayTextToOffset = -2; hasLinkDescription = true; } else { innerLinkText = linkText.slice(2, -2); displayTextFromOffset = 2; displayTextToOffset = -2; } [linkPath, linkHandler] = parseLinkText(innerLinkText); } else if (node === parser_terms_exports.AngleLink) { [linkPath, linkHandler] = parseLinkText(linkText.slice(1, -1)); displayTextFromOffset = 1; displayTextToOffset = -1; } if (linkHandler === "internal-file" && linkIsImage(linkPath) && !hasLinkDescription) { linkHandler = "internal-inline-image"; displayTextFromOffset = null; displayTextToOffset = null; } if (displayTextFromOffset !== null) { displayText = linkText.slice(displayTextFromOffset, linkText.length + displayTextToOffset); } return [linkPath, displayText, linkHandler, displayTextFromOffset]; }; function* iterateHeadings(node) { const headings = node.getChildren(parser_terms_exports.Heading); for (const heading of headings) { yield heading; yield* iterateHeadings(heading); } } function* iterateOrgIds(orgmodeParser, orgContent) { var _a, _b; const tree = orgmodeParser.parse(orgContent); const id_regex = /:ID:\s+([^\s]+)\s*/; const topPropertyDrawer = (_a = tree.topNode.getChild(parser_terms_exports.ZerothSection)) == null ? void 0 : _a.getChild(parser_terms_exports.PropertyDrawer); if (topPropertyDrawer) { const top_pd_content = orgContent.slice(topPropertyDrawer.from, topPropertyDrawer.to); const match_file = id_regex.exec(top_pd_content); if (match_file) { const extracted_id = match_file[1]; yield { orgId: extracted_id, start: 0 }; } } for (const heading of iterateHeadings(tree.topNode)) { const propertyDrawer = (_b = heading.node.getChild(parser_terms_exports.Section)) == null ? void 0 : _b.getChild(parser_terms_exports.PropertyDrawer); if (!propertyDrawer) { continue; } const heading_start = heading.from; const pd_content = orgContent.slice(propertyDrawer.from, propertyDrawer.to); const match_heading = id_regex.exec(pd_content); if (match_heading) { const extracted_id = match_heading[1]; yield { orgId: extracted_id, start: heading_start }; } } } // org-live-preview.ts var import_state2 = require("@codemirror/state"); var import_view2 = require("@codemirror/view"); var import_language4 = require("@codemirror/language"); var ImageWidget = class extends import_view2.WidgetType { constructor(path, getImageUri) { super(); this.path = path; this.getImageUri = getImageUri; } eq(other) { return this.path == other.path; } toDOM(view) { const image = document.createElement("img"); const obsidianPath = this.getImageUri(this.path); if (obsidianPath) { image.src = this.getImageUri(this.path); } else { image.src = this.path; } return image; } }; function isNodeSelected(selection, node) { return ( // selection starts inside node selection.from >= node.from && selection.from <= node.to || // selection ends inside node selection.to >= node.from && selection.to <= node.to || // selection is bigger than node selection.from < node.from && selection.to > node.to ); } function loadDecorations(state, settings, obsidianUtils) { const builderBuffer = new Array(); const selectionPos = state.selection.main; (0, import_language4.syntaxTree)(state).iterate({ enter(node) { const nodeIsSelected = isNodeSelected(selectionPos, node); if (node.type.id === parser_terms_exports.Block) { const firstLine = state.doc.lineAt(node.from); const lastLine = state.doc.lineAt(node.to - 1); for (let i = firstLine.number; i <= lastLine.number; ++i) { const line = state.doc.line(i); builderBuffer.push([line.from, line.from, import_view2.Decoration.line({ class: nodeTypeClass(node.type.id) })]); } const firstLineIsSelected = isNodeSelected(selectionPos, firstLine); if (!firstLineIsSelected) { builderBuffer.push([firstLine.from, firstLine.from + "#+BEGIN_".length, import_view2.Decoration.replace({})]); builderBuffer.push([firstLine.from + "#+BEGIN_".length, firstLine.to, import_view2.Decoration.mark({ class: "org-block-header" })]); } const lastLineIsSelected = isNodeSelected(selectionPos, lastLine); if (!lastLineIsSelected) { builderBuffer.push([lastLine.from, lastLine.to, import_view2.Decoration.replace({})]); } } else if (node.type.id === parser_terms_exports.PlainLink || node.type.id === parser_terms_exports.RegularLink || node.type.id === parser_terms_exports.AngleLink) { const linkText = state.doc.sliceString(node.from, node.to); const [linkPath, displayText, linkHandler, displayTextFromOffset] = extractLinkFromNode(node.type.id, linkText); if (linkHandler === "internal-inline-image") { if (nodeIsSelected) { builderBuffer.push([node.from, node.to, import_view2.Decoration.mark({ class: nodeTypeClass(node.type.id) })]); builderBuffer.push([ node.to, node.to, import_view2.Decoration.widget({ widget: new ImageWidget(linkPath, obsidianUtils.getImageUri), block: true }) ]); } else { builderBuffer.push([ node.from, node.to, import_view2.Decoration.replace({ widget: new ImageWidget(linkPath, obsidianUtils.getImageUri) }) ]); } } else if (!nodeIsSelected) { if (node.type.id === parser_terms_exports.RegularLink && linkPath !== displayText) { builderBuffer.push([node.from, node.from + displayTextFromOffset, import_view2.Decoration.replace({})]); builderBuffer.push([ node.from + displayTextFromOffset, node.to - 2, import_view2.Decoration.mark({ tagName: "a", attributes: { href: "#" } }) ]); builderBuffer.push([node.to - 2, node.to, import_view2.Decoration.replace({})]); } else if (node.type.id === parser_terms_exports.RegularLink) { builderBuffer.push([node.from, node.from + 2, import_view2.Decoration.replace({})]); builderBuffer.push([ node.from + 2, node.to - 2, import_view2.Decoration.mark({ tagName: "a", attributes: { href: "#" } }) ]); builderBuffer.push([node.to - 2, node.to, import_view2.Decoration.replace({})]); } else if (node.type.id === parser_terms_exports.AngleLink) { builderBuffer.push([node.from, node.from + 1, import_view2.Decoration.replace({})]); builderBuffer.push([ node.from + 1, node.to - 1, import_view2.Decoration.mark({ tagName: "a", attributes: { href: "#" } }) ]); builderBuffer.push([node.to - 1, node.to, import_view2.Decoration.replace({})]); } } else { builderBuffer.push([node.from, node.to, import_view2.Decoration.mark({ class: nodeTypeClass(node.type.id) })]); } } else if (node.type.id === parser_terms_exports.TextBold || node.type.id === parser_terms_exports.TextItalic || node.type.id === parser_terms_exports.TextUnderline || node.type.id === parser_terms_exports.TextVerbatim || node.type.id === parser_terms_exports.TextCode || node.type.id === parser_terms_exports.TextStrikeThrough) { if (!nodeIsSelected) { builderBuffer.push([node.from, node.from + 1, import_view2.Decoration.replace({})]); } builderBuffer.push([node.from, node.to, import_view2.Decoration.mark({ class: nodeTypeClass(node.type.id) })]); if (!nodeIsSelected) { builderBuffer.push([node.to - 1, node.to, import_view2.Decoration.replace({})]); } } else if (node.type.id === parser_terms_exports.Heading) { const headingLine = state.doc.lineAt(node.from); const headingLevel = headingLine.text.match(/^\*+/)[0].length; const headingClass = nodeTypeClass(node.type.id); const starsPos = { from: headingLine.from, to: headingLine.from + headingLevel + 1 }; const nodeStarsIsSelected = isNodeSelected(selectionPos, starsPos); if (settings.hideStars && !nodeStarsIsSelected) { builderBuffer.push([headingLine.from, headingLine.from + headingLevel + 1, import_view2.Decoration.replace({})]); builderBuffer.push([headingLine.from, headingLine.to, import_view2.Decoration.mark({ class: `${headingClass} ${headingClass}-${headingLevel}` })]); } else { builderBuffer.push([headingLine.from, headingLine.to, import_view2.Decoration.mark({ class: `${headingClass} ${headingClass}-${headingLevel}` })]); } const section = node.node.getChild(parser_terms_exports.Section); if (section) { builderBuffer.push([section.from, section.to, import_view2.Decoration.mark({ class: `${headingClass}-${headingLevel}` })]); } } else if (node.type.id === parser_terms_exports.Title || node.type.id === parser_terms_exports.PlanningDeadline || node.type.id === parser_terms_exports.PlanningScheduled || node.type.id === parser_terms_exports.PlanningClosed || node.type.id === parser_terms_exports.PropertyDrawer || node.type.id === parser_terms_exports.ZerothSection || node.type.id === parser_terms_exports.Section || node.type.id === parser_terms_exports.CommentLine || node.type.id === parser_terms_exports.KeywordComment || node.type.id === parser_terms_exports.TodoKeyword || node.type.id === parser_terms_exports.Priority || node.type.id === parser_terms_exports.Tags) { builderBuffer.push([node.from, node.to, import_view2.Decoration.mark({ class: nodeTypeClass(node.type.id) })]); } } }); const decorationRanges = []; for (const [from, to, decoration] of builderBuffer) { decorationRanges.push(decoration.range(from, to)); } return import_state2.RangeSet.of(decorationRanges, true); } var orgmodeLivePreview = (codeMirror, settings, obsidianUtils) => { return import_state2.StateField.define({ create(state) { return loadDecorations(state, settings, obsidianUtils); }, update(oldState, transaction) { return loadDecorations(transaction.state, settings, obsidianUtils); }, provide(field) { return [ import_view2.EditorView.decorations.from(field), import_view2.EditorView.domEventHandlers({ mousedown: (e) => { const clickPos = codeMirror.posAtCoords(e); const state = codeMirror.state; let nodeIterator = (0, import_language4.syntaxTree)(state).resolveStack(clickPos); let linkNode = null; while (nodeIterator) { if (nodeIterator.node.type.id === parser_terms_exports.RegularLink || nodeIterator.node.type.id === parser_terms_exports.AngleLink || nodeIterator.node.type.id === parser_terms_exports.PlainLink) { linkNode = nodeIterator.node; break; } nodeIterator = nodeIterator.next; } if (!linkNode) { return; } const linkText = state.doc.sliceString(linkNode.from, linkNode.to); const [linkPath, displayText, linkHandler, displayTextFromOffset] = extractLinkFromNode(linkNode.type.id, linkText); const orgmodeDecorationSet = state.field(field); orgmodeDecorationSet.between(clickPos, clickPos, (from, to, deco) => { if (deco.spec.tagName === "a") { if (linkHandler === "external") { window.open(linkPath); } else if (linkHandler === "internal-file") { obsidianUtils.navigateToFile(linkPath); } else if (linkHandler === "internal-id") { const orgCustomId = linkPath; obsidianUtils.navigateToOrgId(orgCustomId); } return false; } }); } }) ]; } }); }; // main.ts var todoKeywordsReloader = new import_state3.Compartment(); var vimCompartment = new import_state3.Compartment(); function parseKeywordTextArea(value) { return value.replace(/\n/g, ",").split(",").map((x) => x.trim()).filter((x) => x != ""); } var OrgmodeSettingTab = class extends import_obsidian.PluginSettingTab { constructor(app, plugin) { super(app, plugin); this.plugin = plugin; } display() { const { containerEl } = this; containerEl.empty(); new import_obsidian.Setting(containerEl).setName("Keywords for active (todo) tasks").addTextArea((text) => { text.setValue(this.plugin.settings.todoKeywords.join(",")).setPlaceholder("comma-separated values").onChange(async (value) => { this.plugin.settings.todoKeywords = parseKeywordTextArea(value); await this.plugin.saveSettings(); }); }); new import_obsidian.Setting(containerEl).setName("Keywords for completed (done) tasks").addTextArea((text) => { text.setValue(this.plugin.settings.doneKeywords.join(",")).setPlaceholder("comma-separated values").onChange(async (value) => { this.plugin.settings.doneKeywords = parseKeywordTextArea(value); await this.plugin.saveSettings(); }); }); new import_obsidian.Setting(containerEl).setName("Hide heading stars").setDesc("Hiding the stars is useful when using CSS to replace them").addToggle((toggle) => { toggle.setValue(this.plugin.settings.hideStars).onChange(async (value) => { this.plugin.settings.hideStars = value; await this.plugin.saveSettings(); }); }); } }; var OrgmodePlugin = class extends import_obsidian.Plugin { constructor() { super(...arguments); this.settingTab = null; this.orgViewCreator = (leaf) => { return new OrgView(leaf, this.orgmodeParser, this.settings); }; } async loadSettings() { this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); this.settings.todoKeywords = parseKeywordTextArea(this.settings.todoKeywords.join(",")); this.settings.doneKeywords = parseKeywordTextArea(this.settings.doneKeywords.join(",")); const words = [...this.settings.todoKeywords, ...this.settings.doneKeywords]; this.orgmodeParser = OrgmodeParser(words); } async saveSettings() { await this.saveData(this.settings); const view = this.app.workspace.getActiveViewOfType(OrgView); const words = [...this.settings.todoKeywords, ...this.settings.doneKeywords]; this.orgmodeParser = OrgmodeParser(words); view.codeMirror.dispatch({ effects: todoKeywordsReloader.reconfigure(new import_language5.LanguageSupport(OrgmodeLanguage(this.orgmodeParser))) }); } async onload() { await this.loadSettings(); this.settingTab = new OrgmodeSettingTab(this.app, this); this.addSettingTab(this.settingTab); this.registerView("orgmode", this.orgViewCreator); this.registerExtensions(["org"], "orgmode"); this.registerMarkdownCodeBlockProcessor("orgmode-tasks", async (src, el, ctx) => { try { let parameters = null; parameters = (0, import_obsidian.parseYaml)(src); if (typeof parameters.filepath === "undefined") { throw Error("Missing parameters filepath"); } const tfile = this.app.vault.getFileByPath(parameters.filepath); if (!tfile) { throw Error(`file not found: ${parameters.filepath}`); } const orgTasksSync = new OrgTasksSync(this.settings, this.orgmodeParser, this.app.vault); const rootEl = el.createEl("div"); const renderChild = new import_obsidian.MarkdownRenderChild(el); ctx.addChild(renderChild); renderChild.unload = () => { orgTasksSync.onunload(); }; const onStatusChange = async (orgmode_task) => { await orgTasksSync.updateTaskStatus(tfile, orgmode_task); }; let orgmode_tasks = await orgTasksSync.getTasks(tfile); this.render(orgmode_tasks, rootEl, onStatusChange); orgTasksSync.onmodified(tfile, (refreshed_tasks) => { this.render(refreshed_tasks, rootEl, onStatusChange); }); } catch (e) { el.createEl("h3", { text: "Error: " + e.message }); return; } }); } render(orgmode_tasks, rootEl, onStatusChange) { rootEl.innerHTML = ""; var list = rootEl.createEl("ul", { cls: "contains-task-list plugin-tasks-query-result tasks-layout-hide-urgency tasks-layout-hide-edit-button" }); orgmode_tasks.forEach((orgmode_task, i) => { this.renderTask(orgmode_task, i, list, onStatusChange); }); } renderTask(orgmode_task, i, list, onStatusChange) { const li = list.createEl("li", { cls: "task-list-item plugin-tasks-list-item" }); li.setAttribute("data-line", i.toString()); li.setAttribute("data-task-priority", "normal"); li.setAttribute("data-task-status-type", orgmode_task.statusType); if (orgmode_task.statusType === "DONE" /* DONE */) { li.setAttribute("data-task", "x"); li.setAttribute("data-task-status-name", "Done"); } else { li.setAttribute("data-task", ""); li.setAttribute("data-task-status-name", "Todo"); } const input = li.createEl("input", { cls: "task-list-item-checkbox", type: "checkbox" }); input.setAttribute("data-line", i.toString()); input.checked = orgmode_task.statusType === "DONE" /* DONE */; input.addEventListener("click", (e) => { onStatusChange(orgmode_task); }); li.createSpan({ cls: "tasks-list-text" }).createSpan({ cls: "task-description" }).createSpan({ text: orgmode_task.description }); } }; var OrgView = class extends import_obsidian.TextFileView { constructor(leaf, orgmodeParser, settings) { super(leaf); this.getViewData = () => { return this.codeMirror.state.doc.toString(); }; this.setViewData = (data, clear) => { this.codeMirror.setState(import_state3.EditorState.create({ doc: data, extensions: this.extensions })); }; this.clear = () => { }; this.codeMirror = new import_view3.EditorView({ parent: this.contentEl }); this.extensions = [ (0, import_commands2.history)(), // @ts-expect-error, not typed vimCompartment.of(this.app.vault.getConfig("vimMode") ? vim() : []), import_view3.keymap.of([...import_commands2.defaultKeymap, ...import_commands2.historyKeymap]), todoKeywordsReloader.of(new import_language5.LanguageSupport(OrgmodeLanguage(orgmodeParser))), import_view3.EditorView.lineWrapping, makeHeadingsFoldable, (0, import_language5.foldGutter)({ markerDOM: (open) => { const foldIcon = document.createElement("div"); const foldIcon_svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); const foldIcon_svg_path = document.createElementNS("http://www.w3.org/2000/svg", "path"); foldIcon_svg.setAttributeNS(null, "width", "24"); foldIcon_svg.setAttributeNS(null, "height", "24"); foldIcon_svg.setAttributeNS(null, "viewBox", "0 0 24 24"); foldIcon_svg.setAttributeNS(null, "fill", "none"); foldIcon_svg.setAttributeNS(null, "stroke", "currentColor"); foldIcon_svg.setAttributeNS(null, "stroke-width", "2"); foldIcon_svg.setAttributeNS(null, "stroke-linecap", "round"); foldIcon_svg.setAttributeNS(null, "stroke-linejoin", "round"); foldIcon_svg.setAttributeNS(null, "class", "svg-icon"); foldIcon_svg_path.setAttribute("d", "M3 8L12 17L21 8"); foldIcon_svg.appendChild(foldIcon_svg_path); foldIcon_svg.setCssStyles({ "height": "100%" }); if (open) { foldIcon.addClass("open-fold-icon"); } else { foldIcon.addClass("closed-fold-icon"); foldIcon_svg.setCssStyles({ "transform": "rotate(-90deg)", "color": "var(--text-accent)" }); } foldIcon.appendChild(foldIcon_svg); foldIcon.setCssStyles({ "height": "100%" }); return foldIcon; } }), import_view3.EditorView.editorAttributes.of({ class: "orgmode-view" }), import_view3.EditorView.editorAttributes.of({ class: "mod-cm6" }), import_view3.EditorView.baseTheme({ ".cm-gutters": { backgroundColor: "unset !important", border: "unset !important" }, ".open-fold-icon": { opacity: "0" }, ".open-fold-icon:hover": { opacity: "1" }, ".cm-panels": { backgroundColor: "#2e2e2e" } }), import_view3.EditorView.updateListener.of((v) => { if (v.docChanged) { this.requestSave(); } if (v.focusChanged) { const compartmentState = vimCompartment.get(this.codeMirror.state); const loaded = !!(Array.isArray(compartmentState) && compartmentState.length); const userset = !!this.app.vault.getConfig("vimMode"); if (userset && !loaded) { this.codeMirror.dispatch({ effects: vimCompartment.reconfigure(vim()) }); } if (!userset && loaded) { this.codeMirror.dispatch({ effects: vimCompartment.reconfigure([]) }); } } }), orgmodeLivePreview( this.codeMirror, settings, { navigateToFile: (filePath) => { try { let tfile = this.app.metadataCache.getFirstLinkpathDest(filePath, "."); if (!tfile) { tfile = this.app.metadataCache.getFirstLinkpathDest(filePath + ".org", "."); } this.leaf.openFile(tfile); } catch (e) { return; } }, getImageUri: (linkPath) => { try { let imageFile = this.app.metadataCache.getFirstLinkpathDest(linkPath, "."); let browserUri = this.app.vault.getResourcePath(imageFile); return browserUri; } catch (e) { return null; } }, navigateToOrgId: async (orgCustomId) => { try { const orgFiles = this.app.vault.getFiles().filter((x) => x.extension == "org"); for (const orgFile of orgFiles) { const orgContent = await this.app.vault.cachedRead(orgFile); for (const { orgId, start } of iterateOrgIds(orgmodeParser, orgContent)) { if (orgCustomId === orgId) { this.leaf.openFile(orgFile).then(() => { this.codeMirror.focus(); this.codeMirror.dispatch( { selection: { head: start, anchor: start } }, { effects: import_view3.EditorView.scrollIntoView(start, { y: "start" }) } ); }); return; } } } new import_obsidian.Notice(`Cannot find entry with ID "${orgCustomId}"`); } catch (e) { console.log(e); return; } } } ) ]; Vim.defineEx("write", "w", () => { this.save(); }); } getDisplayText() { if (this.file) { return this.file.basename; } else { return "org (No File)"; } } canAcceptExtension(extension) { return extension === "org"; } getViewType() { return "orgmode"; } };