main 98594d0

Program.cs RawHistoryFolder

1// SPDX-License-Identifier: MIT
2
3using System;
4using System.Collections.Generic;
5using System.IO;
6using System.Linq;
7using System.Text;
8using GitHub.Actions.Expressions;
9using GitHub.Actions.Expressions.Data;
10using GitHub.Actions.Expressions.Sdk;
11using GitHub.Actions.Expressions.Sdk.Functions;
12using Newtonsoft.Json;
13using Newtonsoft.Json.Linq;
14
15// Differential harness: runs expressions through the runner's own
16// Expressions2 code (compiled from the runner repository) and prints one JSON
17// line per case.
18//
19// Input (argv[0]): JSON {"contexts": {name: json}, "cases": [{"e": expr, "ctx": {name: json} | null}]}
20// Output: JSON lines {"k": kind, "s": string form, "j": toJson, "err": {"t": "parse"|"eval", "m": message}}
21
22internal sealed class CtxNode : NamedValue
23{
24    protected override Object EvaluateCore(EvaluationContext context, out ResultMemory resultMemory)
25    {
26        resultMemory = null;
27        return (context.State as DictionaryExpressionData)[Name];
28    }
29}
30
31internal sealed class Success : Function { protected override Object EvaluateCore(EvaluationContext c, out ResultMemory m) { m = null; return true; } }
32internal sealed class Always : Function { protected override Object EvaluateCore(EvaluationContext c, out ResultMemory m) { m = null; return true; } }
33internal sealed class HashFiles : Function
34{
35    protected override Object EvaluateCore(EvaluationContext c, out ResultMemory m)
36    {
37        m = null;
38        var s = "hash:";
39        for (var i = 0; i < Parameters.Count; i++)
40        {
41            if (i > 0) s += "|";
42            s += Parameters[i].Evaluate(c).ConvertToString();
43        }
44        return s;
45    }
46}
47
48internal static class P
49{
50    static DictionaryExpressionData Load(JObject ctx)
51    {
52        var d = new DictionaryExpressionData();
53        foreach (var p in ctx.Properties())
54        {
55            var token = p.Value;
56            d[p.Name] = token.ToExpressionData();
57        }
58        return d;
59    }
60
61    static int Main(string[] args)
62    {
63        JObject root; using (var jr0 = new JsonTextReader(new StringReader(File.ReadAllText(args[0]))) { DateParseHandling = DateParseHandling.None }) root = JObject.Load(jr0);
64        var defaultCtx = (JObject)root["contexts"];
65        var funcs = new IFunctionInfo[]
66        {
67            new FunctionInfo<Success>("success", 0, 0),
68            new FunctionInfo<Always>("always", 0, 0),
69            new FunctionInfo<HashFiles>("hashFiles", 1, 255),
70        };
71        var output = new StreamWriter(Console.OpenStandardOutput(), new UTF8Encoding(false));
72        var defaultData = Load(defaultCtx);
73        foreach (var c in (JArray)root["cases"])
74        {
75            var e = (string)c["e"];
76            var custom = c["ctx"] as JObject;
77            var data = custom != null ? Load(custom) : defaultData;
78            var names = (custom ?? defaultCtx).Properties().Select(p => p.Name);
79            var res = new JObject();
80            IExpressionNode tree = null;
81            try
82            {
83                tree = new ExpressionParser().CreateTree(e, null, names.Select(n => (INamedValueInfo)new NamedValueInfo<CtxNode>(n)).ToList(), funcs);
84            }
85            catch (Exception ex)
86            {
87                res["err"] = new JObject { ["t"] = "parse", ["m"] = ex.Message, ["x"] = ex.GetType().Name };
88            }
89            if (res["err"] == null)
90            {
91                if (tree == null)
92                {
93                    res["empty"] = true;
94                }
95                else
96                {
97                    try
98                    {
99                        var r = tree.Evaluate(null, null, data, null);
100                        res["k"] = r.Kind.ToString();
101                        res["s"] = r.ConvertToString();
102                        // toJson of the result
103                        var tj = new ToJson();
104                        tj.AddParameter(new Literal(r.Value));
105                        try
106                        {
107                            var jr = ((IExpressionNode)tj).Evaluate(null, null, data, null);
108                            res["j"] = jr.ConvertToString();
109                        }
110                        catch (Exception ex2)
111                        {
112                            res["jerr"] = ex2.Message;
113                        }
114                    }
115                    catch (Exception ex)
116                    {
117                        res["err"] = new JObject { ["t"] = "eval", ["m"] = ex.Message, ["x"] = ex.GetType().Name };
118                    }
119                }
120            }
121            // ASCII-escaped, so that a lone surrogate (which UTF-8 cannot carry) survives.
122            var sw = new StringWriter();
123            using (var jw = new JsonTextWriter(sw) { StringEscapeHandling = StringEscapeHandling.EscapeNonAscii, Formatting = Formatting.None })
124            {
125                res.WriteTo(jw);
126            }
127            output.WriteLine(sw.ToString());
128        }
129        output.Flush();
130        return 0;
131    }
132}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 3

↑↓ moveenter openesc close