/** * @fileOverview Completion request handler for skewer.js * @requires skewer * @version 1.0 */ /** * Handles a completion request from Emacs. * @param request The request object sent by Emacs * @returns The completions and init values to be returned to Emacs */ skewer.fn.complete = function(request) { var result = { type : request.type, id : request.id, strict : request.strict, status : "success" }, /** * Methods for generating candidates */ METHOD = { EVAL : 0, GLOBAL : 1 }, /** * Add the properties from object to extendObject. Properties * may be from the prototype but we still want to add them. */ extend = function(extendObject, object) { for(var key in object) { extendObject[key] = object[key]; } }, globalCompletion = function() { var global = Function('return this')(), keys = Object.keys(global); candidates = buildCandidates(global, keys); }, evalCompletion = function(evalObject) { var obj = (eval, eval)(evalObject); if (typeof obj === "object") { candidates = buildCandidates(obj) || {}; while (request.prototypes && (obj = Object.getPrototypeOf(obj)) !== null) { extend(candidates, buildCandidates(obj)); } } else if (typeof obj === "function"){ candidates = buildCandidates(obj) || {}; extend(candidates, buildCandidates(Object.getPrototypeOf(obj))); if (request.prototypes) { var protoObject = Object.getPrototypeOf(obj.prototype); if (protoObject !== null) { extend(candidates, buildCandidates(protoObject)); } else { extend(candidates, buildCandidates(obj.prototype)); } } } }, /** * Completion candidates sent back to Emacs. Keys are * completion candidates the values are the inital items or * function interfaces. */ candidates = {}, /** * Build the candiates to return to Emacs. * @param obj The object to get candidates from * @param items The selected keys from obj to create candidates for * @return object containing completion candidates and documentation strings */ buildCandidates = function(obj, items) { var keys = items || Object.getOwnPropertyNames(obj), values = {}; for (var i = 0; i < keys.length; i++) { var key = keys[i]; if (key === "callee" || key === "caller" || key === "arguments") continue; if (Object.prototype.toString.call(obj[key]) === "[object Function]") { values[key] = obj[key].toString(); } else if (typeof obj[key] === "object"){ values[key] = "[object Object]"; } else if (typeof obj[key] === "number") { if (!(obj instanceof Array)) { values[key] = obj[key].toString(); } } else if (typeof obj[key] === "string") { values[key] = obj[key].toString(); } else if(obj[key] === true) { values[key] = "true"; } else if (obj[key] === false) { values[key] = "false"; } else { values[key] = ""; } } return values; }; try { switch (request.method) { case METHOD.GLOBAL: globalCompletion(); break; default: evalCompletion(request.eval); } result.value = candidates; } catch (error){ skewer.errorResult(error, result, request); } return result; };