summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-piglet <[email protected]>2025-09-01 18:37:05 +0300
committerrobot-piglet <[email protected]>2025-09-01 19:06:57 +0300
commit6f768e78a7bbc89778e9b2764e7f85bdeb64f034 (patch)
treeb7d88b0f418957da9eee57a85c81edefe83990f2
parenta8b4824e60974c2562979da8a101385095519b1d (diff)
Intermediate changes
commit_hash:1623077a586fe91fb5d853b4efee5d1e623189cb
-rw-r--r--build/external_resources/ruff/resources.json16
-rw-r--r--build/external_resources/ruff/ya.make5
-rw-r--r--library/python/find_root/README.md9
-rw-r--r--library/python/find_root/__init__.py33
-rw-r--r--library/python/find_root/ya.make4
-rw-r--r--tools/ruff_linter/bin/__main__.py161
-rw-r--r--tools/ruff_linter/bin/ya.make15
-rw-r--r--yql/essentials/tools/yql_highlight/artifact/ya.make5
-rw-r--r--yql/essentials/tools/yql_highlight/generator.cpp14
-rw-r--r--yql/essentials/tools/yql_highlight/generator.h8
-rw-r--r--yql/essentials/tools/yql_highlight/generator_highlight_js.cpp2
-rw-r--r--yql/essentials/tools/yql_highlight/generator_json.cpp2
-rw-r--r--yql/essentials/tools/yql_highlight/generator_monarch.cpp30
-rw-r--r--yql/essentials/tools/yql_highlight/generator_textmate.cpp6
-rw-r--r--yql/essentials/tools/yql_highlight/generator_vim.cpp2
-rw-r--r--yql/essentials/tools/yql_highlight/yql_highlight.cpp19
16 files changed, 300 insertions, 31 deletions
diff --git a/build/external_resources/ruff/resources.json b/build/external_resources/ruff/resources.json
new file mode 100644
index 00000000000..7bab23868b2
--- /dev/null
+++ b/build/external_resources/ruff/resources.json
@@ -0,0 +1,16 @@
+{
+ "by_platform": {
+ "darwin-arm64": {
+ "uri": "sbr:8282760403"
+ },
+ "darwin-x86_64": {
+ "uri": "sbr:8283225479"
+ },
+ "linux-x86_64": {
+ "uri": "sbr:8282728054"
+ },
+ "win32-x86_64": {
+ "uri": "sbr:8283116250"
+ }
+ }
+}
diff --git a/build/external_resources/ruff/ya.make b/build/external_resources/ruff/ya.make
new file mode 100644
index 00000000000..f0f09166615
--- /dev/null
+++ b/build/external_resources/ruff/ya.make
@@ -0,0 +1,5 @@
+RESOURCES_LIBRARY()
+
+DECLARE_EXTERNAL_HOST_RESOURCES_BUNDLE_BY_JSON(RUFF resources.json)
+
+END()
diff --git a/library/python/find_root/README.md b/library/python/find_root/README.md
new file mode 100644
index 00000000000..9a370d2f2ff
--- /dev/null
+++ b/library/python/find_root/README.md
@@ -0,0 +1,9 @@
+# find_root
+
+A simple library for Arcadia root detection.
+
+Простая библиотека для обнаружения корня Аркадии.
+
+Имеется два варианта детектора:
+- каноническая версия `detect_root` (смотрит только на файловую систему)
+- расширенная `get_arcadia_root` + `try_get_arcadia_root` (смотрит на переменные окружения)
diff --git a/library/python/find_root/__init__.py b/library/python/find_root/__init__.py
index 6da604d62e1..5cf6625ad95 100644
--- a/library/python/find_root/__init__.py
+++ b/library/python/find_root/__init__.py
@@ -18,3 +18,36 @@ def _find_path(starts_from, check):
if next_p == p:
return None
p = next_p
+
+
+def try_get_arcadia_root(start_path=os.path.abspath(__file__)):
+ """
+ Extended Arcadia root lookup: use various env vars
+ :param start_path: initial path for lookup
+ Obtain Arcadia root or **empty string** when arcadia root cannot be found.
+ """
+ env_root = os.getenv("ARCADIA_ROOT")
+ if env_root:
+ return env_root
+
+ path = start_path
+ while path != "/" and not os.path.exists(os.path.join(path, ".arcadia.root")):
+ path = os.path.dirname(path)
+
+ # if after all, we reached root, try to check up from ya path
+ # env variable "_" contains path to ya
+ if path == "/" and start_path == os.path.abspath(__file__):
+ path = try_get_arcadia_root(os.path.dirname(os.getenv("_")))
+
+ return path if path != "/" else ""
+
+
+def get_arcadia_root(start_path=os.path.abspath(__file__)):
+ """
+ :param start_path: initial path for lookup
+ Obtain Arcadia root or raise exception when root cannot be found.
+ """
+ arcadia_root = try_get_arcadia_root(start_path=start_path)
+ if not arcadia_root:
+ raise Exception("Cannot find Arcadia root")
+ return arcadia_root
diff --git a/library/python/find_root/ya.make b/library/python/find_root/ya.make
index 35821361805..235c6295674 100644
--- a/library/python/find_root/ya.make
+++ b/library/python/find_root/ya.make
@@ -1,5 +1,7 @@
PY23_LIBRARY()
-PY_SRCS(__init__.py)
+ALL_PY_SRCS()
+
+STYLE_RUFF()
END()
diff --git a/tools/ruff_linter/bin/__main__.py b/tools/ruff_linter/bin/__main__.py
new file mode 100644
index 00000000000..aa8038c9d9a
--- /dev/null
+++ b/tools/ruff_linter/bin/__main__.py
@@ -0,0 +1,161 @@
+import logging
+import os
+import subprocess
+import time
+import tomllib
+from pathlib import Path
+
+from build.plugins.lib.test_const import RUFF_RESOURCE
+from library.python.testing.custom_linter_util import linter_params, reporter
+from library.python.testing.style import rules
+
+
+logger = logging.getLogger(__name__)
+
+FORMAT_SNIPPET_LINES_LIMIT = 100
+
+
+def get_ruff_bin(params) -> str:
+ ruff_root = params.global_resources[RUFF_RESOURCE]
+ return os.path.join(ruff_root, 'bin', 'ruff')
+
+
+def check_extend_option_present(config: Path) -> bool:
+ with config.open('rb') as afile:
+ cfg = tomllib.load(afile)
+ if config.name == 'pyproject.toml' and cfg.get('tool', {}).get('ruff'):
+ return 'extend' in cfg['tool']['ruff']
+ elif config.name == 'ruff.toml':
+ return 'extend' in cfg
+ raise RuntimeError(f'Unknown config type: {config.name}')
+
+
+def run_ruff(ruff_bin: str, cmd_args: list[str], filename: str, config: Path) -> list[str]:
+ # XXX: `--no-cache` is important because we run ruff in source root and don't want to pollute arcadia
+ cmd = [ruff_bin, *cmd_args, '--no-cache', '--config', config, filename]
+ res = subprocess.run(
+ cmd,
+ capture_output=True,
+ encoding='utf8',
+ errors='replace',
+ env=dict(os.environ.copy(), RUFF_OUTPUT_FORMAT='concise'),
+ cwd=os.path.dirname(config), # for correct support of `exclude`
+ )
+ return res.stdout.splitlines(keepends=True) if res.returncode else []
+
+
+def process_file(orig_filename: str, ruff_bin: str, orig_config: Path, source_root: str, check_format: bool) -> str:
+ logger.debug('Check %s with config %s', orig_filename, orig_config)
+
+ # In order for `exclude` option (pyproject.toml) to work we have two options:
+ # 1. Run ruff with files AND config in build root
+ # 2. Run ruff with files AND config in source root
+ # For these two options there are differences in how 1st party vs 3rd party libraries are detected: in source root
+ # we have access to the whole arcadia. Because of that PEERDIR'ed arcadia libraries are considered 1st party.
+ # In build root, on the contrary, PEERDIR'ed libraries are not available so they are considered 3rd party.
+ # In order to match `ya style` behavior which is executed as in the second case we have to go with the second option.
+ # Then we MUST make sure we don't write anything to arcadia and don't "steal" files from arcadia.
+ # From the model point of view first option is more correct but it would require marking all PEERDIR'ed libraries
+ # 3rd party in pyproject.toml (`known-third-party`).
+
+ file_path = os.path.relpath(orig_filename, source_root)
+
+ if file_path.startswith(('fintech/uservices', 'taxi', 'sdg', 'electro')):
+ # TODO(alevitskii) TPS-28865, TPS-31380. Run checks for fintech and taxi in build root too.
+ # TODO(alevitskii): have to give a pass for sdg, because they started using `extend`...
+ filename = os.path.realpath(orig_filename) if os.path.islink(orig_filename) else orig_filename
+ config = orig_config.resolve() if orig_config.is_symlink() else orig_config
+ else:
+ filename = orig_filename
+ config = orig_config
+
+ if check_format:
+ ruff_format_check_out = run_ruff(ruff_bin, ['format', '--diff'], filename, config)
+ if len(ruff_format_check_out) > FORMAT_SNIPPET_LINES_LIMIT:
+ ruff_format_check_out = ruff_format_check_out[:FORMAT_SNIPPET_LINES_LIMIT]
+ ruff_format_check_out.append('[truncated]...\n')
+ # first two lines are absolute file paths, replace with relative ones
+ if ruff_format_check_out:
+ ruff_format_check_out[0] = f'--- [[imp]]{file_path}[[rst]]\n'
+ ruff_format_check_out[1] = f'+++ [[imp]]{file_path}[[rst]]\n'
+ else:
+ ruff_format_check_out = []
+
+ ruff_check_out = run_ruff(ruff_bin, ['check', '-q'], filename, config)
+ # Every line starts with an absolute path to a file, replace with relative one
+ for idx, line in enumerate(ruff_check_out):
+ ruff_check_out[idx] = f'[[imp]]{file_path}[[rst]]:{line.split(':', 1)[-1]}'
+
+ msg = ''
+ if ruff_format_check_out:
+ msg += '[[bad]]Formatting errors[[rst]]:\n'
+ msg += ''.join(ruff_format_check_out)
+
+ if ruff_format_check_out and ruff_check_out:
+ msg += '\n'
+
+ if ruff_check_out:
+ msg += '[[bad]]Linting errors[[rst]]:\n'
+ msg += ''.join(ruff_check_out)
+
+ return msg
+
+
+def main():
+ params = linter_params.get_params()
+
+ style_config_path = Path(params.configs[0])
+
+ # TODO To enable `extend` we first need to fully move execution to build root (src files + configs)
+ # otherwise we risk allowing to steal from arcadia. To do that we need to mark modules 1st-party/3rd-party
+ # in pyproject.toml.
+ extend_option_present = check_extend_option_present(style_config_path)
+ # TODO(alevitskii): sdg is an unfortunate victim of an oversight, we need to fix it
+ is_sdg = str(style_config_path.relative_to(params.source_root)).startswith('sdg')
+
+ ruff_bin = get_ruff_bin(params)
+
+ report = reporter.LintReport()
+ for file_name in params.files:
+ start_time = time.time()
+
+ if extend_option_present and not is_sdg:
+ elapsed = time.time() - start_time
+ report.add(
+ file_name,
+ reporter.LintStatus.FAIL,
+ "`extend` option in not supported in ruff config files for now. Modify your configs not to have it.",
+ elapsed=elapsed,
+ )
+ continue
+
+ skip_reason = rules.get_skip_reason(file_name, Path(file_name).read_text(), skip_links=False)
+ if skip_reason:
+ elapsed = time.time() - start_time
+ report.add(
+ file_name,
+ reporter.LintStatus.SKIPPED,
+ f"Style check is omitted: {skip_reason}",
+ elapsed=elapsed,
+ )
+ continue
+
+ error = process_file(
+ file_name, ruff_bin, style_config_path, params.source_root, params.extra_params.get('check_format') == 'yes'
+ )
+ elapsed = time.time() - start_time
+
+ if error:
+ rel_file_name = os.path.relpath(file_name, params.source_root)
+ message = f'Run [[imp]]ya style --ruff {rel_file_name}[[rst]] to fix format\n{error}'
+ status = reporter.LintStatus.FAIL
+ else:
+ message = ''
+ status = reporter.LintStatus.GOOD
+ report.add(file_name, status, message, elapsed=elapsed)
+
+ report.dump(params.report_file)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/ruff_linter/bin/ya.make b/tools/ruff_linter/bin/ya.make
new file mode 100644
index 00000000000..fd89609321f
--- /dev/null
+++ b/tools/ruff_linter/bin/ya.make
@@ -0,0 +1,15 @@
+PY3_PROGRAM(ruff_linter)
+
+STYLE_PYTHON()
+
+PEERDIR(
+ build/plugins/lib/test_const
+ library/python/testing/custom_linter_util
+ library/python/testing/style
+)
+
+PY_SRCS(
+ __main__.py
+)
+
+END()
diff --git a/yql/essentials/tools/yql_highlight/artifact/ya.make b/yql/essentials/tools/yql_highlight/artifact/ya.make
index f288dd14e85..ec20e685ec1 100644
--- a/yql/essentials/tools/yql_highlight/artifact/ya.make
+++ b/yql/essentials/tools/yql_highlight/artifact/ya.make
@@ -21,6 +21,11 @@ RUN_PROGRAM(
)
RUN_PROGRAM(
+ yql/essentials/tools/yql_highlight --language="yql" --generate="monarch" --mode="ansi"
+ STDOUT YQL.ansi.monarch.json
+)
+
+RUN_PROGRAM(
yql/essentials/tools/yql_highlight --language="yqls" --generate="monarch"
STDOUT YQLs.monarch.json
)
diff --git a/yql/essentials/tools/yql_highlight/generator.cpp b/yql/essentials/tools/yql_highlight/generator.cpp
index 16a95a60beb..45f95624760 100644
--- a/yql/essentials/tools/yql_highlight/generator.cpp
+++ b/yql/essentials/tools/yql_highlight/generator.cpp
@@ -6,25 +6,25 @@ namespace NSQLHighlight {
class TOnlyFunctionGenerator: public IGenerator {
public:
- explicit TOnlyFunctionGenerator(std::function<void(IOutputStream&, const THighlighting&)> function)
+ explicit TOnlyFunctionGenerator(TGeneratorFunction function)
: Function_(std::move(function))
{
}
- void Write(IOutputStream& out, const THighlighting& highlighting) override {
- Function_(out, highlighting);
+ void Write(IOutputStream& out, const THighlighting& highlighting, bool ansi) override {
+ Function_(out, highlighting, ansi);
}
- void Write(const TFsPath& path, const THighlighting& highlighting) override {
+ void Write(const TFsPath& path, const THighlighting& highlighting, bool ansi) override {
TFileOutput out(path);
- Write(out, highlighting);
+ Write(out, highlighting, ansi);
}
private:
- std::function<void(IOutputStream&, const THighlighting&)> Function_;
+ TGeneratorFunction Function_;
};
- IGenerator::TPtr MakeOnlyFileGenerator(std::function<void(IOutputStream&, const THighlighting&)> function) {
+ IGenerator::TPtr MakeOnlyFileGenerator(TGeneratorFunction function) {
return new TOnlyFunctionGenerator(std::move(function));
}
diff --git a/yql/essentials/tools/yql_highlight/generator.h b/yql/essentials/tools/yql_highlight/generator.h
index 2d90e9e2c88..83341276ef9 100644
--- a/yql/essentials/tools/yql_highlight/generator.h
+++ b/yql/essentials/tools/yql_highlight/generator.h
@@ -11,10 +11,12 @@ namespace NSQLHighlight {
public:
using TPtr = TIntrusivePtr<IGenerator>;
- virtual void Write(IOutputStream& out, const THighlighting& highlighting) = 0;
- virtual void Write(const TFsPath& path, const THighlighting& highlighting) = 0;
+ virtual void Write(IOutputStream& out, const THighlighting& highlighting, bool ansi) = 0;
+ virtual void Write(const TFsPath& path, const THighlighting& highlighting, bool ansi) = 0;
};
- IGenerator::TPtr MakeOnlyFileGenerator(std::function<void(IOutputStream&, const THighlighting&)> function);
+ using TGeneratorFunction = std::function<void(IOutputStream&, const THighlighting&, bool)>;
+
+ IGenerator::TPtr MakeOnlyFileGenerator(TGeneratorFunction function);
} // namespace NSQLHighlight
diff --git a/yql/essentials/tools/yql_highlight/generator_highlight_js.cpp b/yql/essentials/tools/yql_highlight/generator_highlight_js.cpp
index cc22b8cda08..d8673a24601 100644
--- a/yql/essentials/tools/yql_highlight/generator_highlight_js.cpp
+++ b/yql/essentials/tools/yql_highlight/generator_highlight_js.cpp
@@ -110,7 +110,7 @@ namespace NSQLHighlight {
return json;
}
- void GenerateHighlightJS(IOutputStream& out, const THighlighting& highlighting) {
+ void GenerateHighlightJS(IOutputStream& out, const THighlighting& highlighting, bool /* ansi */) {
Print(out, ToHighlightJSON(highlighting));
}
diff --git a/yql/essentials/tools/yql_highlight/generator_json.cpp b/yql/essentials/tools/yql_highlight/generator_json.cpp
index 1d503b54d42..846d2f85d2d 100644
--- a/yql/essentials/tools/yql_highlight/generator_json.cpp
+++ b/yql/essentials/tools/yql_highlight/generator_json.cpp
@@ -7,7 +7,7 @@
namespace NSQLHighlight {
IGenerator::TPtr MakeJsonGenerator() {
- return MakeOnlyFileGenerator([](IOutputStream& out, const THighlighting& highlighting) {
+ return MakeOnlyFileGenerator([](IOutputStream& out, const THighlighting& highlighting, bool /* ansi */) {
Print(out, ToJson(highlighting));
});
}
diff --git a/yql/essentials/tools/yql_highlight/generator_monarch.cpp b/yql/essentials/tools/yql_highlight/generator_monarch.cpp
index b38416c8caa..19d461a9464 100644
--- a/yql/essentials/tools/yql_highlight/generator_monarch.cpp
+++ b/yql/essentials/tools/yql_highlight/generator_monarch.cpp
@@ -88,9 +88,13 @@ namespace NSQLHighlight {
}
}
- NJson::TJsonValue ToMonarchMultiLineState(const TUnit& unit) {
+ NJson::TJsonValue ToMonarchMultiLineState(const TUnit& unit, bool ansi) {
Y_ENSURE(unit.RangePattern);
+ TString group = ToMonarchSelector(unit.Kind);
+ TString begin = RE2::QuoteMeta(unit.RangePattern->Begin);
+ TString end = RE2::QuoteMeta(unit.RangePattern->End);
+
NJson::TJsonValue json;
if (unit.Kind == EUnitKind::StringLiteral) {
@@ -112,15 +116,13 @@ namespace NSQLHighlight {
{"goBack", 4},
},
});
+ } else if (unit.Kind == EUnitKind::Comment && ansi) {
+ json.AppendValue(NJson::TJsonArray{begin, group, "@" + group});
}
- TString group = ToMonarchSelector(unit.Kind);
- TString begin = RE2::QuoteMeta(unit.RangePattern->Begin);
- TString end = RE2::QuoteMeta(unit.RangePattern->End);
-
json.AppendValue(NJson::TJsonArray{"[^" + begin + "]", group});
json.AppendValue(NJson::TJsonArray{end, group, "@pop"});
- json.AppendValue(NJson::TJsonArray{"[" + begin + "]", group});
+ json.AppendValue(NJson::TJsonArray{begin, group});
return json;
}
@@ -156,7 +158,7 @@ namespace NSQLHighlight {
return json;
}
- NJson::TJsonValue ToMonarchRootState(const THighlighting& highlighting) {
+ NJson::TJsonValue ToMonarchRootState(const THighlighting& highlighting, bool ansi) {
NJson::TJsonValue json;
json.AppendValue(NJson::TJsonMap{{"include", "@whitespace"}});
for (const TUnit& unit : highlighting.Units) {
@@ -165,7 +167,13 @@ namespace NSQLHighlight {
}
TString group = ToMonarchSelector(unit.Kind);
- for (const NSQLTranslationV1::TRegexPattern& pattern : unit.Patterns) {
+
+ const auto* patterns = &unit.Patterns;
+ if (!unit.PatternsANSI.Empty() && ansi) {
+ patterns = unit.PatternsANSI.Get();
+ }
+
+ for (const NSQLTranslationV1::TRegexPattern& pattern : *patterns) {
TString regex = ToMonarchRegex(unit, pattern);
json.AppendValue(NJson::TJsonArray{regex, group});
}
@@ -173,7 +181,7 @@ namespace NSQLHighlight {
return json;
}
- void GenerateMonarch(IOutputStream& out, const THighlighting& highlighting) {
+ void GenerateMonarch(IOutputStream& out, const THighlighting& highlighting, bool ansi) {
NJsonWriter::TBuf buf(NJsonWriter::HEM_DONT_ESCAPE_HTML, &out);
buf.SetIndentSpaces(4);
@@ -189,10 +197,10 @@ namespace NSQLHighlight {
buf.WriteKey("tokenizer");
buf.BeginObject();
- write_json("root", ToMonarchRootState(highlighting));
+ write_json("root", ToMonarchRootState(highlighting, ansi));
write_json("whitespace", ToMonarchWhitespaceState(highlighting));
ForEachMultiLine(highlighting, [&](const TUnit& unit) {
- write_json(ToMonarchStateName(unit.Kind), ToMonarchMultiLineState(unit));
+ write_json(ToMonarchStateName(unit.Kind), ToMonarchMultiLineState(unit, ansi));
});
write_json("embedded", MonarchEmbeddedState());
buf.EndObject();
diff --git a/yql/essentials/tools/yql_highlight/generator_textmate.cpp b/yql/essentials/tools/yql_highlight/generator_textmate.cpp
index fb9641e4723..d7e2eeb879a 100644
--- a/yql/essentials/tools/yql_highlight/generator_textmate.cpp
+++ b/yql/essentials/tools/yql_highlight/generator_textmate.cpp
@@ -231,7 +231,7 @@ namespace NSQLHighlight {
}
}
- void GenerateTextMateJson(IOutputStream& out, const THighlighting& highlighting) {
+ void GenerateTextMateJson(IOutputStream& out, const THighlighting& highlighting, bool /* ansi */) {
Print(out, ToJson(ToTextMateLanguage(highlighting)));
}
@@ -258,7 +258,7 @@ namespace NSQLHighlight {
}
public:
- void Write(IOutputStream& out, const THighlighting& highlighting) final {
+ void Write(IOutputStream& out, const THighlighting& highlighting, bool /* ansi */) final {
const auto [bundle, info, syntax] = Paths(highlighting);
out << "File " << bundle << "/" << info << ":" << '\n';
@@ -267,7 +267,7 @@ namespace NSQLHighlight {
WriteSyntax(out, ToTextMateLanguage(highlighting));
}
- void Write(const TFsPath& path, const THighlighting& highlighting) final {
+ void Write(const TFsPath& path, const THighlighting& highlighting, bool /* ansi */) final {
const auto [bundle, info, syntax] = Paths(highlighting);
if (TString name = path.GetName(); !name.StartsWith(bundle)) {
diff --git a/yql/essentials/tools/yql_highlight/generator_vim.cpp b/yql/essentials/tools/yql_highlight/generator_vim.cpp
index f56276b9a76..a709e4cba90 100644
--- a/yql/essentials/tools/yql_highlight/generator_vim.cpp
+++ b/yql/essentials/tools/yql_highlight/generator_vim.cpp
@@ -144,7 +144,7 @@ namespace NSQLHighlight {
} // namespace
- void GenerateVim(IOutputStream& out, const THighlighting& highlighting) {
+ void GenerateVim(IOutputStream& out, const THighlighting& highlighting, bool /* ansi */) {
out << "if exists(\"b:current_syntax\")" << '\n';
out << " finish" << '\n';
out << "endif" << '\n';
diff --git a/yql/essentials/tools/yql_highlight/yql_highlight.cpp b/yql/essentials/tools/yql_highlight/yql_highlight.cpp
index d871004720e..601a3ddf356 100644
--- a/yql/essentials/tools/yql_highlight/yql_highlight.cpp
+++ b/yql/essentials/tools/yql_highlight/yql_highlight.cpp
@@ -36,6 +36,11 @@ const TGeneratorMap generators = {
{"highlightjs", MakeHighlightJSGenerator},
};
+const TVector<TString> modes = {
+ "default",
+ "ansi",
+};
+
template <class TMap>
TVector<TString> Keys(const TMap& map) {
TVector<TString> result;
@@ -78,6 +83,7 @@ int Run(int argc, char* argv[]) {
TString syntax;
TString target;
TString path;
+ TString mode;
NLastGetopt::TOpts opts = NLastGetopt::TOpts::Default();
opts.AddLongOption('l', "language", "choice a syntax")
@@ -89,6 +95,11 @@ int Run(int argc, char* argv[]) {
.RequiredArgument("target")
.Choices(Keys(generators))
.StoreResult(&target);
+ opts.AddLongOption('m', "mode", "set a lexer mode")
+ .RequiredArgument("mode")
+ .Choices(modes)
+ .DefaultValue("default")
+ .StoreResult(&mode);
opts.AddLongOption('o', "output", "path to output file")
.OptionalArgument("path")
.StoreResult(&path);
@@ -100,17 +111,19 @@ int Run(int argc, char* argv[]) {
const THighlightingFactory* factory = highlightings.FindPtr(syntax);
Y_ENSURE(factory, "No highlighting for syntax '" << syntax << "'");
- THighlighting highlighting = (*factory)();
+ const THighlighting highlighting = (*factory)();
if (res.Has("generate")) {
const TGeneratorFactory* generator = generators.FindPtr(target);
Y_ENSURE(generator, "No generator for target '" << target << "'");
+ const bool ansi = (mode == "ansi");
+
if (res.Has("output")) {
TFsPath stdpath(path.c_str());
- (*generator)()->Write(stdpath, highlighting);
+ (*generator)()->Write(stdpath, highlighting, ansi);
} else {
- (*generator)()->Write(Cout, highlighting);
+ (*generator)()->Write(Cout, highlighting, ansi);
}
return 0;