/* 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); // src/main.ts var main_exports = {}; __export(main_exports, { DEFAULT_SETTINGS: () => DEFAULT_SETTINGS, default: () => CssEditorPlugin }); module.exports = __toCommonJS(main_exports); var import_obsidian11 = require("obsidian"); // src/views/CssEditorView.ts var import_obsidian7 = require("obsidian"); var import_view8 = require("@codemirror/view"); // 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(CM) { var Pos2 = CM.Pos; function updateSelectionForSurrogateCharacters(cm, curStart, curEnd) { if (curStart.line === curEnd.line && curStart.ch >= curEnd.ch - 1) { var text = cm.getLine(curStart.line); var charCode = text.charCodeAt(curStart.ch); if (55296 <= charCode && charCode <= 55551) { curEnd.ch += 1; } } return { start: curStart, end: curEnd }; } var defaultKeymap2 = [ // Key to key mapping. This goes first to make it possible to override // existing mappings. { keys: "", type: "keyToKey", toKeys: "h" }, { keys: "", type: "keyToKey", toKeys: "l" }, { keys: "", type: "keyToKey", toKeys: "k" }, { keys: "", type: "keyToKey", toKeys: "j" }, { keys: "g", type: "keyToKey", toKeys: "gk" }, { keys: "g", type: "keyToKey", toKeys: "gj" }, { keys: "", type: "keyToKey", toKeys: "l" }, { keys: "", type: "keyToKey", toKeys: "h" }, { keys: "", type: "keyToKey", toKeys: "x" }, { keys: "", type: "keyToKey", toKeys: "W" }, { keys: "", type: "keyToKey", toKeys: "B" }, { keys: "", type: "keyToKey", toKeys: "w" }, { keys: "", type: "keyToKey", toKeys: "b" }, { keys: "", type: "keyToKey", toKeys: "j" }, { keys: "", type: "keyToKey", toKeys: "k" }, { keys: "", type: "keyToKey", toKeys: "" }, { keys: "", type: "keyToKey", toKeys: "" }, { keys: "", type: "keyToKey", toKeys: "", context: "insert" }, { keys: "", type: "keyToKey", toKeys: "", context: "insert" }, { keys: "", type: "keyToKey", toKeys: "" }, // ipad keyboard sends C-Esc instead of C-[ { keys: "", type: "keyToKey", toKeys: "", context: "insert" }, { keys: "s", type: "keyToKey", toKeys: "cl", context: "normal" }, { keys: "s", type: "keyToKey", toKeys: "c", context: "visual" }, { keys: "S", type: "keyToKey", toKeys: "cc", context: "normal" }, { keys: "S", type: "keyToKey", toKeys: "VdO", context: "visual" }, { keys: "", type: "keyToKey", toKeys: "0" }, { keys: "", type: "keyToKey", toKeys: "$" }, { keys: "", type: "keyToKey", toKeys: "" }, { keys: "", type: "keyToKey", toKeys: "" }, { keys: "", type: "keyToKey", toKeys: "j^", context: "normal" }, { keys: "", type: "keyToKey", toKeys: "i", context: "normal" }, { keys: "", type: "action", action: "toggleOverwrite", context: "insert" }, // Motions { keys: "H", type: "motion", motion: "moveToTopLine", motionArgs: { linewise: true, toJumplist: true } }, { keys: "M", type: "motion", motion: "moveToMiddleLine", motionArgs: { linewise: true, toJumplist: true } }, { keys: "L", type: "motion", motion: "moveToBottomLine", motionArgs: { linewise: true, toJumplist: true } }, { keys: "h", type: "motion", motion: "moveByCharacters", motionArgs: { forward: false } }, { keys: "l", type: "motion", motion: "moveByCharacters", motionArgs: { forward: true } }, { keys: "j", type: "motion", motion: "moveByLines", motionArgs: { forward: true, linewise: true } }, { keys: "k", type: "motion", motion: "moveByLines", motionArgs: { forward: false, linewise: true } }, { keys: "gj", type: "motion", motion: "moveByDisplayLines", motionArgs: { forward: true } }, { keys: "gk", type: "motion", motion: "moveByDisplayLines", motionArgs: { forward: false } }, { keys: "w", type: "motion", motion: "moveByWords", motionArgs: { forward: true, wordEnd: false } }, { keys: "W", type: "motion", motion: "moveByWords", motionArgs: { forward: true, wordEnd: false, bigWord: true } }, { keys: "e", type: "motion", motion: "moveByWords", motionArgs: { forward: true, wordEnd: true, inclusive: true } }, { keys: "E", type: "motion", motion: "moveByWords", motionArgs: { forward: true, wordEnd: true, bigWord: true, inclusive: true } }, { keys: "b", type: "motion", motion: "moveByWords", motionArgs: { forward: false, wordEnd: false } }, { keys: "B", type: "motion", motion: "moveByWords", motionArgs: { forward: false, wordEnd: false, bigWord: true } }, { keys: "ge", type: "motion", motion: "moveByWords", motionArgs: { forward: false, wordEnd: true, inclusive: true } }, { keys: "gE", type: "motion", motion: "moveByWords", motionArgs: { forward: false, wordEnd: true, bigWord: true, inclusive: true } }, { keys: "{", type: "motion", motion: "moveByParagraph", motionArgs: { forward: false, toJumplist: true } }, { keys: "}", type: "motion", motion: "moveByParagraph", motionArgs: { forward: true, toJumplist: true } }, { keys: "(", type: "motion", motion: "moveBySentence", motionArgs: { forward: false } }, { keys: ")", type: "motion", motion: "moveBySentence", motionArgs: { forward: true } }, { keys: "", type: "motion", motion: "moveByPage", motionArgs: { forward: true } }, { keys: "", type: "motion", motion: "moveByPage", motionArgs: { forward: false } }, { keys: "", type: "motion", motion: "moveByScroll", motionArgs: { forward: true, explicitRepeat: true } }, { keys: "", type: "motion", motion: "moveByScroll", motionArgs: { forward: false, explicitRepeat: true } }, { keys: "gg", type: "motion", motion: "moveToLineOrEdgeOfDocument", motionArgs: { forward: false, explicitRepeat: true, linewise: true, toJumplist: true } }, { keys: "G", type: "motion", motion: "moveToLineOrEdgeOfDocument", motionArgs: { forward: true, explicitRepeat: true, linewise: true, toJumplist: true } }, { keys: "g$", type: "motion", motion: "moveToEndOfDisplayLine" }, { keys: "g^", type: "motion", motion: "moveToStartOfDisplayLine" }, { keys: "g0", type: "motion", motion: "moveToStartOfDisplayLine" }, { keys: "0", type: "motion", motion: "moveToStartOfLine" }, { keys: "^", type: "motion", motion: "moveToFirstNonWhiteSpaceCharacter" }, { keys: "+", type: "motion", motion: "moveByLines", motionArgs: { forward: true, toFirstChar: true } }, { keys: "-", type: "motion", motion: "moveByLines", motionArgs: { forward: false, toFirstChar: true } }, { keys: "_", type: "motion", motion: "moveByLines", motionArgs: { forward: true, toFirstChar: true, repeatOffset: -1 } }, { keys: "$", type: "motion", motion: "moveToEol", motionArgs: { inclusive: true } }, { keys: "%", type: "motion", motion: "moveToMatchedSymbol", motionArgs: { inclusive: true, toJumplist: true } }, { keys: "f", type: "motion", motion: "moveToCharacter", motionArgs: { forward: true, inclusive: true } }, { keys: "F", type: "motion", motion: "moveToCharacter", motionArgs: { forward: false } }, { keys: "t", type: "motion", motion: "moveTillCharacter", motionArgs: { forward: true, inclusive: true } }, { keys: "T", type: "motion", motion: "moveTillCharacter", motionArgs: { forward: false } }, { keys: ";", type: "motion", motion: "repeatLastCharacterSearch", motionArgs: { forward: true } }, { keys: ",", type: "motion", motion: "repeatLastCharacterSearch", motionArgs: { forward: false } }, { keys: "'", type: "motion", motion: "goToMark", motionArgs: { toJumplist: true, linewise: true } }, { keys: "`", type: "motion", motion: "goToMark", motionArgs: { toJumplist: true } }, { keys: "]`", type: "motion", motion: "jumpToMark", motionArgs: { forward: true } }, { keys: "[`", type: "motion", motion: "jumpToMark", motionArgs: { forward: false } }, { keys: "]'", type: "motion", motion: "jumpToMark", motionArgs: { forward: true, linewise: true } }, { keys: "['", type: "motion", motion: "jumpToMark", motionArgs: { forward: false, linewise: true } }, // the next two aren't motions but must come before more general motion declarations { keys: "]p", type: "action", action: "paste", isEdit: true, actionArgs: { after: true, isEdit: true, matchIndent: true } }, { keys: "[p", type: "action", action: "paste", isEdit: true, actionArgs: { after: false, isEdit: true, matchIndent: true } }, { keys: "]", type: "motion", motion: "moveToSymbol", motionArgs: { forward: true, toJumplist: true } }, { keys: "[", type: "motion", motion: "moveToSymbol", motionArgs: { forward: false, toJumplist: true } }, { keys: "|", type: "motion", motion: "moveToColumn" }, { keys: "o", type: "motion", motion: "moveToOtherHighlightedEnd", context: "visual" }, { keys: "O", type: "motion", motion: "moveToOtherHighlightedEnd", motionArgs: { sameLine: true }, context: "visual" }, // Operators { keys: "d", type: "operator", operator: "delete" }, { keys: "y", type: "operator", operator: "yank" }, { keys: "c", type: "operator", operator: "change" }, { keys: "=", type: "operator", operator: "indentAuto" }, { keys: ">", type: "operator", operator: "indent", operatorArgs: { indentRight: true } }, { keys: "<", type: "operator", operator: "indent", operatorArgs: { indentRight: false } }, { keys: "g~", type: "operator", operator: "changeCase" }, { keys: "gu", type: "operator", operator: "changeCase", operatorArgs: { toLower: true }, isEdit: true }, { keys: "gU", type: "operator", operator: "changeCase", operatorArgs: { toLower: false }, isEdit: true }, { keys: "n", type: "motion", motion: "findNext", motionArgs: { forward: true, toJumplist: true } }, { keys: "N", type: "motion", motion: "findNext", motionArgs: { forward: false, toJumplist: true } }, { keys: "gn", type: "motion", motion: "findAndSelectNextInclusive", motionArgs: { forward: true } }, { keys: "gN", type: "motion", motion: "findAndSelectNextInclusive", motionArgs: { forward: false } }, { keys: "gq", type: "operator", operator: "hardWrap" }, { keys: "gw", type: "operator", operator: "hardWrap", operatorArgs: { keepCursor: true } }, { keys: "g?", type: "operator", operator: "rot13" }, // Operator-Motion dual commands { keys: "x", type: "operatorMotion", operator: "delete", motion: "moveByCharacters", motionArgs: { forward: true }, operatorMotionArgs: { visualLine: false } }, { keys: "X", type: "operatorMotion", operator: "delete", motion: "moveByCharacters", motionArgs: { forward: false }, operatorMotionArgs: { visualLine: true } }, { keys: "D", type: "operatorMotion", operator: "delete", motion: "moveToEol", motionArgs: { inclusive: true }, context: "normal" }, { keys: "D", type: "operator", operator: "delete", operatorArgs: { linewise: true }, context: "visual" }, { keys: "Y", type: "operatorMotion", operator: "yank", motion: "expandToLine", motionArgs: { linewise: true }, context: "normal" }, { keys: "Y", type: "operator", operator: "yank", operatorArgs: { linewise: true }, context: "visual" }, { keys: "C", type: "operatorMotion", operator: "change", motion: "moveToEol", motionArgs: { inclusive: true }, context: "normal" }, { keys: "C", type: "operator", operator: "change", operatorArgs: { linewise: true }, context: "visual" }, { keys: "~", type: "operatorMotion", operator: "changeCase", motion: "moveByCharacters", motionArgs: { forward: true }, operatorArgs: { shouldMoveCursor: true }, context: "normal" }, { keys: "~", type: "operator", operator: "changeCase", context: "visual" }, { keys: "", type: "operatorMotion", operator: "delete", motion: "moveToStartOfLine", context: "insert" }, { keys: "", type: "operatorMotion", operator: "delete", motion: "moveByWords", motionArgs: { forward: false, wordEnd: false }, context: "insert" }, //ignore C-w in normal mode { keys: "", type: "idle", context: "normal" }, // Actions { keys: "", type: "action", action: "jumpListWalk", actionArgs: { forward: true } }, { keys: "", type: "action", action: "jumpListWalk", actionArgs: { forward: false } }, { keys: "", type: "action", action: "scroll", actionArgs: { forward: true, linewise: true } }, { keys: "", type: "action", action: "scroll", actionArgs: { forward: false, linewise: true } }, { keys: "a", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "charAfter" }, context: "normal" }, { keys: "A", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "eol" }, context: "normal" }, { keys: "A", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "endOfSelectedArea" }, context: "visual" }, { keys: "i", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "inplace" }, context: "normal" }, { keys: "gi", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "lastEdit" }, context: "normal" }, { keys: "I", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "firstNonBlank" }, context: "normal" }, { keys: "gI", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "bol" }, context: "normal" }, { keys: "I", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { insertAt: "startOfSelectedArea" }, context: "visual" }, { keys: "o", type: "action", action: "newLineAndEnterInsertMode", isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: true }, context: "normal" }, { keys: "O", type: "action", action: "newLineAndEnterInsertMode", isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: false }, context: "normal" }, { keys: "v", type: "action", action: "toggleVisualMode" }, { keys: "V", type: "action", action: "toggleVisualMode", actionArgs: { linewise: true } }, { keys: "", type: "action", action: "toggleVisualMode", actionArgs: { blockwise: true } }, { keys: "", type: "action", action: "toggleVisualMode", actionArgs: { blockwise: true } }, { keys: "gv", type: "action", action: "reselectLastSelection" }, { keys: "J", type: "action", action: "joinLines", isEdit: true }, { keys: "gJ", type: "action", action: "joinLines", actionArgs: { keepSpaces: true }, isEdit: true }, { keys: "p", type: "action", action: "paste", isEdit: true, actionArgs: { after: true, isEdit: true } }, { keys: "P", type: "action", action: "paste", isEdit: true, actionArgs: { after: false, isEdit: true } }, { keys: "r", type: "action", action: "replace", isEdit: true }, { keys: "@", type: "action", action: "replayMacro" }, { keys: "q", type: "action", action: "enterMacroRecordMode" }, // Handle Replace-mode as a special case of insert mode. { keys: "R", type: "action", action: "enterInsertMode", isEdit: true, actionArgs: { replace: true }, context: "normal" }, { keys: "R", type: "operator", operator: "change", operatorArgs: { linewise: true, fullLine: true }, context: "visual", exitVisualBlock: true }, { keys: "u", type: "action", action: "undo", context: "normal" }, { keys: "u", type: "operator", operator: "changeCase", operatorArgs: { toLower: true }, context: "visual", isEdit: true }, { keys: "U", type: "operator", operator: "changeCase", operatorArgs: { toLower: false }, context: "visual", isEdit: true }, { keys: "", type: "action", action: "redo" }, { keys: "m", type: "action", action: "setMark" }, { keys: '"', type: "action", action: "setRegister" }, { keys: "", type: "action", action: "insertRegister", context: "insert", isEdit: true }, { keys: "", type: "action", action: "oneNormalCommand", context: "insert" }, { keys: "zz", type: "action", action: "scrollToCursor", actionArgs: { position: "center" } }, { keys: "z.", type: "action", action: "scrollToCursor", actionArgs: { position: "center" }, motion: "moveToFirstNonWhiteSpaceCharacter" }, { keys: "zt", type: "action", action: "scrollToCursor", actionArgs: { position: "top" } }, { keys: "z", type: "action", action: "scrollToCursor", actionArgs: { position: "top" }, motion: "moveToFirstNonWhiteSpaceCharacter" }, { keys: "zb", type: "action", action: "scrollToCursor", actionArgs: { position: "bottom" } }, { keys: "z-", type: "action", action: "scrollToCursor", actionArgs: { position: "bottom" }, motion: "moveToFirstNonWhiteSpaceCharacter" }, { keys: ".", type: "action", action: "repeatLastEdit" }, { keys: "", type: "action", action: "incrementNumberToken", isEdit: true, actionArgs: { increase: true, backtrack: false } }, { keys: "", type: "action", action: "incrementNumberToken", isEdit: true, actionArgs: { increase: false, backtrack: false } }, { keys: "", type: "action", action: "indent", actionArgs: { indentRight: true }, context: "insert" }, { keys: "", type: "action", action: "indent", actionArgs: { indentRight: false }, context: "insert" }, // Text object motions { keys: "a", type: "motion", motion: "textObjectManipulation" }, { keys: "i", type: "motion", motion: "textObjectManipulation", motionArgs: { textObjectInner: true } }, // Search { keys: "/", type: "search", searchArgs: { forward: true, querySrc: "prompt", toJumplist: true } }, { keys: "?", type: "search", searchArgs: { forward: false, querySrc: "prompt", toJumplist: true } }, { keys: "*", type: "search", searchArgs: { forward: true, querySrc: "wordUnderCursor", wholeWordOnly: true, toJumplist: true } }, { keys: "#", type: "search", searchArgs: { forward: false, querySrc: "wordUnderCursor", wholeWordOnly: true, toJumplist: true } }, { keys: "g*", type: "search", searchArgs: { forward: true, querySrc: "wordUnderCursor", toJumplist: true } }, { keys: "g#", type: "search", searchArgs: { forward: false, querySrc: "wordUnderCursor", toJumplist: true } }, // Ex command { keys: ":", type: "ex" } ]; var usedKeys = /* @__PURE__ */ Object.create(null); 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: "marks", excludeFromCommandHistory: true }, { 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); CM.signal(cm, "vim-mode-change", { mode: "normal" }); cm.on("cursorActivity", onCursorActivity); maybeInitVimState(cm); CM.on(cm.getInputField(), "paste", getOnPasteFn(cm)); } function leaveVimMode(cm) { cm.setOption("disableInput", false); cm.off("cursorActivity", onCursorActivity); CM.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 = [CM.isWordChar, function(ch) { return ch && !CM.isWordChar(ch) && !/\s/.test(ch); }], bigWordCharTest = [function(ch) { return /\S/.test(ch); }]; var validMarks = ["<", ">"]; var validRegisters = ["-", '"', ".", ":", "_", "/", "+"]; var latinCharRegex = /^\w$/; var upperCaseChars = /^[A-Z]$/; try { upperCaseChars = new RegExp("^[\\p{Lu}]$", "u"); } catch (_) { } 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(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 = ( /**@type {(Marker|undefined)[]} */ 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 { /**@type{Pos|undefined} */ 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; } /** * @arg {CodeMirror} cm * @arg {string} registerName */ 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, function() { }, { 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: ( /**@type{vimState["lastSelection"]}*/ /**@type{unknown}*/ null ), lastPastedText: void 0, sel: { anchor: new Pos2(0, 0), head: new Pos2(0, 0) }, // Buffer-local/window-local values of vim options. options: {}, // Whether the next character should be interpreted literally // Necassary for correct implementation of f, r etc. // in terms of langmaps. expectLiteralNext: false, status: "" }; } 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; } } class InsertModeKey { /** * Wrapper for special keys pressed in insert mode * @arg {string} keyName * @arg {KeyboardEvent} e * @returns */ constructor(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; } } 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) | undefined} */ findKey: function(cm_, key, origin) { var vim2 = maybeInitVimState(cm_); var cm = ( /**@type {CodeMirrorV}*/ cm_ ); function handleMacroRecording() { var macroModeState = vimGlobalState.macroModeState; if (macroModeState.isRecording) { if (key == "q") { macroModeState.exitMacroRecordMode(); clearInputState(cm); return true; } if (origin != "mapping") { logKey(macroModeState, key); } } } function handleEsc() { if (key == "") { if (vim2.visualMode) { exitVisualMode(cm); } else if (vim2.insertMode) { exitInsertMode(cm); } else { return; } clearInputState(cm); return true; } } function handleKeyInsertMode() { if (handleEsc()) { return true; } vim2.inputState.keyBuffer.push(key); var keys2 = vim2.inputState.keyBuffer.join(""); var keysAreChars = key.length == 1; var match = commandDispatcher.matchCommand(keys2, defaultKeymap2, vim2.inputState, "insert"); var changeQueue = vim2.inputState.changeQueue; if (match.type == "none") { clearInputState(cm); return false; } else if (match.type == "partial") { if (match.expectLiteralNext) vim2.expectLiteralNext = true; if (lastInsertModeKeyTimer) { window.clearTimeout(lastInsertModeKeyTimer); } lastInsertModeKeyTimer = keysAreChars && window.setTimeout( function() { if (vim2.insertMode && vim2.inputState.keyBuffer.length) { clearInputState(cm); } }, getOption("insertModeEscKeysTimeout") ); if (keysAreChars) { var selections = cm.listSelections(); if (!changeQueue || changeQueue.removed.length != selections.length) changeQueue = vim2.inputState.changeQueue = new ChangeQueue(); changeQueue.inserted += key; for (var i = 0; i < selections.length; i++) { var from = cursorMin(selections[i].anchor, selections[i].head); var to = cursorMax(selections[i].anchor, selections[i].head); var text = cm.getRange(from, cm.state.overwrite ? offsetCursor(to, 0, 1) : to); changeQueue.removed[i] = (changeQueue.removed[i] || "") + text; } } return !keysAreChars; } else if (match.type == "full") { vim2.inputState.keyBuffer.length = 0; } 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 = vim2.insertMode ? handleKeyInsertMode() : handleKeyNonInsertMode(); if (command === false) { return !vim2.insertMode && (key.length === 1 || CM.isMac && //.test(key)) ? function() { return true; } : void 0; } else if (command === true) { return function() { return true; }; } else if (command) { return function() { return cm.operation(function() { cm.curOp.isVimOp = true; try { if (typeof command != "object") return; 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; }); }; } }, /**@type {(cm: CodeMirrorV, input: string)=>void} */ 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 (!virtualPrompt) throw new Error("No prompt to send key to"); 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 (!virtualPrompt) return; 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 (CM.isMac && name == "A-" && key.length == 1) { 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) > 128) { if (!usedKeys[key]) { var code = ((_a = e.code) == null ? void 0 : _a.slice(-1)) || ""; if (!e.shiftKey) code = code.toLowerCase(); if (code) { key = code; if (!name && e.altKey) name = "A-"; } } } } 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 keymap3 = {}; if (!langmapString) return { keymap: keymap3, 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) keymap3[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) keymap3[pairs[i]] = pairs[i + 1]; } }); return { keymap: keymap3, 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 = void 0; this.changeQueue = null; } /** @param {string} n */ 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; CM.signal(cm, "vim-command-done", reason); } function ChangeQueue() { this.removed = []; this.inserted = ""; } class Register { /** @arg {string} [text] @arg {boolean} [linewise] @arg {boolean } [blockwise] */ constructor(text, linewise, blockwise) { this.clear(); this.keyBuffer = [text || ""]; this.insertModeChanges = []; this.searchQueries = []; this.linewise = !!linewise; this.blockwise = !!blockwise; } /** @arg {string} [text] @arg {boolean} [linewise] @arg {boolean } [blockwise] */ setText(text, linewise, blockwise) { this.keyBuffer = [text || ""]; this.linewise = !!linewise; this.blockwise = !!blockwise; } /** @arg {string} text @arg {boolean} [linewise] */ pushText(text, linewise) { if (linewise) { if (!this.linewise) { this.keyBuffer.push("\n"); } this.linewise = true; } this.keyBuffer.push(text); } /** @arg {InsertModeChanges} changes */ pushInsertModeChanges(changes) { this.insertModeChanges.push(createInsertModeChanges(changes)); } /** @arg {string} query */ pushSearchQuery(query) { this.searchQueries.push(query); } clear() { this.keyBuffer = []; this.insertModeChanges = []; this.searchQueries = []; this.linewise = false; } toString() { return this.keyBuffer.join(""); } } function defineRegister(name, register) { var registers = vimGlobalState.registerController.registers; if (!name || name.length != 1) { throw Error("Register name must be 1 character"); } if (registers[name]) { throw Error("Register already defined " + name); } registers[name] = register; validRegisters.push(name); } class RegisterController { /** @arg {Object} registers */ constructor(registers) { this.registers = registers; this.unnamedRegister = registers['"'] = new Register(); registers["."] = new Register(); registers[":"] = new Register(); registers["/"] = new Register(); registers["+"] = new Register(); } /** * @param {string | null | undefined} registerName * @param {string} operator * @param {string} text * @param {boolean} [linewise] * @param {boolean} [blockwise] */ 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 || !registerName) { 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. * @arg {string} input * @arg {boolean} up */ 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; } /** @arg {string} 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 = { /** * @param {string} keys * @param {vimKey[]} keyMap * @param {InputStateInterface} inputState * @param {string} context */ matchCommand: function(keys2, keyMap, inputState, context) { var matches = commandMatches(keys2, keyMap, context, inputState); var bestMatch = matches.full[0]; if (!bestMatch) { if (matches.partial.length) { return { type: "partial", expectLiteralNext: matches.partial.length == 1 && matches.partial[0].keys.slice(-11) == "" // langmap literal logic }; } return { type: "none" }; } if (bestMatch.keys.slice(-11) == "" || bestMatch.keys.slice(-10) == "") { var character = lastChar(keys2); if (!character || character.length > 1) return { type: "clear" }; inputState.selectedCharacter = character; } return { type: "full", command: bestMatch }; }, /** * @arg {CodeMirrorV} cm * @arg {vimState} vim * @arg {vimKey} command */ processCommand: function(cm, vim2, command) { vim2.inputState.repeatOverride = command.repeatOverride; switch (command.type) { case "motion": this.processMotion(cm, vim2, command); break; case "operator": this.processOperator(cm, vim2, command); break; case "operatorMotion": this.processOperatorMotion(cm, vim2, command); break; case "action": this.processAction(cm, vim2, command); break; case "search": this.processSearch(cm, vim2, command); break; case "ex": case "keyToEx": this.processEx(cm, vim2, command); break; } }, /** * @arg {CodeMirrorV} cm * @arg {vimState} vim * @arg {import("./types").motionCommand|import("./types").operatorMotionCommand} command */ processMotion: function(cm, vim2, command) { vim2.inputState.motion = command.motion; vim2.inputState.motionArgs = /**@type {MotionArgs}*/ copyArgs(command.motionArgs); this.evalInput(cm, vim2); }, /** * @arg {CodeMirrorV} cm * @arg {vimState} vim * @arg {import("./types").operatorCommand|import("./types").operatorMotionCommand} command */ processOperator: function(cm, vim2, command) { var inputState = vim2.inputState; if (inputState.operator) { if (inputState.operator == command.operator) { inputState.motion = "expandToLine"; inputState.motionArgs = { linewise: true, repeat: 1 }; this.evalInput(cm, vim2); return; } else { clearInputState(cm); } } inputState.operator = command.operator; inputState.operatorArgs = copyArgs(command.operatorArgs); if (command.keys.length > 1) { inputState.operatorShortcut = command.keys; } if (command.exitVisualBlock) { vim2.visualBlock = false; updateCmSelection(cm); } if (vim2.visualMode) { this.evalInput(cm, vim2); } }, /** * @arg {CodeMirrorV} cm * @arg {vimState} vim * @arg {import("./types").operatorMotionCommand} command */ processOperatorMotion: function(cm, vim2, command) { var visualMode = vim2.visualMode; var operatorMotionArgs = copyArgs(command.operatorMotionArgs); if (operatorMotionArgs) { if (visualMode && operatorMotionArgs.visualLine) { vim2.visualLine = true; } } this.processOperator(cm, vim2, command); if (!visualMode) { this.processMotion(cm, vim2, command); } }, /** * @arg {CodeMirrorV} cm * @arg {vimState} vim * @arg {import("./types").actionCommand} command */ processAction: function(cm, vim2, command) { var inputState = vim2.inputState; var repeat = inputState.getRepeat(); var repeatIsExplicit = !!repeat; var actionArgs = ( /**@type {ActionArgs}*/ copyArgs(command.actionArgs) || { repeat: 1 } ); if (inputState.selectedCharacter) { actionArgs.selectedCharacter = inputState.selectedCharacter; } if (command.operator) { this.processOperator(cm, vim2, command); } if (command.motion) { this.processMotion(cm, vim2, command); } if (command.motion || command.operator) { this.evalInput(cm, vim2); } actionArgs.repeat = repeat || 1; actionArgs.repeatIsExplicit = repeatIsExplicit; actionArgs.registerName = inputState.registerName; clearInputState(cm); vim2.lastMotion = null; if (command.isEdit) { this.recordLastEdit(vim2, inputState, command); } actions[command.action](cm, actionArgs, vim2); }, /** @arg {CodeMirrorV} cm @arg {vimState} vim @arg {import("./types").searchCommand} command*/ processSearch: function(cm, vim2, command) { if (!cm.getSearchCursor) { return; } var forward = command.searchArgs.forward; var wholeWordOnly = command.searchArgs.wholeWordOnly; getSearchState(cm).setReversed(!forward); var promptPrefix = forward ? "/" : "?"; var originalQuery = getSearchState(cm).getQuery(); var originalScrollPos = cm.getScrollInfo(); var lastQuery = ""; 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 pcreLabel() { return getOption("pcre") ? "(JavaScript regexp: set pcre)" : "(Vim regexp: set nopcre)"; } function onPromptKeyUp(e, query, close) { var keyName = vimKeyFromEvent(e), up, offset; if (keyName == "" || keyName == "") { up = keyName == "" ? true : false; offset = e.target ? e.target.selectionEnd : 0; query = vimGlobalState.searchHistoryController.nextMatch(query, up) || ""; close(query); if (offset && e.target) e.target.selectionEnd = e.target.selectionStart = Math.min(offset, e.target.value.length); } else if (keyName && keyName != "" && keyName != "") { vimGlobalState.searchHistoryController.reset(); } lastQuery = query; onChange2(); } function onChange2() { var parsedQuery; try { parsedQuery = updateSearchQuery( cm, lastQuery, true, true /** smartCase */ ); } catch (e) { } if (parsedQuery) { cm.scrollIntoView(findNext(cm, !forward, parsedQuery), 30); } else { clearSearchHighlight(cm); cm.scrollTo(originalScrollPos.left, originalScrollPos.top); } } function onPromptKeyDown(e, query, close) { var keyName = vimKeyFromEvent(e); if (keyName == "" || keyName == "" || keyName == "" || keyName == "" && query == "") { vimGlobalState.searchHistoryController.pushInput(query); vimGlobalState.searchHistoryController.reset(); updateSearchQuery(cm, (originalQuery == null ? void 0 : originalQuery.source) || ""); clearSearchHighlight(cm); cm.scrollTo(originalScrollPos.left, originalScrollPos.top); CM.e_stop(e); clearInputState(cm); close(); cm.focus(); } else if (keyName == "" || keyName == "") { CM.e_stop(e); } else if (keyName == "") { CM.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: dom( "span", { $cursor: "pointer", onmousedown: function(e) { e.preventDefault(); setOption("pcre", !getOption("pcre")); this.textContent = pcreLabel(); onChange2(); } }, pcreLabel() ), onKeyUp: onPromptKeyUp, onKeyDown: onPromptKeyDown }); } break; case "wordUnderCursor": var word = expandWordUnderCursor(cm, { noSymbol: true }); var isKeyword = true; if (!word) { word = expandWordUnderCursor(cm, { noSymbol: false }); isKeyword = false; } if (!word) { showConfirm(cm, "No word under cursor"); clearInputState(cm); return; } let query = cm.getLine(word.start.line).substring( word.start.ch, word.end.ch ); if (isKeyword && wholeWordOnly) { query = "\\b" + query + "\\b"; } else { query = escapeRegex(query); } vimGlobalState.jumpList.cachedCursor = cm.getCursor(); cm.setCursor(word.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); clearSearchHighlight(cm); } function onPromptKeyDown(e, input, close) { var keyName = vimKeyFromEvent(e), up, offset; if (keyName == "" || keyName == "" || keyName == "" || keyName == "" && input == "") { vimGlobalState.exCommandHistoryController.pushInput(input); vimGlobalState.exCommandHistoryController.reset(); CM.e_stop(e); clearInputState(cm); clearSearchHighlight(cm); close(); cm.focus(); } if (keyName == "" || keyName == "") { CM.e_stop(e); up = keyName == "" ? true : false; offset = e.target ? e.target.selectionEnd : 0; input = vimGlobalState.exCommandHistoryController.nextMatch(input, up) || ""; close(input); if (offset && e.target) e.target.selectionEnd = e.target.selectionStart = Math.min(offset, e.target.value.length); } else if (keyName == "") { CM.e_stop(e); close(""); } else if (keyName && keyName != "" && keyName != "") { vimGlobalState.exCommandHistoryController.reset(); } } function onPromptKeyUp(e, query) { var inputStream = new CM.StringStream(query); var params = ( /**@type{import("./types").exCommandArgs}*/ {} ); try { exCommandDispatcher.parseInput_(cm, inputStream, params); if (params.commandName != "s") { clearSearchHighlight(cm); return; } var command2 = exCommandDispatcher.matchCommand_(params.commandName); if (!command2) return; exCommandDispatcher.parseCommandArgs_(inputStream, params, command2); if (!params.argString) return; var regex = parseQuery(params.argString.slice(1), true, true); if (regex) highlightSearchMatches(cm, regex); } catch (e2) { } } if (command.type == "keyToEx") { exCommandDispatcher.processCommand(cm, command.exArgs.input); } else { var promptOptions = { onClose: onPromptClose, onKeyDown: onPromptKeyDown, onKeyUp: onPromptKeyUp, prefix: ":" }; if (vim2.visualMode) { promptOptions.value = "'<,'>"; promptOptions.selectValueOnOpen = false; } showPrompt(cm, promptOptions); } }, /**@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 Pos2(oldAnchor.line + lineOffset, oldAnchor.ch); } else if (lastSel.visualBlock) { newHead = new Pos2(oldAnchor.line + lineOffset, oldAnchor.ch + chOffset); } else if (lastSel.head.line == lastSel.anchor.line) { newHead = new Pos2(oldAnchor.line, oldAnchor.ch + chOffset); } else { newHead = new Pos2(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 Pos2(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 Pos2(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); }, moveToMiddleLine: function(cm) { var range = getUserVisibleLines(cm); var line = Math.floor((range.top + range.bottom) * 0.5); return new Pos2(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); }, moveToBottomLine: function(cm, _head, motionArgs) { var line = getUserVisibleLines(cm).bottom - motionArgs.repeat + 1; return new Pos2(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); }, expandToLine: function(_cm, head, motionArgs) { var cur2 = head; return new Pos2(cur2.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); var result = findNext(cm, prev, query, motionArgs.repeat); if (!result) { showConfirm(cm, "No match found " + query + (getOption("pcre") ? " (set nopcre to use Vim regexps)" : "")); } return result; }, /** * 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 Pos2(next[1].line, next[1].ch - 1); if (vim2.visualMode) { if (vim2.visualLine || vim2.visualBlock) { vim2.visualLine = false; vim2.visualBlock = false; CM.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; CM.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) { var sel = vim2.sel; if (vim2.visualBlock && motionArgs.sameLine) { return [ clipCursorToContent(cm, new Pos2(sel.anchor.line, sel.head.ch)), clipCursorToContent(cm, new Pos2(sel.head.line, sel.anchor.ch)) ]; } else { return [sel.head, 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 Pos2(best.line, findFirstNonWhiteSpaceCharacter(cm.getLine(best.line))); } return best; }, moveByCharacters: function(_cm, head, motionArgs) { var cur2 = head; var repeat = motionArgs.repeat; var ch = motionArgs.forward ? cur2.ch + repeat : cur2.ch - repeat; return new Pos2(cur2.line, ch); }, moveByLines: function(cm, head, motionArgs, vim2) { var cur2 = head; var endCh = cur2.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 ? cur2.line + repeat : cur2.line - repeat; var first = cm.firstLine(); var last = cm.lastLine(); var posV = cm.findPosV(cur2, 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 && cur2.line == first) { return this.moveToStartOfLine(cm, head, motionArgs, vim2); } else if (line > last && cur2.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 Pos2(line, endCh), "div").left; return new Pos2(line, endCh); }, moveByDisplayLines: function(cm, head, motionArgs, vim2) { var cur2 = 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(cur2, "div").left; } var repeat = motionArgs.repeat; var res = cm.findPosV(cur2, 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 Pos2(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 Pos2( 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 Pos2(line, ch + 1)); if (style !== "string" && style !== "comment") { break; } } } if (ch < lineText.length) { var re = symbol === "<" || symbol === ">" ? /[(){}[\]<>]/ : /[(){}[\]]/; var matched = cm.findMatchingBracket(new Pos2(line, ch), { bracketRegex: re }); return matched.to; } else { return cursor; } }, moveToStartOfLine: function(_cm, head) { return new Pos2(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 Pos2( 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 Pos2(anchor.line, findFirstNonWhiteSpaceCharacter(cm.getLine(anchor.line))); if (head.line > anchor.line) { head = new Pos2(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 Pos2(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 || 1 : 1; if (vim2.visualBlock) { var tabSize = cm.getOption("tabSize"); var indent = cm.getOption("indentWithTabs") ? " " : " ".repeat(tabSize); var cursor; for (var i = ranges.length - 1; i >= 0; i--) { cursor = cursorMin(ranges[i].anchor, ranges[i].head); if (args.indentRight) { cm.replaceRange(indent.repeat(repeat), cursor, cursor); } else { var text = cm.getLine(cursor.line); var end = 0; for (var j = 0; j < repeat; j++) { var ch = text[cursor.ch + end]; if (ch == " ") { end++; } else if (ch == " ") { end++; for (var k = 1; k < indent.length; k++) { ch = text[cursor.ch + end]; if (ch !== " ") break; end++; } } else { break; } } cm.replaceRange("", cursor, offsetCursor(cursor, 0, end)); } } return cursor; } else 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 Pos2(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; }, rot13: function(cm, args, ranges, oldAnchor, newHead) { var selections = cm.getSelections(); var swapped = []; for (var j = 0; j < selections.length; j++) { const replacement = selections[j].split("").map((x) => { const code = x.charCodeAt(0); if (code >= 65 && code <= 90) { return String.fromCharCode(65 + (code - 65 + 13) % 26); } else if (code >= 97 && code <= 122) { return String.fromCharCode(97 + (code - 97 + 13) % 26); } else { return x; } }).join(""); swapped.push(replacement); } 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); } } }; 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 Pos2(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 Pos2(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"); CM.signal(cm, "vim-mode-change", { mode: "replace" }); } else { cm.toggleOverwrite(false); cm.setOption("keyMap", "vim-insert"); CM.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 Pos2(head.line, lineLength(cm, head.line)); } else if (insertAt == "bol") { head = new Pos2(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 Pos2(sel.anchor.line, 0); } } else { head = new Pos2( 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 Pos2(sel.anchor.line, 0); } } else { head = new Pos2( 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"); CM.signal(cm, "vim-mode-change", { mode: "replace" }); } else { cm.toggleOverwrite(false); cm.setOption("keyMap", "vim-insert"); CM.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 }); CM.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 Pos2(anchor.line, anchor.ch + repeat - 1) ); var newPosition = updateSelectionForSurrogateCharacters(cm, anchor, head); vim2.sel = { anchor: newPosition.start, head: newPosition.end }; CM.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; CM.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)); CM.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 Pos2( 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 Pos2(curStart.line, finalCh), new Pos2(curStart.line + 1, nextStartCh) ); } var curFinalPos = clipCursorToContent(cm, new Pos2(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 Pos2(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 = CM.commands.newlineAndIndentContinueComment || CM.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 cur2 = 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) { text = Array(actionArgs.repeat + 1).join(text); } var linewise = register.linewise; var blockwise = register.blockwise; var textLines = blockwise ? text.split("\n") : void 0; if (textLines) { if (linewise) { textLines.pop(); } for (var i = 0; i < textLines.length; i++) { textLines[i] = textLines[i] == "" ? " " : textLines[i]; } cur2.ch += actionArgs.after ? 1 : 0; cur2.ch = Math.min(lineLength(cm, cur2.line), cur2.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); cur2.ch = lineLength(cm, cur2.line); } else { cur2.ch = 0; } } else { cur2.ch += actionArgs.after ? 1 : 0; } var curPosFinal; if (vim2.visualMode) { vim2.lastPastedText = text; var lastSelectionCurEnd; var selectedArea = getSelectedAreaRange(cm); 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 Pos2(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 && textLines) { cm.setCursor(cur2); for (var i = 0; i < textLines.length; i++) { var line = cur2.line + i; if (line > cm.lastLine()) { cm.replaceRange("\n", new Pos2(line, 0)); } var lastCh = lineLength(cm, line); if (lastCh < cur2.ch) { extendLineToColumn(cm, line, cur2.ch); } } cm.setCursor(cur2); selectBlock(cm, new Pos2(cur2.line + textLines.length - 1, cur2.ch)); cm.replaceSelections(textLines); curPosFinal = cur2; } else { cm.replaceRange(text, cur2); if (linewise) { var line = actionArgs.after ? cur2.line + 1 : cur2.line; curPosFinal = new Pos2(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); } else { curPosFinal = copyCursor(cur2); 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, CM.commands.undo, actionArgs.repeat)(); cm.setCursor(clipCursorToContent(cm, cm.getCursor("start"))); }); }, redo: function(cm, actionArgs) { repeatFn(cm, CM.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; CM.on(cm, "vim-command-done", function handler() { if (vim2.visualMode) return; if (vim2.insertModeReturn) { vim2.insertModeReturn = false; if (!vim2.insertMode) { actions.enterInsertMode(cm, {}, vim2); } } CM.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 Pos2(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); (CM.commands.newlineAndIndentContinueComment || CM.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 cur2 = cm.getCursor(); var lineStr = cm.getLine(cur2.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 (cur2.ch < end) break; } if (!actionArgs.backtrack && end <= cur2.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 Pos2(cur2.line, start); var to = new Pos2(cur2.line, end); cm.replaceRange(numberStr, from, to); } else { return; } cm.setCursor(new Pos2(cur2.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, cur2, oldCur) { var vim2 = cm.state.vim; var includeLineBreak = vim2.insertMode || vim2.visualMode; var line = Math.min(Math.max(cm.firstLine(), cur2.line), cm.lastLine()); var text = cm.getLine(line); var maxCh = text.length - 1 + Number(!!includeLineBreak); var ch = Math.min(Math.max(0, cur2.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 Pos2(line, ch); } function copyArgs(args) { var ret = ( /**@type{typeof args}*/ {} ); for (var prop in args) { if (Object.prototype.hasOwnProperty.call(args, prop)) { ret[prop] = args[prop]; } } return ( /**@type{typeof args}*/ ret ); } function offsetCursor(cur2, offsetLine, offsetCh) { if (typeof offsetLine === "object") { offsetCh = offsetLine.ch; offsetLine = offsetLine.line; } return new Pos2(cur2.line + offsetLine, cur2.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, full }; } function commandMatch(pressed, mapped) { const isLastCharacter = mapped.slice(-11) == ""; const isLastRegister = mapped.slice(-10) == ""; if (isLastCharacter || isLastRegister) { var prefixLen = mapped.length - (isLastCharacter ? 11 : 10); var pressedPrefix = pressed.slice(0, prefixLen); var mappedPrefix = mapped.slice(0, prefixLen); return pressedPrefix == mappedPrefix && pressed.length > prefixLen ? "full" : mappedPrefix.indexOf(pressedPrefix) == 0 ? "partial" : false; } else { return pressed == mapped ? "full" : mapped.indexOf(pressed) == 0 ? "partial" : false; } } function lastChar(keys2) { var match = /^.*(<[^>]+>)$/.exec(keys2); var selectedCharacter = match ? match[1] : keys2.slice(-1); if (selectedCharacter.length > 1) { switch (selectedCharacter) { case "": case "": selectedCharacter = "\n"; break; case "": case "": selectedCharacter = " "; break; default: selectedCharacter = ""; break; } } return selectedCharacter; } function repeatFn(cm, fn, repeat) { return function() { for (var i = 0; i < repeat; i++) { fn(cm); } }; } function copyCursor(cur2) { return new Pos2(cur2.line, cur2.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 Pos2(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 Pos2(line, baseCh), head: new Pos2(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 = cursorEqual(ranges[i].anchor, cursor); var atHead = cursorEqual(ranges[i].head, cursor); if (atAnchor || atHead) { return i; } } return -1; } function getSelectedAreaRange(cm, vim2) { 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]; } 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 = void 0; } 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 Pos2(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 Pos2(top + i, fromCh), head: new Pos2(top + i, toCh) }); } return { ranges, primary }; } throw "never happens"; } function getHead(cm) { var cur2 = cm.getCursor("head"); if (cm.getSelection().length == 1) { cur2 = cursorMin(cur2, cm.getCursor("anchor")); } return cur2; } 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) CM.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 cur2 = cursor || getHead(cm); var line = cm.getLine(cur2.line); var endLine = line; var startLineNumber = cur2.line; var endLineNumber = startLineNumber; var idx = cur2.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, cur2, 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 = cur2.ch <= start && /\s/.test(line.charAt(cur2.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 Pos2(startLineNumber, start), end: new Pos2(endLineNumber, end) }; } function expandTagUnderCursor(cm, head, inclusive) { var cur2 = head; if (!CM.findMatchingTag || !CM.findEnclosingTag) { return { start: cur2, end: cur2 }; } var tags3 = CM.findMatchingTag(cm, head) || CM.findEnclosingTag(cm, head); if (!tags3 || !tags3.open || !tags3.close) { return { start: cur2, end: cur2 }; } if (inclusive) { return { start: tags3.open.from, end: tags3.close.to }; } return { start: tags3.open.to, end: tags3.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) { var _a; if (state.nextCh === "#") { var token = (_a = state.lineText.match(/^#(\w+)/)) == null ? void 0 : _a[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 cur2 = copyCursor(cm.getCursor()); var increment = forward ? 1 : -1; var endLine = forward ? cm.lineCount() : -1; var curCh = cur2.ch; var line = cur2.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 cur2; 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)) { cur2.line = line; cur2.ch = state.index; repeat--; } } if (state.nextCh || state.curMoveThrough) { return new Pos2(line, state.index); } return cur2; } function findWord(cm, cur2, forward, bigWord, emptyLineIsWord) { var lineNum = cur2.line; var pos = cur2.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 == cur2.ch && lineNum == cur2.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, cur2, repeat, forward, wordEnd, bigWord) { var curStart = copyCursor(cur2); var words = []; if (forward && !wordEnd || !forward && wordEnd) { repeat++; } var emptyLineIsWord = !(forward && wordEnd); for (var i = 0; i < repeat; i++) { var word = findWord(cm, cur2, forward, bigWord, emptyLineIsWord); if (!word) { 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(word); cur2 = new Pos2(word.line, forward ? word.to - 1 : word.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 Pos2(lastWord.line, lastWord.from); } else if (forward && wordEnd) { return lastWord && new Pos2(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 Pos2(lastWord.line, lastWord.to); } else { return lastWord && new Pos2(lastWord.line, lastWord.from); } } function moveToEol(cm, head, motionArgs, vim2, keepHPos) { var cur2 = head; var retval = new Pos2(cur2.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 cur2 = head || cm.getCursor(); var start = cur2.ch; var idx; for (var i = 0; i < repeat; i++) { var line = cm.getLine(cur2.line); idx = charIdxInLine(start, line, character, forward); if (idx == -1) { return void 0; } start = idx; } if (idx != void 0) return new Pos2(cm.getCursor().line, idx); } function moveToColumn(cm, repeat) { var line = cm.getCursor().line; return clipCursorToContent(cm, new Pos2(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); } else { idx = line.lastIndexOf(character, start - 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 isEmpty(i2) { return !cm.getLine(i2); } function isBoundary(i2, dir2, any) { if (any) { return isEmpty(i2) != isEmpty(i2 + dir2); } return !isEmpty(i2) && isEmpty(i2 + dir2); } if (dir) { while (min <= i && i <= max && repeat > 0) { if (isBoundary(i, dir)) { repeat--; } i += dir; } return { start: new Pos2(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 = isEmpty(line); for (i = line; i <= max && repeat; i++) { if (isBoundary(i, 1, true)) { if (!inclusive || isEmpty(i) != startState) { repeat--; } } } end = new Pos2(i, 0); if (i > max && !startState) { startState = true; } else { inclusive = false; } for (i = line; i > min; i--) { if (!inclusive || isEmpty(i) == startState || i == line) { if (isBoundary(i, -1, true)) { break; } } } start = new Pos2(i, 0); return { start, end }; } function getSentence(cm, cur2, repeat, dir, inclusive) { function nextChar2(curr) { if (curr.line === null) return; 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; nextChar2(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 { nextChar2(curr); while (curr.line !== null) { if (isWhiteSpaceString(curr.line[curr.pos])) { lastSentencePos = curr.pos; nextChar2(curr); } else { break; } } return { ln: curr.ln, pos: lastSentencePos + 1 }; } } nextChar2(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; nextChar2(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 }; } } } nextChar2(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: cur2.line, pos: cur2.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 Pos2(curr_index.ln, curr_index.pos); } function findSentence(cm, cur2, repeat, dir) { function nextChar2(cm2, idx) { if (idx.line === null) return; 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; 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 === ""; nextChar2(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; } nextChar2(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; var last_valid_pos = null; var skip_empty_lines = curr.line === ""; nextChar2(cm2, curr); while (curr.line !== null) { if (curr.line === "" && !skip_empty_lines) { if (last_valid_pos !== null) { return { ln: last_valid_ln, pos: last_valid_pos }; } 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 { ln: last_valid_ln, pos: last_valid_pos }; } else if (curr.line !== "" && !isWhiteSpaceString(curr.line[curr.pos])) { skip_empty_lines = false; last_valid_ln = curr.ln; last_valid_pos = curr.pos; } nextChar2(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 { ln: last_valid_ln, pos: last_valid_pos }; } var curr_index = { ln: cur2.line, pos: cur2.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 Pos2(curr_index.ln, curr_index.pos); } function selectCompanionObject(cm, head, symb, inclusive) { var cur2 = head; var bracketRegexp = { "(": /[()]/, ")": /[()]/, "[": /[[\]]/, "]": /[[\]]/, "{": /[{}]/, "}": /[{}]/, "<": /[<>]/, ">": /[<>]/ }[symb]; var openSym = { "(": "(", ")": "(", "[": "[", "]": "[", "{": "{", "}": "{", "<": "<", ">": "<" }[symb]; var curChar = cm.getLine(cur2.line).charAt(cur2.ch); var offset = curChar === openSym ? 1 : 0; var startBracket = cm.scanForBracket(new Pos2(cur2.line, cur2.ch + offset), -1, void 0, { "bracketRegex": bracketRegexp }); var endBracket = cm.scanForBracket(new Pos2(cur2.line, cur2.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 cur2 = copyCursor(head); var line = cm.getLine(cur2.line); var chars = line.split(""); var start, end, i, len; var firstIndex = chars.indexOf(symb); if (cur2.ch < firstIndex) { cur2.ch = firstIndex; } else if (firstIndex < cur2.ch && chars[cur2.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 = cur2.ch; --cur2.ch; } } if (chars[cur2.ch] == symb && !end) { start = cur2.ch + 1; } else { for (i = cur2.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: cur2, end: cur2 }; } if (inclusive) { --start; ++end; } return { start: new Pos2(cur2.line, start), end: new Pos2(cur2.line, end) }; } defineOption("pcre", true, "boolean"); class SearchState { constructor() { this.highlightTimeout; } 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 modes = { V: "|(){+?*.[$^", // verynomagic M: "|(){+?*.[", // nomagic m: "|(){+?", // magic v: "<>" // verymagic }; var escapes = { ">": "(?<=[\\w])(?=[^\\w]|$)", "<": "(?<=[^\\w]|^)(?=[\\w])" }; var specials = modes.m; var regex = str.replace(/\\.|[\[|(){+*?.$^<>]/g, function(match) { if (match[0] === "\\") { var nextChar2 = match[1]; if (nextChar2 === "}" || specials.indexOf(nextChar2) != -1) { return nextChar2; } if (nextChar2 in modes) { specials = modes[nextChar2]; return ""; } if (nextChar2 in escapes) { return escapes[nextChar2]; } return match; } else { if (specials.indexOf(match) != -1) { return escapes[match] || "\\" + match; } return match; } }); var i = regex.indexOf("\\zs"); if (i != -1) { regex = "(?<=" + regex.slice(0, i) + ")" + regex.slice(i + 3); } i = regex.indexOf("\\ze"); if (i != -1) { regex = regex.slice(0, i) + "(?=" + regex.slice(i + 3) + ")"; } return regex; } 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 CM.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); 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 i = 1; i < arguments.length; i++) { var a = arguments[i]; if (!a) 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 if (typeof a[key] == "function") n[key] = a[key]; else n.setAttribute(key, a[key]); } } return n; } function showConfirm(cm, template, long) { var pre = dom("div", { $color: "red", $whiteSpace: "pre", class: "cm-vim-message" }, template); if (cm.openNotification) { if (long) { pre = dom("div", {}, pre, dom("div", {}, "Press ENTER or type command to continue")); if (cm.state.closeVimNotification) { cm.state.closeVimNotification(); } cm.state.closeVimNotification = cm.openNotification(pre, { bottom: true, duration: 0 }); } else { cm.openNotification(pre, { bottom: true, duration: 15e3 }); } } else { alert(pre.innerText); } } function makePrompt(prefix, desc) { return dom( "div", { $display: "flex", $flex: 1 }, dom( "span", { $fontFamily: "monospace", $whiteSpace: "pre", $flex: 1, $display: "flex" }, prefix, dom("input", { type: "text", autocorrect: "off", autocapitalize: "off", spellcheck: "false", $flex: 1 }) ), desc && dom("span", { $color: "#888" }, desc) ); } function showPrompt(cm, options2) { var _a; 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; (_a = options2.onClose) == null ? void 0 : _a.call(options2, prompt(shortText, "")); } } function regexEqual(r1, r2) { if (r1 instanceof RegExp && r2 instanceof RegExp) { return r1.flags == r2.flags && r1.source == r2.source; } 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 = void 0; 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 Pos2(cm.lastLine()) : new Pos2(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 Pos2(cm.lastLine()) : new Pos2(cm.firstLine(), 0) ); if (!cursor.find(prev)) { return; } } } var from = cursor.from(); var to = cursor.to(); return from && to && [from, to]; }); } function clearSearchHighlight(cm) { var state = getSearchState(cm); if (state.highlightTimeout) { clearTimeout(state.highlightTimeout); state.highlightTimeout = void 0; } 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 Pos2(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_(); } /** * @arg {CodeMirrorV} cm * @arg {string} input * @arg {{ callback: () => void; } | undefined} [opt_params] */ processCommand(cm, input, opt_params) { var that = this; cm.operation(function() { if (cm.curOp) cm.curOp.isVimOp = true; that._processCommand(cm, input, opt_params); }); } /** * @arg {CodeMirrorV} cm * @arg {string} input * @arg {{ callback?: () => void; input?: string, line?: string, commandName?: string } } [opt_params] */ _processCommand(cm, input, opt_params) { var vim2 = cm.state.vim; var commandHistoryRegister = vimGlobalState.registerController.getRegister(":"); var previousCommand = commandHistoryRegister.toString(); var inputStream = new CM.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; } } /** * @param {CodeMirrorV} cm * @param {import("@codemirror/language").StringStream} inputStream * @param {{ callback?: (() => void) | undefined; input?: string | undefined; line?: any; commandName?: any; lineEnd?: any; selectionLine?: any; selectionLineEnd?: any; }} result */ 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; } /** * @param {CodeMirrorV} cm * @param {import("@codemirror/language").StringStream} inputStream */ 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; } } /** * @param {string | import("@codemirror/language").StringStream} inputStream * @param {number} line */ 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; } /** * @param {import("@codemirror/language").StringStream} inputStream * @param {import("./types").exCommandArgs} params * @param {import("./types").exCommandDefinition} command */ parseCommandArgs_(inputStream, params, command) { var _a; if (inputStream.eol()) { return; } params.argString = (_a = inputStream.match(/.*/)) == null ? void 0 : _a[0]; var delim = command.argDelimiter || /\s+/; var args = trim(params.argString || "").split(delim); if (args.length && args[0]) { params.args = args; } } /** * @arg {string} commandName */ 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; } } } } 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|void, 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; } _mapCommand(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); removeUsedKeys(keys2); 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]); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params @arg {'insert'|'normal'|string} [ctx] @arg {boolean} [defaultOnly]*/ 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, true); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ marks: function(cm, params) { var filterArgs = params.args; var marks = cm.state.vim.marks; var regInfo = "-----------Marks-----------\nmark line col\n\n"; if (!filterArgs) { for (var name in marks) { var marker = marks[name] && marks[name].find(); if (marker) { regInfo += name + " " + marker.line + " " + marker.ch + "\n"; } } } else { var registerNames = filterArgs.join(""); for (var i = 0; i < registerNames.length; i++) { var name = registerNames.charAt(i); var marker = marks[name] && marks[name].find(); if (marker) { regInfo += name + " " + marker.line + " " + marker.ch + "\n"; } } } showConfirm(cm, regInfo, true); }, /** @arg {CodeMirrorV} cm @arg {ExParams} params*/ sort: function(cm, params) { var reverse, ignoreCase, unique, number, pattern; function parseArgs() { if (params.argString) { var args = new CM.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 = parseArgs(); 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 Pos2(lineStart, 0); var curEnd = new Pos2(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 noremap2 = false; var argString = params.argString; if (argString && argString[0] == "!") { argString = argString.slice(1); noremap2 = 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(), { noremap: noremap2 }); if (cm.state.vim.insertMode) { exitInsertMode(cm, true); } } } else { doKeyToKey(cm, params.argString.trimStart(), { noremap: noremap2 }); 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 Pos2(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: CM.commands.redo, undo: CM.commands.undo, /** @arg {CodeMirrorV} cm */ write: function(cm) { if (CM.commands.save) { CM.commands.save(cm); } else if (cm.save) { cm.save(); } }, /** @arg {CodeMirrorV} cm */ nohlsearch: function(cm) { clearSearchHighlight(cm); }, /** @arg {CodeMirrorV} cm */ yank: function(cm) { var cur2 = copyCursor(cm.getCursor()); var line = cur2.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 Pos2(line, 0), head: new Pos2(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 Pos2(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 CM.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(); vimApi.defineEx("version", "ve", (cm) => { showConfirm(cm, "Codemirror-vim version: 6.3.0"); }); function doReplace(cm, confirm, global, lineStart, lineEnd, searchCursor, query, replaceWith, callback) { cm.state.vim.exMode = true; var done = false; var matches = 0; var lastPos; var modifiedLineNumber; var joined; function replaceAll() { cm.operation(function() { while (!done) { replace(); next(); } stop(); }); } function replace() { var newText = ""; var match = searchCursor.match || searchCursor.pos && searchCursor.pos.match; if (match) { newText = replaceWith.replace(/\$(\d{1,3}|[$&])/g, function(_, x) { if (x == "$") return "$"; if (x == "&") return match[0]; var x1 = x; while (parseInt(x1) >= match.length && x1.length > 0) { x1 = x1.slice(0, x1.length - 1); } if (x1) return match[x1] + x.slice(x1.length, x.length); return _; }); } else { var text = cm.getRange(searchCursor.from(), searchCursor.to()); 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(); } if (match) matches++; 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(); } else if (done) { showConfirm( cm, (matches ? "Found " + matches + " matches" : "No matches found") + " for pattern: " + query + (getOption("pcre") ? " (set nopcre to use Vim regexps)" : "") ); } } function onPromptKeyDown(e, _value, close) { CM.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(); // fall through and exit. case "q": case "": case "": case "": stop(close); break; } if (done) { stop(close); } return true; } next(); if (done) { showConfirm(cm, "No matches for " + query + (getOption("pcre") ? " (set nopcre to use vim regexps)" : "")); 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; CM.off(cm.getInputField(), "keydown", onKeyEventTargetKeyDown); } if (!isPlaying && vim2.insertModeRepeat && 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("")); CM.signal(cm, "vim-mode-change", { mode: "normal" }); if (macroModeState.isRecording) { logInsertModeChange(macroModeState); } } function _mapCommand(command) { defaultKeymap2.unshift(command); if (command.keys) addUsedKeys(command.keys); } function addUsedKeys(keys2) { keys2.split(/(<(?:[CSMA]-)*\w+>|.)/i).forEach(function(part) { if (part) { if (!usedKeys[part]) usedKeys[part] = 0; usedKeys[part]++; } }); } function removeUsedKeys(keys2) { keys2.split(/(<(?:[CSMA]-)*\w+>|.)/i).forEach(function(part) { if (usedKeys[part]) usedKeys[part]--; }); } 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; CM.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 onKeyEventTargetKeyDown(e) { var macroModeState = vimGlobalState.macroModeState; var lastChange = macroModeState.lastInsertModeChanges; var keyName = CM.keyName ? CM.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) { CM.lookupKey(key, "vim-insert", function keyHandler(binding) { if (typeof binding == "string") { CM.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; if (cm.state.closeVimNotification) { var close = cm.state.closeVimNotification; cm.state.closeVimNotification = null; close(); if (key == "") { clearInputState(cm); return true; } } var wasMultiselect = cm.isInMultiSelectMode(); if (vim2.wasInVisualBlock && !wasMultiselect) { vim2.wasInVisualBlock = false; } else if (wasMultiselect && vim2.visualBlock) { vim2.wasInVisualBlock = true; } if (key == "" && !vim2.insertMode && !vim2.visualMode && wasMultiselect && vim2.status == "") { clearInputState(cm); } else if (visualBlock || !wasMultiselect || cm.inVirtualSelectionMode) { isHandled = vimApi.handleKey(cm, key, origin); } else { var old = cloneVimState(vim2); var changeQueueList = vim2.inputState.changeQueueList || []; cm.operation(function() { var _a; if (cm.curOp) cm.curOp.isVimOp = true; var index = 0; cm.forEachSelection(function() { cm.state.vim.inputState.changeQueue = changeQueueList[index]; var head = cm.getCursor("head"); var anchor = cm.getCursor("anchor"); var headOffset = !cursorIsBefore(head, anchor) ? -1 : 0; var anchorOffset = cursorIsBefore(head, anchor) ? -1 : 0; head = offsetCursor(head, 0, headOffset); anchor = offsetCursor(anchor, 0, anchorOffset); cm.state.vim.sel.head = head; cm.state.vim.sel.anchor = anchor; isHandled = vimApi.handleKey(cm, key, origin); if (cm.virtualSelection) { changeQueueList[index] = cm.state.vim.inputState.changeQueue; cm.state.vim = cloneVimState(old); } index++; }); if (((_a = cm.curOp) == null ? void 0 : _a.cursorActivity) && !isHandled) cm.curOp.cursorActivity = false; cm.state.vim = vim2; vim2.inputState.changeQueueList = changeQueueList; vim2.inputState.changeQueue = null; }, true); } if (isHandled && !vim2.visualMode && !vim2.insertMode && 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 = { Left: (cm) => (0, import_view.runScopeHandlers)(cm.cm6, { key: "Left" }, "editor"), Right: (cm) => (0, import_view.runScopeHandlers)(cm.cm6, { key: "Right" }, "editor"), Up: (cm) => (0, import_view.runScopeHandlers)(cm.cm6, { key: "Up" }, "editor"), Down: (cm) => (0, import_view.runScopeHandlers)(cm.cm6, { key: "Down" }, "editor"), Backspace: (cm) => (0, import_view.runScopeHandlers)(cm.cm6, { key: "Backspace" }, "editor"), Delete: (cm) => (0, import_view.runScopeHandlers)(cm.cm6, { key: "Delete" }, "editor") }; var CodeMirror = class _CodeMirror { // -------------------------- openDialog(template, callback, options) { return openDialog(this, template, callback, options); } openNotification(template, options) { return openNotification(this, template, options); } 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); } 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(p) { var sel = this.cm6.state.selection.main; var offset = p == "head" || !p ? sel.head : p == "anchor" ? sel.anchor : p == "start" ? sel.from : p == "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(p, primIndex) { var doc = this.cm6.state.doc; var ranges = p.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(p) { var doc = this.cm6.state.doc; var ch = p.ch; var lineNumber = p.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, config3) { return scanForBracket(this, pos, dir, style, config3); } 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 cur2 = state.selection.main.head; if (cur2 < state.doc.length && state.sliceDoc(cur2, cur2 + 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; var afterEmptyMatch = false; 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 ? afterEmptyMatch ? last.to - 1 : last.from : firstOffset; last = prevMatchInRange(0, endAt); } else { let startFrom = last ? afterEmptyMatch ? last.to + 1 : last.to : firstOffset; last = nextMatch(startFrom); } lastCM5Result = last && { from: posFromIndex(doc, last.from), to: posFromIndex(doc, last.to), match: last.match }; afterEmptyMatch = last ? last.from == last.to : false; 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); } } }, get match() { return lastCM5Result && lastCM5Result.match; } }; } 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 scrollIntoView2 = false; if (op) { if (op.change) { signalTo(op.changeHandlers, this, op.change); } if (op && op.cursorActivity) { signalTo(op.cursorActivityHandlers, this, null); if (op.isVimOp) scrollIntoView2 = true; } this.curOp = null; } if (scrollIntoView2) this.scrollIntoView(); } moveH(increment, unit) { if (unit == "char") { var cur2 = this.getCursor(); this.setCursor(cur2.line, cur2.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) == " "; // TODO case "indentUnit": return this.cm6.state.facet(import_language.indentUnit).length || 2; case "textwidth": return this.state.textwidth; // for tests 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 && /^Arrow/.test(key)) result = CodeMirror.keys[key.slice(5)]; 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; dialog.style.flex = "1"; 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 && 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(config3) { return config3 && config3.bracketRegex || /[(){}[\]]/; } function scanForBracket(cm, where, dir, style, config3) { var maxScanLen = config3 && config3.maxScanLineLength || 1e4; var maxScanLines = config3 && config3.maxScanLines || 1e3; var stack = []; var re = bracketRegex(config3); 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) { return null; } 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 space2 = findSpace(line, max, 5); if (space2) { var indentation = (_a = /^\s*/.exec(line)) === null || _a === void 0 ? void 0 : _a[0]; cm.replaceRange("\n" + indentation, new Pos(row, space2.start), new Pos(row, space2.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 space2 = findSpace(mergedLine, max, 5); if (space2 && space2.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(p) { return this.left == p.left && this.top == p.top && this.height == p.height && this.fontFamily == p.fontFamily && this.fontSize == p.fontSize && this.fontWeight == p.fontWeight && this.color == p.color && this.className == p.className && this.letter == p.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 config3 = getDrawSelectionConfig2(this.cm.cm6.state); let blinkRate = config3.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 * view.scaleX, top: rect.top - view.scrollDOM.scrollTop * view.scaleY }; } function measureCursor(cm, view, cursor, primary) { var _a, _b, _c, _d; 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) { let letter = head < view.state.doc.length && view.state.sliceDoc(head, head + 1); if (letter != "\n") 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; if (node instanceof Text && domAtPos.offset >= node.data.length) { if ((_a = node.parentElement) === null || _a === void 0 ? void 0 : _a.nextSibling) { node = (_b = node.parentElement) === null || _b === void 0 ? void 0 : _b.nextSibling; domAtPos = { node, offset: 0 }; } } 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 = (_d = (_c = view).coordsForChar) === null || _d === void 0 ? void 0 : _d.call(_c, 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) / view.scaleX, (pos.top - base.top + h * (1 - hCoeff)) / view.scaleY, h * hCoeff / view.scaleY, 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", display: "flex" }, ".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.spacer = document.createElement("span"); this.spacer.style.flex = "1"; this.statusButton = document.createElement("span"); this.statusButton.onclick = (e) => { Vim.handleKey(this.cm, "", "user"); this.cm.focus(); }; this.statusButton.style.cssText = "cursor: pointer"; } update(update) { var _a; if ((update.viewportChanged || update.docChanged) && this.query) { this.highlight(this.query); } if (update.docChanged) { this.cm.onChange(update); } if (update.selectionSet) { this.cm.onSelectionChange(); } if (update.viewportChanged) ; if (this.cm.curOp && !this.cm.curOp.isVimOp) { this.cm.onBeforeEndOperation(); } if (update.transactions) { for (let tr of update.transactions) for (let effect of tr.effects) { if (effect.is(import_search.setSearchQuery)) { let forVim = (_a = effect.value) === null || _a === void 0 ? void 0 : _a.forVim; if (!forVim) { this.highlight(null); } else { let query = effect.value.create(); this.highlight(query); } } } } this.blockCursor.update(update); } updateClass() { const state = this.cm.state; if (!state.vim || state.vim.insertMode && !state.overwrite) this.view.scrollDOM.classList.remove("cm-vimMode"); else this.view.scrollDOM.classList.add("cm-vimMode"); } updateStatus() { let dom = this.cm.state.statusbar; let vim2 = this.cm.state.vim; if (!dom || !vim2) return; let dialog = this.cm.state.dialog; if (dialog) { if (dialog.parentElement != dom) { dom.textContent = ""; dom.appendChild(dialog); } } else { dom.textContent = ""; var status = (vim2.mode || "normal").toUpperCase(); if (vim2.insertModeReturn) status += "(C-O)"; this.statusButton.textContent = `--${status}--`; dom.appendChild(this.statusButton); dom.appendChild(this.spacer); } this.dom.textContent = vim2.status; dom.appendChild(this.dom); } destroy() { Vim.leaveVimMode(this.cm); this.updateClass(); this.blockCursor.destroy(); delete this.view.cm; } highlight(query) { this.query = query; if (!query) return this.decorations = import_view.Decoration.none; let { view } = this; let builder = new import_state.RangeSetBuilder(); for (let i = 0, ranges = view.visibleRanges, l = ranges.length; i < l; i++) { let { from, to } = ranges[i]; while (i < l - 1 && to > ranges[i + 1].from - 2 * HighlightMargin) to = ranges[++i].to; query.highlight(view.state, from, to, (from2, to2) => { builder.add(from2, to2, matchMark); }); } return this.decorations = builder.finish(); } handleKey(e, view) { const cm = this.cm; let vim2 = cm.state.vim; if (!vim2) return; const key = Vim.vimKeyFromEvent(e, vim2); CodeMirror.signal(this.cm, "inputEvent", { type: "handleKey", key }); if (!key) return; if (key == "" && !vim2.insertMode && !vim2.visualMode && this.query) { const searchState = vim2.searchState_; if (searchState) { cm.removeOverlay(searchState.getOverlay()); searchState.setOverlay(null); } } let isCopy = key === "" && !CodeMirror.isMac; if (isCopy && cm.somethingSelected()) { this.waitForCopy = true; return true; } vim2.status = (vim2.status || "") + key; let result = Vim.multiSelectHandleKey(cm, key, "user"); vim2 = Vim.maybeInitVimState_(cm); if (!result && vim2.insertMode && cm.state.overwrite) { if (e.key && e.key.length == 1 && !/\n/.test(e.key)) { result = true; cm.overWriteSelection(e.key); } else if (e.key == "Backspace") { result = true; CodeMirror.commands.cursorCharLeft(cm); } } if (result) { CodeMirror.signal(this.cm, "vim-keypress", key); e.preventDefault(); e.stopPropagation(); this.blockCursor.scheduleRedraw(); } this.updateStatus(); return !!result; } }, { eventHandlers: { copy: function(e, view) { if (!this.waitForCopy) return; this.waitForCopy = false; Promise.resolve().then(() => { var cm = this.cm; var vim2 = cm.state.vim; if (!vim2) return; if (vim2.insertMode) { cm.setSelection(cm.getCursor(), cm.getCursor()); } else { cm.operation(() => { if (cm.curOp) cm.curOp.isVimOp = true; Vim.handleKey(cm, "", "user"); }); } }); }, compositionstart: function(e, view) { this.useNextTextInput = true; CodeMirror.signal(this.cm, "inputEvent", e); }, compositionupdate: function(e, view) { CodeMirror.signal(this.cm, "inputEvent", e); }, compositionend: function(e, view) { CodeMirror.signal(this.cm, "inputEvent", e); }, keypress: function(e, view) { CodeMirror.signal(this.cm, "inputEvent", e); if (this.lastKeydown == "Dead") this.handleKey(e, view); }, keydown: function(e, view) { CodeMirror.signal(this.cm, "inputEvent", e); this.lastKeydown = e.key; if (this.lastKeydown == "Unidentified" || this.lastKeydown == "Process" || this.lastKeydown == "Dead") { this.useNextTextInput = true; } else { this.useNextTextInput = false; this.handleKey(e, view); } } }, provide: () => { return [ import_view.EditorView.inputHandler.of((view, from, to, text) => { var _a, _b; var cm = getCM(view); if (!cm) return false; var vim2 = (_a = cm.state) === null || _a === void 0 ? void 0 : _a.vim; var vimPlugin2 = cm.state.vimPlugin; if (vim2 && !vim2.insertMode && !((_b = cm.curOp) === null || _b === void 0 ? void 0 : _b.isVimOp)) { if (text === "\0\0") { return true; } CodeMirror.signal(cm, "inputEvent", { type: "text", text, from, to }); if (text.length == 1 && vimPlugin2.useNextTextInput) { if (vim2.expectLiteralNext && view.composing) { vimPlugin2.compositionText = text; return false; } if (vimPlugin2.compositionText) { var toRemove = vimPlugin2.compositionText; vimPlugin2.compositionText = ""; var head = view.state.selection.main.head; var textInDoc = view.state.sliceDoc(head - toRemove.length, head); if (toRemove === textInDoc) { var pos = cm.getCursor(); cm.replaceRange("", cm.posFromIndex(head - toRemove.length), pos); } } vimPlugin2.handleKey({ key: text, preventDefault: () => { }, stopPropagation: () => { } }); forceEndComposition(view); return true; } } return false; }) ]; }, decorations: (v) => v.decorations }); function forceEndComposition(view) { var parent = view.scrollDOM.parentElement; if (!parent) return; if (FIREFOX_LINUX) { view.contentDOM.textContent = "\0\0"; view.contentDOM.dispatchEvent(new CustomEvent("compositionend")); return; } var sibling = view.scrollDOM.nextSibling; var selection = window.getSelection(); var savedSelection = selection && { anchorNode: selection.anchorNode, anchorOffset: selection.anchorOffset, focusNode: selection.focusNode, focusOffset: selection.focusOffset }; view.scrollDOM.remove(); parent.insertBefore(view.scrollDOM, sibling); try { if (savedSelection && selection) { selection.setPosition(savedSelection.anchorNode, savedSelection.anchorOffset); if (savedSelection.focusNode) { selection.extend(savedSelection.focusNode, savedSelection.focusOffset); } } } catch (e) { console.error(e); } view.focus(); view.contentDOM.dispatchEvent(new CustomEvent("compositionend")); } var matchMark = /* @__PURE__ */ import_view.Decoration.mark({ class: "cm-searchMatch" }); var showVimPanel = /* @__PURE__ */ import_state.StateEffect.define(); var vimPanelState = /* @__PURE__ */ import_state.StateField.define({ create: () => false, update(value, tr) { for (let e of tr.effects) if (e.is(showVimPanel)) value = e.value; return value; }, provide: (f) => { return import_view.showPanel.from(f, (on2) => on2 ? createVimPanel : null); } }); function createVimPanel(view) { let dom = document.createElement("div"); dom.className = "cm-vim-panel"; let cm = view.cm; if (cm.state.dialog) { dom.appendChild(cm.state.dialog); } return { top: false, dom }; } function statusPanel(view) { let dom = document.createElement("div"); dom.className = "cm-vim-panel"; let cm = view.cm; cm.state.statusbar = dom; cm.state.vimPlugin.updateStatus(); return { dom }; } function vim(options = {}) { return [ vimStyle, vimPlugin, hideNativeSelection, options.status ? import_view.showPanel.of(statusPanel) : vimPanelState ]; } function getCM(view) { return view.cm || null; } // src/CssFile.ts var CssFile = class { constructor(name) { /** File extension. */ this.extension = "css"; if (typeof name !== "string" || name.length === 0) { throw new Error("Invalid file name."); } const extensionWithDot = `.${this.extension}`; const basename = name.endsWith(extensionWithDot) ? name.slice(0, name.length - extensionWithDot.length) : name; this.name = `${basename}.${this.extension}`; this.basename = basename; } }; // src/obsidian/file-system-helpers.ts var import_obsidian = require("obsidian"); function getSnippetDirectory(app) { return `${app.vault.configDir}/snippets/`; } async function readSnippetFile(app, file) { const data = await app.vault.adapter.read( (0, import_obsidian.normalizePath)(`${getSnippetDirectory(app)}${file.name}`) ); return data; } async function createSnippetFile(app, fileName, data = "") { const file = new CssFile(fileName); await _validateFile(app, file); await _createSnippetDirectoryIfNotExists(app); await app.vault.adapter.write( (0, import_obsidian.normalizePath)(`${getSnippetDirectory(app)}${file.name}`), data ); return file; } async function renameSnippetFile(app, oldFile, newFileName) { const newFile = new CssFile(newFileName); if (oldFile.name === newFile.name) return oldFile; await _validateFile(app, newFile); await app.vault.adapter.rename( (0, import_obsidian.normalizePath)(`${getSnippetDirectory(app)}${oldFile.name}`), (0, import_obsidian.normalizePath)(`${getSnippetDirectory(app)}${newFile.name}`) ); toggleSnippetFileState(app, oldFile); toggleSnippetFileState(app, newFile); app.workspace.trigger("css-snippet-rename", newFile, oldFile.name); return newFile; } async function writeSnippetFile(app, file, data) { await app.vault.adapter.write( (0, import_obsidian.normalizePath)(`${getSnippetDirectory(app)}${file.name}`), data ); } async function checkSnippetExists(app, fileName) { return app.vault.adapter.exists( (0, import_obsidian.normalizePath)(`${getSnippetDirectory(app)}${fileName}`) ); } async function deleteSnippetFile(app, file) { await app.vault.adapter.remove( (0, import_obsidian.normalizePath)(`${getSnippetDirectory(app)}${file.name}`) ); } function toggleSnippetFileState(app, file) { var _a; if (!((_a = app.customCss) == null ? void 0 : _a.enabledSnippets) || !app.customCss.setCssEnabledStatus) { throw new Error("Failed to enable/disable CSS snippet."); } const isEnabled = app.customCss.enabledSnippets.has(file.basename); app.customCss.setCssEnabledStatus(file.basename, !isEnabled); return !isEnabled; } async function _createSnippetDirectoryIfNotExists(app) { if (!await app.vault.adapter.exists(getSnippetDirectory(app))) { await app.vault.adapter.mkdir(getSnippetDirectory(app)); } } async function _validateFile(app, file) { const errors = { exists: "", regex: "" }; if (file.name.length > 0 && await checkSnippetExists(app, file.name)) { errors.exists = "File already exists."; } const regex = /^[0-9a-zA-Z\-_ ]+\.css$/; if (!regex.test(file.name)) { errors.regex = "Must end with .css and only contain alphanumeric, spaces, dashes, or underscore characters."; } if (Object.values(errors).some((x) => x !== "")) { const message = Object.values(errors).filter((x) => x !== "").reduce((acc, curr) => `${acc} ${curr}`, "Failed to create file."); throw new Error(message); } } // src/codemirror-extensions/basic-extensions.ts var import_commands2 = require("@codemirror/commands"); var import_language6 = require("@codemirror/language"); var import_state3 = require("@codemirror/state"); var import_view5 = require("@codemirror/view"); // node_modules/@codemirror/autocomplete/dist/index.js var import_state2 = require("@codemirror/state"); var import_view2 = require("@codemirror/view"); var import_language2 = require("@codemirror/language"); var CompletionContext = class { /** Create a new completion context. (Mostly useful for testing completion sources—in the editor, the extension will create these for you.) */ constructor(state, pos, explicit) { this.state = state; this.pos = pos; this.explicit = explicit; this.abortListeners = []; } /** Get the extent, content, and (if there is a token) type of the token before `this.pos`. */ tokenBefore(types) { let token = (0, import_language2.syntaxTree)(this.state).resolveInner(this.pos, -1); while (token && types.indexOf(token.name) < 0) token = token.parent; return token ? { from: token.from, to: this.pos, text: this.state.sliceDoc(token.from, this.pos), type: token.type } : null; } /** Get the match of the given expression directly before the cursor. */ matchBefore(expr) { let line = this.state.doc.lineAt(this.pos); let start = Math.max(line.from, this.pos - 250); let str = line.text.slice(start - line.from, this.pos - line.from); let found = str.search(ensureAnchor(expr, false)); return found < 0 ? null : { from: start + found, to: this.pos, text: str.slice(found) }; } /** Yields true when the query has been aborted. Can be useful in asynchronous queries to avoid doing work that will be ignored. */ get aborted() { return this.abortListeners == null; } /** Allows you to register abort handlers, which will be called when the query is [aborted](https://codemirror.net/6/docs/ref/#autocomplete.CompletionContext.aborted). */ addEventListener(type, listener) { if (type == "abort" && this.abortListeners) this.abortListeners.push(listener); } }; function toSet(chars) { let flat = Object.keys(chars).join(""); let words = /\w/.test(flat); if (words) flat = flat.replace(/\w/g, ""); return `[${words ? "\\w" : ""}${flat.replace(/[^\w\s]/g, "\\$&")}]`; } function prefixMatch(options) { let first = /* @__PURE__ */ Object.create(null), rest = /* @__PURE__ */ Object.create(null); for (let { label } of options) { first[label[0]] = true; for (let i = 1; i < label.length; i++) rest[label[i]] = true; } let source = toSet(first) + toSet(rest) + "*$"; return [new RegExp("^" + source), new RegExp(source)]; } function completeFromList(list) { let options = list.map((o) => typeof o == "string" ? { label: o } : o); let [validFor, match] = options.every((o) => /^\w+$/.test(o.label)) ? [/\w*$/, /\w+$/] : prefixMatch(options); return (context) => { let token = context.matchBefore(match); return token || context.explicit ? { from: token ? token.from : context.pos, options, validFor } : null; }; } var Option = class { constructor(completion, source, match, score2) { this.completion = completion; this.source = source; this.match = match; this.score = score2; } }; function cur(state) { return state.selection.main.from; } function ensureAnchor(expr, start) { var _a; let { source } = expr; let addStart = start && source[0] != "^", addEnd = source[source.length - 1] != "$"; if (!addStart && !addEnd) return expr; return new RegExp(`${addStart ? "^" : ""}(?:${source})${addEnd ? "$" : ""}`, (_a = expr.flags) !== null && _a !== void 0 ? _a : expr.ignoreCase ? "i" : ""); } var pickedCompletion = /* @__PURE__ */ import_state2.Annotation.define(); function insertCompletionText(state, text, from, to) { let { main } = state.selection, fromOff = from - main.from, toOff = to - main.from; return Object.assign(Object.assign({}, state.changeByRange((range) => { if (range != main && from != to && state.sliceDoc(range.from + fromOff, range.from + toOff) != state.sliceDoc(from, to)) return { range }; return { changes: { from: range.from + fromOff, to: to == main.from ? range.to : range.from + toOff, insert: text }, range: import_state2.EditorSelection.cursor(range.from + fromOff + text.length) }; })), { userEvent: "input.complete" }); } var SourceCache = /* @__PURE__ */ new WeakMap(); function asSource(source) { if (!Array.isArray(source)) return source; let known = SourceCache.get(source); if (!known) SourceCache.set(source, known = completeFromList(source)); return known; } var startCompletionEffect = /* @__PURE__ */ import_state2.StateEffect.define(); var closeCompletionEffect = /* @__PURE__ */ import_state2.StateEffect.define(); var FuzzyMatcher = class { constructor(pattern) { this.pattern = pattern; this.chars = []; this.folded = []; this.any = []; this.precise = []; this.byWord = []; for (let p = 0; p < pattern.length; ) { let char = (0, import_state2.codePointAt)(pattern, p), size = (0, import_state2.codePointSize)(char); this.chars.push(char); let part = pattern.slice(p, p + size), upper = part.toUpperCase(); this.folded.push((0, import_state2.codePointAt)(upper == part ? part.toLowerCase() : upper, 0)); p += size; } this.astral = pattern.length != this.chars.length; } // Matches a given word (completion) against the pattern (input). // Will return null for no match, and otherwise an array that starts // with the match score, followed by any number of `from, to` pairs // indicating the matched parts of `word`. // // The score is a number that is more negative the worse the match // is. See `Penalty` above. match(word) { if (this.pattern.length == 0) return [ -100 /* NotFull */ ]; if (word.length < this.pattern.length) return null; let { chars, folded, any, precise, byWord } = this; if (chars.length == 1) { let first = (0, import_state2.codePointAt)(word, 0), firstSize = (0, import_state2.codePointSize)(first); let score2 = firstSize == word.length ? 0 : -100; if (first == chars[0]) ; else if (first == folded[0]) score2 += -200; else return null; return [score2, 0, firstSize]; } let direct = word.indexOf(this.pattern); if (direct == 0) return [word.length == this.pattern.length ? 0 : -100, 0, this.pattern.length]; let len = chars.length, anyTo = 0; if (direct < 0) { for (let i = 0, e = Math.min(word.length, 200); i < e && anyTo < len; ) { let next = (0, import_state2.codePointAt)(word, i); if (next == chars[anyTo] || next == folded[anyTo]) any[anyTo++] = i; i += (0, import_state2.codePointSize)(next); } if (anyTo < len) return null; } let preciseTo = 0; let byWordTo = 0, byWordFolded = false; let adjacentTo = 0, adjacentStart = -1, adjacentEnd = -1; let hasLower = /[a-z]/.test(word), wordAdjacent = true; for (let i = 0, e = Math.min(word.length, 200), prevType = 0; i < e && byWordTo < len; ) { let next = (0, import_state2.codePointAt)(word, i); if (direct < 0) { if (preciseTo < len && next == chars[preciseTo]) precise[preciseTo++] = i; if (adjacentTo < len) { if (next == chars[adjacentTo] || next == folded[adjacentTo]) { if (adjacentTo == 0) adjacentStart = i; adjacentEnd = i + 1; adjacentTo++; } else { adjacentTo = 0; } } } let ch, type = next < 255 ? next >= 48 && next <= 57 || next >= 97 && next <= 122 ? 2 : next >= 65 && next <= 90 ? 1 : 0 : (ch = (0, import_state2.fromCodePoint)(next)) != ch.toLowerCase() ? 1 : ch != ch.toUpperCase() ? 2 : 0; if (!i || type == 1 && hasLower || prevType == 0 && type != 0) { if (chars[byWordTo] == next || folded[byWordTo] == next && (byWordFolded = true)) byWord[byWordTo++] = i; else if (byWord.length) wordAdjacent = false; } prevType = type; i += (0, import_state2.codePointSize)(next); } if (byWordTo == len && byWord[0] == 0 && wordAdjacent) return this.result(-100 + (byWordFolded ? -200 : 0), byWord, word); if (adjacentTo == len && adjacentStart == 0) return [-200 - word.length + (adjacentEnd == word.length ? 0 : -100), 0, adjacentEnd]; if (direct > -1) return [-700 - word.length, direct, direct + this.pattern.length]; if (adjacentTo == len) return [-200 + -700 - word.length, adjacentStart, adjacentEnd]; if (byWordTo == len) return this.result(-100 + (byWordFolded ? -200 : 0) + -700 + (wordAdjacent ? 0 : -1100), byWord, word); return chars.length == 2 ? null : this.result((any[0] ? -700 : 0) + -200 + -1100, any, word); } result(score2, positions, word) { let result = [score2 - word.length], i = 1; for (let pos of positions) { let to = pos + (this.astral ? (0, import_state2.codePointSize)((0, import_state2.codePointAt)(word, pos)) : 1); if (i > 1 && result[i - 1] == pos) result[i - 1] = to; else { result[i++] = pos; result[i++] = to; } } return result; } }; var completionConfig = /* @__PURE__ */ import_state2.Facet.define({ combine(configs) { return (0, import_state2.combineConfig)(configs, { activateOnTyping: true, selectOnOpen: true, override: null, closeOnBlur: true, maxRenderedOptions: 100, defaultKeymap: true, tooltipClass: () => "", optionClass: () => "", aboveCursor: false, icons: true, addToOptions: [], positionInfo: defaultPositionInfo, compareCompletions: (a, b) => a.label.localeCompare(b.label), interactionDelay: 75 }, { defaultKeymap: (a, b) => a && b, closeOnBlur: (a, b) => a && b, icons: (a, b) => a && b, tooltipClass: (a, b) => (c) => joinClass(a(c), b(c)), optionClass: (a, b) => (c) => joinClass(a(c), b(c)), addToOptions: (a, b) => a.concat(b) }); } }); function joinClass(a, b) { return a ? b ? a + " " + b : a : b; } function defaultPositionInfo(view, list, option, info, space2) { let rtl = view.textDirection == import_view2.Direction.RTL, left = rtl, narrow = false; let side = "top", offset, maxWidth; let spaceLeft = list.left - space2.left, spaceRight = space2.right - list.right; let infoWidth = info.right - info.left, infoHeight = info.bottom - info.top; if (left && spaceLeft < Math.min(infoWidth, spaceRight)) left = false; else if (!left && spaceRight < Math.min(infoWidth, spaceLeft)) left = true; if (infoWidth <= (left ? spaceLeft : spaceRight)) { offset = Math.max(space2.top, Math.min(option.top, space2.bottom - infoHeight)) - list.top; maxWidth = Math.min(400, left ? spaceLeft : spaceRight); } else { narrow = true; maxWidth = Math.min( 400, (rtl ? list.right : space2.right - list.left) - 30 /* Margin */ ); let spaceBelow = space2.bottom - list.bottom; if (spaceBelow >= infoHeight || spaceBelow > list.top) { offset = option.bottom - list.top; } else { side = "bottom"; offset = list.bottom - option.top; } } return { style: `${side}: ${offset}px; max-width: ${maxWidth}px`, class: "cm-completionInfo-" + (narrow ? rtl ? "left-narrow" : "right-narrow" : left ? "left" : "right") }; } function optionContent(config3) { let content = config3.addToOptions.slice(); if (config3.icons) content.push({ render(completion) { let icon = document.createElement("div"); icon.classList.add("cm-completionIcon"); if (completion.type) icon.classList.add(...completion.type.split(/\s+/g).map((cls) => "cm-completionIcon-" + cls)); icon.setAttribute("aria-hidden", "true"); return icon; }, position: 20 }); content.push({ render(completion, _s, match) { let labelElt = document.createElement("span"); labelElt.className = "cm-completionLabel"; let { label } = completion, off2 = 0; for (let j = 1; j < match.length; ) { let from = match[j++], to = match[j++]; if (from > off2) labelElt.appendChild(document.createTextNode(label.slice(off2, from))); let span = labelElt.appendChild(document.createElement("span")); span.appendChild(document.createTextNode(label.slice(from, to))); span.className = "cm-completionMatchedText"; off2 = to; } if (off2 < label.length) labelElt.appendChild(document.createTextNode(label.slice(off2))); return labelElt; }, position: 50 }, { render(completion) { if (!completion.detail) return null; let detailElt = document.createElement("span"); detailElt.className = "cm-completionDetail"; detailElt.textContent = completion.detail; return detailElt; }, position: 80 }); return content.sort((a, b) => a.position - b.position).map((a) => a.render); } function rangeAroundSelected(total, selected, max) { if (total <= max) return { from: 0, to: total }; if (selected < 0) selected = 0; if (selected <= total >> 1) { let off3 = Math.floor(selected / max); return { from: off3 * max, to: (off3 + 1) * max }; } let off2 = Math.floor((total - selected) / max); return { from: total - (off2 + 1) * max, to: total - off2 * max }; } var CompletionTooltip = class { constructor(view, stateField, applyCompletion2) { this.view = view; this.stateField = stateField; this.applyCompletion = applyCompletion2; this.info = null; this.infoDestroy = null; this.placeInfoReq = { read: () => this.measureInfo(), write: (pos) => this.placeInfo(pos), key: this }; this.space = null; this.currentClass = ""; let cState = view.state.field(stateField); let { options, selected } = cState.open; let config3 = view.state.facet(completionConfig); this.optionContent = optionContent(config3); this.optionClass = config3.optionClass; this.tooltipClass = config3.tooltipClass; this.range = rangeAroundSelected(options.length, selected, config3.maxRenderedOptions); this.dom = document.createElement("div"); this.dom.className = "cm-tooltip-autocomplete"; this.updateTooltipClass(view.state); this.dom.addEventListener("mousedown", (e) => { for (let dom = e.target, match; dom && dom != this.dom; dom = dom.parentNode) { if (dom.nodeName == "LI" && (match = /-(\d+)$/.exec(dom.id)) && +match[1] < options.length) { this.applyCompletion(view, options[+match[1]]); e.preventDefault(); return; } } }); this.dom.addEventListener("focusout", (e) => { let state = view.state.field(this.stateField, false); if (state && state.tooltip && view.state.facet(completionConfig).closeOnBlur && e.relatedTarget != view.contentDOM) view.dispatch({ effects: closeCompletionEffect.of(null) }); }); this.list = this.dom.appendChild(this.createListBox(options, cState.id, this.range)); this.list.addEventListener("scroll", () => { if (this.info) this.view.requestMeasure(this.placeInfoReq); }); } mount() { this.updateSel(); } update(update) { var _a, _b, _c; let cState = update.state.field(this.stateField); let prevState = update.startState.field(this.stateField); this.updateTooltipClass(update.state); if (cState != prevState) { this.updateSel(); if (((_a = cState.open) === null || _a === void 0 ? void 0 : _a.disabled) != ((_b = prevState.open) === null || _b === void 0 ? void 0 : _b.disabled)) this.dom.classList.toggle("cm-tooltip-autocomplete-disabled", !!((_c = cState.open) === null || _c === void 0 ? void 0 : _c.disabled)); } } updateTooltipClass(state) { let cls = this.tooltipClass(state); if (cls != this.currentClass) { for (let c of this.currentClass.split(" ")) if (c) this.dom.classList.remove(c); for (let c of cls.split(" ")) if (c) this.dom.classList.add(c); this.currentClass = cls; } } positioned(space2) { this.space = space2; if (this.info) this.view.requestMeasure(this.placeInfoReq); } updateSel() { let cState = this.view.state.field(this.stateField), open = cState.open; if (open.selected > -1 && open.selected < this.range.from || open.selected >= this.range.to) { this.range = rangeAroundSelected(open.options.length, open.selected, this.view.state.facet(completionConfig).maxRenderedOptions); this.list.remove(); this.list = this.dom.appendChild(this.createListBox(open.options, cState.id, this.range)); this.list.addEventListener("scroll", () => { if (this.info) this.view.requestMeasure(this.placeInfoReq); }); } if (this.updateSelectedOption(open.selected)) { this.destroyInfo(); let { completion } = open.options[open.selected]; let { info } = completion; if (!info) return; let infoResult = typeof info === "string" ? document.createTextNode(info) : info(completion); if (!infoResult) return; if ("then" in infoResult) { infoResult.then((obj) => { if (obj && this.view.state.field(this.stateField, false) == cState) this.addInfoPane(obj, completion); }).catch((e) => (0, import_view2.logException)(this.view.state, e, "completion info")); } else { this.addInfoPane(infoResult, completion); } } } addInfoPane(content, completion) { this.destroyInfo(); let wrap = this.info = document.createElement("div"); wrap.className = "cm-tooltip cm-completionInfo"; if (content.nodeType != null) { wrap.appendChild(content); this.infoDestroy = null; } else { let { dom, destroy } = content; wrap.appendChild(dom); this.infoDestroy = destroy || null; } this.dom.appendChild(wrap); this.view.requestMeasure(this.placeInfoReq); } updateSelectedOption(selected) { let set = null; for (let opt = this.list.firstChild, i = this.range.from; opt; opt = opt.nextSibling, i++) { if (opt.nodeName != "LI" || !opt.id) { i--; } else if (i == selected) { if (!opt.hasAttribute("aria-selected")) { opt.setAttribute("aria-selected", "true"); set = opt; } } else { if (opt.hasAttribute("aria-selected")) opt.removeAttribute("aria-selected"); } } if (set) scrollIntoView(this.list, set); return set; } measureInfo() { let sel = this.dom.querySelector("[aria-selected]"); if (!sel || !this.info) return null; let listRect = this.dom.getBoundingClientRect(); let infoRect = this.info.getBoundingClientRect(); let selRect = sel.getBoundingClientRect(); let space2 = this.space; if (!space2) { let win = this.dom.ownerDocument.defaultView || window; space2 = { left: 0, top: 0, right: win.innerWidth, bottom: win.innerHeight }; } if (selRect.top > Math.min(space2.bottom, listRect.bottom) - 10 || selRect.bottom < Math.max(space2.top, listRect.top) + 10) return null; return this.view.state.facet(completionConfig).positionInfo(this.view, listRect, selRect, infoRect, space2); } placeInfo(pos) { if (this.info) { if (pos) { if (pos.style) this.info.style.cssText = pos.style; this.info.className = "cm-tooltip cm-completionInfo " + (pos.class || ""); } else { this.info.style.cssText = "top: -1e6px"; } } } createListBox(options, id, range) { const ul = document.createElement("ul"); ul.id = id; ul.setAttribute("role", "listbox"); ul.setAttribute("aria-expanded", "true"); ul.setAttribute("aria-label", this.view.state.phrase("Completions")); let curSection = null; for (let i = range.from; i < range.to; i++) { let { completion, match } = options[i], { section } = completion; if (section) { let name = typeof section == "string" ? section : section.name; if (name != curSection && (i > range.from || range.from == 0)) { curSection = name; if (typeof section != "string" && section.header) { ul.appendChild(section.header(section)); } else { let header = ul.appendChild(document.createElement("completion-section")); header.textContent = name; } } } const li = ul.appendChild(document.createElement("li")); li.id = id + "-" + i; li.setAttribute("role", "option"); let cls = this.optionClass(completion); if (cls) li.className = cls; for (let source of this.optionContent) { let node = source(completion, this.view.state, match); if (node) li.appendChild(node); } } if (range.from) ul.classList.add("cm-completionListIncompleteTop"); if (range.to < options.length) ul.classList.add("cm-completionListIncompleteBottom"); return ul; } destroyInfo() { if (this.info) { if (this.infoDestroy) this.infoDestroy(); this.info.remove(); this.info = null; } } destroy() { this.destroyInfo(); } }; function completionTooltip(stateField, applyCompletion2) { return (view) => new CompletionTooltip(view, stateField, applyCompletion2); } function scrollIntoView(container, element) { let parent = container.getBoundingClientRect(); let self = element.getBoundingClientRect(); if (self.top < parent.top) container.scrollTop -= parent.top - self.top; else if (self.bottom > parent.bottom) container.scrollTop += self.bottom - parent.bottom; } function score(option) { return (option.boost || 0) * 100 + (option.apply ? 10 : 0) + (option.info ? 5 : 0) + (option.type ? 1 : 0); } function sortOptions(active, state) { let options = []; let sections = null; let addOption = (option) => { options.push(option); let { section } = option.completion; if (section) { if (!sections) sections = []; let name = typeof section == "string" ? section : section.name; if (!sections.some((s) => s.name == name)) sections.push(typeof section == "string" ? { name } : section); } }; for (let a of active) if (a.hasResult()) { if (a.result.filter === false) { let getMatch = a.result.getMatch; for (let option of a.result.options) { let match = [1e9 - options.length]; if (getMatch) for (let n of getMatch(option)) match.push(n); addOption(new Option(option, a.source, match, match[0])); } } else { let matcher = new FuzzyMatcher(state.sliceDoc(a.from, a.to)), match; for (let option of a.result.options) if (match = matcher.match(option.label)) { addOption(new Option(option, a.source, match, match[0] + (option.boost || 0))); } } } if (sections) { let sectionOrder = /* @__PURE__ */ Object.create(null), pos = 0; let cmp = (a, b) => { var _a, _b; return ((_a = a.rank) !== null && _a !== void 0 ? _a : 1e9) - ((_b = b.rank) !== null && _b !== void 0 ? _b : 1e9) || (a.name < b.name ? -1 : 1); }; for (let s of sections.sort(cmp)) { pos -= 1e5; sectionOrder[s.name] = pos; } for (let option of options) { let { section } = option.completion; if (section) option.score += sectionOrder[typeof section == "string" ? section : section.name]; } } let result = [], prev = null; let compare = state.facet(completionConfig).compareCompletions; for (let opt of options.sort((a, b) => b.score - a.score || compare(a.completion, b.completion))) { let cur2 = opt.completion; if (!prev || prev.label != cur2.label || prev.detail != cur2.detail || prev.type != null && cur2.type != null && prev.type != cur2.type || prev.apply != cur2.apply || prev.boost != cur2.boost) result.push(opt); else if (score(opt.completion) > score(prev)) result[result.length - 1] = opt; prev = opt.completion; } return result; } var CompletionDialog = class _CompletionDialog { constructor(options, attrs, tooltip, timestamp, selected, disabled) { this.options = options; this.attrs = attrs; this.tooltip = tooltip; this.timestamp = timestamp; this.selected = selected; this.disabled = disabled; } setSelected(selected, id) { return selected == this.selected || selected >= this.options.length ? this : new _CompletionDialog(this.options, makeAttrs(id, selected), this.tooltip, this.timestamp, selected, this.disabled); } static build(active, state, id, prev, conf) { let options = sortOptions(active, state); if (!options.length) { return prev && active.some( (a) => a.state == 1 /* Pending */ ) ? new _CompletionDialog(prev.options, prev.attrs, prev.tooltip, prev.timestamp, prev.selected, true) : null; } let selected = state.facet(completionConfig).selectOnOpen ? 0 : -1; if (prev && prev.selected != selected && prev.selected != -1) { let selectedValue = prev.options[prev.selected].completion; for (let i = 0; i < options.length; i++) if (options[i].completion == selectedValue) { selected = i; break; } } return new _CompletionDialog(options, makeAttrs(id, selected), { pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8), create: completionTooltip(completionState, applyCompletion), above: conf.aboveCursor }, prev ? prev.timestamp : Date.now(), selected, false); } map(changes) { return new _CompletionDialog(this.options, this.attrs, Object.assign(Object.assign({}, this.tooltip), { pos: changes.mapPos(this.tooltip.pos) }), this.timestamp, this.selected, this.disabled); } }; var CompletionState = class _CompletionState { constructor(active, id, open) { this.active = active; this.id = id; this.open = open; } static start() { return new _CompletionState(none, "cm-ac-" + Math.floor(Math.random() * 2e6).toString(36), null); } update(tr) { let { state } = tr, conf = state.facet(completionConfig); let sources = conf.override || state.languageDataAt("autocomplete", cur(state)).map(asSource); let active = sources.map((source) => { let value = this.active.find((s) => s.source == source) || new ActiveSource( source, this.active.some( (a) => a.state != 0 /* Inactive */ ) ? 1 : 0 /* Inactive */ ); return value.update(tr, conf); }); if (active.length == this.active.length && active.every((a, i) => a == this.active[i])) active = this.active; let open = this.open; if (open && tr.docChanged) open = open.map(tr.changes); if (tr.selection || active.some((a) => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) || !sameResults(active, this.active)) open = CompletionDialog.build(active, state, this.id, open, conf); else if (open && open.disabled && !active.some( (a) => a.state == 1 /* Pending */ )) open = null; if (!open && active.every( (a) => a.state != 1 /* Pending */ ) && active.some((a) => a.hasResult())) active = active.map((a) => a.hasResult() ? new ActiveSource( a.source, 0 /* Inactive */ ) : a); for (let effect of tr.effects) if (effect.is(setSelectedEffect)) open = open && open.setSelected(effect.value, this.id); return active == this.active && open == this.open ? this : new _CompletionState(active, this.id, open); } get tooltip() { return this.open ? this.open.tooltip : null; } get attrs() { return this.open ? this.open.attrs : baseAttrs; } }; function sameResults(a, b) { if (a == b) return true; for (let iA = 0, iB = 0; ; ) { while (iA < a.length && !a[iA].hasResult) iA++; while (iB < b.length && !b[iB].hasResult) iB++; let endA = iA == a.length, endB = iB == b.length; if (endA || endB) return endA == endB; if (a[iA++].result != b[iB++].result) return false; } } var baseAttrs = { "aria-autocomplete": "list" }; function makeAttrs(id, selected) { let result = { "aria-autocomplete": "list", "aria-haspopup": "listbox", "aria-controls": id }; if (selected > -1) result["aria-activedescendant"] = id + "-" + selected; return result; } var none = []; function getUserEvent(tr) { return tr.isUserEvent("input.type") ? "input" : tr.isUserEvent("delete.backward") ? "delete" : null; } var ActiveSource = class _ActiveSource { constructor(source, state, explicitPos = -1) { this.source = source; this.state = state; this.explicitPos = explicitPos; } hasResult() { return false; } update(tr, conf) { let event = getUserEvent(tr), value = this; if (event) value = value.handleUserEvent(tr, event, conf); else if (tr.docChanged) value = value.handleChange(tr); else if (tr.selection && value.state != 0) value = new _ActiveSource( value.source, 0 /* Inactive */ ); for (let effect of tr.effects) { if (effect.is(startCompletionEffect)) value = new _ActiveSource(value.source, 1, effect.value ? cur(tr.state) : -1); else if (effect.is(closeCompletionEffect)) value = new _ActiveSource( value.source, 0 /* Inactive */ ); else if (effect.is(setActiveEffect)) { for (let active of effect.value) if (active.source == value.source) value = active; } } return value; } handleUserEvent(tr, type, conf) { return type == "delete" || !conf.activateOnTyping ? this.map(tr.changes) : new _ActiveSource( this.source, 1 /* Pending */ ); } handleChange(tr) { return tr.changes.touchesRange(cur(tr.startState)) ? new _ActiveSource( this.source, 0 /* Inactive */ ) : this.map(tr.changes); } map(changes) { return changes.empty || this.explicitPos < 0 ? this : new _ActiveSource(this.source, this.state, changes.mapPos(this.explicitPos)); } }; var ActiveResult = class _ActiveResult extends ActiveSource { constructor(source, explicitPos, result, from, to) { super(source, 2, explicitPos); this.result = result; this.from = from; this.to = to; } hasResult() { return true; } handleUserEvent(tr, type, conf) { var _a; let from = tr.changes.mapPos(this.from), to = tr.changes.mapPos(this.to, 1); let pos = cur(tr.state); if ((this.explicitPos < 0 ? pos <= from : pos < this.from) || pos > to || type == "delete" && cur(tr.startState) == this.from) return new ActiveSource( this.source, type == "input" && conf.activateOnTyping ? 1 : 0 /* Inactive */ ); let explicitPos = this.explicitPos < 0 ? -1 : tr.changes.mapPos(this.explicitPos), updated; if (checkValid(this.result.validFor, tr.state, from, to)) return new _ActiveResult(this.source, explicitPos, this.result, from, to); if (this.result.update && (updated = this.result.update(this.result, from, to, new CompletionContext(tr.state, pos, explicitPos >= 0)))) return new _ActiveResult(this.source, explicitPos, updated, updated.from, (_a = updated.to) !== null && _a !== void 0 ? _a : cur(tr.state)); return new ActiveSource(this.source, 1, explicitPos); } handleChange(tr) { return tr.changes.touchesRange(this.from, this.to) ? new ActiveSource( this.source, 0 /* Inactive */ ) : this.map(tr.changes); } map(mapping) { return mapping.empty ? this : new _ActiveResult(this.source, this.explicitPos < 0 ? -1 : mapping.mapPos(this.explicitPos), this.result, mapping.mapPos(this.from), mapping.mapPos(this.to, 1)); } }; function checkValid(validFor, state, from, to) { if (!validFor) return false; let text = state.sliceDoc(from, to); return typeof validFor == "function" ? validFor(text, from, to, state) : ensureAnchor(validFor, true).test(text); } var setActiveEffect = /* @__PURE__ */ import_state2.StateEffect.define({ map(sources, mapping) { return sources.map((s) => s.map(mapping)); } }); var setSelectedEffect = /* @__PURE__ */ import_state2.StateEffect.define(); var completionState = /* @__PURE__ */ import_state2.StateField.define({ create() { return CompletionState.start(); }, update(value, tr) { return value.update(tr); }, provide: (f) => [ import_view2.showTooltip.from(f, (val) => val.tooltip), import_view2.EditorView.contentAttributes.from(f, (state) => state.attrs) ] }); function applyCompletion(view, option) { const apply = option.completion.apply || option.completion.label; let result = view.state.field(completionState).active.find((a) => a.source == option.source); if (!(result instanceof ActiveResult)) return false; if (typeof apply == "string") view.dispatch(Object.assign(Object.assign({}, insertCompletionText(view.state, apply, result.from, result.to)), { annotations: pickedCompletion.of(option.completion) })); else apply(view, option.completion, result.from, result.to); return true; } function moveCompletionSelection(forward, by = "option") { return (view) => { let cState = view.state.field(completionState, false); if (!cState || !cState.open || cState.open.disabled || Date.now() - cState.open.timestamp < view.state.facet(completionConfig).interactionDelay) return false; let step = 1, tooltip; if (by == "page" && (tooltip = (0, import_view2.getTooltip)(view, cState.open.tooltip))) step = Math.max(2, Math.floor(tooltip.dom.offsetHeight / tooltip.dom.querySelector("li").offsetHeight) - 1); let { length } = cState.open.options; let selected = cState.open.selected > -1 ? cState.open.selected + step * (forward ? 1 : -1) : forward ? 0 : length - 1; if (selected < 0) selected = by == "page" ? 0 : length - 1; else if (selected >= length) selected = by == "page" ? length - 1 : 0; view.dispatch({ effects: setSelectedEffect.of(selected) }); return true; }; } var acceptCompletion = (view) => { let cState = view.state.field(completionState, false); if (view.state.readOnly || !cState || !cState.open || cState.open.selected < 0 || cState.open.disabled || Date.now() - cState.open.timestamp < view.state.facet(completionConfig).interactionDelay) return false; return applyCompletion(view, cState.open.options[cState.open.selected]); }; var startCompletion = (view) => { let cState = view.state.field(completionState, false); if (!cState) return false; view.dispatch({ effects: startCompletionEffect.of(true) }); return true; }; var closeCompletion = (view) => { let cState = view.state.field(completionState, false); if (!cState || !cState.active.some( (a) => a.state != 0 /* Inactive */ )) return false; view.dispatch({ effects: closeCompletionEffect.of(null) }); return true; }; var RunningQuery = class { constructor(active, context) { this.active = active; this.context = context; this.time = Date.now(); this.updates = []; this.done = void 0; } }; var DebounceTime = 50; var MaxUpdateCount = 50; var MinAbortTime = 1e3; var completionPlugin = /* @__PURE__ */ import_view2.ViewPlugin.fromClass(class { constructor(view) { this.view = view; this.debounceUpdate = -1; this.running = []; this.debounceAccept = -1; this.composing = 0; for (let active of view.state.field(completionState).active) if (active.state == 1) this.startQuery(active); } update(update) { let cState = update.state.field(completionState); if (!update.selectionSet && !update.docChanged && update.startState.field(completionState) == cState) return; let doesReset = update.transactions.some((tr) => { return (tr.selection || tr.docChanged) && !getUserEvent(tr); }); for (let i = 0; i < this.running.length; i++) { let query = this.running[i]; if (doesReset || query.updates.length + update.transactions.length > MaxUpdateCount && Date.now() - query.time > MinAbortTime) { for (let handler of query.context.abortListeners) { try { handler(); } catch (e) { (0, import_view2.logException)(this.view.state, e); } } query.context.abortListeners = null; this.running.splice(i--, 1); } else { query.updates.push(...update.transactions); } } if (this.debounceUpdate > -1) clearTimeout(this.debounceUpdate); this.debounceUpdate = cState.active.some((a) => a.state == 1 && !this.running.some((q) => q.active.source == a.source)) ? setTimeout(() => this.startUpdate(), DebounceTime) : -1; if (this.composing != 0) for (let tr of update.transactions) { if (getUserEvent(tr) == "input") this.composing = 2; else if (this.composing == 2 && tr.selection) this.composing = 3; } } startUpdate() { this.debounceUpdate = -1; let { state } = this.view, cState = state.field(completionState); for (let active of cState.active) { if (active.state == 1 && !this.running.some((r) => r.active.source == active.source)) this.startQuery(active); } } startQuery(active) { let { state } = this.view, pos = cur(state); let context = new CompletionContext(state, pos, active.explicitPos == pos); let pending = new RunningQuery(active, context); this.running.push(pending); Promise.resolve(active.source(context)).then((result) => { if (!pending.context.aborted) { pending.done = result || null; this.scheduleAccept(); } }, (err) => { this.view.dispatch({ effects: closeCompletionEffect.of(null) }); (0, import_view2.logException)(this.view.state, err); }); } scheduleAccept() { if (this.running.every((q) => q.done !== void 0)) this.accept(); else if (this.debounceAccept < 0) this.debounceAccept = setTimeout(() => this.accept(), DebounceTime); } // For each finished query in this.running, try to create a result // or, if appropriate, restart the query. accept() { var _a; if (this.debounceAccept > -1) clearTimeout(this.debounceAccept); this.debounceAccept = -1; let updated = []; let conf = this.view.state.facet(completionConfig); for (let i = 0; i < this.running.length; i++) { let query = this.running[i]; if (query.done === void 0) continue; this.running.splice(i--, 1); if (query.done) { let active = new ActiveResult(query.active.source, query.active.explicitPos, query.done, query.done.from, (_a = query.done.to) !== null && _a !== void 0 ? _a : cur(query.updates.length ? query.updates[0].startState : this.view.state)); for (let tr of query.updates) active = active.update(tr, conf); if (active.hasResult()) { updated.push(active); continue; } } let current = this.view.state.field(completionState).active.find((a) => a.source == query.active.source); if (current && current.state == 1) { if (query.done == null) { let active = new ActiveSource( query.active.source, 0 /* Inactive */ ); for (let tr of query.updates) active = active.update(tr, conf); if (active.state != 1) updated.push(active); } else { this.startQuery(current); } } } if (updated.length) this.view.dispatch({ effects: setActiveEffect.of(updated) }); } }, { eventHandlers: { blur(event) { let state = this.view.state.field(completionState, false); if (state && state.tooltip && this.view.state.facet(completionConfig).closeOnBlur) { let dialog = state.open && (0, import_view2.getTooltip)(this.view, state.open.tooltip); if (!dialog || !dialog.dom.contains(event.relatedTarget)) this.view.dispatch({ effects: closeCompletionEffect.of(null) }); } }, compositionstart() { this.composing = 1; }, compositionend() { if (this.composing == 3) { setTimeout(() => this.view.dispatch({ effects: startCompletionEffect.of(false) }), 20); } this.composing = 0; } } }); var baseTheme = /* @__PURE__ */ import_view2.EditorView.baseTheme({ ".cm-tooltip.cm-tooltip-autocomplete": { "& > ul": { fontFamily: "monospace", whiteSpace: "nowrap", overflow: "hidden auto", maxWidth_fallback: "700px", maxWidth: "min(700px, 95vw)", minWidth: "250px", maxHeight: "10em", height: "100%", listStyle: "none", margin: 0, padding: 0, "& > li, & > completion-section": { padding: "1px 3px", lineHeight: 1.2 }, "& > li": { overflowX: "hidden", textOverflow: "ellipsis", cursor: "pointer" }, "& > completion-section": { display: "list-item", borderBottom: "1px solid silver", paddingLeft: "0.5em", opacity: 0.7 } } }, "&light .cm-tooltip-autocomplete ul li[aria-selected]": { background: "#17c", color: "white" }, "&light .cm-tooltip-autocomplete-disabled ul li[aria-selected]": { background: "#777" }, "&dark .cm-tooltip-autocomplete ul li[aria-selected]": { background: "#347", color: "white" }, "&dark .cm-tooltip-autocomplete-disabled ul li[aria-selected]": { background: "#444" }, ".cm-completionListIncompleteTop:before, .cm-completionListIncompleteBottom:after": { content: '"\xB7\xB7\xB7"', opacity: 0.5, display: "block", textAlign: "center" }, ".cm-tooltip.cm-completionInfo": { position: "absolute", padding: "3px 9px", width: "max-content", maxWidth: `${400}px`, boxSizing: "border-box" }, ".cm-completionInfo.cm-completionInfo-left": { right: "100%" }, ".cm-completionInfo.cm-completionInfo-right": { left: "100%" }, ".cm-completionInfo.cm-completionInfo-left-narrow": { right: `${30}px` }, ".cm-completionInfo.cm-completionInfo-right-narrow": { left: `${30}px` }, "&light .cm-snippetField": { backgroundColor: "#00000022" }, "&dark .cm-snippetField": { backgroundColor: "#ffffff22" }, ".cm-snippetFieldPosition": { verticalAlign: "text-top", width: 0, height: "1.15em", display: "inline-block", margin: "0 -0.7px -.7em", borderLeft: "1.4px dotted #888" }, ".cm-completionMatchedText": { textDecoration: "underline" }, ".cm-completionDetail": { marginLeft: "0.5em", fontStyle: "italic" }, ".cm-completionIcon": { fontSize: "90%", width: ".8em", display: "inline-block", textAlign: "center", paddingRight: ".6em", opacity: "0.6", boxSizing: "content-box" }, ".cm-completionIcon-function, .cm-completionIcon-method": { "&:after": { content: "'\u0192'" } }, ".cm-completionIcon-class": { "&:after": { content: "'\u25CB'" } }, ".cm-completionIcon-interface": { "&:after": { content: "'\u25CC'" } }, ".cm-completionIcon-variable": { "&:after": { content: "'\u{1D465}'" } }, ".cm-completionIcon-constant": { "&:after": { content: "'\u{1D436}'" } }, ".cm-completionIcon-type": { "&:after": { content: "'\u{1D461}'" } }, ".cm-completionIcon-enum": { "&:after": { content: "'\u222A'" } }, ".cm-completionIcon-property": { "&:after": { content: "'\u25A1'" } }, ".cm-completionIcon-keyword": { "&:after": { content: "'\u{1F511}\uFE0E'" } // Disable emoji rendering }, ".cm-completionIcon-namespace": { "&:after": { content: "'\u25A2'" } }, ".cm-completionIcon-text": { "&:after": { content: "'abc'", fontSize: "50%", verticalAlign: "middle" } } }); var defaults = { brackets: ["(", "[", "{", "'", '"'], before: ")]}:;>", stringPrefixes: [] }; var closeBracketEffect = /* @__PURE__ */ import_state2.StateEffect.define({ map(value, mapping) { let mapped = mapping.mapPos(value, -1, import_state2.MapMode.TrackAfter); return mapped == null ? void 0 : mapped; } }); var closedBracket = /* @__PURE__ */ new class extends import_state2.RangeValue { }(); closedBracket.startSide = 1; closedBracket.endSide = -1; var bracketState = /* @__PURE__ */ import_state2.StateField.define({ create() { return import_state2.RangeSet.empty; }, update(value, tr) { if (tr.selection) { let lineStart = tr.state.doc.lineAt(tr.selection.main.head).from; let prevLineStart = tr.startState.doc.lineAt(tr.startState.selection.main.head).from; if (lineStart != tr.changes.mapPos(prevLineStart, -1)) value = import_state2.RangeSet.empty; } value = value.map(tr.changes); for (let effect of tr.effects) if (effect.is(closeBracketEffect)) value = value.update({ add: [closedBracket.range(effect.value, effect.value + 1)] }); return value; } }); function closeBrackets() { return [inputHandler, bracketState]; } var definedClosing = "()[]{}<>"; function closing(ch) { for (let i = 0; i < definedClosing.length; i += 2) if (definedClosing.charCodeAt(i) == ch) return definedClosing.charAt(i + 1); return (0, import_state2.fromCodePoint)(ch < 128 ? ch : ch + 1); } function config(state, pos) { return state.languageDataAt("closeBrackets", pos)[0] || defaults; } var android = typeof navigator == "object" && /* @__PURE__ */ /Android\b/.test(navigator.userAgent); var inputHandler = /* @__PURE__ */ import_view2.EditorView.inputHandler.of((view, from, to, insert) => { if ((android ? view.composing : view.compositionStarted) || view.state.readOnly) return false; let sel = view.state.selection.main; if (insert.length > 2 || insert.length == 2 && (0, import_state2.codePointSize)((0, import_state2.codePointAt)(insert, 0)) == 1 || from != sel.from || to != sel.to) return false; let tr = insertBracket(view.state, insert); if (!tr) return false; view.dispatch(tr); return true; }); var deleteBracketPair = ({ state, dispatch }) => { if (state.readOnly) return false; let conf = config(state, state.selection.main.head); let tokens = conf.brackets || defaults.brackets; let dont = null, changes = state.changeByRange((range) => { if (range.empty) { let before = prevChar(state.doc, range.head); for (let token of tokens) { if (token == before && nextChar(state.doc, range.head) == closing((0, import_state2.codePointAt)(token, 0))) return { changes: { from: range.head - token.length, to: range.head + token.length }, range: import_state2.EditorSelection.cursor(range.head - token.length) }; } } return { range: dont = range }; }); if (!dont) dispatch(state.update(changes, { scrollIntoView: true, userEvent: "delete.backward" })); return !dont; }; var closeBracketsKeymap = [ { key: "Backspace", run: deleteBracketPair } ]; function insertBracket(state, bracket) { let conf = config(state, state.selection.main.head); let tokens = conf.brackets || defaults.brackets; for (let tok of tokens) { let closed = closing((0, import_state2.codePointAt)(tok, 0)); if (bracket == tok) return closed == tok ? handleSame(state, tok, tokens.indexOf(tok + tok + tok) > -1, conf) : handleOpen(state, tok, closed, conf.before || defaults.before); if (bracket == closed && closedBracketAt(state, state.selection.main.from)) return handleClose(state, tok, closed); } return null; } function closedBracketAt(state, pos) { let found = false; state.field(bracketState).between(0, state.doc.length, (from) => { if (from == pos) found = true; }); return found; } function nextChar(doc, pos) { let next = doc.sliceString(pos, pos + 2); return next.slice(0, (0, import_state2.codePointSize)((0, import_state2.codePointAt)(next, 0))); } function prevChar(doc, pos) { let prev = doc.sliceString(pos - 2, pos); return (0, import_state2.codePointSize)((0, import_state2.codePointAt)(prev, 0)) == prev.length ? prev : prev.slice(1); } function handleOpen(state, open, close, closeBefore) { let dont = null, changes = state.changeByRange((range) => { if (!range.empty) return { changes: [{ insert: open, from: range.from }, { insert: close, from: range.to }], effects: closeBracketEffect.of(range.to + open.length), range: import_state2.EditorSelection.range(range.anchor + open.length, range.head + open.length) }; let next = nextChar(state.doc, range.head); if (!next || /\s/.test(next) || closeBefore.indexOf(next) > -1) return { changes: { insert: open + close, from: range.head }, effects: closeBracketEffect.of(range.head + open.length), range: import_state2.EditorSelection.cursor(range.head + open.length) }; return { range: dont = range }; }); return dont ? null : state.update(changes, { scrollIntoView: true, userEvent: "input.type" }); } function handleClose(state, _open, close) { let dont = null, changes = state.changeByRange((range) => { if (range.empty && nextChar(state.doc, range.head) == close) return { changes: { from: range.head, to: range.head + close.length, insert: close }, range: import_state2.EditorSelection.cursor(range.head + close.length) }; return dont = { range }; }); return dont ? null : state.update(changes, { scrollIntoView: true, userEvent: "input.type" }); } function handleSame(state, token, allowTriple, config3) { let stringPrefixes = config3.stringPrefixes || defaults.stringPrefixes; let dont = null, changes = state.changeByRange((range) => { if (!range.empty) return { changes: [{ insert: token, from: range.from }, { insert: token, from: range.to }], effects: closeBracketEffect.of(range.to + token.length), range: import_state2.EditorSelection.range(range.anchor + token.length, range.head + token.length) }; let pos = range.head, next = nextChar(state.doc, pos), start; if (next == token) { if (nodeStart(state, pos)) { return { changes: { insert: token + token, from: pos }, effects: closeBracketEffect.of(pos + token.length), range: import_state2.EditorSelection.cursor(pos + token.length) }; } else if (closedBracketAt(state, pos)) { let isTriple = allowTriple && state.sliceDoc(pos, pos + token.length * 3) == token + token + token; let content = isTriple ? token + token + token : token; return { changes: { from: pos, to: pos + content.length, insert: content }, range: import_state2.EditorSelection.cursor(pos + content.length) }; } } else if (allowTriple && state.sliceDoc(pos - 2 * token.length, pos) == token + token && (start = canStartStringAt(state, pos - 2 * token.length, stringPrefixes)) > -1 && nodeStart(state, start)) { return { changes: { insert: token + token + token + token, from: pos }, effects: closeBracketEffect.of(pos + token.length), range: import_state2.EditorSelection.cursor(pos + token.length) }; } else if (state.charCategorizer(pos)(next) != import_state2.CharCategory.Word) { if (canStartStringAt(state, pos, stringPrefixes) > -1 && !probablyInString(state, pos, token, stringPrefixes)) return { changes: { insert: token + token, from: pos }, effects: closeBracketEffect.of(pos + token.length), range: import_state2.EditorSelection.cursor(pos + token.length) }; } return { range: dont = range }; }); return dont ? null : state.update(changes, { scrollIntoView: true, userEvent: "input.type" }); } function nodeStart(state, pos) { let tree = (0, import_language2.syntaxTree)(state).resolveInner(pos + 1); return tree.parent && tree.from == pos; } function probablyInString(state, pos, quoteToken, prefixes) { let node = (0, import_language2.syntaxTree)(state).resolveInner(pos, -1); let maxPrefix = prefixes.reduce((m, p) => Math.max(m, p.length), 0); for (let i = 0; i < 5; i++) { let start = state.sliceDoc(node.from, Math.min(node.to, node.from + quoteToken.length + maxPrefix)); let quotePos = start.indexOf(quoteToken); if (!quotePos || quotePos > -1 && prefixes.indexOf(start.slice(0, quotePos)) > -1) { let first = node.firstChild; while (first && first.from == node.from && first.to - first.from > quoteToken.length + quotePos) { if (state.sliceDoc(first.to - quoteToken.length, first.to) == quoteToken) return false; first = first.firstChild; } return true; } let parent = node.to == pos && node.parent; if (!parent) break; node = parent; } return false; } function canStartStringAt(state, pos, prefixes) { let charCat = state.charCategorizer(pos); if (charCat(state.sliceDoc(pos - 1, pos)) != import_state2.CharCategory.Word) return pos; for (let prefix of prefixes) { let start = pos - prefix.length; if (state.sliceDoc(start, pos) == prefix && charCat(state.sliceDoc(start - 1, start)) != import_state2.CharCategory.Word) return start; } return -1; } function autocompletion(config3 = {}) { return [ completionState, completionConfig.of(config3), completionPlugin, completionKeymapExt, baseTheme ]; } var completionKeymap = [ { key: "Ctrl-Space", run: startCompletion }, { key: "Escape", run: closeCompletion }, { key: "ArrowDown", run: /* @__PURE__ */ moveCompletionSelection(true) }, { key: "ArrowUp", run: /* @__PURE__ */ moveCompletionSelection(false) }, { key: "PageDown", run: /* @__PURE__ */ moveCompletionSelection(true, "page") }, { key: "PageUp", run: /* @__PURE__ */ moveCompletionSelection(false, "page") }, { key: "Enter", run: acceptCompletion } ]; var completionKeymapExt = /* @__PURE__ */ import_state2.Prec.highest(/* @__PURE__ */ import_view2.keymap.computeN([completionConfig], (state) => state.facet(completionConfig).defaultKeymap ? [completionKeymap] : [])); // src/codemirror-extensions/basic-extensions.ts var import_search2 = require("@codemirror/search"); var import_lint = require("@codemirror/lint"); // src/codemirror-extensions/obsidian-theme.ts var import_view3 = require("@codemirror/view"); var import_language3 = require("@codemirror/language"); var import_highlight = require("@lezer/highlight"); var config2 = { name: "obsidian", dark: false, background: "var(--background-primary)", foreground: "var(--text-normal)", selection: "var(--text-selection)", cursor: "var(--text-normal)", dropdownBackground: "var(--background-primary)", dropdownBorder: "var(--background-modifier-border)", activeLine: "var(--background-secondary)", activeLineNumber: "var(--text-normal)", matchingBracket: "var(--background-modifier-accent)", keyword: "#d73a49", storage: "#d73a49", variable: "var(--text-normal)", parameter: "var(--text-accent-hover)", function: "var(--text-accent-hover)", string: "var(--text-accent)", constant: "var(--text-accent-hover)", type: "var(--text-accent-hover)", class: "#6f42c1", number: "var(--text-accent-hover)", comment: "var(--text-faint)", invalid: "var(--text-error)", regexp: "#032f62", monospace: "var(--font-monospace)" }; var obsidianTheme = import_view3.EditorView.theme( { "&": { color: config2.foreground, backgroundColor: config2.background }, ".cm-scroller": { fontFamily: config2.monospace }, ".cm-content": { caretColor: config2.cursor }, "&.cm-focused .cm-cursor": { borderLeftColor: config2.cursor }, ".cm-selectionBackground, &.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, & ::selection": { backgroundColor: config2.selection }, ".cm-panels": { backgroundColor: config2.dropdownBackground, color: config2.foreground }, ".cm-panels.cm-panels-top": { borderBottom: "2px solid black" }, ".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" }, ".cm-searchMatch": { backgroundColor: config2.dropdownBackground, outline: `1px solid ${config2.dropdownBorder}` }, ".cm-searchMatch.cm-searchMatch-selected": { backgroundColor: config2.selection }, ".cm-activeLine": { backgroundColor: config2.activeLine }, ".cm-activeLineGutter": { backgroundColor: config2.activeLine, ".cm-lineNumbers &": { color: config2.activeLineNumber } }, ".cm-selectionMatch": { backgroundColor: config2.selection }, ".cm-matchingBracket, .cm-nonmatchingBracket": { backgroundColor: config2.matchingBracket, outline: "none" }, ".cm-gutters": { backgroundColor: config2.background, color: config2.comment, borderRight: "1px solid var(--background-modifier-border)" }, ".cm-lineNumbers, .cm-gutterElement": { color: "inherit" }, ".cm-foldPlaceholder": { backgroundColor: "transparent", border: "none", color: config2.foreground }, ".cm-tooltip": { border: `1px solid ${config2.dropdownBorder}`, backgroundColor: config2.dropdownBackground, color: config2.foreground }, ".cm-tooltip.cm-tooltip-autocomplete": { "& > ul": { fontFamily: config2.monospace, "& > li[aria-selected]": { background: config2.selection, color: config2.foreground } } } }, { dark: config2.dark } ); var obsidianHighlightStyle = import_language3.HighlightStyle.define([ { tag: import_highlight.tags.keyword, color: config2.keyword }, { tag: [import_highlight.tags.name, import_highlight.tags.deleted, import_highlight.tags.character, import_highlight.tags.macroName], color: config2.variable }, { tag: [import_highlight.tags.propertyName], color: config2.function }, { tag: [ import_highlight.tags.processingInstruction, import_highlight.tags.string, import_highlight.tags.inserted, import_highlight.tags.special(import_highlight.tags.string) ], color: config2.string }, { tag: [import_highlight.tags.function(import_highlight.tags.variableName), import_highlight.tags.labelName], color: config2.function }, { tag: [import_highlight.tags.color, import_highlight.tags.constant(import_highlight.tags.name), import_highlight.tags.standard(import_highlight.tags.name)], color: config2.constant }, { tag: [import_highlight.tags.definition(import_highlight.tags.name), import_highlight.tags.separator], color: config2.variable }, { tag: [import_highlight.tags.className], color: config2.class }, { tag: [ import_highlight.tags.number, import_highlight.tags.changed, import_highlight.tags.annotation, import_highlight.tags.modifier, import_highlight.tags.self, import_highlight.tags.namespace ], color: config2.number }, { tag: [import_highlight.tags.typeName], color: config2.type, fontStyle: config2.type }, { tag: [import_highlight.tags.operator, import_highlight.tags.operatorKeyword], color: config2.keyword }, { tag: [import_highlight.tags.url, import_highlight.tags.escape, import_highlight.tags.regexp, import_highlight.tags.link], color: config2.regexp }, { tag: [import_highlight.tags.meta, import_highlight.tags.comment], color: config2.comment }, { tag: [import_highlight.tags.atom, import_highlight.tags.bool, import_highlight.tags.special(import_highlight.tags.variableName)], color: config2.variable }, { tag: import_highlight.tags.invalid, color: config2.invalid } ]); var obsidian = [ obsidianTheme, (0, import_language3.syntaxHighlighting)(obsidianHighlightStyle) ]; // node_modules/@lezer/css/dist/index.es.js var import_lr = require("@lezer/lr"); var import_highlight2 = require("@lezer/highlight"); var descendantOp = 94; var Unit = 1; var callee = 95; var identifier = 96; var VariableName = 2; var space = [ 9, 10, 11, 12, 13, 32, 133, 160, 5760, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8232, 8233, 8239, 8287, 12288 ]; var colon = 58; var parenL = 40; var underscore = 95; var bracketL = 91; var dash = 45; var period = 46; var hash = 35; var percent = 37; function isAlpha(ch) { return ch >= 65 && ch <= 90 || ch >= 97 && ch <= 122 || ch >= 161; } function isDigit(ch) { return ch >= 48 && ch <= 57; } var identifiers = new import_lr.ExternalTokenizer((input, stack) => { for (let inside = false, dashes = 0, i = 0; ; i++) { let { next } = input; if (isAlpha(next) || next == dash || next == underscore || inside && isDigit(next)) { if (!inside && (next != dash || i > 0)) inside = true; if (dashes === i && next == dash) dashes++; input.advance(); } else { if (inside) input.acceptToken(next == parenL ? callee : dashes == 2 && stack.canShift(VariableName) ? VariableName : identifier); break; } } }); var descendant = new import_lr.ExternalTokenizer((input) => { if (space.includes(input.peek(-1))) { let { next } = input; if (isAlpha(next) || next == underscore || next == hash || next == period || next == bracketL || next == colon || next == dash) input.acceptToken(descendantOp); } }); var unitToken = new import_lr.ExternalTokenizer((input) => { if (!space.includes(input.peek(-1))) { let { next } = input; if (next == percent) { input.advance(); input.acceptToken(Unit); } if (isAlpha(next)) { do { input.advance(); } while (isAlpha(input.next)); input.acceptToken(Unit); } } }); var cssHighlighting = (0, import_highlight2.styleTags)({ "AtKeyword import charset namespace keyframes media supports": import_highlight2.tags.definitionKeyword, "from to selector": import_highlight2.tags.keyword, NamespaceName: import_highlight2.tags.namespace, KeyframeName: import_highlight2.tags.labelName, TagName: import_highlight2.tags.tagName, ClassName: import_highlight2.tags.className, PseudoClassName: import_highlight2.tags.constant(import_highlight2.tags.className), IdName: import_highlight2.tags.labelName, "FeatureName PropertyName": import_highlight2.tags.propertyName, AttributeName: import_highlight2.tags.attributeName, NumberLiteral: import_highlight2.tags.number, KeywordQuery: import_highlight2.tags.keyword, UnaryQueryOp: import_highlight2.tags.operatorKeyword, "CallTag ValueName": import_highlight2.tags.atom, VariableName: import_highlight2.tags.variableName, Callee: import_highlight2.tags.operatorKeyword, Unit: import_highlight2.tags.unit, "UniversalSelector NestingSelector": import_highlight2.tags.definitionOperator, MatchOp: import_highlight2.tags.compareOperator, "ChildOp SiblingOp, LogicOp": import_highlight2.tags.logicOperator, BinOp: import_highlight2.tags.arithmeticOperator, Important: import_highlight2.tags.modifier, Comment: import_highlight2.tags.blockComment, ParenthesizedContent: import_highlight2.tags.special(import_highlight2.tags.name), ColorLiteral: import_highlight2.tags.color, StringLiteral: import_highlight2.tags.string, ":": import_highlight2.tags.punctuation, "PseudoOp #": import_highlight2.tags.derefOperator, "; ,": import_highlight2.tags.separator, "( )": import_highlight2.tags.paren, "[ ]": import_highlight2.tags.squareBracket, "{ }": import_highlight2.tags.brace }); var spec_callee = { __proto__: null, lang: 32, "nth-child": 32, "nth-last-child": 32, "nth-of-type": 32, "nth-last-of-type": 32, dir: 32, "host-context": 32, url: 60, "url-prefix": 60, domain: 60, regexp: 60, selector: 134 }; var spec_AtKeyword = { __proto__: null, "@import": 114, "@media": 138, "@charset": 142, "@namespace": 146, "@keyframes": 152, "@supports": 164 }; var spec_identifier = { __proto__: null, not: 128, only: 128, from: 158, to: 160 }; var parser = import_lr.LRParser.deserialize({ version: 14, states: "7WQYQ[OOO#_Q[OOOOQP'#Cd'#CdOOQP'#Cc'#CcO#fQ[O'#CfO$YQXO'#CaO$aQ[O'#ChO$lQ[O'#DPO$qQ[O'#DTOOQP'#Ed'#EdO$vQdO'#DeO%bQ[O'#DrO$vQdO'#DtO%sQ[O'#DvO&OQ[O'#DyO&TQ[O'#EPO&cQ[O'#EROOQS'#Ec'#EcOOQS'#ET'#ETQYQ[OOO&jQXO'#CdO'_QWO'#DaO'dQWO'#EjO'oQ[O'#EjQOQWOOOOQP'#Cg'#CgOOQP,59Q,59QO#fQ[O,59QO'yQ[O'#EWO(eQWO,58{O(mQ[O,59SO$lQ[O,59kO$qQ[O,59oO'yQ[O,59sO'yQ[O,59uO'yQ[O,59vO(xQ[O'#D`OOQS,58{,58{OOQP'#Ck'#CkOOQO'#C}'#C}OOQP,59S,59SO)PQWO,59SO)UQWO,59SOOQP'#DR'#DROOQP,59k,59kOOQO'#DV'#DVO)ZQ`O,59oOOQS'#Cp'#CpO$vQdO'#CqO)cQvO'#CsO*pQtO,5:POOQO'#Cx'#CxO)UQWO'#CwO+UQWO'#CyOOQS'#Eg'#EgOOQO'#Dh'#DhO+ZQ[O'#DoO+iQWO'#EkO&TQ[O'#DmO+wQWO'#DpOOQO'#El'#ElO(hQWO,5:^O+|QpO,5:`OOQS'#Dx'#DxO,UQWO,5:bO,ZQ[O,5:bOOQO'#D{'#D{O,cQWO,5:eO,hQWO,5:kO,pQWO,5:mOOQS-E8R-E8RO$vQdO,59{O,xQ[O'#EYO-VQWO,5;UO-VQWO,5;UOOQP1G.l1G.lO-|QXO,5:rOOQO-E8U-E8UOOQS1G.g1G.gOOQP1G.n1G.nO)PQWO1G.nO)UQWO1G.nOOQP1G/V1G/VO.ZQ`O1G/ZO.tQXO1G/_O/[QXO1G/aO/rQXO1G/bO0YQWO,59zO0_Q[O'#DOO0fQdO'#CoOOQP1G/Z1G/ZO$vQdO1G/ZO0mQpO,59]OOQS,59_,59_O$vQdO,59aO0uQWO1G/kOOQS,59c,59cO0zQ!bO,59eO1SQWO'#DhO1_QWO,5:TO1dQWO,5:ZO&TQ[O,5:VO&TQ[O'#EZO1lQWO,5;VO1wQWO,5:XO'yQ[O,5:[OOQS1G/x1G/xOOQS1G/z1G/zOOQS1G/|1G/|O2YQWO1G/|O2_QdO'#D|OOQS1G0P1G0POOQS1G0V1G0VOOQS1G0X1G0XO2mQtO1G/gOOQO,5:t,5:tO3TQ[O,5:tOOQO-E8W-E8WO3bQWO1G0pOOQP7+$Y7+$YOOQP7+$u7+$uO$vQdO7+$uOOQS1G/f1G/fO3mQXO'#EiO3tQWO,59jO3yQtO'#EUO4nQdO'#EfO4xQWO,59ZO4}QpO7+$uOOQS1G.w1G.wOOQS1G.{1G.{OOQS7+%V7+%VO5VQWO1G/PO$vQdO1G/oOOQO1G/u1G/uOOQO1G/q1G/qO5[QWO,5:uOOQO-E8X-E8XO5jQXO1G/vOOQS7+%h7+%hO5qQYO'#CsO(hQWO'#E[O5yQdO,5:hOOQS,5:h,5:hO6XQtO'#EXO$vQdO'#EXO7VQdO7+%ROOQO7+%R7+%ROOQO1G0`1G0`O7jQpO<T![;'S%^;'S;=`%o<%lO%^^;TUoWOy%^z!Q%^!Q![;g![;'S%^;'S;=`%o<%lO%^^;nYoW#[UOy%^z!Q%^!Q![;g![!g%^!g!h<^!h#X%^#X#Y<^#Y;'S%^;'S;=`%o<%lO%^^[[oW#[UOy%^z!O%^!O!P;g!P!Q%^!Q![>T![!g%^!g!h<^!h#X%^#X#Y<^#Y;'S%^;'S;=`%o<%lO%^_?VSpVOy%^z;'S%^;'S;=`%o<%lO%^^?hWjSOy%^z!O%^!O!P;O!P!Q%^!Q![>T![;'S%^;'S;=`%o<%lO%^_@VU#XPOy%^z!Q%^!Q![;g![;'S%^;'S;=`%o<%lO%^~@nTjSOy%^z{@}{;'S%^;'S;=`%o<%lO%^~ASUoWOy@}yzAfz{Bm{;'S@};'S;=`Co<%lO@}~AiTOzAfz{Ax{;'SAf;'S;=`Bg<%lOAf~A{VOzAfz{Ax{!PAf!P!QBb!Q;'SAf;'S;=`Bg<%lOAf~BgOR~~BjP;=`<%lAf~BrWoWOy@}yzAfz{Bm{!P@}!P!QC[!Q;'S@};'S;=`Co<%lO@}~CcSoWR~Oy%^z;'S%^;'S;=`%o<%lO%^~CrP;=`<%l@}^Cz[#[UOy%^z!O%^!O!P;g!P!Q%^!Q![>T![!g%^!g!h<^!h#X%^#X#Y<^#Y;'S%^;'S;=`%o<%lO%^XDuU]POy%^z![%^![!]EX!];'S%^;'S;=`%o<%lO%^XE`S^PoWOy%^z;'S%^;'S;=`%o<%lO%^_EqS!WVOy%^z;'S%^;'S;=`%o<%lO%^YFSSzQOy%^z;'S%^;'S;=`%o<%lO%^XFeU|POy%^z!`%^!`!aFw!a;'S%^;'S;=`%o<%lO%^XGOS|PoWOy%^z;'S%^;'S;=`%o<%lO%^XG_WOy%^z!c%^!c!}Gw!}#T%^#T#oGw#o;'S%^;'S;=`%o<%lO%^XHO[!YPoWOy%^z}%^}!OGw!O!Q%^!Q![Gw![!c%^!c!}Gw!}#T%^#T#oGw#o;'S%^;'S;=`%o<%lO%^XHySxPOy%^z;'S%^;'S;=`%o<%lO%^^I[SvUOy%^z;'S%^;'S;=`%o<%lO%^XIkUOy%^z#b%^#b#cI}#c;'S%^;'S;=`%o<%lO%^XJSUoWOy%^z#W%^#W#XJf#X;'S%^;'S;=`%o<%lO%^XJmS!`PoWOy%^z;'S%^;'S;=`%o<%lO%^XJ|UOy%^z#f%^#f#gJf#g;'S%^;'S;=`%o<%lO%^XKeS!RPOy%^z;'S%^;'S;=`%o<%lO%^_KvS!QVOy%^z;'S%^;'S;=`%o<%lO%^ZLXU!PPOy%^z!_%^!_!`6y!`;'S%^;'S;=`%o<%lO%^WLnP;=`<%l$}", tokenizers: [descendant, unitToken, identifiers, 0, 1, 2, 3], topRules: { "StyleSheet": [0, 4], "Styles": [1, 84] }, specialized: [{ term: 95, get: (value) => spec_callee[value] || -1 }, { term: 56, get: (value) => spec_AtKeyword[value] || -1 }, { term: 96, get: (value) => spec_identifier[value] || -1 }], tokenPrec: 1123 }); // node_modules/@codemirror/lang-css/dist/index.js var import_language4 = require("@codemirror/language"); var import_common = require("@lezer/common"); var _properties = null; function properties() { if (!_properties && typeof document == "object" && document.body) { let { style } = document.body, names = [], seen = /* @__PURE__ */ new Set(); for (let prop in style) if (prop != "cssText" && prop != "cssFloat") { if (typeof style[prop] == "string") { if (/[A-Z]/.test(prop)) prop = prop.replace(/[A-Z]/g, (ch) => "-" + ch.toLowerCase()); if (!seen.has(prop)) { names.push(prop); seen.add(prop); } } } _properties = names.sort().map((name) => ({ type: "property", label: name })); } return _properties || []; } var pseudoClasses = /* @__PURE__ */ [ "active", "after", "any-link", "autofill", "backdrop", "before", "checked", "cue", "default", "defined", "disabled", "empty", "enabled", "file-selector-button", "first", "first-child", "first-letter", "first-line", "first-of-type", "focus", "focus-visible", "focus-within", "fullscreen", "has", "host", "host-context", "hover", "in-range", "indeterminate", "invalid", "is", "lang", "last-child", "last-of-type", "left", "link", "marker", "modal", "not", "nth-child", "nth-last-child", "nth-last-of-type", "nth-of-type", "only-child", "only-of-type", "optional", "out-of-range", "part", "placeholder", "placeholder-shown", "read-only", "read-write", "required", "right", "root", "scope", "selection", "slotted", "target", "target-text", "valid", "visited", "where" ].map((name) => ({ type: "class", label: name })); var values = /* @__PURE__ */ [ "above", "absolute", "activeborder", "additive", "activecaption", "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate", "always", "antialiased", "appworkspace", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page", "avoid-region", "axis-pan", "background", "backwards", "baseline", "below", "bidi-override", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel", "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", "cell", "center", "checkbox", "circle", "cjk-decimal", "clear", "clip", "close-quote", "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse", "compact", "condensed", "contain", "content", "contents", "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop", "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal", "decimal-leading-zero", "default", "default-button", "dense", "destination-atop", "destination-in", "destination-out", "destination-over", "difference", "disc", "discard", "disclosure-closed", "disclosure-open", "document", "dot-dash", "dot-dot-dash", "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", "element", "ellipse", "ellipsis", "embed", "end", "ethiopic-abegede-gez", "ethiopic-halehame-aa-er", "ethiopic-halehame-gez", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed", "extra-expanded", "fantasy", "fast", "fill", "fill-box", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes", "forwards", "from", "geometricPrecision", "graytext", "grid", "groove", "hand", "hard-light", "help", "hidden", "hide", "higher", "highlight", "highlighttext", "horizontal", "hsl", "hsla", "hue", "icon", "ignore", "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis", "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert", "italic", "justify", "keep-all", "landscape", "large", "larger", "left", "level", "lighter", "lighten", "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem", "local", "logical", "loud", "lower", "lower-hexadecimal", "lower-latin", "lower-norwegian", "lowercase", "ltr", "luminosity", "manipulation", "match", "matrix", "matrix3d", "medium", "menu", "menutext", "message-box", "middle", "min-intrinsic", "mix", "monospace", "move", "multiple", "multiple_mask_images", "multiply", "n-resize", "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "opacity", "open-quote", "optimizeLegibility", "optimizeSpeed", "outset", "outside", "outside-shape", "overlay", "overline", "padding", "padding-box", "painted", "page", "paused", "perspective", "pinch-zoom", "plus-darker", "plus-lighter", "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button", "radial-gradient", "radio", "read-only", "read-write", "read-write-plaintext-only", "rectangle", "region", "relative", "repeat", "repeating-linear-gradient", "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY", "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running", "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen", "scroll", "scrollbar", "scroll-position", "se-resize", "self-start", "self-end", "semi-condensed", "semi-expanded", "separate", "serif", "show", "single", "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal", "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square", "start", "static", "status-bar", "stretch", "stroke", "stroke-box", "sub", "subpixel-antialiased", "svg_masks", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table", "table-caption", "table-cell", "table-column", "table-column-group", "table-footer-group", "table-header-group", "table-row", "table-row-group", "text", "text-bottom", "text-top", "textarea", "textfield", "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight", "threedlightshadow", "threedshadow", "to", "top", "transform", "translate", "translate3d", "translateX", "translateY", "translateZ", "transparent", "ultra-condensed", "ultra-expanded", "underline", "unidirectional-pan", "unset", "up", "upper-latin", "uppercase", "url", "var", "vertical", "vertical-text", "view-box", "visible", "visibleFill", "visiblePainted", "visibleStroke", "visual", "w-resize", "wait", "wave", "wider", "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor", "xx-large", "xx-small" ].map((name) => ({ type: "keyword", label: name })).concat(/* @__PURE__ */ [ "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen" ].map((name) => ({ type: "constant", label: name }))); var tags2 = /* @__PURE__ */ [ "a", "abbr", "address", "article", "aside", "b", "bdi", "bdo", "blockquote", "body", "br", "button", "canvas", "caption", "cite", "code", "col", "colgroup", "dd", "del", "details", "dfn", "dialog", "div", "dl", "dt", "em", "figcaption", "figure", "footer", "form", "header", "hgroup", "h1", "h2", "h3", "h4", "h5", "h6", "hr", "html", "i", "iframe", "img", "input", "ins", "kbd", "label", "legend", "li", "main", "meter", "nav", "ol", "output", "p", "pre", "ruby", "section", "select", "small", "source", "span", "strong", "sub", "summary", "sup", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "tr", "u", "ul" ].map((name) => ({ type: "type", label: name })); var identifier2 = /^(\w[\w-]*|-\w[\w-]*|)$/; var variable = /^-(-[\w-]*)?$/; function isVarArg(node, doc) { var _a; if (node.name == "(" || node.type.isError) node = node.parent || node; if (node.name != "ArgList") return false; let callee2 = (_a = node.parent) === null || _a === void 0 ? void 0 : _a.firstChild; if ((callee2 === null || callee2 === void 0 ? void 0 : callee2.name) != "Callee") return false; return doc.sliceString(callee2.from, callee2.to) == "var"; } var VariablesByNode = /* @__PURE__ */ new import_common.NodeWeakMap(); var declSelector = ["Declaration"]; function astTop(node) { for (let cur2 = node; ; ) { if (cur2.type.isTop) return cur2; if (!(cur2 = cur2.parent)) return node; } } function variableNames(doc, node, isVariable) { if (node.to - node.from > 4096) { let known = VariablesByNode.get(node); if (known) return known; let result = [], seen = /* @__PURE__ */ new Set(), cursor = node.cursor(import_common.IterMode.IncludeAnonymous); if (cursor.firstChild()) do { for (let option of variableNames(doc, cursor.node, isVariable)) if (!seen.has(option.label)) { seen.add(option.label); result.push(option); } } while (cursor.nextSibling()); VariablesByNode.set(node, result); return result; } else { let result = [], seen = /* @__PURE__ */ new Set(); node.cursor().iterate((node2) => { var _a; if (isVariable(node2) && node2.matchContext(declSelector) && ((_a = node2.node.nextSibling) === null || _a === void 0 ? void 0 : _a.name) == ":") { let name = doc.sliceString(node2.from, node2.to); if (!seen.has(name)) { seen.add(name); result.push({ label: name, type: "variable" }); } } }); return result; } } var defineCSSCompletionSource = (isVariable) => (context) => { let { state, pos } = context, node = (0, import_language4.syntaxTree)(state).resolveInner(pos, -1); let isDash = node.type.isError && node.from == node.to - 1 && state.doc.sliceString(node.from, node.to) == "-"; if (node.name == "PropertyName" || (isDash || node.name == "TagName") && /^(Block|Styles)$/.test(node.resolve(node.to).name)) return { from: node.from, options: properties(), validFor: identifier2 }; if (node.name == "ValueName") return { from: node.from, options: values, validFor: identifier2 }; if (node.name == "PseudoClassName") return { from: node.from, options: pseudoClasses, validFor: identifier2 }; if (isVariable(node) || (context.explicit || isDash) && isVarArg(node, state.doc)) return { from: isVariable(node) || isDash ? node.from : pos, options: variableNames(state.doc, astTop(node), isVariable), validFor: variable }; if (node.name == "TagName") { for (let { parent } = node; parent; parent = parent.parent) if (parent.name == "Block") return { from: node.from, options: properties(), validFor: identifier2 }; return { from: node.from, options: tags2, validFor: identifier2 }; } if (!context.explicit) return null; let above = node.resolve(pos), before = above.childBefore(pos); if (before && before.name == ":" && above.name == "PseudoClassSelector") return { from: pos, options: pseudoClasses, validFor: identifier2 }; if (before && before.name == ":" && above.name == "Declaration" || above.name == "ArgList") return { from: pos, options: values, validFor: identifier2 }; if (above.name == "Block" || above.name == "Styles") return { from: pos, options: properties(), validFor: identifier2 }; return null; }; var cssLanguage = /* @__PURE__ */ import_language4.LRLanguage.define({ name: "css", parser: /* @__PURE__ */ parser.configure({ props: [ /* @__PURE__ */ import_language4.indentNodeProp.add({ Declaration: /* @__PURE__ */ (0, import_language4.continuedIndent)() }), /* @__PURE__ */ import_language4.foldNodeProp.add({ Block: import_language4.foldInside }) ] }), languageData: { commentTokens: { block: { open: "/*", close: "*/" } }, indentOnInput: /^\s*\}$/, wordChars: "-" } }); // src/codemirror-extensions/reconfigured-css.ts var import_language5 = require("@codemirror/language"); var import_common2 = require("@lezer/common"); var ClassSelectorCtx = ["ClassSelector"]; var IdSelectorCtx = ["IdSelector"]; var SelectorsByNode = { ["class" /* CLASS */]: new import_common2.NodeWeakMap(), ["id" /* ID */]: new import_common2.NodeWeakMap() }; var Identifier = /^(\w[\w-]*|-\w[\w-]*|)$/; function getASTTop(node) { for (let cur2 = node; ; ) { if (cur2.type.isTop) return cur2; if (!(cur2 = cur2.parent)) return node; } } function isSelectorIdentifier(node) { if (node.name == "ClassName") return "class" /* CLASS */; if (node.name == "IdName") return "id" /* ID */; return false; } function touchSelection(selection, range) { return selection.ranges.findIndex( (selRange) => selRange.from <= range.to && selRange.to >= range.from ) >= 0; } function getSelectorNames(state, node, type) { if (node.to - node.from > 4096) { const known = SelectorsByNode[type].get(node); if (known) return known; const result = [], seen = /* @__PURE__ */ new Set(), cursor = node.cursor(import_common2.IterMode.IncludeAnonymous); if (cursor.firstChild()) do { for (const option of getSelectorNames(state, cursor.node, type)) if (!seen.has(option.label)) { seen.add(option.label); result.push(option); } } while (cursor.nextSibling()); SelectorsByNode[type].set(node, result); return result; } else { const result = [], seen = /* @__PURE__ */ new Set(), { doc, selection } = state; node.cursor().iterate((node2) => { if (type == isSelectorIdentifier(node2) && !touchSelection(selection, node2)) { const name = doc.sliceString(node2.from, node2.to); if (!seen.has(name)) { seen.add(name); result.push({ label: name, type: "variable" }); } } }); return result; } } var cssCompletionSource = (context) => { let result = defineCSSCompletionSource( (node) => node.name == "VariableName" )(context); if (!result) { const { state, pos } = context, node = (0, import_language5.syntaxTree)(state).resolveInner(pos, -1); if (node.matchContext(ClassSelectorCtx)) { const isDot = node.name == "."; result = { from: isDot ? node.to : node.from, options: getSelectorNames( state, getASTTop(node), "class" /* CLASS */ ), validFor: Identifier }; } else if (node.matchContext(IdSelectorCtx)) { const isHash = node.name == "#"; result = { from: isHash ? node.to : node.from, options: getSelectorNames( state, getASTTop(node), "id" /* ID */ ), validFor: Identifier }; } } return result; }; var css = () => new import_language5.LanguageSupport( cssLanguage, cssLanguage.data.of({ autocomplete: cssCompletionSource }) ); // src/codemirror-extensions/highlight-active-line.ts var import_view4 = require("@codemirror/view"); function highlightActiveLine() { return activeLineLayer; } var activeLineLayer = (0, import_view4.layer)({ above: false, class: "cm-activeLineLayer", markers(view) { const selection = view.state.selection, markers = [], paddingTop = view.documentPadding.top, { width, left: contentLeft } = view.contentDOM.getBoundingClientRect(), { left: scrollerLeft } = view.scrollDOM.getBoundingClientRect(); for (const range of selection.ranges) { const { top, height } = view.lineBlockAt(range.head), layer2 = new import_view4.RectangleMarker( "cm-activeLine", contentLeft - scrollerLeft, top + paddingTop, width, height ); markers.push(layer2); } return markers; }, update(update) { return update.docChanged || update.selectionSet || update.viewportChanged || update.geometryChanged; } }); // src/codemirror-extensions/basic-extensions.ts var basicExtensions = [ import_view5.keymap.of([ ...closeBracketsKeymap, // "{|}" -> backspace -> "|" ...import_commands2.defaultKeymap, ...import_search2.searchKeymap, ...import_commands2.historyKeymap, import_commands2.indentWithTab, ...import_language6.foldKeymap, ...completionKeymap, ...import_lint.lintKeymap ]), css(), (0, import_view5.lineNumbers)(), (0, import_language6.foldGutter)(), (0, import_view5.highlightActiveLineGutter)(), (0, import_view5.dropCursor)(), (0, import_view5.drawSelection)({ drawRangeCursor: true }), import_state3.EditorState.allowMultipleSelections.of(true), highlightActiveLine(), (0, import_language6.indentOnInput)(), (0, import_language6.bracketMatching)(), autocompletion(), closeBrackets(), (0, import_search2.highlightSelectionMatches)(), obsidian ].filter((ext) => ext); // src/views/CssEditorView.ts var import_commands3 = require("@codemirror/commands"); // src/codemirror-extensions/compartments.ts var import_state5 = require("@codemirror/state"); // src/codemirror-extensions/relative-line-numbers.ts var import_view6 = require("@codemirror/view"); var import_state4 = require("@codemirror/state"); var import_language7 = require("@codemirror/language"); var relativeLineNumberGutter = new import_state4.Compartment(); var charLengthCache = /* @__PURE__ */ new WeakMap(); function relativeLineNumbersFormatter(lineNo, state) { let charLength = charLengthCache.get(state); if (!charLength) { charLength = state.doc.lines.toString().length; charLengthCache.set(state, charLength); } if (lineNo > state.doc.lines) { return " ".padStart(charLength, " "); } const selection = state.selection.asSingle(); if (!selection.ranges[0]) { return " ".padStart(charLength, " "); } const cursorLine = state.doc.lineAt(selection.ranges[0].to).number; const folds = (0, import_language7.foldedRanges)(state); if (lineNo === cursorLine) { return lineNo.toString().padStart(charLength, " "); } const start = Math.min(cursorLine, lineNo); const stop = Math.max(cursorLine, lineNo); let foldedCount = 0; folds.between(state.doc.line(start).from, state.doc.line(stop).to, () => { foldedCount++; }); const distance = Math.abs(cursorLine - lineNo) - foldedCount; return distance.toString().padStart(charLength, " "); } function absoluteLineNumbers(lineNo, state) { let charLength = charLengthCache.get(state); if (!charLength) { charLength = state.doc.lines.toString().length; charLengthCache.set(state, charLength); } return lineNo.toString().padStart(charLength, " "); } // src/codemirror-extensions/compartments.ts var lineWrap = new import_state5.Compartment(); var indentSize = new import_state5.Compartment(); var historyCompartment = new import_state5.Compartment(); // src/views/CssEditorView.ts var import_language9 = require("@codemirror/language"); // src/modals/CssSnippetRenameModal.ts var import_obsidian3 = require("obsidian"); // src/utils/handle-error.ts var import_obsidian2 = require("obsidian"); function handleError(err, fallbackMessage = "Action failed. Reason unknown.") { let message = fallbackMessage; if (err instanceof Error) { message = err.message; } new import_obsidian2.Notice(message); console.error(`[CSS Editor]: ${message}`); console.error(err); } // src/modals/CssSnippetRenameModal.ts var CssSnippetRenameModal = class extends import_obsidian3.Modal { constructor(app, file) { super(app); this.value = ""; this.file = file; } async onOpen() { await super.onOpen(); this.titleEl.setText("Rename CSS snippet"); this.containerEl.addClass("css-editor-rename-modal"); this.buildForm(); } buildForm() { const textInput = new import_obsidian3.TextComponent(this.contentEl); textInput.setPlaceholder("CSS snippet file name (ex: snippet.css)"); textInput.setValue(this.file.basename); textInput.onChange((val) => this.value = val); textInput.inputEl.addEventListener("keydown", (evt) => { this.handleKeydown(evt); }); const buttonContainer = this.contentEl.createDiv( "modal-button-container" ); new import_obsidian3.ButtonComponent(buttonContainer).setButtonText("Save").setCta().onClick(() => this.save()); new import_obsidian3.ButtonComponent(buttonContainer).setButtonText("Cancel").onClick(() => this.close()); } handleKeydown(evt) { if (evt.key === "Escape") { this.close(); } else if (evt.key === "Enter") { this.save().catch((err) => { handleError(err, "Failed to rename CSS file."); }); } } async save() { try { await renameSnippetFile(this.app, this.file, this.value); this.close(); } catch (err) { handleError(err, "Failed to rename CSS file."); } } }; // src/obsidian/view-helpers.ts function focusAndSelectElement(el) { el.focus({ preventScroll: true }); const range = document.createRange(); range.selectNodeContents(el); const selection = getSelection(); if (selection) { selection.removeAllRanges(); selection.addRange(range); } } // src/codemirror-extensions/color-picker.ts var import_view7 = require("@codemirror/view"); var import_obsidian4 = require("obsidian"); // node_modules/color-string/node_modules/color-name/index.js var color_name_default = { aliceblue: [240, 248, 255], antiquewhite: [250, 235, 215], aqua: [0, 255, 255], aquamarine: [127, 255, 212], azure: [240, 255, 255], beige: [245, 245, 220], bisque: [255, 228, 196], black: [0, 0, 0], blanchedalmond: [255, 235, 205], blue: [0, 0, 255], blueviolet: [138, 43, 226], brown: [165, 42, 42], burlywood: [222, 184, 135], cadetblue: [95, 158, 160], chartreuse: [127, 255, 0], chocolate: [210, 105, 30], coral: [255, 127, 80], cornflowerblue: [100, 149, 237], cornsilk: [255, 248, 220], crimson: [220, 20, 60], cyan: [0, 255, 255], darkblue: [0, 0, 139], darkcyan: [0, 139, 139], darkgoldenrod: [184, 134, 11], darkgray: [169, 169, 169], darkgreen: [0, 100, 0], darkgrey: [169, 169, 169], darkkhaki: [189, 183, 107], darkmagenta: [139, 0, 139], darkolivegreen: [85, 107, 47], darkorange: [255, 140, 0], darkorchid: [153, 50, 204], darkred: [139, 0, 0], darksalmon: [233, 150, 122], darkseagreen: [143, 188, 143], darkslateblue: [72, 61, 139], darkslategray: [47, 79, 79], darkslategrey: [47, 79, 79], darkturquoise: [0, 206, 209], darkviolet: [148, 0, 211], deeppink: [255, 20, 147], deepskyblue: [0, 191, 255], dimgray: [105, 105, 105], dimgrey: [105, 105, 105], dodgerblue: [30, 144, 255], firebrick: [178, 34, 34], floralwhite: [255, 250, 240], forestgreen: [34, 139, 34], fuchsia: [255, 0, 255], gainsboro: [220, 220, 220], ghostwhite: [248, 248, 255], gold: [255, 215, 0], goldenrod: [218, 165, 32], gray: [128, 128, 128], green: [0, 128, 0], greenyellow: [173, 255, 47], grey: [128, 128, 128], honeydew: [240, 255, 240], hotpink: [255, 105, 180], indianred: [205, 92, 92], indigo: [75, 0, 130], ivory: [255, 255, 240], khaki: [240, 230, 140], lavender: [230, 230, 250], lavenderblush: [255, 240, 245], lawngreen: [124, 252, 0], lemonchiffon: [255, 250, 205], lightblue: [173, 216, 230], lightcoral: [240, 128, 128], lightcyan: [224, 255, 255], lightgoldenrodyellow: [250, 250, 210], lightgray: [211, 211, 211], lightgreen: [144, 238, 144], lightgrey: [211, 211, 211], lightpink: [255, 182, 193], lightsalmon: [255, 160, 122], lightseagreen: [32, 178, 170], lightskyblue: [135, 206, 250], lightslategray: [119, 136, 153], lightslategrey: [119, 136, 153], lightsteelblue: [176, 196, 222], lightyellow: [255, 255, 224], lime: [0, 255, 0], limegreen: [50, 205, 50], linen: [250, 240, 230], magenta: [255, 0, 255], maroon: [128, 0, 0], mediumaquamarine: [102, 205, 170], mediumblue: [0, 0, 205], mediumorchid: [186, 85, 211], mediumpurple: [147, 112, 219], mediumseagreen: [60, 179, 113], mediumslateblue: [123, 104, 238], mediumspringgreen: [0, 250, 154], mediumturquoise: [72, 209, 204], mediumvioletred: [199, 21, 133], midnightblue: [25, 25, 112], mintcream: [245, 255, 250], mistyrose: [255, 228, 225], moccasin: [255, 228, 181], navajowhite: [255, 222, 173], navy: [0, 0, 128], oldlace: [253, 245, 230], olive: [128, 128, 0], olivedrab: [107, 142, 35], orange: [255, 165, 0], orangered: [255, 69, 0], orchid: [218, 112, 214], palegoldenrod: [238, 232, 170], palegreen: [152, 251, 152], paleturquoise: [175, 238, 238], palevioletred: [219, 112, 147], papayawhip: [255, 239, 213], peachpuff: [255, 218, 185], peru: [205, 133, 63], pink: [255, 192, 203], plum: [221, 160, 221], powderblue: [176, 224, 230], purple: [128, 0, 128], rebeccapurple: [102, 51, 153], red: [255, 0, 0], rosybrown: [188, 143, 143], royalblue: [65, 105, 225], saddlebrown: [139, 69, 19], salmon: [250, 128, 114], sandybrown: [244, 164, 96], seagreen: [46, 139, 87], seashell: [255, 245, 238], sienna: [160, 82, 45], silver: [192, 192, 192], skyblue: [135, 206, 235], slateblue: [106, 90, 205], slategray: [112, 128, 144], slategrey: [112, 128, 144], snow: [255, 250, 250], springgreen: [0, 255, 127], steelblue: [70, 130, 180], tan: [210, 180, 140], teal: [0, 128, 128], thistle: [216, 191, 216], tomato: [255, 99, 71], turquoise: [64, 224, 208], violet: [238, 130, 238], wheat: [245, 222, 179], white: [255, 255, 255], whitesmoke: [245, 245, 245], yellow: [255, 255, 0], yellowgreen: [154, 205, 50] }; // node_modules/color-string/index.js var reverseNames = /* @__PURE__ */ Object.create(null); for (const name in color_name_default) { if (Object.hasOwn(color_name_default, name)) { reverseNames[color_name_default[name]] = name; } } var cs = { to: {}, get: {} }; cs.get = function(string) { const prefix = string.slice(0, 3).toLowerCase(); let value; let model; switch (prefix) { case "hsl": { value = cs.get.hsl(string); model = "hsl"; break; } case "hwb": { value = cs.get.hwb(string); model = "hwb"; break; } default: { value = cs.get.rgb(string); model = "rgb"; break; } } if (!value) { return null; } return { model, value }; }; cs.get.rgb = function(string) { if (!string) { return null; } const abbr = /^#([a-f\d]{3,4})$/i; const hex = /^#([a-f\d]{6})([a-f\d]{2})?$/i; const rgba = /^rgba?\(\s*([+-]?\d+)(?=[\s,])\s*(?:,\s*)?([+-]?\d+)(?=[\s,])\s*(?:,\s*)?([+-]?\d+)\s*(?:[,|/]\s*([+-]?[\d.]+)(%?)\s*)?\)$/; const per = /^rgba?\(\s*([+-]?[\d.]+)%\s*,?\s*([+-]?[\d.]+)%\s*,?\s*([+-]?[\d.]+)%\s*(?:[,|/]\s*([+-]?[\d.]+)(%?)\s*)?\)$/; const keyword = /^(\w+)$/; let rgb = [0, 0, 0, 1]; let match; let i; let hexAlpha; if (match = string.match(hex)) { hexAlpha = match[2]; match = match[1]; for (i = 0; i < 3; i++) { const i2 = i * 2; rgb[i] = Number.parseInt(match.slice(i2, i2 + 2), 16); } if (hexAlpha) { rgb[3] = Number.parseInt(hexAlpha, 16) / 255; } } else if (match = string.match(abbr)) { match = match[1]; hexAlpha = match[3]; for (i = 0; i < 3; i++) { rgb[i] = Number.parseInt(match[i] + match[i], 16); } if (hexAlpha) { rgb[3] = Number.parseInt(hexAlpha + hexAlpha, 16) / 255; } } else if (match = string.match(rgba)) { for (i = 0; i < 3; i++) { rgb[i] = Number.parseInt(match[i + 1], 10); } if (match[4]) { rgb[3] = match[5] ? Number.parseFloat(match[4]) * 0.01 : Number.parseFloat(match[4]); } } else if (match = string.match(per)) { for (i = 0; i < 3; i++) { rgb[i] = Math.round(Number.parseFloat(match[i + 1]) * 2.55); } if (match[4]) { rgb[3] = match[5] ? Number.parseFloat(match[4]) * 0.01 : Number.parseFloat(match[4]); } } else if (match = string.match(keyword)) { if (match[1] === "transparent") { return [0, 0, 0, 0]; } if (!Object.hasOwn(color_name_default, match[1])) { return null; } rgb = color_name_default[match[1]]; rgb[3] = 1; return rgb; } else { return null; } for (i = 0; i < 3; i++) { rgb[i] = clamp(rgb[i], 0, 255); } rgb[3] = clamp(rgb[3], 0, 1); return rgb; }; cs.get.hsl = function(string) { if (!string) { return null; } const hsl = /^hsla?\(\s*([+-]?(?:\d{0,3}\.)?\d+)(?:deg)?\s*,?\s*([+-]?[\d.]+)%\s*,?\s*([+-]?[\d.]+)%\s*(?:[,|/]\s*([+-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:[eE][+-]?\d+)?)\s*)?\)$/; const match = string.match(hsl); if (match) { const alpha = Number.parseFloat(match[4]); const h = (Number.parseFloat(match[1]) % 360 + 360) % 360; const s = clamp(Number.parseFloat(match[2]), 0, 100); const l = clamp(Number.parseFloat(match[3]), 0, 100); const a = clamp(Number.isNaN(alpha) ? 1 : alpha, 0, 1); return [h, s, l, a]; } return null; }; cs.get.hwb = function(string) { if (!string) { return null; } const hwb = /^hwb\(\s*([+-]?\d{0,3}(?:\.\d+)?)(?:deg)?\s*,\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*(?:,\s*([+-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:[eE][+-]?\d+)?)\s*)?\)$/; const match = string.match(hwb); if (match) { const alpha = Number.parseFloat(match[4]); const h = (Number.parseFloat(match[1]) % 360 + 360) % 360; const w = clamp(Number.parseFloat(match[2]), 0, 100); const b = clamp(Number.parseFloat(match[3]), 0, 100); const a = clamp(Number.isNaN(alpha) ? 1 : alpha, 0, 1); return [h, w, b, a]; } return null; }; cs.to.hex = function(...rgba) { return "#" + hexDouble(rgba[0]) + hexDouble(rgba[1]) + hexDouble(rgba[2]) + (rgba[3] < 1 ? hexDouble(Math.round(rgba[3] * 255)) : ""); }; cs.to.rgb = function(...rgba) { return rgba.length < 4 || rgba[3] === 1 ? "rgb(" + Math.round(rgba[0]) + ", " + Math.round(rgba[1]) + ", " + Math.round(rgba[2]) + ")" : "rgba(" + Math.round(rgba[0]) + ", " + Math.round(rgba[1]) + ", " + Math.round(rgba[2]) + ", " + rgba[3] + ")"; }; cs.to.rgb.percent = function(...rgba) { const r = Math.round(rgba[0] / 255 * 100); const g = Math.round(rgba[1] / 255 * 100); const b = Math.round(rgba[2] / 255 * 100); return rgba.length < 4 || rgba[3] === 1 ? "rgb(" + r + "%, " + g + "%, " + b + "%)" : "rgba(" + r + "%, " + g + "%, " + b + "%, " + rgba[3] + ")"; }; cs.to.hsl = function(...hsla) { return hsla.length < 4 || hsla[3] === 1 ? "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)" : "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, " + hsla[3] + ")"; }; cs.to.hwb = function(...hwba) { let a = ""; if (hwba.length >= 4 && hwba[3] !== 1) { a = ", " + hwba[3]; } return "hwb(" + hwba[0] + ", " + hwba[1] + "%, " + hwba[2] + "%" + a + ")"; }; cs.to.keyword = function(...rgb) { return reverseNames[rgb.slice(0, 3)]; }; function clamp(number_, min, max) { return Math.min(Math.max(min, number_), max); } function hexDouble(number_) { const string_ = Math.round(number_).toString(16).toUpperCase(); return string_.length < 2 ? "0" + string_ : string_; } var color_string_default = cs; // node_modules/color/node_modules/color-name/index.js var color_name_default2 = { aliceblue: [240, 248, 255], antiquewhite: [250, 235, 215], aqua: [0, 255, 255], aquamarine: [127, 255, 212], azure: [240, 255, 255], beige: [245, 245, 220], bisque: [255, 228, 196], black: [0, 0, 0], blanchedalmond: [255, 235, 205], blue: [0, 0, 255], blueviolet: [138, 43, 226], brown: [165, 42, 42], burlywood: [222, 184, 135], cadetblue: [95, 158, 160], chartreuse: [127, 255, 0], chocolate: [210, 105, 30], coral: [255, 127, 80], cornflowerblue: [100, 149, 237], cornsilk: [255, 248, 220], crimson: [220, 20, 60], cyan: [0, 255, 255], darkblue: [0, 0, 139], darkcyan: [0, 139, 139], darkgoldenrod: [184, 134, 11], darkgray: [169, 169, 169], darkgreen: [0, 100, 0], darkgrey: [169, 169, 169], darkkhaki: [189, 183, 107], darkmagenta: [139, 0, 139], darkolivegreen: [85, 107, 47], darkorange: [255, 140, 0], darkorchid: [153, 50, 204], darkred: [139, 0, 0], darksalmon: [233, 150, 122], darkseagreen: [143, 188, 143], darkslateblue: [72, 61, 139], darkslategray: [47, 79, 79], darkslategrey: [47, 79, 79], darkturquoise: [0, 206, 209], darkviolet: [148, 0, 211], deeppink: [255, 20, 147], deepskyblue: [0, 191, 255], dimgray: [105, 105, 105], dimgrey: [105, 105, 105], dodgerblue: [30, 144, 255], firebrick: [178, 34, 34], floralwhite: [255, 250, 240], forestgreen: [34, 139, 34], fuchsia: [255, 0, 255], gainsboro: [220, 220, 220], ghostwhite: [248, 248, 255], gold: [255, 215, 0], goldenrod: [218, 165, 32], gray: [128, 128, 128], green: [0, 128, 0], greenyellow: [173, 255, 47], grey: [128, 128, 128], honeydew: [240, 255, 240], hotpink: [255, 105, 180], indianred: [205, 92, 92], indigo: [75, 0, 130], ivory: [255, 255, 240], khaki: [240, 230, 140], lavender: [230, 230, 250], lavenderblush: [255, 240, 245], lawngreen: [124, 252, 0], lemonchiffon: [255, 250, 205], lightblue: [173, 216, 230], lightcoral: [240, 128, 128], lightcyan: [224, 255, 255], lightgoldenrodyellow: [250, 250, 210], lightgray: [211, 211, 211], lightgreen: [144, 238, 144], lightgrey: [211, 211, 211], lightpink: [255, 182, 193], lightsalmon: [255, 160, 122], lightseagreen: [32, 178, 170], lightskyblue: [135, 206, 250], lightslategray: [119, 136, 153], lightslategrey: [119, 136, 153], lightsteelblue: [176, 196, 222], lightyellow: [255, 255, 224], lime: [0, 255, 0], limegreen: [50, 205, 50], linen: [250, 240, 230], magenta: [255, 0, 255], maroon: [128, 0, 0], mediumaquamarine: [102, 205, 170], mediumblue: [0, 0, 205], mediumorchid: [186, 85, 211], mediumpurple: [147, 112, 219], mediumseagreen: [60, 179, 113], mediumslateblue: [123, 104, 238], mediumspringgreen: [0, 250, 154], mediumturquoise: [72, 209, 204], mediumvioletred: [199, 21, 133], midnightblue: [25, 25, 112], mintcream: [245, 255, 250], mistyrose: [255, 228, 225], moccasin: [255, 228, 181], navajowhite: [255, 222, 173], navy: [0, 0, 128], oldlace: [253, 245, 230], olive: [128, 128, 0], olivedrab: [107, 142, 35], orange: [255, 165, 0], orangered: [255, 69, 0], orchid: [218, 112, 214], palegoldenrod: [238, 232, 170], palegreen: [152, 251, 152], paleturquoise: [175, 238, 238], palevioletred: [219, 112, 147], papayawhip: [255, 239, 213], peachpuff: [255, 218, 185], peru: [205, 133, 63], pink: [255, 192, 203], plum: [221, 160, 221], powderblue: [176, 224, 230], purple: [128, 0, 128], rebeccapurple: [102, 51, 153], red: [255, 0, 0], rosybrown: [188, 143, 143], royalblue: [65, 105, 225], saddlebrown: [139, 69, 19], salmon: [250, 128, 114], sandybrown: [244, 164, 96], seagreen: [46, 139, 87], seashell: [255, 245, 238], sienna: [160, 82, 45], silver: [192, 192, 192], skyblue: [135, 206, 235], slateblue: [106, 90, 205], slategray: [112, 128, 144], slategrey: [112, 128, 144], snow: [255, 250, 250], springgreen: [0, 255, 127], steelblue: [70, 130, 180], tan: [210, 180, 140], teal: [0, 128, 128], thistle: [216, 191, 216], tomato: [255, 99, 71], turquoise: [64, 224, 208], violet: [238, 130, 238], wheat: [245, 222, 179], white: [255, 255, 255], whitesmoke: [245, 245, 245], yellow: [255, 255, 0], yellowgreen: [154, 205, 50] }; // node_modules/color/node_modules/color-convert/conversions.js var reverseKeywords = {}; for (const key of Object.keys(color_name_default2)) { reverseKeywords[color_name_default2[key]] = key; } var convert = { rgb: { channels: 3, labels: "rgb" }, hsl: { channels: 3, labels: "hsl" }, hsv: { channels: 3, labels: "hsv" }, hwb: { channels: 3, labels: "hwb" }, cmyk: { channels: 4, labels: "cmyk" }, xyz: { channels: 3, labels: "xyz" }, lab: { channels: 3, labels: "lab" }, oklab: { channels: 3, labels: ["okl", "oka", "okb"] }, lch: { channels: 3, labels: "lch" }, oklch: { channels: 3, labels: ["okl", "okc", "okh"] }, hex: { channels: 1, labels: ["hex"] }, keyword: { channels: 1, labels: ["keyword"] }, ansi16: { channels: 1, labels: ["ansi16"] }, ansi256: { channels: 1, labels: ["ansi256"] }, hcg: { channels: 3, labels: ["h", "c", "g"] }, apple: { channels: 3, labels: ["r16", "g16", "b16"] }, gray: { channels: 1, labels: ["gray"] } }; var conversions_default = convert; var LAB_FT = (6 / 29) ** 3; function srgbNonlinearTransform(c) { const cc = c > 31308e-7 ? 1.055 * c ** (1 / 2.4) - 0.055 : c * 12.92; return Math.min(Math.max(0, cc), 1); } function srgbNonlinearTransformInv(c) { return c > 0.04045 ? ((c + 0.055) / 1.055) ** 2.4 : c / 12.92; } for (const model of Object.keys(convert)) { if (!("channels" in convert[model])) { throw new Error("missing channels property: " + model); } if (!("labels" in convert[model])) { throw new Error("missing channel labels property: " + model); } if (convert[model].labels.length !== convert[model].channels) { throw new Error("channel and label counts mismatch: " + model); } const { channels, labels } = convert[model]; delete convert[model].channels; delete convert[model].labels; Object.defineProperty(convert[model], "channels", { value: channels }); Object.defineProperty(convert[model], "labels", { value: labels }); } convert.rgb.hsl = function(rgb) { const r = rgb[0] / 255; const g = rgb[1] / 255; const b = rgb[2] / 255; const min = Math.min(r, g, b); const max = Math.max(r, g, b); const delta = max - min; let h; let s; switch (max) { case min: { h = 0; break; } case r: { h = (g - b) / delta; break; } case g: { h = 2 + (b - r) / delta; break; } case b: { h = 4 + (r - g) / delta; break; } } h = Math.min(h * 60, 360); if (h < 0) { h += 360; } const l = (min + max) / 2; if (max === min) { s = 0; } else if (l <= 0.5) { s = delta / (max + min); } else { s = delta / (2 - max - min); } return [h, s * 100, l * 100]; }; convert.rgb.hsv = function(rgb) { let rdif; let gdif; let bdif; let h; let s; const r = rgb[0] / 255; const g = rgb[1] / 255; const b = rgb[2] / 255; const v = Math.max(r, g, b); const diff = v - Math.min(r, g, b); const diffc = function(c) { return (v - c) / 6 / diff + 1 / 2; }; if (diff === 0) { h = 0; s = 0; } else { s = diff / v; rdif = diffc(r); gdif = diffc(g); bdif = diffc(b); switch (v) { case r: { h = bdif - gdif; break; } case g: { h = 1 / 3 + rdif - bdif; break; } case b: { h = 2 / 3 + gdif - rdif; break; } } if (h < 0) { h += 1; } else if (h > 1) { h -= 1; } } return [ h * 360, s * 100, v * 100 ]; }; convert.rgb.hwb = function(rgb) { const r = rgb[0]; const g = rgb[1]; let b = rgb[2]; const h = convert.rgb.hsl(rgb)[0]; const w = 1 / 255 * Math.min(r, Math.min(g, b)); b = 1 - 1 / 255 * Math.max(r, Math.max(g, b)); return [h, w * 100, b * 100]; }; convert.rgb.oklab = function(rgb) { const r = srgbNonlinearTransformInv(rgb[0] / 255); const g = srgbNonlinearTransformInv(rgb[1] / 255); const b = srgbNonlinearTransformInv(rgb[2] / 255); const lp = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b); const mp = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b); const sp = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b); const l = 0.2104542553 * lp + 0.793617785 * mp - 0.0040720468 * sp; const aa = 1.9779984951 * lp - 2.428592205 * mp + 0.4505937099 * sp; const bb = 0.0259040371 * lp + 0.7827717662 * mp - 0.808675766 * sp; return [l * 100, aa * 100, bb * 100]; }; convert.rgb.cmyk = function(rgb) { const r = rgb[0] / 255; const g = rgb[1] / 255; const b = rgb[2] / 255; const k = Math.min(1 - r, 1 - g, 1 - b); const c = (1 - r - k) / (1 - k) || 0; const m = (1 - g - k) / (1 - k) || 0; const y = (1 - b - k) / (1 - k) || 0; return [c * 100, m * 100, y * 100, k * 100]; }; function comparativeDistance(x, y) { return (x[0] - y[0]) ** 2 + (x[1] - y[1]) ** 2 + (x[2] - y[2]) ** 2; } convert.rgb.keyword = function(rgb) { const reversed = reverseKeywords[rgb]; if (reversed) { return reversed; } let currentClosestDistance = Number.POSITIVE_INFINITY; let currentClosestKeyword; for (const keyword of Object.keys(color_name_default2)) { const value = color_name_default2[keyword]; const distance = comparativeDistance(rgb, value); if (distance < currentClosestDistance) { currentClosestDistance = distance; currentClosestKeyword = keyword; } } return currentClosestKeyword; }; convert.keyword.rgb = function(keyword) { return color_name_default2[keyword]; }; convert.rgb.xyz = function(rgb) { const r = srgbNonlinearTransformInv(rgb[0] / 255); const g = srgbNonlinearTransformInv(rgb[1] / 255); const b = srgbNonlinearTransformInv(rgb[2] / 255); const x = r * 0.4124564 + g * 0.3575761 + b * 0.1804375; const y = r * 0.2126729 + g * 0.7151522 + b * 0.072175; const z = r * 0.0193339 + g * 0.119192 + b * 0.9503041; return [x * 100, y * 100, z * 100]; }; convert.rgb.lab = function(rgb) { const xyz = convert.rgb.xyz(rgb); let x = xyz[0]; let y = xyz[1]; let z = xyz[2]; x /= 95.047; y /= 100; z /= 108.883; x = x > LAB_FT ? x ** (1 / 3) : 7.787 * x + 16 / 116; y = y > LAB_FT ? y ** (1 / 3) : 7.787 * y + 16 / 116; z = z > LAB_FT ? z ** (1 / 3) : 7.787 * z + 16 / 116; const l = 116 * y - 16; const a = 500 * (x - y); const b = 200 * (y - z); return [l, a, b]; }; convert.hsl.rgb = function(hsl) { const h = hsl[0] / 360; const s = hsl[1] / 100; const l = hsl[2] / 100; let t3; let value; if (s === 0) { value = l * 255; return [value, value, value]; } const t2 = l < 0.5 ? l * (1 + s) : l + s - l * s; const t1 = 2 * l - t2; const rgb = [0, 0, 0]; for (let i = 0; i < 3; i++) { t3 = h + 1 / 3 * -(i - 1); if (t3 < 0) { t3++; } if (t3 > 1) { t3--; } if (6 * t3 < 1) { value = t1 + (t2 - t1) * 6 * t3; } else if (2 * t3 < 1) { value = t2; } else if (3 * t3 < 2) { value = t1 + (t2 - t1) * (2 / 3 - t3) * 6; } else { value = t1; } rgb[i] = value * 255; } return rgb; }; convert.hsl.hsv = function(hsl) { const h = hsl[0]; let s = hsl[1] / 100; let l = hsl[2] / 100; let smin = s; const lmin = Math.max(l, 0.01); l *= 2; s *= l <= 1 ? l : 2 - l; smin *= lmin <= 1 ? lmin : 2 - lmin; const v = (l + s) / 2; const sv = l === 0 ? 2 * smin / (lmin + smin) : 2 * s / (l + s); return [h, sv * 100, v * 100]; }; convert.hsv.rgb = function(hsv) { const h = hsv[0] / 60; const s = hsv[1] / 100; let v = hsv[2] / 100; const hi = Math.floor(h) % 6; const f = h - Math.floor(h); const p = 255 * v * (1 - s); const q = 255 * v * (1 - s * f); const t2 = 255 * v * (1 - s * (1 - f)); v *= 255; switch (hi) { case 0: { return [v, t2, p]; } case 1: { return [q, v, p]; } case 2: { return [p, v, t2]; } case 3: { return [p, q, v]; } case 4: { return [t2, p, v]; } case 5: { return [v, p, q]; } } }; convert.hsv.hsl = function(hsv) { const h = hsv[0]; const s = hsv[1] / 100; const v = hsv[2] / 100; const vmin = Math.max(v, 0.01); let sl; let l; l = (2 - s) * v; const lmin = (2 - s) * vmin; sl = s * vmin; sl /= lmin <= 1 ? lmin : 2 - lmin; sl = sl || 0; l /= 2; return [h, sl * 100, l * 100]; }; convert.hwb.rgb = function(hwb) { const h = hwb[0] / 360; let wh = hwb[1] / 100; let bl = hwb[2] / 100; const ratio = wh + bl; let f; if (ratio > 1) { wh /= ratio; bl /= ratio; } const i = Math.floor(6 * h); const v = 1 - bl; f = 6 * h - i; if ((i & 1) !== 0) { f = 1 - f; } const n = wh + f * (v - wh); let r; let g; let b; switch (i) { default: case 6: case 0: { r = v; g = n; b = wh; break; } case 1: { r = n; g = v; b = wh; break; } case 2: { r = wh; g = v; b = n; break; } case 3: { r = wh; g = n; b = v; break; } case 4: { r = n; g = wh; b = v; break; } case 5: { r = v; g = wh; b = n; break; } } return [r * 255, g * 255, b * 255]; }; convert.cmyk.rgb = function(cmyk) { const c = cmyk[0] / 100; const m = cmyk[1] / 100; const y = cmyk[2] / 100; const k = cmyk[3] / 100; const r = 1 - Math.min(1, c * (1 - k) + k); const g = 1 - Math.min(1, m * (1 - k) + k); const b = 1 - Math.min(1, y * (1 - k) + k); return [r * 255, g * 255, b * 255]; }; convert.xyz.rgb = function(xyz) { const x = xyz[0] / 100; const y = xyz[1] / 100; const z = xyz[2] / 100; let r; let g; let b; r = x * 3.2404542 + y * -1.5371385 + z * -0.4985314; g = x * -0.969266 + y * 1.8760108 + z * 0.041556; b = x * 0.0556434 + y * -0.2040259 + z * 1.0572252; r = srgbNonlinearTransform(r); g = srgbNonlinearTransform(g); b = srgbNonlinearTransform(b); return [r * 255, g * 255, b * 255]; }; convert.xyz.lab = function(xyz) { let x = xyz[0]; let y = xyz[1]; let z = xyz[2]; x /= 95.047; y /= 100; z /= 108.883; x = x > LAB_FT ? x ** (1 / 3) : 7.787 * x + 16 / 116; y = y > LAB_FT ? y ** (1 / 3) : 7.787 * y + 16 / 116; z = z > LAB_FT ? z ** (1 / 3) : 7.787 * z + 16 / 116; const l = 116 * y - 16; const a = 500 * (x - y); const b = 200 * (y - z); return [l, a, b]; }; convert.xyz.oklab = function(xyz) { const x = xyz[0] / 100; const y = xyz[1] / 100; const z = xyz[2] / 100; const lp = Math.cbrt(0.8189330101 * x + 0.3618667424 * y - 0.1288597137 * z); const mp = Math.cbrt(0.0329845436 * x + 0.9293118715 * y + 0.0361456387 * z); const sp = Math.cbrt(0.0482003018 * x + 0.2643662691 * y + 0.633851707 * z); const l = 0.2104542553 * lp + 0.793617785 * mp - 0.0040720468 * sp; const a = 1.9779984951 * lp - 2.428592205 * mp + 0.4505937099 * sp; const b = 0.0259040371 * lp + 0.7827717662 * mp - 0.808675766 * sp; return [l * 100, a * 100, b * 100]; }; convert.oklab.oklch = function(oklab) { return convert.lab.lch(oklab); }; convert.oklab.xyz = function(oklab) { const ll = oklab[0] / 100; const a = oklab[1] / 100; const b = oklab[2] / 100; const l = (0.999999998 * ll + 0.396337792 * a + 0.215803758 * b) ** 3; const m = (1.000000008 * ll - 0.105561342 * a - 0.063854175 * b) ** 3; const s = (1.000000055 * ll - 0.089484182 * a - 1.291485538 * b) ** 3; const x = 1.227013851 * l - 0.55779998 * m + 0.281256149 * s; const y = -0.040580178 * l + 1.11225687 * m - 0.071676679 * s; const z = -0.076381285 * l - 0.421481978 * m + 1.58616322 * s; return [x * 100, y * 100, z * 100]; }; convert.oklab.rgb = function(oklab) { const ll = oklab[0] / 100; const aa = oklab[1] / 100; const bb = oklab[2] / 100; const l = (ll + 0.3963377774 * aa + 0.2158037573 * bb) ** 3; const m = (ll - 0.1055613458 * aa - 0.0638541728 * bb) ** 3; const s = (ll - 0.0894841775 * aa - 1.291485548 * bb) ** 3; const r = srgbNonlinearTransform(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s); const g = srgbNonlinearTransform(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s); const b = srgbNonlinearTransform(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s); return [r * 255, g * 255, b * 255]; }; convert.oklch.oklab = function(oklch) { return convert.lch.lab(oklch); }; convert.lab.xyz = function(lab) { const l = lab[0]; const a = lab[1]; const b = lab[2]; let x; let y; let z; y = (l + 16) / 116; x = a / 500 + y; z = y - b / 200; const y2 = y ** 3; const x2 = x ** 3; const z2 = z ** 3; y = y2 > LAB_FT ? y2 : (y - 16 / 116) / 7.787; x = x2 > LAB_FT ? x2 : (x - 16 / 116) / 7.787; z = z2 > LAB_FT ? z2 : (z - 16 / 116) / 7.787; x *= 95.047; y *= 100; z *= 108.883; return [x, y, z]; }; convert.lab.lch = function(lab) { const l = lab[0]; const a = lab[1]; const b = lab[2]; let h; const hr = Math.atan2(b, a); h = hr * 360 / 2 / Math.PI; if (h < 0) { h += 360; } const c = Math.sqrt(a * a + b * b); return [l, c, h]; }; convert.lch.lab = function(lch) { const l = lch[0]; const c = lch[1]; const h = lch[2]; const hr = h / 360 * 2 * Math.PI; const a = c * Math.cos(hr); const b = c * Math.sin(hr); return [l, a, b]; }; convert.rgb.ansi16 = function(args, saturation = null) { const [r, g, b] = args; let value = saturation === null ? convert.rgb.hsv(args)[2] : saturation; value = Math.round(value / 50); if (value === 0) { return 30; } let ansi = 30 + (Math.round(b / 255) << 2 | Math.round(g / 255) << 1 | Math.round(r / 255)); if (value === 2) { ansi += 60; } return ansi; }; convert.hsv.ansi16 = function(args) { return convert.rgb.ansi16(convert.hsv.rgb(args), args[2]); }; convert.rgb.ansi256 = function(args) { const r = args[0]; const g = args[1]; const b = args[2]; if (r >> 4 === g >> 4 && g >> 4 === b >> 4) { if (r < 8) { return 16; } if (r > 248) { return 231; } return Math.round((r - 8) / 247 * 24) + 232; } const ansi = 16 + 36 * Math.round(r / 255 * 5) + 6 * Math.round(g / 255 * 5) + Math.round(b / 255 * 5); return ansi; }; convert.ansi16.rgb = function(args) { args = args[0]; let color = args % 10; if (color === 0 || color === 7) { if (args > 50) { color += 3.5; } color = color / 10.5 * 255; return [color, color, color]; } const mult = (Math.trunc(args > 50) + 1) * 0.5; const r = (color & 1) * mult * 255; const g = (color >> 1 & 1) * mult * 255; const b = (color >> 2 & 1) * mult * 255; return [r, g, b]; }; convert.ansi256.rgb = function(args) { args = args[0]; if (args >= 232) { const c = (args - 232) * 10 + 8; return [c, c, c]; } args -= 16; let rem; const r = Math.floor(args / 36) / 5 * 255; const g = Math.floor((rem = args % 36) / 6) / 5 * 255; const b = rem % 6 / 5 * 255; return [r, g, b]; }; convert.rgb.hex = function(args) { const integer = ((Math.round(args[0]) & 255) << 16) + ((Math.round(args[1]) & 255) << 8) + (Math.round(args[2]) & 255); const string = integer.toString(16).toUpperCase(); return "000000".slice(string.length) + string; }; convert.hex.rgb = function(args) { const match = args.toString(16).match(/[a-f\d]{6}|[a-f\d]{3}/i); if (!match) { return [0, 0, 0]; } let colorString = match[0]; if (match[0].length === 3) { colorString = [...colorString].map((char) => char + char).join(""); } const integer = Number.parseInt(colorString, 16); const r = integer >> 16 & 255; const g = integer >> 8 & 255; const b = integer & 255; return [r, g, b]; }; convert.rgb.hcg = function(rgb) { const r = rgb[0] / 255; const g = rgb[1] / 255; const b = rgb[2] / 255; const max = Math.max(Math.max(r, g), b); const min = Math.min(Math.min(r, g), b); const chroma = max - min; let hue; const grayscale = chroma < 1 ? min / (1 - chroma) : 0; if (chroma <= 0) { hue = 0; } else if (max === r) { hue = (g - b) / chroma % 6; } else if (max === g) { hue = 2 + (b - r) / chroma; } else { hue = 4 + (r - g) / chroma; } hue /= 6; hue %= 1; return [hue * 360, chroma * 100, grayscale * 100]; }; convert.hsl.hcg = function(hsl) { const s = hsl[1] / 100; const l = hsl[2] / 100; const c = l < 0.5 ? 2 * s * l : 2 * s * (1 - l); let f = 0; if (c < 1) { f = (l - 0.5 * c) / (1 - c); } return [hsl[0], c * 100, f * 100]; }; convert.hsv.hcg = function(hsv) { const s = hsv[1] / 100; const v = hsv[2] / 100; const c = s * v; let f = 0; if (c < 1) { f = (v - c) / (1 - c); } return [hsv[0], c * 100, f * 100]; }; convert.hcg.rgb = function(hcg) { const h = hcg[0] / 360; const c = hcg[1] / 100; const g = hcg[2] / 100; if (c === 0) { return [g * 255, g * 255, g * 255]; } const pure = [0, 0, 0]; const hi = h % 1 * 6; const v = hi % 1; const w = 1 - v; let mg = 0; switch (Math.floor(hi)) { case 0: { pure[0] = 1; pure[1] = v; pure[2] = 0; break; } case 1: { pure[0] = w; pure[1] = 1; pure[2] = 0; break; } case 2: { pure[0] = 0; pure[1] = 1; pure[2] = v; break; } case 3: { pure[0] = 0; pure[1] = w; pure[2] = 1; break; } case 4: { pure[0] = v; pure[1] = 0; pure[2] = 1; break; } default: { pure[0] = 1; pure[1] = 0; pure[2] = w; } } mg = (1 - c) * g; return [ (c * pure[0] + mg) * 255, (c * pure[1] + mg) * 255, (c * pure[2] + mg) * 255 ]; }; convert.hcg.hsv = function(hcg) { const c = hcg[1] / 100; const g = hcg[2] / 100; const v = c + g * (1 - c); let f = 0; if (v > 0) { f = c / v; } return [hcg[0], f * 100, v * 100]; }; convert.hcg.hsl = function(hcg) { const c = hcg[1] / 100; const g = hcg[2] / 100; const l = g * (1 - c) + 0.5 * c; let s = 0; if (l > 0 && l < 0.5) { s = c / (2 * l); } else if (l >= 0.5 && l < 1) { s = c / (2 * (1 - l)); } return [hcg[0], s * 100, l * 100]; }; convert.hcg.hwb = function(hcg) { const c = hcg[1] / 100; const g = hcg[2] / 100; const v = c + g * (1 - c); return [hcg[0], (v - c) * 100, (1 - v) * 100]; }; convert.hwb.hcg = function(hwb) { const w = hwb[1] / 100; const b = hwb[2] / 100; const v = 1 - b; const c = v - w; let g = 0; if (c < 1) { g = (v - c) / (1 - c); } return [hwb[0], c * 100, g * 100]; }; convert.apple.rgb = function(apple) { return [apple[0] / 65535 * 255, apple[1] / 65535 * 255, apple[2] / 65535 * 255]; }; convert.rgb.apple = function(rgb) { return [rgb[0] / 255 * 65535, rgb[1] / 255 * 65535, rgb[2] / 255 * 65535]; }; convert.gray.rgb = function(args) { return [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255]; }; convert.gray.hsl = function(args) { return [0, 0, args[0]]; }; convert.gray.hsv = convert.gray.hsl; convert.gray.hwb = function(gray) { return [0, 100, gray[0]]; }; convert.gray.cmyk = function(gray) { return [0, 0, 0, gray[0]]; }; convert.gray.lab = function(gray) { return [gray[0], 0, 0]; }; convert.gray.hex = function(gray) { const value = Math.round(gray[0] / 100 * 255) & 255; const integer = (value << 16) + (value << 8) + value; const string = integer.toString(16).toUpperCase(); return "000000".slice(string.length) + string; }; convert.rgb.gray = function(rgb) { const value = (rgb[0] + rgb[1] + rgb[2]) / 3; return [value / 255 * 100]; }; // node_modules/color/node_modules/color-convert/route.js function buildGraph() { const graph = {}; const models2 = Object.keys(conversions_default); for (let { length } = models2, i = 0; i < length; i++) { graph[models2[i]] = { // http://jsperf.com/1-vs-infinity // micro-opt, but this is simple. distance: -1, parent: null }; } return graph; } function deriveBFS(fromModel) { const graph = buildGraph(); const queue = [fromModel]; graph[fromModel].distance = 0; while (queue.length > 0) { const current = queue.pop(); const adjacents = Object.keys(conversions_default[current]); for (let { length } = adjacents, i = 0; i < length; i++) { const adjacent = adjacents[i]; const node = graph[adjacent]; if (node.distance === -1) { node.distance = graph[current].distance + 1; node.parent = current; queue.unshift(adjacent); } } } return graph; } function link(from, to) { return function(args) { return to(from(args)); }; } function wrapConversion(toModel, graph) { const path = [graph[toModel].parent, toModel]; let fn = conversions_default[graph[toModel].parent][toModel]; let cur2 = graph[toModel].parent; while (graph[cur2].parent) { path.unshift(graph[cur2].parent); fn = link(conversions_default[graph[cur2].parent][cur2], fn); cur2 = graph[cur2].parent; } fn.conversion = path; return fn; } function route(fromModel) { const graph = deriveBFS(fromModel); const conversion = {}; const models2 = Object.keys(graph); for (let { length } = models2, i = 0; i < length; i++) { const toModel = models2[i]; const node = graph[toModel]; if (node.parent === null) { continue; } conversion[toModel] = wrapConversion(toModel, graph); } return conversion; } var route_default = route; // node_modules/color/node_modules/color-convert/index.js var convert2 = {}; var models = Object.keys(conversions_default); function wrapRaw(fn) { const wrappedFn = function(...args) { const arg0 = args[0]; if (arg0 === void 0 || arg0 === null) { return arg0; } if (arg0.length > 1) { args = arg0; } return fn(args); }; if ("conversion" in fn) { wrappedFn.conversion = fn.conversion; } return wrappedFn; } function wrapRounded(fn) { const wrappedFn = function(...args) { const arg0 = args[0]; if (arg0 === void 0 || arg0 === null) { return arg0; } if (arg0.length > 1) { args = arg0; } const result = fn(args); if (typeof result === "object") { for (let { length } = result, i = 0; i < length; i++) { result[i] = Math.round(result[i]); } } return result; }; if ("conversion" in fn) { wrappedFn.conversion = fn.conversion; } return wrappedFn; } for (const fromModel of models) { convert2[fromModel] = {}; Object.defineProperty(convert2[fromModel], "channels", { value: conversions_default[fromModel].channels }); Object.defineProperty(convert2[fromModel], "labels", { value: conversions_default[fromModel].labels }); const routes = route_default(fromModel); const routeModels = Object.keys(routes); for (const toModel of routeModels) { const fn = routes[toModel]; convert2[fromModel][toModel] = wrapRounded(fn); convert2[fromModel][toModel].raw = wrapRaw(fn); } } var color_convert_default = convert2; // node_modules/color/index.js var skippedModels = [ // To be honest, I don't really feel like keyword belongs in color convert, but eh. "keyword", // Gray conflicts with some method names, and has its own method defined. "gray", // Shouldn't really be in color-convert either... "hex" ]; var hashedModelKeys = {}; for (const model of Object.keys(color_convert_default)) { hashedModelKeys[[...color_convert_default[model].labels].sort().join("")] = model; } var limiters = {}; function Color(object, model) { if (!(this instanceof Color)) { return new Color(object, model); } if (model && model in skippedModels) { model = null; } if (model && !(model in color_convert_default)) { throw new Error("Unknown model: " + model); } let i; let channels; if (object == null) { this.model = "rgb"; this.color = [0, 0, 0]; this.valpha = 1; } else if (object instanceof Color) { this.model = object.model; this.color = [...object.color]; this.valpha = object.valpha; } else if (typeof object === "string") { const result = color_string_default.get(object); if (result === null) { throw new Error("Unable to parse color from string: " + object); } this.model = result.model; channels = color_convert_default[this.model].channels; this.color = result.value.slice(0, channels); this.valpha = typeof result.value[channels] === "number" ? result.value[channels] : 1; } else if (object.length > 0) { this.model = model || "rgb"; channels = color_convert_default[this.model].channels; const newArray = Array.prototype.slice.call(object, 0, channels); this.color = zeroArray(newArray, channels); this.valpha = typeof object[channels] === "number" ? object[channels] : 1; } else if (typeof object === "number") { this.model = "rgb"; this.color = [ object >> 16 & 255, object >> 8 & 255, object & 255 ]; this.valpha = 1; } else { this.valpha = 1; const keys2 = Object.keys(object); if ("alpha" in object) { keys2.splice(keys2.indexOf("alpha"), 1); this.valpha = typeof object.alpha === "number" ? object.alpha : 0; } const hashedKeys = keys2.sort().join(""); if (!(hashedKeys in hashedModelKeys)) { throw new Error("Unable to parse color from object: " + JSON.stringify(object)); } this.model = hashedModelKeys[hashedKeys]; const { labels } = color_convert_default[this.model]; const color = []; for (i = 0; i < labels.length; i++) { color.push(object[labels[i]]); } this.color = zeroArray(color); } if (limiters[this.model]) { channels = color_convert_default[this.model].channels; for (i = 0; i < channels; i++) { const limit = limiters[this.model][i]; if (limit) { this.color[i] = limit(this.color[i]); } } } this.valpha = Math.max(0, Math.min(1, this.valpha)); if (Object.freeze) { Object.freeze(this); } } Color.prototype = { toString() { return this.string(); }, toJSON() { return this[this.model](); }, string(places) { let self = this.model in color_string_default.to ? this : this.rgb(); self = self.round(typeof places === "number" ? places : 1); const arguments_ = self.valpha === 1 ? self.color : [...self.color, this.valpha]; return color_string_default.to[self.model](...arguments_); }, percentString(places) { const self = this.rgb().round(typeof places === "number" ? places : 1); const arguments_ = self.valpha === 1 ? self.color : [...self.color, this.valpha]; return color_string_default.to.rgb.percent(...arguments_); }, array() { return this.valpha === 1 ? [...this.color] : [...this.color, this.valpha]; }, object() { const result = {}; const { channels } = color_convert_default[this.model]; const { labels } = color_convert_default[this.model]; for (let i = 0; i < channels; i++) { result[labels[i]] = this.color[i]; } if (this.valpha !== 1) { result.alpha = this.valpha; } return result; }, unitArray() { const rgb = this.rgb().color; rgb[0] /= 255; rgb[1] /= 255; rgb[2] /= 255; if (this.valpha !== 1) { rgb.push(this.valpha); } return rgb; }, unitObject() { const rgb = this.rgb().object(); rgb.r /= 255; rgb.g /= 255; rgb.b /= 255; if (this.valpha !== 1) { rgb.alpha = this.valpha; } return rgb; }, round(places) { places = Math.max(places || 0, 0); return new Color([...this.color.map(roundToPlace(places)), this.valpha], this.model); }, alpha(value) { if (value !== void 0) { return new Color([...this.color, Math.max(0, Math.min(1, value))], this.model); } return this.valpha; }, // Rgb red: getset("rgb", 0, maxfn(255)), green: getset("rgb", 1, maxfn(255)), blue: getset("rgb", 2, maxfn(255)), hue: getset(["hsl", "hsv", "hsl", "hwb", "hcg"], 0, (value) => (value % 360 + 360) % 360), saturationl: getset("hsl", 1, maxfn(100)), lightness: getset("hsl", 2, maxfn(100)), saturationv: getset("hsv", 1, maxfn(100)), value: getset("hsv", 2, maxfn(100)), chroma: getset("hcg", 1, maxfn(100)), gray: getset("hcg", 2, maxfn(100)), white: getset("hwb", 1, maxfn(100)), wblack: getset("hwb", 2, maxfn(100)), cyan: getset("cmyk", 0, maxfn(100)), magenta: getset("cmyk", 1, maxfn(100)), yellow: getset("cmyk", 2, maxfn(100)), black: getset("cmyk", 3, maxfn(100)), x: getset("xyz", 0, maxfn(95.047)), y: getset("xyz", 1, maxfn(100)), z: getset("xyz", 2, maxfn(108.833)), l: getset("lab", 0, maxfn(100)), a: getset("lab", 1), b: getset("lab", 2), keyword(value) { if (value !== void 0) { return new Color(value); } return color_convert_default[this.model].keyword(this.color); }, hex(value) { if (value !== void 0) { return new Color(value); } return color_string_default.to.hex(...this.rgb().round().color); }, hexa(value) { if (value !== void 0) { return new Color(value); } const rgbArray = this.rgb().round().color; let alphaHex = Math.round(this.valpha * 255).toString(16).toUpperCase(); if (alphaHex.length === 1) { alphaHex = "0" + alphaHex; } return color_string_default.to.hex(...rgbArray) + alphaHex; }, rgbNumber() { const rgb = this.rgb().color; return (rgb[0] & 255) << 16 | (rgb[1] & 255) << 8 | rgb[2] & 255; }, luminosity() { const rgb = this.rgb().color; const lum = []; for (const [i, element] of rgb.entries()) { const chan = element / 255; lum[i] = chan <= 0.04045 ? chan / 12.92 : ((chan + 0.055) / 1.055) ** 2.4; } return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2]; }, contrast(color2) { const lum1 = this.luminosity(); const lum2 = color2.luminosity(); if (lum1 > lum2) { return (lum1 + 0.05) / (lum2 + 0.05); } return (lum2 + 0.05) / (lum1 + 0.05); }, level(color2) { const contrastRatio = this.contrast(color2); if (contrastRatio >= 7) { return "AAA"; } return contrastRatio >= 4.5 ? "AA" : ""; }, isDark() { const rgb = this.rgb().color; const yiq = (rgb[0] * 2126 + rgb[1] * 7152 + rgb[2] * 722) / 1e4; return yiq < 128; }, isLight() { return !this.isDark(); }, negate() { const rgb = this.rgb(); for (let i = 0; i < 3; i++) { rgb.color[i] = 255 - rgb.color[i]; } return rgb; }, lighten(ratio) { const hsl = this.hsl(); hsl.color[2] += hsl.color[2] * ratio; return hsl; }, darken(ratio) { const hsl = this.hsl(); hsl.color[2] -= hsl.color[2] * ratio; return hsl; }, saturate(ratio) { const hsl = this.hsl(); hsl.color[1] += hsl.color[1] * ratio; return hsl; }, desaturate(ratio) { const hsl = this.hsl(); hsl.color[1] -= hsl.color[1] * ratio; return hsl; }, whiten(ratio) { const hwb = this.hwb(); hwb.color[1] += hwb.color[1] * ratio; return hwb; }, blacken(ratio) { const hwb = this.hwb(); hwb.color[2] += hwb.color[2] * ratio; return hwb; }, grayscale() { const rgb = this.rgb().color; const value = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11; return Color.rgb(value, value, value); }, fade(ratio) { return this.alpha(this.valpha - this.valpha * ratio); }, opaquer(ratio) { return this.alpha(this.valpha + this.valpha * ratio); }, rotate(degrees) { const hsl = this.hsl(); let hue = hsl.color[0]; hue = (hue + degrees) % 360; hue = hue < 0 ? 360 + hue : hue; hsl.color[0] = hue; return hsl; }, mix(mixinColor, weight) { if (!mixinColor || !mixinColor.rgb) { throw new Error('Argument to "mix" was not a Color instance, but rather an instance of ' + typeof mixinColor); } const color1 = mixinColor.rgb(); const color2 = this.rgb(); const p = weight === void 0 ? 0.5 : weight; const w = 2 * p - 1; const a = color1.alpha() - color2.alpha(); const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2; const w2 = 1 - w1; return Color.rgb( w1 * color1.red() + w2 * color2.red(), w1 * color1.green() + w2 * color2.green(), w1 * color1.blue() + w2 * color2.blue(), color1.alpha() * p + color2.alpha() * (1 - p) ); } }; for (const model of Object.keys(color_convert_default)) { if (skippedModels.includes(model)) { continue; } const { channels } = color_convert_default[model]; Color.prototype[model] = function(...arguments_) { if (this.model === model) { return new Color(this); } if (arguments_.length > 0) { return new Color(arguments_, model); } return new Color([...assertArray(color_convert_default[this.model][model].raw(this.color)), this.valpha], model); }; Color[model] = function(...arguments_) { let color = arguments_[0]; if (typeof color === "number") { color = zeroArray(arguments_, channels); } return new Color(color, model); }; } function roundTo(number, places) { return Number(number.toFixed(places)); } function roundToPlace(places) { return function(number) { return roundTo(number, places); }; } function getset(model, channel, modifier) { model = Array.isArray(model) ? model : [model]; for (const m of model) { (limiters[m] || (limiters[m] = []))[channel] = modifier; } model = model[0]; return function(value) { let result; if (value !== void 0) { if (modifier) { value = modifier(value); } result = this[model](); result.color[channel] = value; return result; } result = this[model]().color[channel]; if (modifier) { result = modifier(result); } return result; }; } function maxfn(max) { return function(v) { return Math.max(0, Math.min(max, v)); }; } function assertArray(value) { return Array.isArray(value) ? value : [value]; } function zeroArray(array, length) { for (let i = 0; i < length; i++) { if (typeof array[i] !== "number") { array[i] = 0; } } return array; } var color_default = Color; // src/utils/colors.ts var import_state6 = require("@codemirror/state"); var import_language8 = require("@codemirror/language"); // src/codemirror-extensions/inline-css.ts var inlineCssLanguage = cssLanguage.configure({ top: "Styles" }); // src/utils/colors.ts function findColorValues(state) { const matches = []; const tree = (0, import_language8.syntaxTree)(state); const doc = state.doc; tree.cursor().iterate((nodeRef) => { const { node } = nodeRef; const nodeText = doc.sliceString(node.from, node.to); if (isColorValue(node.name, nodeText)) { matches.push({ from: node.from, to: node.to, color: nodeText }); } else if (node.name === "Comment") { const commentMatches = findColorsInComment(nodeText, node.from); matches.push(...commentMatches); } }); return matches.sort((a, b) => a.from - b.from); } function convertToColorModel(color, model) { switch (model) { case "rgb": return convertToRgb(color); case "hsl": return convertToHsl(color); case "hex": return convertToHex(color); default: return color; } } function getColorModel(color) { try { if (color.startsWith("#")) return "hex"; if (isValidColorName(color)) return "hex"; return color_default(color).toJSON().model; } catch (e) { return "hex"; } } function convertToHex(color) { try { return color_default(color).hex().toLowerCase(); } catch (e) { return color; } } function convertToRgb(color) { try { return color_default(color).rgb().toString(); } catch (e) { return color; } } function convertToHsl(color) { try { return color_default(color).hsl().round().toString(); } catch (e) { return color; } } function isColorValue(nodeName, nodeText) { switch (nodeName) { case "ColorLiteral": return true; case "ValueName": return isValidColorName(nodeText); case "CallExpression": return /^(rgb|rgba|hsl|hsla|hwb)\s*\(/.test(nodeText); default: return false; } } var validColorNames = /* @__PURE__ */ new Set([ "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "green", "greenyellow", "grey", "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen" ]); function isValidColorName(name) { return validColorNames.has(name.toLowerCase()); } function findColorsInComment(commentText, commentStart) { var _a, _b; const matches = []; const withoutDelimiters = commentText.replace(/^\/\*|\*\/$/g, ""); const content = withoutDelimiters.trim(); if (!content) { return matches; } const leadingWhitespaceMatch = withoutDelimiters.match(/^(\s*)/); const leadingWhitespaceLength = leadingWhitespaceMatch ? (_b = (_a = leadingWhitespaceMatch[1]) == null ? void 0 : _a.length) != null ? _b : 0 : 0; const totalOffset = 2 + leadingWhitespaceLength; try { const commentState = import_state6.EditorState.create({ doc: content, extensions: [inlineCssLanguage] }); const commentTree = (0, import_language8.syntaxTree)(commentState); const commentDoc = commentState.doc; commentTree.cursor().iterate((nodeRef) => { const { node } = nodeRef; const nodeText = commentDoc.sliceString(node.from, node.to); if (isColorValue(node.name, nodeText)) { const absoluteStart = commentStart + node.from + totalOffset; const absoluteEnd = commentStart + node.to + totalOffset; matches.push({ from: absoluteStart, to: absoluteEnd, color: nodeText }); } }); } catch (error) { console.warn( "Failed to parse comment as CSS, skipping color detection:", error ); } return matches; } // src/codemirror-extensions/color-picker.ts var ColorPickerWidget = class extends import_view7.WidgetType { constructor(color, from, to, view) { super(); this.color = color; this.from = from; this.to = to; this.view = view; } eq(other) { return this.color === other.color && this.from === other.from && this.to === other.to; } toDOM() { const wrapper = document.createElement("span"); wrapper.className = "css-editor-color-picker-wrapper"; new import_obsidian4.ColorComponent(wrapper).setValue(convertToHex(this.color)).onChange((newColor) => { const model = getColorModel(this.color); this.view.dispatch({ changes: { from: this.from, to: this.to, insert: convertToColorModel(newColor, model) } }); }); return wrapper; } }; var colorPickerPlugin = import_view7.ViewPlugin.fromClass( class { constructor(view) { this.decorations = this.buildDecorations(view); } update(update) { if (update.docChanged || update.viewportChanged) { this.decorations = this.buildDecorations(update.view); } } buildDecorations(view) { const builder = new Array(); const doc = view.state.doc; if (!doc || doc.length === 0) { return import_view7.Decoration.set([]); } const colorMatches = findColorValues(view.state); for (const match of colorMatches) { if (match.from < 0 || match.to > doc.length || match.from >= match.to) { continue; } const line = doc.lineAt(match.from); if (view.viewport.from <= line.to && line.from <= view.viewport.to) { const decoration = import_view7.Decoration.widget({ widget: new ColorPickerWidget( match.color, match.from, match.to, view ), side: 1 }); builder.push(decoration.range(match.to)); } } return import_view7.Decoration.set(builder); } destroy() { this.decorations = import_view7.Decoration.set([]); } }, { decorations: (v) => v.decorations } ); // src/obsidian/workspace-helpers.ts var import_obsidian5 = require("obsidian"); async function openView(workspace, type, openInNewTab, state) { const leaf = workspace.getLeaf(openInNewTab); await leaf.setViewState({ type, state }); workspace.setActiveLeaf(leaf); } async function detachCssFileLeaves(workspace, file) { var _a; const leaves = workspace.getLeavesOfType(VIEW_TYPE_CSS); for (const leaf of leaves) { if ((0, import_obsidian5.requireApiVersion)("1.7.2")) { await leaf.loadIfDeferred(); } if (((_a = leaf.getViewState().state) == null ? void 0 : _a.file) === file.name) { leaf.detach(); } } } // src/modals/CssSnippetDeleteConfirmModal.ts var import_obsidian6 = require("obsidian"); var CssSnippetDeleteConfirmModal = class extends import_obsidian6.Modal { constructor(app, plugin, file) { super(app); this.plugin = plugin; this.file = file; } async onOpen() { await super.onOpen(); this.titleEl.setText("Delete CSS snippet"); this.containerEl.addClass("css-editor-delete-confirm-modal"); this.buildForm(); } buildForm() { this.contentEl.createEl("p", { text: `Are you sure you want to delete "${this.file.name}"?` }); this.contentEl.createEl("p", { text: "This action cannot be undone." }); const buttonContainer = this.contentEl.createDiv( "modal-button-container" ); const dontAskAgainLabel = buttonContainer.createEl("label", { cls: "mod-checkbox" }); const dontAskAgainCheckbox = dontAskAgainLabel.createEl("input", { type: "checkbox" }); dontAskAgainCheckbox.insertAdjacentText("afterend", "Don't ask again"); new import_obsidian6.ButtonComponent(buttonContainer).setButtonText("Delete").setWarning().onClick(() => this.delete()); new import_obsidian6.ButtonComponent(buttonContainer).setButtonText("Cancel").onClick(() => this.close()); } async delete() { try { const dontAskAgain = this.contentEl.querySelector( 'input[type="checkbox"]' ); if (dontAskAgain == null ? void 0 : dontAskAgain.checked) { this.plugin.settings.promptDelete = false; await this.plugin.saveSettings(); } await detachCssFileLeaves(this.app.workspace, this.file); await deleteSnippetFile(this.app, this.file); this.close(); } catch (err) { handleError(err, "Failed to delete CSS file."); } } }; // src/views/CssEditorView.ts var VIEW_TYPE_CSS = "css-editor-view"; var CssEditorView = class extends import_obsidian7.ItemView { constructor(leaf, plugin) { var _a, _b; super(leaf); this.file = null; this.isSavingTitle = false; /** If the editor contents differ from the file contents on disk */ this.isEditorDirty = false; this.requestSave = (0, import_obsidian7.debounce)(this.save.bind(this), 1e3); this.plugin = plugin; this.navigation = true; this.editor = new import_view8.EditorView({ parent: this.contentEl, extensions: [ basicExtensions, lineWrap.of( this.plugin.settings.lineWrap ? import_view8.EditorView.lineWrapping : [] ), indentSize.of( import_language9.indentUnit.of("".padEnd(this.plugin.settings.indentSize)) ), historyCompartment.of((0, import_commands3.history)()), colorPickerPlugin, relativeLineNumberGutter.of( (0, import_view8.lineNumbers)({ formatNumber: this.plugin.settings.relativeLineNumbers ? relativeLineNumbersFormatter : absoluteLineNumbers }) ), ((_b = (_a = this.app.vault).getConfig) == null ? void 0 : _b.call(_a, "vimMode")) ? vim() : [], import_view8.EditorView.updateListener.of((update) => { if (update.docChanged) { this.isEditorDirty = true; this.requestSave(update.state.doc.toString()); if (this.file) { this.app.workspace.trigger( "css-editor-change", this.file, update.state.doc.toString() ); } } }) ] }); this.scope = new import_obsidian7.Scope(this.app.scope); this.scope.register(null, "F2", () => { if (!this.file) return; if (this.titleEl.isShown()) { focusAndSelectElement(this.titleEl); } else { new CssSnippetRenameModal(this.app, this.file).open(); } }); } getViewType() { return VIEW_TYPE_CSS; } getIcon() { return "file-code"; } getDisplayText() { var _a, _b; return (_b = (_a = this.file) == null ? void 0 : _a.basename) != null ? _b : "No file open"; } // eslint-disable-next-line @typescript-eslint/require-await async onOpen() { const timer = window.setInterval(() => { this.editor.focus(); if (this.editor.hasFocus) clearInterval(timer); }, 200); this.registerInterval(timer); if (import_obsidian7.Platform.isMobileApp) { this.titleEl.addEventListener("touchstart", () => { this.titleEl.contentEditable = "true"; }); } else { this.titleEl.contentEditable = "true"; } this.titleEl.addEventListener("focus", this.onTitleFocus.bind(this)); this.titleEl.addEventListener("blur", this.onTitleBlur.bind(this)); this.titleEl.addEventListener( "keydown", this.onTitleKeydown.bind(this) ); this.registerEvent( this.app.workspace.on("css-editor-change", (file, data) => { var _a; if (((_a = this.file) == null ? void 0 : _a.name) === file.name && this.getEditorData() !== data) { this.dispatchEditorData(data); } }) ); this.registerEvent( this.app.workspace.on("css-snippet-rename", (file, oldFileName) => { var _a; if (((_a = this.file) == null ? void 0 : _a.name) === oldFileName) { this.file = file; this.titleEl.setText(this.getDisplayText()); this.leaf.updateHeader(); this.app.workspace.requestSaveLayout(); } }) ); this.registerEvent( this.app.workspace.on("css-change", async (data) => { if (!this.file) return; if (typeof data === "object" && data !== null && "source" in data && (data == null ? void 0 : data.source) === "style-settings") { return; } if (this.isEditorDirty) { this.isEditorDirty = false; return; } const contents = await readSnippetFile(this.app, this.file); if (contents !== this.getEditorData()) { this.dispatchEditorData(contents); } }) ); this.registerEvent( this.app.workspace.on("leaf-menu", (menu, leaf) => { if (leaf === this.leaf && !!this.file) { menu.addItem((item) => { item.setIcon("lucide-edit-3").setSection("action").setTitle("Rename...").onClick(() => { if (this.file) { new CssSnippetRenameModal( this.app, this.file ).open(); } }); }); menu.addItem((item) => { const isEnabled = this.isEnabled(); item.setIcon( isEnabled ? "lucide-toggle-left" : "lucide-toggle-right" ).setSection("action").setTitle( isEnabled ? "Disable snippet" : "Enable snippet" ).onClick(() => { if (this.file) { toggleSnippetFileState(this.app, this.file); } }); }); menu.addItem((item) => { item.setIcon("lucide-trash-2").setSection("danger").setTitle("Delete snippet").setWarning(true).onClick(async () => { if (this.file) { if (this.plugin.settings.promptDelete) { new CssSnippetDeleteConfirmModal( this.app, this.plugin, this.file ).open(); } else { try { await detachCssFileLeaves( this.app.workspace, this.file ); await deleteSnippetFile( this.app, this.file ); } catch (err) { handleError( err, "Failed to delete CSS file." ); } } } }); }); } }) ); } onTitleFocus() { var _a, _b; this.titleEl.spellcheck = ((_b = (_a = this.app.vault).getConfig) == null ? void 0 : _b.call(_a, "spellcheck")) === true; } onTitleBlur() { this.saveTitle(this.titleEl).catch(handleError); this.titleEl.spellcheck = false; if (import_obsidian7.Platform.isMobileApp) { this.titleEl.contentEditable = "false"; } this.editor.focus(); } onTitleKeydown(event) { if (!this.file) return; if (event.isComposing) return; if (event.key === "Escape") { this.titleEl.setText(this.getDisplayText()); this.titleEl.blur(); } if (event.key === "Enter" || event.key === "Tab") { event.preventDefault(); this.saveTitle(this.titleEl).catch(handleError); this.titleEl.blur(); } } async saveTitle(el) { if (!this.file) return; const newTitle = el.getText().trim(); if (newTitle === this.file.basename) return; if (this.isSavingTitle) return; this.isSavingTitle = true; await renameSnippetFile(this.app, this.file, newTitle); this.isSavingTitle = false; } getEditorData() { return this.editor.state.doc.toString(); } dispatchEditorTransaction(...specs) { this.editor.dispatch(...specs); } dispatchEditorData(data) { this.editor.dispatch({ changes: { from: 0, to: this.editor.state.doc.length, insert: data } }); } getState() { var _a; return { file: (_a = this.file) == null ? void 0 : _a.name }; } async setState(state, result) { var _a; let file = null; if (state && typeof state === "object") { if ("filename" in state && typeof state.filename === "string") { file = new CssFile(state.filename); } if ("file" in state) { if (state.file instanceof CssFile) { file = state.file; } else if (typeof state.file === "string") { file = new CssFile(state.file); } } } if (file) { if (file.name !== ((_a = this.file) == null ? void 0 : _a.name)) { try { await this.loadFile(file); } catch (e) { await this.loadFile(null); } } } else { await this.loadFile(null); } result.history = true; return super.setState({ file: file == null ? void 0 : file.name }, result); } async loadFile(file) { this.file = file; this.titleEl.setText(this.getDisplayText()); this.leaf.updateHeader(); const data = file ? await readSnippetFile(this.app, file) : ""; this.dispatchEditorData(data); this.resetHistory(); this.app.workspace.requestSaveLayout(); } resetHistory() { this.editor.dispatch({ effects: [historyCompartment.reconfigure([])] }); this.editor.dispatch({ effects: [historyCompartment.reconfigure((0, import_commands3.history)())] }); } isEnabled() { var _a, _b; if (!this.file) return false; const currentState = (_b = (_a = this.app.customCss) == null ? void 0 : _a.enabledSnippets) == null ? void 0 : _b.has( this.file.basename ); return currentState || false; } /** * You should almost always call `requestSave` instead of `save` to debounce the saving. */ async save(data) { if (this.file) { await writeSnippetFile(this.app, this.file, data); } } // eslint-disable-next-line @typescript-eslint/require-await async onClose() { this.editor.destroy(); } }; // src/modals/CssSnippetFuzzySuggestModal.ts var import_obsidian8 = require("obsidian"); var CssSnippetFuzzySuggestModal = class extends import_obsidian8.FuzzySuggestModal { constructor(app, plugin) { super(app); this.plugin = plugin; this.scope.register(["Mod"], "Enter", (evt) => { var _a, _b; if (!evt.isComposing && ((_b = (_a = this.chooser) == null ? void 0 : _a.useSelectedItem) == null ? void 0 : _b.call(_a, evt))) { return false; } return true; }); this.scope.register(["Shift"], "Enter", (evt) => { this.selectSuggestion( { item: new CssFile(this.inputEl.value), match: { score: 0, matches: [] } }, evt ); return false; }); this.scope.register(["Mod"], "Delete", (evt) => { var _a, _b; if (!evt.isComposing && ((_b = (_a = this.chooser) == null ? void 0 : _a.useSelectedItem) == null ? void 0 : _b.call(_a, evt))) { return false; } return true; }); this.scope.register([], "Tab", (evt) => { var _a, _b; if (this.chooser) { const selectedItem = this.chooser.selectedItem; const file = (_a = this.chooser.values[selectedItem]) == null ? void 0 : _a.item; if (!file) return false; const isEnabled = toggleSnippetFileState(this.app, file); const buttonEl = (_b = this.chooser.suggestions[selectedItem]) == null ? void 0 : _b.querySelector( ".css-editor-status" ); buttonEl == null ? void 0 : buttonEl.setText(isEnabled ? "enabled" : "disabled"); buttonEl == null ? void 0 : buttonEl.toggleClass("mod-cta", isEnabled); } return false; }); this.containerEl.addClass("css-editor-quick-switcher-modal"); this.setPlaceholder("Find or create a CSS snippet..."); this.setInstructions([ { command: "\u2191\u2193", purpose: "to navigate" }, { command: import_obsidian8.Platform.isMacOS ? "\u2318 \u21B5" : "ctrl \u21B5", purpose: "to open in new tab" }, { command: "shift \u21B5", purpose: "to create" }, { command: import_obsidian8.Platform.isMacOS ? "\u2318 del" : "ctrl del", purpose: "to delete" }, { command: "tab", purpose: "to enable/disable" }, { command: "esc", purpose: "to dismiss" } ]); } isEnabled(item) { var _a, _b; const currentState = (_b = (_a = this.app.customCss) == null ? void 0 : _a.enabledSnippets) == null ? void 0 : _b.has( item.basename ); return currentState || false; } getItems() { var _a; if ((_a = this.app.customCss) == null ? void 0 : _a.snippets) { return this.app.customCss.snippets.map((x) => new CssFile(x)); } return []; } getItemText(item) { return item.name; } renderSuggestion(item, el) { super.renderSuggestion(item, el); el.addClass("mod-complex"); if (el.hasChildNodes()) { const existingChildren = Array.from(el.childNodes); el.childNodes.forEach((child) => { el.removeChild(child); }); el.appendChild( createDiv( { cls: "suggestion-content" }, (suggestionContentEl) => { suggestionContentEl.appendChild( createDiv( { cls: "css-editor-suggestion-name" }, (nestedEl) => { existingChildren.forEach((child) => { nestedEl.appendChild(child); }); } ) ); suggestionContentEl.appendChild( createDiv( { cls: "css-editor-suggestion-description" }, (el2) => el2.appendText( `${getSnippetDirectory(this.app)}${item.item.name}` ) ) ); } ) ); const isEnabled = this.isEnabled(item.item); const isNewElement = this.inputEl.value.trim().length > 0 && item.match.score === 0; if (!isNewElement) { const button = new import_obsidian8.ButtonComponent(el).setButtonText(isEnabled ? "enabled" : "disabled").setClass("css-editor-status").onClick((e) => { e.stopPropagation(); const newState = toggleSnippetFileState( this.app, item.item ); button.setButtonText(newState ? "enabled" : "disabled"); if (newState) { button.setCta(); } else { button.removeCta(); } }); if (isEnabled) { button.setCta(); } } } if (this.inputEl.value.trim().length > 0 && item.match.score === 0) { el.appendChild( createDiv({ cls: "suggestion-aux" }, (el2) => { el2.appendChild( createSpan({ cls: "suggestion-hotkey" }, (el3) => { el3.appendText("Enter to create"); }) ); }) ); } } selectSuggestion(value, evt) { try { this.onChooseSuggestion(value, evt); this.close(); } catch (err) { handleError(err, "Failed to open CSS file."); } } onChooseSuggestion(item, evt) { const isCreateNewDueToNoSuggestion = this.inputEl.value.trim().length > 0 && item.match.score === 0; if (isCreateNewDueToNoSuggestion && item.item) { const openInNewTab = evt.metaKey; this.plugin.createAndOpenSnippet(item.item.name, openInNewTab).catch((err) => { handleError(err, "Failed to create and open CSS file."); }); } else { this.onChooseItem(item.item, evt); } } onNoSuggestion() { var _a, _b, _c, _d, _e, _f, _g, _h; const item = this.inputEl.value.trim(); if (item.length > 0) { (_b = (_a = this.chooser) == null ? void 0 : _a.setSuggestions) == null ? void 0 : _b.call(_a, [ { item: new CssFile(item), match: { score: 0, matches: [] } } ]); (_d = (_c = this.chooser) == null ? void 0 : _c.addMessage) == null ? void 0 : _d.call( _c, "No CSS snippets found. Enter to create a new one." ); } else { (_f = (_e = this.chooser) == null ? void 0 : _e.setSuggestions) == null ? void 0 : _f.call(_e, []); (_h = (_g = this.chooser) == null ? void 0 : _g.addMessage) == null ? void 0 : _h.call( _g, "No CSS snippets found. Type to search..." ); } } onChooseItem(item, evt) { if (!item) return; if (evt instanceof KeyboardEvent) { if (evt.key === "Enter") { const openInNewTab = evt.metaKey; if (evt.shiftKey) { this.plugin.createAndOpenSnippet(item.name, openInNewTab).catch((err) => { handleError( err, "Failed to create and open CSS file." ); }); } else { openView(this.app.workspace, VIEW_TYPE_CSS, openInNewTab, { file: item }).catch(handleError); } } else if (evt.key === "Delete") { if (this.plugin.settings.promptDelete) { new CssSnippetDeleteConfirmModal( this.app, this.plugin, item ).open(); } else { Promise.all([ detachCssFileLeaves(this.app.workspace, item), deleteSnippetFile(this.app, item) ]).then(() => { new import_obsidian8.Notice(`${item.name} was deleted.`); }).catch((err) => { handleError(err, "Failed to delete CSS file."); }); } } } else { const openInNewTab = evt.metaKey; openView(this.app.workspace, VIEW_TYPE_CSS, openInNewTab, { file: item }).catch(handleError); } } }; // node_modules/monkey-around/mjs/index.js function around(obj, factories) { const removers = Object.keys(factories).map((key) => around1(obj, key, factories[key])); return removers.length === 1 ? removers[0] : function() { removers.forEach((r) => r()); }; } function around1(obj, method, createWrapper) { const original = obj[method], hadOwn = obj.hasOwnProperty(method); let current = createWrapper(original); if (original) Object.setPrototypeOf(current, original); Object.setPrototypeOf(wrapper, current); obj[method] = wrapper; return remove; function wrapper(...args) { if (current === original && obj[method] === wrapper) remove(); return current.apply(this, args); } function remove() { if (obj[method] === wrapper) { if (hadOwn) obj[method] = original; else delete obj[method]; } if (current === original) return; current = original; Object.setPrototypeOf(wrapper, original || Function); } } // src/obsidian/ignore-obsidian-hotkey.ts function ignoreObsidianHotkey(scope, keymapInfo, checkCallback) { const uninstallCommand = around(scope, { handleKey(originalMethod) { return function(...args) { const invokedHotkey = args[1]; if (isKeymapInfo(invokedHotkey) && keymapInfo.key === invokedHotkey.key && keymapInfo.modifiers === invokedHotkey.modifiers && checkCallback()) { return true; } const result = originalMethod && originalMethod.apply(this, args); return result; }; } }); return uninstallCommand; } function isKeymapInfo(hotkey) { return !!hotkey && typeof hotkey === "object" && "key" in hotkey && typeof hotkey.key === "string" && "modifiers" in hotkey; } // src/modals/CssSnippetCreateModal.ts var import_obsidian9 = require("obsidian"); var CssSnippetCreateModal = class extends import_obsidian9.Modal { constructor(app, plugin) { super(app); this.value = ""; this.plugin = plugin; } async onOpen() { await super.onOpen(); this.titleEl.setText("Create CSS snippet"); this.containerEl.addClass("css-editor-create-modal"); this.buildForm(); } buildForm() { const textInput = new import_obsidian9.TextComponent(this.contentEl); textInput.setPlaceholder("CSS snippet file name (ex: snippet.css)"); textInput.onChange((val) => this.value = val); textInput.inputEl.addEventListener("keydown", (evt) => { this.handleKeydown(evt).catch(handleError); }); const buttonContainer = this.contentEl.createDiv( "modal-button-container" ); new import_obsidian9.ButtonComponent(buttonContainer).setButtonText("Save").setCta().onClick(() => this.save()); new import_obsidian9.ButtonComponent(buttonContainer).setButtonText("Cancel").onClick(() => this.close()); } async handleKeydown(evt) { if (evt.key === "Escape") { this.close(); } else if (evt.key === "Enter") { await this.save(evt.metaKey); } } async save(openInNewTab = false) { try { await this.plugin.createAndOpenSnippet(this.value, openInNewTab); this.close(); } catch (err) { handleError(err, "Failed to create and open CSS file."); } } }; // src/obsidian/setting-tab.ts var import_language10 = require("@codemirror/language"); var import_view9 = require("@codemirror/view"); var import_obsidian10 = require("obsidian"); function updateCSSEditorView(app, spec) { app.workspace.getLeavesOfType(VIEW_TYPE_CSS).forEach((leaf) => { if (leaf.view instanceof CssEditorView) { leaf.view.dispatchEditorTransaction(spec); } }); } var CSSEditorSettingTab = class extends import_obsidian10.PluginSettingTab { constructor(app, plugin) { super(app, plugin); this.plugin = plugin; } display() { this.containerEl.empty(); new import_obsidian10.Setting(this.containerEl).setName("Confirm CSS snippet deletion").setDesc("Prompt before CSS snippet deletion.").addToggle((toggle) => { toggle.setValue(this.plugin.settings.promptDelete); toggle.onChange(async (val) => { this.plugin.settings.promptDelete = val; await this.plugin.saveSettings(); }); }); new import_obsidian10.Setting(this.containerEl).setName("Line wrap").setDesc("Toggle line wrap in the editor.").addToggle((toggle) => { toggle.setValue(this.plugin.settings.lineWrap); toggle.onChange(async (val) => { this.plugin.settings.lineWrap = val; await this.plugin.saveSettings(); updateCSSEditorView(this.app, { effects: lineWrap.reconfigure( val ? import_view9.EditorView.lineWrapping : [] ) }); }); }); new import_obsidian10.Setting(this.containerEl).setName("Indent size").setDesc("Adjust the amount of spaces used for indentation.").addText((field) => { field.setPlaceholder("2"); field.setValue(this.plugin.settings.indentSize.toString()); field.onChange(async (val) => { val = val.replace(/\D/g, ""); field.setValue(val); const size = parseInt(val); this.plugin.settings.indentSize = size; await this.plugin.saveSettings(); updateCSSEditorView(this.app, { effects: indentSize.reconfigure( import_language10.indentUnit.of("".padEnd(size)) ) }); }); }); new import_obsidian10.Setting(this.containerEl).setName("Relative line numbers").setDesc("Show line numbers relative to cursor position.").addToggle((toggle) => { toggle.setValue(this.plugin.settings.relativeLineNumbers); toggle.onChange(async (val) => { this.plugin.settings.relativeLineNumbers = val; await this.plugin.saveSettings(); updateCSSEditorView(this.app, { effects: relativeLineNumberGutter.reconfigure( (0, import_view9.lineNumbers)({ formatNumber: val ? relativeLineNumbersFormatter : absoluteLineNumbers }) ) }); }); }); } }; // src/main.ts var DEFAULT_SETTINGS = { promptDelete: true, lineWrap: true, indentSize: 2, relativeLineNumbers: false }; var CssEditorPlugin = class extends import_obsidian11.Plugin { async onload() { await this.loadSettings(); this.addCommand({ id: "create-css-snippet", name: "Create CSS snippet", callback: () => { new CssSnippetCreateModal(this.app, this).open(); } }); this.addCommand({ id: "open-quick-switcher", name: "Open quick switcher", callback: () => { new CssSnippetFuzzySuggestModal(this.app, this).open(); } }); this.addCommand({ id: "delete-css-snippet", name: "Delete CSS snippet", checkCallback: (checking) => { const activeCssEditorView = this.app.workspace.getActiveViewOfType(CssEditorView); if (!activeCssEditorView) return false; const { file } = activeCssEditorView.getState(); if (!file) return false; if (checking) return true; const cssFile = new CssFile(file); if (this.settings.promptDelete) { new CssSnippetDeleteConfirmModal( this.app, this, cssFile ).open(); } else { detachCssFileLeaves(this.app.workspace, cssFile).then(async () => { await deleteSnippetFile(this.app, cssFile); new import_obsidian11.Notice(`"${cssFile.name}" was deleted.`); }).catch((err) => { handleError(err, "Failed to delete CSS file."); }); } return true; } }); this.addCommand({ id: "toggle-css-snippet-enabled-status", name: "Toggle the enabled/disabled state of CSS snippet", checkCallback: (checking) => { const activeCssEditorView = this.app.workspace.getActiveViewOfType(CssEditorView); if (!activeCssEditorView) return false; const { file } = activeCssEditorView.getState(); if (!file) return false; if (checking) return true; const cssFile = new CssFile(file); const isEnabled = toggleSnippetFileState(this.app, cssFile); new import_obsidian11.Notice( `"${cssFile.name}" is now ${isEnabled ? "enabled" : "disabled"}.` ); return true; } }); this.register( ignoreObsidianHotkey( this.app.scope, { key: "/", modifiers: "Meta" }, () => !!this.app.workspace.getActiveViewOfType(CssEditorView) ) ); this.registerView( VIEW_TYPE_CSS, (leaf) => new CssEditorView(leaf, this) ); this.settingTab = new CSSEditorSettingTab(this.app, this); this.addSettingTab(this.settingTab); } onunload() { } async loadSettings() { this.settings = Object.assign( {}, DEFAULT_SETTINGS, await this.loadData() ); } async saveSettings() { await this.saveData(this.settings); } async createAndOpenSnippet(filename, openInNewTab) { var _a, _b; const file = await createSnippetFile(this.app, filename, ""); (_b = (_a = this.app.customCss) == null ? void 0 : _a.setCssEnabledStatus) == null ? void 0 : _b.call(_a, file.basename, true); new import_obsidian11.Notice(`${file.name} was created.`); await openView(this.app.workspace, VIEW_TYPE_CSS, openInNewTab, { file }); } }; /* nosourcemap */