diff options
author | scottmg <scottmg@chromium.org> | 2014-10-03 15:52:11 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-10-03 22:52:24 +0000 |
commit | 56d85cbf5bddd6bb9b68104a9f30af2b215a6e27 (patch) | |
tree | f2f12d0e4c6e35703ff29c9471bdff10a3411afa /tools/gn | |
parent | 1c28072cfdcbfbb27bafe384e739877ee74b3831 (diff) | |
download | chromium_src-56d85cbf5bddd6bb9b68104a9f30af2b215a6e27.zip chromium_src-56d85cbf5bddd6bb9b68104a9f30af2b215a6e27.tar.gz chromium_src-56d85cbf5bddd6bb9b68104a9f30af2b215a6e27.tar.bz2 |
gn format: accept input from stdin, add vim helper
Also add test for empty function call (which was asserting
with invalid iterator).
R=brettw@chromium.org
BUG=348474
Review URL: https://codereview.chromium.org/626093003
Cr-Commit-Position: refs/heads/master@{#298106}
Diffstat (limited to 'tools/gn')
-rw-r--r-- | tools/gn/bin/gn-format.py | 58 | ||||
-rw-r--r-- | tools/gn/command_format.cc | 109 | ||||
-rw-r--r-- | tools/gn/command_format_unittest.cc | 2 | ||||
-rw-r--r-- | tools/gn/format_test_data/024.gn | 1 | ||||
-rw-r--r-- | tools/gn/format_test_data/024.golden | 2 |
5 files changed, 152 insertions, 20 deletions
diff --git a/tools/gn/bin/gn-format.py b/tools/gn/bin/gn-format.py new file mode 100644 index 0000000..c835753 --- /dev/null +++ b/tools/gn/bin/gn-format.py @@ -0,0 +1,58 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# Based on clang-format.py. +# +# This file is a minimal gn format vim-integration. To install: +# - Change 'binary' if gn is not on the path (see below). +# - Add to your .vimrc: +# +# map <F1> :pyf <path-to-this-file>/gn-format.py<CR> +# +# gn format currently formats only a complete file so visual ranges, etc. won't +# be used. It operates on the current, potentially unsaved buffer and does not +# create or save any files. To revert a formatting, just undo. + +import difflib +import subprocess +import sys +import vim + +# Change this to the full path if gn is not on the path. +binary = 'gn' + +def main(): + # Get the current text. + buf = vim.current.buffer + text = '\n'.join(buf) + + # Avoid flashing an ugly cmd prompt on Windows when invoking gn. + startupinfo = None + if sys.platform.startswith('win32'): + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + startupinfo.wShowWindow = subprocess.SW_HIDE + + # Call formatter. + p = subprocess.Popen([binary, 'format', '--stdin'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + stdin=subprocess.PIPE, startupinfo=startupinfo, + universal_newlines=True) + stdout, stderr = p.communicate(input=text) + if p.returncode != 0: + print 'Formatting failed, please report to gn-dev@chromium.org.' + print stdout, stderr + else: + # Otherwise, replace current buffer. + lines = stdout.split('\n') + # Last line should have trailing \n, but we don't want to insert a blank + # line at the end of the buffer, so remove that. + if lines[-1] == '': + lines = lines[:-1] + sequence = difflib.SequenceMatcher(None, vim.current.buffer, lines) + for op in reversed(sequence.get_opcodes()): + if op[0] is not 'equal': + vim.current.buffer[op[1]:op[2]] = lines[op[3]:op[4]] + +main() diff --git a/tools/gn/command_format.cc b/tools/gn/command_format.cc index c7076b0..e05d0f1 100644 --- a/tools/gn/command_format.cc +++ b/tools/gn/command_format.cc @@ -20,6 +20,7 @@ namespace commands { const char kSwitchDumpTree[] = "dump-tree"; const char kSwitchInPlace[] = "in-place"; +const char kSwitchStdin[] = "stdin"; const char kFormat[] = "format"; const char kFormat_HelpShort[] = @@ -40,10 +41,15 @@ const char kFormat_Help[] = " Instead writing the formatted file to stdout, replace the input\n" " with the formatted output.\n" "\n" + " --stdin\n" + " Read input from stdin (and write to stdout). Not compatible with\n" + " --in-place of course.\n" + "\n" "Examples\n" " gn format //some/BUILD.gn\n" " gn format some\\BUILD.gn\n" - " gn format /abspath/some/BUILD.gn\n"; + " gn format /abspath/some/BUILD.gn\n" + " gn format --stdin\n"; namespace { @@ -408,8 +414,10 @@ void Printer::Sequence(SequenceStyle style, // TODO(scottmg): Need to know if there's an attached block for " {". fits_on_current_line = fits_on_current_line && CurrentColumn() + total_length < kMaximumWidth; - max_item_width = - *std::max_element(natural_lengths.begin(), natural_lengths.end()); + if (natural_lengths.size() > 0) { + max_item_width = + *std::max_element(natural_lengths.begin(), natural_lengths.end()); + } } if (list.size() == 0 && !force_multiline) { @@ -501,6 +509,38 @@ void Printer::Sequence(SequenceStyle style, margin_ = old_margin; } +void DoFormat(const ParseNode* root, bool dump_tree, std::string* output) { + if (dump_tree) { + std::ostringstream os; + root->Print(os, 0); + printf("----------------------\n"); + printf("-- PARSE TREE --------\n"); + printf("----------------------\n"); + printf("%s", os.str().c_str()); + printf("----------------------\n"); + } + Printer pr; + pr.Block(root); + *output = pr.String(); +} + +std::string ReadStdin() { + static const int kBufferSize = 256; + char buffer[kBufferSize]; + std::string result; + while (true) { + char* input = NULL; + input = fgets(buffer, kBufferSize, stdin); + if (input == NULL && feof(stdin)) + return result; + int length = static_cast<int>(strlen(buffer)); + if (length == 0) + return result; + else + result += std::string(buffer, length); + } +} + } // namespace bool FormatFileToString(Setup* setup, @@ -515,35 +555,64 @@ bool FormatFileToString(Setup* setup, err.PrintToStdout(); return false; } - if (dump_tree) { - std::ostringstream os; - parse_node->Print(os, 0); - printf("----------------------\n"); - printf("-- PARSE TREE --------\n"); - printf("----------------------\n"); - printf("%s", os.str().c_str()); - printf("----------------------\n"); + DoFormat(parse_node, dump_tree, output); + return true; +} + +bool FormatStringToString(const std::string& input, + bool dump_tree, + std::string* output) { + SourceFile source_file; + InputFile file(source_file); + file.SetContents(input); + Err err; + // Tokenize. + std::vector<Token> tokens = Tokenizer::Tokenize(&file, &err); + if (err.has_error()) { + err.PrintToStdout(); + return false; } - Printer pr; - pr.Block(parse_node); - *output = pr.String(); + + // Parse. + scoped_ptr<ParseNode> parse_node = Parser::Parse(tokens, &err); + if (err.has_error()) { + err.PrintToStdout(); + return false; + } + + DoFormat(parse_node.get(), dump_tree, output); return true; } int RunFormat(const std::vector<std::string>& args) { + bool dump_tree = + base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchDumpTree); + + bool from_stdin = + base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchStdin); + + if (from_stdin) { + if (args.size() != 0) { + Err(Location(), "Expecting no arguments when reading from stdin.\n") + .PrintToStdout(); + return 1; + } + std::string input = ReadStdin(); + std::string output; + if (!FormatStringToString(input, dump_tree, &output)) + return 1; + printf("%s", output.c_str()); + return 0; + } + // TODO(scottmg): Eventually, this should be a list/spec of files, and they - // should all be done in parallel and in-place. For now, we don't want to - // overwrite good data with mistakenly reformatted stuff, so we just simply - // print the formatted output to stdout. + // should all be done in parallel. if (args.size() != 1) { Err(Location(), "Expecting exactly one argument, see `gn help format`.\n") .PrintToStdout(); return 1; } - bool dump_tree = - base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchDumpTree); - Setup setup; SourceDir source_dir = SourceDirForCurrentDirectory(setup.build_settings().root_path()); diff --git a/tools/gn/command_format_unittest.cc b/tools/gn/command_format_unittest.cc index cad69a4..4140f80 100644 --- a/tools/gn/command_format_unittest.cc +++ b/tools/gn/command_format_unittest.cc @@ -57,3 +57,5 @@ FORMAT_TEST(019) FORMAT_TEST(020) FORMAT_TEST(021) FORMAT_TEST(022) +// TODO(scottmg): Refactor funccall. FORMAT_TEST(023) +FORMAT_TEST(024) diff --git a/tools/gn/format_test_data/024.gn b/tools/gn/format_test_data/024.gn new file mode 100644 index 0000000..5034cdc --- /dev/null +++ b/tools/gn/format_test_data/024.gn @@ -0,0 +1 @@ +somefunc(){} diff --git a/tools/gn/format_test_data/024.golden b/tools/gn/format_test_data/024.golden new file mode 100644 index 0000000..f2c755d --- /dev/null +++ b/tools/gn/format_test_data/024.golden @@ -0,0 +1,2 @@ +somefunc() { +} |