aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/tools/yql_highlight/generate_textmate.cpp
blob: 28244c323d4226d9336352028e73aa93f5e31658 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include "generate_textmate.h"

#include "json.h"

#include <library/cpp/json/json_value.h>

#include <util/string/builder.h>
#include <util/string/cast.h>

namespace NSQLHighlight {

    namespace {

        TString ToTextMateRegex(const TUnit& unit, const NSQLTranslationV1::TRegexPattern& pattern) {
            TStringBuilder regex;

            if (pattern.IsCaseInsensitive) {
                regex << "(?i)";
            }

            if (unit.IsPlain) {
                regex << R"re(\b)re";
            }

            regex << "(" << pattern.Body << ")";

            if (!pattern.After.empty()) {
                regex << "(?=" << pattern.After << ")";
            }

            if (unit.IsPlain) {
                regex << R"re(\b)re";
            }

            return regex;
        }

        TStringBuf ToTextMateGroup(EUnitKind kind) {
            switch (kind) {
                case EUnitKind::Keyword:
                    return "keyword.control";
                case EUnitKind::Punctuation:
                    return "keyword.operator";
                case EUnitKind::QuotedIdentifier:
                    return "string.interpolated";
                case EUnitKind::BindParameterIdentifier:
                    return "variable.parameter";
                case EUnitKind::TypeIdentifier:
                    return "entity.name.type";
                case EUnitKind::FunctionIdentifier:
                    return "entity.name.function";
                case EUnitKind::Identifier:
                    return "variable.other";
                case EUnitKind::Literal:
                    return "constant.numeric";
                case EUnitKind::StringLiteral:
                    return "string.quoted.double";
                case EUnitKind::Comment:
                    return "comment.block";
                case EUnitKind::Whitespace:
                    return "";
                case EUnitKind::Error:
                    return "";
            }
        }

        TMaybe<NJson::TJsonMap> TextMateMultilinePattern(const TUnit& unit) {
            auto range = unit.RangePattern;
            if (!range) {
                return Nothing();
            }

            return NJson::TJsonMap({
                {"begin", range->Begin},
                {"end", range->End},
                {"name", ToTextMateGroup(unit.Kind)},
            });
        }

        NJson::TJsonMap ToTextMatePattern(const TUnit& unit, const NSQLTranslationV1::TRegexPattern& pattern) {
            return NJson::TJsonMap({
                {"match", ToTextMateRegex(unit, pattern)},
                {"name", ToTextMateGroup(unit.Kind)},
            });
        }

        TString ToTextMateName(EUnitKind kind) {
            return ToString(kind);
        }

    } // namespace

    void GenerateTextMate(IOutputStream& out, const THighlighting& highlighting) {
        NJson::TJsonMap root;
        root["$schema"] = "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json";
        root["name"] = "yql";
        root["scopeName"] = "source.yql";
        root["fileTypes"] = NJson::TJsonArray({"yql"});

        for (const TUnit& unit : highlighting.Units) {
            if (unit.IsCodeGenExcluded) {
                continue;
            }

            TString name = ToTextMateName(unit.Kind);

            root["patterns"].AppendValue(NJson::TJsonMap({
                {"include", "#" + name},
            }));

            for (const NSQLTranslationV1::TRegexPattern& pattern : unit.Patterns) {
                auto textmate = ToTextMatePattern(unit, pattern);
                root["repository"][name]["patterns"].AppendValue(std::move(textmate));
            }

            if (auto textmate = TextMateMultilinePattern(unit)) {
                root["repository"][name]["patterns"].AppendValue(*textmate);
            }
        }

        Print(out, root);
    }

} // namespace NSQLHighlight