Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

386
LINES

< > BotCompany Repo | #1030131 // JavaXHyperlinker - annotates JavaX sources in HTML. Also, COLORS!

JavaX fragment (include) [tags: use-pretranspiled]

Libraryless. Click here for Pure Java version (17527L/108K).

1  
// TODO: fix interaction with line spans made by show-snippet.php
2  
3  
// Transpile & reload-in-eleu #1008705 after changing this 
4  
5  
// TODO: use Map<IntRange, MapSO> attributesForCharRanges
6  
// and generate HTML properly from that
7  
8  
sclass JavaXHyperlinker {
9  
  bool targetBlank;
10  
  
11  
  asclass PeepHole {
12  
    LS tok;
13  
    int cIdx;
14  
    S prevPrev, prev, token, next;
15  
    
16  
    abstract void explain(int i default cIdx, S text);
17  
    abstract void link(int i default cIdx, S url);
18  
  }
19  
  
20  
  // only a single token allowed on LHS
21  
  SS shortFor = litmap(
22  
    "BigInt", "BigInteger",
23  
    "$1", "m.unq(0)",
24  
    "$2", "m.unq(1)",
25  
    "$3", "m.unq(2)",
26  
    "LS", "List<String>",
27  
    "sclass", "static class",
28  
    "asclass", "abstract static class",
29  
    "svoid", "static void",
30  
    "SS", "Map<String, String>",
31  
    "S", "String",
32  
    "ret", "return",
33  
    "L", "List",
34  
    "Cl", "Collection",
35  
    "O", "Object",
36  
    "sO", "static Object",
37  
    "sS", "static String",
38  
    "fO", "final Object",
39  
    "fS", "final String",
40  
    "sS", "static String",
41  
    "sbool", "static boolean",
42  
    "fbool", "final boolean",
43  
    "bool", "boolean",
44  
    "Int", "Integer",
45  
    "cast", "casting to the type required on the left-hand side",
46  
    "°", "()",
47  
    "ItIt", "IterableIterator",
48  
    "ES", "Ext<S> (string plus extended information)",
49  
    "CloseableItIt", "CloseableIterableIterator",
50  
    "LPairS", "List<Pair<String>>",
51  
    "ISegmenter", "IF1<BufferedImage, L<Rect>>",
52  
    "dbl", "double",
53  
  );
54  
  
55  
  S explFunc = "anonymous function declaration (similar to Java 8 lambdas)";
56  
  S explPNoconsole = "Main program including Substance L&F, started in non-AWT thread, hiding the console";
57  
  
58  
  // any number of tokens allowed on LHS
59  
  SS tokenExplanations = litmap(
60  
    "cm", "cm summons the last version of a module in Stefan's OS (cm originally stood for 'compact module')",
61  
    "~.", "short for accessing a field or calling a method by reflection",
62  
    "beaConcept", "a BEA concept is just a concept (database-enabled Java class) derived from BEAObject (the AGI base class)",
63  
    "== null ?:", "short for: == null ? null :",
64  
    "p-exp {", "main program with automatic upgrade",
65  
    "mapLike", "a function that takes a global function name as first argument and can be called like this: <mapLikeFunction> <otherFunction>(...)",
66  
    "mapMethodLike", "a function that takes a method or field name as first argument and can be called like this: <mapMethodLikeFunction> <methodOrFieldName>(...)",
67  
    "func(", explFunc, "func{", explFunc,
68  
    //"f(", explFunc, "f{", explFunc,
69  
    "voidfunc", "anonymous function declaration without return value (similar to Java 8 lambdas)",
70  
    "ctex", "ctex rethrows exceptions as RuntimeExceptions so you don't have to declare them",
71  
    "p {", "short for: public static void main(String[] args)",
72  
    "p-experiment {", "Main program with a nice big console & auto-restart",
73  
    "p-substance {", "Main program including Substance L&F, started in AWT thread",
74  
    "p-subst {", "Main program including Substance L&F, started in non-AWT thread",
75  
    "p-noconsole {", explPNoconsole,
76  
    "pn {", explPNoconsole,
77  
    "answer {", "Answer function - static S answer(S s) { new Matches m; ...; null; }",
78  
    "time {", "Run the code block and print how long it took",
79  
    "cprint {", "A module with default class name derived from DynPrintLog",
80  
    "semiauto {", "In a semiauto block, JavaX automatically adds a ; to (almost) every line",
81  
    "autosemi {", "In an autosemi block, JavaX automatically adds a ; to (almost) every line",
82  
    "Clusters", "Clusters<A> is short for Map<A, Collection<A>>",
83  
    "temp", "temp is like try (...) extending to the end of the current block",
84  
    "pcall {", "protected call - try { ... } catch { print exception }",
85  
    "r {", "r { ... } is short for: new Runnable() { public void run() { ... } }",
86  
    "runnable {", "runnable { ... } is short for: new Runnable() { public void run() { ... } }",
87  
    "pcall-short {", "protected call, shorter output - try { ... } catch { printShortException }",
88  
    "LPair<", "LPair<...> is short for: L<Pair<...>>",
89  
    "visualize {", "Visualisation method for an OS module; returns a Swing component",
90  
    "visualize as", "define a visualization for the module",
91  
    "enhanceFrame {", "Method that changes properties of an OS module's frame",
92  
    "run {", "short for: public void run()",
93  
    "start {", "Method that is run when an OS module is loaded",
94  
    "enter {", "Methods in a module should be marked 'enter' for bookkeeping",
95  
    "vf<", "reference to function as voidfunc",
96  
    "compact module", "try to save memory by reusing code between modules",
97  
    "cmodule", "cmodule = compact module for Stefan's OS. compact = try to save memory by reusing code between modules",
98  
    "cmodule2", "cmodule2 = compact module for Stefan's OS (newer version). compact = try to save memory by reusing code between modules",
99  
    "rThread {", "Runnable in a new thread",
100  
    "shit(", "short for: return with print",
101  
    "shit:", "short for: return with print",
102  
    ":=", [[the := operator translates to a simple comma, but converts an identifier on its left-hand side into a string]],
103  
    "noeq", "don't auto-generate equals+hashCode methods",
104  
    "for single (", "for single is for ping + singletonUnlessNull",
105  
    "selfType", "selfType is replaced with the enclosing class's name",
106  
    "runnable class", "short for: class X implementing Runnable { run { ... }}",
107  
    "aka", "In JavaX, methods can have multiple names",
108  
  );
109  
  
110  
  SS sc, sf;
111  
  StringTree2<S> tokenExplanationsTree;
112  
  new L<IVF1<PeepHole>> explainers;
113  
  NotTooOften ntoClearCaches = nto_mins(5);
114  
115  
  *() {
116  
    maybeClearCaches();
117  
    tokenExplanationsTree = stringTree2_javaTok(tokenExplanations);
118  
  }
119  
  
120  
  void maybeClearCaches {
121  
    ntoClearCaches.do(-> clearCaches());
122  
  }
123  
124  
  S codeToHTML(S code, bool real default true) {
125  
    maybeClearCaches();
126  
    
127  
    LS tok = javaTok(code);
128  
  
129  
    new Map<Int, S> links; // token index -> sf snippet ID
130  
    new Map<Int, S> explanations; // token index -> explanation text
131  
    
132  
    putMultipleKeys(explanations, allPlus(4, jfindAll(tok, "void <id> q {")),
133  
      "Function will execute in module's queue");
134  
      
135  
    // Go over all tokens and colorize
136  
    
137  
    new Map<Int, S> styles;
138  
    tokensToColors(tok, styles);
139  
      
140  
    // Go over code tokens, generate links and explanations
141  
    
142  
    new Matches m;
143  
    for (int i = 1; i < l(tok); i += 2) {
144  
      S t = tok.get(i);
145  
      S prev = get(tok, i-2), prevPrev = get(tok, i-4);
146  
      S next = get(tok, i+2);
147  
      S sfID = sf.get(t);
148  
      
149  
      PeepHole ph = new {
150  
        void explain(int i, S text) { explanations.put(i, text); }
151  
        void link(int i, S url) { links.put(i, url); }
152  
      };
153  
      ph.tok = tok;
154  
      ph.cIdx = i;
155  
      ph.prevPrev = prevPrev;
156  
      ph.prev = prev;
157  
      ph.token = t;
158  
      ph.next = next;
159  
      
160  
      pcallFAll(explainers, ph);
161  
      
162  
      // please include functions
163  
      if (eq(t, "include") && eq(next, "functions")) {
164  
        i += 4;
165  
        S name;
166  
        while (i < l(tok) && isIdentifier(name = get(tok, i))) {
167  
          mapPut(links, i, sf.get(name));
168  
          i += 2;
169  
        }
170  
        continue;
171  
      }
172  
            
173  
      if (startsWith(t, "lambda", m) && isInteger(m.rest()) && isIdentifier(next))
174  
        explanations.put(i, "lambda reference to a \*m.rest()*/-argument function");
175  
        
176  
      if (eq(t, "is") && isIdentifier(next))
177  
        explanations.put(i, "synonym of 'implements'");
178  
        
179  
      if (eq(t, "methodLambda0") && isIdentifier(next))
180  
        explanations.put(i, "short for: x -> x.\*next*/() (with a fresh variable instead of x)");
181  
        
182  
      if (eqOneOf(t, "lambda0", "l0") && isIdentifier(next))
183  
        explanations.put(i, "short for: -> \*next*/()");
184  
        
185  
      if (eq(t, "swappable") && isIdentifier(next))
186  
        explanations.put(i, "swappable functions can be exchanged per object instance");
187  
        
188  
      if (eq(t, "main") && isIdentifier(next))
189  
        explanations.put(i, "reference to the current 'main' class (where all the standard functions are held, not always called 'main')");
190  
        
191  
      if (eq(t, "autoDispose") && isIdentifier(next))
192  
        explanations.put(i, [[autoDispose adds a cleanMeUp method that properly disposes of this variable]]);
193  
        
194  
      if (eq(t, "optional") && isIdentifier(next))
195  
        explanations.put(i, [[optional parameter (null if omitted)]]);
196  
        
197  
      if (eq(t, "macro") && isIdentifier(next))
198  
        explanations.put(i, "define a macro called '" + next + "', visible until the end of the enclosing block (or until redefined)");
199  
        
200  
      if (eq(t, "virtual") && isIdentifier(next))
201  
        explanations.put(i, [["virtual" represents a type that is not visible in this realm, so it is transpiled to just Object]]);
202  
        
203  
      if (eq(t, "concept") && isIdentifier(next))
204  
        explanations.put(i, "A concept is like a Java class, but persistable");
205  
        
206  
      if (eq(t, "flexeq") && isIdentifier(next))
207  
        explanations.put(i, "flexeq is a fix for records inside parameterized classes");
208  
        
209  
      if (eq(t, "switchable") && isIdentifier(next))
210  
        explanations.put(i, "A field that can be changed through the module's popup menu");
211  
        
212  
      if (eq(t, "embedded") && isIdentifier(next))
213  
        explanations.put(i, [["embedded" allows you to put a function where they would not normally be allowed]]);
214  
        
215  
      if (eq(t, "visual") && isIdentifier(next))
216  
        explanations.put(i, "short definition of the visualize() function");
217  
        
218  
      if (eq(t, "dm_q") && isIdentifier(next))
219  
        explanations.put(i, "Function reference delegating to module queue");
220  
        
221  
      if (eq(t, "!") && isIdentifier(prev) && neq(next, "="))
222  
        explanations.put(i, "! is short for .get()");
223  
        
224  
      /*if (eq(t, "!") && containsNewLine(get(tok, i-1)) && isInteger(next))
225  
        explanations.put(i, "Translator invocation");*/
226  
        
227  
      if (eq(t, "#") && isIdentifier(next))
228  
        explanations.put(i, "#<name> makes an identifier local to the scope");
229  
      
230  
      if (eq(t, "f") && isIdentifier(next))
231  
        explanations.put(i, "f <name> references a static function in the main class");
232  
      
233  
      if (eq(t, "r") && isIdentifier(next))
234  
        explanations.put(i, "short for: r { " + next + "() }");
235  
      
236  
      if (eqOneOf(t, "rThread", "rThreadEnter") && isIdentifier(next))
237  
        explanations.put(i, "short for: " + t + " { " + next + "() }");
238  
      
239  
      if (eq(t, "dispose") && isIdentifier(next))
240  
        explanations.put(i, "short for: cleanUp(" + next + "); " + next + " = null;");
241  
      
242  
      if (eq(t, "*") && eq(next, "("))
243  
        explanations.put(i, "Short syntax for a constructor declaration");
244  
    
245  
      if (eq(t, "thread") && eq(next, "{"))
246  
        explanations.put(i, "Start a new thread with the following code");
247  
        
248  
      if (eq(t, "module") && isIdentifier(next))
249  
        explanations.put(i, "A module is a class that can be loaded in Stefan's OS");
250  
        
251  
      if (eq(t, "record") && isIdentifier(next))
252  
        explanations.put(i, "A record is a value-based class");
253  
        
254  
      if (eq(t, "srecord") && isIdentifier(next))
255  
        explanations.put(i, "An srecord is a static value-based class");
256  
        
257  
      if (eqOneOf(t, "cached", "simplyCached") && isIdentifier(next))
258  
        explanations.put(i, "A function that caches its return value");
259  
        
260  
      if (eq(t, "thread") && isQuoted(next))
261  
        explanations.put(i, "Start a new thread with the following name & code");
262  
        
263  
      if (eq(t, "if") && isQuoted(next)) pcall {
264  
        LS tok2 = tok_subListWithoutBorderNTokens(tok, i, i+3);
265  
        tok_expandIfQuoted(tok2);
266  
        explanations.put(i, "short for: " + join(tok2));
267  
      }
268  
        
269  
      if (eq(t, "html") && eq(next, "{"))
270  
        explanations.put(i, "short for: static Object html(String uri, final Map<String, String> params) ctex {");
271  
        
272  
      if (eq(t, 'try) && eq(next, 'answer))
273  
        doublePut(explanations, i, i+2, "\"try answer\" returns the expression if it isn't null or empty");
274  
        
275  
      if (isSingleQuoteIdentifier(t))
276  
        explanations.put(i, "string constant, " + quote(fromSingleQuoteIdentifier(t)));
277  
        
278  
      if (eq(t, "event") && isIdentifier(next))
279  
        explanations.put(i, "declare a function called " + next + "() plus helpers for adding listeners");
280  
        
281  
      if (eqOneOf(t, 'null, 'false, 'true, 'this)
282  
        && eq(next, ";")
283  
        && tok_tokenBeforeLonelyReturnValue(tok, i-2))
284  
        doublePut(explanations, i, i+2, "short for: return " + t + ";");
285  
        
286  
      S e = shortFor.get(t);
287  
      if (e != null)
288  
        mapPut(explanations, i, "short for: " + e);
289  
        
290  
      // link to standard function
291  
      if (!explanations.containsKey(i) && sfID != null) {
292  
        if (eqOneOf(prev, "f", "r", "rThread", "function")
293  
          || startsWith(prev, "lambda")
294  
          || isIdentifier(next) && eqGet(tok, i+4, "(")
295  
          || eqOneOf(next, "(", "°")
296  
            && (neq(prev, ".") || eq(prevPrev, "main") && neq(get(tok, i-6), "."))
297  
          || eq(prev, "{") && eq(next, "}") && eq(prevPrev, "postProcess")
298  
          || eq(prev, ":") && eq(prevPrev, ":"))
299  
          links.put(i, sfID);
300  
      }
301  
      
302  
      L<S> fewTokens = codeTokens(subList(tok, i-1, i+2*5));
303  
      Pair<S, Int> p = stringTreeLeafValue2(tokenExplanationsTree, fewTokens);
304  
      if (p != null) {
305  
        //print(struct(p));
306  
        int lastCodeToken = i+p.b*2-2;
307  
        if (eq(get(tok, lastCodeToken), "{")) lastCodeToken -= 2;
308  
        mapPutInRange(explanations, i, lastCodeToken+1, p.a);
309  
      }
310  
  
311  
      if (isQuoted(t) && eq(prev, "(") && isIdentifier(prevPrev)
312  
        && isMechFunction(prevPrev))
313  
        mapPut(links, i, neatMechListURL(unquote(t)));
314  
      
315  
      //mapPut(explanations, i, tokenExplanations.get(t));
316  
        
317  
      mapPut(links, i, sc.get(t));
318  
    }
319  
    
320  
    // go over tokens, output HTML characters
321  
    
322  
    new StringBuilder out;
323  
    SS titles = getSnippetTitles(filter isSnippetID(values(links)));
324  
    for i over tok: {
325  
      S t = tok.get(i);
326  
      if (empty(t)) continue;
327  
      S id = links.get(i), ex = explanations.get(i);
328  
      S style = styles.get(i);
329  
      if (t.startsWith("[[") && t.endsWith("]]")) {
330  
        S explanation = "[[...]] denotes a multi-line string constant (as in Lua)";
331  
        out.append(dottedSpan("[[", explanation));
332  
        S inner = htmlencode(dropPrefix("[[", dropSuffix("]]", t)));
333  
        out.append(span(inner, style := "background-color: #77FF77"));
334  
        out.append(dottedSpan("]]", explanation));
335  
        continue;
336  
      }
337  
      if (t.startsWith("[=[") && t.endsWith("]=]")) {
338  
        S explanation = "[=[...]=] denotes a multi-line string constant (as in Lua)";
339  
        out.append(dottedSpan("[=[", explanation));
340  
        S inner = htmlencode(dropPrefix("[=[", dropSuffix("]=]", t)));
341  
        out.append(span(inner, style := "background-color: #77FF77"));
342  
        out.append(dottedSpan("]=]", explanation));
343  
        continue;
344  
      }
345  
      S enc = htmlencode(t);
346  
      out.append(id != null
347  
        ? ahref(makeLink(real, id), enc,
348  
          title := isSnippetID(id) ? titles.get(fsI(id)) : ex, style := "text-decoration: none; color: black; border-bottom: dotted 1px", target := targetBlank ? "_blank" : null)
349  
        : ex != null ? dottedSpan(enc, ex)
350  
        : style != null ? span(enc, +style)
351  
        : enc);
352  
    }
353  
    S html = str(out);
354  
    html = dynamize_noEncode(html);
355  
    ret html;
356  
  }
357  
358  
  // id can be a URL
359  
  S makeLink(bool real, S id) {
360  
    if (isRelativeOrAbsoluteURL(id)) ret id;
361  
    if (real)
362  
      ret longSnippetLink(id);
363  
    ret "/" + psI(id);
364  
  }
365  
  
366  
  void clearCaches {
367  
    stdFunctions_clearCache();
368  
    sc = standardClassesMap();
369  
    sf = stdFunctions_cached();
370  
    //sf.putAll(tok_findStandardFunctionDefinitions(javaTokSnippet(#1022367)));
371  
  }
372  
  
373  
  bool isMechFunction(S s) {
374  
    ret startsWithOneOf(s, "mech", "mL");
375  
  }
376  
  
377  
  void tokensToColors(LS tok, Map<Int, S> styles) {
378  
    for (int i = 0; i < l(tok); i += 2)
379  
      if (tok_whitespaceContainsJavaComments(tok.get(i)))
380  
        styles.put(i, "color: #666666");
381  
  }
382  
  
383  
  void addExplainer(IVF1<PeepHole> explainer) {
384  
    explainers.add(explainer);
385  
  }
386  
} // end of JavaXHyperlinker

Author comment

Began life as a copy of #1008705

download  show line numbers  debug dex  old transpilations   

Travelled to 5 computer(s): bhatertpkbcr, mowyntqkapby, mqqgnosmbjvj, pyentgdyhuwx, vouqrxazstgt

No comments. add comment

Snippet ID: #1030131
Snippet name: JavaXHyperlinker - annotates JavaX sources in HTML. Also, COLORS!
Eternal ID of this version: #1030131/63
Text MD5: e2b2c559f3ac8d71094faabc7943623a
Transpilation MD5: 72a2574a8bb882b4c960398890fd2379
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-07-30 02:19:45
Source code size: 16641 bytes / 386 lines
Pitched / IR pitched: No / No
Views / Downloads: 330 / 770
Version history: 62 change(s)
Referenced in: [show references]