Created
September 21, 2011 15:06
-
-
Save davestewart/1232292 to your computer and use it in GitHub Desktop.
Auto-Commenting macro for Komodo Edit
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @fileoverview Enter trigger for PHPdoc (code based on TAB trigger for Abbreviations by Stan Angeloff) | |
* @author Nathan Rijksen (http://naatan.com/) | |
* @contributor Todd Whiteman | |
* @contributor Michal Kocarek (http://brainbox.cz/) | |
* @contributor Alexander Kavoun (http://takkmoil.com/) | |
* @contributor Dave Stewart (http://davestewart.co.uk/) | |
* @version 0.3 | |
*/ | |
xjsfl.autocomment = | |
{ | |
// ---------------------------------------------------------------------------------------------------- | |
// Events | |
// ---------------------------------------------------------------------------------------------------- | |
events: | |
{ | |
add:function() | |
{ | |
this.remove(); | |
ko.views.manager.topView.addEventListener('keypress', this.onKeyPress, true); | |
}, | |
remove:function() | |
{ | |
if (xjsfl.autocomment && xjsfl.autocomment.onKeyPress) | |
{ | |
ko.views.manager.topView.removeEventListener('keypress', this.onKeyPress, true); | |
} | |
}, | |
onKeyPress:function(event) | |
{ | |
// Only trap when ENTER pressed with no modifiers | |
if (event.keyCode === 13 && ( ! event.ctrlKey && ! event.altKey && ! event.shiftKey ) ) | |
{ | |
if(xjsfl.autocomment.processInput()) | |
{ | |
event.preventDefault(); | |
event.stopPropagation(); | |
} | |
} | |
} | |
}, | |
// ---------------------------------------------------------------------------------------------------- | |
// Prefs | |
// ---------------------------------------------------------------------------------------------------- | |
prefs: | |
{ | |
tabWidth: 4, | |
fixedWidths: {tag:7, type:15, name:15}, | |
useFixedWidths: false | |
}, | |
styles: | |
{ | |
exts: | |
{ | |
php: [/^php\d?$/i], | |
js: [/^(js\w*|as)$/i] | |
}, | |
pref: 'php', | |
associate:function(rx, style) | |
{ | |
if(/^(php|js)$/i.test(style)) | |
{ | |
this.exts[style].push(rx); | |
} | |
} | |
}, | |
// ---------------------------------------------------------------------------------------------------- | |
// Input | |
// ---------------------------------------------------------------------------------------------------- | |
processInput:function() | |
{ | |
// variables | |
var view = ko.views.manager.currentView; | |
/** | |
* @type {Components.interfaces.ISciMoz} | |
*/ | |
var editor = view.scimoz; | |
// Don't do anything if there is a selection within the document | |
if (editor.anchor != editor.currentPos) | |
{ | |
return false; | |
} | |
// grab last 3 characters so we can test for /** | |
var currentPos = editor.currentPos; | |
var text = editor.getTextRange(currentPos - 3, currentPos); | |
// test for opening block comment | |
if (text !== null && text == '/**') | |
{ | |
// get the contents of the next line | |
var lineIndex = editor.lineFromPosition(currentPos); | |
var nextLineStart = editor.positionFromLine(lineIndex + 1); | |
var nextLineEnd = editor.getLineEndPosition(lineIndex + 1); | |
var nextLine = editor.getTextRange(nextLineStart, nextLineEnd); | |
// return early if the next line already starts with whitespace + a star character | |
if (/^[\t ]*\*/.test(nextLine)) | |
{ | |
return false; | |
} | |
// get doc style-type | |
var ext = view.item.url.split('.').pop(); | |
for(var style in this.styles.exts) | |
{ | |
for each(var rx in this.styles.exts[style]) | |
{ | |
if (rx.test(ext)) | |
{ | |
return this.processOutput(nextLine, style); | |
} | |
} | |
} | |
// fall back to default style | |
return this.processOutput(nextLine, this.styles.pref); | |
} | |
// return false | |
return false; | |
}, | |
// ---------------------------------------------------------------------------------------------------- | |
// Output | |
// ---------------------------------------------------------------------------------------------------- | |
processOutput:function(line, style) | |
{ | |
// -------------------------------------------------------------------------------- | |
// params object | |
/** | |
* The Param class is an object-oriented wrapper to create rows and columns of param types | |
* @param {String} kind The kind of param, i.e. @param, @returm | |
* @param {String} type The datatype of the param (if relevant) | |
* @param {String} name The name of the param | |
* @returns {String} A description of the param or return type | |
*/ | |
function Param(kind, type, name) | |
{ | |
// param values | |
this.kind = kind; | |
this.type = type || ''; | |
this.name = name || ''; | |
// update type & name column widths (declared in createOutput()) | |
widths.type = Math.max(this.type.length, widths.type); | |
widths.name = Math.max(this.name.length, widths.name); | |
// to string | |
/** | |
* Converts the Param class to a String | |
* @param {Number} padding The number of extra tabs to add | |
* @returns {String} A @param or @returns row | |
*/ | |
this.toString = function(padding) | |
{ | |
var output = ' * @'; | |
output += pad(this.kind, widths.tag, tabWidth, 0); | |
output += pad(this.type, widths.type, tabWidth, 1); | |
output += pad(this.name, widths.name, tabWidth, 1); | |
output += tabstopDesc + '\n'; | |
return output; | |
} | |
// utility function to pad columns to the correct widths | |
function pad(str, width, tabWidth, padding) | |
{ | |
// set virtual width to the initial string width | |
var vwidth = str.length; | |
var output = ''; | |
// pad initial word to the next column | |
var mod = str.length % tabWidth; | |
if(mod != 0) | |
{ | |
output += '\t'; | |
vwidth += (tabWidth - mod); | |
} | |
// while the column is smaller than the max width, pad to fit | |
while(vwidth < width) | |
{ | |
vwidth += tabWidth; | |
output += '\t'; | |
} | |
// ensure that any tabs that butt exactly up to the next tab are given space | |
if(width % tabWidth == 0) | |
{ | |
output += '\t' | |
} | |
// add any extra gutters between columns | |
output += new Array((padding || 0) + 1).join('\t') | |
// return | |
return str + output; | |
} | |
} | |
// -------------------------------------------------------------------------------- | |
// processing functions | |
function processFunction(matches) | |
{ | |
// -------------------------------------------------------------------------------- | |
// function components | |
function processParams(strParams) | |
{ | |
// variables | |
var params = []; | |
var matches = strParams.match(rxParams); | |
// loop over params | |
for each(var match in matches) | |
{ | |
// match parts | |
var parts = match.match(rxParam); | |
// create Param object | |
if(style == 'js') | |
{ | |
params.push(new Param('param', '{' + createTabstop(parts[2] || 'Type') + '}', parts[1])); | |
} | |
else | |
{ | |
params.push(new Param('param', createTabstop(parts[1]|| 'Object'), parts[2])); | |
} | |
} | |
// return | |
return params; | |
} | |
/** | |
* Processes the return type of a match and returns a Param object | |
* @param {String} type The String type of an object | |
* @returns {Param} A Param instance | |
*/ | |
function processReturn(type) | |
{ | |
// create param | |
if(style == 'js') | |
{ | |
var param = new Param('returns', '{' + createTabstop(type || 'Type') + '}', ''); | |
} | |
else | |
{ | |
var param = new Param('returns', createTabstop(type || 'Object'), ''); | |
} | |
// return | |
return param | |
} | |
// -------------------------------------------------------------------------------- | |
// process | |
// create components | |
var params = processParams(matches[1]); | |
var returns = processReturn(matches[2]); | |
// optionally hard-code columns | |
if(this.prefs.useFixedWidths) | |
{ | |
widths = this.prefs.fixedWidths; | |
} | |
// output | |
var output = '\n'; | |
output += ' * [[%tabstop:Summary]]\n'; | |
if(params && params.length) | |
{ | |
for each(var param in params) | |
{ | |
output += param.toString(); | |
} | |
} | |
output += returns.toString(); | |
output += ' */'; | |
// trace | |
return output; | |
} | |
function processClass() | |
{ | |
return '\n * ' + tabstopDesc + ' */'; | |
} | |
function processVariable() | |
{ | |
if (style == 'php') | |
{ | |
return '\n * @var ' + tabstopType + ' ' + tabstopDesc + '\n */'; | |
} | |
else if (style == 'js') | |
{ | |
return ' @type {' + tabstopType + '} ' + tabstopDesc + ' */'; | |
} | |
return ''; | |
} | |
function createTabstop(text) | |
{ | |
return '[[%tabstop:' +text+ ']]'; | |
} | |
// -------------------------------------------------------------------------------- | |
// variables | |
// matching parameters | |
var rxClass = /^\s*?class/i; | |
var rxVariable = /^\s*?(?:var|private|public|protected)/; | |
var rxFunction = /\bfunction\b\s*(?:\w*)\s*\((.*)\):?([\w\*]+)?/ | |
var rxParam = /([$\w]+)[\s:]?([$\w\*]+)?/; | |
var rxParams = new RegExp(rxParam.source, 'g'); | |
// variables | |
var tabWidth = this.prefs.tabWidth; | |
var widths = {tag:0, type:0, name:0}; | |
var matches = null; | |
var snippet = ''; | |
// tabstops | |
var tabstopType = '[[%tabstop:Type]]'; | |
var tabstopDesc = '[[%tabstop:Description]]'; | |
// -------------------------------------------------------------------------------- | |
// process | |
// process the next line | |
if(rxClass.test(line)) | |
{ | |
snippet = processClass(); | |
} | |
else if(rxFunction.test(line)) | |
{ | |
snippet = processFunction.call(this, line.match(rxFunction)); | |
} | |
else if(rxVariable.test(line)) | |
{ | |
snippet = processVariable(); | |
} | |
else | |
{ | |
return false; | |
} | |
// create the snippet | |
var snippetObj = | |
{ | |
value: snippet, | |
name: 'autodoc snippet', | |
indent_relative: 'true', | |
hasAttribute: function (name) | |
{ | |
return name in this; | |
}, | |
getStringAttribute: function (name) | |
{ | |
return this[name]; | |
} | |
}; | |
// insert snippet | |
ko.projects.snippetInsert(snippetObj); | |
// return | |
return true; | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment