Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Syntax Tree (RubyKaigi)

Kevin Newton
September 09, 2022
1.1k

Syntax Tree (RubyKaigi)

Syntax Tree is a new toolkit for interacting with the Ruby parse tree. It can be used to analyze, inspect, debug, and format your Ruby code. In this talk we'll walk through how it works, how to use it in your own applications, and the exciting future possibilities enabled by Syntax Tree.

Kevin Newton

September 09, 2022
Tweet

Transcript

  1. Build a syntax tree Format the syntax tree Create a

    CLI Create a language server (LSP) Syntax Tree
  2. Build a syntax tree Format the syntax tree Create a

    CLI Create a language server (LSP) Translate the syntax tree Syntax Tree
  3. Build · Format · CLI · LSP · Translate class

    VCall < Node attr_reader :value, :location, :comments def initialize(value:, location:, comments: []) @value = value @location = location @comments = comments end def accept(visitor) visitor.visit_vcall(self) end def child_nodes [value] end alias deconstruct child_nodes def deconstruct_keys(keys) { value: value, location: location, comments: comments } end end
  4. Build · Format · CLI · LSP · Translate class

    VCall < Node attr_reader :value, :location, :comments def initialize(value:, location:, comments: []) @value = value @location = location @comments = comments end def accept(visitor) visitor.visit_vcall(self) end def child_nodes [value] end alias deconstruct child_nodes def deconstruct_keys(keys) { value: value, location: location, comments: comments } end end Named fields
  5. Build · Format · CLI · LSP · Translate class

    VCall < Node attr_reader :value, :location, :comments def initialize(value:, location:, comments: []) @value = value @location = location @comments = comments end def accept(visitor) visitor.visit_vcall(self) end def child_nodes [value] end alias deconstruct child_nodes def deconstruct_keys(keys) { value: value, location: location, comments: comments } end end Named fields #location/#comments
  6. Build · Format · CLI · LSP · Translate class

    VCall < Node attr_reader :value, :location, :comments def initialize(value:, location:, comments: []) @value = value @location = location @comments = comments end def accept(visitor) visitor.visit_vcall(self) end def child_nodes [value] end alias deconstruct child_nodes def deconstruct_keys(keys) { value: value, location: location, comments: comments } end end Named fields #location/#comments #accept/#child_nodes
  7. Build · Format · CLI · LSP · Translate class

    VCall < Node attr_reader :value, :location, :comments def initialize(value:, location:, comments: []) @value = value @location = location @comments = comments end def accept(visitor) visitor.visit_vcall(self) end def child_nodes [value] end alias deconstruct child_nodes def deconstruct_keys(keys) { value: value, location: location, comments: comments } end end Named fields #location/#comments #accept/#child_nodes #deconstruct/ 
 #deconstruct_keys
  8. Build · Format · CLI · LSP · Translate class

    VCall < Node attr_reader :value, :location, :comments def initialize(value:, location:, comments: []) @value = value @location = location @comments = comments end def accept(visitor) visitor.visit_vcall(self) end def child_nodes [value] end alias deconstruct child_nodes def deconstruct_keys(keys) { value: value, location: location, comments: comments } end end Named fields #location/#comments #accept/#child_nodes #deconstruct/ 
 #deconstruct_keys Immutable
  9. Ripper::EVENTS.count # => 190 SyntaxTree::Node.descendants.count 
 # => 162 qwords_new/qwords_add

    -> SyntaxTree::QWords Define each node Build · Format · CLI · LSP · Translate
  10. var_ref : user_variable { /*%%%*/ if (!($$ = gettable(p, $1,

    &@$))) $$ = NEW_BEGIN(0, &@$); /*% if (id_is_var(p, get_id($1))) { $$ = dispatch1(var_ref, $1); } else { $$ = dispatch1(vcall, $1); } %*/ } | keyword_variable { /*%%%*/ if (!($$ = gettable(p, $1, &@$))) $$ = NEW_BEGIN(0, &@$); /*% %*/ /*% ripper: var_ref!($1) %*/ } ; Build · Format · CLI · LSP · Translate
  11. var_ref : user_variable { /*%%%*/ if (!($$ = gettable(p, $1,

    &@$))) $$ = NEW_BEGIN(0, &@$); /*% if (id_is_var(p, get_id($1))) { $$ = dispatch1(var_ref, $1); } else { $$ = dispatch1(vcall, $1); } %*/ } | keyword_variable { /*%%%*/ if (!($$ = gettable(p, $1, &@$))) $$ = NEW_BEGIN(0, &@$); /*% %*/ /*% ripper: var_ref!($1) %*/ } ; Build · Format · CLI · LSP · Translate
  12. class Foo def bar baz end end Build · Format

    · CLI · LSP · Translate class Parser < Ripper def on_const(value) = [:@const, value] def on_ident(value) = [:@ident, value] def on_const_ref(const) = [:const_ref, const] def on_vcall(ident) = [:vcall, ident] def on_class(const, superclass, bodystmt) [:class, [const, superclass, bodystmt]] end def on_def(name, params, bodystmt) [:def, [name, params, bodystmt]] end end
  13. class Foo def bar baz end end Build · Format

    · CLI · LSP · Translate class Parser < Ripper def on_const(value) = [:@const, value] def on_ident(value) = [:@ident, value] def on_const_ref(const) = [:const_ref, const] def on_vcall(ident) = [:vcall, ident] def on_class(const, superclass, bodystmt) [:class, [const, superclass, bodystmt]] end def on_def(name, params, bodystmt) [:def, [name, params, bodystmt]] end end
  14. class Foo def bar baz end end Build · Format

    · CLI · LSP · Translate class Parser < Ripper def on_const(value) = [:@const, value] def on_ident(value) = [:@ident, value] def on_const_ref(const) = [:const_ref, const] def on_vcall(ident) = [:vcall, ident] def on_class(const, superclass, bodystmt) [:class, [const, superclass, bodystmt]] end def on_def(name, params, bodystmt) [:def, [name, params, bodystmt]] end end
  15. class Foo def bar baz end end Build · Format

    · CLI · LSP · Translate class Parser < Ripper def on_const(value) = [:@const, value] def on_ident(value) = [:@ident, value] def on_const_ref(const) = [:const_ref, const] def on_vcall(ident) = [:vcall, ident] def on_class(const, superclass, bodystmt) [:class, [const, superclass, bodystmt]] end def on_def(name, params, bodystmt) [:def, [name, params, bodystmt]] end end
  16. class Foo def bar baz end end Build · Format

    · CLI · LSP · Translate class Parser < Ripper def on_const(value) = [:@const, value] def on_ident(value) = [:@ident, value] def on_const_ref(const) = [:const_ref, const] def on_vcall(ident) = [:vcall, ident] def on_class(const, superclass, bodystmt) [:class, [const, superclass, bodystmt]] end def on_def(name, params, bodystmt) [:def, [name, params, bodystmt]] end end
  17. class Foo def bar baz end end Build · Format

    · CLI · LSP · Translate class Parser < Ripper def on_const(value) = [:@const, value] def on_ident(value) = [:@ident, value] def on_const_ref(const) = [:const_ref, const] def on_vcall(ident) = [:vcall, ident] def on_class(const, superclass, bodystmt) [:class, [const, superclass, bodystmt]] end def on_def(name, params, bodystmt) [:def, [name, params, bodystmt]] end end
  18. class Foo def bar baz end end Build · Format

    · CLI · LSP · Translate class Parser < Ripper def on_const(value) = [:@const, value] def on_ident(value) = [:@ident, value] def on_const_ref(const) = [:const_ref, const] def on_vcall(ident) = [:vcall, ident] def on_class(const, superclass, bodystmt) [:class, [const, superclass, bodystmt]] end def on_def(name, params, bodystmt) [:def, [name, params, bodystmt]] end end
  19. class Foo def bar baz end end Build · Format

    · CLI · LSP · Translate class Parser < Ripper def on_const(value) = [:@const, value] def on_ident(value) = [:@ident, value] def on_const_ref(const) = [:const_ref, const] def on_vcall(ident) = [:vcall, ident] def on_class(const, superclass, bodystmt) [:class, [const, superclass, bodystmt]] end def on_def(name, params, bodystmt) [:def, [name, params, bodystmt]] end end
  20. Build · Format · CLI · LSP · Translate class

    Parser < Ripper def on_const(value) = [:@const, value] def on_ident(value) = [:@ident, value] def on_const_ref(const) = [:const_ref, const] def on_vcall(ident) = [:vcall, ident] def on_class(const, superclass, bodystmt) [:class, [const, superclass, bodystmt]] end def on_def(name, params, bodystmt) [:def, [name, params, bodystmt]] end end
  21. Build · Format · CLI · LSP · Translate class

    Parser < Ripper def on_const(value) = [:@const, value] def on_ident(value) = [:@ident, value] def on_kw(value) = @stack << [:@kw, value] def on_const_ref(const) = [:const_ref, const] def on_vcall(ident) = [:vcall, ident] def on_class(const, superclass, bodystmt) kw = @stack.rfind { |token| token in [:@kw, "class"] } [:class, [@stack.delete(kw), const, superclass, bodystmt]] end def on_def(name, params, bodystmt) kw = @stack.rfind { |token| token in [:@kw, "def"] } [:def, [@stack.delete(kw), name, params, bodystmt]] end end
  22. Build · Format · CLI · LSP · Translate class

    Parser < Ripper def on_const(value) = [:@const, value] def on_ident(value) = [:@ident, value] def on_kw(value) = @stack << [:@kw, value] def on_const_ref(const) = [:const_ref, const] def on_vcall(ident) = [:vcall, ident] def on_class(const, superclass, bodystmt) kw = @stack.rfind { |token| token in [:@kw, "class"] } [:class, [@stack.delete(kw), const, superclass, bodystmt]] end def on_def(name, params, bodystmt) kw = @stack.rfind { |token| token in [:@kw, "def"] } [:def, [@stack.delete(kw), name, params, bodystmt]] end end
  23. Build · Format · CLI · LSP · Translate ->

    (positional; local1, local2) {}
  24. Build · Format · CLI · LSP · Translate ->

    (positional; local1, local2) {} range = (location.start_char + 1)...location.end_char locals = lambda_locals(source[range]) Paren.new( lparen: params.lparen, contents: LambdaVar.new( params: params.contents, locals: locals, location: location ), location: params.location, comments: params.comments )
  25. Build · Format · CLI · LSP · Translate class

    Foo # comment def bar baz end end
  26. Build · Format · CLI · LSP · Translate class

    Foo def bar # comment baz end end
  27. Build · Format · CLI · LSP · Translate class

    Foo def bar baz # comment end end
  28. Build · Format · CLI · LSP · Translate #

    comment class Foo def bar baz end end
  29. Build · Format · CLI · LSP · Translate class

    Foo # comment def bar baz end end
  30. Build · Format · CLI · LSP · Translate #

    comment1 class Foo # comment2 # comment3 def bar # comment4 baz # comment5 end end
  31. Build · Format · CLI · LSP · Translate #

    comment1 class Foo # comment2 # comment3 def bar # comment4 baz # comment5 end end [ ]
  32. Build · Format · CLI · LSP · Translate #

    comment1 class Foo # comment2 # comment3 def bar # comment4 baz # comment5 end end [ # comment1, ]
  33. Build · Format · CLI · LSP · Translate #

    comment1 class Foo # comment2 # comment3 def bar # comment4 baz # comment5 end end [ # comment1, # comment2, ]
  34. Build · Format · CLI · LSP · Translate #

    comment1 class Foo # comment2 # comment3 def bar # comment4 baz # comment5 end end [ # comment1, # comment2, # comment3, ]
  35. Build · Format · CLI · LSP · Translate #

    comment1 class Foo # comment2 # comment3 def bar # comment4 baz # comment5 end end [ # comment1, # comment2, # comment3, # comment4, ]
  36. Build · Format · CLI · LSP · Translate #

    comment1 class Foo # comment2 # comment3 def bar # comment4 baz # comment5 end end [ # comment1, # comment2, # comment3, # comment4, # comment5 ]
  37. Build · Format · CLI · LSP · Translate [

    # comment1, # comment2, # comment3, # comment4, # comment5 ] (program (statements ((class (const_ref (const "Foo")) (bodystmt (statements ((void_stmt), (def (ident "bar") (params) (bodystmt (statements ((vcall (ident "baz")))))))))))))
  38. Build · Format · CLI · LSP · Translate (program

    (statements ((comment "# comment1"), (class (const_ref (const "Foo") ((comment "# comment2"))) (bodystmt (statements ((void_stmt), (comment "# comment3"), (def (ident "bar") (params ((comment "# comment4"))) (bodystmt (statements ((vcall (ident "baz") ((comment "# comment5"))))))))))))))
  39. Build · Format · CLI · LSP · Translate class

    Visitor def visit(node) node&.accept(self) end def visit_child_nodes(node) node.child_nodes.map do |node| visit(node) end end end
  40. Build · Format · CLI · LSP · Translate class

    VCall < Node def accept(visitor) visitor.visit_vcall(self) end end class Visitor def visit(node) node&.accept(self) end def visit_child_nodes(node) node.child_nodes.map do |node| visit(node) end end end
  41. Build · Format · CLI · LSP · Translate class

    VCall < Node def accept(visitor) visitor.visit_vcall(self) end end # Visit an ARef node. alias visit_aref visit_child_nodes # Visit an ARefField node. alias visit_aref_field visit_child_nodes # Visit an Alias node. alias visit_alias visit_child_nodes # Visit an ArgBlock node. alias visit_arg_block visit_child_nodes # Visit an ArgParen node. alias visit_arg_paren visit_child_nodes # Visit an ArgStar node. alias visit_arg_star visit_child_nodes # Visit an Args node. alias visit_args visit_child_nodes # Visit an ArgsForward node. alias visit_args_forward visit_child_nodes # Visit an ArrayLiteral node. alias visit_array visit_child_nodes # Visit an AryPtn node. alias visit_aryptn visit_child_nodes # Visit an Assign node. alias visit_assign visit_child_nodes # Visit an Assoc node. alias visit_assoc visit_child_nodes # Visit an AssocSplat node. alias visit_assoc_splat visit_child_nodes # Visit a Backref node. alias visit_backref visit_child_nodes class Visitor def visit(node) node&.accept(self) end def visit_child_nodes(node) node.child_nodes.map do |node| visit(node) end end end
  42. Build · Format · CLI · LSP · Translate class

    VCall < Node def accept(visitor) visitor.visit_vcall(self) end end alias visit_vcall visit_child_nodes # Visit a VoidStmt node. alias visit_void_stmt visit_child_nodes # Visit a When node. alias visit_when visit_child_nodes # Visit a While node. alias visit_while visit_child_nodes # Visit a WhileMod node. alias visit_while_mod visit_child_nodes # Visit a Word node. alias visit_word visit_child_nodes # Visit a Words node. alias visit_words visit_child_nodes # Visit a WordsBeg node. alias visit_words_beg visit_child_nodes # Visit a XString node. alias visit_xstring visit_child_nodes # Visit a XStringLiteral node. alias visit_xstring_literal visit_child_nodes # Visit a Yield node. alias visit_yield visit_child_nodes # Visit a Yield0 node. alias visit_yield0 visit_child_nodes # Visit a ZSuper node. alias visit_zsuper visit_child_nodes # Visit an EndContent node. alias visit___end__ visit_child_nodes class Visitor def visit(node) node&.accept(self) end def visit_child_nodes(node) node.child_nodes.map do |node| visit(node) end end end
  43. Build · Format · CLI · LSP · Translate class

    RegexpVisitor < Visitor def visit_regexp_literal(node) # do something with regexp literal node here node.options # call super to continue walking the tree super end end
  44. Build · Format · CLI · LSP · Translate class

    JSONVisitor < Visitor def visit_aref(node) node(node, "aref") do field("collection", node.collection) field("index", node.index) comments(node) end end def visit_aref_field(node) node(node, "aref_field") do field("collection", node.collection) field("index", node.index) comments(node) end end def visit_alias(node) node(node, "alias") do field("left", node.left) field("right", node.right) comments(node) end end
  45. prettyprint Build group, text, breakable to layout content Break outermost

    groups to fit to print width Algorithm Build · Format · CLI · LSP · Translate
  46. Build · Format · CLI · LSP · Translate [foo1,

    foo2, [bar1, bar2, bar3, bar4], foo3, foo4, [baz1, baz2]]
  47. Build · Format · CLI · LSP · Translate [foo1,

    foo2, [bar1, bar2, bar3, bar4], foo3, foo4, [baz1, baz2]]
  48. Build · Format · CLI · LSP · Translate [foo1,

    foo2, [bar1, bar2, bar3, bar4], foo3, foo4, [baz1, baz2]]
  49. Build · Format · CLI · LSP · Translate [

    foo1, foo2, [bar1, bar2, bar3, bar4], foo3, foo4, [baz1, baz2] ]
  50. Build · Format · CLI · LSP · Translate [

    foo1, foo2, [bar1, bar2, bar3, bar4], foo3, foo4, [baz1, baz2] ]
  51. Build · Format · CLI · LSP · Translate [

    foo1, foo2, [ bar1, bar2, bar3, bar4 ], foo3, foo4, [baz1, baz2] ]
  52. breakGroup([group([text(["["]), indent([breakable, text(["foo1", ","]), breakable, text(["foo2", ","]), breakable, group([text(["["]), indent([breakable,

    text(["bar1", ","]), breakable, text(["bar2", ","]), breakable, text(["bar3", ","]), breakable, text(["bar4"])]), breakable, text(["]"])]), text([","]), breakable, text(["foo3", ","]), breakable, text(["foo4", ","]), breakable, ... Build · Format · CLI · LSP · Translate
  53. breakGroup([group([text(["["]), indent([breakable, text(["foo1", ","]), breakable, text(["foo2", ","]), breakable, group([text(["["]), indent([breakable,

    text(["bar1", ","]), breakable, text(["bar2", ","]), breakable, text(["bar3", ","]), breakable, text(["bar4"])]), breakable, text(["]"])]), text([","]), breakable, text(["foo3", ","]), breakable, text(["foo4", ","]), breakable, ... Build · Format · CLI · LSP · Translate
  54. breakGroup([group([text(["["]), indent([breakable, text(["foo1", ","]), breakable, text(["foo2", ","]), breakable, group([text(["["]), indent([breakable,

    text(["bar1", ","]), breakable, text(["bar2", ","]), breakable, text(["bar3", ","]), breakable, text(["bar4"])]), breakable, text(["]"])]), text([","]), breakable, text(["foo3", ","]), breakable, text(["foo4", ","]), breakable, ... Build · Format · CLI · LSP · Translate
  55. breakGroup([group([text(["["]), indent([breakable, text(["foo1", ","]), breakable, text(["foo2", ","]), breakable, group([text(["["]), indent([breakable,

    text(["bar1", ","]), breakable, text(["bar2", ","]), breakable, text(["bar3", ","]), breakable, text(["bar4"])]), breakable, text(["]"])]), text([","]), breakable, text(["foo3", ","]), breakable, text(["foo4", ","]), breakable, ... Build · Format · CLI · LSP · Translate
  56. breakGroup([group([text(["["]), indent([breakable, text(["foo1", ","]), breakable, text(["foo2", ","]), breakable, group([text(["["]), indent([breakable,

    text(["bar1", ","]), breakable, text(["bar2", ","]), breakable, text(["bar3", ","]), breakable, text(["bar4"])]), breakable, text(["]"])]), text([","]), breakable, text(["foo3", ","]), breakable, text(["foo4", ","]), breakable, ... Build · Format · CLI · LSP · Translate
  57. I made too many additions to prettyprint Build · Format

    · CLI · LSP · Translate 😅😅😅
  58. Build · Format · CLI · LSP · Translate here_is_a_method_call(1,

    2, <<~HEREDOC this is the content of the heredoc HEREDOC )
  59. Build · Format · CLI · LSP · Translate here_is_a_method_call(1,

    2, <<~HEREDOC this is the content of the heredoc HEREDOC )
  60. Build · Format · CLI · LSP · Translate here_is_a_method_call(1,

    2, <<~HEREDOC) this is the content of the heredoc HEREDOC
  61. Build · Format · CLI · LSP · Translate def

    foo return [1, 2, 3].map { |element| element * 2 } # comment end
  62. Build · Format · CLI · LSP · Translate def

    foo return [1, 2, 3].map { |element| element * 2 } # comment end
  63. Build · Format · CLI · LSP · Translate def

    foo return( [1, 2, 3].map do |element| element * 2 end ) # comment end
  64. Build · Format · CLI · LSP · Translate class

    If < Node def format(q) if node.consequent || node.statements.empty? q.group { format_break(q, force: true) } else q.group do q .if_break { format_break(q, force: false) } .if_flat do Parentheses.flat(q) do q.format(node.statements) q.text(" if ") q.format(node.predicate) end end end end end end
  65. Build · Format · CLI · LSP · Translate class

    If < Node def format(q) if node.consequent || node.statements.empty? q.group { format_break(q, force: true) } else q.group do q .if_break { format_break(q, force: false) } .if_flat do Parentheses.flat(q) do q.format(node.statements) q.text(" if ") q.format(node.predicate) end end end end end end
  66. Build · Format · CLI · LSP · Translate stree

    ast [OPTIONS] [FILE] Print out the AST corresponding to the given files stree check [OPTIONS] [FILE] Check that the given files are formatted as syntax tree would format them stree debug [OPTIONS] [FILE] Check that the given files can be formatted idempotently stree doc [OPTIONS] [FILE] Print out the doc tree that would be used to format the given files stree format [OPTIONS] [FILE] Print out the formatted version of the given files stree json [OPTIONS] [FILE] Print out the JSON representation of the given files stree match [OPTIONS] [FILE] Print out a pattern-matching Ruby expression that would match the given files stree help Display this help message stree lsp Run syntax tree in language server mode stree version Output the current version of syntax tree stree write [OPTIONS] [FILE] Read, format, and write back the source of the given files
  67. Build · Format · CLI · LSP · Translate stree

    ast [OPTIONS] [FILE] Print out the AST corresponding to the given files stree check [OPTIONS] [FILE] Check that the given files are formatted as syntax tree would format them stree debug [OPTIONS] [FILE] Check that the given files can be formatted idempotently stree doc [OPTIONS] [FILE] Print out the doc tree that would be used to format the given files stree format [OPTIONS] [FILE] Print out the formatted version of the given files stree json [OPTIONS] [FILE] Print out the JSON representation of the given files stree match [OPTIONS] [FILE] Print out a pattern-matching Ruby expression that would match the given files stree help Display this help message stree lsp Run syntax tree in language server mode stree version Output the current version of syntax tree stree write [OPTIONS] [FILE] Read, format, and write back the source of the given files
  68. Build · Format · CLI · LSP · Translate stree

    ast [OPTIONS] [FILE] Print out the AST corresponding to the given files stree check [OPTIONS] [FILE] Check that the given files are formatted as syntax tree would format them stree debug [OPTIONS] [FILE] Check that the given files can be formatted idempotently stree doc [OPTIONS] [FILE] Print out the doc tree that would be used to format the given files stree format [OPTIONS] [FILE] Print out the formatted version of the given files stree json [OPTIONS] [FILE] Print out the JSON representation of the given files stree match [OPTIONS] [FILE] Print out a pattern-matching Ruby expression that would match the given files stree help Display this help message stree lsp Run syntax tree in language server mode stree version Output the current version of syntax tree stree write [OPTIONS] [FILE] Read, format, and write back the source of the given files
  69. Build · Format · CLI · LSP · Translate stree

    ast [OPTIONS] [FILE] Print out the AST corresponding to the given files stree check [OPTIONS] [FILE] Check that the given files are formatted as syntax tree would format them stree debug [OPTIONS] [FILE] Check that the given files can be formatted idempotently stree doc [OPTIONS] [FILE] Print out the doc tree that would be used to format the given files stree format [OPTIONS] [FILE] Print out the formatted version of the given files stree json [OPTIONS] [FILE] Print out the JSON representation of the given files stree match [OPTIONS] [FILE] Print out a pattern-matching Ruby expression that would match the given files stree help Display this help message stree lsp Run syntax tree in language server mode stree version Output the current version of syntax tree stree write [OPTIONS] [FILE] Read, format, and write back the source of the given files
  70. Build · Format · CLI · LSP · Translate stree

    ast [OPTIONS] [FILE] Print out the AST corresponding to the given files stree check [OPTIONS] [FILE] Check that the given files are formatted as syntax tree would format them stree debug [OPTIONS] [FILE] Check that the given files can be formatted idempotently stree doc [OPTIONS] [FILE] Print out the doc tree that would be used to format the given files stree format [OPTIONS] [FILE] Print out the formatted version of the given files stree json [OPTIONS] [FILE] Print out the JSON representation of the given files stree match [OPTIONS] [FILE] Print out a pattern-matching Ruby expression that would match the given files stree help Display this help message stree lsp Run syntax tree in language server mode stree version Output the current version of syntax tree stree write [OPTIONS] [FILE] Read, format, and write back the source of the given files
  71. Language plugins Build · Format · CLI · LSP ·

    Translate rbs haml json xml css
  72. Build · Format · CLI · LSP · Translate stree

    ast [OPTIONS] [FILE] Print out the AST corresponding to the given files stree check [OPTIONS] [FILE] Check that the given files are formatted as syntax tree would format them stree debug [OPTIONS] [FILE] Check that the given files can be formatted idempotently stree doc [OPTIONS] [FILE] Print out the doc tree that would be used to format the given files stree format [OPTIONS] [FILE] Print out the formatted version of the given files stree json [OPTIONS] [FILE] Print out the JSON representation of the given files stree match [OPTIONS] [FILE] Print out a pattern-matching Ruby expression that would match the given files stree help Display this help message stree lsp Run syntax tree in language server mode stree version Output the current version of syntax tree stree write [OPTIONS] [FILE] Read, format, and write back the source of the given files
  73. Build · Format · CLI · LSP · Translate stree

    ast [OPTIONS] [FILE] Print out the AST corresponding to the given files stree check [OPTIONS] [FILE] Check that the given files are formatted as syntax tree would format them stree debug [OPTIONS] [FILE] Check that the given files can be formatted idempotently stree doc [OPTIONS] [FILE] Print out the doc tree that would be used to format the given files stree format [OPTIONS] [FILE] Print out the formatted version of the given files stree json [OPTIONS] [FILE] Print out the JSON representation of the given files stree match [OPTIONS] [FILE] Print out a pattern-matching Ruby expression that would match the given files stree help Display this help message stree lsp Run syntax tree in language server mode stree version Output the current version of syntax tree stree write [OPTIONS] [FILE] Read, format, and write back the source of the given files
  74. Language server protocol Runs a JSON RPC server behind an

    editor Build · Format · CLI · LSP · Translate
  75. Language server protocol Runs a JSON RPC server behind an

    editor textDocument/didChange textDocument/didOpen textDocument/didClose Build · Format · CLI · LSP · Translate
  76. Language server protocol Runs a JSON RPC server behind an

    editor textDocument/didChange textDocument/didOpen textDocument/didClose textDocument/formatting Build · Format · CLI · LSP · Translate
  77. Language server protocol Runs a JSON RPC server behind an

    editor textDocument/didChange textDocument/didOpen textDocument/didClose textDocument/formatting textDocument/inlayHint Build · Format · CLI · LSP · Translate
  78. Shopify/ruby-lsp Document highlight Document symbols Folding ranges Formatting Selection ranges

    Semantic highlighting Build · Format · CLI · LSP · Translate