template-obsidian-vault/.obsidian/plugins/orgmode-cm6/main.js

14717 lines
510 KiB
JavaScript
Raw Permalink Normal View History

2024-10-02 18:57:21 +00:00
/*
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: "<Left>", type: "keyToKey", toKeys: "h" },
{ keys: "<Right>", type: "keyToKey", toKeys: "l" },
{ keys: "<Up>", type: "keyToKey", toKeys: "k" },
{ keys: "<Down>", type: "keyToKey", toKeys: "j" },
{ keys: "g<Up>", type: "keyToKey", toKeys: "gk" },
{ keys: "g<Down>", type: "keyToKey", toKeys: "gj" },
{ keys: "<Space>", type: "keyToKey", toKeys: "l" },
{ keys: "<BS>", type: "keyToKey", toKeys: "h" },
{ keys: "<Del>", type: "keyToKey", toKeys: "x" },
{ keys: "<C-Space>", type: "keyToKey", toKeys: "W" },
{ keys: "<C-BS>", type: "keyToKey", toKeys: "B" },
{ keys: "<S-Space>", type: "keyToKey", toKeys: "w" },
{ keys: "<S-BS>", type: "keyToKey", toKeys: "b" },
{ keys: "<C-n>", type: "keyToKey", toKeys: "j" },
{ keys: "<C-p>", type: "keyToKey", toKeys: "k" },
{ keys: "<C-[>", type: "keyToKey", toKeys: "<Esc>" },
{ keys: "<C-c>", type: "keyToKey", toKeys: "<Esc>" },
{ keys: "<C-[>", type: "keyToKey", toKeys: "<Esc>", context: "insert" },
{ keys: "<C-c>", type: "keyToKey", toKeys: "<Esc>", context: "insert" },
{ keys: "<C-Esc>", type: "keyToKey", toKeys: "<Esc>" },
// ipad keyboard sends C-Esc instead of C-[
{ keys: "<C-Esc>", type: "keyToKey", toKeys: "<Esc>", 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: "<Home>", type: "keyToKey", toKeys: "0" },
{ keys: "<End>", type: "keyToKey", toKeys: "$" },
{ keys: "<PageUp>", type: "keyToKey", toKeys: "<C-b>" },
{ keys: "<PageDown>", type: "keyToKey", toKeys: "<C-f>" },
{ keys: "<CR>", type: "keyToKey", toKeys: "j^", context: "normal" },
{ keys: "<Ins>", type: "keyToKey", toKeys: "i", context: "normal" },
{ keys: "<Ins>", 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: "<C-f>", type: "motion", motion: "moveByPage", motionArgs: { forward: true } },
{ keys: "<C-b>", type: "motion", motion: "moveByPage", motionArgs: { forward: false } },
{ keys: "<C-d>", type: "motion", motion: "moveByScroll", motionArgs: { forward: true, explicitRepeat: true } },
{ keys: "<C-u>", 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<character>", type: "motion", motion: "moveToCharacter", motionArgs: { forward: true, inclusive: true } },
{ keys: "F<character>", type: "motion", motion: "moveToCharacter", motionArgs: { forward: false } },
{ keys: "t<character>", type: "motion", motion: "moveTillCharacter", motionArgs: { forward: true, inclusive: true } },
{ keys: "T<character>", type: "motion", motion: "moveTillCharacter", motionArgs: { forward: false } },
{ keys: ";", type: "motion", motion: "repeatLastCharacterSearch", motionArgs: { forward: true } },
{ keys: ",", type: "motion", motion: "repeatLastCharacterSearch", motionArgs: { forward: false } },
{ keys: "'<register>", type: "motion", motion: "goToMark", motionArgs: { toJumplist: true, linewise: true } },
{ keys: "`<register>", 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: "]<character>", type: "motion", motion: "moveToSymbol", motionArgs: { forward: true, toJumplist: true } },
{ keys: "[<character>", 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: "<C-u>", type: "operatorMotion", operator: "delete", motion: "moveToStartOfLine", context: "insert" },
{ keys: "<C-w>", type: "operatorMotion", operator: "delete", motion: "moveByWords", motionArgs: { forward: false, wordEnd: false }, context: "insert" },
//ignore C-w in normal mode
{ keys: "<C-w>", type: "idle", context: "normal" },
// Actions
{ keys: "<C-i>", type: "action", action: "jumpListWalk", actionArgs: { forward: true } },
{ keys: "<C-o>", type: "action", action: "jumpListWalk", actionArgs: { forward: false } },
{ keys: "<C-e>", type: "action", action: "scroll", actionArgs: { forward: true, linewise: true } },
{ keys: "<C-y>", 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: "<C-v>", type: "action", action: "toggleVisualMode", actionArgs: { blockwise: true } },
{ keys: "<C-q>", 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<character>", type: "action", action: "replace", isEdit: true },
{ keys: "@<register>", type: "action", action: "replayMacro" },
{ keys: "q<register>", 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: "<C-r>", type: "action", action: "redo" },
{ keys: "m<register>", type: "action", action: "setMark" },
{ keys: '"<register>', type: "action", action: "setRegister" },
{ keys: "<C-r><register>", type: "action", action: "insertRegister", context: "insert", isEdit: true },
{ keys: "<C-o>", 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<CR>", 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: "<C-a>", type: "action", action: "incrementNumberToken", isEdit: true, actionArgs: { increase: true, backtrack: false } },
{ keys: "<C-x>", type: "action", action: "incrementNumberToken", isEdit: true, actionArgs: { increase: false, backtrack: false } },
{ keys: "<C-t>", type: "action", action: "indent", actionArgs: { indentRight: true }, context: "insert" },
{ keys: "<C-d>", type: "action", action: "indent", actionArgs: { indentRight: false }, context: "insert" },
// Text object motions
{ keys: "a<register>", type: "motion", motion: "textObjectManipulation" },
{ keys: "i<register>", 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<character>, r<character> 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 == "<Esc>") {
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<string, Register>} 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) == "<character>"
// 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) == "<character>" || bestMatch.keys.slice(-10) == "<register>") {
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 == "<Up>" || keyName == "<Down>") {
up = keyName == "<Up>" ? 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 != "<Left>" && keyName != "<Right>") {
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 == "<Esc>" || keyName == "<C-c>" || keyName == "<C-[>" || keyName == "<BS>" && 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 == "<Up>" || keyName == "<Down>") {
CodeMirror2.e_stop(e);
} else if (keyName == "<C-u>") {
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 == "<Esc>" || keyName == "<C-c>" || keyName == "<C-[>" || keyName == "<BS>" && input == "") {
vimGlobalState.exCommandHistoryController.pushInput(input);
vimGlobalState.exCommandHistoryController.reset();
CodeMirror2.e_stop(e);
clearInputState(cm);
close();
cm.focus();
}
if (keyName == "<Up>" || keyName == "<Down>") {
CodeMirror2.e_stop(e);
up = keyName == "<Up>" ? 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 == "<C-u>") {
CodeMirror2.e_stop(e);
close("");
} else if (keyName && keyName != "<Left>" && keyName != "<Right>") {
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) == "<character>";
const isLastRegister = mapped.slice(-10) == "<register>";
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 "<CR>":
case "<S-CR>":
selectedCharacter = "\n";
break;
case "<Space>":
case "<S-Space>":
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 "<Esc>":
case "<C-c>":
case "<C-[>":
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 == "<Esc>" && !vim2.insertMode && !vim2.visualMode && wasMultiselect && vim2.status == "<Esc>") {
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, "<Esc>", "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 == "<Esc>" && !vim2.insertMode && !vim2.visualMode && this.query) {
const searchState = vim2.searchState_;
if (searchState) {
cm.removeOverlay(searchState.getOverlay());
searchState.setOverlay(null);
}
}
let isCopy = key === "<C-c>" && !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, "<Esc>", "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 = "<SPACE>";
} else if (charCode == EOF || charCode == SOF) {
char = "<EOF/SOF>";
}
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";
}
};