diff options
| author | robot-piglet <[email protected]> | 2025-09-01 18:37:05 +0300 |
|---|---|---|
| committer | robot-piglet <[email protected]> | 2025-09-01 19:06:57 +0300 |
| commit | 6f768e78a7bbc89778e9b2764e7f85bdeb64f034 (patch) | |
| tree | b7d88b0f418957da9eee57a85c81edefe83990f2 | |
| parent | a8b4824e60974c2562979da8a101385095519b1d (diff) | |
Intermediate changes
commit_hash:1623077a586fe91fb5d853b4efee5d1e623189cb
| -rw-r--r-- | build/external_resources/ruff/resources.json | 16 | ||||
| -rw-r--r-- | build/external_resources/ruff/ya.make | 5 | ||||
| -rw-r--r-- | library/python/find_root/README.md | 9 | ||||
| -rw-r--r-- | library/python/find_root/__init__.py | 33 | ||||
| -rw-r--r-- | library/python/find_root/ya.make | 4 | ||||
| -rw-r--r-- | tools/ruff_linter/bin/__main__.py | 161 | ||||
| -rw-r--r-- | tools/ruff_linter/bin/ya.make | 15 | ||||
| -rw-r--r-- | yql/essentials/tools/yql_highlight/artifact/ya.make | 5 | ||||
| -rw-r--r-- | yql/essentials/tools/yql_highlight/generator.cpp | 14 | ||||
| -rw-r--r-- | yql/essentials/tools/yql_highlight/generator.h | 8 | ||||
| -rw-r--r-- | yql/essentials/tools/yql_highlight/generator_highlight_js.cpp | 2 | ||||
| -rw-r--r-- | yql/essentials/tools/yql_highlight/generator_json.cpp | 2 | ||||
| -rw-r--r-- | yql/essentials/tools/yql_highlight/generator_monarch.cpp | 30 | ||||
| -rw-r--r-- | yql/essentials/tools/yql_highlight/generator_textmate.cpp | 6 | ||||
| -rw-r--r-- | yql/essentials/tools/yql_highlight/generator_vim.cpp | 2 | ||||
| -rw-r--r-- | yql/essentials/tools/yql_highlight/yql_highlight.cpp | 19 |
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; |
