Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/python-wasm
Path: blob/main/python/pylang/tools/completer.ts
1396 views
1
/*
2
* Copyright (C) 2021 William Stein <[email protected]>
3
* Copyright (C) 2015 Kovid Goyal <kovid at kovidgoyal.net>
4
*
5
* Distributed under terms of the BSD license
6
*/
7
8
import { runInThisContext } from "vm";
9
import { Compiler } from "./compiler";
10
11
type Token = any;
12
13
export default function Completer(compiler: Compiler) {
14
const allKeywords: string[] = compiler.ALL_KEYWORDS.split(" ");
15
16
function globalNames(): string[] {
17
try {
18
const names: string[] = runInThisContext(
19
"Object.getOwnPropertyNames((() => this)())"
20
);
21
return [...new Set(names.concat(allKeywords))].sort();
22
} catch (e) {
23
console.log(e.stack || e.toString());
24
}
25
return [];
26
}
27
28
function objectNames(obj: any, prefix: string): string[] {
29
if (obj == null) return [];
30
31
const names: string[] = [];
32
33
function add(o): void {
34
const items = Object.getOwnPropertyNames(o).filter((name) =>
35
name.startsWith(prefix)
36
);
37
names.push(...items);
38
}
39
40
let p;
41
if (typeof obj === "object" || typeof obj === "function") {
42
add(obj);
43
p = Object.getPrototypeOf(obj);
44
} else {
45
p = obj.constructor?.prototype;
46
}
47
48
// Walk the prototype chain
49
try {
50
// Circular refs possible? Let's guard against that.
51
for (let sentinel = 0; sentinel < 5 && p != null; sentinel++) {
52
add(p);
53
p = Object.getPrototypeOf(p);
54
}
55
} catch (_err) {}
56
57
// unique and sorted:
58
return [...new Set(names)].sort();
59
}
60
61
function prefixMatches(prefix: string, items: string[]): string[] {
62
return items.filter((item) => item.startsWith(prefix)).sort();
63
}
64
65
function findCompletions(line: string) {
66
let t;
67
try {
68
t = compiler.tokenizer(line, "<repl>");
69
} catch (_err) {
70
return [];
71
}
72
const tokens: Token[] = [];
73
let token: Token;
74
while (true) {
75
try {
76
token = t();
77
} catch (_err) {
78
return [];
79
}
80
if (token.type === "eof") break;
81
if (token.type === "punc" && "(){},;:".includes(token.value)) {
82
// empties the tokens since we care about what's next only
83
tokens.splice(0, tokens.length);
84
}
85
tokens.push(token);
86
}
87
if (tokens.length == 0) {
88
// New line or trailing space
89
return [globalNames(), ""];
90
}
91
let lastTok: any = tokens[tokens.length - 1];
92
if (
93
lastTok.value === "." ||
94
(lastTok.type === "name" && compiler.IDENTIFIER_PAT.test(lastTok.value))
95
) {
96
lastTok = lastTok.value;
97
if (lastTok === ".") {
98
tokens.push({ value: "" });
99
lastTok = "";
100
}
101
if (tokens.length > 1 && tokens[tokens.length - 2].value === ".") {
102
// A compound expression
103
let prefix = "";
104
let result;
105
for (const tok of tokens.slice(0, tokens.length - 2)) {
106
prefix += tok.value;
107
}
108
if (prefix) {
109
try {
110
result = runInThisContext(prefix);
111
} catch (e) {
112
return [];
113
}
114
return [objectNames(result, lastTok), lastTok];
115
}
116
} else {
117
return [prefixMatches(lastTok, globalNames()), lastTok];
118
}
119
}
120
return [];
121
}
122
123
return findCompletions;
124
}
125
126