Skip to content
This repository has been archived by the owner on Mar 13, 2023. It is now read-only.

Commit

Permalink
New implementation of Brackets plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
sergeche committed Apr 29, 2014
1 parent 40f4c89 commit a0d348a
Show file tree
Hide file tree
Showing 8 changed files with 371 additions and 1,308 deletions.
14 changes: 9 additions & 5 deletions brackets-fs.js
@@ -1,10 +1,14 @@
define(['./path', 'filesystem/FileSystem', 'emmet/plugin/file'], function(path, fs, emmetFile) {
define(function(require, exports, module) {
var path = require('./path');
var emmetFile = require('emmet/plugin/file');
var FileSystem = brackets.getModule('filesystem/FileSystem');

emmetFile({
_exists: function(file) {

},
read: function(file, size, callback) {
var fd = fs.getFileForPath(file);
var fd = FileSystem.getFileForPath(file);
if (!fd) {
return callback('File "' + path + '" does not exists.');
}
Expand All @@ -22,7 +26,7 @@ define(['./path', 'filesystem/FileSystem', 'emmet/plugin/file'], function(path,
while (dirname && dirname !== path.dirname(dirname)) {
dirname = path.dirname(dirname);
f = path.join(dirname, fileName);
if (fs.getFileForPath(f)) {
if (FileSystem.getFileForPath(f)) {
return f;
}
}
Expand All @@ -31,7 +35,7 @@ define(['./path', 'filesystem/FileSystem', 'emmet/plugin/file'], function(path,
},

createPath: function(parent, fileName, callback) {
fs.getFileForPath(parent).exists(function(err, exists) {
FileSystem.getFileForPath(parent).exists(function(err, exists) {
if (exists) {
parent = path.dirname(parent);
}
Expand All @@ -41,7 +45,7 @@ define(['./path', 'filesystem/FileSystem', 'emmet/plugin/file'], function(path,
},

save: function(file, content) {
fs.getFileForPath(file).write(content, {encoding: 'ascii'});
FileSystem.getFileForPath(file).write(content, {encoding: 'ascii'});
}
});

Expand Down
352 changes: 194 additions & 158 deletions editor.js
@@ -1,160 +1,196 @@
define(['./emmet'], function(emmet) {
var require = emmet.require;
var _ = require('_');
/**
* Emmet Editor interface implementation for Brackets.
* Interface is optimized for multiple cursor usage: authors
* should run acttion multiple times and update `selectionIndex`
* property on each iteration.
*/
define(function(require, exports, module) {
var emmet = require('emmet/emmet');
var utils = require('emmet/utils/common');
var editorUtils = require('emmet/utils/editor');
var actionUtils = require('emmet/utils/action');
var tabStops = require('emmet/assets/tabStops');

var modeMap = {
"text/html": "html",
"htmlmixed": "html",
"text/x-brackets-html": "html",
"application/xml": "xml",
"text/xsl": "xsl",
"text/css": "css",
"text/x-less": "less",
"text/x-scss": "scss",
"text/x-sass": "sass",
"php": "html"
};

return {
context: null,
filePath: null,
setupContext: function (context, filePath) {
this.context = context;
this.filePath = filePath;
var indentation = "\t";
if (!context.getOption("indentWithTabs")) {
indentation = require("utils").repeatString(" ", context.getOption("indentUnit"));
}

require("resources").setVariable("indentation", indentation);
},

getSelectionRange: function () {
var caretPos = this.getCaretPos();
return {
start: caretPos,
end: caretPos + this.getSelection().length
};
},

createSelection: function (start, end) {
if (start == end) {
this.context.setCursor(this.context.posFromIndex(start));
} else {
this.context.setSelection(this.context.posFromIndex(start), this.context.posFromIndex(end));
}
},

getCurrentLineRange: function () {
var caret = this.context.getCursor(true);
return {
start: this.context.indexFromPos({line: caret.line, ch: 0}),
end: this.context.indexFromPos({line: caret.line, ch: this.context.getLine(caret.line).length})
};
},

getCaretPos: function () {
return this.context.indexFromPos(this.context.getCursor(true));
},

setCaretPos: function (pos) {
this.createSelection(pos, pos);
},

getCurrentLine: function () {
return this.context.getLine(this.context.getCursor(true).line) || "";
},

replaceContent: function (value, start, end, noIndent) {
if (_.isUndefined(end))
end = _.isUndefined(start) ? value.length : start;
if (_.isUndefined(start)) start = 0;
var utils = require("utils");

// indent new value
if (!noIndent) {
value = utils.padString(value, utils.getLinePaddingFromPosition(this.getContent(), start));
}

// find new caret position
var tabstopData = 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
};
}

// do a compound change to record all changes into single undo event
var that = this;
var op = this.context.operation || this.context.compoundChange;
op.call(this.context, function() {
that.context.replaceRange(value, that.context.posFromIndex(start), that.context.posFromIndex(end));
that.createSelection(firstTabStop.start, firstTabStop.end);
});
},

getContent: function () {
return this.context.getValue();
},

getCMSyntax: function() {
var syntax = this.context.getOption("mode");
return syntax in modeMap ? modeMap[syntax] : syntax;
},

getSyntax: function () {
var syntax = this.getCMSyntax();
return require('actionUtils').detectSyntax(this, syntax);
},

/**
* Returns current output profile name (@see emmet#setupProfile)
* @return {String}
*/
getProfileName: function () {
if (this.context.getOption("profile"))
return this.context.getOption("profile");

return require('actionUtils').detectProfile(this);
},

/**
* Ask user to enter something
* @param {String} title Dialog title
* @return {String} Entered data
* @since 0.65
*/
prompt: function (title) {
return prompt(title);
},

/**
* Returns current selection
* @return {String}
* @since 0.65
*/
getSelection: function () {
return this.context.getSelection() || "";
},

/**
* Returns current editor"s file path
* @return {String}
* @since 0.65
*/
getFilePath: function () {
return this.filePath;
}
};
var Editor = brackets.getModule('editor/Editor').Editor;

/**
* Normalizes text before it goes to editor: replaces indentation
* and newlines with ones used in editor
* @param {String} text Text to normalize
* @param {Editor} editor Brackets editor instance
* @return {String}
*/
function normalize(text, editor) {
var indentation = '\t';
if (!Editor.getUseTabChar()) {
indentation = '';
var units = Editor.getSpaceUnits();
while (units--) {
indentation += ' ';
}
}

return editorUtils.normalize(text, {
indentation: indentation,
newline: '\n'
});
}

return {
editor: null,
selectionIndex: 0,
modeMap: {
'text/html': 'html',
'application/xml': 'xml',
'text/xsl': 'xsl',
'text/css': 'css',
'text/x-less': 'less',
'text/x-scss': 'scss',
'text/x-sass': 'sass'
},

setup: function(editor, selIndex) {
this.editor = editor;
this.selectionIndex = selIndex || 0;
},

_convertRange: function(sel) {
return {
start: this.editor.indexFromPos(sel.start),
end: this.editor.indexFromPos(sel.end)
};
},

_currentLineRange: function() {
var sel = this.editor.getSelections()[this.selectionIndex];
return this.editor.convertToLineSelections([sel])[0].selectionForEdit;
},

_posFromIndex: function(index) {
// XXX: shouldn’t use private editor._codeMirror here,
// Brackets must provide `posFromIndex()` method alias
return this.editor._codeMirror.posFromIndex(index);
},

/**
* Returns list of selections for current CodeMirror instance.
* @return {Array}
*/
selectionList: function() {
return this.editor.getSelections().map(this._convertRange, this);
},

getCaretPos: function() {
return this.getSelectionRange().start;
},

setCaretPos: function(pos) {
this.createSelection(pos);
},

/**
* Returns current selection range (for current selection index)
* @return {Object}
*/
getSelectionRange: function() {
return this.selectionList()[this.selectionIndex];
},

createSelection: function(start, end) {
end = end || start;

var sels = this.editor.getSelections();
sels[this.selectionIndex] = {
start: this._posFromIndex(start),
end: this._posFromIndex(end)
};
this.editor.setSelections(sels);
},

/**
* Returns current selection
* @return {String}
*/
getSelection: function() {
var sel = this.editor.getSelections()[this.selectionIndex];
return this.editor.document.getRange(sel.start, sel.end);
},

getCurrentLineRange: function() {
return this._convertRange(this._currentLineRange());
},

getCurrentLine: function() {
var lineRange = this._currentLineRange();
return this.editor.document.getRange(lineRange.start, lineRange.end);
},

getContent: function() {
return this.editor.document.getText();
},

replaceContent: function(value, start, end, noIndent) {
if (typeof end == 'undefined') {
end = (typeof start == 'undefined') ? this.getContent().length : start;
}
if (typeof start == 'undefined') {
start = 0;
}

// indent new value
if (!noIndent) {
value = utils.padString(value, utils.getLinePaddingFromPosition(this.getContent(), start));
}

// find new caret position
var tabstopData = tabStops.extract(value, {
escape: function(ch) {
return ch;
}
});
value = tabstopData.text;

var firstTabStop = tabstopData.tabstops[0] || {start: value.length, end: value.length};
firstTabStop.start += start;
firstTabStop.end += start;

this.editor.document.replaceRange(value, this._posFromIndex(start), this._posFromIndex(end));
this.createSelection(firstTabStop.start, firstTabStop.end);
},

getSyntax: function() {
var sel = this.editor.getSelections()[this.selectionIndex];
var mode = this.editor.getModeForRange(sel.start, sel.end).name;
return this.modeMap[mode] || mode;
},

/**
* Returns current output profile name (@see emmet#setupProfile)
* @return {String}
*/
getProfileName: function() {
return actionUtils.detectProfile(this);
},

/**
* Ask user to enter something
* @param {String} title Dialog title
* @return {String} Entered data
*/
prompt: function(title) {
return prompt(title);
},

/**
* Returns current editor's file path
* @return {String}
*/
getFilePath: function() {
if (this.editor.document.isUntitled()) {
return null;
}

return this.editor.document.file.fullPath;
}
};
});

0 comments on commit a0d348a

Please sign in to comment.