1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
/**
* @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;
};
|