From 5697b15801350983eb0c6f822b519a7c82e3d24b Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Sat, 7 May 2022 14:53:24 -0400 Subject: [PATCH 1/4] Change quote locked to better handle single or double quotes --- lib/syntax_tree/node.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 07bafb00..d153ef78 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -3904,7 +3904,7 @@ module Quotes # quotes, then single quotes would deactivate it.) def self.locked?(node) node.parts.any? do |part| - part.is_a?(TStringContent) && part.value.match?(/\\|#[@${]/) + !part.is_a?(TStringContent) || part.value.match?(/\\|#[@${]/) end end From 5901fb8438a1639c476125a64bafe260631aa44c Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Sat, 7 May 2022 15:12:18 -0400 Subject: [PATCH 2/4] Add the single quotes configuration option --- README.md | 22 +++++++---- lib/syntax_tree/formatter/single_quotes.rb | 13 +++++++ lib/syntax_tree/plugin/single_quotes.rb | 4 ++ test/formatter/single_quotes_test.rb | 45 ++++++++++++++++++++++ 4 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 lib/syntax_tree/formatter/single_quotes.rb create mode 100644 lib/syntax_tree/plugin/single_quotes.rb create mode 100644 test/formatter/single_quotes_test.rb diff --git a/README.md b/README.md index b0c916bd..8955a310 100644 --- a/README.md +++ b/README.md @@ -404,7 +404,17 @@ The language server additionally includes this custom request to return a textua ## Plugins -You can register additional languages that can flow through the same CLI with Syntax Tree's plugin system. To register a new language, call: +You can register additional configuration and additional languages that can flow through the same CLI with Syntax Tree's plugin system. When invoking the CLI, you pass through the list of plugins with the `--plugins` options to the commands that accept them. They should be a comma-delimited list. When the CLI first starts, it will require the files corresponding to those names. + +### Configuration + +To register additional configuration, define a file somewhere in your load path named `syntax_tree/my_plugin` directory. Then when invoking the CLI, you will pass `--plugins=my_plugin`. That will get required. In this way, you can modify Syntax Tree however you would like. Some plugins ship with Syntax Tree itself. They are: + +* `plugin/single_quotes` - This will change all of your string literals to use single quotes instead of the default double quotes. + +### Languages + +To register a new language, call: ```ruby SyntaxTree.register_handler(".mylang", MyLanguage) @@ -416,13 +426,11 @@ In this case, whenever the CLI encounters a filepath that ends with the given ex * `MyLanguage.parse(source)` - this should return the syntax tree corresponding to the given source. Those objects should implement the `pretty_print` interface. * `MyLanguage.format(source)` - this should return the formatted version of the given source. -Below are listed all of the "official" plugins hosted under the same GitHub organization, which can be used as references for how to implement other plugins. - -* [SyntaxTree::Haml](https://github.com/ruby-syntax-tree/syntax_tree-haml) for the [Haml template language](https://haml.info/). -* [SyntaxTree::JSON](https://github.com/ruby-syntax-tree/syntax_tree-json) for JSON. -* [SyntaxTree::RBS](https://github.com/ruby-syntax-tree/syntax_tree-rbs) for the [RBS type language](https://github.com/ruby/rbs). +Below are listed all of the "official" language plugins hosted under the same GitHub organization, which can be used as references for how to implement other plugins. -When invoking the CLI, you pass through the list of plugins with the `--plugins` options to the commands that accept them. They should be a comma-delimited list. When the CLI first starts, it will require the files corresponding to those names. +* [haml](https://github.com/ruby-syntax-tree/syntax_tree-haml) for the [Haml template language](https://haml.info/). +* [json](https://github.com/ruby-syntax-tree/syntax_tree-json) for JSON. +* [rbs](https://github.com/ruby-syntax-tree/syntax_tree-rbs) for the [RBS type language](https://github.com/ruby/rbs). ## Integration diff --git a/lib/syntax_tree/formatter/single_quotes.rb b/lib/syntax_tree/formatter/single_quotes.rb new file mode 100644 index 00000000..4d1f41b3 --- /dev/null +++ b/lib/syntax_tree/formatter/single_quotes.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module SyntaxTree + class Formatter + # This module overrides the quote method on the formatter to use single + # quotes for everything instead of double quotes. + module SingleQuotes + def quote + "'" + end + end + end +end diff --git a/lib/syntax_tree/plugin/single_quotes.rb b/lib/syntax_tree/plugin/single_quotes.rb new file mode 100644 index 00000000..d8034084 --- /dev/null +++ b/lib/syntax_tree/plugin/single_quotes.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +require "syntax_tree/formatter/single_quotes" +SyntaxTree::Formatter.prepend(SyntaxTree::Formatter::SingleQuotes) diff --git a/test/formatter/single_quotes_test.rb b/test/formatter/single_quotes_test.rb new file mode 100644 index 00000000..8bf82cb8 --- /dev/null +++ b/test/formatter/single_quotes_test.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require_relative "../test_helper" +require "syntax_tree/formatter/single_quotes" + +module SyntaxTree + class Formatter + class TestFormatter < Formatter + prepend Formatter::SingleQuotes + end + + def test_empty_string_literal + assert_format("''\n", "\"\"") + end + + def test_string_literal + assert_format("'string'\n", "\"string\"") + end + + def test_string_literal_with_interpolation + assert_format("\"\#{foo}\"\n") + end + + def test_dyna_symbol + assert_format(":'symbol'\n", ":\"symbol\"") + end + + def test_label + assert_format( + "{ foo => foo, :'bar' => bar }\n", + "{ foo => foo, \"bar\": bar }" + ) + end + + private + + def assert_format(expected, source = expected) + formatter = TestFormatter.new(source, []) + SyntaxTree.parse(source).format(formatter) + + formatter.flush + assert_equal(expected, formatter.output.join) + end + end +end From c5ac4b3cd876ed38acae704fae551616b9239643 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Tue, 10 May 2022 14:33:09 -0400 Subject: [PATCH 3/4] Fix nested hash patterns from accidentally adding a `then` to their output. --- CHANGELOG.md | 7 ++++++- Gemfile.lock | 2 +- lib/syntax_tree/node.rb | 7 +++++-- lib/syntax_tree/parser.rb | 10 ++++++++-- lib/syntax_tree/version.rb | 2 +- test/fixtures/hshptn.rb | 5 +++++ 6 files changed, 26 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26e538c3..eeb9231f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ## [Unreleased] +## [2.4.1] - 2022-05-10 + +- Fix nested hash patterns from accidentally adding a `then` to their output. + ## [2.4.0] - 2022-05-07 ### Added @@ -209,7 +213,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - 🎉 Initial release! 🎉 -[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.4.0...HEAD +[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.4.1...HEAD +[2.4.1]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.4.0...v2.4.1 [2.4.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.3.1...v2.4.0 [2.3.1]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.3.0...v2.3.1 [2.3.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v2.2.0...v2.3.0 diff --git a/Gemfile.lock b/Gemfile.lock index 8357fd92..b4eebdd4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - syntax_tree (2.4.0) + syntax_tree (2.4.1) GEM remote: https://rubygems.org/ diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index d153ef78..fdb40631 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -5064,13 +5064,16 @@ def format(q) parts = keywords.map { |(key, value)| KeywordFormatter.new(key, value) } parts << KeywordRestFormatter.new(keyword_rest) if keyword_rest + nested = PATTERNS.include?(q.parent.class) contents = -> do q.group { q.seplist(parts) { |part| q.format(part, stackable: false) } } # If there isn't a constant, and there's a blank keyword_rest, then we # have an plain ** that needs to have a `then` after it in order to # parse correctly on the next parse. - q.text(" then") if !constant && keyword_rest && keyword_rest.value.nil? + if !constant && keyword_rest && keyword_rest.value.nil? && !nested + q.text(" then") + end end # If there is a constant, we're going to format to have the constant name @@ -5097,7 +5100,7 @@ def format(q) # If there's only one pair, then we'll just print the contents provided # we're not inside another pattern. - if !PATTERNS.include?(q.parent.class) && parts.size == 1 + if !nested && parts.size == 1 contents.call return end diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index 75d3c322..f5ffe47d 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -1671,9 +1671,15 @@ def on_heredoc_end(value) # (nil | VarField) keyword_rest # ) -> HshPtn def on_hshptn(constant, keywords, keyword_rest) - # Create an artificial VarField if we find an extra ** on the end - if !keyword_rest && (token = find_token(Op, "**", consume: false)) + if keyword_rest + # We're doing this to delete the token from the list so that it doesn't + # confuse future patterns by thinking they have an extra ** on the end. + find_token(Op, "**") + elsif (token = find_token(Op, "**", consume: false)) tokens.delete(token) + + # Create an artificial VarField if we find an extra ** on the end. This + # means the formatting will be a little more consistent. keyword_rest = VarField.new(value: nil, location: token.location) end diff --git a/lib/syntax_tree/version.rb b/lib/syntax_tree/version.rb index 894ff1b7..fbecb604 100644 --- a/lib/syntax_tree/version.rb +++ b/lib/syntax_tree/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module SyntaxTree - VERSION = "2.4.0" + VERSION = "2.4.1" end diff --git a/test/fixtures/hshptn.rb b/test/fixtures/hshptn.rb index 2935f9c1..7a35b4d0 100644 --- a/test/fixtures/hshptn.rb +++ b/test/fixtures/hshptn.rb @@ -66,3 +66,8 @@ case foo in **nil end +% +case foo +in bar, { baz:, **nil } +in qux: +end From eb4721355d1d4afae92d64680f8d3865838e7004 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Tue, 10 May 2022 14:40:59 -0400 Subject: [PATCH 4/4] Update CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eeb9231f..fe3030e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ## [2.4.1] - 2022-05-10 -- Fix nested hash patterns from accidentally adding a `then` to their output. +- [#73](https://github.com/ruby-syntax-tree/syntax_tree/pull/73) - Fix nested hash patterns from accidentally adding a `then` to their output. ## [2.4.0] - 2022-05-07