1 | import javax.swing.event.AncestorListener; |
2 | import javax.swing.event.AncestorEvent; |
3 | import javax.swing.Timer; |
4 | public class main { |
5 | static class GenTesting { |
6 | Object makeGenerators; // voidfunc(L<Gen> gens, L<S> log) |
7 | |
8 | // method to compare generator output & user line |
9 | String comparison = "eqic"; |
10 | |
11 | GenTesting(Object makeGenerators) { |
12 | this.makeGenerators = makeGenerators;} |
13 | |
14 | MultiSet<String> scoreGenerators(List<String> log) { |
15 | return scoreGenerators(log, null); |
16 | } |
17 | |
18 | MultiSet<String> scoreGenerators(List<String> log, BitSet interestingLines) { |
19 | new MultiSet<String> scores; |
20 | for (int i = 0; i < l(log); i++) |
21 | if (interestingLines == null || interestingLines.get(i)) |
22 | scoreGenerators1(subList(log, 0, i+1), scores); |
23 | print(/*asciiHeading2("SCORES")*/); |
24 | for (String name : scores.getTopTen()) |
25 | print(" [" + scores.get(name) + "] " + name); |
26 | print(); |
27 | return scores; |
28 | } |
29 | |
30 | void scoreGenerators1(List<String> log, MultiSet<String> scores) { |
31 | if (empty(log)) return; |
32 | String line = last(log); |
33 | log = dropLast(log); |
34 | |
35 | genLog_set(log); |
36 | try { |
37 | List<Gen> gens = makeGenerators(log); |
38 | |
39 | for (Gen gen : gens) { |
40 | try { |
41 | if (compare(callGen(gen), line)) |
42 | scores.add(gen.name); |
43 | } catch (Throwable _e) {} |
44 | } |
45 | } finally { |
46 | genLog_clear(); |
47 | } |
48 | } |
49 | |
50 | String callSingle(List<String> log, Object genName) { |
51 | genLog_set(log); |
52 | try { |
53 | List<Gen> gens = makeGenerators(log); |
54 | Gen gen = findByField(gens, "name", genName); |
55 | if (gen == null) return null; |
56 | return callGen(gen); |
57 | } finally { |
58 | genLog_clear(); |
59 | } |
60 | } |
61 | |
62 | boolean verifySingle(List<String> log, Object genName) { |
63 | if (empty(log)) return false; |
64 | String line = last(log); |
65 | log = dropLast(log); |
66 | |
67 | genLog_set(log); |
68 | try { |
69 | List<Gen> gens = makeGenerators(log); |
70 | Gen gen = findByField(gens, "name", genName); |
71 | if (gen == null) return false; |
72 | |
73 | try { |
74 | if (compare(callGen(gen), line)) return true; |
75 | } catch (Throwable _e) {} return false; |
76 | } finally { |
77 | genLog_clear(); |
78 | } |
79 | } |
80 | |
81 | List<Gen> makeGenerators(List<String> log) { |
82 | new List<Gen> gens; |
83 | callF(makeGenerators, gens, log); |
84 | return gens; |
85 | } |
86 | |
87 | // returns score |
88 | int scoreGenerator(List<String> log, String genName) { |
89 | int score = 0; |
90 | for (int i = 1; i < l(log); i++) { |
91 | String expect = log.get(i), s = null; |
92 | boolean ok = false; |
93 | try { |
94 | s = callSingle(subList(log, 0, i), genName); |
95 | ok = compare(s, expect); |
96 | } catch (Throwable e) { |
97 | s = exceptionToStringShort(e); |
98 | } |
99 | if (ok) { |
100 | ++score; |
101 | print(genName + " OK: " + s + (eq(s, expect) ? "" : " / " + expect)); |
102 | } else |
103 | print(genName + " NO [" + s + "]: " + expect); |
104 | } |
105 | print(); |
106 | return score; |
107 | } |
108 | |
109 | boolean compare(String a, String b) { |
110 | if (eq(comparison, "eq")) |
111 | return eq(a, b); |
112 | else if (eq(comparison, "eqic")) |
113 | return eqic(a, b); |
114 | else if (eq(comparison, "match")) |
115 | return match(a, b); |
116 | else |
117 | throw fail("Unknown comparison: " + comparison); |
118 | } |
119 | |
120 | // run a single generator on all lines and print each line |
121 | void debugSingle(List<String> log, String name) { |
122 | for (int i = 0; i < l(log); i++) |
123 | debugSingle1(subList(log, 0, i+1), name); |
124 | } |
125 | |
126 | void debugSingle1(List<String> log, String genName) { |
127 | String line = last(log); |
128 | log = dropLast(log); |
129 | |
130 | genLog_set(log); |
131 | try { |
132 | List<Gen> gens = makeGenerators(log); |
133 | Gen gen = findByField(gens, "name", genName); |
134 | if (gen == null) return; |
135 | |
136 | boolean ok = false; |
137 | try { |
138 | ok = compare(callGen(gen), line); |
139 | } catch (Throwable _e) {} |
140 | |
141 | print((ok ? "OK" : "NO") + " " + line); |
142 | } finally { |
143 | genLog_clear(); |
144 | } |
145 | } |
146 | } // GenTesting |
147 | |
148 | static class Thinker { |
149 | List<String> ranking = synchroList(); |
150 | int listMakingTimeout = 2000; |
151 | int maxListLength = 100; |
152 | boolean showExceptions, debug; |
153 | volatile int load; |
154 | |
155 | void startUp(List<String> log) { |
156 | readLocally2(this, "ranking"); |
157 | print("Ranking: " + structure(ranking)); |
158 | } |
159 | |
160 | MultiSet<String> scores(List<String> log) { |
161 | return makeGT().scoreGenerators(log); |
162 | } |
163 | |
164 | MultiSet<String> scores(List<String> log, BitSet interestingLines) { |
165 | return makeGT().scoreGenerators(log, interestingLines); |
166 | } |
167 | |
168 | GenTesting makeGT() { |
169 | return new GenTesting(new Object { void get(List<Gen> gens, List<String> log) { makeGenerators(gens, log); } |
170 | public String toString() { return "makeGenerators(gens, log);"; }}); |
171 | } |
172 | |
173 | // also called from outside |
174 | void recommendSolver(String solverID) { |
175 | if (!isRecommendedSolver(solverID = fsi(solverID))) { |
176 | print("Adding recommended solver: " + solverID); |
177 | logQuoted("recommendations.txt", solverID); |
178 | } else |
179 | print("Solver already recommended: " + solverID); |
180 | } |
181 | |
182 | boolean isRecommendedSolver(String solverID) { |
183 | return contains(scanLog("recommendations.txt"), fsI(solverID)); |
184 | } |
185 | |
186 | // log = what's in the chat |
187 | // input = what user is typing |
188 | void makeListData(List<String> thelog, String input, List l) { |
189 | long started = now(); |
190 | try { |
191 | long timeout = started + listMakingTimeout; |
192 | new HashMap<String, Map> seen; // maps to the line |
193 | |
194 | // extended log including what user is typing |
195 | List<String> xlog = listPlus(thelog, input); |
196 | |
197 | // Make generators for both modes |
198 | |
199 | new List<Gen> gens; |
200 | for (boolean completing : ll(false, true)) { |
201 | new List<Gen> gens_; |
202 | try { |
203 | genLog_set(completing ? xlog : log); |
204 | gCompleting_set(completing); |
205 | makeGenerators(gens_, log); |
206 | for (Gen g : gens_) |
207 | gens.add(new Gen(g.name + gMode(), g.func)); |
208 | } finally { |
209 | genLog_clear(); |
210 | gCompleting_set(null); |
211 | } |
212 | } |
213 | |
214 | // Rank all generators |
215 | |
216 | gens = rankGenerators(gens); |
217 | |
218 | // Produce list |
219 | |
220 | int i = -1; |
221 | while (now() < timeout && l(l) < maxListLength && nempty(gens)) { |
222 | i = (i+1) % l(gens); |
223 | Gen gen = gens.get(i); |
224 | boolean completing = gen.name.endsWith("/i"); |
225 | |
226 | try { |
227 | genLog_set(completing ? xlog : log); |
228 | gCompleting_set(completing); |
229 | boolean remove = false; |
230 | if (debug) |
231 | print("Trying generator " + gen.name); |
232 | try { |
233 | String s = callGen(gen); |
234 | if (empty(s) || eq(input, s)) |
235 | remove = true; |
236 | else if (seen.containsKey(s)) { |
237 | Map line = seen.get(s); |
238 | setAdd((List) line.get("Suggesters"), gen.name); |
239 | remove = true; |
240 | } else { |
241 | int k = l(l)+1; |
242 | String key = k <= 12 ? "F" + k : null; |
243 | Map line = litorderedmap("Key", key, "Suggestion", s, "Suggesters", ll(gen.name)); |
244 | l.add(line); |
245 | seen.put(s, line); |
246 | } |
247 | } catch (Throwable e) { |
248 | if (showExceptions) |
249 | l.add(litorderedmap("Suggestion", "[error] " + exceptionToStringShort(e), "Suggesters", ll(gen.name))); |
250 | remove = true; |
251 | } |
252 | if (remove) |
253 | gens.remove(i--); |
254 | } finally { |
255 | genLog_clear(); |
256 | gCompleting_set(null); |
257 | } |
258 | } |
259 | } catch (Throwable e) { |
260 | printStackTrace(e); |
261 | l.add(e.toString()); |
262 | } finally { |
263 | load = (int) ((now()-started)*100/listMakingTimeout); |
264 | } |
265 | } |
266 | |
267 | List<Gen> rankGenerators(List<Gen> gens) { |
268 | Map<String, Gen> index = indexByField(gens, "name"); |
269 | new List<Gen> l; |
270 | List<String> rank = cloneList(ranking); |
271 | for (String name : rank) { |
272 | Gen g = index.get(name); |
273 | if (g != null) { |
274 | l.add(g); |
275 | index.remove(name); |
276 | } |
277 | } |
278 | l.addAll(values(index)); // add rest in unspecified order |
279 | //print("Using ranking: " + struct(rank)); |
280 | //print("Ranked generators: " + struct(l)); |
281 | return l; |
282 | } |
283 | |
284 | void rankToTop(String name) { |
285 | if (empty(name)) return; |
286 | if (eq(first(ranking), name)) return; |
287 | ranking.remove(name); |
288 | ranking.add(0, name); |
289 | saveLocally2(this, "ranking"); |
290 | print("New ranking: " + structure(ranking)); |
291 | } |
292 | } // Thinker |
293 | static String generatorsID; |
294 | |
295 | static JFrame frame; |
296 | static JTable table, chatTable; |
297 | //static JTextArea chat; |
298 | static JTextField input; |
299 | static List<String> log = synchroList(); |
300 | static List<String> recommendations; |
301 | static List<Thread> thinkThreads = synchroList(); |
302 | static JLabel status; |
303 | static String lastInput; |
304 | |
305 | static int listDelay = 2000; |
306 | static int maxLineLength = 1000; |
307 | static int maxLongStringLength = 100*1000; |
308 | |
309 | static Boolean thinking; |
310 | static new Thinker thinker; |
311 | static boolean showCPU = true; |
312 | |
313 | static String systemPrefix = "[system]"; |
314 | |
315 | static String dialog = "new"; |
316 | |
317 | static void randomMain() { |
318 | //substanceLAF("EmeraldDusk"); // Too dark! |
319 | //substanceLAF("ChallengerDeep"); // So purple! |
320 | //substance("MistAqua"); |
321 | substance("Moderate"); |
322 | |
323 | table = tableWithTooltips(); |
324 | //chat = autoScroll(wordWrapTextArea()); |
325 | chatTable = tableWithTooltips(); |
326 | input = new JTextField; |
327 | status = new JLabel(" "); |
328 | |
329 | frame = showFrame(vgrid(centerAndSouth( |
330 | //jtabs(1, "Chat", chat, "Details", chatTable), |
331 | chatTable, |
332 | input), centerAndSouth(table, status))); |
333 | //setFrameIconLater(frame, "#1003593"); |
334 | |
335 | addMenu(frame, "Random", |
336 | "Delete last line (!delete)", new Runnable() { public void run() { try { post("!delete"); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}, |
337 | "Reload generators (!gen)", new Runnable() { public void run() { try { post("!gen"); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}, |
338 | "Restart app (!restart)", new Runnable() { public void run() { try { post("!restart"); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}, |
339 | "Restart Java engine (!fresh)", new Runnable() { public void run() { try { post("!fresh"); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}, |
340 | "Execute Java code (!j ...)", new Runnable() { public void run() { try { setInput("!j 1+2"); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}, |
341 | "Switch dialog (!dialog ...)", new Runnable() { public void run() { try { setInput("!dialog bla"); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}, |
342 | "Restore last input", new Runnable() { public void run() { try { if (nempty(lastInput)) setInput(lastInput); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}, |
343 | "Show raw dialog", new Runnable() { public void run() { try { showText("Raw Dialog", rawDialog()); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}); |
344 | |
345 | onEnter(input, new Runnable() { public void run() { try { |
346 | post(); |
347 | } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}); |
348 | |
349 | onDoubleClick(table, new Object { void get(int row) { |
350 | chooseSuggestion(row); |
351 | } |
352 | public String toString() { return "chooseSuggestion(row);"; }}); |
353 | |
354 | for (int i = 1; i <= 12; i++) { |
355 | final int _i = i; |
356 | registerFunctionKey(frame, i, new Runnable() { public void run() { try { |
357 | chooseSuggestionForEditing(_i-1); |
358 | } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}); |
359 | registerShiftFunctionKey(frame, i, new Runnable() { public void run() { try { |
360 | chooseSuggestion(_i-1); |
361 | } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}); |
362 | } |
363 | |
364 | onUpdate(input, new Runnable() { public void run() { try { updateOnce(); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}); |
365 | |
366 | loadDialog(); |
367 | logEvent("Starting"); |
368 | |
369 | updateOnce(); |
370 | |
371 | input.requestFocus(); |
372 | |
373 | if (isAction(last(log)) && confirmYesNo(input, "Run action? " + last(log))) |
374 | action(last(log)); |
375 | } |
376 | |
377 | static String getInput() { |
378 | return joinLines(" # ", input.getText().trim()); |
379 | } |
380 | |
381 | static void post() { |
382 | postAsUser(getInput(), null); |
383 | } |
384 | |
385 | static void postAsUser(String i, Map infos) { |
386 | if (inputAllowedByUser(i)) |
387 | post(i, infos); |
388 | } |
389 | |
390 | static void chooseSuggestionForEditing(int row) { |
391 | Map<String, String> map = getTableLineAsMap(table, row); |
392 | if (map == null) return; |
393 | rankToTop(map); |
394 | String s = trim(unnull(map.get("Suggestion"))); |
395 | logEvent("Suggestion chosen for editing", mapPlus(map, "Row", row+1, "Input", getInput(), "Top Suggesters", topSuggesters())); |
396 | setInput(s); |
397 | } |
398 | |
399 | static void setInput(final String s) { |
400 | swingNowOrLater(r { |
401 | lastInput = input.getText(); |
402 | input.setText(s); |
403 | input.selectAll(); |
404 | input.requestFocus(); |
405 | }); |
406 | } |
407 | |
408 | static void rankToTop(Map map) { |
409 | // Table cells have been structure'd by dataToTable |
410 | thinker.rankToTop(first((List<String>) unstructure(getString(map, "Suggesters")))); |
411 | } |
412 | |
413 | static void chooseSuggestion(int row) { |
414 | Map<String, String> map = getTableLineAsMap(table, row); |
415 | if (map == null) return; |
416 | rankToTop(map); |
417 | String s = trim(unnull(map.get("Suggestion"))); |
418 | if (empty(s)) return; |
419 | |
420 | //logEvent("Suggestion chosen", mapPlus(map, "Row", row+1, "Input", getInput(), "Top Suggesters", topSuggesters)); |
421 | setInput(s); |
422 | postAsUser(s, mapPlus(map, "Index", row+1)); |
423 | } |
424 | |
425 | static List topSuggesters() { |
426 | int n = 20; |
427 | n = min(n, tableRows(table)); |
428 | new List topSuggesters; |
429 | for (int i = 0; i < n; i++) |
430 | topSuggesters.add(getTableLineAsMap(table, i)); |
431 | //if (empty(topSuggesters)) topSuggesters = null; |
432 | return topSuggesters; |
433 | } |
434 | |
435 | static void logEvent(String type) { |
436 | logEvent(type, litmap()); |
437 | } |
438 | |
439 | static void logEvent(String type, Map map) { |
440 | logStructure(new File(dialogDir(), "event.log"), |
441 | ll(type, chatTime(), map)); |
442 | } |
443 | |
444 | static boolean inputAllowedByUser(String i) { |
445 | return !swic(i, systemPrefix); |
446 | } |
447 | |
448 | // may be called from other thread |
449 | static void postSystemMessage(final String msg) { |
450 | if (empty(msg)) return; |
451 | swingNowOrLater(r { |
452 | post(systemPrefix + " " + msg, litmap("By", "System")); |
453 | }); |
454 | } |
455 | |
456 | static void post(String i) { |
457 | post(i, null); |
458 | } |
459 | |
460 | static void post(String i, Map infos) { |
461 | try { |
462 | i = trim(i); |
463 | if (empty(i)) return; |
464 | //i = escapeNewLines(i); |
465 | infos = mapPlus(infos, "Top Suggesters", topSuggesters()); |
466 | |
467 | boolean tooLong = l(i) > maxLongStringLength; |
468 | |
469 | if (l(i) > maxLineLength) { |
470 | String id = saveLongString(i); |
471 | i = substring(i, 0, maxLineLength) + "... [" + (tooLong ? "too " : "") + "long text " + id + "]"; |
472 | } |
473 | } catch (Throwable e) { |
474 | printStackTrace(e); |
475 | i = systemPrefix + " " + exceptionToStringShort(e); |
476 | } |
477 | |
478 | String s = i + "\n"; |
479 | //chat.append(escapeNewLines(i) + "\n"); |
480 | appendToFile(logFile(), "[" + chatTime() + "] " + s); |
481 | logEvent("Posting", litmap("Text", i, "Infos", infos)); |
482 | log.add(i); |
483 | updateChatTable(); |
484 | input.selectAll(); |
485 | updateOnce(); |
486 | try { |
487 | action(i); |
488 | } catch (Throwable e) { |
489 | printStackTrace(e); |
490 | postSystemMessage(exceptionToStringShort(e)); |
491 | } |
492 | } |
493 | |
494 | static String dropActionPrefix(String s) { |
495 | if (s == null) return null; |
496 | s = dropBracketPrefix(s); // e.g. "[bot]" |
497 | if (!s.startsWith("!")) return null; |
498 | return s.substring(1); |
499 | } |
500 | |
501 | static boolean isAction(String s) { |
502 | return dropActionPrefix(s) != null; |
503 | } |
504 | |
505 | static void action(String s) { |
506 | s = dropActionPrefix(s); |
507 | if (s == null) return; |
508 | |
509 | final String _s = s; |
510 | { Thread _t_0 = new Thread("Action") { |
511 | public void run() { |
512 | try { |
513 | { JWindow _loading_window = showLoadingAnimation(); try { |
514 | try { |
515 | genLog_set(getLog()); // 'case user needs it |
516 | randomsOwnCmds(_s); |
517 | systemCommands(_s); |
518 | } catch (Throwable e) { |
519 | printStackTrace(e); |
520 | postSystemMessage("Error - " + exceptionToStringShort(e)); |
521 | } |
522 | } finally { disposeWindow(_loading_window); }} |
523 | } catch (Exception _e) { |
524 | throw _e instanceof RuntimeException ? (RuntimeException) _e : new RuntimeException(_e); } } |
525 | }; |
526 | _t_0.start(); } |
527 | } |
528 | |
529 | static volatile boolean again; |
530 | |
531 | // This logic is bad... |
532 | static void fillList(boolean force) { |
533 | boolean t = force || shouldUpdateList(); |
534 | if (neq(t, thinking)) { |
535 | thinking = t; |
536 | setFrameIcon(table, t ? "#1003603" : "#1003593"); |
537 | } |
538 | |
539 | if (!t) { |
540 | if (!force) |
541 | againl8r(); |
542 | } else { |
543 | if (nempty(thinkThreads)) { again = true; return; } |
544 | fillListImpl(); |
545 | } |
546 | } |
547 | |
548 | static void fillListImpl() { |
549 | { Thread _t_1 = new Thread("Fill List") { |
550 | public void run() { |
551 | try { |
552 | try { |
553 | thinkThreads.add(currentThread()); |
554 | final new List<String> data; |
555 | thinker.makeListData(cloneList(log), getInput(), data); |
556 | |
557 | swingLater(new Runnable() { public void run() { try { |
558 | try { |
559 | dataToTable_uneditable(table, data); |
560 | tableColumnMaxWidth(table, 0, 30); // "Key" column |
561 | } catch (Throwable __e) { printStackTrace(__e); } |
562 | againl8r(); |
563 | } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}); |
564 | } finally { |
565 | thinkThreads.remove(currentThread()); |
566 | if (again) { again = false; fillListImpl(); } |
567 | } |
568 | } catch (Exception _e) { |
569 | throw _e instanceof RuntimeException ? (RuntimeException) _e : new RuntimeException(_e); } } |
570 | }; |
571 | _t_1.start(); } |
572 | } |
573 | |
574 | static void updateOnce() { fillList(true); } |
575 | |
576 | static void againl8r() { |
577 | swingAfter(table, listDelay, new Runnable() { public void run() { try { fillList(false); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}); |
578 | } |
579 | |
580 | static boolean shouldUpdateList() { |
581 | boolean result = false; |
582 | String text = " "; |
583 | if (getFrame(table).isFocused()) { |
584 | result = !mouseInComponent(table); |
585 | text = result ? " Thinking..." + (showCPU && thinker.load != 0 ? " (" + thinker.load + "%)" : "") |
586 | : "Not thinking cause you got the mouse in there"; |
587 | } |
588 | status.setText(text); |
589 | return result; |
590 | } |
591 | |
592 | // also called from outside |
593 | static List<String> loadLog() { |
594 | log.clear(); |
595 | log.addAll(collect(scanEventLogForPosts(dialogDir()), "text")); |
596 | return log; |
597 | } |
598 | |
599 | synchronized static List<String> getLastFromLog(int n) { |
600 | return cloneList(getLast(log, n)); |
601 | } |
602 | |
603 | synchronized static List<String> getLog() { |
604 | return cloneList(log); |
605 | } |
606 | |
607 | static File dialogDir() { |
608 | return prepareProgramFile(dialog); |
609 | } |
610 | |
611 | static File logFile() { |
612 | return new File(dialogDir(), "log.txt"); |
613 | } |
614 | |
615 | static void switchDialog(final String name) { |
616 | swingAndWait(new Runnable() { public void run() { try { |
617 | dialog = name; |
618 | loadDialog(); |
619 | } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}); |
620 | } |
621 | |
622 | static void loadDialog() { |
623 | loadLog(); |
624 | thinker = new Thinker; |
625 | thinker.startUp(log); |
626 | //chat.setText(joinLines(log)); |
627 | updateChatTable(); |
628 | } |
629 | |
630 | static void randomsOwnCmds(String s) { |
631 | new Matches m; |
632 | if (match("dialog *", s, m)) { |
633 | switchDialog(m.unq(0)); |
634 | // TODO: show current dialog somewhere else |
635 | //postSystemMessage("OK, dialog switched to " + quote(dialog)); |
636 | } |
637 | |
638 | if (match("gen", s, m)) |
639 | generators = null; |
640 | |
641 | if (match("delete", s, m)) |
642 | updateChatTable(); |
643 | } |
644 | |
645 | static void updateChatTable() { |
646 | swingNowOrLater(r { |
647 | new List data; |
648 | List<List> l = scanLog_safeUnstructure(new File(dialogDir(), "event.log")); |
649 | for (int i = 0; i < l(l); i++) try { |
650 | List a = l.get(i), prev = get(l, i-1); |
651 | if (firstIs(a, "Posting")) { |
652 | Map map = (Map) ( get(a, 2)); |
653 | String text = getString(map, "Text").trim(); |
654 | if (eq(text, "!delete")) { removeLast(data); continue; } |
655 | String idx = ""; |
656 | Map infos = (Map) ( map.get("Infos")); |
657 | if (infos != null && infos.containsKey("Index")) |
658 | idx = str(infos.get("Index")); |
659 | else try { |
660 | //printStruct("prev: ", prev); |
661 | if (prev != null && firstIs(prev, "Suggestion chosen for editing")) { |
662 | Map m = getMap(prev, 2); |
663 | String suggestion = getString(m, "Suggestion"); |
664 | //print("Suggestion: " + structure(suggestion)); |
665 | idx = str(get(m, "Row")); |
666 | if (neq(suggestion, text)) |
667 | idx += "?"; |
668 | } |
669 | } catch (Throwable __e) { printStackTrace(__e); } |
670 | data.add(litorderedmap("Text", escapeNewLines(text), "Sugg." /* Suggestion Index */, idx)); |
671 | } |
672 | } catch (Throwable __e) { printStackTrace(__e); } |
673 | dataToTable_uneditable(chatTable, data); |
674 | tableColumnMaxWidth(chatTable, 1, 40); // enough for 2 digits and a "?" |
675 | scrollTableDown(chatTable); |
676 | }); |
677 | } |
678 | |
679 | static synchronized String saveLongString(String s) { |
680 | s = substring(s, 0, maxLongStringLength); |
681 | String id; |
682 | File f; |
683 | do { |
684 | id = randomID(10); |
685 | f = getProgramFile("long-strings/" + id); |
686 | } while (f.exists()); |
687 | |
688 | saveTextFile(f, s); |
689 | return id; |
690 | } |
691 | |
692 | static Object generators; |
693 | |
694 | static void makeGenerators(List<Gen> l, List<String> log) { |
695 | synchronized(main.class) { |
696 | if (!isSnippetID(generatorsID)) fail("No generators ID set"); |
697 | if (generators == null) |
698 | generators = hotwire(generatorsID); |
699 | } |
700 | new List l2; |
701 | callOpt(generators, "makeGenerators", l2, log); |
702 | callOpt(generators, "deterministicGenerators", l2); |
703 | l.addAll((List) quickImport(l2)); |
704 | } |
705 | |
706 | static String rawDialog() { |
707 | return fromLines(log); |
708 | } // Random Main v9 |
709 | |
710 | p { swingLater(new Runnable() { public void run() { try { |
711 | generatorsID = "#1004039"; |
712 | randomMain(); |
713 | } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});} |
714 | |
715 | |
716 | static JTextArea showText(final String title, final String text) { |
717 | return (JTextArea) swingAndWait(new Object { Object get() { |
718 | JTextArea textArea = newTypeWriterTextArea(text); |
719 | makeFrame(title, new JScrollPane(textArea)); |
720 | return textArea; |
721 | } |
722 | public String toString() { return "JTextArea textArea = newTypeWriterTextArea(text);\r\n makeFrame(title, new JScrollPane(textArea));\r\n ret textArea;"; }}); |
723 | } |
724 | |
725 | static JTextArea showText(Object text) { |
726 | return showText(str(text)); |
727 | } |
728 | |
729 | static JTextArea showText(String text) { |
730 | return showText(autoFrameTitle(), text); |
731 | } |
732 | |
733 | static Object callF(Object f, Object... args) { |
734 | return callFunction(f, args); |
735 | } |
736 | static String[] dropLast(String[] a, int n) { |
737 | n = Math.min(n, a.length); |
738 | String[] b = new String[a.length-n]; |
739 | System.arraycopy(a, 0, b, 0, b.length); |
740 | return b; |
741 | } |
742 | |
743 | static <A> List<A> dropLast(List<A> l) { |
744 | return subList(l, 0, l(l)-1); |
745 | } |
746 | static Map<String, String> getTableLineAsMap(JTable tbl, int row) { |
747 | if (row >= 0 && row < tbl.getModel().getRowCount()) { |
748 | new Map<String, String> map; |
749 | for (int i = 0; i < tbl.getModel().getColumnCount(); i++) |
750 | map.put(tbl.getModel().getColumnName(i), |
751 | String.valueOf(tbl.getModel().getValueAt(row, i))); |
752 | return map; |
753 | } |
754 | return null; |
755 | } |
756 | static JPanel vgrid(List parts) { |
757 | return vgrid(asArray(parts)); |
758 | } |
759 | |
760 | static JPanel vgrid(Object... parts) { |
761 | new JPanel panel; |
762 | panel.setLayout(new GridLayout(parts.length, 1)); |
763 | smartAdd(panel, parts); |
764 | return panel; |
765 | } |
766 | static String trim(String s) { return s == null ? null : s.trim(); } |
767 | static String trim(StringBuilder buf) { return buf.toString().trim(); } |
768 | static String trim(StringBuffer buf) { return buf.toString().trim(); } |
769 | // key = 1 to 12 |
770 | static void registerFunctionKey(JFrame frame, int key, final Runnable r) { |
771 | String name = "F" + key; |
772 | Action action = abstractAction(name, r); |
773 | JComponent pnl = frame.getRootPane(); |
774 | KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F1+key-1, 0); |
775 | pnl.getActionMap().put(name, action); |
776 | pnl.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, name); |
777 | } |
778 | static String fsI(String id) { |
779 | return formatSnippetID(id); |
780 | } |
781 | static void swingAndWait(Runnable r) { try { |
782 | |
783 | if (isAWTThread()) |
784 | r.run(); |
785 | else |
786 | EventQueue.invokeAndWait(r); |
787 | |
788 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
789 | |
790 | static Object swingAndWait(final Object f) { |
791 | if (isAWTThread()) |
792 | return callF(f); |
793 | else { |
794 | final new Var result; |
795 | swingAndWait(new Runnable() { public void run() { try { |
796 | result.set(callF(f)); |
797 | } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}); |
798 | return result.get(); |
799 | } |
800 | } |
801 | static Thread currentThread() { |
802 | return Thread.currentThread(); |
803 | } |
804 | static void printStackTrace(Throwable e) { |
805 | // we go to system.out now - system.err is nonsense |
806 | print(getStackTrace(e)); |
807 | } |
808 | |
809 | static void printStackTrace() { |
810 | printStackTrace(new Throwable()); |
811 | } |
812 | static JMenu addMenu(JFrame frame, String menuName, Object... items) { |
813 | JMenuBar bar = addMenuBar(frame); |
814 | JMenu menu = new JMenu(menuName); |
815 | fillJMenu(menu, items); |
816 | bar.add(menu); |
817 | return menu; |
818 | } |
819 | static boolean mouseInComponent(Component c) { |
820 | return boundsOnScreen(c).contains(mousePosition()); |
821 | } |
822 | static <A> List<A> cloneList(Collection<A> l) { |
823 | //O mutex = getOpt(l, "mutex"); |
824 | /*if (mutex != null) |
825 | synchronized(mutex) { |
826 | ret new ArrayList<A>(l); |
827 | } |
828 | else |
829 | ret new ArrayList<A>(l);*/ |
830 | // assume mutex is equal to collection, which will be true unless you explicitly pass a mutex to synchronizedList() which no one ever does. |
831 | synchronized(l) { |
832 | return new ArrayList<A>(l); |
833 | } |
834 | } |
835 | static Map litmap(Object... x) { |
836 | new TreeMap map; |
837 | litmap_impl(map, x); |
838 | return map; |
839 | } |
840 | |
841 | static void litmap_impl(Map map, Object... x) { |
842 | for (int i = 0; i < x.length-1; i += 2) |
843 | if (x[i+1] != null) |
844 | map.put(x[i], x[i+1]); |
845 | } |
846 | // key = 1 to 12 |
847 | static void registerShiftFunctionKey(JFrame frame, int key, final Runnable r) { |
848 | String name = "Shift+F" + key; |
849 | Action action = abstractAction(name, r); |
850 | JComponent pnl = frame.getRootPane(); |
851 | KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F1+key-1, InputEvent.SHIFT_MASK); |
852 | pnl.getActionMap().put(name, action); |
853 | pnl.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, name); |
854 | } |
855 | static String str(Object o) { |
856 | return String.valueOf(o); |
857 | } |
858 | static RuntimeException fail() { |
859 | throw new RuntimeException("fail"); |
860 | } |
861 | |
862 | static RuntimeException fail(Object msg) { |
863 | throw new RuntimeException(String.valueOf(msg)); |
864 | } |
865 | |
866 | static RuntimeException fail(String msg) { |
867 | throw new RuntimeException(unnull(msg)); |
868 | } |
869 | |
870 | // disabled for now to shorten some programs |
871 | /*static RuntimeException fail(S msg, O... args) { |
872 | throw new RuntimeException(format(msg, args)); |
873 | }*/ |
874 | static boolean contains(Collection c, Object o) { |
875 | return c != null && c.contains(o); |
876 | } |
877 | |
878 | static boolean contains(Object[] x, Object o) { |
879 | if (x != null) |
880 | for (Object a : x) |
881 | if (eq(a, o)) |
882 | return true; |
883 | return false; |
884 | } |
885 | |
886 | static boolean contains(String s, char c) { |
887 | return s.indexOf(c) >= 0; |
888 | } |
889 | static void logStructure(File logFile, Object o) { |
890 | logQuoted(logFile, structure(o)); |
891 | } |
892 | |
893 | // quick version - log to file in program directory |
894 | static void logStructure(String fileName, Object o) { |
895 | logStructure(getProgramFile(fileName), o); |
896 | } |
897 | static String fsi(String id) { |
898 | return formatSnippetID(id); |
899 | } |
900 | |
901 | static String unnull(String s) { |
902 | return s == null ? "" : s; |
903 | } |
904 | |
905 | static <A> List<A> unnull(List<A> l) { |
906 | return l == null ? emptyList() : l; |
907 | } |
908 | |
909 | static Object[] unnull(Object[] a) { |
910 | return a == null ? new Object[0] : a; |
911 | } |
912 | static boolean swic(String a, String b) { |
913 | return startsWithIgnoreCase(a, b); |
914 | } |
915 | // runnable can be a func(O o) {} receving the selected item |
916 | static void onDoubleClick(final JList list, final Object runnable) { |
917 | list.addMouseListener(new MouseAdapter() { |
918 | public void mouseClicked(MouseEvent evt) { |
919 | if (evt.getClickCount() == 2) { |
920 | int idx = list.locationToIndex(evt.getPoint()); |
921 | Object item = list.getModel().getElementAt(idx); |
922 | list.setSelectedIndex(idx); |
923 | callF(runnable, item); |
924 | } |
925 | } |
926 | }); |
927 | } |
928 | |
929 | // runnable can be a func(O o) {} receving the selected row index |
930 | static void onDoubleClick(final JTable table, final Object runnable) { |
931 | table.addMouseListener(new MouseAdapter() { |
932 | public void mouseClicked(MouseEvent evt) { |
933 | if (evt.getClickCount() == 2) { |
934 | int idx = table.rowAtPoint(evt.getPoint()); |
935 | table.setRowSelectionInterval(idx, idx); |
936 | callF(runnable, idx); |
937 | } |
938 | } |
939 | }); |
940 | } |
941 | static class DynamicObject { |
942 | String className; |
943 | new Map<String, Object> fieldValues; |
944 | } |
945 | |
946 | static Object unstructure(String text) { |
947 | return unstructure(text, false); |
948 | } |
949 | |
950 | // TODO: backrefs for hashmap{} etc |
951 | static Object unstructure(String text, final boolean allDynamic) { |
952 | if (text == null) return null; |
953 | final List<String> tok = javaTok(text); |
954 | final boolean debug = unstructure_debug; |
955 | |
956 | class X { |
957 | int i = 1; |
958 | new HashMap<Integer, Object> refs; |
959 | |
960 | Object parse() { |
961 | String t = tok.get(i); |
962 | |
963 | int refID = 0; |
964 | if (t.startsWith("m") && isInteger(t.substring(1))) { |
965 | refID = parseInt(t.substring(1)); |
966 | i += 2; |
967 | t = tok.get(i); |
968 | } |
969 | |
970 | if (debug) |
971 | print("parse: " + quote(t)); |
972 | |
973 | if (t.startsWith("\"")) { |
974 | String s = unquote(tok.get(i)); |
975 | i += 2; |
976 | return s; |
977 | } |
978 | if (t.startsWith("'")) { |
979 | char c = unquoteCharacter(tok.get(i)); |
980 | i += 2; |
981 | return c; |
982 | } |
983 | if (t.equals("bigint")) |
984 | return parseBigInt(); |
985 | if (t.equals("d")) |
986 | return parseDouble(); |
987 | if (t.equals("false") || t.equals("f")) { |
988 | i += 2; return false; |
989 | } |
990 | if (t.equals("true") || t.equals("t")) { |
991 | i += 2; return true; |
992 | } |
993 | if (t.equals("-")) { |
994 | t = tok.get(i+2); |
995 | i += 4; |
996 | return isLongConstant(t) ? (Object) (-parseLong(t)) : (Object) (-parseInt(t)); |
997 | } |
998 | if (isInteger(t) || isLongConstant(t)) { |
999 | i += 2; |
1000 | if (debug) |
1001 | print("isLongConstant " + quote(t) + " => " + isLongConstant(t)); |
1002 | if (isLongConstant(t)) return parseLong(t); |
1003 | long l = parseLong(t); |
1004 | return l != (int) l ? new Long(l) : new Integer((int) l); |
1005 | } |
1006 | |
1007 | if (t.equals("File")) { |
1008 | File f = new File(unquote(tok.get(i+2))); |
1009 | i += 4; |
1010 | return f; |
1011 | } |
1012 | |
1013 | if (t.startsWith("r") && isInteger(t.substring(1))) { |
1014 | i += 2; |
1015 | int ref = Integer.parseInt(t.substring(1)); |
1016 | Object o = refs.get(ref); |
1017 | if (o == null) |
1018 | print("Warning: unsatisfied back reference " + ref); |
1019 | return o; |
1020 | } |
1021 | |
1022 | return parse_inner(refID); |
1023 | } |
1024 | |
1025 | // everything that can be backreferenced |
1026 | Object parse_inner(int refID) { |
1027 | String t = tok.get(i); |
1028 | |
1029 | if (debug) |
1030 | print("parse_inner: " + quote(t)); |
1031 | |
1032 | if (t.equals("hashset")) |
1033 | return parseHashSet(); |
1034 | if (t.equals("treeset")) |
1035 | return parseTreeSet(); |
1036 | if (t.equals("hashmap")) |
1037 | return parseHashMap(); |
1038 | if (t.equals("{")) |
1039 | return parseMap(); |
1040 | if (t.equals("[")) |
1041 | return parseList(); |
1042 | if (t.equals("array")) |
1043 | return parseArray(); |
1044 | if (t.equals("class")) |
1045 | return parseClass(); |
1046 | if (t.equals("l")) |
1047 | return parseLisp(); |
1048 | if (t.equals("null")) { |
1049 | i += 2; return null; |
1050 | } |
1051 | if (isJavaIdentifier(t)) { |
1052 | Class c = allDynamic ? null : findClass(t); |
1053 | DynamicObject dO = null; |
1054 | Object o = null; |
1055 | if (c != null) |
1056 | o = nuObject(c); |
1057 | else { |
1058 | dO = new DynamicObject; |
1059 | dO.className = t; |
1060 | } |
1061 | |
1062 | if (refID != 0) |
1063 | refs.put(refID, o); |
1064 | |
1065 | i += 2; |
1066 | if (i < tok.size() && tok.get(i).equals("(")) { |
1067 | consume("("); |
1068 | while (!tok.get(i).equals(")")) { |
1069 | // It's like parsing a map. |
1070 | //Object key = parse(); |
1071 | //if (tok.get(i).equals(")")) |
1072 | // key = onlyField(); |
1073 | String key = unquote(tok.get(i)); |
1074 | i += 2; |
1075 | consume("="); |
1076 | Object value = parse(); |
1077 | if (o != null) |
1078 | setOpt(o, key, value); |
1079 | else |
1080 | dO.fieldValues.put(key, value); |
1081 | if (tok.get(i).equals(",")) i += 2; |
1082 | } |
1083 | consume(")"); |
1084 | } |
1085 | return o != null ? o : dO; |
1086 | } |
1087 | throw new RuntimeException("Unknown token " + (i+1) + ": " + t); |
1088 | } |
1089 | |
1090 | Object parseSet(Set set) { |
1091 | set.addAll((List) parseList()); |
1092 | return set; |
1093 | } |
1094 | |
1095 | Object parseLisp() { |
1096 | consume("l"); |
1097 | consume("("); |
1098 | List list = new ArrayList; |
1099 | while (!tok.get(i).equals(")")) { |
1100 | list.add(parse()); |
1101 | if (tok.get(i).equals(",")) i += 2; |
1102 | } |
1103 | consume(")"); |
1104 | return newObject("main$Lisp", (String) list.get(0), subList(list, 1)); |
1105 | } |
1106 | |
1107 | Object parseList() { |
1108 | consume("["); |
1109 | List list = new ArrayList; |
1110 | while (!tok.get(i).equals("]")) { |
1111 | list.add(parse()); |
1112 | if (tok.get(i).equals(",")) i += 2; |
1113 | } |
1114 | consume("]"); |
1115 | return list; |
1116 | } |
1117 | |
1118 | Object parseArray() { |
1119 | consume("array"); |
1120 | consume("{"); |
1121 | List list = new ArrayList; |
1122 | while (!tok.get(i).equals("}")) { |
1123 | list.add(parse()); |
1124 | if (tok.get(i).equals(",")) i += 2; |
1125 | } |
1126 | consume("}"); |
1127 | return list.toArray(); |
1128 | } |
1129 | |
1130 | Object parseClass() { |
1131 | consume("class"); |
1132 | consume("("); |
1133 | String name = tok.get(i); |
1134 | i += 2; |
1135 | consume(")"); |
1136 | Class c = allDynamic ? null : findClass(name); |
1137 | if (c != null) return c; |
1138 | new DynamicObject dO; |
1139 | dO.className = "java.lang.Class"; |
1140 | dO.fieldValues.put("name", name); |
1141 | return dO; |
1142 | } |
1143 | |
1144 | Object parseBigInt() { |
1145 | consume("bigint"); |
1146 | consume("("); |
1147 | String val = tok.get(i); |
1148 | i += 2; |
1149 | if (eq(val, "-")) { |
1150 | val = "-" + tok.get(i); |
1151 | i += 2; |
1152 | } |
1153 | consume(")"); |
1154 | return new BigInteger(val); |
1155 | } |
1156 | |
1157 | Object parseDouble() { |
1158 | consume("d"); |
1159 | consume("("); |
1160 | String val = unquote(tok.get(i)); |
1161 | i += 2; |
1162 | consume(")"); |
1163 | return Double.parseDouble(val); |
1164 | } |
1165 | |
1166 | Object parseHashMap() { |
1167 | consume("hashmap"); |
1168 | return parseMap(new HashMap); |
1169 | } |
1170 | |
1171 | Object parseHashSet() { |
1172 | consume("hashset"); |
1173 | return parseSet(new HashSet); |
1174 | } |
1175 | |
1176 | Object parseTreeSet() { |
1177 | consume("treeset"); |
1178 | return parseSet(new TreeSet); |
1179 | } |
1180 | |
1181 | Object parseMap() { |
1182 | return parseMap(new TreeMap); |
1183 | } |
1184 | |
1185 | Object parseMap(Map map) { |
1186 | consume("{"); |
1187 | while (!tok.get(i).equals("}")) { |
1188 | Object key = parse(); |
1189 | consume("="); |
1190 | Object value = parse(); |
1191 | map.put(key, value); |
1192 | if (tok.get(i).equals(",")) i += 2; |
1193 | } |
1194 | consume("}"); |
1195 | return map; |
1196 | } |
1197 | |
1198 | void consume(String s) { |
1199 | if (!tok.get(i).equals(s)) { |
1200 | String prevToken = i-2 >= 0 ? tok.get(i-2) : ""; |
1201 | String nextTokens = join(tok.subList(i, Math.min(i+4, tok.size()))); |
1202 | fail(quote(s) + " expected: " + prevToken + " " + nextTokens + " (" + i + "/" + tok.size() + ")"); |
1203 | } |
1204 | i += 2; |
1205 | } |
1206 | } |
1207 | |
1208 | return new X().parse(); |
1209 | } |
1210 | |
1211 | static boolean unstructure_debug; |
1212 | static void removeLast(List l) { |
1213 | if (!l.isEmpty()) |
1214 | l.remove(l(l)-1); |
1215 | } |
1216 | public static boolean isSnippetID(String s) { |
1217 | try { |
1218 | parseSnippetID(s); |
1219 | return true; |
1220 | } catch (RuntimeException e) { |
1221 | return false; |
1222 | } |
1223 | } |
1224 | static int min(int a, int b) { |
1225 | return Math.min(a, b); |
1226 | } |
1227 | |
1228 | static double min(double[] c) { |
1229 | double x = Double.MAX_VALUE; |
1230 | for (double d : c) x = Math.min(x, d); |
1231 | return x; |
1232 | } |
1233 | |
1234 | static byte min(byte[] c) { |
1235 | byte x = 127; |
1236 | for (byte d : c) if (d < x) x = d; |
1237 | return x; |
1238 | } |
1239 | static void scrollTableDown(JTable table) { |
1240 | table.scrollRectToVisible(table.getCellRect(table.getRowCount()-1, 0, true)); |
1241 | } |
1242 | // get purpose 1: access a list/array (safer version of x.get(y)) |
1243 | |
1244 | static <A> A get(List<A> l, int idx) { |
1245 | return idx >= 0 && idx < l(l) ? l.get(idx) : null; |
1246 | } |
1247 | |
1248 | static <A> A get(A[] l, int idx) { |
1249 | return idx >= 0 && idx < l(l) ? l[idx] : null; |
1250 | } |
1251 | |
1252 | // get purpose 2: access a field by reflection or a map |
1253 | |
1254 | static Object get(Object o, String field) { |
1255 | if (o instanceof Class) return get((Class) o, field); |
1256 | |
1257 | if (o instanceof Map) |
1258 | return ((Map) o).get(field); |
1259 | |
1260 | if (o.getClass().getName().equals("main$DynamicObject")) |
1261 | return call(get_raw(o, "fieldValues"), "get", field); |
1262 | |
1263 | return get_raw(o, field); |
1264 | } |
1265 | |
1266 | static Object get_raw(Object o, String field) { |
1267 | try { |
1268 | Field f = get_findField(o.getClass(), field); |
1269 | f.setAccessible(true); |
1270 | return f.get(o); |
1271 | } catch (Exception e) { |
1272 | throw new RuntimeException(e); |
1273 | } |
1274 | } |
1275 | |
1276 | static Object get(Class c, String field) { |
1277 | try { |
1278 | Field f = get_findStaticField(c, field); |
1279 | f.setAccessible(true); |
1280 | return f.get(null); |
1281 | } catch (Exception e) { |
1282 | throw new RuntimeException(e); |
1283 | } |
1284 | } |
1285 | |
1286 | static Field get_findStaticField(Class<?> c, String field) { |
1287 | Class _c = c; |
1288 | do { |
1289 | for (Field f : _c.getDeclaredFields()) |
1290 | if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0) |
1291 | return f; |
1292 | _c = _c.getSuperclass(); |
1293 | } while (_c != null); |
1294 | throw new RuntimeException("Static field '" + field + "' not found in " + c.getName()); |
1295 | } |
1296 | |
1297 | static Field get_findField(Class<?> c, String field) { |
1298 | Class _c = c; |
1299 | do { |
1300 | for (Field f : _c.getDeclaredFields()) |
1301 | if (f.getName().equals(field)) |
1302 | return f; |
1303 | _c = _c.getSuperclass(); |
1304 | } while (_c != null); |
1305 | throw new RuntimeException("Field '" + field + "' not found in " + c.getName()); |
1306 | } |
1307 | static Object quickImport(Object o) { |
1308 | return quickExport(o, mc()); |
1309 | } |
1310 | static String escapeNewLines(String s) { |
1311 | return s.replace("\n", " | "); |
1312 | } |
1313 | static JFrame showFrame() { |
1314 | return makeFrame(); |
1315 | } |
1316 | |
1317 | static JFrame showFrame(Object content) { |
1318 | return makeFrame(content); |
1319 | } |
1320 | |
1321 | static JFrame showFrame(String title) { |
1322 | return makeFrame(title); |
1323 | } |
1324 | |
1325 | static JFrame showFrame(String title, Object content) { |
1326 | return makeFrame(title, content); |
1327 | } |
1328 | static List<String> scanLog(String progID, String fileName) { |
1329 | return scanLog(getProgramFile(progID, fileName)); |
1330 | } |
1331 | |
1332 | static List<String> scanLog(String fileName) { |
1333 | return scanLog(getProgramFile(fileName)); |
1334 | } |
1335 | |
1336 | static List<String> scanLog(File file) { |
1337 | new List<String> l; |
1338 | for (String s : toLines(file)) |
1339 | if (isProperlyQuoted(s)) |
1340 | l.add(unquote(s)); |
1341 | return l; |
1342 | } |
1343 | static <A> List<A> subList(List<A> l, int startIndex) { |
1344 | return subList(l, startIndex, l(l)); |
1345 | } |
1346 | |
1347 | static <A> List<A> subList(List<A> l, int startIndex, int endIndex) { |
1348 | startIndex = max(0, min(l(l), startIndex)); |
1349 | endIndex = max(0, min(l(l), endIndex)); |
1350 | if (startIndex > endIndex) return litlist(); |
1351 | return l.subList(startIndex, endIndex); |
1352 | } |
1353 | static <A> List<A> listPlus(List<A> l, A... more) { |
1354 | return concatLists(l, asList(more)); |
1355 | } |
1356 | static int l(Object[] array) { |
1357 | return array == null ? 0 : array.length; |
1358 | } |
1359 | |
1360 | static int l(byte[] array) { |
1361 | return array == null ? 0 : array.length; |
1362 | } |
1363 | |
1364 | static int l(int[] array) { |
1365 | return array == null ? 0 : array.length; |
1366 | } |
1367 | |
1368 | static int l(char[] array) { |
1369 | return array == null ? 0 : array.length; |
1370 | } |
1371 | |
1372 | static int l(Collection c) { |
1373 | return c == null ? 0 : c.size(); |
1374 | } |
1375 | |
1376 | static int l(Map m) { |
1377 | return m == null ? 0 : m.size(); |
1378 | } |
1379 | |
1380 | static int l(String s) { |
1381 | return s == null ? 0 : s.length(); |
1382 | } |
1383 | |
1384 | static int l(Object o) { |
1385 | return l((List) o); // incomplete |
1386 | } |
1387 | |
1388 | static String exceptionToStringShort(Throwable e) { |
1389 | e = getInnerException(e); |
1390 | String msg = unnull(e.getMessage()); |
1391 | if (msg.indexOf("Error") < 0 && msg.indexOf("Exception") < 0) |
1392 | return dropPrefix("java.lang.", str(e)); |
1393 | else |
1394 | return msg; |
1395 | } |
1396 | static ThreadLocal<Boolean> gCompleting; |
1397 | |
1398 | static boolean gCompleting() { |
1399 | gCompleting_init(); |
1400 | Boolean b = gCompleting.get(); |
1401 | /*if (b == null) |
1402 | b = (Bool) callOpt(creator(), "gCompleting");*/ |
1403 | return isTrue(b); |
1404 | } |
1405 | |
1406 | static void gCompleting_set(Boolean b) { |
1407 | gCompleting_init(); |
1408 | gCompleting.set(b); |
1409 | } |
1410 | |
1411 | static void gCompleting_init() { |
1412 | if (gCompleting == null) { |
1413 | gCompleting = (ThreadLocal) getOpt(creator(), "gCompleting"); |
1414 | if (gCompleting == null) gCompleting = new ThreadLocal; |
1415 | } |
1416 | } |
1417 | static String gMode() { |
1418 | return gCompleting() ? "/i" : ""; |
1419 | } |
1420 | // action = runnable or method name |
1421 | static void onUpdate(JTextComponent c, final Object r) { |
1422 | c.getDocument().addDocumentListener(new DocumentListener() { |
1423 | public void insertUpdate(DocumentEvent e) { |
1424 | callFunction(r); |
1425 | } |
1426 | public void removeUpdate(DocumentEvent e) { |
1427 | callFunction(r); |
1428 | } |
1429 | public void changedUpdate(DocumentEvent e) { |
1430 | callFunction(r); |
1431 | } |
1432 | }); |
1433 | } |
1434 | static Object first(Object list) { |
1435 | return ((List) list).isEmpty() ? null : ((List) list).get(0); |
1436 | } |
1437 | |
1438 | static <A> A first(List<A> list) { |
1439 | return list.isEmpty() ? null : list.get(0); |
1440 | } |
1441 | |
1442 | static <A> A first(A[] bla) { |
1443 | return bla == null || bla.length == 0 ? null : bla[0]; |
1444 | } |
1445 | static void setFrameIcon(JFrame frame, String imageID) { |
1446 | try { |
1447 | if (frame != null) |
1448 | frame.setIconImage(imageIcon(imageID).getImage()); |
1449 | } catch (Throwable __e) { printStackTrace(__e); } |
1450 | } |
1451 | |
1452 | static void setFrameIcon(Component c, String imageID) { |
1453 | setFrameIcon(getFrame(c), imageID); |
1454 | } |
1455 | static <A> ArrayList<A> ll(A... a) { |
1456 | return litlist(a); |
1457 | } |
1458 | static LinkedHashMap litorderedmap(Object... x) { |
1459 | new LinkedHashMap map; |
1460 | litmap_impl(map, x); |
1461 | return map; |
1462 | } |
1463 | static String dropBracketPrefix(String s) { |
1464 | s = s.trim(); |
1465 | if (s.startsWith("[")) { |
1466 | int i = s.indexOf(']'); |
1467 | return s.substring(i+1).trim(); |
1468 | } |
1469 | return s; |
1470 | } |
1471 | static File prepareProgramFile(String name) { |
1472 | return mkdirsForFile(getProgramFile(name)); |
1473 | } |
1474 | static String joinLines(List<String> lines) { |
1475 | return fromLines(lines); |
1476 | } |
1477 | |
1478 | static String joinLines(String glue, String text) { |
1479 | return join(glue, toLines(text)); |
1480 | } |
1481 | static <A> List<A> getLast(List<A> l, int n) { |
1482 | return subList(l, l(l)-n); |
1483 | } |
1484 | static boolean empty(Collection c) { |
1485 | return isEmpty(c); |
1486 | } |
1487 | |
1488 | static boolean empty(String s) { |
1489 | return isEmpty(s); |
1490 | } |
1491 | |
1492 | static boolean empty(Map map) { |
1493 | return map == null || map.isEmpty(); |
1494 | } |
1495 | |
1496 | static boolean empty(Object o) { |
1497 | if (o instanceof Collection) return empty((Collection) o); |
1498 | if (o instanceof String) return empty((String) o); |
1499 | if (o instanceof Map) return empty((Map) o); |
1500 | return false; |
1501 | } |
1502 | static boolean confirmYesNo(Component owner, String msg) { |
1503 | return JOptionPane.showConfirmDialog(owner, |
1504 | msg, "JavaX", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION; |
1505 | } |
1506 | // Let's just generally synchronize this to be safe. |
1507 | static synchronized void appendToFile(String path, String s) { try { |
1508 | |
1509 | new File(path).getParentFile().mkdirs(); |
1510 | //print("[Logging to " + path + "]"); |
1511 | Writer writer = new BufferedWriter(new OutputStreamWriter( |
1512 | new FileOutputStream(path, true), "UTF-8")); |
1513 | writer.write(s); |
1514 | writer.close(); |
1515 | |
1516 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
1517 | |
1518 | static void appendToFile(File path, String s) { |
1519 | if (path != null) |
1520 | appendToFile(path.getPath(), s); |
1521 | } |
1522 | |
1523 | static <A> A findByField(Collection<A> c, String field, Object value) { |
1524 | for (A a : c) |
1525 | if (eq(getOpt(a, field), value)) |
1526 | return a; |
1527 | return null; |
1528 | } |
1529 | static boolean neq(Object a, Object b) { |
1530 | return !eq(a, b); |
1531 | } |
1532 | static ThreadLocal<List<String>> genLog_log; |
1533 | |
1534 | static List<String> genLog() { |
1535 | genLog_init(); |
1536 | List<String> log = genLog_log.get(); |
1537 | /*if (log == null) |
1538 | log = (L) callOpt(creator(), "genLog");*/ |
1539 | return assertNotNull("No log set for this thread", log); |
1540 | } |
1541 | |
1542 | static void genLog_set(List<String> log) { |
1543 | genLog_init(); |
1544 | genLog_log.set(log); |
1545 | } |
1546 | |
1547 | static void genLog_clear() { |
1548 | genLog_init(); |
1549 | genLog_log.set(null); |
1550 | } |
1551 | |
1552 | static void genLog_init() { |
1553 | if (genLog_log == null) { |
1554 | genLog_log = (ThreadLocal) getOpt(creator(), "genLog_log"); |
1555 | if (genLog_log == null) genLog_log = new ThreadLocal; |
1556 | } |
1557 | } |
1558 | static <A> boolean firstIs(List<A> l, A a) { |
1559 | return eq(get(l, 0), a); |
1560 | } |
1561 | // automatic conversion to string (for returning numbers etc.) |
1562 | static String callGen(Gen gen) { |
1563 | return strPreserveNull(callF(gen.func)); |
1564 | } |
1565 | static <A> A last(List<A> l) { |
1566 | return l.isEmpty() ? null : l.get(l.size()-1); |
1567 | } |
1568 | static boolean eq(Object a, Object b) { |
1569 | if (a == null) return b == null; |
1570 | if (a.equals(b)) return true; |
1571 | if (a instanceof BigInteger) { |
1572 | if (b instanceof Integer) return a.equals(BigInteger.valueOf((Integer) b)); |
1573 | if (b instanceof Long) return a.equals(BigInteger.valueOf((Long) b)); |
1574 | } |
1575 | return false; |
1576 | } |
1577 | static TableWithTooltips tableWithTooltips() { |
1578 | return new TableWithTooltips; |
1579 | } |
1580 | |
1581 | static class TableWithTooltips extends JTable { |
1582 | public String getToolTipText(MouseEvent e) { |
1583 | String tip = null; |
1584 | Point p = e.getPoint(); |
1585 | int rowIndex = rowAtPoint(p); |
1586 | int colIndex = columnAtPoint(p); |
1587 | |
1588 | try { |
1589 | return str(getValueAt(rowIndex, colIndex)); |
1590 | } catch (Throwable _e) { return null; |
1591 | } |
1592 | } |
1593 | } |
1594 | static Map getMap(Map map, Object key) { |
1595 | return map == null ? null : (Map) map.get(key); |
1596 | } |
1597 | |
1598 | static Map getMap(List l, int idx) { |
1599 | return (Map) get(l, idx); |
1600 | } |
1601 | |
1602 | static Map getMap(Object o, Object key) { |
1603 | if (o instanceof Map) return getMap((Map) o, key); |
1604 | if (key instanceof String) |
1605 | return (Map) get(o, (String) key); |
1606 | throw fail("Not a string key: " + getClassName(key)); |
1607 | } |
1608 | static void onEnter(JTextField tf, final Runnable action) { |
1609 | tf.addActionListener(new ActionListener() { |
1610 | public void actionPerformed(ActionEvent evt) { |
1611 | try { |
1612 | action.run(); |
1613 | } catch (Throwable e) { |
1614 | e.printStackTrace(); |
1615 | } |
1616 | } |
1617 | }); |
1618 | } |
1619 | /** writes safely (to temp file, then rename) */ |
1620 | public static void saveTextFile(String fileName, String contents) throws IOException { |
1621 | File file = new File(fileName); |
1622 | File parentFile = file.getParentFile(); |
1623 | if (parentFile != null) |
1624 | parentFile.mkdirs(); |
1625 | String tempFileName = fileName + "_temp"; |
1626 | if (contents != null) { |
1627 | FileOutputStream fileOutputStream = new FileOutputStream(tempFileName); |
1628 | OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "UTF-8"); |
1629 | PrintWriter printWriter = new PrintWriter(outputStreamWriter); |
1630 | printWriter.print(contents); |
1631 | printWriter.close(); |
1632 | } |
1633 | |
1634 | if (file.exists() && !file.delete()) |
1635 | throw new IOException("Can't delete " + fileName); |
1636 | |
1637 | if (contents != null) |
1638 | if (!new File(tempFileName).renameTo(file)) |
1639 | throw new IOException("Can't rename " + tempFileName + " to " + fileName); |
1640 | } |
1641 | |
1642 | public static void saveTextFile(File fileName, String contents) { |
1643 | try { |
1644 | saveTextFile(fileName.getPath(), contents); |
1645 | } catch (IOException e) { |
1646 | throw new RuntimeException(e); |
1647 | } |
1648 | } |
1649 | |
1650 | static List scanLog_safeUnstructure(String progID, String fileName) { |
1651 | return scanLog_safeUnstructure(getProgramFile(progID, fileName)); |
1652 | } |
1653 | |
1654 | static List scanLog_safeUnstructure(String fileName) { |
1655 | return scanLog_safeUnstructure(getProgramFile(fileName)); |
1656 | } |
1657 | |
1658 | static List scanLog_safeUnstructure(File file) { |
1659 | new List l; |
1660 | for (String s : scanLog(file)) try { |
1661 | l.add(safeUnstructure(s)); |
1662 | } catch (Throwable __e) { printStackTrace(__e); } |
1663 | return l; |
1664 | } |
1665 | static void readLocally(String progID, String varNames) { |
1666 | readLocally2(mc(), progID, varNames); |
1667 | } |
1668 | |
1669 | static void readLocally(String varNames) { |
1670 | readLocally2(mc(), programID(), varNames); |
1671 | } |
1672 | |
1673 | static void readLocally2(Object obj, String varNames) { |
1674 | readLocally2(obj, programID(), varNames); |
1675 | } |
1676 | |
1677 | // read a string variable from standard storage |
1678 | // does not overwrite variable contents if there is no file |
1679 | static synchronized void readLocally2(Object obj, String progID, String varNames) { |
1680 | for (String variableName : codeTokensOnly(javaTok(varNames))) { |
1681 | File textFile = new File(programDir(progID), variableName + ".text"); |
1682 | File structureFile = new File(programDir(progID), variableName + ".structure"); |
1683 | |
1684 | String value = loadTextFile(textFile); |
1685 | if (value != null) |
1686 | set(main.class, variableName, value); |
1687 | else { |
1688 | value = loadTextFile(structureFile); |
1689 | if (value != null) |
1690 | readLocally_set(obj, variableName, unstructure(value)); |
1691 | } |
1692 | } |
1693 | } |
1694 | |
1695 | static void readLocally_set(Object c, String varName, Object value) { |
1696 | Object oldValue = get(c, varName); |
1697 | if (oldValue instanceof List && !(oldValue instanceof ArrayList) && value != null) { |
1698 | // Assume it's a synchroList. |
1699 | value = synchroList((List) value); |
1700 | } |
1701 | set(c, varName, value); |
1702 | } |
1703 | |
1704 | static List collect(Collection c, String field) { |
1705 | return collectField(c, field); |
1706 | } |
1707 | static int tableRows(JTable table) { |
1708 | return table.getRowCount(); |
1709 | } |
1710 | static Object callOpt(Object o, String method, Object... args) { |
1711 | try { |
1712 | if (o == null) return null; |
1713 | if (o instanceof Class) { |
1714 | Method m = callOpt_findStaticMethod((Class) o, method, args, false); |
1715 | if (m == null) return null; |
1716 | m.setAccessible(true); |
1717 | return m.invoke(null, args); |
1718 | } else { |
1719 | Method m = callOpt_findMethod(o, method, args, false); |
1720 | if (m == null) return null; |
1721 | m.setAccessible(true); |
1722 | return m.invoke(o, args); |
1723 | } |
1724 | } catch (Exception e) { |
1725 | throw new RuntimeException(e); |
1726 | } |
1727 | } |
1728 | |
1729 | static Method callOpt_findStaticMethod(Class c, String method, Object[] args, boolean debug) { |
1730 | Class _c = c; |
1731 | while (c != null) { |
1732 | for (Method m : c.getDeclaredMethods()) { |
1733 | if (debug) |
1734 | System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; |
1735 | if (!m.getName().equals(method)) { |
1736 | if (debug) System.out.println("Method name mismatch: " + method); |
1737 | continue; |
1738 | } |
1739 | |
1740 | if ((m.getModifiers() & Modifier.STATIC) == 0 || !callOpt_checkArgs(m, args, debug)) |
1741 | continue; |
1742 | |
1743 | return m; |
1744 | } |
1745 | c = c.getSuperclass(); |
1746 | } |
1747 | return null; |
1748 | } |
1749 | |
1750 | static Method callOpt_findMethod(Object o, String method, Object[] args, boolean debug) { |
1751 | Class c = o.getClass(); |
1752 | while (c != null) { |
1753 | for (Method m : c.getDeclaredMethods()) { |
1754 | if (debug) |
1755 | System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; |
1756 | if (m.getName().equals(method) && callOpt_checkArgs(m, args, debug)) |
1757 | return m; |
1758 | } |
1759 | c = c.getSuperclass(); |
1760 | } |
1761 | return null; |
1762 | } |
1763 | |
1764 | private static boolean callOpt_checkArgs(Method m, Object[] args, boolean debug) { |
1765 | Class<?>[] types = m.getParameterTypes(); |
1766 | if (types.length != args.length) { |
1767 | if (debug) |
1768 | System.out.println("Bad parameter length: " + args.length + " vs " + types.length); |
1769 | return false; |
1770 | } |
1771 | for (int i = 0; i < types.length; i++) |
1772 | if (!(args[i] == null || isInstanceX(types[i], args[i]))) { |
1773 | if (debug) |
1774 | System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]); |
1775 | return false; |
1776 | } |
1777 | return true; |
1778 | } |
1779 | |
1780 | |
1781 | static <A, B> Collection<B> values(Map<A, B> map) { |
1782 | return map.values(); |
1783 | } |
1784 | |
1785 | static JFrame getFrame(Object o) { |
1786 | if (!(o instanceof Component)) return null; |
1787 | Component c = (Component) o; |
1788 | while (c != null) { |
1789 | if (c instanceof JFrame) return (JFrame) c; |
1790 | c = c.getParent(); |
1791 | } |
1792 | return null; |
1793 | } |
1794 | static JPanel centerAndSouth(Component c, Component s) { |
1795 | JPanel panel = new JPanel(new BorderLayout); |
1796 | panel.add(BorderLayout.CENTER, wrap(c)); |
1797 | panel.add(BorderLayout.SOUTH, wrap(s)); |
1798 | return panel; |
1799 | } |
1800 | static JTable dataToTable_uneditable(final JTable table, final Object data) { |
1801 | swingNowOrLater(r { |
1802 | dataToTable(table, data, true); |
1803 | makeTableUneditable(table); |
1804 | }); |
1805 | return table; |
1806 | } |
1807 | |
1808 | static <A, B> Map<A, B> mapPlus(Map<A, B> m, Object... data) { |
1809 | m = cloneTreeMap(m); |
1810 | litmap_impl(m, data); |
1811 | return m; |
1812 | } |
1813 | public static String fromLines(List<String> lines) { |
1814 | StringBuilder buf = new StringBuilder(); |
1815 | if (lines != null) |
1816 | for (String line : lines) |
1817 | buf.append(line).append('\n'); |
1818 | return buf.toString(); |
1819 | } |
1820 | static void logQuoted(String logFile, String line) { |
1821 | logQuoted(getProgramFile(logFile), line); |
1822 | } |
1823 | |
1824 | static void logQuoted(File logFile, String line) { |
1825 | appendToFile(logFile, quote(line) + "\n"); |
1826 | } |
1827 | static String substring(String s, int x) { |
1828 | return safeSubstring(s, x); |
1829 | } |
1830 | |
1831 | static String substring(String s, int x, int y) { |
1832 | return safeSubstring(s, x, y); |
1833 | } |
1834 | static <A> List<A> synchroList() { |
1835 | return Collections.synchronizedList(new ArrayList<A>()); |
1836 | } |
1837 | |
1838 | static <A> List<A> synchroList(List<A> l) { |
1839 | return Collections.synchronizedList(l); |
1840 | } |
1841 | |
1842 | static long now_virtualTime; |
1843 | static long now() { |
1844 | return now_virtualTime != 0 ? now_virtualTime : System.currentTimeMillis(); |
1845 | } |
1846 | |
1847 | static void systemCommands(String s) { |
1848 | postSystemMessage(systemCommands_impl(s)); |
1849 | } |
1850 | |
1851 | static String systemCommands_impl(String s) { |
1852 | new Matches m; |
1853 | |
1854 | // SYSTEM COMMANDS |
1855 | |
1856 | if (matchOneOf(s, m, "start program *", "start *") |
1857 | && isSnippetID(m.unq(0))) { |
1858 | String progID = m.fsi(0); |
1859 | String title = getSnippetTitle(progID); |
1860 | // TODO: Show author! |
1861 | String msg = "Run program " + progID + " - " + title + "?"; |
1862 | if (confirmOKCancel(frame, msg)) { |
1863 | postSystemMessage("Starting program " + progID + " - " + quote(title)); |
1864 | nohupJavax(progID); |
1865 | } else |
1866 | postSystemMessage("Program start cancelled by user (was: " + progID + ")"); |
1867 | } |
1868 | |
1869 | if (matchOneOf(s, m, "hotwire *", "hotwire * with argument *")) { |
1870 | String progID = m.fsi(0), arg = unnull(m.unq(1)); |
1871 | String title = getSnippetTitle(progID); |
1872 | |
1873 | String msg = "Hotwire & run program " + progID + " - " + quote(title) + (empty(arg) ? "" : " with argument " + quote(arg)) + "?"; |
1874 | if (confirmOKCancel(frame, msg)) { |
1875 | postSystemMessage("Hotwiring & running program " + progID + " - " + quote(title) + (empty(arg) ? "" : " with argument " + quote(arg))); |
1876 | run(progID, arg); |
1877 | } else |
1878 | postSystemMessage("Program start cancelled by user (was: " + progID + ")"); |
1879 | } |
1880 | |
1881 | if (matchOneOf(s, "jfresh", "fresh")) { |
1882 | return veryQuickJava_refresh() ? "OK, translator dropped." : "Nothing to do"; |
1883 | } |
1884 | |
1885 | if (startsWithOneOf(s, "java ", "j ")) { |
1886 | String code = onlyAfter(s, ' '); |
1887 | return systemCommands_evalJava(code); |
1888 | } |
1889 | |
1890 | if (startsWith(s, "jfresh ")) { |
1891 | veryQuickJava_refresh(); |
1892 | String code = dropPrefix("jfresh", s); |
1893 | return systemCommands_evalJava(code); |
1894 | } |
1895 | |
1896 | if (match("restart", s, m)) { |
1897 | postSystemMessage("Restarting..."); |
1898 | restart(); |
1899 | } |
1900 | |
1901 | if (match("pop", s, m)) { // pop up last chat line in a window |
1902 | String text = nextToLast(log); |
1903 | if (empty(text)) |
1904 | return "Nothing to show"; |
1905 | else |
1906 | showText(text); |
1907 | } return null; |
1908 | } |
1909 | |
1910 | static Object systemCommands_lastResult; |
1911 | |
1912 | static String systemCommands_evalJava(String code) { |
1913 | code = trim(code); |
1914 | code = tok_addReturn(code); |
1915 | String returnType = containsReturnWithArgument(code) ? "O" : "void"; |
1916 | String main = "!include #1003911\n" + // functions for quick eval |
1917 | "static " + returnType + " calc() { " + code + "\n" + "}"; |
1918 | Object obj = veryQuickJava(main); |
1919 | long time = now(); |
1920 | Object result = callCalc(obj); |
1921 | systemCommands_lastResult = result; |
1922 | time = now()-time; |
1923 | return time + " ms\n" + systemCommands_prettyPrint(result); |
1924 | } |
1925 | |
1926 | static String systemCommands_prettyPrint(Object o) { |
1927 | if (o instanceof List) |
1928 | return fromLines(map(new Object { Object get(Object o) { return systemCommands_prettyPrint(o) ; } |
1929 | public String toString() { return "systemCommands_prettyPrint(o)"; }}, (List) o)); |
1930 | |
1931 | if (eq(getClassName(o), "main$Snippet")) |
1932 | return formatSnippetID(getString(o, "id")) + " - " + getString(o, "title"); |
1933 | |
1934 | return structureOrText(o); |
1935 | } |
1936 | static <A> boolean setAdd(Collection<A> c, A a) { |
1937 | if (c.contains(a)) return false; |
1938 | c.add(a); |
1939 | return true; |
1940 | } |
1941 | // compile JavaX source, load classes & return main class |
1942 | // src can be a snippet ID or actual source code |
1943 | // TODO: record injection? |
1944 | |
1945 | static Class<?> hotwire(String src) { |
1946 | try { |
1947 | Class j = getJavaX(); |
1948 | |
1949 | synchronized(j) { // hopefully this goes well... |
1950 | List<File> libraries = new ArrayList<File>(); |
1951 | File srcDir = (File) call(j, "transpileMain", src, libraries); |
1952 | if (srcDir == null) |
1953 | fail("transpileMain returned null (src=" + quote(src) + ")"); |
1954 | |
1955 | Object androidContext = get(j, "androidContext"); |
1956 | if (androidContext != null) |
1957 | return (Class) call(j, "loadx2android", srcDir, src); |
1958 | |
1959 | File classesDir = (File) call(j, "TempDirMaker_make"); |
1960 | String javacOutput = (String) call(j, "compileJava", srcDir, libraries, classesDir); |
1961 | System.out.println(javacOutput); |
1962 | |
1963 | URL[] urls = new URL[libraries.size()+1]; |
1964 | urls[0] = classesDir.toURI().toURL(); |
1965 | for (int i = 0; i < libraries.size(); i++) |
1966 | urls[i+1] = libraries.get(i).toURI().toURL(); |
1967 | |
1968 | // make class loader |
1969 | URLClassLoader classLoader = new URLClassLoader(urls); |
1970 | |
1971 | // load & return main class |
1972 | Class<?> theClass = classLoader.loadClass("main"); |
1973 | |
1974 | callOpt(j, "registerSourceCode", theClass, loadTextFile(new File(srcDir, "main.java"))); |
1975 | |
1976 | call(j, "setVars", theClass, isSnippetID(src) ? src: null); |
1977 | |
1978 | if (isSnippetID(src)) |
1979 | callOpt(j, "addInstance", src, theClass); |
1980 | |
1981 | if (!_inCore()) |
1982 | hotwire_copyOver(theClass); |
1983 | |
1984 | return theClass; |
1985 | } |
1986 | } catch (Exception e) { |
1987 | throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e); |
1988 | } |
1989 | } |
1990 | static File getProgramFile(String progID, String fileName) { |
1991 | return new File(getProgramDir(progID), fileName); |
1992 | } |
1993 | |
1994 | static File getProgramFile(String fileName) { |
1995 | return getProgramFile(getProgramID(), fileName); |
1996 | } |
1997 | |
1998 | static void saveLocally(String variableName) { |
1999 | saveLocally(programID(), variableName); |
2000 | } |
2001 | |
2002 | static void saveLocally(String progID, String variableName) { |
2003 | saveLocally2(mc(), progID, variableName); |
2004 | } |
2005 | |
2006 | static void saveLocally2(Object obj, String variableName) { |
2007 | saveLocally2(obj, programID(), variableName); |
2008 | } |
2009 | |
2010 | static synchronized void saveLocally2(Object obj, String progID, String variableName) { |
2011 | File textFile = new File(programDir(progID), variableName + ".text"); |
2012 | File structureFile = new File(programDir(progID), variableName + ".structure"); |
2013 | Object x = get(obj, variableName); |
2014 | |
2015 | if (x == null) { |
2016 | textFile.delete(); |
2017 | structureFile.delete(); |
2018 | } else if (x instanceof String) { |
2019 | saveTextFile(textFile, (String) x); |
2020 | structureFile.delete(); |
2021 | } else { |
2022 | saveTextFile(structureFile, structure(x)); |
2023 | textFile.delete(); |
2024 | } |
2025 | } |
2026 | static void swingAfter(JFrame base, int delay, Runnable r) { |
2027 | installTimer((JComponent) base.getContentPane(), r, delay, delay, false); |
2028 | } |
2029 | |
2030 | static void swingAfter(JComponent base, int delay, Runnable r) { |
2031 | installTimer(base, r, delay, delay, false); |
2032 | } |
2033 | static void substance() { |
2034 | substanceLAF(); |
2035 | } |
2036 | |
2037 | static void substance(String skinName) { |
2038 | substanceLAF(skinName); |
2039 | } |
2040 | static boolean match(String pat, String s) { |
2041 | return match3(pat, s); |
2042 | } |
2043 | |
2044 | static boolean match(String pat, String s, Matches matches) { |
2045 | return match3(pat, s, matches); |
2046 | } |
2047 | |
2048 | static boolean nempty(Collection c) { |
2049 | return !isEmpty(c); |
2050 | } |
2051 | |
2052 | static boolean nempty(CharSequence s) { |
2053 | return !isEmpty(s); |
2054 | } |
2055 | |
2056 | static boolean nempty(Object[] o) { |
2057 | return !isEmpty(o); |
2058 | } |
2059 | |
2060 | static boolean eqic(String a, String b) { |
2061 | if ((a == null) != (b == null)) return false; |
2062 | if (a == null) return true; |
2063 | return a.equalsIgnoreCase(b); |
2064 | } |
2065 | static String chatTime() { |
2066 | return formatInt(month(), 2) + "/" + formatInt(days(), 2) + " " + formatInt(hours(), 2) + ":" + formatInt(minutes(), 2) + ":" + formatInt(seconds(), 2); |
2067 | } |
2068 | static String getString(Map map, Object key) { |
2069 | return map == null ? null : (String) map.get(key); |
2070 | } |
2071 | |
2072 | static String getString(List l, int idx) { |
2073 | return (String) get(l, idx); |
2074 | } |
2075 | |
2076 | static String getString(Object o, Object key) { |
2077 | if (o instanceof Map) return getString((Map) o, key); |
2078 | if (key instanceof String) |
2079 | return (String) get(o, (String) key); |
2080 | throw fail("Not a string key: " + getClassName(key)); |
2081 | } |
2082 | static String structure(Object o) { |
2083 | new HashSet refd; |
2084 | return structure_2(structure_1(o, 0, new IdentityHashMap, refd), refd); |
2085 | } |
2086 | |
2087 | // leave to false, unless unstructure() breaks |
2088 | static boolean structure_allowShortening = false; |
2089 | |
2090 | static String structure_1(Object o, int stringSizeLimit, IdentityHashMap<Object, Integer> seen, HashSet<Integer> refd) { |
2091 | if (o == null) return "null"; |
2092 | |
2093 | // these are never back-referenced (for readability) |
2094 | |
2095 | if (o instanceof String) |
2096 | return quote(stringSizeLimit != 0 ? shorten((String) o, stringSizeLimit) : (String) o); |
2097 | |
2098 | if (o instanceof BigInteger) |
2099 | return "bigint(" + o + ")"; |
2100 | |
2101 | if (o instanceof Double) |
2102 | return "d(" + quote(str(o)) + ")"; |
2103 | |
2104 | if (o instanceof Long) |
2105 | return o + "L"; |
2106 | |
2107 | if (o instanceof Integer) |
2108 | return str(o); |
2109 | |
2110 | if (o instanceof Boolean) |
2111 | return ((Boolean) o).booleanValue() ? "t" : "f"; |
2112 | |
2113 | if (o instanceof Character) |
2114 | return quoteCharacter((Character) o); |
2115 | |
2116 | if (o instanceof File) |
2117 | return "File " + quote(((File) o).getPath()); |
2118 | |
2119 | // referencable objects follow |
2120 | |
2121 | Integer ref = seen.get(o); |
2122 | if (ref != null) { |
2123 | refd.add(ref); |
2124 | return "r" + ref; |
2125 | } |
2126 | |
2127 | ref = seen.size()+1; |
2128 | seen.put(o, ref); |
2129 | String r = "m" + ref + " "; // marker |
2130 | |
2131 | String name = o.getClass().getName(); |
2132 | |
2133 | StringBuilder buf = new StringBuilder(); |
2134 | |
2135 | if (o instanceof HashSet) |
2136 | return r + "hashset " + structure_1(new ArrayList((Set) o), stringSizeLimit, seen, refd); |
2137 | |
2138 | if (o instanceof TreeSet) |
2139 | return r + "treeset " + structure_1(new ArrayList((Set) o), stringSizeLimit, seen, refd); |
2140 | |
2141 | if (o instanceof Collection) { |
2142 | for (Object x : (Collection) o) { |
2143 | if (buf.length() != 0) buf.append(", "); |
2144 | buf.append(structure_1(x, stringSizeLimit, seen, refd)); |
2145 | } |
2146 | return r + "[" + buf + "]"; |
2147 | } |
2148 | |
2149 | if (o instanceof Map) { |
2150 | for (Object e : ((Map) o).entrySet()) { |
2151 | if (buf.length() != 0) buf.append(", "); |
2152 | buf.append(structure_1(((Map.Entry) e).getKey(), stringSizeLimit, seen, refd)); |
2153 | buf.append("="); |
2154 | buf.append(structure_1(((Map.Entry) e).getValue(), stringSizeLimit, seen, refd)); |
2155 | } |
2156 | return r + (o instanceof HashMap ? "hashmap" : "") + "{" + buf + "}"; |
2157 | } |
2158 | |
2159 | if (o.getClass().isArray()) { |
2160 | int n = Array.getLength(o); |
2161 | for (int i = 0; i < n; i++) { |
2162 | if (buf.length() != 0) buf.append(", "); |
2163 | buf.append(structure_1(Array.get(o, i), stringSizeLimit, seen, refd)); |
2164 | } |
2165 | return r + "array{" + buf + "}"; |
2166 | } |
2167 | |
2168 | if (o instanceof Class) |
2169 | return r + "class(" + quote(((Class) o).getName()) + ")"; |
2170 | |
2171 | if (o instanceof Throwable) |
2172 | return r + "exception(" + quote(((Throwable) o).getMessage()) + ")"; |
2173 | |
2174 | if (o instanceof BitSet) { |
2175 | BitSet bs = (BitSet) o; |
2176 | for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) { |
2177 | if (buf.length() != 0) buf.append(", "); |
2178 | buf.append(i); |
2179 | } |
2180 | return "bitset{" + buf + "}"; |
2181 | } |
2182 | |
2183 | // Need more cases? This should cover all library classes... |
2184 | if (name.startsWith("java.") || name.startsWith("javax.")) |
2185 | return r + String.valueOf(o); |
2186 | |
2187 | String shortName = o.getClass().getName().replaceAll("^main\\$", ""); |
2188 | |
2189 | if (shortName.equals("Lisp")) { |
2190 | buf.append("l(" + structure_1(getOpt(o, "head"), stringSizeLimit, seen, refd)); |
2191 | List args = (List) ( getOpt(o, "args")); |
2192 | if (nempty(args)) |
2193 | for (int i = 0; i < l(args); i++) { |
2194 | buf.append(", "); |
2195 | Object arg = args.get(i); |
2196 | |
2197 | // sweet shortening |
2198 | if (arg != null && eq(arg.getClass().getName(), "main$Lisp") && isTrue(call(arg, "isEmpty"))) |
2199 | arg = get(arg, "head"); |
2200 | |
2201 | buf.append(structure_1(arg, stringSizeLimit, seen, refd)); |
2202 | } |
2203 | buf.append(")"); |
2204 | return r + str(buf); |
2205 | } |
2206 | |
2207 | int numFields = 0; |
2208 | String fieldName = ""; |
2209 | if (shortName.equals("DynamicObject")) { |
2210 | shortName = (String) get(o, "className"); |
2211 | Map<String, Object> fieldValues = (Map) get(o, "fieldValues"); |
2212 | |
2213 | for (String _fieldName : fieldValues.keySet()) { |
2214 | fieldName = _fieldName; |
2215 | Object value = fieldValues.get(fieldName); |
2216 | if (value != null) { |
2217 | if (buf.length() != 0) buf.append(", "); |
2218 | buf.append(fieldName + "=" + structure_1(value, stringSizeLimit, seen, refd)); |
2219 | } |
2220 | ++numFields; |
2221 | } |
2222 | } else { |
2223 | // regular class |
2224 | |
2225 | Class c = o.getClass(); |
2226 | while (c != Object.class) { |
2227 | Field[] fields = c.getDeclaredFields(); |
2228 | for (Field field : fields) { |
2229 | if ((field.getModifiers() & Modifier.STATIC) != 0) |
2230 | continue; |
2231 | fieldName = field.getName(); |
2232 | |
2233 | // skip outer object reference |
2234 | if (fieldName.indexOf("$") >= 0) continue; |
2235 | |
2236 | Object value; |
2237 | try { |
2238 | field.setAccessible(true); |
2239 | value = field.get(o); |
2240 | } catch (Exception e) { |
2241 | value = "?"; |
2242 | } |
2243 | |
2244 | // put special cases here... |
2245 | |
2246 | if (value != null) { |
2247 | if (buf.length() != 0) buf.append(", "); |
2248 | buf.append(fieldName + "=" + structure_1(value, stringSizeLimit, seen, refd)); |
2249 | } |
2250 | ++numFields; |
2251 | } |
2252 | c = c.getSuperclass(); |
2253 | } |
2254 | } |
2255 | |
2256 | String b = buf.toString(); |
2257 | |
2258 | if (numFields == 1 && structure_allowShortening) |
2259 | b = b.replaceAll("^" + fieldName + "=", ""); // drop field name if only one |
2260 | String s = shortName; |
2261 | if (buf.length() != 0) |
2262 | s += "(" + b + ")"; |
2263 | return r + s; |
2264 | } |
2265 | |
2266 | // drop unused markers |
2267 | static String structure_2(String s, HashSet<Integer> refd) { |
2268 | List<String> tok = javaTok(s); |
2269 | new StringBuilder out; |
2270 | for (int i = 1; i < l(tok); i += 2) { |
2271 | String t = tok.get(i); |
2272 | if (t.startsWith("m") && isInteger(t.substring(1)) |
2273 | && !refd.contains(parseInt(t.substring(1)))) |
2274 | continue; |
2275 | out.append(t).append(tok.get(i+1)); |
2276 | } |
2277 | return str(out); |
2278 | } |
2279 | |
2280 | // does not store null values |
2281 | static Map indexByField(Collection c, String field) { |
2282 | new HashMap map; |
2283 | for (Object a : c) { |
2284 | Object val = getOpt(a, field); |
2285 | if (val != null) |
2286 | map.put(val, a); |
2287 | } |
2288 | return map; |
2289 | } |
2290 | static volatile new StringBuffer local_log; // not redirected |
2291 | static volatile StringBuffer print_log = local_log; // might be redirected, e.g. to main bot |
2292 | |
2293 | // in bytes - will cut to half that |
2294 | static volatile int print_log_max = 1024*1024; |
2295 | static volatile int local_log_max = 100*1024; |
2296 | |
2297 | static boolean print_silent; // total mute if set |
2298 | |
2299 | static void print() { |
2300 | print(""); |
2301 | } |
2302 | |
2303 | // slightly overblown signature to return original object... |
2304 | static <A> A print(A o) { |
2305 | if (print_silent) return o; |
2306 | String s = String.valueOf(o) + "\n"; |
2307 | StringBuffer loc = local_log; |
2308 | StringBuffer buf = print_log; |
2309 | int loc_max = print_log_max; |
2310 | if (buf != loc && buf != null) { |
2311 | print_append(buf, s, print_log_max); |
2312 | loc_max = local_log_max; |
2313 | } |
2314 | if (loc != null) |
2315 | print_append(loc, s, loc_max); |
2316 | System.out.print(s); |
2317 | return o; |
2318 | } |
2319 | |
2320 | static void print(long l) { |
2321 | print(String.valueOf(l)); |
2322 | } |
2323 | |
2324 | static void print(char c) { |
2325 | print(String.valueOf(c)); |
2326 | } |
2327 | |
2328 | static void print_append(StringBuffer buf, String s, int max) { |
2329 | synchronized(buf) { |
2330 | buf.append(s); |
2331 | max /= 2; |
2332 | if (buf.length() > max) try { |
2333 | int newLength = max/2; |
2334 | int ofs = buf.length()-newLength; |
2335 | String newString = buf.substring(ofs); |
2336 | buf.setLength(0); |
2337 | buf.append("[...] ").append(newString); |
2338 | } catch (Exception e) { |
2339 | buf.setLength(0); |
2340 | } |
2341 | } |
2342 | } |
2343 | static void tableColumnMaxWidth(JTable table, int columnIdx, int width) { |
2344 | try { |
2345 | if (inRange(columnIdx, table.getColumnCount())) |
2346 | table.getColumnModel().getColumn(columnIdx).setMaxWidth(width); |
2347 | } catch (Throwable __e) { printStackTrace(__e); } |
2348 | } |
2349 | static String randomID(int length) { |
2350 | return makeRandomID(length); |
2351 | } |
2352 | static class ELPost { |
2353 | String text; |
2354 | int suggestionIndex; // Which suggestion was taken? |
2355 | String suggester; |
2356 | } |
2357 | |
2358 | static List<ELPost> scanEventLogForPosts(String progID, String dialogName) { |
2359 | return scanEventLogForPosts(getProgramFile(progID, dialogName)); |
2360 | } |
2361 | |
2362 | // dialogDir can also be the log file |
2363 | static List<ELPost> scanEventLogForPosts(File dialogDir) { |
2364 | if (dialogDir == null) return null; |
2365 | List<List> l = scanLog_safeUnstructure(fileFromDir(dialogDir, "event.log")); |
2366 | new List<ELPost> data; |
2367 | for (int i = 0; i < l(l); i++) try { |
2368 | List a = l.get(i), prev = get(l, i-1); |
2369 | if (firstIs(a, "Posting")) { |
2370 | Map map = (Map) ( get(a, 2)); |
2371 | String text = getString(map, "Text").trim(); |
2372 | if (eq(text, "!delete")) { removeLast(data); continue; } |
2373 | new ELPost post; |
2374 | post.text = text; |
2375 | try { |
2376 | if (prev != null && firstIs(prev, "Suggestion chosen")) { |
2377 | Map m = getMap(prev, 2); |
2378 | String suggestion = getString(m, "Suggestion"); |
2379 | if (eq(suggestion, post.text)) { |
2380 | post.suggestionIndex = toInt(get(m, "Row")); |
2381 | post.suggester = getString(m, "Suggester"); |
2382 | } |
2383 | } |
2384 | } catch (Throwable __e) { printStackTrace(__e); } |
2385 | data.add(post); |
2386 | } |
2387 | } catch (Throwable __e) { printStackTrace(__e); } |
2388 | return data; |
2389 | } |
2390 | |
2391 | |
2392 | |
2393 | static boolean startsWithOneOf(String s, String... l) { |
2394 | for (String x : l) if (startsWith(s, x)) return true; return false; |
2395 | } |
2396 | static Object[] asArray(List l) { |
2397 | return toObjectArray(l); |
2398 | } |
2399 | |
2400 | static Object[] asArray(Class type, List l) { |
2401 | return l.toArray((Object[]) Array.newInstance(type, l.size())); |
2402 | } |
2403 | static JFrame makeFrame() { |
2404 | return makeFrame((Component) null); |
2405 | } |
2406 | |
2407 | static JFrame makeFrame(Object content) { |
2408 | return makeFrame(programTitle(), content); |
2409 | } |
2410 | |
2411 | static JFrame makeFrame(String title) { |
2412 | return makeFrame(title, null); |
2413 | } |
2414 | |
2415 | static JFrame makeFrame(String title, Object content) { |
2416 | return makeFrame(title, content, true); |
2417 | } |
2418 | |
2419 | static JFrame makeFrame(String title, Object content, boolean showIt) { |
2420 | JFrame frame = new JFrame(title); |
2421 | if (content != null) |
2422 | frame.getContentPane().add(wrap(content)); |
2423 | frame.setBounds(300, 100, 500, 400); |
2424 | if (showIt) |
2425 | frame.setVisible(true); |
2426 | //callOpt(content, "requestFocus"); |
2427 | //exitOnFrameClose(frame); |
2428 | |
2429 | // standard right-click behavior on titles |
2430 | if (isSubstanceLAF()) |
2431 | onTitleRightClick(frame, new Runnable() { public void run() { try { showConsole(); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}); |
2432 | return frame; |
2433 | } |
2434 | static Object callFunction(Object f, Object... args) { |
2435 | if (f == null) return null; |
2436 | if (f instanceof Runnable) { |
2437 | ((Runnable) f).run(); |
2438 | return null; |
2439 | } else if (f instanceof String) |
2440 | return call(mc(), (String) f, args); |
2441 | else |
2442 | return call(f, "get", args); |
2443 | //else throw fail("Can't call a " + getClassName(f)); |
2444 | } |
2445 | static <A> ArrayList<A> asList(A[] a) { |
2446 | return new ArrayList<A>(Arrays.asList(a)); |
2447 | } |
2448 | |
2449 | static ArrayList<Integer> asList(int[] a) { |
2450 | ArrayList<Integer> l = new ArrayList(); |
2451 | for (int i : a) l.add(i); |
2452 | return l; |
2453 | } |
2454 | |
2455 | static <A> ArrayList<A> asList(Collection<A> s) { |
2456 | return s == null ? new ArrayList() |
2457 | : s instanceof ArrayList ? (ArrayList) s : new ArrayList(s); |
2458 | } |
2459 | static String quote(String s) { |
2460 | if (s == null) return "null"; |
2461 | return "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\r", "\\r").replace("\n", "\\n") + "\""; |
2462 | } |
2463 | |
2464 | static String quote(long l) { |
2465 | return quote("" + l); |
2466 | } |
2467 | |
2468 | static String quote(char c) { |
2469 | return quote("" + c); |
2470 | } |
2471 | |
2472 | static <A> A assertNotNull(A a) { |
2473 | assertTrue(a != null); |
2474 | return a; |
2475 | } |
2476 | |
2477 | static <A> A assertNotNull(String msg, A a) { |
2478 | assertTrue(msg, a != null); |
2479 | return a; |
2480 | } |
2481 | static String quoteCharacter(char c) { |
2482 | if (c == '\'') return "'\\''"; |
2483 | if (c == '\\') return "'\\\\'"; |
2484 | return "'" + c + "'"; |
2485 | } |
2486 | |
2487 | static boolean isAWTThread() { |
2488 | return SwingUtilities.isEventDispatchThread(); |
2489 | } |
2490 | static void smartAdd(JPanel panel, Object... parts) { |
2491 | for (Object o : parts) { |
2492 | Component c; |
2493 | if (o instanceof String) |
2494 | c = new JLabel((String) o); |
2495 | else |
2496 | c = wrap(o); |
2497 | panel.add(c); |
2498 | } |
2499 | } |
2500 | static boolean isProperlyQuoted(String s) { |
2501 | return s.length() >= 2 |
2502 | && s.startsWith("\"") |
2503 | && s.endsWith("\"") |
2504 | && !s.endsWith("\\\""); |
2505 | } |
2506 | static String strPreserveNull(Object s) { |
2507 | return s == null ? null : str(s); |
2508 | } |
2509 | static Point mousePosition() { |
2510 | return MouseInfo.getPointerInfo().getLocation(); |
2511 | } |
2512 | static JMenuBar addMenuBar(JFrame f) { |
2513 | JMenuBar bar = f.getJMenuBar(); |
2514 | if (bar == null) |
2515 | f.setJMenuBar(bar = new JMenuBar()); |
2516 | return bar; |
2517 | } |
2518 | static String programID; |
2519 | |
2520 | static String getProgramID() { |
2521 | return nempty(programID) ? formatSnippetID(programID) : "?"; |
2522 | } |
2523 | |
2524 | // TODO: ask JavaX instead |
2525 | static String getProgramID(Class c) { |
2526 | String id = (String) getOpt(c, "programID"); |
2527 | if (nempty(id)) |
2528 | return formatSnippetID(id); |
2529 | return "?"; |
2530 | } |
2531 | |
2532 | static String getProgramID(Object o) { |
2533 | return getProgramID(getMainClass(o)); |
2534 | } |
2535 | // replacement for class JavaTok |
2536 | // maybe incomplete, might want to add floating point numbers |
2537 | // todo also: extended multi-line strings |
2538 | |
2539 | static int javaTok_n, javaTok_elements; |
2540 | static boolean javaTok_opt; |
2541 | |
2542 | static List<String> javaTok(String s) { |
2543 | return javaTok(s, null); |
2544 | } |
2545 | |
2546 | static List<String> javaTok(String s, List<String> existing) { |
2547 | ++javaTok_n; |
2548 | int nExisting = javaTok_opt && existing != null ? existing.size() : 0; |
2549 | List<String> tok = existing != null ? new ArrayList(nExisting) : new ArrayList(); |
2550 | int l = s.length(); |
2551 | |
2552 | int i = 0, n = 0; |
2553 | while (i < l) { |
2554 | int j = i; |
2555 | char c; String cc; |
2556 | |
2557 | // scan for whitespace |
2558 | while (j < l) { |
2559 | c = s.charAt(j); |
2560 | cc = s.substring(j, Math.min(j+2, l)); |
2561 | if (c == ' ' || c == '\t' || c == '\r' || c == '\n') |
2562 | ++j; |
2563 | else if (cc.equals("/*")) { |
2564 | do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/")); |
2565 | j = Math.min(j+2, l); |
2566 | } else if (cc.equals("//")) { |
2567 | do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); |
2568 | } else |
2569 | break; |
2570 | } |
2571 | |
2572 | if (n < nExisting && javaTok_isCopyable(existing.get(n), s, i, j)) |
2573 | tok.add(existing.get(n)); |
2574 | else |
2575 | tok.add(quickSubstring(s, i, j)); |
2576 | ++n; |
2577 | i = j; |
2578 | if (i >= l) break; |
2579 | c = s.charAt(i); // cc is not needed in rest of loop body |
2580 | cc = s.substring(i, Math.min(i+2, l)); |
2581 | |
2582 | // scan for non-whitespace |
2583 | if (c == '\'' || c == '"') { |
2584 | char opener = c; |
2585 | ++j; |
2586 | while (j < l) { |
2587 | if (s.charAt(j) == opener || s.charAt(j) == '\n') { // end at \n to not propagate unclosed string literal errors |
2588 | ++j; |
2589 | break; |
2590 | } else if (s.charAt(j) == '\\' && j+1 < l) |
2591 | j += 2; |
2592 | else |
2593 | ++j; |
2594 | } |
2595 | } else if (Character.isJavaIdentifierStart(c)) |
2596 | do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || "'".indexOf(s.charAt(j)) >= 0)); // for stuff like "don't" |
2597 | else if (Character.isDigit(c)) { |
2598 | do ++j; while (j < l && Character.isDigit(s.charAt(j))); |
2599 | if (j < l && s.charAt(j) == 'L') ++j; // Long constants like 1L |
2600 | } else if (cc.equals("[[")) { |
2601 | do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]")); |
2602 | j = Math.min(j+2, l); |
2603 | } else if (cc.equals("[=") && i+2 < l && s.charAt(i+2) == '[') { |
2604 | do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]")); |
2605 | j = Math.min(j+3, l); |
2606 | } else |
2607 | ++j; |
2608 | |
2609 | if (n < nExisting && javaTok_isCopyable(existing.get(n), s, i, j)) |
2610 | tok.add(existing.get(n)); |
2611 | else |
2612 | tok.add(quickSubstring(s, i, j)); |
2613 | ++n; |
2614 | i = j; |
2615 | } |
2616 | |
2617 | if ((tok.size() % 2) == 0) tok.add(""); |
2618 | javaTok_elements += tok.size(); |
2619 | return tok; |
2620 | } |
2621 | |
2622 | static List<String> javaTok(List<String> tok) { |
2623 | return javaTok(join(tok), tok); |
2624 | } |
2625 | |
2626 | static boolean javaTok_isCopyable(String t, String s, int i, int j) { |
2627 | return t.length() == j-i |
2628 | && s.regionMatches(i, t, 0, j-i); // << could be left out, but that's brave |
2629 | } |
2630 | // patterns last so we can use var args |
2631 | static boolean matchOneOf(String s, Matches m, String... pats) { |
2632 | for (String pat : pats) |
2633 | if (match(pat, s, m)) return true; return false; |
2634 | } |
2635 | |
2636 | static boolean matchOneOf(String s, String... pats) { |
2637 | return matchOneOf(s, null, pats); |
2638 | } |
2639 | static Object newObject(Class c, Object... args) { |
2640 | return nuObject(c, args); |
2641 | } |
2642 | |
2643 | static Object newObject(String className, Object... args) { |
2644 | return nuObject(className, args); |
2645 | } |
2646 | |
2647 | // We'd be really fancy if we filtered out return statements in |
2648 | // inner blocks. |
2649 | static boolean containsReturnWithArgument(String code) { |
2650 | List<String> tok = javaTok(code); |
2651 | for (int i = 1; i+2 < l(tok); i += 2) |
2652 | if (eqOneOf(tok.get(i), "ret", "return") && neq(tok.get(i+2), ";")) return true; return false; |
2653 | } |
2654 | static String onlyAfter(String s, char c) { |
2655 | int i = s.indexOf(c); |
2656 | return i >= 0 ? s.substring(i+1) : ""; |
2657 | } |
2658 | static Class __javax; |
2659 | |
2660 | static Class getJavaX() { |
2661 | return __javax; |
2662 | } |
2663 | static void set(Object o, String field, Object value) { |
2664 | if (o instanceof Class) set((Class) o, field, value); |
2665 | else try { |
2666 | Field f = set_findField(o.getClass(), field); |
2667 | smartSet(f, o, value); |
2668 | } catch (Exception e) { |
2669 | throw new RuntimeException(e); |
2670 | } |
2671 | } |
2672 | |
2673 | static void set(Class c, String field, Object value) { |
2674 | try { |
2675 | Field f = set_findStaticField(c, field); |
2676 | smartSet(f, null, value); |
2677 | } catch (Exception e) { |
2678 | throw new RuntimeException(e); |
2679 | } |
2680 | } |
2681 | |
2682 | static Field set_findField(Class<?> c, String field) { |
2683 | for (Field f : c.getDeclaredFields()) |
2684 | if (f.getName().equals(field)) |
2685 | return f; |
2686 | throw new RuntimeException("Field '" + field + "' not found in " + c.getName()); |
2687 | } |
2688 | |
2689 | static Field set_findStaticField(Class<?> c, String field) { |
2690 | for (Field f : c.getDeclaredFields()) |
2691 | if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0) |
2692 | return f; |
2693 | throw new RuntimeException("Static field '" + field + "' not found in " + c.getName()); |
2694 | } |
2695 | static List collectField(Collection c, String field) { |
2696 | new List l; |
2697 | for (Object a : c) |
2698 | l.add(getOpt(a, field)); |
2699 | return l; |
2700 | } |
2701 | static Throwable getInnerException(Throwable e) { |
2702 | while (e.getCause() != null) |
2703 | e = e.getCause(); |
2704 | return e; |
2705 | } |
2706 | static Object call(Object o) { |
2707 | return callFunction(o); |
2708 | } |
2709 | |
2710 | // varargs assignment fixer for a single string array argument |
2711 | static Object call(Object o, String method, String[] arg) { |
2712 | return call(o, method, new Object[] {arg}); |
2713 | } |
2714 | |
2715 | static Object call(Object o, String method, Object... args) { |
2716 | try { |
2717 | if (o instanceof Class) { |
2718 | Method m = call_findStaticMethod((Class) o, method, args, false); |
2719 | m.setAccessible(true); |
2720 | return m.invoke(null, args); |
2721 | } else { |
2722 | Method m = call_findMethod(o, method, args, false); |
2723 | m.setAccessible(true); |
2724 | return m.invoke(o, args); |
2725 | } |
2726 | } catch (Exception e) { |
2727 | throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e); |
2728 | } |
2729 | } |
2730 | |
2731 | static Method call_findStaticMethod(Class c, String method, Object[] args, boolean debug) { |
2732 | Class _c = c; |
2733 | while (c != null) { |
2734 | for (Method m : c.getDeclaredMethods()) { |
2735 | if (debug) |
2736 | System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; |
2737 | if (!m.getName().equals(method)) { |
2738 | if (debug) System.out.println("Method name mismatch: " + method); |
2739 | continue; |
2740 | } |
2741 | |
2742 | if ((m.getModifiers() & Modifier.STATIC) == 0 || !call_checkArgs(m, args, debug)) |
2743 | continue; |
2744 | |
2745 | return m; |
2746 | } |
2747 | c = c.getSuperclass(); |
2748 | } |
2749 | throw new RuntimeException("Method '" + method + "' (static) with " + args.length + " parameter(s) not found in " + _c.getName()); |
2750 | } |
2751 | |
2752 | static Method call_findMethod(Object o, String method, Object[] args, boolean debug) { |
2753 | Class c = o.getClass(); |
2754 | while (c != null) { |
2755 | for (Method m : c.getDeclaredMethods()) { |
2756 | if (debug) |
2757 | System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; |
2758 | if (m.getName().equals(method) && call_checkArgs(m, args, debug)) |
2759 | return m; |
2760 | } |
2761 | c = c.getSuperclass(); |
2762 | } |
2763 | throw new RuntimeException("Method '" + method + "' (non-static) with " + args.length + " parameter(s) not found in " + o.getClass().getName()); |
2764 | } |
2765 | |
2766 | private static boolean call_checkArgs(Method m, Object[] args, boolean debug) { |
2767 | Class<?>[] types = m.getParameterTypes(); |
2768 | if (types.length != args.length) { |
2769 | if (debug) |
2770 | System.out.println("Bad parameter length: " + args.length + " vs " + types.length); |
2771 | return false; |
2772 | } |
2773 | for (int i = 0; i < types.length; i++) |
2774 | if (!(args[i] == null || isInstanceX(types[i], args[i]))) { |
2775 | if (debug) |
2776 | System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]); |
2777 | return false; |
2778 | } |
2779 | return true; |
2780 | } |
2781 | |
2782 | |
2783 | static boolean isTrue(Object o) { |
2784 | return booleanValue(o); |
2785 | } |
2786 | static int days() { |
2787 | return Calendar.getInstance().get(Calendar.DAY_OF_MONTH); |
2788 | } |
2789 | // c = Component or something implementing swing() |
2790 | static Component wrap(Object swingable) { |
2791 | Component c = (Component) ( swingable instanceof Component ? swingable : call(swingable, "swing")); |
2792 | if (c instanceof JTable || c instanceof JList || c instanceof JTextArea) |
2793 | return new JScrollPane(c); |
2794 | return c; |
2795 | } |
2796 | |
2797 | static Object callCalc(Object o) { |
2798 | return call(o, "calc"); |
2799 | } |
2800 | static boolean startsWithIgnoreCase(String a, String b) { |
2801 | return a != null && a.regionMatches(true, 0, b, 0, b.length()); |
2802 | } |
2803 | static <A> A nextToLast(List<A> l) { |
2804 | return get(l, l(l)-2); |
2805 | } |
2806 | // class Matches is added by #752 |
2807 | |
2808 | static boolean match3(String pat, String s) { |
2809 | return match3(pat, s, null); |
2810 | } |
2811 | |
2812 | static boolean match3(String pat, String s, Matches matches) { |
2813 | if (s == null) return false; |
2814 | return match3(pat, parse3(s), matches); |
2815 | } |
2816 | |
2817 | static boolean match3(String pat, List<String> toks, Matches matches) { |
2818 | List<String> tokpat = parse3(pat); |
2819 | return match3(tokpat,toks,matches); |
2820 | } |
2821 | |
2822 | static boolean match3(List<String> tokpat, List<String> toks, Matches matches) { |
2823 | |
2824 | String[] m = match2(tokpat, toks); |
2825 | //print(structure(tokpat) + " on " + structure(toks) + " => " + structure(m)); |
2826 | if (m == null) |
2827 | return false; |
2828 | else { |
2829 | if (matches != null) matches.m = m; |
2830 | return true; |
2831 | } |
2832 | } |
2833 | static Class run(String progID, String... args) { |
2834 | Class main = hotwire(progID); |
2835 | callMain(main, args); |
2836 | return main; |
2837 | } |
2838 | static boolean isInteger(String s) { |
2839 | return s != null && Pattern.matches("\\-?\\d+", s); |
2840 | } |
2841 | static String getStackTrace(Throwable throwable) { |
2842 | StringWriter writer = new StringWriter(); |
2843 | throwable.printStackTrace(new PrintWriter(writer)); |
2844 | return writer.toString(); |
2845 | } |
2846 | static void makeTableUneditable(JTable table) { |
2847 | for (int c = 0; c < table.getColumnCount(); c++) { |
2848 | Class<?> col_class = table.getColumnClass(c); |
2849 | table.setDefaultEditor(col_class, null); // remove editor |
2850 | } |
2851 | } |
2852 | static File programDir() { |
2853 | return programDir(getProgramID()); |
2854 | } |
2855 | |
2856 | static File programDir(String snippetID) { |
2857 | return new File(javaxDataDir(), formatSnippetID(snippetID)); |
2858 | } |
2859 | |
2860 | static String formatSnippetID(String id) { |
2861 | return "#" + parseSnippetID(id); |
2862 | } |
2863 | |
2864 | static String formatSnippetID(long id) { |
2865 | return "#" + id; |
2866 | } |
2867 | // returns true if a translator had been loaded |
2868 | static synchronized boolean veryQuickJava_refresh() { |
2869 | if (getOpt(mc(), "transpileRaw_trans") == null) return false; |
2870 | setOpt(mc(), "transpileRaw_trans", null); return true; |
2871 | } |
2872 | static int month() { |
2873 | return Calendar.getInstance().get(Calendar.MONTH)+1; |
2874 | } |
2875 | // optionally convert expression to return statement |
2876 | static String tok_addReturn(List<String> tok) { |
2877 | String lastToken = get(tok, l(tok)-2); |
2878 | //print("addReturn: " + structure(tok) + ", lastToken: " + quote(lastToken)); |
2879 | if (eq(lastToken, "}") || eq(lastToken, ";")) return join(tok); |
2880 | return "ret " + join(tok) + ";"; |
2881 | } |
2882 | |
2883 | static String tok_addReturn(String s) { |
2884 | return tok_addReturn(javaTok(s)); |
2885 | } |
2886 | public static File mkdirsForFile(File file) { |
2887 | File dir = file.getParentFile(); |
2888 | if (dir != null) // is null if file is in current dir |
2889 | dir.mkdirs(); |
2890 | return file; |
2891 | } |
2892 | |
2893 | static void substanceLAF() { |
2894 | substanceLAF(null); |
2895 | } |
2896 | |
2897 | static void substanceLAF(String skinName) { |
2898 | try { |
2899 | if (!substanceLookAndFeelEnabled()) { |
2900 | Object x = hotwire("#1003448"); |
2901 | if (skinName != null) |
2902 | set(x, "skinName", skinName); |
2903 | runMain(x); |
2904 | JFrame.setDefaultLookAndFeelDecorated(substanceLookAndFeelEnabled()); |
2905 | } |
2906 | } catch (Throwable __e) { printStackTrace(__e); } |
2907 | } |
2908 | static List emptyList() { |
2909 | return new ArrayList; |
2910 | //ret Collections.emptyList(); |
2911 | } |
2912 | static File fileFromDir(File f, String name) { |
2913 | return f.isDirectory() ? new File(f, name) : f; |
2914 | } |
2915 | |
2916 | // first delay = delay |
2917 | static void installTimer(JComponent component, Runnable r, int delay) { |
2918 | installTimer(component, r, delay, delay); |
2919 | } |
2920 | |
2921 | // first delay = delay |
2922 | static void installTimer(JFrame frame, int delay, Runnable r) { |
2923 | installTimer(frame.getRootPane(), r, delay, delay); |
2924 | } |
2925 | |
2926 | // first delay = delay |
2927 | static void installTimer(JComponent component, int delay, Runnable r) { |
2928 | installTimer(component, r, delay, delay); |
2929 | } |
2930 | |
2931 | static void installTimer(final JComponent component, final Runnable r, final int delay, final int firstDelay) { |
2932 | installTimer(component, r, delay, firstDelay, true); |
2933 | } |
2934 | |
2935 | static void installTimer(final JComponent component, final Runnable r, final int delay, final int firstDelay, final boolean repeats) { |
2936 | swingLater(new Runnable() { public void run() { try { |
2937 | final Timer timer = new Timer(delay, new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent _evt) { |
2938 | r.run(); |
2939 | }}); |
2940 | timer.setInitialDelay(firstDelay); |
2941 | timer.setRepeats(repeats); |
2942 | |
2943 | if (component.isShowing()) |
2944 | timer.start(); |
2945 | |
2946 | component.addAncestorListener(new AncestorListener() { |
2947 | public void ancestorAdded(AncestorEvent event) { |
2948 | timer.start(); |
2949 | } |
2950 | |
2951 | public void ancestorRemoved(AncestorEvent event) { |
2952 | timer.stop(); |
2953 | } |
2954 | |
2955 | public void ancestorMoved(AncestorEvent event) { |
2956 | } |
2957 | }); |
2958 | } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}); |
2959 | } |
2960 | |
2961 | public static String unquote(String s) { |
2962 | if (s == null) return null; |
2963 | if (s.startsWith("[")) { |
2964 | int i = 1; |
2965 | while (i < s.length() && s.charAt(i) == '=') ++i; |
2966 | if (i < s.length() && s.charAt(i) == '[') { |
2967 | String m = s.substring(1, i); |
2968 | if (s.endsWith("]" + m + "]")) |
2969 | return s.substring(i+1, s.length()-i-1); |
2970 | } |
2971 | } |
2972 | |
2973 | if (s.startsWith("\"") /*&& s.endsWith("\"")*/ && s.length() > 1) { |
2974 | String st = s.substring(1, s.endsWith("\"") ? s.length()-1 : s.length()); |
2975 | StringBuilder sb = new StringBuilder(st.length()); |
2976 | |
2977 | for (int i = 0; i < st.length(); i++) { |
2978 | char ch = st.charAt(i); |
2979 | if (ch == '\\') { |
2980 | char nextChar = (i == st.length() - 1) ? '\\' : st |
2981 | .charAt(i + 1); |
2982 | // Octal escape? |
2983 | if (nextChar >= '0' && nextChar <= '7') { |
2984 | String code = "" + nextChar; |
2985 | i++; |
2986 | if ((i < st.length() - 1) && st.charAt(i + 1) >= '0' |
2987 | && st.charAt(i + 1) <= '7') { |
2988 | code += st.charAt(i + 1); |
2989 | i++; |
2990 | if ((i < st.length() - 1) && st.charAt(i + 1) >= '0' |
2991 | && st.charAt(i + 1) <= '7') { |
2992 | code += st.charAt(i + 1); |
2993 | i++; |
2994 | } |
2995 | } |
2996 | sb.append((char) Integer.parseInt(code, 8)); |
2997 | continue; |
2998 | } |
2999 | switch (nextChar) { |
3000 | case '\\': |
3001 | ch = '\\'; |
3002 | break; |
3003 | case 'b': |
3004 | ch = '\b'; |
3005 | break; |
3006 | case 'f': |
3007 | ch = '\f'; |
3008 | break; |
3009 | case 'n': |
3010 | ch = '\n'; |
3011 | break; |
3012 | case 'r': |
3013 | ch = '\r'; |
3014 | break; |
3015 | case 't': |
3016 | ch = '\t'; |
3017 | break; |
3018 | case '\"': |
3019 | ch = '\"'; |
3020 | break; |
3021 | case '\'': |
3022 | ch = '\''; |
3023 | break; |
3024 | // Hex Unicode: u???? |
3025 | case 'u': |
3026 | if (i >= st.length() - 5) { |
3027 | ch = 'u'; |
3028 | break; |
3029 | } |
3030 | int code = Integer.parseInt( |
3031 | "" + st.charAt(i + 2) + st.charAt(i + 3) |
3032 | + st.charAt(i + 4) + st.charAt(i + 5), 16); |
3033 | sb.append(Character.toChars(code)); |
3034 | i += 5; |
3035 | continue; |
3036 | default: |
3037 | ch = nextChar; // added by Stefan |
3038 | } |
3039 | i++; |
3040 | } |
3041 | sb.append(ch); |
3042 | } |
3043 | return sb.toString(); |
3044 | } else |
3045 | return s; // return original |
3046 | } |
3047 | static String programID() { |
3048 | return getProgramID(); |
3049 | } |
3050 | static int hours() { |
3051 | return Calendar.getInstance().get(Calendar.HOUR_OF_DAY); |
3052 | } |
3053 | static boolean isEmpty(Collection c) { |
3054 | return c == null || c.isEmpty(); |
3055 | } |
3056 | |
3057 | static boolean isEmpty(CharSequence s) { |
3058 | return s == null || s.length() == 0; |
3059 | } |
3060 | |
3061 | static boolean isEmpty(Object[] a) { |
3062 | return a == null || a.length == 0; |
3063 | } |
3064 | |
3065 | static boolean isEmpty(Map map) { |
3066 | return map == null || map.isEmpty(); |
3067 | } |
3068 | static String makeRandomID(int length) { |
3069 | Random random = new Random(); |
3070 | char[] id = new char[length]; |
3071 | for (int i = 0; i < id.length; i++) |
3072 | id[i] = (char) ((int) 'a' + random.nextInt(26)); |
3073 | return new String(id); |
3074 | } |
3075 | static char unquoteCharacter(String s) { |
3076 | assertTrue(s.startsWith("'") && s.length() > 1); |
3077 | return unquote("\"" + s.substring(1, s.endsWith("'") ? s.length()-1 : s.length()) + "\"").charAt(0); |
3078 | } |
3079 | static int parseInt(String s) { |
3080 | return empty(s) ? 0 : Integer.parseInt(s); |
3081 | } |
3082 | static String structureOrText(Object o) { |
3083 | return o instanceof String ? (String) o : structure(o); |
3084 | } |
3085 | static void setOpt(Object o, String field, Object value) { |
3086 | if (o instanceof Class) setOpt((Class) o, field, value); |
3087 | else try { |
3088 | Field f = setOpt_findField(o.getClass(), field); |
3089 | if (f != null) |
3090 | smartSet(f, o, value); |
3091 | } catch (Exception e) { |
3092 | throw new RuntimeException(e); |
3093 | } |
3094 | } |
3095 | |
3096 | static void setOpt(Class c, String field, Object value) { |
3097 | try { |
3098 | Field f = setOpt_findStaticField(c, field); |
3099 | if (f != null) |
3100 | smartSet(f, null, value); |
3101 | } catch (Exception e) { |
3102 | throw new RuntimeException(e); |
3103 | } |
3104 | } |
3105 | |
3106 | static Field setOpt_findField(Class<?> c, String field) { |
3107 | for (Field f : c.getDeclaredFields()) |
3108 | if (f.getName().equals(field)) |
3109 | return f; |
3110 | return null; |
3111 | } |
3112 | |
3113 | static Field setOpt_findStaticField(Class<?> c, String field) { |
3114 | for (Field f : c.getDeclaredFields()) |
3115 | if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0) |
3116 | return f; |
3117 | return null; |
3118 | } |
3119 | static Object getOpt(Object o, String field) { |
3120 | if (o instanceof String) o = getBot ((String) o); |
3121 | if (o == null) return null; |
3122 | if (o instanceof Class) return getOpt((Class) o, field); |
3123 | |
3124 | if (o.getClass().getName().equals("main$DynamicObject")) |
3125 | return ((Map) getOpt_raw(o, "fieldValues")).get(field); |
3126 | |
3127 | if (o instanceof Map) return ((Map) o).get(field); |
3128 | |
3129 | return getOpt_raw(o, field); |
3130 | } |
3131 | |
3132 | static Object getOpt_raw(Object o, String field) { |
3133 | try { |
3134 | Field f = getOpt_findField(o.getClass(), field); |
3135 | if (f == null) return null; |
3136 | f.setAccessible(true); |
3137 | return f.get(o); |
3138 | } catch (Exception e) { |
3139 | throw new RuntimeException(e); |
3140 | } |
3141 | } |
3142 | |
3143 | static Object getOpt(Class c, String field) { |
3144 | try { |
3145 | if (c == null) return null; |
3146 | Field f = getOpt_findStaticField(c, field); |
3147 | if (f == null) return null; |
3148 | f.setAccessible(true); |
3149 | return f.get(null); |
3150 | } catch (Exception e) { |
3151 | throw new RuntimeException(e); |
3152 | } |
3153 | } |
3154 | |
3155 | static Field getOpt_findStaticField(Class<?> c, String field) { |
3156 | Class _c = c; |
3157 | do { |
3158 | for (Field f : _c.getDeclaredFields()) |
3159 | if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0) |
3160 | return f; |
3161 | _c = _c.getSuperclass(); |
3162 | } while (_c != null); |
3163 | return null; |
3164 | } |
3165 | |
3166 | static Field getOpt_findField(Class<?> c, String field) { |
3167 | Class _c = c; |
3168 | do { |
3169 | for (Field f : _c.getDeclaredFields()) |
3170 | if (f.getName().equals(field)) |
3171 | return f; |
3172 | _c = _c.getSuperclass(); |
3173 | } while (_c != null); |
3174 | return null; |
3175 | } |
3176 | // hopefully covers all cases :) |
3177 | static String safeSubstring(String s, int x, int y) { |
3178 | if (s == null) return null; |
3179 | if (x < 0) x = 0; |
3180 | if (x > s.length()) return ""; |
3181 | if (y < x) y = x; |
3182 | if (y > s.length()) y = s.length(); |
3183 | return s.substring(x, y); |
3184 | } |
3185 | |
3186 | static String safeSubstring(String s, int x) { |
3187 | return safeSubstring(s, x, l(s)); |
3188 | } |
3189 | |
3190 | static int seconds() { |
3191 | return Calendar.getInstance().get(Calendar.SECOND); |
3192 | } |
3193 | static String shorten(String s, int max) { |
3194 | if (s == null) return ""; |
3195 | return s.length() <= max ? s : s.substring(0, Math.min(s.length(), max)) + "..."; |
3196 | } |
3197 | public static String join(String glue, Iterable<String> strings) { |
3198 | StringBuilder buf = new StringBuilder(); |
3199 | Iterator<String> i = strings.iterator(); |
3200 | if (i.hasNext()) { |
3201 | buf.append(i.next()); |
3202 | while (i.hasNext()) |
3203 | buf.append(glue).append(i.next()); |
3204 | } |
3205 | return buf.toString(); |
3206 | } |
3207 | |
3208 | public static String join(String glue, String[] strings) { |
3209 | return join(glue, Arrays.asList(strings)); |
3210 | } |
3211 | |
3212 | public static String join(Iterable<String> strings) { |
3213 | return join("", strings); |
3214 | } |
3215 | |
3216 | public static String join(String[] strings) { |
3217 | return join("", strings); |
3218 | } |
3219 | |
3220 | static String dropPrefix(String prefix, String s) { |
3221 | return s.startsWith(prefix) ? s.substring(l(prefix)) : s; |
3222 | } |
3223 | static List<String> codeTokensOnly(List<String> tok) { |
3224 | new List<String> l; |
3225 | for (int i = 1; i < tok.size(); i += 2) |
3226 | l.add(tok.get(i)); |
3227 | return l; |
3228 | } |
3229 | // currently finds only inner classes of class "main" |
3230 | // returns null on not found |
3231 | // this is the simple version that is not case-tolerant |
3232 | static Class findClass(String name) { |
3233 | try { |
3234 | return Class.forName("main$" + name); |
3235 | } catch (ClassNotFoundException e) { |
3236 | return null; |
3237 | } |
3238 | } |
3239 | static Object safeUnstructure(String s) { |
3240 | return unstructure(s, true); |
3241 | } |
3242 | static boolean isJavaIdentifier(String s) { |
3243 | if (s.length() == 0 || !Character.isJavaIdentifierStart(s.charAt(0))) |
3244 | return false; |
3245 | for (int i = 1; i < s.length(); i++) |
3246 | if (!Character.isJavaIdentifierPart(s.charAt(i))) |
3247 | return false; |
3248 | return true; |
3249 | } |
3250 | static boolean _inCore() { |
3251 | return false; |
3252 | } |
3253 | static JTable dataToTable(Object data) { |
3254 | return dataToTable(showTable(), data); |
3255 | } |
3256 | |
3257 | static JTable dataToTable(Object data, String title) { |
3258 | return dataToTable(showTable(title), data); |
3259 | } |
3260 | |
3261 | static JTable dataToTable(JTable table, Object data) { |
3262 | return dataToTable(table, data, false); |
3263 | } |
3264 | |
3265 | static JTable dataToTable(JTable table, Object data, boolean now) { |
3266 | new List<List<String>> rows; |
3267 | new List<String> cols; |
3268 | |
3269 | if (data instanceof List) { |
3270 | for (Object x : (List) data) try { |
3271 | rows.add(dataToTable_makeRow(x, cols)); |
3272 | } catch (Throwable __e) { printStackTrace(__e); } |
3273 | } else if (data instanceof Map) { |
3274 | Map map = (Map) ( data); |
3275 | for (Object key : map.keySet()) { |
3276 | Object value = map.get(key); |
3277 | rows.add(litlist(structureOrText(key), structureOrText(value))); |
3278 | } |
3279 | } else |
3280 | print("Unknown data type: " + data); |
3281 | |
3282 | if (now) |
3283 | table.setModel(fillTableWithStrings_makeModel(rows, toStringArray(cols))); |
3284 | else |
3285 | fillTableWithStrings(table, rows, cols); |
3286 | return table; |
3287 | } |
3288 | |
3289 | static Rectangle boundsOnScreen(Component c) { |
3290 | if (c.getParent() instanceof JViewport |
3291 | && c.getParent().getParent() instanceof JScrollPane) |
3292 | c = c.getParent().getParent(); |
3293 | return new Rectangle(c.getLocationOnScreen(), c.getSize()); |
3294 | } |
3295 | static <A> ArrayList<A> litlist(A... a) { |
3296 | return new ArrayList<A>(Arrays.asList(a)); |
3297 | } |
3298 | static boolean isLongConstant(String s) { |
3299 | if (!s.endsWith("L")) return false; |
3300 | s = s.substring(0, l(s)-1); |
3301 | return isInteger(s); |
3302 | } |
3303 | static List<String> toLines(File f) { |
3304 | return toLines(loadTextFile(f)); |
3305 | } |
3306 | |
3307 | public static List<String> toLines(String s) { |
3308 | List<String> lines = new ArrayList<String>(); |
3309 | if (s == null) return lines; |
3310 | int start = 0; |
3311 | while (true) { |
3312 | int i = toLines_nextLineBreak(s, start); |
3313 | if (i < 0) { |
3314 | if (s.length() > start) lines.add(s.substring(start)); |
3315 | break; |
3316 | } |
3317 | |
3318 | lines.add(s.substring(start, i)); |
3319 | if (s.charAt(i) == '\r' && i+1 < s.length() && s.charAt(i+1) == '\n') |
3320 | i += 2; |
3321 | else |
3322 | ++i; |
3323 | |
3324 | start = i; |
3325 | } |
3326 | return lines; |
3327 | } |
3328 | |
3329 | private static int toLines_nextLineBreak(String s, int start) { |
3330 | for (int i = start; i < s.length(); i++) { |
3331 | char c = s.charAt(i); |
3332 | if (c == '\r' || c == '\n') |
3333 | return i; |
3334 | } |
3335 | return -1; |
3336 | } |
3337 | static void nohupJavax(String javaxargs) { |
3338 | nohupJavax(javaxargs, ""); |
3339 | } |
3340 | |
3341 | // vm args are ignored if pre-spun VM found... |
3342 | static void nohupJavax(String javaxargs, String vmArgs) { |
3343 | javaxargs = javaxargs.trim(); |
3344 | if (javaxargs.startsWith("#")) javaxargs = javaxargs.substring(1); |
3345 | String snippetID = javaTok(javaxargs).get(1); |
3346 | int idx = javaxargs.indexOf(' '); |
3347 | String args = idx < 0 ? "" : javaxargs.substring(idx+1).trim(); |
3348 | |
3349 | String line; |
3350 | if (args.length() != 0) |
3351 | line = format3("please start program * with arguments *", snippetID, args); |
3352 | else |
3353 | line = format3("please start program *", snippetID); |
3354 | String answer = sendToLocalBotOpt("A pre-spun VM.", line); |
3355 | if (match3("ok", answer)) { |
3356 | print("OK, used pre-spun VM."); |
3357 | } else { |
3358 | if (answer != null) |
3359 | print("> " + answer); |
3360 | print("Using standard nohup."); |
3361 | classicNohupJavax(javaxargs, vmArgs); |
3362 | } |
3363 | } |
3364 | static String autoFrameTitle() { |
3365 | return getProgramTitle(); |
3366 | } |
3367 | static List map(Object f, List l) { |
3368 | new List x; |
3369 | Object mc = mc(); |
3370 | for (Object o : unnull(l)) |
3371 | x.add(callFunction(f, o)); |
3372 | return x; |
3373 | } |
3374 | static WeakReference<Class> creator_class; |
3375 | |
3376 | static Class creator() { |
3377 | return creator_class == null ? null : creator_class.get(); |
3378 | } |
3379 | static void fillJMenu(JMenu m, Object... x) { |
3380 | if (x == null) return; |
3381 | for (int i = 0; i < l(x); i++) { |
3382 | Object o = x[i], y = get(x, i+1); |
3383 | if (eqOneOf(o, "***", "---", "===", "")) |
3384 | m.addSeparator(); |
3385 | else if (o instanceof String && y instanceof Runnable) { |
3386 | m.add(jmenuItem((String) o, (Runnable) y)); |
3387 | ++i; |
3388 | } else if (o instanceof JMenuItem) |
3389 | m.add((JMenuItem) o); // "call" might use wrong method |
3390 | else if (o instanceof String || o instanceof Action || o instanceof Component) |
3391 | call(m, "add", o); |
3392 | else |
3393 | print("Unknown menu item: " + o); |
3394 | } |
3395 | } |
3396 | static int max(int a, int b) { |
3397 | return Math.max(a, b); |
3398 | } |
3399 | |
3400 | static long max(int a, long b) { |
3401 | return Math.max((long) a, b); |
3402 | } |
3403 | |
3404 | static long max(long a, long b) { |
3405 | return Math.max(a, b); |
3406 | } |
3407 | |
3408 | static double max(int a, double b) { |
3409 | return Math.max((double) a, b); |
3410 | } |
3411 | |
3412 | static int max(Collection<Integer> c) { |
3413 | int x = Integer.MIN_VALUE; |
3414 | for (int i : c) x = max(x, i); |
3415 | return x; |
3416 | } |
3417 | |
3418 | static double max(double[] c) { |
3419 | if (c.length == 0) return Double.MIN_VALUE; |
3420 | double x = c[0]; |
3421 | for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]); |
3422 | return x; |
3423 | } |
3424 | |
3425 | static byte max(byte[] c) { |
3426 | byte x = -128; |
3427 | for (byte d : c) if (d > x) x = d; |
3428 | return x; |
3429 | } |
3430 | static void restart() { |
3431 | nohupJavax(programID()); |
3432 | System.exit(0); |
3433 | } |
3434 | static File getProgramDir() { |
3435 | return programDir(); |
3436 | } |
3437 | |
3438 | static File getProgramDir(String snippetID) { |
3439 | return programDir(snippetID); |
3440 | } |
3441 | static Object quickExport(Object o, Object dest) { try { |
3442 | |
3443 | return quickExport_impl(o, dest, new IdentityHashMap); |
3444 | |
3445 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
3446 | |
3447 | static Object quickExport_impl(Object o, Object dest, IdentityHashMap seen) { try { |
3448 | |
3449 | if (o == null || o instanceof String || o instanceof Number) return o; |
3450 | |
3451 | Object oo = seen.get(o); |
3452 | if (oo != null) return oo; |
3453 | |
3454 | if (o instanceof List) { |
3455 | List l = (List) ( o); |
3456 | List destO = new ArrayList(l.size()); |
3457 | seen.put(o, destO); |
3458 | for (int i = 0; i < l.size(); i++) |
3459 | destO.add(quickExport_impl(l.get(i), dest, seen)); |
3460 | return destO; |
3461 | } |
3462 | |
3463 | if (o instanceof Map) { |
3464 | Map m = (Map) ( o); |
3465 | Map destO = new HashMap(); |
3466 | seen.put(o, destO); |
3467 | for (Object e : ((Map) o).entrySet()) |
3468 | destO.put( |
3469 | quickExport_impl(((Map.Entry) e).getKey(), dest, seen), |
3470 | quickExport_impl(((Map.Entry) e).getValue(), dest, seen)); |
3471 | return destO; |
3472 | } |
3473 | |
3474 | String className = o.getClass().getName(); |
3475 | if (className.startsWith("main$") && !isAnonymousClassName(className)) { |
3476 | Class destClass = getClass(dest, className); |
3477 | //print(o.getClass() + " => " + destClass); |
3478 | |
3479 | if (o.getClass() == destClass) |
3480 | return o; // no export necessary |
3481 | |
3482 | // actually make a new object, copy fields |
3483 | |
3484 | Object destO = nuObject(destClass); |
3485 | seen.put(o, destO); |
3486 | |
3487 | // TODO: superclasses |
3488 | Field[] fields = o.getClass().getDeclaredFields(); |
3489 | for (Field field : fields) { |
3490 | if ((field.getModifiers() & Modifier.STATIC) != 0) |
3491 | continue; |
3492 | field.setAccessible(true); |
3493 | Object value = field.get(o); |
3494 | setOpt(destO, field.getName(), quickExport_impl(value, dest, seen)); |
3495 | } |
3496 | |
3497 | return destO; |
3498 | } |
3499 | |
3500 | // assume it's a shared library object |
3501 | return o; |
3502 | |
3503 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
3504 | static long parseLong(String s) { |
3505 | if (s == null) return 0; |
3506 | return Long.parseLong(dropSuffix("L", s)); |
3507 | } |
3508 | |
3509 | static long parseLong(Object s) { |
3510 | return Long.parseLong((String) s); |
3511 | } |
3512 | static JTextArea newTypeWriterTextArea() { |
3513 | new JTextArea textArea; |
3514 | textArea.setFont(typeWriterFont()); |
3515 | return textArea; |
3516 | } |
3517 | |
3518 | static JTextArea newTypeWriterTextArea(String text) { |
3519 | JTextArea textArea = newTypeWriterTextArea(); |
3520 | textArea.setText(text); |
3521 | return textArea; |
3522 | } |
3523 | static String getSnippetTitle(String id) { try { |
3524 | |
3525 | if (!isSnippetID(id)) return "?"; |
3526 | return loadPageSilently(new URL("http://tinybrain.de:8080/tb-int/getfield.php?id=" + parseSnippetID(id) + "&field=title")); |
3527 | |
3528 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
3529 | static String formatInt(int i, int digits) { |
3530 | return padLeft(str(i), '0', digits); |
3531 | } |
3532 | |
3533 | static void hotwire_copyOver(Class c) { |
3534 | synchronized(StringBuffer.class) { |
3535 | for (String field : litlist("print_log", "print_silent")) { |
3536 | Object o = get(mc(), field); |
3537 | if (o != null) |
3538 | setOpt(c, field, o); |
3539 | } |
3540 | |
3541 | Object mainBot = getMainBot(); |
3542 | if (mainBot != null) |
3543 | setOpt(c, "mainBot", mainBot); |
3544 | |
3545 | setOpt(c, "creator_class", new WeakReference(mc())); |
3546 | } |
3547 | } |
3548 | static Class mc() { |
3549 | return getMainClass(); |
3550 | } |
3551 | // extended over Class.isInstance() to handle primitive types |
3552 | static boolean isInstanceX(Class type, Object arg) { |
3553 | if (type == boolean.class) return arg instanceof Boolean; |
3554 | if (type == int.class) return arg instanceof Integer; |
3555 | if (type == long.class) return arg instanceof Long; |
3556 | if (type == float.class) return arg instanceof Float; |
3557 | if (type == short.class) return arg instanceof Short; |
3558 | if (type == char.class) return arg instanceof Character; |
3559 | if (type == byte.class) return arg instanceof Byte; |
3560 | if (type == double.class) return arg instanceof Double; |
3561 | return type.isInstance(arg); |
3562 | } |
3563 | static int minutes() { |
3564 | return Calendar.getInstance().get(Calendar.MINUTE); |
3565 | } |
3566 | static <A> List<A> concatLists(List<A>... lists) { |
3567 | new List<A> l; |
3568 | for (List<A> list : lists) |
3569 | if (list != null) |
3570 | l.addAll(list); |
3571 | return l; |
3572 | } |
3573 | |
3574 | static <A> List<A> concatLists(Collection<List<A>> lists) { |
3575 | new List<A> l; |
3576 | for (List<A> list : lists) |
3577 | if (list != null) |
3578 | l.addAll(list); |
3579 | return l; |
3580 | } |
3581 | |
3582 | static Object nuObject(String className, Object... args) { try { |
3583 | |
3584 | return nuObject(Class.forName(className), args); |
3585 | |
3586 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
3587 | |
3588 | static Object nuObject(Object realm, String className, Object... args) { |
3589 | return nuObject(_getClass(realm, className), args); |
3590 | } |
3591 | |
3592 | static <A> A nuObject(Class<A> c, Object... args) { try { |
3593 | |
3594 | Constructor m = nuObject_findConstructor(c, args); |
3595 | m.setAccessible(true); |
3596 | return (A) m.newInstance(args); |
3597 | |
3598 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
3599 | |
3600 | static Constructor nuObject_findConstructor(Class c, Object... args) { |
3601 | for (Constructor m : c.getDeclaredConstructors()) { |
3602 | if (!nuObject_checkArgs(m.getParameterTypes(), args, false)) |
3603 | continue; |
3604 | return m; |
3605 | } |
3606 | throw new RuntimeException("Constructor with " + args.length + " matching parameter(s) not found in " + c.getName()); |
3607 | } |
3608 | |
3609 | static boolean nuObject_checkArgs(Class[] types, Object[] args, boolean debug) { |
3610 | if (types.length != args.length) { |
3611 | if (debug) |
3612 | System.out.println("Bad parameter length: " + args.length + " vs " + types.length); |
3613 | return false; |
3614 | } |
3615 | for (int i = 0; i < types.length; i++) |
3616 | if (!(args[i] == null || isInstanceX(types[i], args[i]))) { |
3617 | if (debug) |
3618 | System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]); |
3619 | return false; |
3620 | } |
3621 | return true; |
3622 | } |
3623 | static String getClassName(Object o) { |
3624 | return o == null ? "null" : o.getClass().getName(); |
3625 | } |
3626 | static boolean confirmOKCancel(final Component owner, final String msg) { |
3627 | return isTrue(swingAndWait(new Object { Object get() { return |
3628 | JOptionPane.showConfirmDialog(owner, |
3629 | msg, "JavaX", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION |
3630 | ; } |
3631 | public String toString() { return "JOptionPane.showConfirmDialog(owner,\r\n msg, \"JavaX\", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION"; }})); |
3632 | } |
3633 | static AbstractAction abstractAction(String name, final Runnable r) { |
3634 | return new AbstractAction(name) { |
3635 | public void actionPerformed(ActionEvent evt) { |
3636 | r.run(); |
3637 | } |
3638 | }; |
3639 | } |
3640 | static boolean inRange(int x, int n) { |
3641 | return x >= 0 && x < n; |
3642 | } |
3643 | static double parseDouble(String s) { |
3644 | return Double.parseDouble(s); |
3645 | } |
3646 | public static long parseSnippetID(String snippetID) { |
3647 | long id = Long.parseLong(shortenSnippetID(snippetID)); |
3648 | if (id == 0) fail("0 is not a snippet ID"); |
3649 | return id; |
3650 | } |
3651 | static <A, B> Map<A, B> cloneTreeMap(Map<A, B> map) { |
3652 | // assume mutex is equal to collection, which will be true unless you explicitly pass a mutex to synchronizedList() which no one ever does. |
3653 | if (map == null) return new TreeMap; |
3654 | else synchronized(map) { |
3655 | return new TreeMap(map); |
3656 | } |
3657 | } |
3658 | static ImageIcon imageIcon(String imageID) { try { |
3659 | |
3660 | return new ImageIcon(loadLibrary(imageID).toURI().toURL()); |
3661 | |
3662 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
3663 | static int toInt(Object o) { |
3664 | if (o == null) return 0; |
3665 | if (o instanceof Number) |
3666 | return ((Number) o).intValue(); |
3667 | if (o instanceof String) |
3668 | return parseInt((String) o); |
3669 | throw fail("woot not int: " + getClassName(o)); |
3670 | } |
3671 | public static String loadTextFile(String fileName) { |
3672 | try { |
3673 | return loadTextFile(fileName, null); |
3674 | } catch (IOException e) { |
3675 | throw new RuntimeException(e); |
3676 | } |
3677 | } |
3678 | |
3679 | public static String loadTextFile(String fileName, String defaultContents) throws IOException { |
3680 | if (!new File(fileName).exists()) |
3681 | return defaultContents; |
3682 | |
3683 | FileInputStream fileInputStream = new FileInputStream(fileName); |
3684 | InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8"); |
3685 | return loadTextFile(inputStreamReader); |
3686 | } |
3687 | |
3688 | public static String loadTextFile(File fileName) { |
3689 | try { |
3690 | return loadTextFile(fileName, null); |
3691 | } catch (IOException e) { |
3692 | throw new RuntimeException(e); |
3693 | } |
3694 | } |
3695 | |
3696 | public static String loadTextFile(File fileName, String defaultContents) throws IOException { |
3697 | try { |
3698 | return loadTextFile(fileName.getPath(), defaultContents); |
3699 | } catch (IOException e) { |
3700 | throw new RuntimeException(e); |
3701 | } |
3702 | } |
3703 | |
3704 | public static String loadTextFile(Reader reader) throws IOException { |
3705 | StringBuilder builder = new StringBuilder(); |
3706 | try { |
3707 | char[] buffer = new char[1024]; |
3708 | int n; |
3709 | while (-1 != (n = reader.read(buffer))) |
3710 | builder.append(buffer, 0, n); |
3711 | |
3712 | } finally { |
3713 | reader.close(); |
3714 | } |
3715 | return builder.toString(); |
3716 | } |
3717 | // mainJava is a complete program, but without the !752/!759 at the top |
3718 | // returns link to main class |
3719 | static Class veryQuickJava(String mainJava) { |
3720 | return veryQuickJava2(mainJava); // It's just better. |
3721 | } |
3722 | static boolean startsWith(String a, String b) { |
3723 | return a != null && a.startsWith(b); |
3724 | } |
3725 | |
3726 | static boolean startsWith(List a, List b) { |
3727 | if (a == null || l(b) > l(a)) return false; |
3728 | for (int i = 0; i < l(b); i++) |
3729 | if (neq(a.get(i), b.get(i))) |
3730 | return false; |
3731 | return true; |
3732 | } |
3733 | |
3734 | |
3735 | static void onTitleRightClick(final JFrame frame, final Runnable r) { |
3736 | swingLater(new Runnable() { public void run() { try { |
3737 | if (!isSubstanceLAF()) |
3738 | print("Can't add title right click!"); |
3739 | else { |
3740 | JComponent titleBar = getTitlePaneComponent(frame); |
3741 | titleBar.addMouseListener(new MouseAdapter() { |
3742 | public void mousePressed(MouseEvent evt) { |
3743 | if (evt.getButton() != MouseEvent.BUTTON1) |
3744 | r.run(); |
3745 | } |
3746 | }); |
3747 | } |
3748 | } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}); |
3749 | } |
3750 | static Font typeWriterFont() { |
3751 | return new Font("Courier", Font.PLAIN, 14); |
3752 | } |
3753 | static String shortenSnippetID(String snippetID) { |
3754 | if (snippetID.startsWith("#")) |
3755 | snippetID = snippetID.substring(1); |
3756 | String httpBlaBla = "http://tinybrain.de/"; |
3757 | if (snippetID.startsWith(httpBlaBla)) |
3758 | snippetID = snippetID.substring(httpBlaBla.length()); |
3759 | return "" + parseLong(snippetID); |
3760 | } |
3761 | static String quickSubstring(String s, int i, int j) { |
3762 | if (i == j) return ""; |
3763 | return s.substring(i, j); |
3764 | } |
3765 | static void showConsole() { |
3766 | JFrame frame = consoleFrame(); |
3767 | if (frame != null) |
3768 | frame.setVisible(true); |
3769 | } |
3770 | static Object mainBot; |
3771 | |
3772 | static Object getMainBot() { |
3773 | return mainBot; |
3774 | } |
3775 | static Class getMainClass() { try { |
3776 | |
3777 | return Class.forName("main"); |
3778 | |
3779 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
3780 | |
3781 | static Class getMainClass(Object o) { try { |
3782 | |
3783 | return (o instanceof Class ? (Class) o : o.getClass()).getClassLoader().loadClass("main"); |
3784 | |
3785 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
3786 | static String[] toStringArray(List<String> list) { |
3787 | return list.toArray(new String[list.size()]); |
3788 | } |
3789 | |
3790 | static String[] toStringArray(Object o) { |
3791 | if (o instanceof String[]) |
3792 | return (String[]) o; |
3793 | else if (o instanceof List) |
3794 | return toStringArray((List<String>) o); |
3795 | else |
3796 | throw fail("Not a list or array: " + structure(o)); |
3797 | } |
3798 | |
3799 | static boolean isAnonymousClassName(String s) { |
3800 | for (int i = 0; i < l(s)-1; i++) |
3801 | if (s.charAt(i) == '$' && Character.isDigit(s.charAt(i+1))) return true; return false; |
3802 | } |
3803 | // match2 matches multiple "*" (matches a single token) wildcards and zero or one "..." wildcards (matches multiple tokens) |
3804 | |
3805 | static String[] match2(List<String> pat, List<String> tok) { |
3806 | // standard case (no ...) |
3807 | int i = pat.indexOf("..."); |
3808 | if (i < 0) return match2_match(pat, tok); |
3809 | |
3810 | pat = new ArrayList<String>(pat); // We're modifying it, so copy first |
3811 | pat.set(i, "*"); |
3812 | while (pat.size() < tok.size()) { |
3813 | pat.add(i, "*"); |
3814 | pat.add(i+1, ""); // doesn't matter |
3815 | } |
3816 | |
3817 | return match2_match(pat, tok); |
3818 | } |
3819 | |
3820 | static String[] match2_match(List<String> pat, List<String> tok) { |
3821 | List<String> result = new ArrayList<String>(); |
3822 | if (pat.size() != tok.size()) { |
3823 | /*if (debug) |
3824 | print("Size mismatch: " + structure(pat) + " vs " + structure(tok));*/ |
3825 | return null; |
3826 | } |
3827 | for (int i = 1; i < pat.size(); i += 2) { |
3828 | String p = pat.get(i), t = tok.get(i); |
3829 | /*if (debug) |
3830 | print("Checking " + p + " against " + t);*/ |
3831 | if (eq(p, "*")) |
3832 | result.add(t); |
3833 | else if (!equalsIgnoreCase(unquote(p), unquote(t))) // bold change - match quoted and unquoted now |
3834 | return null; |
3835 | } |
3836 | return result.toArray(new String[result.size()]); |
3837 | } |
3838 | |
3839 | static String format3(String pat, Object... args) { |
3840 | if (args.length == 0) return pat; |
3841 | |
3842 | List<String> tok = javaTokPlusPeriod(pat); |
3843 | int argidx = 0; |
3844 | for (int i = 1; i < tok.size(); i += 2) |
3845 | if (tok.get(i).equals("*")) |
3846 | tok.set(i, format3_formatArg(argidx < args.length ? args[argidx++] : "null")); |
3847 | return join(tok); |
3848 | } |
3849 | |
3850 | static String format3_formatArg(Object arg) { |
3851 | if (arg == null) return "null"; |
3852 | if (arg instanceof String) { |
3853 | String s = (String) arg; |
3854 | return isIdentifier(s) || isNonNegativeInteger(s) ? s : quote(s); |
3855 | } |
3856 | if (arg instanceof Integer || arg instanceof Long) return String.valueOf(arg); |
3857 | return quote(structure(arg)); |
3858 | } |
3859 | |
3860 | |
3861 | static void callMain(Object c, String... args) { |
3862 | callOpt(c, "main", new Object[] {args}); |
3863 | } |
3864 | static Class<?> _getClass(String name) { |
3865 | try { |
3866 | return Class.forName(name); |
3867 | } catch (ClassNotFoundException e) { |
3868 | return null; |
3869 | } |
3870 | } |
3871 | |
3872 | static Class _getClass(Object o) { |
3873 | return o instanceof Class ? (Class) o : o.getClass(); |
3874 | } |
3875 | |
3876 | static Class _getClass(Object realm, String name) { try { |
3877 | |
3878 | return getClass(realm).getClassLoader().loadClass(classNameToVM(name)); |
3879 | |
3880 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
3881 | static void dataToTable_dynSet(List<String> l, int i, String s) { |
3882 | while (i >= l.size()) l.add(""); |
3883 | l.set(i, s); |
3884 | } |
3885 | |
3886 | static List<String> dataToTable_makeRow(Object x, List<String> cols) { |
3887 | if (instanceOf(x, "DynamicObject")) |
3888 | x = get_raw(x, "fieldValues"); |
3889 | |
3890 | if (x instanceof Map) { |
3891 | Map m = (Map) ( x); |
3892 | new List<String> row; |
3893 | for (Object _field : m.keySet()) { |
3894 | String field = (String) ( _field); |
3895 | Object value = m.get(field); |
3896 | int col = cols.indexOf(field); |
3897 | if (col < 0) { |
3898 | cols.add(field); |
3899 | col = cols.size()-1; |
3900 | } |
3901 | dataToTable_dynSet(row, col, structureOrText(value)); |
3902 | } |
3903 | return row; |
3904 | } |
3905 | |
3906 | return litlist(structureOrText(x)); |
3907 | } |
3908 | static String getProgramTitle() { |
3909 | return getProgramName(); |
3910 | } |
3911 | static void runMain(Object c, String... args) { |
3912 | callMain(c, args); |
3913 | } |
3914 | static String padLeft(String s, char c, int n) { |
3915 | return rep(c, n-l(s)) + s; |
3916 | } |
3917 | static boolean veryQuickJava_silent = true; |
3918 | |
3919 | // mainJava is a complete program, but without the !752/!759 at the top |
3920 | // returns link to main class |
3921 | static Class veryQuickJava2(String mainJava) { |
3922 | transpileRaw_silent = veryQuickJava_silent; |
3923 | String src = transpileRaw(mainJava); // transpiled, with lib references |
3924 | new List<String> libs; |
3925 | src = findTranslators2(src, libs); |
3926 | //print("Libs found: " + struct(libs)); |
3927 | return hotwireCore(concatLists(ll(javaCompile(src, join(" ", libs))), loadLibraries(libs))); |
3928 | } |
3929 | static void fillTableWithStrings(final JTable table, List<List<String>> rows, List<String> colNames) { |
3930 | fillTableWithStrings(table, rows, toStringArray(colNames)); |
3931 | } |
3932 | |
3933 | // thread-safe |
3934 | static void fillTableWithStrings(final JTable table, List<List<String>> rows, String... colNames) { |
3935 | final DefaultTableModel model = fillTableWithStrings_makeModel(rows, colNames); |
3936 | |
3937 | swingNowOrLater(r { |
3938 | setTableModel(table, model); |
3939 | }); |
3940 | } |
3941 | |
3942 | static DefaultTableModel fillTableWithStrings_makeModel(List<List<String>> rows, String... colNames) { |
3943 | Object[][] data = new Object[rows.size()][]; |
3944 | int w = 0; |
3945 | for (int i = 0; i < rows.size(); i++) { |
3946 | List<String> l = rows.get(i); |
3947 | Object[] r = new Object[l.size()]; |
3948 | for (int j = 0; j < l.size(); j++) |
3949 | r[j] = l.get(j); |
3950 | data[i] = r; |
3951 | w = Math.max(w, l.size()); |
3952 | } |
3953 | Object[] columnNames = new Object[w]; |
3954 | for (int i = 0; i < w; i++) |
3955 | columnNames[i] = i < l(colNames) ? colNames[i] : "?"; |
3956 | return new DefaultTableModel(data, columnNames); |
3957 | } |
3958 | |
3959 | static void classicNohupJavax(String javaxargs) { |
3960 | classicNohupJavax(javaxargs, ""); |
3961 | } |
3962 | |
3963 | static void classicNohupJavax(String javaxargs, String vmArgs) { try { |
3964 | |
3965 | int x = latestInstalledJavaX(); |
3966 | File xfile = new File(userHome(), ".javax/x" + Math.max(x, 30) + ".jar"); |
3967 | if (!xfile.isFile()) { |
3968 | String url = "http://tinybrain.de/x30.jar"; |
3969 | byte[] data = loadBinaryPage(url); |
3970 | if (data.length < 1000000) |
3971 | fail("Could not load " + url); |
3972 | saveBinaryFile(xfile.getPath(), data); |
3973 | } |
3974 | String jarPath = xfile.getPath(); |
3975 | if (javaxargs.startsWith("#")) javaxargs = javaxargs.substring(1); |
3976 | nohup("java " + vmArgs + " -jar " + (isWindows() ? winQuote(jarPath) : bashQuote(jarPath)) + " " + javaxargs); |
3977 | |
3978 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
3979 | static Object getBot(String botID) { |
3980 | return callOpt(getMainBot(), "getBot", botID); |
3981 | } |
3982 | |
3983 | static boolean isSubstanceLAF() { |
3984 | return substanceLookAndFeelEnabled(); |
3985 | } |
3986 | static boolean substanceLookAndFeelEnabled() { |
3987 | return startsWith(getLookAndFeel(), "org.pushingpixels."); |
3988 | } |
3989 | static JMenuItem jmenuItem(String text, final Runnable r) { |
3990 | JMenuItem mi = new JMenuItem(text); |
3991 | mi.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent _evt) { r.run(); }}); |
3992 | return mi; |
3993 | } |
3994 | static JTable showTable(Object data) { |
3995 | return dataToTable(data); |
3996 | } |
3997 | |
3998 | static JTable showTable(Object data, String title) { |
3999 | return dataToTable(data, title); |
4000 | } |
4001 | |
4002 | static JTable showTable() { |
4003 | return showTable(new ArrayList<List<String>>(), new ArrayList<String>()); |
4004 | } |
4005 | |
4006 | static JTable showTable(String title) { |
4007 | return showTable(new ArrayList<List<String>>(), new ArrayList<String>(), title); |
4008 | } |
4009 | |
4010 | static JTable showTable(List<List<String>> rows, List<String> cols) { |
4011 | return showTable(rows, cols, autoFrameTitle()); |
4012 | } |
4013 | |
4014 | static JTable showTable(List<List<String>> rows, List<String> cols, String title) { |
4015 | JFrame frame = new JFrame(title); |
4016 | frame.setBounds(10, 10, 500, 400); |
4017 | centerFrame(frame); |
4018 | |
4019 | JTable tbl = tableWithToolTips(); |
4020 | fillTableWithStrings(tbl, rows, cols); |
4021 | |
4022 | frame.getContentPane().add(new JScrollPane(tbl)); |
4023 | frame.setVisible(true); |
4024 | |
4025 | return tbl; |
4026 | } |
4027 | static List<String> parse3(String s) { |
4028 | return dropPunctuation(javaTokPlusPeriod(s)); |
4029 | } |
4030 | static new ThreadLocal<String> loadPage_charset; |
4031 | static boolean loadPage_allowGzip = true, loadPage_debug; |
4032 | static boolean loadPage_anonymous; // don't send computer ID |
4033 | static int loadPage_verboseness = 100000; |
4034 | |
4035 | public static String loadPageSilently(String url) { |
4036 | try { |
4037 | return loadPageSilently(new URL(loadPage_preprocess(url))); |
4038 | } catch (IOException e) { throw new RuntimeException(e); } |
4039 | } |
4040 | |
4041 | public static String loadPageSilently(URL url) { |
4042 | try { |
4043 | IOException e = null; |
4044 | for (int tries = 0; tries < 60; tries++) |
4045 | try { |
4046 | URLConnection con = url.openConnection(); |
4047 | return loadPage(con, url); |
4048 | } catch (IOException _e) { |
4049 | e = _e; |
4050 | print("Retrying because of: " + e); |
4051 | sleepSeconds(1); |
4052 | } |
4053 | throw e; |
4054 | } catch (IOException e) { throw new RuntimeException(e); } |
4055 | } |
4056 | |
4057 | static String loadPage_preprocess(String url) { |
4058 | if (url.startsWith("tb/")) |
4059 | url = "tinybrain.de:8080/" + url; |
4060 | if (url.indexOf("://") < 0) |
4061 | url = "http://" + url; |
4062 | return url; |
4063 | } |
4064 | |
4065 | public static String loadPage(String url) { |
4066 | try { |
4067 | return loadPage(new URL(loadPage_preprocess(url))); |
4068 | } catch (IOException e) { throw new RuntimeException(e); } |
4069 | } |
4070 | |
4071 | public static String loadPage(URL url) { |
4072 | print("Loading: " + url.toExternalForm()); |
4073 | return loadPageSilently(url); |
4074 | } |
4075 | |
4076 | public static String loadPage(URLConnection con, URL url) throws IOException { |
4077 | try { |
4078 | if (!loadPage_anonymous) { |
4079 | String computerID = getComputerID(); |
4080 | if (computerID != null) |
4081 | con.setRequestProperty("X-ComputerID", computerID); |
4082 | } |
4083 | if (loadPage_allowGzip) |
4084 | con.setRequestProperty("Accept-Encoding", "gzip"); |
4085 | } catch (Throwable e) {} // fails if within doPost |
4086 | String contentType = con.getContentType(); |
4087 | if (contentType == null) |
4088 | throw new IOException("Page could not be read: " + url); |
4089 | //print("Content-Type: " + contentType); |
4090 | String charset = loadPage_charset == null ? null : loadPage_charset.get(); |
4091 | if (charset == null) charset = loadPage_guessCharset(contentType); |
4092 | |
4093 | InputStream in = con.getInputStream(); |
4094 | if ("gzip".equals(con.getContentEncoding())) { |
4095 | if (loadPage_debug) |
4096 | print("loadPage: Using gzip."); |
4097 | in = new GZIPInputStream(in); |
4098 | } |
4099 | Reader r = new InputStreamReader(in, charset); |
4100 | |
4101 | StringBuilder buf = new StringBuilder(); |
4102 | int n = 0; |
4103 | while (true) { |
4104 | int ch = r.read(); |
4105 | if (ch < 0) |
4106 | break; |
4107 | buf.append((char) ch); |
4108 | ++n; |
4109 | if ((n % loadPage_verboseness) == 0) print(" " + n + " chars read"); |
4110 | } |
4111 | return buf.toString(); |
4112 | } |
4113 | |
4114 | static String loadPage_guessCharset(String contentType) { |
4115 | Pattern p = Pattern.compile("text/[a-z]+;\\s+charset=([^\\s]+)\\s*"); |
4116 | Matcher m = p.matcher(contentType); |
4117 | /* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */ |
4118 | return m.matches() ? m.group(1) : "ISO-8859-1"; |
4119 | } |
4120 | |
4121 | static void assertTrue(Object o) { |
4122 | assertEquals(true, o); |
4123 | } |
4124 | |
4125 | static boolean assertTrue(String msg, boolean b) { |
4126 | if (!b) |
4127 | fail(msg); |
4128 | return b; |
4129 | } |
4130 | |
4131 | static boolean assertTrue(boolean b) { |
4132 | if (!b) |
4133 | fail("oops"); |
4134 | return b; |
4135 | } |
4136 | static String programTitle() { |
4137 | return getProgramName(); |
4138 | } |
4139 | static Class<?> getClass(String name) { |
4140 | try { |
4141 | return Class.forName(name); |
4142 | } catch (ClassNotFoundException e) { |
4143 | return null; |
4144 | } |
4145 | } |
4146 | |
4147 | static Class getClass(Object o) { |
4148 | return o instanceof Class ? (Class) o : o.getClass(); |
4149 | } |
4150 | |
4151 | static Class getClass(Object realm, String name) { try { |
4152 | |
4153 | return getClass(realm).getClassLoader().loadClass(classNameToVM(name)); |
4154 | |
4155 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
4156 | static File loadLibrary(String snippetID) { |
4157 | return loadBinarySnippet(snippetID); |
4158 | } |
4159 | static boolean eqOneOf(Object o, Object... l) { |
4160 | for (Object x : l) if (eq(o, x)) return true; return false; |
4161 | } |
4162 | static boolean booleanValue(Object o) { |
4163 | return eq(true, o); |
4164 | } |
4165 | static File javaxDataDir_dir; // can be set to work on different base dir |
4166 | |
4167 | static File javaxDataDir() { |
4168 | return javaxDataDir_dir != null ? javaxDataDir_dir : new File(userHome(), "JavaX-Data"); |
4169 | } |
4170 | static Object[] toObjectArray(List list) { |
4171 | return list.toArray(new Object[list.size()]); |
4172 | } |
4173 | static String dropSuffix(String suffix, String s) { |
4174 | return s.endsWith(suffix) ? s.substring(0, l(s)-l(suffix)) : s; |
4175 | } |
4176 | static void smartSet(Field f, Object o, Object value) throws Exception { |
4177 | f.setAccessible(true); |
4178 | |
4179 | // take care of common case (long to int) |
4180 | if (f.getType() == int.class && value instanceof Long) |
4181 | value = ((Long) value).intValue(); |
4182 | |
4183 | f.set(o, value); |
4184 | } |
4185 | static String sendToLocalBotOpt(String bot, String text) { |
4186 | if (bot == null) return null; |
4187 | DialogIO channel = findBot(bot); |
4188 | if (channel == null) { |
4189 | print(quote(bot) + " not found, skipping send: " + quote(text)); |
4190 | return null; |
4191 | } |
4192 | try { |
4193 | channel.readLine(); |
4194 | print(bot + "> " + text); |
4195 | channel.sendLine(text); |
4196 | String s = channel.readLine(); |
4197 | print(bot + "< " + s); |
4198 | return s; |
4199 | } catch (Throwable e) { |
4200 | e.printStackTrace(); |
4201 | return null; |
4202 | } finally { |
4203 | channel.close(); |
4204 | } |
4205 | } |
4206 | |
4207 | |
4208 | public static boolean isWindows() { |
4209 | return System.getProperty("os.name").contains("Windows"); |
4210 | } |
4211 | static boolean equalsIgnoreCase(String a, String b) { |
4212 | return a == null ? b == null : a.equalsIgnoreCase(b); |
4213 | } |
4214 | /** possibly improvable */ |
4215 | public static String bashQuote(String text) { |
4216 | if (text == null) return null; |
4217 | return "\"" + text |
4218 | .replace("\\", "\\\\") |
4219 | .replace("\"", "\\\"") |
4220 | .replace("\n", "\\n") |
4221 | .replace("\r", "\\r") + "\""; |
4222 | } |
4223 | |
4224 | static Object transpileRaw_trans; |
4225 | static Object transpileRaw_silent = true; |
4226 | |
4227 | static synchronized String transpileRaw(String mainJava) { |
4228 | if (transpileRaw_trans == null) |
4229 | // Note: we sync the whole main class on this |
4230 | transpileRaw_trans = hotwire("#759"); |
4231 | |
4232 | setOpt(transpileRaw_trans, "print_silent", transpileRaw_silent); |
4233 | |
4234 | set(transpileRaw_trans, "mainJava", mainJava); |
4235 | callMain(transpileRaw_trans); |
4236 | return (String) get(transpileRaw_trans, "mainJava"); |
4237 | } |
4238 | static File loadBinarySnippet(String snippetID) { try { |
4239 | |
4240 | long id = parseSnippetID(snippetID); |
4241 | File f = DiskSnippetCache_getLibrary(id); |
4242 | if (f == null) { |
4243 | byte[] data = loadDataSnippetImpl(snippetID); |
4244 | DiskSnippetCache_putLibrary(id, data); |
4245 | f = DiskSnippetCache_getLibrary(id); |
4246 | } |
4247 | return f; |
4248 | |
4249 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
4250 | static JComponent getTitlePaneComponent(Window window) { |
4251 | if (!substanceLookAndFeelEnabled()) return null; |
4252 | |
4253 | JRootPane rootPane = null; |
4254 | if (window instanceof JFrame) { |
4255 | JFrame f = (JFrame) window; |
4256 | rootPane = f.getRootPane(); |
4257 | } |
4258 | if (window instanceof JDialog) { |
4259 | JDialog d = (JDialog) window; |
4260 | rootPane = d.getRootPane(); |
4261 | } |
4262 | if (rootPane != null) { |
4263 | Object /*SubstanceRootPaneUI*/ ui = rootPane.getUI(); |
4264 | return (JComponent) call(ui, "getTitlePane"); |
4265 | } |
4266 | return null; |
4267 | } |
4268 | |
4269 | static void setTableModel(JTable table, TableModel model) { |
4270 | int i = table.getSelectedRow(); |
4271 | table.setModel(model); |
4272 | if (i >= 0 && i < model.getRowCount()) |
4273 | table.setRowSelectionInterval(i, i); |
4274 | } |
4275 | |
4276 | static String findTranslators2(String src, List<String> libsOut) { |
4277 | List<String> tok = javaTok(src); |
4278 | int i; |
4279 | while ((i = jfind(tok, "!<int>")) >= 0) { |
4280 | setAdd(libsOut, tok.get(i+2)); |
4281 | clearTokens(tok, i, i+3); |
4282 | } |
4283 | return join(tok); |
4284 | } |
4285 | static void centerFrame(JFrame frame) { |
4286 | frame.setLocationRelativeTo(null); // magic trick |
4287 | } |
4288 | static new Map<String, Integer> findBot_cache; |
4289 | static int findBot_timeout = 5000; |
4290 | |
4291 | static DialogIO findBot(String searchPattern) { |
4292 | // first split off sub-bot suffix |
4293 | String subBot = null; |
4294 | int i = searchPattern.indexOf('/'); |
4295 | if (i >= 0 && (isJavaIdentifier(searchPattern.substring(0, i)) || isInteger(searchPattern.substring(0, i)))) { |
4296 | subBot = searchPattern.substring(i+1); |
4297 | searchPattern = searchPattern.substring(0, i); |
4298 | if (!isInteger(searchPattern)) |
4299 | searchPattern = "Multi-Port at " + searchPattern + "."; |
4300 | } |
4301 | |
4302 | // assume it's a port if it's an integer |
4303 | if (isInteger(searchPattern)) |
4304 | return talkToSubBot(subBot, talkTo(parseInt(searchPattern))); |
4305 | |
4306 | if (eq(searchPattern, "remote")) |
4307 | return talkToSubBot(subBot, talkTo("second.tinybrain.de", 4999)); |
4308 | |
4309 | Integer port = findBot_cache.get(searchPattern); |
4310 | if (port != null) try { |
4311 | DialogIO io = talkTo("localhost", port); |
4312 | io.waitForLine(/*findBot_timeout*/); // TODO: implement |
4313 | String line = io.readLineNoBlock(); |
4314 | if (indexOfIgnoreCase(line, searchPattern) == 0) { |
4315 | call(io, "pushback", line); // put hello string back in |
4316 | return talkToSubBot(subBot, io); |
4317 | } |
4318 | } catch (Exception e) { |
4319 | e.printStackTrace(); |
4320 | } |
4321 | |
4322 | List<ProgramScan.Program> bots = quickBotScan(); |
4323 | |
4324 | // find top-level bots |
4325 | for (ProgramScan.Program p : bots) { |
4326 | if (indexOfIgnoreCase(p.helloString, searchPattern) == 0) { // strict matching - start of hello string only, but case-insensitive |
4327 | findBot_cache.put(searchPattern, p.port); |
4328 | return talkToSubBot(subBot, talkTo("localhost", p.port)); |
4329 | } |
4330 | } |
4331 | |
4332 | // find sub-bots |
4333 | for (ProgramScan.Program p : bots) { |
4334 | String botName = firstPartOfHelloString(p.helloString); |
4335 | boolean isVM = startsWithIgnoreCase(p.helloString, "This is a JavaX VM."); |
4336 | boolean shouldRecurse = startsWithIgnoreCase(botName, "Multi-Port") || isVM; |
4337 | |
4338 | if (shouldRecurse) try { |
4339 | Map<Number, String> subBots = (Map) unstructure(sendToLocalBot(p.port, "list bots")); |
4340 | for (Number vport : subBots.keySet()) { |
4341 | String name = subBots.get(vport); |
4342 | if (startsWithIgnoreCase(name, searchPattern)) |
4343 | return talkToSubBot(vport.longValue(), talkTo("localhost", p.port)); |
4344 | } |
4345 | } catch (Exception e) { e.printStackTrace(); } |
4346 | } |
4347 | |
4348 | return null; |
4349 | } |
4350 | /** possibly improvable */ |
4351 | public static String winQuote(String text) { |
4352 | if (text == null) return null; |
4353 | return "\"" + text |
4354 | .replace("\\", "\\\\") |
4355 | .replace("\"", "\\\"") |
4356 | .replace("\n", "\\n") |
4357 | .replace("\r", "\\r") + "\""; |
4358 | } |
4359 | |
4360 | static boolean instanceOf(Object o, String className) { |
4361 | if (o == null) return false; |
4362 | String c = o.getClass().getName(); |
4363 | return eq(c, className) || eq(c, "main$" + className); |
4364 | } |
4365 | static String rep(int n, char c) { |
4366 | return repeat(c, n); |
4367 | } |
4368 | |
4369 | static String rep(char c, int n) { |
4370 | return repeat(c, n); |
4371 | } |
4372 | |
4373 | static <A> List<A> rep(A a, int n) { |
4374 | return repeat(a, n); |
4375 | } |
4376 | |
4377 | static boolean isNonNegativeInteger(String s) { |
4378 | return s != null && Pattern.matches("\\d+", s); |
4379 | } |
4380 | static String classNameToVM(String name) { |
4381 | return name.replace(".", "$"); |
4382 | } |
4383 | // This is made for NL parsing. |
4384 | // It's javaTok extended with "..." token, "$n" and "#n" and |
4385 | // special quotes (which are converted to normal ones). |
4386 | |
4387 | static List<String> javaTokPlusPeriod(String s) { |
4388 | List<String> tok = new ArrayList<String>(); |
4389 | int l = s.length(); |
4390 | |
4391 | int i = 0; |
4392 | while (i < l) { |
4393 | int j = i; |
4394 | char c; String cc; |
4395 | |
4396 | // scan for whitespace |
4397 | while (j < l) { |
4398 | c = s.charAt(j); |
4399 | cc = s.substring(j, Math.min(j+2, l)); |
4400 | if (c == ' ' || c == '\t' || c == '\r' || c == '\n') |
4401 | ++j; |
4402 | else if (cc.equals("/*")) { |
4403 | do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/")); |
4404 | j = Math.min(j+2, l); |
4405 | } else if (cc.equals("//")) { |
4406 | do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); |
4407 | } else |
4408 | break; |
4409 | } |
4410 | |
4411 | tok.add(s.substring(i, j)); |
4412 | i = j; |
4413 | if (i >= l) break; |
4414 | c = s.charAt(i); |
4415 | cc = s.substring(i, Math.min(i+2, l)); |
4416 | |
4417 | // scan for non-whitespace |
4418 | if (c == '\u201C' || c == '\u201D') c = '"'; // normalize quotes |
4419 | if (c == '\'' || c == '"') { |
4420 | char opener = c; |
4421 | ++j; |
4422 | while (j < l) { |
4423 | char _c = s.charAt(j); |
4424 | if (_c == '\u201C' || _c == '\u201D') _c = '"'; // normalize quotes |
4425 | if (_c == opener) { |
4426 | ++j; |
4427 | break; |
4428 | } else if (s.charAt(j) == '\\' && j+1 < l) |
4429 | j += 2; |
4430 | else |
4431 | ++j; |
4432 | } |
4433 | if (j-1 >= i+1) { |
4434 | tok.add(opener + s.substring(i+1, j-1) + opener); |
4435 | i = j; |
4436 | continue; |
4437 | } |
4438 | } else if (Character.isJavaIdentifierStart(c)) |
4439 | do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || s.charAt(j) == '\'')); // for things like "this one's" |
4440 | else if (Character.isDigit(c)) |
4441 | do ++j; while (j < l && Character.isDigit(s.charAt(j))); |
4442 | else if (cc.equals("[[")) { |
4443 | do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]")); |
4444 | j = Math.min(j+2, l); |
4445 | } else if (cc.equals("[=") && i+2 < l && s.charAt(i+2) == '[') { |
4446 | do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]")); |
4447 | j = Math.min(j+3, l); |
4448 | } else if (s.substring(j, Math.min(j+3, l)).equals("...")) |
4449 | j += 3; |
4450 | else if (c == '$' || c == '#') |
4451 | do ++j; while (j < l && Character.isDigit(s.charAt(j))); |
4452 | else |
4453 | ++j; |
4454 | |
4455 | tok.add(s.substring(i, j)); |
4456 | i = j; |
4457 | } |
4458 | |
4459 | if ((tok.size() % 2) == 0) tok.add(""); |
4460 | return tok; |
4461 | } |
4462 | |
4463 | /** writes safely (to temp file, then rename) */ |
4464 | public static void saveBinaryFile(String fileName, byte[] contents) throws IOException { |
4465 | File file = new File(fileName); |
4466 | File parentFile = file.getParentFile(); |
4467 | if (parentFile != null) |
4468 | parentFile.mkdirs(); |
4469 | String tempFileName = fileName + "_temp"; |
4470 | FileOutputStream fileOutputStream = new FileOutputStream(tempFileName); |
4471 | fileOutputStream.write(contents); |
4472 | fileOutputStream.close(); |
4473 | if (file.exists() && !file.delete()) |
4474 | throw new IOException("Can't delete " + fileName); |
4475 | |
4476 | if (!new File(tempFileName).renameTo(file)) |
4477 | throw new IOException("Can't rename " + tempFileName + " to " + fileName); |
4478 | } |
4479 | |
4480 | static void saveBinaryFile(File fileName, byte[] contents) { |
4481 | try { |
4482 | saveBinaryFile(fileName.getPath(), contents); |
4483 | } catch (IOException e) { |
4484 | throw new RuntimeException(e); |
4485 | } |
4486 | } |
4487 | static List<File> loadLibraries(List<String> snippetIDs) { |
4488 | return map("loadLibrary", snippetIDs); |
4489 | } |
4490 | static JFrame consoleFrame() { |
4491 | return (JFrame) getOpt(get(getJavaX(), "console"), "frame"); |
4492 | } |
4493 | static Class hotwireCore(List urlsOrFiles) { |
4494 | List<URL> urls = map("toURL", urlsOrFiles); |
4495 | return hotwireCore((URL[]) asArray(URL.class, urls)); |
4496 | } |
4497 | |
4498 | static Class hotwireCore(URL... urls) { try { |
4499 | |
4500 | // make class loader |
4501 | URLClassLoader classLoader = new URLClassLoader(urls); |
4502 | |
4503 | // load & return main class |
4504 | Class<?> theClass = classLoader.loadClass("main"); |
4505 | |
4506 | if (!_inCore()) |
4507 | hotwire_copyOver(theClass); |
4508 | |
4509 | return theClass; |
4510 | |
4511 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
4512 | static TableWithTooltips tableWithToolTips() { |
4513 | return tableWithTooltips(); |
4514 | } |
4515 | |
4516 | static String getComputerID() { try { |
4517 | |
4518 | return computerID(); |
4519 | |
4520 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
4521 | static String _userHome; |
4522 | static String userHome() { |
4523 | if (_userHome == null) { |
4524 | if (isAndroid()) |
4525 | _userHome = "/storage/sdcard0/"; |
4526 | else |
4527 | _userHome = System.getProperty("user.home"); |
4528 | //System.out.println("userHome: " + _userHome); |
4529 | } |
4530 | return _userHome; |
4531 | } |
4532 | |
4533 | static File userHome(String path) { |
4534 | return new File(userDir(), path); |
4535 | } |
4536 | static <A> A assertEquals(Object x, A y) { |
4537 | return assertEquals(null, x, y); |
4538 | } |
4539 | |
4540 | static <A> A assertEquals(String msg, Object x, A y) { |
4541 | if (!(x == null ? y == null : x.equals(y))) |
4542 | fail((msg != null ? msg + ": " : "") + structure(x) + " != " + structure(y)); |
4543 | return y; |
4544 | } |
4545 | static boolean isIdentifier(String s) { |
4546 | return isJavaIdentifier(s); |
4547 | } |
4548 | static String getLookAndFeel() { |
4549 | return getClassName(UIManager.getLookAndFeel()); |
4550 | } |
4551 | static void sleepSeconds(double s) { |
4552 | if (s > 0) sleep(round(s*1000)); |
4553 | } |
4554 | static int latestInstalledJavaX() { |
4555 | File[] files = new File(userHome(), ".javax").listFiles(); |
4556 | int v = 0; |
4557 | if (files != null) for (File f : files) { |
4558 | Matcher m = Pattern.compile("x(\\d\\d\\d?)\\.jar").matcher(f.getName()); |
4559 | if (m.matches()) |
4560 | v = Math.max(v, Integer.parseInt(m.group(1))); |
4561 | } |
4562 | return v; |
4563 | } |
4564 | public static File nohup(String cmd) throws IOException { |
4565 | File outFile = File.createTempFile("nohup_" + nohup_sanitize(cmd), ".out"); |
4566 | nohup(cmd, outFile, false); |
4567 | return outFile; |
4568 | } |
4569 | |
4570 | static String nohup_sanitize(String s) { |
4571 | return s.replaceAll("[^a-zA-Z0-9\\-_]", ""); |
4572 | } |
4573 | |
4574 | /** outFile takes stdout and stderr. */ |
4575 | public static void nohup(String cmd, File outFile, boolean append) throws IOException { |
4576 | String command = nohup_makeNohupCommand(cmd, outFile, append); |
4577 | |
4578 | File scriptFile = File.createTempFile("_realnohup", isWindows() ? ".bat" : ""); |
4579 | System.out.println("[Nohup] " + command); |
4580 | try { |
4581 | //System.out.println("[RealNohup] Script file: " + scriptFile.getPath()); |
4582 | saveTextFile(scriptFile.getPath(), command); |
4583 | String[] command2; |
4584 | if (isWindows()) |
4585 | command2 = new String[] {"cmd", "/c", "start", "/b", scriptFile.getPath() }; |
4586 | else |
4587 | command2 = new String[] {"/bin/bash", scriptFile.getPath() }; |
4588 | |
4589 | Process process = Runtime.getRuntime().exec(command2); |
4590 | try { |
4591 | process.waitFor(); |
4592 | } catch (InterruptedException e) { |
4593 | throw new RuntimeException(e); |
4594 | } |
4595 | int value = process.exitValue(); |
4596 | //System.out.println("exit value: " + value); |
4597 | } finally { |
4598 | if (!isWindows()) |
4599 | scriptFile.delete(); |
4600 | } |
4601 | } |
4602 | |
4603 | public static String nohup_makeNohupCommand(String cmd, File outFile, boolean append) { |
4604 | mkdirsForFile(outFile); |
4605 | |
4606 | String command; |
4607 | if (isWindows()) |
4608 | command = cmd + (append ? " >>" : " >") + winQuote(outFile.getPath()) + " 2>&1"; |
4609 | else |
4610 | command = "nohup " + cmd + (append ? " >>" : " >") + bashQuote(outFile.getPath()) + " 2>&1 &"; |
4611 | return command; |
4612 | } |
4613 | |
4614 | static List<String> dropPunctuation_keep = litlist("*", "<", ">"); |
4615 | |
4616 | static List<String> dropPunctuation(List<String> tok) { |
4617 | tok = new ArrayList<String>(tok); |
4618 | for (int i = 1; i < tok.size(); i += 2) { |
4619 | String t = tok.get(i); |
4620 | if (t.length() == 1 && !Character.isLetter(t.charAt(0)) && !Character.isDigit(t.charAt(0)) && !dropPunctuation_keep.contains(t)) { |
4621 | tok.set(i-1, tok.get(i-1) + tok.get(i+1)); |
4622 | tok.remove(i); |
4623 | tok.remove(i); |
4624 | i -= 2; |
4625 | } |
4626 | } |
4627 | return tok; |
4628 | } |
4629 | |
4630 | static String dropPunctuation(String s) { |
4631 | return join(dropPunctuation(nlTok(s))); |
4632 | } |
4633 | static byte[] loadBinaryPage(String url) throws IOException { |
4634 | return loadBinaryPage(new URL(url).openConnection()); |
4635 | } |
4636 | |
4637 | public static byte[] loadBinaryPage(URLConnection con) throws IOException { |
4638 | //setHeaders(con); |
4639 | ByteArrayOutputStream buf = new ByteArrayOutputStream(); |
4640 | InputStream inputStream = con.getInputStream(); |
4641 | int n = 0; |
4642 | while (true) { |
4643 | int ch = inputStream.read(); |
4644 | if (ch < 0) |
4645 | break; |
4646 | buf.write(ch); |
4647 | if (++n % 100000 == 0) |
4648 | System.err.println(" " + n + " bytes loaded."); |
4649 | } |
4650 | inputStream.close(); |
4651 | return buf.toByteArray(); |
4652 | } |
4653 | |
4654 | static File javaCompile(String src) { |
4655 | return javaCompile(src, ""); |
4656 | } |
4657 | |
4658 | // returns path to classes dir |
4659 | static synchronized File javaCompile(String src, String dehlibs) { |
4660 | String javaTarget = null; // use default target |
4661 | |
4662 | //print("Compiling " + l(src) + " chars"); |
4663 | |
4664 | Class j = getJavaX(); |
4665 | if (javaTarget != null) |
4666 | setOpt(j, "javaTarget", javaTarget); |
4667 | //setOpt(j, "verbose", true); |
4668 | File srcDir = (File) ( call(j, "TempDirMaker_make")); |
4669 | String className = getNameOfPublicClass(javaTok(src)); |
4670 | String fileName = className + ".java"; |
4671 | File mainJava = new File(srcDir, fileName); |
4672 | //print("main java: " + mainJava.getAbsolutePath()); |
4673 | saveTextFile(mainJava, src); |
4674 | File classesDir = (File) call(j, "TempDirMaker_make"); |
4675 | new List<File> libraries; |
4676 | |
4677 | Matcher m = Pattern.compile("\\d+").matcher(dehlibs); |
4678 | while (m.find()) { |
4679 | String libID = m.group(); |
4680 | print("libID=" + quote(libID)); |
4681 | assertTrue(isSnippetID(libID)); |
4682 | libraries.add(loadLibrary(libID)); |
4683 | } |
4684 | |
4685 | try { |
4686 | // This seems to be empty in case of success with Eclipse compiler. |
4687 | String compilerOutput = (String) ( call(j, "compileJava", srcDir, libraries, classesDir)); |
4688 | if (nempty(compilerOutput)) print("Compiler said: " + quote(compilerOutput)); |
4689 | |
4690 | // sanity test |
4691 | if (!new File(classesDir, className + ".class").exists()) |
4692 | fail("No class generated (" + className + ")"); |
4693 | } catch (Exception e) { |
4694 | //e.printStackTrace(); |
4695 | fail("Compile Error\n" + getOpt(j, "javaCompilerOutput")); |
4696 | } |
4697 | |
4698 | return classesDir; |
4699 | } |
4700 | |
4701 | static String getProgramName_cache; |
4702 | |
4703 | static synchronized String getProgramName() { |
4704 | if (getProgramName_cache == null) |
4705 | getProgramName_cache = getSnippetTitle(getProgramID()); |
4706 | return getProgramName_cache; |
4707 | } |
4708 | |
4709 | |
4710 | static DialogIO talkToSubBot(final long vport, final DialogIO io) { |
4711 | return talkToSubBot(String.valueOf(vport), io); |
4712 | } |
4713 | |
4714 | static DialogIO talkToSubBot(final String subBot, final DialogIO io) { |
4715 | if (subBot == null) return io; |
4716 | |
4717 | return new DialogIO() { |
4718 | // delegate all but sendLine |
4719 | boolean isStillConnected() { return io.isStillConnected(); } |
4720 | String readLineImpl() { return io.readLineImpl(); } |
4721 | boolean isLocalConnection() { return io.isLocalConnection(); } |
4722 | Socket getSocket() { return io.getSocket(); } |
4723 | void close() { io.close(); } |
4724 | |
4725 | void sendLine(String line) { |
4726 | io.sendLine(format3("please forward to bot *: *", subBot, line)); |
4727 | } |
4728 | }; |
4729 | } |
4730 | static void sleep(long ms) { |
4731 | try { |
4732 | Thread.sleep(ms); |
4733 | } catch (Exception e) { throw new RuntimeException(e); } |
4734 | } |
4735 | |
4736 | static void sleep() { try { |
4737 | |
4738 | print("Sleeping."); |
4739 | synchronized(main.class) { main.class.wait(); } |
4740 | |
4741 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
4742 | |
4743 | // Data files are immutable, use centralized cache |
4744 | public static File DiskSnippetCache_getLibrary(long snippetID) throws IOException { |
4745 | File file = new File(getGlobalCache(), "data_" + snippetID + ".jar"); |
4746 | return file.exists() ? file : null; |
4747 | } |
4748 | |
4749 | public static void DiskSnippetCache_putLibrary(long snippetID, byte[] data) throws IOException { |
4750 | saveBinaryFile(new File(getGlobalCache(), "data_" + snippetID).getPath() + ".jar", data); |
4751 | } |
4752 | |
4753 | static byte[] loadDataSnippetImpl(String snippetID) throws IOException { |
4754 | byte[] data; |
4755 | try { |
4756 | URL url = new URL("http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_" |
4757 | + parseSnippetID(snippetID) + "&contentType=application/binary"); |
4758 | System.err.println("Loading library: " + url); |
4759 | try { |
4760 | data = loadBinaryPage(url.openConnection()); |
4761 | } catch (IOException e) { |
4762 | data = null; |
4763 | } |
4764 | |
4765 | if (data == null || data.length == 0) { |
4766 | url = new URL("http://data.tinybrain.de/blobs/" |
4767 | + parseSnippetID(snippetID)); |
4768 | System.err.println("Loading library: " + url); |
4769 | data = loadBinaryPage(url.openConnection()); |
4770 | } |
4771 | System.err.println("Bytes loaded: " + data.length); |
4772 | } catch (FileNotFoundException e) { |
4773 | throw new IOException("Binary snippet #" + snippetID + " not found or not public"); |
4774 | } |
4775 | return data; |
4776 | } |
4777 | static URL toURL(Object o) { try { |
4778 | |
4779 | if (o instanceof URL) return (URL) o; |
4780 | if (o instanceof String) return new URL((String) o); |
4781 | if (o instanceof File) return fileToURL((File) o); |
4782 | fail("Can't convert to URL: " + o); |
4783 | |
4784 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
4785 | static String _computerID; |
4786 | public static String computerID() { try { |
4787 | |
4788 | if (_computerID == null) { |
4789 | File file = new File(userHome(), ".tinybrain/computer-id"); |
4790 | _computerID = loadTextFile(file.getPath(), null); |
4791 | if (_computerID == null) { |
4792 | _computerID = makeRandomID(12); |
4793 | saveTextFile(file.getPath(), _computerID); |
4794 | } |
4795 | } |
4796 | return _computerID; |
4797 | |
4798 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
4799 | static String firstPartOfHelloString(String s) { |
4800 | int i = s.lastIndexOf('/'); |
4801 | return i < 0 ? s : rtrim(s.substring(0, i)); |
4802 | } |
4803 | static String getNameOfPublicClass(List<String> tok) { |
4804 | for (List<String> c : allClasses(tok)) |
4805 | if (hasModifier(c, "public")) |
4806 | return getClassDeclarationName(c); |
4807 | return null; |
4808 | } |
4809 | |
4810 | static void clearTokens(List<String> tok) { |
4811 | clearAllTokens(tok); |
4812 | } |
4813 | |
4814 | static void clearTokens(List<String> tok, int i, int j) { |
4815 | clearAllTokens(tok, i, j); |
4816 | } |
4817 | static List<ProgramScan.Program> quickBotScan() { |
4818 | return ProgramScan.quickBotScan(); |
4819 | } |
4820 | |
4821 | static List<ProgramScan.Program> quickBotScan(int[] preferredPorts) { |
4822 | return ProgramScan.quickBotScan(preferredPorts); |
4823 | } |
4824 | |
4825 | static List<ProgramScan.Program> quickBotScan(String searchPattern) { |
4826 | List<ProgramScan.Program> l = new ArrayList<ProgramScan.Program>(); |
4827 | for (ProgramScan.Program p : ProgramScan.quickBotScan()) |
4828 | if (indexOfIgnoreCase(p.helloString, searchPattern) == 0) |
4829 | l.add(p); |
4830 | return l; |
4831 | } |
4832 | |
4833 | static List<String> nlTok(String s) { |
4834 | return javaTokPlusPeriod(s); |
4835 | } |
4836 | static int jfind(List<String> tok, String in) { |
4837 | List<String> tokin = javaTok(in); |
4838 | jfind_preprocess(tokin); |
4839 | return findCodeTokens(tok, false, toStringArray(codeTokensOnly(tokin))); |
4840 | } |
4841 | |
4842 | static void jfind_preprocess(List<String> tok) { |
4843 | for (String type : litlist("quoted", "id", "int")) |
4844 | replaceSublist(tok, litlist("<", "", type, "", ">"), litlist("<" + type + ">")); |
4845 | } |
4846 | static DialogIO talkTo(int port) { |
4847 | return talkTo("localhost", port); |
4848 | } |
4849 | |
4850 | static DialogIO talkTo(String ip, int port) { try { |
4851 | |
4852 | final Socket s = new Socket(ip, port); |
4853 | //print("Talking to " + ip + ":" + port); |
4854 | |
4855 | final Writer w = new OutputStreamWriter(s.getOutputStream(), "UTF-8"); |
4856 | final BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8")); |
4857 | return new DialogIO() { |
4858 | boolean isLocalConnection() { |
4859 | return s.getInetAddress().isLoopbackAddress(); |
4860 | } |
4861 | |
4862 | boolean isStillConnected() { |
4863 | return !(eos || s.isClosed()); |
4864 | } |
4865 | |
4866 | void sendLine(String line) { try { |
4867 | |
4868 | w.write(line + "\n"); |
4869 | w.flush(); |
4870 | |
4871 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
4872 | |
4873 | String readLineImpl() { try { |
4874 | |
4875 | return in.readLine(); |
4876 | |
4877 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
4878 | |
4879 | void close() { |
4880 | try { |
4881 | s.close(); |
4882 | } catch (IOException e) { |
4883 | // whatever |
4884 | } |
4885 | } |
4886 | |
4887 | Socket getSocket() { |
4888 | return s; |
4889 | } |
4890 | }; |
4891 | |
4892 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
4893 | static String sendToLocalBot(String bot, String text, Object... args) { |
4894 | text = format3(text, args); |
4895 | |
4896 | DialogIO channel = findBot(bot); |
4897 | if (channel == null) |
4898 | fail(quote(bot) + " not found"); |
4899 | try { |
4900 | channel.readLine(); |
4901 | print(bot + "> " + shorten(text, 80)); |
4902 | channel.sendLine(text); |
4903 | String s = channel.readLine(); |
4904 | print(bot + "< " + shorten(s, 80)); |
4905 | return s; |
4906 | } catch (Throwable e) { |
4907 | e.printStackTrace(); |
4908 | return null; |
4909 | } finally { |
4910 | channel.close(); |
4911 | } |
4912 | } |
4913 | |
4914 | static String sendToLocalBot(int port, String text, Object... args) { |
4915 | text = format3(text, args); |
4916 | DialogIO channel = talkTo(port); |
4917 | try { |
4918 | channel.readLine(); |
4919 | print(port + "> " + shorten(text, 80)); |
4920 | channel.sendLine(text); |
4921 | String s = channel.readLine(); |
4922 | print(port + "< " + shorten(s, 80)); |
4923 | return s; |
4924 | } catch (Throwable e) { |
4925 | e.printStackTrace(); |
4926 | return null; |
4927 | } finally { |
4928 | if (channel != null) |
4929 | channel.close(); |
4930 | } |
4931 | } |
4932 | // works on lists and strings and null |
4933 | |
4934 | static int indexOfIgnoreCase(Object a, Object b) { |
4935 | if (a == null) return -1; |
4936 | if (a instanceof String) { |
4937 | Matcher m = Pattern.compile((String) b, Pattern.CASE_INSENSITIVE + Pattern.LITERAL).matcher((String) a); |
4938 | if (m.find()) return m.start(); else return -1; |
4939 | } |
4940 | if (a instanceof List) { |
4941 | for (int i = 0; i < ((List) a).size(); i++) { |
4942 | Object o = ((List) a).get(i); |
4943 | if (o != null && ((String) o).equalsIgnoreCase((String) b)) |
4944 | return i; |
4945 | } |
4946 | return -1; |
4947 | } |
4948 | throw fail("Unknown type: " + a); |
4949 | } |
4950 | static String repeat(char c, int n) { |
4951 | n = max(n, 0); |
4952 | char[] chars = new char[n]; |
4953 | for (int i = 0; i < n; i++) |
4954 | chars[i] = c; |
4955 | return new String(chars); |
4956 | } |
4957 | |
4958 | static <A> List<A> repeat(A a, int n) { |
4959 | new List<A> l; |
4960 | for (int i = 0; i < n; i++) |
4961 | l.add(a); |
4962 | return l; |
4963 | } |
4964 | |
4965 | static long round(double d) { |
4966 | return Math.round(d); |
4967 | } |
4968 | static File userDir() { |
4969 | return new File(userHome()); |
4970 | } |
4971 | |
4972 | static File userDir(String path) { |
4973 | return new File(userHome(), path); |
4974 | } |
4975 | static boolean isAndroid() { return System.getProperty("java.vendor").toLowerCase().indexOf("android") >= 0; } |
4976 | |
4977 | |
4978 | static String getClassDeclarationName(List<String> c) { |
4979 | for (int i = 1; i+2 < c.size(); i += 2) |
4980 | if (c.get(i).equals("class")) |
4981 | return c.get(i+2); |
4982 | return null; |
4983 | } |
4984 | |
4985 | |
4986 | static URL fileToURL(File f) { try { |
4987 | |
4988 | return f.toURI().toURL(); |
4989 | |
4990 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
4991 | static File getGlobalCache() { |
4992 | File file = new File(userHome(), ".tinybrain/snippet-cache"); |
4993 | file.mkdirs(); |
4994 | return file; |
4995 | } |
4996 | |
4997 | // lists returned are actual CNC (N/C/N/.../C/N) - and connected to |
4998 | // original list |
4999 | static List<List<String>> allClasses(List<String> tok) { |
5000 | List<List<String>> l = new ArrayList(); |
5001 | for (int i = 1; i < tok.size(); i += 2) { |
5002 | if (tok.get(i).equals("class") && (i == 1 || !tok.get(i-2).equals("."))) { |
5003 | int j = i; |
5004 | while (j < tok.size() && !tok.get(j).equals("{")) |
5005 | j += 2; |
5006 | j = findEndOfBlock(tok, j)+1; |
5007 | i = leftScanModifiers(tok, i); |
5008 | l.add(tok.subList(i-1, Math.min(tok.size(), j))); |
5009 | i = j-2; |
5010 | } |
5011 | } |
5012 | return l; |
5013 | } |
5014 | |
5015 | static List<List<String>> allClasses(String text) { |
5016 | return allClasses(javaTok(text)); |
5017 | } |
5018 | static List<String> replaceSublist(List<String> l, List<String> x, List<String> y) { |
5019 | if (x == null) return l; |
5020 | |
5021 | int i = 0; |
5022 | while (true) { |
5023 | i = indexOfSubList(l, x, i); |
5024 | if (i < 0) break; |
5025 | |
5026 | // It's inefficient :D |
5027 | for (int j = 0; j < l(x); j++) l.remove(i); |
5028 | l.addAll(i, y); |
5029 | i += l(y); |
5030 | } |
5031 | return l; |
5032 | } |
5033 | // scans a Java construct (class, method) and checks its modifiers |
5034 | static boolean hasModifier(List<String> tok, String modifier) { |
5035 | for (int i = 1; i < tok.size() && getJavaModifiers().contains(tok.get(i)); i += 2) |
5036 | if (tok.get(i).equals(modifier)) |
5037 | return true; |
5038 | return false; |
5039 | } |
5040 | |
5041 | static void clearAllTokens(List<String> tok) { |
5042 | for (int i = 0; i < tok.size(); i++) |
5043 | tok.set(i, ""); |
5044 | } |
5045 | |
5046 | static void clearAllTokens(List<String> tok, int i, int j) { |
5047 | for (; i < j; i++) |
5048 | tok.set(i, ""); |
5049 | } |
5050 | static int findCodeTokens(List<String> tok, String... tokens) { |
5051 | return findCodeTokens(tok, 1, false, tokens); |
5052 | } |
5053 | |
5054 | static int findCodeTokens(List<String> tok, boolean ignoreCase, String... tokens) { |
5055 | return findCodeTokens(tok, 1, ignoreCase, tokens); |
5056 | } |
5057 | |
5058 | static int findCodeTokens(List<String> tok, int startIdx, boolean ignoreCase, String... tokens) { |
5059 | return findCodeTokens(tok, startIdx, ignoreCase, tokens, null); |
5060 | } |
5061 | |
5062 | static List<String> findCodeTokens_specials = litlist("*", "<quoted>", "<id>", "<int>", "\\*"); |
5063 | static boolean findCodeTokens_debug; |
5064 | static int findCodeTokens_indexed, findCodeTokens_unindexed; |
5065 | |
5066 | static int findCodeTokens(List<String> tok, int startIdx, boolean ignoreCase, String[] tokens, Object condition) { |
5067 | if (findCodeTokens_debug) { |
5068 | if (eq(getClassName(tok), "main$IndexedList2")) |
5069 | findCodeTokens_indexed++; |
5070 | else |
5071 | findCodeTokens_unindexed++; |
5072 | } |
5073 | // bail out early if first token not found (works great with IndexedList) |
5074 | if (!findCodeTokens_specials.contains(tokens[0]) |
5075 | && !tok.contains(tokens[0] /*, startIdx << no signature in List for this, unfortunately */)) return -1; |
5076 | |
5077 | outer: for (int i = startIdx | 1; i+tokens.length*2-2 < tok.size(); i += 2) { |
5078 | for (int j = 0; j < tokens.length; j++) { |
5079 | String p = tokens[j], t = tok.get(i+j*2); |
5080 | boolean match; |
5081 | if (eq(p, "*")) match = true; |
5082 | else if (eq(p, "<quoted>")) match = isQuoted(t); |
5083 | else if (eq(p, "<id>")) match = isIdentifier(t); |
5084 | else if (eq(p, "<int>")) match = isInteger(t); |
5085 | else if (eq(p, "\\*")) match = eq("*", t); |
5086 | else match = ignoreCase ? eqic(p, t) : eq(p, t); |
5087 | |
5088 | if (!match) |
5089 | continue outer; |
5090 | } |
5091 | |
5092 | if (condition == null || checkCondition(condition, tok, i-1)) // pass N index |
5093 | return i; |
5094 | } |
5095 | return -1; |
5096 | } |
5097 | public static String rtrim(String s) { |
5098 | int i = s.length(); |
5099 | while (i > 0 && " \t\r\n".indexOf(s.charAt(i-1)) >= 0) |
5100 | --i; |
5101 | return i < s.length() ? s.substring(0, i) : s; |
5102 | } |
5103 | |
5104 | |
5105 | static <A> int indexOfSubList(List<A> x, List<A> y, int i) { |
5106 | outer: for (; i+l(y) <= l(x); i++) { |
5107 | for (int j = 0; j < l(y); j++) |
5108 | if (neq(x.get(i+j), y.get(j))) |
5109 | continue outer; |
5110 | return i; |
5111 | } |
5112 | return -1; |
5113 | } |
5114 | // supports the usual quotings (', ", variable length double brackets) |
5115 | static boolean isQuoted(String s) { |
5116 | if (s.startsWith("'") || s.startsWith("\"")) return true; |
5117 | if (!s.startsWith("[")) return false; |
5118 | int i = 1; |
5119 | while (i < s.length() && s.charAt(i) == '=') ++i; |
5120 | return i < s.length() && s.charAt(i) == '['; |
5121 | //return Pattern.compile("^\\[=*\\[").matcher(s).find(); |
5122 | } |
5123 | static boolean checkCondition(Object condition, Object... args) { |
5124 | return isTrue(call(condition, "check", args)); |
5125 | } |
5126 | static int leftScanModifiers(List<String> tok, int i) { |
5127 | List<String> mod = getJavaModifiers(); |
5128 | while (i > 1 && mod.contains(tok.get(i-2))) |
5129 | i -= 2; |
5130 | return i; |
5131 | } |
5132 | |
5133 | static List<String> getJavaModifiers_list = litlist("static", "abstract", "public", "private", "protected", "final", "native", "volatile", "synchronized", "transient"); |
5134 | |
5135 | static List<String> getJavaModifiers() { |
5136 | return getJavaModifiers_list; |
5137 | } |
5138 | // i must point at the opening bracket ("{") |
5139 | // index returned is index of closing bracket + 1 |
5140 | static int findEndOfBlock(List<String> cnc, int i) { |
5141 | int j = i+2, level = 1; |
5142 | while (j < cnc.size()) { |
5143 | if (cnc.get(j).equals("{")) ++level; |
5144 | else if (cnc.get(j).equals("}")) --level; |
5145 | if (level == 0) |
5146 | return j+1; |
5147 | ++j; |
5148 | } |
5149 | return cnc.size(); |
5150 | } |
5151 | |
5152 | |
5153 | static class Gen { |
5154 | String name; |
5155 | Object func; |
5156 | |
5157 | *() {} |
5158 | *(String *name, Object *func) {} |
5159 | |
5160 | public String toString() { |
5161 | return name; |
5162 | } |
5163 | } |
5164 | |
5165 | static class Var<A> { |
5166 | A v; |
5167 | |
5168 | *() {} |
5169 | *(A *v) {} |
5170 | |
5171 | synchronized void set(A a) { v = a; } |
5172 | synchronized A get() { return v; } |
5173 | } |
5174 | |
5175 | static class ProgramScan { |
5176 | static int threads = isWindows() ? 500 : 10; |
5177 | static int timeout = 5000; // hmm... |
5178 | static String ip = "127.0.0.1"; |
5179 | static int quickScanFrom = 10000, quickScanTo = 10999; |
5180 | static int maxNumberOfBotPorts = 100; |
5181 | static boolean verbose; |
5182 | |
5183 | static class Program { |
5184 | int port; |
5185 | String helloString; |
5186 | |
5187 | *(int *port, String *helloString) {} |
5188 | } |
5189 | |
5190 | static List<Program> scan() { try { |
5191 | |
5192 | return scan(1, 65535); |
5193 | |
5194 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
5195 | |
5196 | static List<Program> scan(int fromPort, int toPort) { |
5197 | return scan(fromPort, toPort, new int[0]); |
5198 | } |
5199 | |
5200 | static List<Program> scan(int fromPort, int toPort, int[] preferredPorts) { try { |
5201 | |
5202 | Set<Integer> preferredPortsSet = new HashSet<Integer>(asList(preferredPorts)); |
5203 | String name = toPort < 10000 ? "bot" : "program"; |
5204 | final ExecutorService es = Executors.newFixedThreadPool(threads); |
5205 | if (verbose) print(firstToUpper(name) + "-scanning " + ip + " with timeout " + timeout + " ms in " + threads + " threads."); |
5206 | startTiming(); |
5207 | new List<Future<Program>> futures; |
5208 | for (int port : preferredPorts) |
5209 | futures.add(checkPort(es, ip, port, timeout)); |
5210 | for (int port = fromPort; port <= toPort; port++) |
5211 | if (!preferredPortsSet.contains(port)) |
5212 | futures.add(checkPort(es, ip, port, timeout)); |
5213 | es.shutdown(); |
5214 | new List<Program> programs; |
5215 | for (final Future<Program> f : futures) { |
5216 | Program p = f.get(); |
5217 | if (p != null) |
5218 | programs.add(p); |
5219 | } |
5220 | stopTiming(); |
5221 | if (verbose) print("Found " + programs.size() + " " + name + "(s) on " + ip); |
5222 | return programs; |
5223 | |
5224 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
5225 | |
5226 | static Future<Program> checkPort(final ExecutorService es, final String ip, final int port, final int timeout) { |
5227 | return es.submit(new Callable<Program>() { |
5228 | @Override public Program call() { |
5229 | try { |
5230 | Socket socket = new Socket(); |
5231 | socket.setSoTimeout(timeout); |
5232 | socket.connect(new InetSocketAddress(ip, port), timeout); |
5233 | if (verbose) print("Connected to " + ip + ":" + port); |
5234 | BufferedReader in = new BufferedReader( |
5235 | new InputStreamReader(socket.getInputStream(), "UTF-8")); |
5236 | String hello = or(in.readLine(), "?"); |
5237 | socket.close(); |
5238 | return new Program(port, hello); |
5239 | } catch (Exception ex) { |
5240 | return null; |
5241 | } |
5242 | } |
5243 | }); |
5244 | } |
5245 | |
5246 | static List<Program> quickScan() { |
5247 | return scan(quickScanFrom, quickScanTo); |
5248 | } |
5249 | |
5250 | static List<Program> quickBotScan() { |
5251 | return quickBotScan(new int[0]); |
5252 | } |
5253 | |
5254 | static List<Program> quickBotScan(int[] preferredPorts) { |
5255 | return scan(4990, 5000+maxNumberOfBotPorts-1, preferredPorts); |
5256 | } |
5257 | } |
5258 | |
5259 | static abstract class DialogIO { |
5260 | String line; |
5261 | boolean eos; |
5262 | |
5263 | abstract String readLineImpl(); |
5264 | abstract boolean isStillConnected(); |
5265 | abstract void sendLine(String line); |
5266 | abstract boolean isLocalConnection(); |
5267 | abstract Socket getSocket(); |
5268 | abstract void close(); |
5269 | |
5270 | int getPort() { return getSocket().getPort(); } |
5271 | |
5272 | boolean helloRead; |
5273 | |
5274 | String readLineNoBlock() { |
5275 | String l = line; |
5276 | line = null; |
5277 | return l; |
5278 | } |
5279 | |
5280 | boolean waitForLine() { try { |
5281 | |
5282 | if (line != null) return true; |
5283 | //print("Readline"); |
5284 | line = readLineImpl(); |
5285 | //print("Readline done: " + line); |
5286 | if (line == null) eos = true; |
5287 | return line != null; |
5288 | |
5289 | } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} |
5290 | |
5291 | String readLine() { |
5292 | waitForLine(); |
5293 | helloRead = true; |
5294 | return readLineNoBlock(); |
5295 | } |
5296 | |
5297 | String ask(String s, Object... args) { |
5298 | if (!helloRead) readLine(); |
5299 | if (args.length != 0) s = format3(s, args); |
5300 | sendLine(s); |
5301 | return readLine(); |
5302 | } |
5303 | |
5304 | String askLoudly(String s, Object... args) { |
5305 | if (!helloRead) readLine(); |
5306 | if (args.length != 0) s = format3(s, args); |
5307 | print("> " + s); |
5308 | sendLine(s); |
5309 | String answer = readLine(); |
5310 | print("< " + answer); |
5311 | return answer; |
5312 | } |
5313 | |
5314 | void pushback(String l) { |
5315 | if (line != null) |
5316 | fail(); |
5317 | line = l; |
5318 | helloRead = false; |
5319 | } |
5320 | } |
5321 | |
5322 | static abstract class DialogHandler { |
5323 | abstract void run(DialogIO io); |
5324 | } |
5325 | |
5326 | static class Matches { |
5327 | String[] m; |
5328 | String get(int i) { return i < m.length ? m[i] : null; } |
5329 | String unq(int i) { return unquote(get(i)); } |
5330 | String fsi(int i) { return formatSnippetID(unq(i)); } |
5331 | String fsi() { return fsi(0); } |
5332 | String tlc(int i) { return unq(i).toLowerCase(); } |
5333 | boolean bool(int i) { return "true".equals(unq(i)); } |
5334 | String rest() { return m[m.length-1]; } // for matchStart |
5335 | int psi(int i) { return Integer.parseInt(unq(i)); } |
5336 | } |
5337 | |
5338 | |
5339 | // Now uses TreeMap for nicer sorting (i.e., A must be a orderable type) |
5340 | static class MultiSet<A> { |
5341 | Map<A, Integer> map = new TreeMap<A, Integer>(); |
5342 | |
5343 | public MultiSet(boolean useTreeMap) { |
5344 | if (!useTreeMap) |
5345 | map = new HashMap; |
5346 | } |
5347 | |
5348 | public MultiSet() { |
5349 | } |
5350 | |
5351 | public MultiSet(Collection<A> c) { |
5352 | addAll(c); |
5353 | } |
5354 | |
5355 | public void add(A key) { |
5356 | add(key, 1); |
5357 | } |
5358 | |
5359 | public void addAll(Collection<A> c) { |
5360 | if (c != null) for (A a : c) |
5361 | add(a); |
5362 | } |
5363 | |
5364 | public void add(A key, int count) { |
5365 | if (map.containsKey(key)) |
5366 | map.put(key, map.get(key)+count); |
5367 | else |
5368 | map.put(key, count); |
5369 | } |
5370 | |
5371 | public int get(A key) { |
5372 | return key != null && map.containsKey(key) ? map.get(key) : 0; |
5373 | } |
5374 | |
5375 | public boolean contains(A key) { |
5376 | return map.containsKey(key); |
5377 | } |
5378 | |
5379 | public void remove(A key) { |
5380 | Integer i = map.get(key); |
5381 | if (i != null && i > 1) |
5382 | map.put(key, i - 1); |
5383 | else |
5384 | map.remove(key); |
5385 | } |
5386 | |
5387 | public List<A> getTopTen() { |
5388 | return getTopTen(10); |
5389 | } |
5390 | |
5391 | public List<A> getTopTen(int maxSize) { |
5392 | List<A> list = getSortedListDescending(); |
5393 | return list.size() > maxSize ? list.subList(0, maxSize) : list; |
5394 | } |
5395 | |
5396 | public List<A> getSortedListDescending() { |
5397 | List<A> list = new ArrayList<A>(map.keySet()); |
5398 | Collections.sort(list, new Comparator<A>() { |
5399 | public int compare(A a, A b) { |
5400 | return map.get(b).compareTo(map.get(a)); |
5401 | } |
5402 | }); |
5403 | return list; |
5404 | } |
5405 | |
5406 | public int getNumberOfUniqueElements() { |
5407 | return map.size(); |
5408 | } |
5409 | |
5410 | public Set<A> asSet() { |
5411 | return map.keySet(); |
5412 | } |
5413 | |
5414 | public A getMostPopularEntry() { |
5415 | int max = 0; |
5416 | A a = null; |
5417 | for (Map.Entry<A,Integer> entry : map.entrySet()) { |
5418 | if (entry.getValue() > max) { |
5419 | max = entry.getValue(); |
5420 | a = entry.getKey(); |
5421 | } |
5422 | } |
5423 | return a; |
5424 | } |
5425 | |
5426 | public void removeAll(A key) { |
5427 | map.remove(key); |
5428 | } |
5429 | |
5430 | public int size() { |
5431 | int size = 0; |
5432 | for (int i : map.values()) |
5433 | size += i; |
5434 | return size; |
5435 | } |
5436 | |
5437 | public MultiSet<A> mergeWith(MultiSet<A> set) { |
5438 | MultiSet<A> result = new MultiSet<A>(); |
5439 | for (A a : set.asSet()) { |
5440 | result.add(a, set.get(a)); |
5441 | } |
5442 | return result; |
5443 | } |
5444 | |
5445 | public boolean isEmpty() { |
5446 | return map.isEmpty(); |
5447 | } |
5448 | |
5449 | public String toString() { |
5450 | return structure(this); |
5451 | } |
5452 | |
5453 | public void clear() { |
5454 | map.clear(); |
5455 | } |
5456 | } |
5457 | |
5458 | static long startTiming_startTime; |
5459 | static void startTiming() { |
5460 | startTiming_startTime = now(); |
5461 | } |
5462 | |
5463 | static void stopTiming() { |
5464 | long end = now(); |
5465 | print("Time: " + (end-startTiming_startTime) + " ms"); |
5466 | } |
5467 | static JWindow showLoadingAnimation() { |
5468 | ret showAnimationInTopRightCorner("#1003543", "Hold on user..."); |
5469 | } |
5470 | static BufferedReader readLine_reader; |
5471 | |
5472 | static String readLine() { |
5473 | ret (String) call(getJavaX(), "readLine"); |
5474 | } |
5475 | static void swingLater(int delay, final Runnable r) { |
5476 | javax.swing.Timer timer = new javax.swing.Timer(delay, actionListener { |
5477 | r.run(); |
5478 | }); |
5479 | timer.setRepeats(false); |
5480 | timer.start(); |
5481 | } |
5482 | |
5483 | static void swingLater(Runnable r) { |
5484 | SwingUtilities.invokeLater(r); |
5485 | } |
5486 | |
5487 | static void swingNowOrLater(Runnable r) { |
5488 | if (isAWTThread()) |
5489 | r.run(); |
5490 | else |
5491 | swingLater(r); |
5492 | } |
5493 | static Set asSet(O[] array) { |
5494 | new HashSet set; |
5495 | for (O o : array) |
5496 | if (o != null) |
5497 | set.add(o); |
5498 | ret set; |
5499 | } |
5500 | |
5501 | static Set<S> asSet(S[] array) { |
5502 | new TreeSet<S> set; |
5503 | for (S o : array) |
5504 | if (o != null) |
5505 | set.add(o); |
5506 | ret set; |
5507 | } |
5508 | |
5509 | static Set<S> asSet(Collection<S> l) { |
5510 | new TreeSet<S> set; |
5511 | for (S o : l) |
5512 | if (o != null) |
5513 | set.add(o); |
5514 | ret set; |
5515 | } |
5516 | static <A> A or(A a, A b) { |
5517 | return a != null ? a : b; |
5518 | } |
5519 | static void disposeWindow(final Window window) { |
5520 | awt { |
5521 | window.dispose(); |
5522 | } |
5523 | } |
5524 | static String firstToUpper(String s) { |
5525 | if (s.length() == 0) return s; |
5526 | return Character.toUpperCase(s.charAt(0)) + s.substring(1); |
5527 | } |
5528 | |
5529 | } |
Travelled to 13 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, ddnzoavkxhuk, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1004053 |
Snippet name: | Bug |
Eternal ID of this version: | #1004053/1 |
Text MD5: | 23e79db20826ee367ee750471d6824b3 |
Author: | stefan |
Category: | |
Type: | Document |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2016-08-05 02:21:09 |
Source code size: | 168409 bytes / 5529 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 688 / 356 |
Referenced in: | [show references] |