My Vim Configuration
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

357 lines
7.2 KiB

#!/usr/bin/env node
/**
* @author: Lin Zhang ( myhere.2009 AT gmail DOT com )
* @fileoverview: This script for auto-generate nodejs-doc.vim
*/
var util = require('util'),
fs = require('fs'),
path = require('path'),
os = require('os'),
emitter = new (require('events')).EventEmitter();
init();
function init() {
initEvents();
initLoading();
getNodejsDoc();
}
function initEvents() {
// uncatched exception
process.on('uncaughtException', function(err) {
clearLoading();
console.error('Error: ' + err.stack);
});
emitter.on('vimscript/done', function(message) {
clearLoading();
console.log(message);
console.log('Done!');
});
}
function initLoading() {
var chars = [
'-',
'\\',
'|',
'/'
];
var index = 0,
total = chars.length;
initLoading.timer = setInterval(function() {
index = ++index % total;
var c = chars[index];
// clear console
// @see: https://groups.google.com/forum/?fromgroups#!topic/nodejs/i-oqYFVty5I
process.stdout.write('\033[2J\033[0;0H');
console.log('please wait:');
console.log(c);
}, 200);
}
function clearLoading() {
clearInterval(initLoading.timer);
}
function getNodejsDoc() {
var http = require('http');
var req = http.get('http://nodejs.org/api/all.json', function(res){
var chunks = [];
res.on('data', function(chunk) {
chunks.push(chunk);
});
res.on('end', function() {
var buf = Buffer.concat(chunks),
body = buf.toString('utf-8');
extract2VimScript(body);
});
}).on('error', function(e) {
console.error('problem with request: ' + e.message);
});
}
function extract2VimScript(body) {
// for debug
fs.writeFile('./nodejs-doc-all.json', body);
var json = JSON.parse(body),
vimObject;
var _globals = sortModuleByName(mergeObject(getModsInfo(json.globals),
getModsInfo(json.vars))),
_modules = sortModuleByName(getModsInfo(json.modules)),
_vars = (getVarInfo(json.vars))
.concat(getVarInfo(json.globals))
.sort(sortCompleteWord);
_globals = copyGlobals(_globals, _modules);
vimObject = {
'globals': _globals,
'modules': _modules,
'vars': _vars
};
var filename = path.join(__dirname, 'nodejs-doc.vim'),
comment = '" this file is auto created by "' + __filename + '", please do not edit it yourself!',
content = 'let g:nodejs_complete_data = ' + JSON.stringify(vimObject),
content = comment + os.EOL + content;
fs.writeFile(filename, content, function(err) {
emitter.emit('vimscript/done', 'write file to "' + filename + '" complete.');
});
// for debug
fs.writeFileSync(filename + '.js', JSON.stringify(vimObject, null, 2));
}
function getModsInfo(mods) {
var ret = {};
if (!util.isArray(mods)) {
return ret;
}
mods.forEach(function(mod) {
var mod_name = getModName(mod),
mod_props = getModProps(mod);
// class
var mod_classes = {};
var classes = mod.classes || [];
classes.forEach(function(cls) {
var names = getClassName(cls, mod_name);
var cls_name = names.cls_name,
_mod_name = names.mod_name;
if (_mod_name && mod_name != _mod_name) {
mod_name = names.mod_name;
}
mod_classes[cls_name] = getModProps(cls);
});
if (mod_props.length == 0 && classes.length == 0) {
} else {
ret[mod_name] = {
props: mod_props,
classes: mod_classes
}
}
});
return ret;
}
function getModProps(mod) {
var is_legal_property_name = function(name) {
name += '';
name = name.trim();
return (/^[$a-zA-Z_][$a-zA-Z0-9_]*$/i).test(name);
};
var props = [];
// properties
var properties = mod.properties || [];
properties.forEach(function(property) {
var name = property.name;
if (is_legal_property_name(name)) {
var item = {};
item.word = name;
item.kind = 'm';
item.info = ' ';
props.push(item);
} else {
console.log('illegal name: ' + name);
}
});
// methods
var methods = mod.methods || [];
methods.forEach(function(method) {
var name = method.name;
if (is_legal_property_name(name)) {
var item = {};
if (method.type == 'method') {
item.word = name;
item.info = method.textRaw;
item.kind = 'f';
props.push(item);
}
} else {
console.log('illegal name: ' + name);
}
});
// classes
var classes = mod.classes || [];
classes.forEach(function(cls) {
var mod_name = getModName(mod);
var names = getClassName(cls, mod_name);
var name = names.cls_name;
if (is_legal_property_name(name)) {
var item = {};
item.word = names.cls_name;
item.kind = 'f';
item.info = ' ';
props.push(item);
} else {
console.log('illegal name: ' + name);
}
});
props = props.sort(sortCompleteWord);
return props;
}
function getModName(mod) {
// module name
var mod_name = mod.name;
// invalid module name like 'tls_(ssl)'
// then guess the module name from textRaw 'TLS (SSL)'
if ((/[^_a-z\d\$]/i).test(mod_name)) {
var textRaw = mod.textRaw;
var matched = textRaw.match(/^[_a-z\d\$]+/i);
if (matched) {
var mod_name_len = matched[0].length;
mod_name = mod_name.substr(0, mod_name_len);
}
}
return mod_name;
}
function getClassName(cls, mod_name) {
var str = cls.name;
var names = str.split('.');
var _mod_name = names[0],
cls_name;
if (names.length == 1) {
cls_name = _mod_name;
}
else {
// 修正 mod_name; events.EventEmitter
if (_mod_name.toLowerCase() == mod_name.toLowerCase()) {
mod_name = _mod_name;
}
cls_name = names.slice(1).join('.');
}
return {
mod_name: mod_name,
cls_name: cls_name
};
}
function getVarInfo(vars) {
var ret = [];
if (!util.isArray(vars)) {
return ret;
}
vars.forEach(function(_var) {
// if var is a function
if ((/\([^\(\)]*\)\s*$/).test(_var.textRaw)) {
ret.push({
word: _var.name,
info: _var.textRaw,
kind: 'f'
});
} else {
ret.push({
word: _var.name,
kind: 'v',
info: ' '
});
}
});
// sort
ret = ret.sort(sortCompleteWord);
return ret;
}
function copyGlobals(globals, modules) {
var _Buffer = modules.buffer.classes.Buffer;
globals.Buffer = {
props: [],
classes: {
'.self': _Buffer
}
};
return globals;
}
// helpers
/**
* @param {Object}
*/
function sortModuleByName(mods) {
var keys = Object.keys(mods);
// sort
keys.sort();
var ret = {};
keys.forEach(function(k) {
ret[k] = mods[k];
});
return ret;
}
/**
* @param {Object}
* @param {Object}
*/
function sortCompleteWord(a, b) {
var a_w = a.word.toLowerCase(),
b_w = b.word.toLowerCase();
return a_w < b_w ? -1 : (a_w > b_w ? 1 : 0);
}
/**
* @desc merge Object
* @arguemnts: {Object}
*
* @return: return the new merged Object
*/
function mergeObject() {
var ret = {},
args = Array.prototype.slice.call(arguments);
args.forEach(function(obj) {
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
ret[p] = obj[p];
}
}
});
return ret;
}