From 509c29e58acfbb2bc319884eb116d6fd98030b37 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Tue, 19 Jul 2022 11:16:13 -0400 Subject: [PATCH] Allow specifying --print-width in the CLI --- README.md | 18 +++++++ lib/syntax_tree.rb | 7 ++- lib/syntax_tree/cli.rb | 103 ++++++++++++++++++++++++++++------------- test/cli_test.rb | 8 ++++ 4 files changed, 102 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 4c472e37..9c33fd42 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,12 @@ If there are files with unformatted code, you will receive: The listed files did not match the expected format. ``` +To change the print width that you are checking against, specify the `--print-width` option, as in: + +```sh +stree check --print-width=100 path/to/file.rb +``` + ### format This command will output the formatted version of each of the listed files. Importantly, it will not write that content back to the source files. It is meant to display the formatted version only. @@ -132,6 +138,12 @@ For a file that contains `1 + 1`, you will receive: 1 + 1 ``` +To change the print width that you are formatting with, specify the `--print-width` option, as in: + +```sh +stree format --print-width=100 path/to/file.rb +``` + ### json This command will output a JSON representation of the syntax tree that is functionally equivalent to the input. This is mostly used in contexts where you need to access the tree from JavaScript or serialize it over a network. @@ -213,6 +225,12 @@ This will list every file that is being formatted. It will output light gray if path/to/file.rb 0ms ``` +To change the print width that you are writing with, specify the `--print-width` option, as in: + +```sh +stree write --print-width=100 path/to/file.rb +``` + ## Library Syntax Tree can be used as a library to access the syntax tree underlying Ruby source code. diff --git a/lib/syntax_tree.rb b/lib/syntax_tree.rb index 1dbd3ac8..5772b821 100644 --- a/lib/syntax_tree.rb +++ b/lib/syntax_tree.rb @@ -29,6 +29,11 @@ module SyntaxTree HANDLERS = {} HANDLERS.default = SyntaxTree + # This is the default print width when formatting. It can be overridden in the + # CLI by passing the --print-width option or here in the API by passing the + # optional second argument to ::format. + DEFAULT_PRINT_WIDTH = 80 + # This is a hook provided so that plugins can register themselves as the # handler for a particular file type. def self.register_handler(extension, handler) @@ -43,7 +48,7 @@ def self.parse(source) end # Parses the given source and returns the formatted source. - def self.format(source, maxwidth = 80) + def self.format(source, maxwidth = DEFAULT_PRINT_WIDTH) formatter = Formatter.new(source, [], maxwidth) parse(source).format(formatter) diff --git a/lib/syntax_tree/cli.rb b/lib/syntax_tree/cli.rb index c8e42831..0bb756ef 100644 --- a/lib/syntax_tree/cli.rb +++ b/lib/syntax_tree/cli.rb @@ -91,9 +91,15 @@ class Check < Action class UnformattedError < StandardError end + attr_reader :print_width + + def initialize(print_width:) + @print_width = print_width + end + def run(item) source = item.source - raise UnformattedError if source != item.handler.format(source) + raise UnformattedError if source != item.handler.format(source, print_width) rescue StandardError warn("[#{Color.yellow("warn")}] #{item.filepath}") raise @@ -114,13 +120,19 @@ class Debug < Action class NonIdempotentFormatError < StandardError end + attr_reader :print_width + + def initialize(print_width:) + @print_width = print_width + end + def run(item) handler = item.handler warning = "[#{Color.yellow("warn")}] #{item.filepath}" - formatted = handler.format(item.source) + formatted = handler.format(item.source, print_width) - raise NonIdempotentFormatError if formatted != handler.format(formatted) + raise NonIdempotentFormatError if formatted != handler.format(formatted, print_width) rescue StandardError warn(warning) raise @@ -148,8 +160,14 @@ def run(item) # An action of the CLI that formats the input source and prints it out. class Format < Action + attr_reader :print_width + + def initialize(print_width:) + @print_width = print_width + end + def run(item) - puts item.handler.format(item.source) + puts item.handler.format(item.source, print_width) end end @@ -173,12 +191,18 @@ def run(item) # An action of the CLI that formats the input source and writes the # formatted output back to the file. class Write < Action + attr_reader :print_width + + def initialize(print_width:) + @print_width = print_width + end + def run(item) filepath = item.filepath start = Time.now source = item.source - formatted = item.handler.format(source) + formatted = item.handler.format(source, print_width) File.write(filepath, formatted) if filepath != :stdin color = source == formatted ? Color.gray(filepath) : filepath @@ -194,43 +218,44 @@ def run(item) # The help message displayed if the input arguments are not correctly # ordered or formatted. HELP = <<~HELP - #{Color.bold("stree ast [OPTIONS] [FILE]")} + #{Color.bold("stree ast [--plugins=...] [--print-width=NUMBER] FILE")} Print out the AST corresponding to the given files - #{Color.bold("stree check [OPTIONS] [FILE]")} + #{Color.bold("stree check [--plugins=...] [--print-width=NUMBER] FILE")} Check that the given files are formatted as syntax tree would format them - #{Color.bold("stree debug [OPTIONS] [FILE]")} + #{Color.bold("stree debug [--plugins=...] [--print-width=NUMBER] FILE")} Check that the given files can be formatted idempotently - #{Color.bold("stree doc [OPTIONS] [FILE]")} + #{Color.bold("stree doc [--plugins=...] FILE")} Print out the doc tree that would be used to format the given files - #{Color.bold("stree format [OPTIONS] [FILE]")} + #{Color.bold("stree format [--plugins=...] [--print-width=NUMBER] FILE")} Print out the formatted version of the given files - #{Color.bold("stree json [OPTIONS] [FILE]")} + #{Color.bold("stree json [--plugins=...] FILE")} Print out the JSON representation of the given files - #{Color.bold("stree match [OPTIONS] [FILE]")} + #{Color.bold("stree match [--plugins=...] FILE")} Print out a pattern-matching Ruby expression that would match the given files #{Color.bold("stree help")} Display this help message - #{Color.bold("stree lsp [OPTIONS]")} + #{Color.bold("stree lsp [--plugins=...]")} Run syntax tree in language server mode #{Color.bold("stree version")} Output the current version of syntax tree - #{Color.bold("stree write [OPTIONS] [FILE]")} + #{Color.bold("stree write [--plugins=...] [--print-width=NUMBER] FILE")} Read, format, and write back the source of the given files - [OPTIONS] - --plugins=... A comma-separated list of plugins to load. + + --print-width=NUMBER + The maximum line width to use when formatting. HELP class << self @@ -238,19 +263,31 @@ class << self # passed to the invocation. def run(argv) name, *arguments = argv - - # If there are any plugins specified on the command line, then load them - # by requiring them here. We do this by transforming something like - # - # stree format --plugins=haml template.haml - # - # into - # - # require "syntax_tree/haml" - # - if arguments.first&.start_with?("--plugins=") - plugins = arguments.shift[/^--plugins=(.*)$/, 1] - plugins.split(",").each { |plugin| require "syntax_tree/#{plugin}" } + print_width = DEFAULT_PRINT_WIDTH + + while arguments.first&.start_with?("--") + case (argument = arguments.shift) + when /^--plugins=(.+)$/ + # If there are any plugins specified on the command line, then load + # them by requiring them here. We do this by transforming something + # like + # + # stree format --plugins=haml template.haml + # + # into + # + # require "syntax_tree/haml" + # + $1.split(",").each { |plugin| require "syntax_tree/#{plugin}" } + when /^--print-width=(\d+)$/ + # If there is a print width specified on the command line, then + # parse that out here and use it when formatting. + print_width = Integer($1) + else + warn("Unknown CLI option: #{argument}") + warn(HELP) + return 1 + end end case name @@ -271,9 +308,9 @@ def run(argv) when "a", "ast" AST.new when "c", "check" - Check.new + Check.new(print_width: print_width) when "debug" - Debug.new + Debug.new(print_width: print_width) when "doc" Doc.new when "j", "json" @@ -281,9 +318,9 @@ def run(argv) when "m", "match" Match.new when "f", "format" - Format.new + Format.new(print_width: print_width) when "w", "write" - Write.new + Write.new(print_width: print_width) else warn(HELP) return 1 diff --git a/test/cli_test.rb b/test/cli_test.rb index 7f2bcd26..31e4b7e2 100644 --- a/test/cli_test.rb +++ b/test/cli_test.rb @@ -52,6 +52,14 @@ def test_check_unformatted assert_includes(result.stderr, "expected") end + def test_check_print_width + file = Tempfile.new(%w[test- .rb]) + file.write("#{"a" * 40} + #{"b" * 40}\n") + + result = run_cli("check", "--print-width=100", file: file) + assert_includes(result.stdio, "match") + end + def test_debug result = run_cli("debug") assert_includes(result.stdio, "idempotently")