7580bcf90c3e2026e05b37255bf61c1f.js 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293
  1. ace.define("ace/snippets",["require","exports","module","ace/lib/dom","ace/lib/oop","ace/lib/event_emitter","ace/lib/lang","ace/range","ace/range_list","ace/keyboard/hash_handler","ace/tokenizer","ace/clipboard","ace/editor"], function(require, exports, module){"use strict";
  2. var dom = require("./lib/dom");
  3. var oop = require("./lib/oop");
  4. var EventEmitter = require("./lib/event_emitter").EventEmitter;
  5. var lang = require("./lib/lang");
  6. var Range = require("./range").Range;
  7. var RangeList = require("./range_list").RangeList;
  8. var HashHandler = require("./keyboard/hash_handler").HashHandler;
  9. var Tokenizer = require("./tokenizer").Tokenizer;
  10. var clipboard = require("./clipboard");
  11. var VARIABLES = {
  12. CURRENT_WORD: function (editor) {
  13. return editor.session.getTextRange(editor.session.getWordRange());
  14. },
  15. SELECTION: function (editor, name, indentation) {
  16. var text = editor.session.getTextRange();
  17. if (indentation)
  18. return text.replace(/\n\r?([ \t]*\S)/g, "\n" + indentation + "$1");
  19. return text;
  20. },
  21. CURRENT_LINE: function (editor) {
  22. return editor.session.getLine(editor.getCursorPosition().row);
  23. },
  24. PREV_LINE: function (editor) {
  25. return editor.session.getLine(editor.getCursorPosition().row - 1);
  26. },
  27. LINE_INDEX: function (editor) {
  28. return editor.getCursorPosition().row;
  29. },
  30. LINE_NUMBER: function (editor) {
  31. return editor.getCursorPosition().row + 1;
  32. },
  33. SOFT_TABS: function (editor) {
  34. return editor.session.getUseSoftTabs() ? "YES" : "NO";
  35. },
  36. TAB_SIZE: function (editor) {
  37. return editor.session.getTabSize();
  38. },
  39. CLIPBOARD: function (editor) {
  40. return clipboard.getText && clipboard.getText();
  41. },
  42. FILENAME: function (editor) {
  43. return /[^/\\]*$/.exec(this.FILEPATH(editor))[0];
  44. },
  45. FILENAME_BASE: function (editor) {
  46. return /[^/\\]*$/.exec(this.FILEPATH(editor))[0].replace(/\.[^.]*$/, "");
  47. },
  48. DIRECTORY: function (editor) {
  49. return this.FILEPATH(editor).replace(/[^/\\]*$/, "");
  50. },
  51. FILEPATH: function (editor) { return "/not implemented.txt"; },
  52. WORKSPACE_NAME: function () { return "Unknown"; },
  53. FULLNAME: function () { return "Unknown"; },
  54. BLOCK_COMMENT_START: function (editor) {
  55. var mode = editor.session.$mode || {};
  56. return mode.blockComment && mode.blockComment.start || "";
  57. },
  58. BLOCK_COMMENT_END: function (editor) {
  59. var mode = editor.session.$mode || {};
  60. return mode.blockComment && mode.blockComment.end || "";
  61. },
  62. LINE_COMMENT: function (editor) {
  63. var mode = editor.session.$mode || {};
  64. return mode.lineCommentStart || "";
  65. },
  66. CURRENT_YEAR: date.bind(null, { year: "numeric" }),
  67. CURRENT_YEAR_SHORT: date.bind(null, { year: "2-digit" }),
  68. CURRENT_MONTH: date.bind(null, { month: "numeric" }),
  69. CURRENT_MONTH_NAME: date.bind(null, { month: "long" }),
  70. CURRENT_MONTH_NAME_SHORT: date.bind(null, { month: "short" }),
  71. CURRENT_DATE: date.bind(null, { day: "2-digit" }),
  72. CURRENT_DAY_NAME: date.bind(null, { weekday: "long" }),
  73. CURRENT_DAY_NAME_SHORT: date.bind(null, { weekday: "short" }),
  74. CURRENT_HOUR: date.bind(null, { hour: "2-digit", hour12: false }),
  75. CURRENT_MINUTE: date.bind(null, { minute: "2-digit" }),
  76. CURRENT_SECOND: date.bind(null, { second: "2-digit" })
  77. };
  78. VARIABLES.SELECTED_TEXT = VARIABLES.SELECTION;
  79. function date(dateFormat) {
  80. var str = new Date().toLocaleString("en-us", dateFormat);
  81. return str.length == 1 ? "0" + str : str;
  82. }
  83. var SnippetManager = /** @class */ (function () {
  84. function SnippetManager() {
  85. this.snippetMap = {};
  86. this.snippetNameMap = {};
  87. this.variables = VARIABLES;
  88. }
  89. SnippetManager.prototype.getTokenizer = function () {
  90. return SnippetManager["$tokenizer"] || this.createTokenizer();
  91. };
  92. SnippetManager.prototype.createTokenizer = function () {
  93. function TabstopToken(str) {
  94. str = str.substr(1);
  95. if (/^\d+$/.test(str))
  96. return [{ tabstopId: parseInt(str, 10) }];
  97. return [{ text: str }];
  98. }
  99. function escape(ch) {
  100. return "(?:[^\\\\" + ch + "]|\\\\.)";
  101. }
  102. var formatMatcher = {
  103. regex: "/(" + escape("/") + "+)/",
  104. onMatch: function (val, state, stack) {
  105. var ts = stack[0];
  106. ts.fmtString = true;
  107. ts.guard = val.slice(1, -1);
  108. ts.flag = "";
  109. return "";
  110. },
  111. next: "formatString"
  112. };
  113. SnippetManager["$tokenizer"] = new Tokenizer({
  114. start: [
  115. { regex: /\\./, onMatch: function (val, state, stack) {
  116. var ch = val[1];
  117. if (ch == "}" && stack.length) {
  118. val = ch;
  119. }
  120. else if ("`$\\".indexOf(ch) != -1) {
  121. val = ch;
  122. }
  123. return [val];
  124. } },
  125. { regex: /}/, onMatch: function (val, state, stack) {
  126. return [stack.length ? stack.shift() : val];
  127. } },
  128. { regex: /\$(?:\d+|\w+)/, onMatch: TabstopToken },
  129. { regex: /\$\{[\dA-Z_a-z]+/, onMatch: function (str, state, stack) {
  130. var t = TabstopToken(str.substr(1));
  131. stack.unshift(t[0]);
  132. return t;
  133. }, next: "snippetVar" },
  134. { regex: /\n/, token: "newline", merge: false }
  135. ],
  136. snippetVar: [
  137. { regex: "\\|" + escape("\\|") + "*\\|", onMatch: function (val, state, stack) {
  138. var choices = val.slice(1, -1).replace(/\\[,|\\]|,/g, function (operator) {
  139. return operator.length == 2 ? operator[1] : "\x00";
  140. }).split("\x00").map(function (value) {
  141. return { value: value };
  142. });
  143. stack[0].choices = choices;
  144. return [choices[0]];
  145. }, next: "start" },
  146. formatMatcher,
  147. { regex: "([^:}\\\\]|\\\\.)*:?", token: "", next: "start" }
  148. ],
  149. formatString: [
  150. { regex: /:/, onMatch: function (val, state, stack) {
  151. if (stack.length && stack[0].expectElse) {
  152. stack[0].expectElse = false;
  153. stack[0].ifEnd = { elseEnd: stack[0] };
  154. return [stack[0].ifEnd];
  155. }
  156. return ":";
  157. } },
  158. { regex: /\\./, onMatch: function (val, state, stack) {
  159. var ch = val[1];
  160. if (ch == "}" && stack.length)
  161. val = ch;
  162. else if ("`$\\".indexOf(ch) != -1)
  163. val = ch;
  164. else if (ch == "n")
  165. val = "\n";
  166. else if (ch == "t")
  167. val = "\t";
  168. else if ("ulULE".indexOf(ch) != -1)
  169. val = { changeCase: ch, local: ch > "a" };
  170. return [val];
  171. } },
  172. { regex: "/\\w*}", onMatch: function (val, state, stack) {
  173. var next = stack.shift();
  174. if (next)
  175. next.flag = val.slice(1, -1);
  176. this.next = next && next.tabstopId ? "start" : "";
  177. return [next || val];
  178. }, next: "start" },
  179. { regex: /\$(?:\d+|\w+)/, onMatch: function (val, state, stack) {
  180. return [{ text: val.slice(1) }];
  181. } },
  182. { regex: /\${\w+/, onMatch: function (val, state, stack) {
  183. var token = { text: val.slice(2) };
  184. stack.unshift(token);
  185. return [token];
  186. }, next: "formatStringVar" },
  187. { regex: /\n/, token: "newline", merge: false },
  188. { regex: /}/, onMatch: function (val, state, stack) {
  189. var next = stack.shift();
  190. this.next = next && next.tabstopId ? "start" : "";
  191. return [next || val];
  192. }, next: "start" }
  193. ],
  194. formatStringVar: [
  195. { regex: /:\/\w+}/, onMatch: function (val, state, stack) {
  196. var ts = stack[0];
  197. ts.formatFunction = val.slice(2, -1);
  198. return [stack.shift()];
  199. }, next: "formatString" },
  200. formatMatcher,
  201. { regex: /:[\?\-+]?/, onMatch: function (val, state, stack) {
  202. if (val[1] == "+")
  203. stack[0].ifEnd = stack[0];
  204. if (val[1] == "?")
  205. stack[0].expectElse = true;
  206. }, next: "formatString" },
  207. { regex: "([^:}\\\\]|\\\\.)*:?", token: "", next: "formatString" }
  208. ]
  209. });
  210. return SnippetManager["$tokenizer"];
  211. };
  212. SnippetManager.prototype.tokenizeTmSnippet = function (str, startState) {
  213. return this.getTokenizer().getLineTokens(str, startState).tokens.map(function (x) {
  214. return x.value || x;
  215. });
  216. };
  217. SnippetManager.prototype.getVariableValue = function (editor, name, indentation) {
  218. if (/^\d+$/.test(name))
  219. return (this.variables.__ || {})[name] || "";
  220. if (/^[A-Z]\d+$/.test(name))
  221. return (this.variables[name[0] + "__"] || {})[name.substr(1)] || "";
  222. name = name.replace(/^TM_/, "");
  223. if (!this.variables.hasOwnProperty(name))
  224. return "";
  225. var value = this.variables[name];
  226. if (typeof value == "function")
  227. value = this.variables[name](editor, name, indentation);
  228. return value == null ? "" : value;
  229. };
  230. SnippetManager.prototype.tmStrFormat = function (str, ch, editor) {
  231. if (!ch.fmt)
  232. return str;
  233. var flag = ch.flag || "";
  234. var re = ch.guard;
  235. re = new RegExp(re, flag.replace(/[^gim]/g, ""));
  236. var fmtTokens = typeof ch.fmt == "string" ? this.tokenizeTmSnippet(ch.fmt, "formatString") : ch.fmt;
  237. var _self = this;
  238. var formatted = str.replace(re, function () {
  239. var oldArgs = _self.variables.__;
  240. _self.variables.__ = [].slice.call(arguments);
  241. var fmtParts = _self.resolveVariables(fmtTokens, editor);
  242. var gChangeCase = "E";
  243. for (var i = 0; i < fmtParts.length; i++) {
  244. var ch = fmtParts[i];
  245. if (typeof ch == "object") {
  246. fmtParts[i] = "";
  247. if (ch.changeCase && ch.local) {
  248. var next = fmtParts[i + 1];
  249. if (next && typeof next == "string") {
  250. if (ch.changeCase == "u")
  251. fmtParts[i] = next[0].toUpperCase();
  252. else
  253. fmtParts[i] = next[0].toLowerCase();
  254. fmtParts[i + 1] = next.substr(1);
  255. }
  256. }
  257. else if (ch.changeCase) {
  258. gChangeCase = ch.changeCase;
  259. }
  260. }
  261. else if (gChangeCase == "U") {
  262. fmtParts[i] = ch.toUpperCase();
  263. }
  264. else if (gChangeCase == "L") {
  265. fmtParts[i] = ch.toLowerCase();
  266. }
  267. }
  268. _self.variables.__ = oldArgs;
  269. return fmtParts.join("");
  270. });
  271. return formatted;
  272. };
  273. SnippetManager.prototype.tmFormatFunction = function (str, ch, editor) {
  274. if (ch.formatFunction == "upcase")
  275. return str.toUpperCase();
  276. if (ch.formatFunction == "downcase")
  277. return str.toLowerCase();
  278. return str;
  279. };
  280. SnippetManager.prototype.resolveVariables = function (snippet, editor) {
  281. var result = [];
  282. var indentation = "";
  283. var afterNewLine = true;
  284. for (var i = 0; i < snippet.length; i++) {
  285. var ch = snippet[i];
  286. if (typeof ch == "string") {
  287. result.push(ch);
  288. if (ch == "\n") {
  289. afterNewLine = true;
  290. indentation = "";
  291. }
  292. else if (afterNewLine) {
  293. indentation = /^\t*/.exec(ch)[0];
  294. afterNewLine = /\S/.test(ch);
  295. }
  296. continue;
  297. }
  298. if (!ch)
  299. continue;
  300. afterNewLine = false;
  301. if (ch.fmtString) {
  302. var j = snippet.indexOf(ch, i + 1);
  303. if (j == -1)
  304. j = snippet.length;
  305. ch.fmt = snippet.slice(i + 1, j);
  306. i = j;
  307. }
  308. if (ch.text) {
  309. var value = this.getVariableValue(editor, ch.text, indentation) + "";
  310. if (ch.fmtString)
  311. value = this.tmStrFormat(value, ch, editor);
  312. if (ch.formatFunction)
  313. value = this.tmFormatFunction(value, ch, editor);
  314. if (value && !ch.ifEnd) {
  315. result.push(value);
  316. gotoNext(ch);
  317. }
  318. else if (!value && ch.ifEnd) {
  319. gotoNext(ch.ifEnd);
  320. }
  321. }
  322. else if (ch.elseEnd) {
  323. gotoNext(ch.elseEnd);
  324. }
  325. else if (ch.tabstopId != null) {
  326. result.push(ch);
  327. }
  328. else if (ch.changeCase != null) {
  329. result.push(ch);
  330. }
  331. }
  332. function gotoNext(ch) {
  333. var i1 = snippet.indexOf(ch, i + 1);
  334. if (i1 != -1)
  335. i = i1;
  336. }
  337. return result;
  338. };
  339. SnippetManager.prototype.getDisplayTextForSnippet = function (editor, snippetText) {
  340. var processedSnippet = processSnippetText.call(this, editor, snippetText);
  341. return processedSnippet.text;
  342. };
  343. SnippetManager.prototype.insertSnippetForSelection = function (editor, snippetText, options) {
  344. if (options === void 0) { options = {}; }
  345. var processedSnippet = processSnippetText.call(this, editor, snippetText, options);
  346. var range = editor.getSelectionRange();
  347. var end = editor.session.replace(range, processedSnippet.text);
  348. var tabstopManager = new TabstopManager(editor);
  349. var selectionId = editor.inVirtualSelectionMode && editor.selection.index;
  350. tabstopManager.addTabstops(processedSnippet.tabstops, range.start, end, selectionId);
  351. };
  352. SnippetManager.prototype.insertSnippet = function (editor, snippetText, options) {
  353. if (options === void 0) { options = {}; }
  354. var self = this;
  355. if (editor.inVirtualSelectionMode)
  356. return self.insertSnippetForSelection(editor, snippetText, options);
  357. editor.forEachSelection(function () {
  358. self.insertSnippetForSelection(editor, snippetText, options);
  359. }, null, { keepOrder: true });
  360. if (editor.tabstopManager)
  361. editor.tabstopManager.tabNext();
  362. };
  363. SnippetManager.prototype.$getScope = function (editor) {
  364. var scope = editor.session.$mode.$id || "";
  365. scope = scope.split("/").pop();
  366. if (scope === "html" || scope === "php") {
  367. if (scope === "php" && !editor.session.$mode.inlinePhp)
  368. scope = "html";
  369. var c = editor.getCursorPosition();
  370. var state = editor.session.getState(c.row);
  371. if (typeof state === "object") {
  372. state = state[0];
  373. }
  374. if (state.substring) {
  375. if (state.substring(0, 3) == "js-")
  376. scope = "javascript";
  377. else if (state.substring(0, 4) == "css-")
  378. scope = "css";
  379. else if (state.substring(0, 4) == "php-")
  380. scope = "php";
  381. }
  382. }
  383. return scope;
  384. };
  385. SnippetManager.prototype.getActiveScopes = function (editor) {
  386. var scope = this.$getScope(editor);
  387. var scopes = [scope];
  388. var snippetMap = this.snippetMap;
  389. if (snippetMap[scope] && snippetMap[scope].includeScopes) {
  390. scopes.push.apply(scopes, snippetMap[scope].includeScopes);
  391. }
  392. scopes.push("_");
  393. return scopes;
  394. };
  395. SnippetManager.prototype.expandWithTab = function (editor, options) {
  396. var self = this;
  397. var result = editor.forEachSelection(function () {
  398. return self.expandSnippetForSelection(editor, options);
  399. }, null, { keepOrder: true });
  400. if (result && editor.tabstopManager)
  401. editor.tabstopManager.tabNext();
  402. return result;
  403. };
  404. SnippetManager.prototype.expandSnippetForSelection = function (editor, options) {
  405. var cursor = editor.getCursorPosition();
  406. var line = editor.session.getLine(cursor.row);
  407. var before = line.substring(0, cursor.column);
  408. var after = line.substr(cursor.column);
  409. var snippetMap = this.snippetMap;
  410. var snippet;
  411. this.getActiveScopes(editor).some(function (scope) {
  412. var snippets = snippetMap[scope];
  413. if (snippets)
  414. snippet = this.findMatchingSnippet(snippets, before, after);
  415. return !!snippet;
  416. }, this);
  417. if (!snippet)
  418. return false;
  419. if (options && options.dryRun)
  420. return true;
  421. editor.session.doc.removeInLine(cursor.row, cursor.column - snippet.replaceBefore.length, cursor.column + snippet.replaceAfter.length);
  422. this.variables.M__ = snippet.matchBefore;
  423. this.variables.T__ = snippet.matchAfter;
  424. this.insertSnippetForSelection(editor, snippet.content);
  425. this.variables.M__ = this.variables.T__ = null;
  426. return true;
  427. };
  428. SnippetManager.prototype.findMatchingSnippet = function (snippetList, before, after) {
  429. for (var i = snippetList.length; i--;) {
  430. var s = snippetList[i];
  431. if (s.startRe && !s.startRe.test(before))
  432. continue;
  433. if (s.endRe && !s.endRe.test(after))
  434. continue;
  435. if (!s.startRe && !s.endRe)
  436. continue;
  437. s.matchBefore = s.startRe ? s.startRe.exec(before) : [""];
  438. s.matchAfter = s.endRe ? s.endRe.exec(after) : [""];
  439. s.replaceBefore = s.triggerRe ? s.triggerRe.exec(before)[0] : "";
  440. s.replaceAfter = s.endTriggerRe ? s.endTriggerRe.exec(after)[0] : "";
  441. return s;
  442. }
  443. };
  444. SnippetManager.prototype.register = function (snippets, scope) {
  445. var snippetMap = this.snippetMap;
  446. var snippetNameMap = this.snippetNameMap;
  447. var self = this;
  448. if (!snippets)
  449. snippets = [];
  450. function wrapRegexp(src) {
  451. if (src && !/^\^?\(.*\)\$?$|^\\b$/.test(src))
  452. src = "(?:" + src + ")";
  453. return src || "";
  454. }
  455. function guardedRegexp(re, guard, opening) {
  456. re = wrapRegexp(re);
  457. guard = wrapRegexp(guard);
  458. if (opening) {
  459. re = guard + re;
  460. if (re && re[re.length - 1] != "$")
  461. re = re + "$";
  462. }
  463. else {
  464. re = re + guard;
  465. if (re && re[0] != "^")
  466. re = "^" + re;
  467. }
  468. return new RegExp(re);
  469. }
  470. function addSnippet(s) {
  471. if (!s.scope)
  472. s.scope = scope || "_";
  473. scope = s.scope;
  474. if (!snippetMap[scope]) {
  475. snippetMap[scope] = [];
  476. snippetNameMap[scope] = {};
  477. }
  478. var map = snippetNameMap[scope];
  479. if (s.name) {
  480. var old = map[s.name];
  481. if (old)
  482. self.unregister(old);
  483. map[s.name] = s;
  484. }
  485. snippetMap[scope].push(s);
  486. if (s.prefix)
  487. s.tabTrigger = s.prefix;
  488. if (!s.content && s.body)
  489. s.content = Array.isArray(s.body) ? s.body.join("\n") : s.body;
  490. if (s.tabTrigger && !s.trigger) {
  491. if (!s.guard && /^\w/.test(s.tabTrigger))
  492. s.guard = "\\b";
  493. s.trigger = lang.escapeRegExp(s.tabTrigger);
  494. }
  495. if (!s.trigger && !s.guard && !s.endTrigger && !s.endGuard)
  496. return;
  497. s.startRe = guardedRegexp(s.trigger, s.guard, true);
  498. s.triggerRe = new RegExp(s.trigger);
  499. s.endRe = guardedRegexp(s.endTrigger, s.endGuard, true);
  500. s.endTriggerRe = new RegExp(s.endTrigger);
  501. }
  502. if (Array.isArray(snippets)) {
  503. snippets.forEach(addSnippet);
  504. }
  505. else {
  506. Object.keys(snippets).forEach(function (key) {
  507. addSnippet(snippets[key]);
  508. });
  509. }
  510. this._signal("registerSnippets", { scope: scope });
  511. };
  512. SnippetManager.prototype.unregister = function (snippets, scope) {
  513. var snippetMap = this.snippetMap;
  514. var snippetNameMap = this.snippetNameMap;
  515. function removeSnippet(s) {
  516. var nameMap = snippetNameMap[s.scope || scope];
  517. if (nameMap && nameMap[s.name]) {
  518. delete nameMap[s.name];
  519. var map = snippetMap[s.scope || scope];
  520. var i = map && map.indexOf(s);
  521. if (i >= 0)
  522. map.splice(i, 1);
  523. }
  524. }
  525. if (snippets.content)
  526. removeSnippet(snippets);
  527. else if (Array.isArray(snippets))
  528. snippets.forEach(removeSnippet);
  529. };
  530. SnippetManager.prototype.parseSnippetFile = function (str) {
  531. str = str.replace(/\r/g, "");
  532. var list = [], /**@type{Snippet}*/ snippet = {};
  533. var re = /^#.*|^({[\s\S]*})\s*$|^(\S+) (.*)$|^((?:\n*\t.*)+)/gm;
  534. var m;
  535. while (m = re.exec(str)) {
  536. if (m[1]) {
  537. try {
  538. snippet = JSON.parse(m[1]);
  539. list.push(snippet);
  540. }
  541. catch (e) { }
  542. }
  543. if (m[4]) {
  544. snippet.content = m[4].replace(/^\t/gm, "");
  545. list.push(snippet);
  546. snippet = {};
  547. }
  548. else {
  549. var key = m[2], val = m[3];
  550. if (key == "regex") {
  551. var guardRe = /\/((?:[^\/\\]|\\.)*)|$/g;
  552. snippet.guard = guardRe.exec(val)[1];
  553. snippet.trigger = guardRe.exec(val)[1];
  554. snippet.endTrigger = guardRe.exec(val)[1];
  555. snippet.endGuard = guardRe.exec(val)[1];
  556. }
  557. else if (key == "snippet") {
  558. snippet.tabTrigger = val.match(/^\S*/)[0];
  559. if (!snippet.name)
  560. snippet.name = val;
  561. }
  562. else if (key) {
  563. snippet[key] = val;
  564. }
  565. }
  566. }
  567. return list;
  568. };
  569. SnippetManager.prototype.getSnippetByName = function (name, editor) {
  570. var snippetMap = this.snippetNameMap;
  571. var snippet;
  572. this.getActiveScopes(editor).some(function (scope) {
  573. var snippets = snippetMap[scope];
  574. if (snippets)
  575. snippet = snippets[name];
  576. return !!snippet;
  577. }, this);
  578. return snippet;
  579. };
  580. return SnippetManager;
  581. }());
  582. oop.implement(SnippetManager.prototype, EventEmitter);
  583. var processSnippetText = function (editor, snippetText, options) {
  584. if (options === void 0) { options = {}; }
  585. var cursor = editor.getCursorPosition();
  586. var line = editor.session.getLine(cursor.row);
  587. var tabString = editor.session.getTabString();
  588. var indentString = line.match(/^\s*/)[0];
  589. if (cursor.column < indentString.length)
  590. indentString = indentString.slice(0, cursor.column);
  591. snippetText = snippetText.replace(/\r/g, "");
  592. var tokens = this.tokenizeTmSnippet(snippetText);
  593. tokens = this.resolveVariables(tokens, editor);
  594. tokens = tokens.map(function (x) {
  595. if (x == "\n" && !options.excludeExtraIndent)
  596. return x + indentString;
  597. if (typeof x == "string")
  598. return x.replace(/\t/g, tabString);
  599. return x;
  600. });
  601. var tabstops = [];
  602. tokens.forEach(function (p, i) {
  603. if (typeof p != "object")
  604. return;
  605. var id = p.tabstopId;
  606. var ts = tabstops[id];
  607. if (!ts) {
  608. ts = tabstops[id] = [];
  609. ts.index = id;
  610. ts.value = "";
  611. ts.parents = {};
  612. }
  613. if (ts.indexOf(p) !== -1)
  614. return;
  615. if (p.choices && !ts.choices)
  616. ts.choices = p.choices;
  617. ts.push(p);
  618. var i1 = tokens.indexOf(p, i + 1);
  619. if (i1 === -1)
  620. return;
  621. var value = tokens.slice(i + 1, i1);
  622. var isNested = value.some(function (t) { return typeof t === "object"; });
  623. if (isNested && !ts.value) {
  624. ts.value = value;
  625. }
  626. else if (value.length && (!ts.value || typeof ts.value !== "string")) {
  627. ts.value = value.join("");
  628. }
  629. });
  630. tabstops.forEach(function (ts) { ts.length = 0; });
  631. var expanding = {};
  632. function copyValue(val) {
  633. var copy = [];
  634. for (var i = 0; i < val.length; i++) {
  635. var p = val[i];
  636. if (typeof p == "object") {
  637. if (expanding[p.tabstopId])
  638. continue;
  639. var j = val.lastIndexOf(p, i - 1);
  640. p = copy[j] || { tabstopId: p.tabstopId };
  641. }
  642. copy[i] = p;
  643. }
  644. return copy;
  645. }
  646. for (var i = 0; i < tokens.length; i++) {
  647. var p = tokens[i];
  648. if (typeof p != "object")
  649. continue;
  650. var id = p.tabstopId;
  651. var ts = tabstops[id];
  652. var i1 = tokens.indexOf(p, i + 1);
  653. if (expanding[id]) {
  654. if (expanding[id] === p) {
  655. delete expanding[id];
  656. Object.keys(expanding).forEach(function (parentId) {
  657. ts.parents[parentId] = true;
  658. });
  659. }
  660. continue;
  661. }
  662. expanding[id] = p;
  663. var value = ts.value;
  664. if (typeof value !== "string")
  665. value = copyValue(value);
  666. else if (p.fmt)
  667. value = this.tmStrFormat(value, p, editor);
  668. tokens.splice.apply(tokens, [i + 1, Math.max(0, i1 - i)].concat(value, p));
  669. if (ts.indexOf(p) === -1)
  670. ts.push(p);
  671. }
  672. var row = 0, column = 0;
  673. var text = "";
  674. tokens.forEach(function (t) {
  675. if (typeof t === "string") {
  676. var lines = t.split("\n");
  677. if (lines.length > 1) {
  678. column = lines[lines.length - 1].length;
  679. row += lines.length - 1;
  680. }
  681. else
  682. column += t.length;
  683. text += t;
  684. }
  685. else if (t) {
  686. if (!t.start)
  687. t.start = { row: row, column: column };
  688. else
  689. t.end = { row: row, column: column };
  690. }
  691. });
  692. return {
  693. text: text,
  694. tabstops: tabstops,
  695. tokens: tokens
  696. };
  697. };
  698. var TabstopManager = /** @class */ (function () {
  699. function TabstopManager(editor) {
  700. this.index = 0;
  701. this.ranges = [];
  702. this.tabstops = [];
  703. if (editor.tabstopManager)
  704. return editor.tabstopManager;
  705. editor.tabstopManager = this;
  706. this.$onChange = this.onChange.bind(this);
  707. this.$onChangeSelection = lang.delayedCall(this.onChangeSelection.bind(this)).schedule;
  708. this.$onChangeSession = this.onChangeSession.bind(this);
  709. this.$onAfterExec = this.onAfterExec.bind(this);
  710. this.attach(editor);
  711. }
  712. TabstopManager.prototype.attach = function (editor) {
  713. this.$openTabstops = null;
  714. this.selectedTabstop = null;
  715. this.editor = editor;
  716. this.session = editor.session;
  717. this.editor.on("change", this.$onChange);
  718. this.editor.on("changeSelection", this.$onChangeSelection);
  719. this.editor.on("changeSession", this.$onChangeSession);
  720. this.editor.commands.on("afterExec", this.$onAfterExec);
  721. this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler);
  722. };
  723. TabstopManager.prototype.detach = function () {
  724. this.tabstops.forEach(this.removeTabstopMarkers, this);
  725. this.ranges.length = 0;
  726. this.tabstops.length = 0;
  727. this.selectedTabstop = null;
  728. this.editor.off("change", this.$onChange);
  729. this.editor.off("changeSelection", this.$onChangeSelection);
  730. this.editor.off("changeSession", this.$onChangeSession);
  731. this.editor.commands.off("afterExec", this.$onAfterExec);
  732. this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler);
  733. this.editor.tabstopManager = null;
  734. this.session = null;
  735. this.editor = null;
  736. };
  737. TabstopManager.prototype.onChange = function (delta) {
  738. var isRemove = delta.action[0] == "r";
  739. var selectedTabstop = this.selectedTabstop || {};
  740. var parents = selectedTabstop.parents || {};
  741. var tabstops = this.tabstops.slice();
  742. for (var i = 0; i < tabstops.length; i++) {
  743. var ts = tabstops[i];
  744. var active = ts == selectedTabstop || parents[ts.index];
  745. ts.rangeList.$bias = active ? 0 : 1;
  746. if (delta.action == "remove" && ts !== selectedTabstop) {
  747. var parentActive = ts.parents && ts.parents[selectedTabstop.index];
  748. var startIndex = ts.rangeList.pointIndex(delta.start, parentActive);
  749. startIndex = startIndex < 0 ? -startIndex - 1 : startIndex + 1;
  750. var endIndex = ts.rangeList.pointIndex(delta.end, parentActive);
  751. endIndex = endIndex < 0 ? -endIndex - 1 : endIndex - 1;
  752. var toRemove = ts.rangeList.ranges.slice(startIndex, endIndex);
  753. for (var j = 0; j < toRemove.length; j++)
  754. this.removeRange(toRemove[j]);
  755. }
  756. ts.rangeList.$onChange(delta);
  757. }
  758. var session = this.session;
  759. if (!this.$inChange && isRemove && session.getLength() == 1 && !session.getValue())
  760. this.detach();
  761. };
  762. TabstopManager.prototype.updateLinkedFields = function () {
  763. var ts = this.selectedTabstop;
  764. if (!ts || !ts.hasLinkedRanges || !ts.firstNonLinked)
  765. return;
  766. this.$inChange = true;
  767. var session = this.session;
  768. var text = session.getTextRange(ts.firstNonLinked);
  769. for (var i = 0; i < ts.length; i++) {
  770. var range = ts[i];
  771. if (!range.linked)
  772. continue;
  773. var original = range.original;
  774. var fmt = exports.snippetManager.tmStrFormat(text, original, this.editor);
  775. session.replace(range, fmt);
  776. }
  777. this.$inChange = false;
  778. };
  779. TabstopManager.prototype.onAfterExec = function (e) {
  780. if (e.command && !e.command.readOnly)
  781. this.updateLinkedFields();
  782. };
  783. TabstopManager.prototype.onChangeSelection = function () {
  784. if (!this.editor)
  785. return;
  786. var lead = this.editor.selection.lead;
  787. var anchor = this.editor.selection.anchor;
  788. var isEmpty = this.editor.selection.isEmpty();
  789. for (var i = 0; i < this.ranges.length; i++) {
  790. if (this.ranges[i].linked)
  791. continue;
  792. var containsLead = this.ranges[i].contains(lead.row, lead.column);
  793. var containsAnchor = isEmpty || this.ranges[i].contains(anchor.row, anchor.column);
  794. if (containsLead && containsAnchor)
  795. return;
  796. }
  797. this.detach();
  798. };
  799. TabstopManager.prototype.onChangeSession = function () {
  800. this.detach();
  801. };
  802. TabstopManager.prototype.tabNext = function (dir) {
  803. var max = this.tabstops.length;
  804. var index = this.index + (dir || 1);
  805. index = Math.min(Math.max(index, 1), max);
  806. if (index == max)
  807. index = 0;
  808. this.selectTabstop(index);
  809. this.updateTabstopMarkers();
  810. if (index === 0) {
  811. this.detach();
  812. }
  813. };
  814. TabstopManager.prototype.selectTabstop = function (index) {
  815. this.$openTabstops = null;
  816. var ts = this.tabstops[this.index];
  817. if (ts)
  818. this.addTabstopMarkers(ts);
  819. this.index = index;
  820. ts = this.tabstops[this.index];
  821. if (!ts || !ts.length)
  822. return;
  823. this.selectedTabstop = ts;
  824. var range = ts.firstNonLinked || ts;
  825. if (ts.choices)
  826. range.cursor = range.start;
  827. if (!this.editor.inVirtualSelectionMode) {
  828. var sel = this.editor.multiSelect;
  829. sel.toSingleRange(range);
  830. for (var i = 0; i < ts.length; i++) {
  831. if (ts.hasLinkedRanges && ts[i].linked)
  832. continue;
  833. sel.addRange(ts[i].clone(), true);
  834. }
  835. }
  836. else {
  837. this.editor.selection.fromOrientedRange(range);
  838. }
  839. this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler);
  840. if (this.selectedTabstop && this.selectedTabstop.choices)
  841. this.editor.execCommand("startAutocomplete", { matches: this.selectedTabstop.choices });
  842. };
  843. TabstopManager.prototype.addTabstops = function (tabstops, start, end) {
  844. var useLink = this.useLink || !this.editor.getOption("enableMultiselect");
  845. if (!this.$openTabstops)
  846. this.$openTabstops = [];
  847. if (!tabstops[0]) {
  848. var p = Range.fromPoints(end, end);
  849. moveRelative(p.start, start);
  850. moveRelative(p.end, start);
  851. tabstops[0] = [p];
  852. tabstops[0].index = 0;
  853. }
  854. var i = this.index;
  855. var arg = [i + 1, 0];
  856. var ranges = this.ranges;
  857. var snippetId = this.snippetId = (this.snippetId || 0) + 1;
  858. tabstops.forEach(function (ts, index) {
  859. var dest = this.$openTabstops[index] || ts;
  860. dest.snippetId = snippetId;
  861. for (var i = 0; i < ts.length; i++) {
  862. var p = ts[i];
  863. var range = Range.fromPoints(p.start, p.end || p.start);
  864. movePoint(range.start, start);
  865. movePoint(range.end, start);
  866. range.original = p;
  867. range.tabstop = dest;
  868. ranges.push(range);
  869. if (dest != ts)
  870. dest.unshift(range);
  871. else
  872. dest[i] = range;
  873. if (p.fmtString || (dest.firstNonLinked && useLink)) {
  874. range.linked = true;
  875. dest.hasLinkedRanges = true;
  876. }
  877. else if (!dest.firstNonLinked)
  878. dest.firstNonLinked = range;
  879. }
  880. if (!dest.firstNonLinked)
  881. dest.hasLinkedRanges = false;
  882. if (dest === ts) {
  883. arg.push(dest);
  884. this.$openTabstops[index] = dest;
  885. }
  886. this.addTabstopMarkers(dest);
  887. dest.rangeList = dest.rangeList || new RangeList();
  888. dest.rangeList.$bias = 0;
  889. dest.rangeList.addList(dest);
  890. }, this);
  891. if (arg.length > 2) {
  892. if (this.tabstops.length)
  893. arg.push(arg.splice(2, 1)[0]);
  894. this.tabstops.splice.apply(this.tabstops, arg);
  895. }
  896. };
  897. TabstopManager.prototype.addTabstopMarkers = function (ts) {
  898. var session = this.session;
  899. ts.forEach(function (range) {
  900. if (!range.markerId)
  901. range.markerId = session.addMarker(range, "ace_snippet-marker", "text");
  902. });
  903. };
  904. TabstopManager.prototype.removeTabstopMarkers = function (ts) {
  905. var session = this.session;
  906. ts.forEach(function (range) {
  907. session.removeMarker(range.markerId);
  908. range.markerId = null;
  909. });
  910. };
  911. TabstopManager.prototype.updateTabstopMarkers = function () {
  912. if (!this.selectedTabstop)
  913. return;
  914. var currentSnippetId = this.selectedTabstop.snippetId;
  915. if (this.selectedTabstop.index === 0) {
  916. currentSnippetId--;
  917. }
  918. this.tabstops.forEach(function (ts) {
  919. if (ts.snippetId === currentSnippetId)
  920. this.addTabstopMarkers(ts);
  921. else
  922. this.removeTabstopMarkers(ts);
  923. }, this);
  924. };
  925. TabstopManager.prototype.removeRange = function (range) {
  926. var i = range.tabstop.indexOf(range);
  927. if (i != -1)
  928. range.tabstop.splice(i, 1);
  929. i = this.ranges.indexOf(range);
  930. if (i != -1)
  931. this.ranges.splice(i, 1);
  932. i = range.tabstop.rangeList.ranges.indexOf(range);
  933. if (i != -1)
  934. range.tabstop.splice(i, 1);
  935. this.session.removeMarker(range.markerId);
  936. if (!range.tabstop.length) {
  937. i = this.tabstops.indexOf(range.tabstop);
  938. if (i != -1)
  939. this.tabstops.splice(i, 1);
  940. if (!this.tabstops.length)
  941. this.detach();
  942. }
  943. };
  944. return TabstopManager;
  945. }());
  946. TabstopManager.prototype.keyboardHandler = new HashHandler();
  947. TabstopManager.prototype.keyboardHandler.bindKeys({
  948. "Tab": function (editor) {
  949. if (exports.snippetManager && exports.snippetManager.expandWithTab(editor))
  950. return;
  951. editor.tabstopManager.tabNext(1);
  952. editor.renderer.scrollCursorIntoView();
  953. },
  954. "Shift-Tab": function (editor) {
  955. editor.tabstopManager.tabNext(-1);
  956. editor.renderer.scrollCursorIntoView();
  957. },
  958. "Esc": function (editor) {
  959. editor.tabstopManager.detach();
  960. }
  961. });
  962. var movePoint = function (point, diff) {
  963. if (point.row == 0)
  964. point.column += diff.column;
  965. point.row += diff.row;
  966. };
  967. var moveRelative = function (point, start) {
  968. if (point.row == start.row)
  969. point.column -= start.column;
  970. point.row -= start.row;
  971. };
  972. dom.importCssString("\n.ace_snippet-marker {\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n background: rgba(194, 193, 208, 0.09);\n border: 1px dotted rgba(211, 208, 235, 0.62);\n position: absolute;\n}", "snippets.css", false);
  973. exports.snippetManager = new SnippetManager();
  974. var Editor = require("./editor").Editor;
  975. (function () {
  976. this.insertSnippet = function (content, options) {
  977. return exports.snippetManager.insertSnippet(this, content, options);
  978. };
  979. this.expandSnippet = function (options) {
  980. return exports.snippetManager.expandWithTab(this, options);
  981. };
  982. }).call(Editor.prototype);
  983. });
  984. ace.define("ace/ext/emmet",["require","exports","module","ace/keyboard/hash_handler","ace/editor","ace/snippets","ace/range","ace/config","resources","resources","tabStops","resources","utils","actions"], function(require, exports, module){"use strict";
  985. var HashHandler = require("../keyboard/hash_handler").HashHandler;
  986. var Editor = require("../editor").Editor;
  987. var snippetManager = require("../snippets").snippetManager;
  988. var Range = require("../range").Range;
  989. var config = require("../config");
  990. var emmet, emmetPath;
  991. var AceEmmetEditor = /** @class */ (function () {
  992. function AceEmmetEditor() {
  993. }
  994. AceEmmetEditor.prototype.setupContext = function (editor) {
  995. this.ace = editor;
  996. this.indentation = editor.session.getTabString();
  997. if (!emmet)
  998. emmet = window["emmet"];
  999. var resources = emmet.resources || emmet.require("resources");
  1000. resources.setVariable("indentation", this.indentation);
  1001. this.$syntax = null;
  1002. this.$syntax = this.getSyntax();
  1003. };
  1004. AceEmmetEditor.prototype.getSelectionRange = function () {
  1005. var range = this.ace.getSelectionRange();
  1006. var doc = this.ace.session.doc;
  1007. return {
  1008. start: doc.positionToIndex(range.start),
  1009. end: doc.positionToIndex(range.end)
  1010. };
  1011. };
  1012. AceEmmetEditor.prototype.createSelection = function (start, end) {
  1013. var doc = this.ace.session.doc;
  1014. this.ace.selection.setRange({
  1015. start: doc.indexToPosition(start),
  1016. end: doc.indexToPosition(end)
  1017. });
  1018. };
  1019. AceEmmetEditor.prototype.getCurrentLineRange = function () {
  1020. var ace = this.ace;
  1021. var row = ace.getCursorPosition().row;
  1022. var lineLength = ace.session.getLine(row).length;
  1023. var index = ace.session.doc.positionToIndex({ row: row, column: 0 });
  1024. return {
  1025. start: index,
  1026. end: index + lineLength
  1027. };
  1028. };
  1029. AceEmmetEditor.prototype.getCaretPos = function () {
  1030. var pos = this.ace.getCursorPosition();
  1031. return this.ace.session.doc.positionToIndex(pos);
  1032. };
  1033. AceEmmetEditor.prototype.setCaretPos = function (index) {
  1034. var pos = this.ace.session.doc.indexToPosition(index);
  1035. this.ace.selection.moveToPosition(pos);
  1036. };
  1037. AceEmmetEditor.prototype.getCurrentLine = function () {
  1038. var row = this.ace.getCursorPosition().row;
  1039. return this.ace.session.getLine(row);
  1040. };
  1041. AceEmmetEditor.prototype.replaceContent = function (value, start, end, noIndent) {
  1042. if (end == null)
  1043. end = start == null ? this.getContent().length : start;
  1044. if (start == null)
  1045. start = 0;
  1046. var editor = this.ace;
  1047. var doc = editor.session.doc;
  1048. var range = Range.fromPoints(doc.indexToPosition(start), doc.indexToPosition(end));
  1049. editor.session.remove(range);
  1050. range.end = range.start;
  1051. value = this.$updateTabstops(value);
  1052. snippetManager.insertSnippet(editor, value);
  1053. };
  1054. AceEmmetEditor.prototype.getContent = function () {
  1055. return this.ace.getValue();
  1056. };
  1057. AceEmmetEditor.prototype.getSyntax = function () {
  1058. if (this.$syntax)
  1059. return this.$syntax;
  1060. var syntax = this.ace.session.$modeId.split("/").pop();
  1061. if (syntax == "html" || syntax == "php") {
  1062. var cursor = this.ace.getCursorPosition();
  1063. var state = this.ace.session.getState(cursor.row);
  1064. if (typeof state != "string")
  1065. state = state[0];
  1066. if (state) {
  1067. state = state.split("-");
  1068. if (state.length > 1)
  1069. syntax = state[0];
  1070. else if (syntax == "php")
  1071. syntax = "html";
  1072. }
  1073. }
  1074. return syntax;
  1075. };
  1076. AceEmmetEditor.prototype.getProfileName = function () {
  1077. var resources = emmet.resources || emmet.require("resources");
  1078. switch (this.getSyntax()) {
  1079. case "css": return "css";
  1080. case "xml":
  1081. case "xsl":
  1082. return "xml";
  1083. case "html":
  1084. var profile = resources.getVariable("profile");
  1085. if (!profile)
  1086. profile = this.ace.session.getLines(0, 2).join("").search(/<!DOCTYPE[^>]+XHTML/i) != -1 ? "xhtml" : "html";
  1087. return profile;
  1088. default:
  1089. var mode = this.ace.session.$mode;
  1090. return mode.emmetConfig && mode.emmetConfig.profile || "xhtml";
  1091. }
  1092. };
  1093. AceEmmetEditor.prototype.prompt = function (title) {
  1094. return prompt(title); // eslint-disable-line no-alert
  1095. };
  1096. AceEmmetEditor.prototype.getSelection = function () {
  1097. return this.ace.session.getTextRange();
  1098. };
  1099. AceEmmetEditor.prototype.getFilePath = function () {
  1100. return "";
  1101. };
  1102. AceEmmetEditor.prototype.$updateTabstops = function (value) {
  1103. var base = 1000;
  1104. var zeroBase = 0;
  1105. var lastZero = null;
  1106. var ts = emmet.tabStops || emmet.require('tabStops');
  1107. var resources = emmet.resources || emmet.require("resources");
  1108. var settings = resources.getVocabulary("user");
  1109. var tabstopOptions = {
  1110. tabstop: function (data) {
  1111. var group = parseInt(data.group, 10);
  1112. var isZero = group === 0;
  1113. if (isZero)
  1114. group = ++zeroBase;
  1115. else
  1116. group += base;
  1117. var placeholder = data.placeholder;
  1118. if (placeholder) {
  1119. placeholder = ts.processText(placeholder, tabstopOptions);
  1120. }
  1121. var result = '${' + group + (placeholder ? ':' + placeholder : '') + '}';
  1122. if (isZero) {
  1123. lastZero = [data.start, result];
  1124. }
  1125. return result;
  1126. },
  1127. escape: function (ch) {
  1128. if (ch == '$')
  1129. return '\\$';
  1130. if (ch == '\\')
  1131. return '\\\\';
  1132. return ch;
  1133. }
  1134. };
  1135. value = ts.processText(value, tabstopOptions);
  1136. if (settings.variables['insert_final_tabstop'] && !/\$\{0\}$/.test(value)) {
  1137. value += '${0}';
  1138. }
  1139. else if (lastZero) {
  1140. var common = emmet.utils ? emmet.utils.common : emmet.require('utils');
  1141. value = common.replaceSubstring(value, '${0}', lastZero[0], lastZero[1]);
  1142. }
  1143. return value;
  1144. };
  1145. return AceEmmetEditor;
  1146. }());
  1147. var keymap = {
  1148. expand_abbreviation: { "mac": "ctrl+alt+e", "win": "alt+e" },
  1149. match_pair_outward: { "mac": "ctrl+d", "win": "ctrl+," },
  1150. match_pair_inward: { "mac": "ctrl+j", "win": "ctrl+shift+0" },
  1151. matching_pair: { "mac": "ctrl+alt+j", "win": "alt+j" },
  1152. next_edit_point: "alt+right",
  1153. prev_edit_point: "alt+left",
  1154. toggle_comment: { "mac": "command+/", "win": "ctrl+/" },
  1155. split_join_tag: { "mac": "shift+command+'", "win": "shift+ctrl+`" },
  1156. remove_tag: { "mac": "command+'", "win": "shift+ctrl+;" },
  1157. evaluate_math_expression: { "mac": "shift+command+y", "win": "shift+ctrl+y" },
  1158. increment_number_by_1: "ctrl+up",
  1159. decrement_number_by_1: "ctrl+down",
  1160. increment_number_by_01: "alt+up",
  1161. decrement_number_by_01: "alt+down",
  1162. increment_number_by_10: { "mac": "alt+command+up", "win": "shift+alt+up" },
  1163. decrement_number_by_10: { "mac": "alt+command+down", "win": "shift+alt+down" },
  1164. select_next_item: { "mac": "shift+command+.", "win": "shift+ctrl+." },
  1165. select_previous_item: { "mac": "shift+command+,", "win": "shift+ctrl+," },
  1166. reflect_css_value: { "mac": "shift+command+r", "win": "shift+ctrl+r" },
  1167. encode_decode_data_url: { "mac": "shift+ctrl+d", "win": "ctrl+'" },
  1168. expand_abbreviation_with_tab: "Tab",
  1169. wrap_with_abbreviation: { "mac": "shift+ctrl+a", "win": "shift+ctrl+a" }
  1170. };
  1171. var editorProxy = new AceEmmetEditor();
  1172. exports.commands = new HashHandler();
  1173. exports.runEmmetCommand = function runEmmetCommand(editor) {
  1174. if (this.action == "expand_abbreviation_with_tab") {
  1175. if (!editor.selection.isEmpty())
  1176. return false;
  1177. var pos = editor.selection.lead;
  1178. var token = editor.session.getTokenAt(pos.row, pos.column);
  1179. if (token && /\btag\b/.test(token.type))
  1180. return false;
  1181. }
  1182. try {
  1183. editorProxy.setupContext(editor);
  1184. var actions = emmet.actions || emmet.require("actions");
  1185. if (this.action == "wrap_with_abbreviation") {
  1186. return setTimeout(function () {
  1187. actions.run("wrap_with_abbreviation", editorProxy);
  1188. }, 0);
  1189. }
  1190. var result = actions.run(this.action, editorProxy);
  1191. }
  1192. catch (e) {
  1193. if (!emmet) {
  1194. var loading = exports.load(runEmmetCommand.bind(this, editor));
  1195. if (this.action == "expand_abbreviation_with_tab")
  1196. return false;
  1197. return loading;
  1198. }
  1199. editor._signal("changeStatus", typeof e == "string" ? e : e.message);
  1200. config.warn(e);
  1201. result = false;
  1202. }
  1203. return result;
  1204. };
  1205. for (var command in keymap) {
  1206. exports.commands.addCommand({
  1207. name: "emmet:" + command,
  1208. action: command,
  1209. bindKey: keymap[command],
  1210. exec: exports.runEmmetCommand,
  1211. multiSelectAction: "forEach"
  1212. });
  1213. }
  1214. exports.updateCommands = function (editor, enabled) {
  1215. if (enabled) {
  1216. editor.keyBinding.addKeyboardHandler(exports.commands);
  1217. }
  1218. else {
  1219. editor.keyBinding.removeKeyboardHandler(exports.commands);
  1220. }
  1221. };
  1222. exports.isSupportedMode = function (mode) {
  1223. if (!mode)
  1224. return false;
  1225. if (mode.emmetConfig)
  1226. return true;
  1227. var id = mode.$id || mode;
  1228. return /css|less|scss|sass|stylus|html|php|twig|ejs|handlebars/.test(id);
  1229. };
  1230. exports.isAvailable = function (editor, command) {
  1231. if (/(evaluate_math_expression|expand_abbreviation)$/.test(command))
  1232. return true;
  1233. var mode = editor.session.$mode;
  1234. var isSupported = exports.isSupportedMode(mode);
  1235. if (isSupported && mode.$modes) {
  1236. try {
  1237. editorProxy.setupContext(editor);
  1238. if (/js|php/.test(editorProxy.getSyntax()))
  1239. isSupported = false;
  1240. }
  1241. catch (e) { }
  1242. }
  1243. return isSupported;
  1244. };
  1245. var onChangeMode = function (e, target) {
  1246. var editor = target;
  1247. if (!editor)
  1248. return;
  1249. var enabled = exports.isSupportedMode(editor.session.$mode);
  1250. if (e.enableEmmet === false)
  1251. enabled = false;
  1252. if (enabled)
  1253. exports.load();
  1254. exports.updateCommands(editor, enabled);
  1255. };
  1256. exports.load = function (cb) {
  1257. if (typeof emmetPath !== "string") {
  1258. config.warn("script for emmet-core is not loaded");
  1259. return false;
  1260. }
  1261. config.loadModule(emmetPath, function () {
  1262. emmetPath = null;
  1263. cb && cb();
  1264. });
  1265. return true;
  1266. };
  1267. exports.AceEmmetEditor = AceEmmetEditor;
  1268. config.defineOptions(Editor.prototype, "editor", {
  1269. enableEmmet: {
  1270. set: function (val) {
  1271. this[val ? "on" : "removeListener"]("changeMode", onChangeMode);
  1272. onChangeMode({ enableEmmet: !!val }, this);
  1273. },
  1274. value: true
  1275. }
  1276. });
  1277. exports.setCore = function (e) {
  1278. if (typeof e == "string")
  1279. emmetPath = e;
  1280. else
  1281. emmet = e;
  1282. };
  1283. }); (function() {
  1284. ace.require(["ace/ext/emmet"], function(m) {
  1285. if (typeof module == "object" && typeof exports == "object" && module) {
  1286. module.exports = m;
  1287. }
  1288. });
  1289. })();