diff options
| author | vitya-smirnov <[email protected]> | 2025-07-31 14:54:51 +0300 |
|---|---|---|
| committer | vitya-smirnov <[email protected]> | 2025-07-31 15:11:42 +0300 |
| commit | 9987028f33c53b335e33a2a52f58cfad1cf558f3 (patch) | |
| tree | 051eec252c5439dce098d3f38b750bc93fbabdda | |
| parent | be28619189eb153f4454ec29cfb94e0359a1838c (diff) | |
YQL-19616: Generate YQL TextMate Bundle
- Introduced the Generator interface.
- Made tool to generate content to stdout and file.
- Supported TextMate Bundle, tested on IDEA and TextMate.
- Fixed UDF highlighting priority.
commit_hash:bcbc446a2fe58da3400f0e981a03d821b8f77dae
16 files changed, 471 insertions, 201 deletions
diff --git a/yql/essentials/sql/v1/highlight/sql_highlight.cpp b/yql/essentials/sql/v1/highlight/sql_highlight.cpp index 97cd0e2f8ce..ea82a43e0d0 100644 --- a/yql/essentials/sql/v1/highlight/sql_highlight.cpp +++ b/yql/essentials/sql/v1/highlight/sql_highlight.cpp @@ -245,11 +245,11 @@ namespace NSQLHighlight { THighlighting h; h.Units.emplace_back(MakeUnit<EUnitKind::Comment>(s)); h.Units.emplace_back(MakeUnit<EUnitKind::Punctuation>(s)); + h.Units.emplace_back(MakeUnit<EUnitKind::FunctionIdentifier>(s)); h.Units.emplace_back(MakeUnit<EUnitKind::TypeIdentifier>(s)); h.Units.emplace_back(MakeUnit<EUnitKind::Keyword>(s)); h.Units.emplace_back(MakeUnit<EUnitKind::QuotedIdentifier>(s)); h.Units.emplace_back(MakeUnit<EUnitKind::BindParameterIdentifier>(s)); - h.Units.emplace_back(MakeUnit<EUnitKind::FunctionIdentifier>(s)); h.Units.emplace_back(MakeUnit<EUnitKind::Identifier>(s)); h.Units.emplace_back(MakeUnit<EUnitKind::Literal>(s)); h.Units.emplace_back(MakeUnit<EUnitKind::StringLiteral>(s)); diff --git a/yql/essentials/sql/v1/highlight/ut/suite.json b/yql/essentials/sql/v1/highlight/ut/suite.json index 04e961a6f91..26fb2f3f4f4 100644 --- a/yql/essentials/sql/v1/highlight/ut/suite.json +++ b/yql/essentials/sql/v1/highlight/ut/suite.json @@ -47,11 +47,11 @@ ["SELECT id, alias from users", "KKKKKK#_#II#P#_#IIIII#_#KKKK#_#IIIII"], ["INSERT INTO users (id, alias) VALUES (12, \"tester\")", "KKKKKK#_#KKKK#_#IIIII#_#P#II#P#_#IIIII#P#_#KKKKKK#_#P#LL#P#_#SSSSSSSS#P"], ["SELECT 123467, \"HeLLo, {name}!\", (1 + (5 * 1 / 0)), MIN(identifier) FROM `local/test/space/table` JOIN test;", "KKKKKK#_#LLLLLL#P#_#SSSSSSSSSSSSSSSS#P#_#P#L#_#P#_#P#L#_#P#_#L#_#P#_#L#P#P#P#_#FFF#P#IIIIIIIIII#P#_#KKKK#_#QQQQQQQQQQQQQQQQQQQQQQQQ#_#KKKK#_#IIII#P"], - ["SELECT Bool(phone) FROM customer", "KKKKKK#_#TTTT#P#IIIII#P#_#KKKK#_#IIIIIIII"] + ["SELECT Bool(phone) FROM customer", "KKKKKK#_#FFFF#P#IIIII#P#_#KKKK#_#IIIIIIII"] ], "TypeIdentifier": [ ["Bool", "TTTT"], - ["Bool(value)", "TTTT#P#IIIII#P"] + ["Bool(value)", "FFFF#P#IIIII#P"] ], "Identifier": [ ["test", "IIII"] diff --git a/yql/essentials/tools/yql_highlight/artifact/ya.make b/yql/essentials/tools/yql_highlight/artifact/ya.make index cb3d1c0d464..b9d54aefba3 100644 --- a/yql/essentials/tools/yql_highlight/artifact/ya.make +++ b/yql/essentials/tools/yql_highlight/artifact/ya.make @@ -6,8 +6,8 @@ RUN_PROGRAM( ) RUN_PROGRAM( - yql/essentials/tools/yql_highlight --generate="textmate" - STDOUT yql.tmLanguage.json + yql/essentials/tools/yql_highlight --generate="tmlanguage" + STDOUT YQL.tmLanguage.json ) RUN_PROGRAM( @@ -15,4 +15,14 @@ RUN_PROGRAM( STDOUT yql_new.vim ) +RUN_PROGRAM( + yql/essentials/tools/yql_highlight --generate="tmbundle" --output="${BINDIR}/YQL.tmbundle.zip" + OUT ${BINDIR}/YQL.tmbundle.zip +) + +RUN_PROGRAM( + yql/essentials/tools/yql_highlight --generate="tmbundle" --output="${BINDIR}/YQL.tmbundle.tar" + OUT ${BINDIR}/YQL.tmbundle.tar +) + END() diff --git a/yql/essentials/tools/yql_highlight/generate_textmate.cpp b/yql/essentials/tools/yql_highlight/generate_textmate.cpp deleted file mode 100644 index 28244c323d4..00000000000 --- a/yql/essentials/tools/yql_highlight/generate_textmate.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#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 diff --git a/yql/essentials/tools/yql_highlight/generate_textmate.h b/yql/essentials/tools/yql_highlight/generate_textmate.h deleted file mode 100644 index ac2c32f50c4..00000000000 --- a/yql/essentials/tools/yql_highlight/generate_textmate.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include <yql/essentials/sql/v1/highlight/sql_highlight.h> - -#include <util/stream/output.h> - -namespace NSQLHighlight { - - void GenerateTextMate(IOutputStream& out, const THighlighting& highlighting); - -} // namespace NSQLHighlight diff --git a/yql/essentials/tools/yql_highlight/generate_vim.h b/yql/essentials/tools/yql_highlight/generate_vim.h deleted file mode 100644 index 54d8e8b41eb..00000000000 --- a/yql/essentials/tools/yql_highlight/generate_vim.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include <yql/essentials/sql/v1/highlight/sql_highlight.h> - -#include <util/stream/output.h> - -namespace NSQLHighlight { - - void GenerateVim(IOutputStream& out, const THighlighting& highlighting); - -} // namespace NSQLHighlight diff --git a/yql/essentials/tools/yql_highlight/generator.cpp b/yql/essentials/tools/yql_highlight/generator.cpp new file mode 100644 index 00000000000..16a95a60beb --- /dev/null +++ b/yql/essentials/tools/yql_highlight/generator.cpp @@ -0,0 +1,31 @@ +#include "generator.h" + +#include <util/stream/file.h> + +namespace NSQLHighlight { + + class TOnlyFunctionGenerator: public IGenerator { + public: + explicit TOnlyFunctionGenerator(std::function<void(IOutputStream&, const THighlighting&)> function) + : Function_(std::move(function)) + { + } + + void Write(IOutputStream& out, const THighlighting& highlighting) override { + Function_(out, highlighting); + } + + void Write(const TFsPath& path, const THighlighting& highlighting) override { + TFileOutput out(path); + Write(out, highlighting); + } + + private: + std::function<void(IOutputStream&, const THighlighting&)> Function_; + }; + + IGenerator::TPtr MakeOnlyFileGenerator(std::function<void(IOutputStream&, const THighlighting&)> function) { + return new TOnlyFunctionGenerator(std::move(function)); + } + +} // namespace NSQLHighlight diff --git a/yql/essentials/tools/yql_highlight/generator.h b/yql/essentials/tools/yql_highlight/generator.h new file mode 100644 index 00000000000..2d90e9e2c88 --- /dev/null +++ b/yql/essentials/tools/yql_highlight/generator.h @@ -0,0 +1,20 @@ +#pragma once + +#include <yql/essentials/sql/v1/highlight/sql_highlight.h> + +#include <util/generic/ptr.h> +#include <util/folder/path.h> + +namespace NSQLHighlight { + + class IGenerator: public TThrRefBase { + public: + using TPtr = TIntrusivePtr<IGenerator>; + + virtual void Write(IOutputStream& out, const THighlighting& highlighting) = 0; + virtual void Write(const TFsPath& path, const THighlighting& highlighting) = 0; + }; + + IGenerator::TPtr MakeOnlyFileGenerator(std::function<void(IOutputStream&, const THighlighting&)> function); + +} // namespace NSQLHighlight diff --git a/yql/essentials/tools/yql_highlight/generator_json.cpp b/yql/essentials/tools/yql_highlight/generator_json.cpp new file mode 100644 index 00000000000..1d503b54d42 --- /dev/null +++ b/yql/essentials/tools/yql_highlight/generator_json.cpp @@ -0,0 +1,15 @@ +#include "generator_json.h" + +#include "json.h" + +#include <yql/essentials/sql/v1/highlight/sql_highlight_json.h> + +namespace NSQLHighlight { + + IGenerator::TPtr MakeJsonGenerator() { + return MakeOnlyFileGenerator([](IOutputStream& out, const THighlighting& highlighting) { + Print(out, ToJson(highlighting)); + }); + } + +} // namespace NSQLHighlight diff --git a/yql/essentials/tools/yql_highlight/generator_json.h b/yql/essentials/tools/yql_highlight/generator_json.h new file mode 100644 index 00000000000..24f09041ff5 --- /dev/null +++ b/yql/essentials/tools/yql_highlight/generator_json.h @@ -0,0 +1,9 @@ +#pragma once + +#include "generator.h" + +namespace NSQLHighlight { + + IGenerator::TPtr MakeJsonGenerator(); + +} // namespace NSQLHighlight diff --git a/yql/essentials/tools/yql_highlight/generator_textmate.cpp b/yql/essentials/tools/yql_highlight/generator_textmate.cpp new file mode 100644 index 00000000000..7a0a66c0e3d --- /dev/null +++ b/yql/essentials/tools/yql_highlight/generator_textmate.cpp @@ -0,0 +1,301 @@ +#include "generator_textmate.h" + +#include "json.h" + +#include <library/cpp/json/json_value.h> +#include <library/cpp/json/json_writer.h> +#include <library/cpp/on_disk/tar_archive/archive_writer.h> + +#include <util/string/builder.h> +#include <util/string/cast.h> +#include <util/memory/blob.h> + +namespace NSQLHighlight { + + namespace NTextMate { + + using TRegex = TString; + + struct TRange { + TRegex Begin; + TRegex End; + }; + + struct TMatcher { + TString Name; + TString Group; + std::variant<TRegex, TRange> Pattern; + }; + + struct TLanguage { + TString Name; + TString ScopeName; + TVector<TString> FileTypes; + TVector<TMatcher> Matchers; + }; + + } // namespace NTextMate + + namespace { + + NTextMate::TRegex 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; + } + + TString 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 ""; + } + } + + TString ToTextMateName(EUnitKind kind) { + return ToString(kind); + } + + TMaybe<NTextMate::TMatcher> TextMateMultilinePattern(const TUnit& unit) { + auto range = unit.RangePattern; + if (!range) { + return Nothing(); + } + + return NTextMate::TMatcher{ + .Name = ToTextMateName(unit.Kind), + .Group = ToTextMateGroup(unit.Kind), + .Pattern = NTextMate::TRange{ + .Begin = range->Begin, + .End = range->End, + }, + }; + } + + NTextMate::TMatcher ToTextMatePattern(const TUnit& unit, const NSQLTranslationV1::TRegexPattern& pattern) { + return NTextMate::TMatcher{ + .Name = ToTextMateName(unit.Kind), + .Group = ToTextMateGroup(unit.Kind), + .Pattern = ToTextMateRegex(unit, pattern), + }; + } + + } // namespace + + NTextMate::TLanguage ToTextMateLanguage(const THighlighting& highlighting) { + NTextMate::TLanguage language = { + .Name = "YQL", + .ScopeName = "source.yql", + .FileTypes = {"yql"}, + }; + + for (const TUnit& unit : highlighting.Units) { + if (unit.IsCodeGenExcluded) { + continue; + } + + for (const NSQLTranslationV1::TRegexPattern& pattern : unit.Patterns) { + language.Matchers.emplace_back(ToTextMatePattern(unit, pattern)); + } + if (auto textmate = TextMateMultilinePattern(unit)) { + language.Matchers.emplace_back(*textmate); + } + } + + return language; + } + + NJson::TJsonValue ToJson(const NTextMate::TMatcher& matcher) { + NJson::TJsonMap json = {{"name", matcher.Group}}; + std::visit([&](const auto& pattern) { + using T = std::decay_t<decltype(pattern)>; + + if constexpr (std::is_same_v<T, NTextMate::TRegex>) { + json["match"] = pattern; + } else if constexpr (std::is_same_v<T, NTextMate::TRange>) { + json["begin"] = pattern.Begin; + json["end"] = pattern.End; + } else { + static_assert(false); + } + }, matcher.Pattern); + return json; + } + + NJson::TJsonValue ToJson(const NTextMate::TLanguage& language) { + NJson::TJsonMap root; + root["$schema"] = "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json"; + root["name"] = language.Name; + root["scopeName"] = language.ScopeName; + + for (const TString& type : language.FileTypes) { + root["fileTypes"].AppendValue(type); + } + + THashSet<TString> visited; + for (const NTextMate::TMatcher& matcher : language.Matchers) { + root["repository"][matcher.Name]["patterns"].AppendValue(ToJson(matcher)); + + if (!visited.contains(matcher.Name)) { + root["patterns"].AppendValue(NJson::TJsonMap({{"include", "#" + matcher.Name}})); + visited.emplace(matcher.Name); + } + } + + return root; + } + + TString EscapeXML(TString string) { + SubstGlobal(string, "<", "<"); + SubstGlobal(string, ">", ">"); + return string; + } + + void WriteXML(IOutputStream& out, const NJson::TJsonValue& json, TString indent = "") { + static constexpr TStringBuf extra = " "; + + if (TString string; json.GetString(&string)) { + out << indent << "<string>" << EscapeXML(string) << "</string>" << "\n"; + } else if (NJson::TJsonValue::TMapType dict; json.GetMap(&dict)) { + out << indent << "<dict>" << '\n'; + for (const auto& [key, value] : dict) { + out << indent << extra << "<key>" << EscapeXML(key) << "</key>" << '\n'; + WriteXML(out, value, indent + extra); + } + out << indent << "</dict>" << '\n'; + } else if (NJson::TJsonValue::TArray array; json.GetArray(&array)) { + out << indent << "<array>" << '\n'; + for (const auto& value : array) { + WriteXML(out, value, indent + extra); + } + out << indent << "</array>" << '\n'; + } else { + TStringStream str; + Print(str, json); + ythrow yexception() << "Unexpected JSON '" + str.Str() + "'"; + } + } + + void GenerateTextMateJson(IOutputStream& out, const THighlighting& highlighting) { + Print(out, ToJson(ToTextMateLanguage(highlighting))); + } + + class TTextMateBundleGenerator: public IGenerator { + private: + static constexpr TStringBuf InfoUUID = "9BB0DBAF-E65C-4E14-A6A7-467D4AA535E0"; + static constexpr TStringBuf SyntaxUUID = "1C3868E4-F96B-4E55-B204-1DCB5A20748B"; + static constexpr TStringBuf BundleDir = "YQL.tmbundle"; + static constexpr TStringBuf InfoFile = "info.plist"; + static constexpr TStringBuf SyntaxFile = "Syntaxes/YQL.tmLanguage"; + + template <class TWriter> + void Write( + NTar::TArchiveWriter& acrhive, + TStringBuf path, + TWriter writer, + const NTextMate::TLanguage& langugage) + { + TStringStream stream; + writer(stream, langugage); + TBlob blob = TBlob::FromString(stream.Str()); + acrhive.WriteFile(TString(path), blob); + } + + public: + void Write(IOutputStream& out, const THighlighting& highlighting) final { + out << "File " << BundleDir << "/" << InfoFile << ":" << '\n'; + WriteInfo(out, ToTextMateLanguage(highlighting)); + out << "File " << BundleDir << "/" << SyntaxFile << ":" << '\n'; + WriteSyntax(out, ToTextMateLanguage(highlighting)); + } + + void Write(const TFsPath& path, const THighlighting& highlighting) final { + if (TString name = path.GetName(); !name.StartsWith(BundleDir)) { + ythrow yexception() + << "Invalid path '" << name + << "', expected '" << BundleDir << "' " + << "as an archive name"; + } + + NTextMate::TLanguage language = ToTextMateLanguage(highlighting); + + NTar::TArchiveWriter archive(path); + Write(archive, InfoFile, WriteInfo, language); + Write(archive, SyntaxFile, WriteSyntax, language); + } + + private: + static void WriteInfo(IOutputStream& out, const NTextMate::TLanguage& language) { + out << R"(<?xml version="1.0" encoding="UTF-8"?>)" << '\n'; + out << R"(<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">)" << '\n'; + out << R"(<plist version="1.0">)" << '\n'; + out << R"(<dict>)" << '\n'; + out << R"( <key>name</key>)" << '\n'; + out << R"( <string>)" << language.Name << R"(</string>)" << '\n'; + out << R"( <key>uuid</key>)" << '\n'; + out << R"( <string>)" << InfoUUID << R"(</string>)" << '\n'; + out << R"(</dict>)" << '\n'; + out << R"(</plist>)" << '\n'; + } + + static void WriteSyntax(IOutputStream& out, const NTextMate::TLanguage& language) { + NJson::TJsonValue json = ToJson(language); + json.EraseValue("$schema"); + json["uuid"] = SyntaxUUID; + + out << R"(<?xml version="1.0" encoding="UTF-8"?>)" << '\n'; + out << R"(<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">)" << '\n'; + out << R"(<plist version="1.0">)" << '\n'; + WriteXML(out, json); + out << R"(</plist>)" << '\n'; + } + }; + + IGenerator::TPtr MakeTextMateJsonGenerator() { + return MakeOnlyFileGenerator(GenerateTextMateJson); + } + + IGenerator::TPtr MakeTextMateBundleGenerator() { + return new TTextMateBundleGenerator(); + } + +} // namespace NSQLHighlight diff --git a/yql/essentials/tools/yql_highlight/generator_textmate.h b/yql/essentials/tools/yql_highlight/generator_textmate.h new file mode 100644 index 00000000000..d1ffbac87a2 --- /dev/null +++ b/yql/essentials/tools/yql_highlight/generator_textmate.h @@ -0,0 +1,11 @@ +#pragma once + +#include "generator.h" + +namespace NSQLHighlight { + + IGenerator::TPtr MakeTextMateJsonGenerator(); + + IGenerator::TPtr MakeTextMateBundleGenerator(); + +} // namespace NSQLHighlight diff --git a/yql/essentials/tools/yql_highlight/generate_vim.cpp b/yql/essentials/tools/yql_highlight/generator_vim.cpp index e914b5c6e32..bb33157ce2e 100644 --- a/yql/essentials/tools/yql_highlight/generate_vim.cpp +++ b/yql/essentials/tools/yql_highlight/generator_vim.cpp @@ -1,4 +1,4 @@ -#include "generate_vim.h" +#include "generator_vim.h" #include <yql/essentials/utils/yql_panic.h> @@ -165,4 +165,8 @@ namespace NSQLHighlight { out.Flush(); } + IGenerator::TPtr MakeVimGenerator() { + return MakeOnlyFileGenerator(GenerateVim); + } + } // namespace NSQLHighlight diff --git a/yql/essentials/tools/yql_highlight/generator_vim.h b/yql/essentials/tools/yql_highlight/generator_vim.h new file mode 100644 index 00000000000..1e3927f8417 --- /dev/null +++ b/yql/essentials/tools/yql_highlight/generator_vim.h @@ -0,0 +1,9 @@ +#pragma once + +#include "generator.h" + +namespace NSQLHighlight { + + IGenerator::TPtr MakeVimGenerator(); + +} // namespace NSQLHighlight diff --git a/yql/essentials/tools/yql_highlight/ya.make b/yql/essentials/tools/yql_highlight/ya.make index c255bcef95d..710d7ff40e6 100644 --- a/yql/essentials/tools/yql_highlight/ya.make +++ b/yql/essentials/tools/yql_highlight/ya.make @@ -1,25 +1,25 @@ IF (NOT EXPORT_CMAKE OR NOT OPENSOURCE OR OPENSOURCE_PROJECT != "yt") + PROGRAM() -PROGRAM() + PEERDIR( + library/cpp/getopt + library/cpp/json + library/cpp/on_disk/tar_archive + yql/essentials/sql/v1/highlight + yql/essentials/utils + ) -PEERDIR( - library/cpp/getopt - library/cpp/json - yql/essentials/sql/v1/highlight - yql/essentials/utils -) - -SRCS( - generate_textmate.cpp - generate_vim.cpp - json.cpp - yql_highlight.cpp -) - -END() - -RECURSE( - artifact -) + SRCS( + generator_json.cpp + generator_textmate.cpp + generator_vim.cpp + generator.cpp + json.cpp + yql_highlight.cpp + ) + END() + RECURSE( + artifact + ) ENDIF() diff --git a/yql/essentials/tools/yql_highlight/yql_highlight.cpp b/yql/essentials/tools/yql_highlight/yql_highlight.cpp index ed651881325..4361ee6e106 100644 --- a/yql/essentials/tools/yql_highlight/yql_highlight.cpp +++ b/yql/essentials/tools/yql_highlight/yql_highlight.cpp @@ -1,8 +1,7 @@ -#include "generate_textmate.h" -#include "generate_vim.h" -#include "json.h" +#include "generator_json.h" +#include "generator_textmate.h" +#include "generator_vim.h" -#include <yql/essentials/sql/v1/highlight/sql_highlight_json.h> #include <yql/essentials/sql/v1/highlight/sql_highlight.h> #include <yql/essentials/sql/v1/highlight/sql_highlighter.h> @@ -14,23 +13,24 @@ using namespace NSQLHighlight; -int RunGenerateJSON() { - THighlighting highlighting = MakeHighlighting(); - Print(Cout, ToJson(highlighting)); - return 0; -} +using TGeneratorFactory = std::function<IGenerator::TPtr()>; -int RunGenerateTextMate() { - THighlighting highlighting = MakeHighlighting(); - GenerateTextMate(Cout, highlighting); - return 0; -} +using TGeneratorMap = THashMap<TString, TGeneratorFactory>; -int RunGenerateVim() { - THighlighting highlighting = MakeHighlighting(); - GenerateVim(Cout, highlighting); - return 0; -} +const TGeneratorMap generators = { + {"json", MakeJsonGenerator}, + {"tmlanguage", MakeTextMateJsonGenerator}, + {"tmbundle", MakeTextMateBundleGenerator}, + {"vim", MakeVimGenerator}, +}; + +const TVector<TString> targets = []() { + TVector<TString> result; + for (const auto& [name, _] : generators) { + result.push_back(name); + } + return result; +}(); int RunHighlighter() { THashMap<EUnitKind, NColorizer::EAnsiCode> ColorByKind = { @@ -64,28 +64,34 @@ int RunHighlighter() { int Run(int argc, char* argv[]) { TString target; + TString path; NLastGetopt::TOpts opts = NLastGetopt::TOpts::Default(); opts.AddLongOption('g', "generate", "generate a highlighting configuration") .RequiredArgument("target") - .Choices({"json", "textmate", "vim"}) + .Choices(targets) .StoreResult(&target); + opts.AddLongOption('o', "output", "path to output file") + .OptionalArgument("path") + .StoreResult(&path); opts.SetFreeArgsNum(0); opts.AddHelpOption(); NLastGetopt::TOptsParseResult res(&opts, argc, argv); if (res.Has("generate")) { - if (target == "json") { - return RunGenerateJSON(); - } - if (target == "textmate") { - return RunGenerateTextMate(); + const TGeneratorFactory* generator = generators.FindPtr(target); + Y_ENSURE(generator, "No generator for target '" << target << "'"); + + if (res.Has("output")) { + TFsPath stdpath(path.c_str()); + (*generator)()->Write(stdpath, MakeHighlighting()); + } else { + (*generator)()->Write(Cout, MakeHighlighting()); } - if (target == "vim") { - return RunGenerateVim(); - } - Y_ABORT(); + + return 0; } + return RunHighlighter(); } |
