323 lines
7.7 KiB
JavaScript
323 lines
7.7 KiB
JavaScript
function activeView() {
|
|
return sublime.active_window().active_view();
|
|
}
|
|
|
|
var editorProxy = emmet.exec(function(require, _) {
|
|
return {
|
|
getSelectionRange: function() {
|
|
var view = activeView();
|
|
var sel = view.sel()[0];
|
|
return {
|
|
start: sel.begin(),
|
|
end: sel.end()
|
|
};
|
|
},
|
|
|
|
createSelection: function(start, end) {
|
|
var view = activeView();
|
|
view.sel().clear();
|
|
|
|
view.sel().add(new sublime.Region(start, end || start));
|
|
view.show(view.sel());
|
|
},
|
|
|
|
getCurrentLineRange: function() {
|
|
var view = activeView();
|
|
var selection = view.sel()[0];
|
|
var line = view.line(selection);
|
|
return {
|
|
start: line.begin(),
|
|
end: line.end()
|
|
};
|
|
},
|
|
|
|
getCaretPos: function() {
|
|
var view = activeView();
|
|
var sel = view.sel();
|
|
return sel && sel[0] ? sel[0].begin() : 0;
|
|
},
|
|
|
|
setCaretPos: function(pos){
|
|
this.createSelection(pos, pos);
|
|
},
|
|
|
|
getCurrentLine: function() {
|
|
var view = activeView();
|
|
return view.substr(view.line(view.sel()[0]));
|
|
},
|
|
|
|
replaceContent: function(value, start, end, noIndent) {
|
|
if (_.isUndefined(end))
|
|
end = _.isUndefined(start) ? this.getContent().length : start;
|
|
if (_.isUndefined(start)) start = 0;
|
|
|
|
// update tabstops: make sure all caret placeholder 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
|
|
value = pyPreprocessText(value);
|
|
sublimeReplaceSubstring(start, end, value, !!noIndent);
|
|
},
|
|
|
|
getContent: function() {
|
|
var view = activeView();
|
|
return view.substr(new sublime.Region(0, view.size()));
|
|
},
|
|
|
|
getSyntax: function() {
|
|
return pyGetSyntax();
|
|
},
|
|
|
|
getProfileName: function() {
|
|
var view = activeView();
|
|
var pos = this.getCaretPos();
|
|
|
|
if (view.match_selector(pos, 'text.html')
|
|
&& sublimeGetOption('autodetect_xhtml', false)
|
|
&& require('actionUtils').isXHTML(this)) {
|
|
return 'xhtml';
|
|
}
|
|
|
|
if (view.match_selector(pos, 'string.quoted.double.block.python')
|
|
|| view.match_selector(pos, 'source.coffee string')
|
|
|| view.match_selector(pos, 'string.unquoted.heredoc')) {
|
|
// use html's default profile for:
|
|
// * Python's multiline block
|
|
// * CoffeeScript string
|
|
// * PHP heredoc
|
|
return pyDetectProfile();
|
|
}
|
|
|
|
if (view.score_selector(pos, 'source string')) {
|
|
return 'line';
|
|
}
|
|
|
|
return pyDetectProfile();
|
|
},
|
|
|
|
prompt: function(title) {
|
|
return pyEditor.prompt();
|
|
},
|
|
|
|
getSelection: function() {
|
|
var view = activeView();
|
|
return view.sel() ? view.substr(view.sel()[0]) : '';
|
|
},
|
|
|
|
getFilePath: function() {
|
|
return activeView().file_name();
|
|
}
|
|
};
|
|
});
|
|
|
|
var _completions = {};
|
|
|
|
function require(name) {
|
|
return emmet.require(name);
|
|
}
|
|
|
|
function pyPreprocessText(value) {
|
|
var base = 1000;
|
|
var zeroBase = 0;
|
|
var lastZero = null;
|
|
var range = require('range');
|
|
var ts = 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) && !/\$\{0\}$/.test(value)) {
|
|
value += '${0}';
|
|
} else if (lastZero) {
|
|
value = require('utils').replaceSubstring(value, '${0}', lastZero);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
function pyExpandAbbreviationAsYouType(abbr) {
|
|
var info = require('editorUtils').outputInfo(editorProxy);
|
|
try {
|
|
var result = emmet.expandAbbreviation(abbr, info.syntax, info.profile,
|
|
require('actionUtils').captureContext(editorProxy));
|
|
return pyPreprocessText(result);
|
|
} catch (e) {
|
|
return '';
|
|
}
|
|
|
|
}
|
|
|
|
function pyWrapAsYouType(abbr, content) {
|
|
var info = require('editorUtils').outputInfo(editorProxy);
|
|
content = require('utils').escapeText(content);
|
|
var ctx = require('actionUtils').captureContext(editorProxy);
|
|
try {
|
|
var result = require('wrapWithAbbreviation').wrap(abbr, content, info.syntax, info.profile, ctx);
|
|
return pyPreprocessText(result);
|
|
} catch(e) {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
function pyCaptureWrappingRange() {
|
|
var info = require('editorUtils').outputInfo(editorProxy);
|
|
var range = editorProxy.getSelectionRange();
|
|
var startOffset = range.start;
|
|
var endOffset = range.end;
|
|
|
|
if (startOffset == endOffset) {
|
|
// no selection, find tag pair
|
|
var match = require('htmlMatcher').find(info.content, startOffset);
|
|
if (!match) {
|
|
// nothing to wrap
|
|
return null;
|
|
}
|
|
|
|
/** @type Range */
|
|
var utils = require('utils');
|
|
var narrowedSel = utils.narrowToNonSpace(info.content, match.range);
|
|
startOffset = narrowedSel.start;
|
|
endOffset = narrowedSel.end;
|
|
}
|
|
|
|
return [startOffset, endOffset];
|
|
}
|
|
|
|
function pyGetTagNameRanges(pos) {
|
|
var ranges = [];
|
|
var info = require('editorUtils').outputInfo(editorProxy);
|
|
|
|
// search for tag
|
|
try {
|
|
var tag = require('htmlMatcher').tag(info.content, pos);
|
|
if (tag) {
|
|
var open = tag.open.range;
|
|
var tagName = /^<([\w\-\:]+)/i.exec(open.substring(info.content))[1];
|
|
ranges.push([open.start + 1, open.start + 1 + tagName.length]);
|
|
|
|
if (tag.close) {
|
|
ranges.push([tag.close.range.start + 2, tag.close.range.start + 2 + tagName.length]);
|
|
}
|
|
}
|
|
} catch (e) {}
|
|
|
|
return ranges;
|
|
}
|
|
|
|
function pyGetTagRanges() {
|
|
var ranges = [];
|
|
var info = require('editorUtils').outputInfo(editorProxy);
|
|
|
|
// search for tag
|
|
try {
|
|
var tag = require('htmlMatcher').tag(info.content, editorProxy.getCaretPos());
|
|
if (tag) {
|
|
ranges.push(tag.open.range.toArray());
|
|
if (tag.close) {
|
|
ranges.push(tag.close.range.toArray());
|
|
}
|
|
}
|
|
} catch (e) {}
|
|
|
|
return ranges;
|
|
}
|
|
|
|
function pyExtractAbbreviation() {
|
|
return require('expandAbbreviation').findAbbreviation(editorProxy);
|
|
}
|
|
|
|
function pyHasSnippet(name) {
|
|
return !!emmet.require('resources').findSnippet(editorProxy.getSyntax(), name);
|
|
}
|
|
|
|
/**
|
|
* Get all available CSS completions. This method is optimized for CSS
|
|
* only since it should contain snippets only so it's not required
|
|
* to do extra parsing
|
|
*/
|
|
function pyGetCSSCompletions(dialect) {
|
|
dialect = dialect || pyGetSyntax();
|
|
|
|
if (!_completions[dialect]) {
|
|
var all = require('resources').getAllSnippets(dialect);
|
|
var css = require('cssResolver');
|
|
_completions[dialect] = _.map(all, function(v, k) {
|
|
var snippetValue = typeof v.parsedValue == 'object'
|
|
? v.parsedValue.data
|
|
: v.value;
|
|
var snippet = css.transformSnippet(snippetValue, false, dialect);
|
|
return {
|
|
k: v.nk,
|
|
label: snippet.replace(/\:\s*\$\{0\}\s*;?$/, ''),
|
|
v: css.expandToSnippet(v.nk, dialect)
|
|
};
|
|
});
|
|
}
|
|
|
|
return _completions[dialect];
|
|
}
|
|
|
|
/**
|
|
* Returns current syntax name
|
|
* @return {String}
|
|
*/
|
|
function pyGetSyntax() {
|
|
var view = activeView();
|
|
var pt = view.sel()[0].begin();
|
|
var scope = 'scope_name' in view ? view.scope_name(pt) : view.syntax_name(pt);
|
|
|
|
if (~scope.indexOf('xsl')) {
|
|
return 'xsl';
|
|
}
|
|
|
|
var syntax = 'html';
|
|
|
|
// detect CSS-like syntaxes independently,
|
|
// since it may cause collisions with some highlighters
|
|
if (/\b(less|scss|sass|css|stylus)\b/.test(scope)) {
|
|
syntax = RegExp.$1;
|
|
} else if (/\b(html|xml|haml)\b/.test(scope)) {
|
|
syntax = RegExp.$1;
|
|
}
|
|
|
|
return require('actionUtils').detectSyntax(editorProxy, syntax);
|
|
}
|
|
|
|
function pyDetectProfile(argument) {
|
|
return require('actionUtils').detectProfile(editorProxy);
|
|
} |