From d4dcdb7736d5c8d1d98e68be7e8e91e2193d6c3d Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 27 Jul 2013 00:45:08 +0400 Subject: [PATCH] use snipetManager for expanding emmet snippets --- Makefile.dryice.js | 30 ++++++------- demo/emmet.html | 1 - lib/ace/ext/emmet.js | 104 +++++++++++++++++++++++++++---------------- lib/ace/snippets.js | 19 +++++--- 4 files changed, 93 insertions(+), 61 deletions(-) diff --git a/Makefile.dryice.js b/Makefile.dryice.js index 09e4eca9..14ffea23 100755 --- a/Makefile.dryice.js +++ b/Makefile.dryice.js @@ -346,6 +346,21 @@ var buildAce = function(options) { dest: targetDir + '/' + name + ".js" }); + console.log('# ace extensions ---------'); + + project.assumeAllFilesLoaded(); + options.extensions.forEach(function(ext) { + console.log("extensions " + ext); + copy({ + source: [{ + project: cloneProject(project), + require: [ 'ace/ext/' + ext ] + }], + filter: getWriteFilters(options, "ext"), + dest: targetDir + "/ext-" + ext + ".js" + }); + }); + console.log('# ace modes ---------'); project.assumeAllFilesLoaded(); @@ -380,21 +395,6 @@ var buildAce = function(options) { }); }); - console.log('# ace extensions ---------'); - - project.assumeAllFilesLoaded(); - options.extensions.forEach(function(ext) { - console.log("extensions " + ext); - copy({ - source: [{ - project: cloneProject(project), - require: [ 'ace/ext/' + ext ] - }], - filter: getWriteFilters(options, "ext"), - dest: targetDir + "/ext-" + ext + ".js" - }); - }); - console.log('# ace key bindings ---------'); // copy key bindings diff --git a/demo/emmet.html b/demo/emmet.html index 65b59bf7..57f13f67 100644 --- a/demo/emmet.html +++ b/demo/emmet.html @@ -32,7 +32,6 @@ // trigger extension ace.require("ace/ext/emmet"); var editor = ace.edit("editor"); - editor.setTheme("ace/theme/tomorrow"); editor.session.setMode("ace/mode/html"); // enable emmet on the current editor editor.setOption("enableEmmet", true); diff --git a/lib/ace/ext/emmet.js b/lib/ace/ext/emmet.js index d6c141bf..5c80ee47 100644 --- a/lib/ace/ext/emmet.js +++ b/lib/ace/ext/emmet.js @@ -32,6 +32,8 @@ define(function(require, exports, module) { "use strict"; var HashHandler = require("ace/keyboard/hash_handler").HashHandler; var Editor = require("ace/editor").Editor; +var snippetManager = require("ace/snippets").snippetManager; +var Range = require("ace/range").Range; var emmet; Editor.prototype.indexToPosition = function(index) { @@ -165,43 +167,17 @@ AceEmmetEditor.prototype = { if (end == null) end = start == null ? this.getContent().length : start; if (start == null) - start = 0; - var utils = emmet.require("utils"); - - // indent new value - if (!noIndent) { - value = utils.padString(value, utils.getLinePaddingFromPosition(this.getContent(), start)); - } - - // find new caret position - var tabstopData = emmet.require("tabStops").extract(value, { - escape: function(ch) { - return ch; - } - }); - - value = tabstopData.text; - var firstTabStop = tabstopData.tabstops[0]; - - if (firstTabStop) { - firstTabStop.start += start; - firstTabStop.end += start; - } else { - firstTabStop = { - start: value.length + start, - end: value.length + start - }; - } - - var range = this.ace.getSelectionRange(); - range.start = this.ace.indexToPosition(start); - range.end = this.ace.indexToPosition(end); - - this.ace.session.replace(range, value); - - range.start = this.ace.indexToPosition(firstTabStop.start); - range.end = this.ace.indexToPosition(firstTabStop.end); - this.ace.selection.setRange(range); + start = 0; + + var editor = this.ace; + var range = Range.fromPoints(editor.indexToPosition(start), editor.indexToPosition(end)); + editor.session.remove(range); + + range.end = range.start; + //editor.selection.setRange(range); + + value = this.$updateTabstops(value); + snippetManager.insertSnippet(editor, value) }, /** @@ -282,6 +258,58 @@ AceEmmetEditor.prototype = { */ getFilePath: function() { return ""; + }, + + // update tabstops: make sure all caret placeholders are unique + // by default, abbreviation parser generates all unlinked (un-mirrored) + // tabstops as ${0}, so we have upgrade all caret tabstops with unique + // positions but make sure that all other tabstops are not linked accidentally + $updateTabstops: function(value) { + var base = 1000; + var zeroBase = 0; + var lastZero = null; + var range = emmet.require('range'); + var ts = emmet.require('tabStops'); + + var tabstopOptions = { + tabstop: function(data) { + var group = parseInt(data.group, 10); + var isZero = group === 0; + if (isZero) + group = ++zeroBase; + else + group += base; + + var placeholder = data.placeholder; + if (placeholder) { + // recursively update nested tabstops + placeholder = ts.processText(placeholder, tabstopOptions); + } + + var result = '${' + group + (placeholder ? ':' + placeholder : '') + '}'; + + if (isZero) { + lastZero = range.create(data.start, result); + } + + return result + }, + escape: function(ch) { + if (ch == '$') return '\\$'; + if (ch == '\\') return '\\\\'; + return ch; + } + }; + + value = ts.processText(value, tabstopOptions); + + if (/*sublimeGetOption('insert_final_tabstop', false)*/ false && !/\$\{0\}$/.test(value)) { + value += '${0}'; + } else if (lastZero) { + value = emmet.require('utils').replaceSubstring(value, '${0}', lastZero); + } + + return value; } }; @@ -359,7 +387,7 @@ var onChangeMode = function(e, target) { if (!editor) return; var modeId = editor.session.$modeId; - var enabled = modeId && /css|less|sass|html|php/.test(modeId); + var enabled = modeId && /css|less|scss|sass|stylus|html|php/.test(modeId); if (e.enableEmmet === false) enabled = false; if (enabled) diff --git a/lib/ace/snippets.js b/lib/ace/snippets.js index cf5ac307..6e11a932 100644 --- a/lib/ace/snippets.js +++ b/lib/ace/snippets.js @@ -675,15 +675,20 @@ var TabstopManager = function(editor) { ts = this.tabstops[this.index]; if (!ts || !ts.length) return; - + this.selectedTabstop = ts; - var sel = this.editor.multiSelect; - sel.toSingleRange(ts.firstNonLinked.clone()); - for (var i = ts.length; i--;) { - if (ts.hasLinkedRanges && ts[i].linked) - continue; - sel.addRange(ts[i].clone(), true); + if (!this.editor.inVirtualSelectionMode) { + var sel = this.editor.multiSelect; + sel.toSingleRange(ts.firstNonLinked.clone()); + for (var i = ts.length; i--;) { + if (ts.hasLinkedRanges && ts[i].linked) + continue; + sel.addRange(ts[i].clone(), true); + } + } else { + this.editor.selection.setRange(ts.firstNonLinked); } + this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler); }; this.addTabstops = function(tabstops, start, end) {