Ruby Association Intermediate Report

In accordance with the Ruby Association’s timeline, this is an intermediate report on the Ruby formatter project.

Proposed work

When I first proposed the project, here are the list of deliverables that I mentioned in the proposal:

Current status

Progress for each bullet is detailed below.

ripper subclass

I’ve created an additional ripper subclass here: https://github.com/kddnewton/syntax_tree/blob/main/lib/syntax_tree.rb. This file lives within the published syntax_tree gem. Each node contains an instance of a SyntaxTree::Location object that can be used to get definitive information about where it existed in the source. Each node also provides attr_reader methods for each of the child nodes, which are all documented.

As a part of this work, I’ve also added documentation to all of the various node types that ship with ripper here: https://kddnewton.com/ripper-docs/. Ideally, I’d like to upstream both the syntax_tree AST builder and the ripper documentation to make it easier for others to contribute and maintain it as a part of CRuby.

prettyprint updates

In order to support all of the necessary formatting capabilities of a Ruby language formatter, I’ve opened a pull request (https://github.com/ruby/ruby/pull/5163) against Ruby that adds a bunch of new functionality to the prettyprint gem. That pull request itself has a lot of details on why the changes are necessary and details about how the gem is impacted.

Formatter

The formatter itself is baked into the syntax_tree gem. Each node has its own corresponding format node (that functions in the same spirit as the pretty_print method convention of accepting a PrettyPrint object). For example, here is the code that handles formatting an ARef node (a node in the syntax tree that corresponds to accessing a collection at an index like collection[index]).

As of the latest commit on the main branch of the syntax_tree repository, syntax_tree supports all of the Ruby 3.1 syntax. As an additional guarantee of stability, I’ve added to the test suite a test that formats all of the files shipped with Ruby twice to test for idempotency.

stree CLI

The syntax_tree gem now ships with an stree executable that functions as a CLI for formatting files. It provides a lot of additional functionality is well (like displaying the syntax tree or the doc node print tree). One additional nicety that it provides is the ability to run stree check **/* which will exit 1 if any files are not formatted as expected (which allows running this in a continuous integration environment).

Language server

Recently, I added language server support to the syntax_tree project to support integrating with editors that support the language server protocol. The code for that lives here. Currently it supports the textDocument/formatting request type, which allows formatOnSave functionality (you can turn this on in your editor of choice today by manually bundling the language server).

One additional piece of functionality that the language server provides is the custom syntaxTree/visualizing request. This request returns the syntax tree of the file corresponding to the given URI, which allows the requesting editor to display a tree-like structure inline with the code being edited. In VSCode, if you execute syntaxTree.visualize, it will now open a side-by-side tab with the displayed tree.

Future work

I still have lots of functionality I’d like to bring to syntax_tree and its related projects. I also have some far-flung dreams that may or may not come to fruition. First, here are the things that I definitely intend to complete before the end of this project:

That’s the extent of the work that corresponds to the proposed work in the grant proposal. However, I have addition desires for other future work beyond the scope of this grant. That includes:

The final report for this grant is due March 18th, and I will be publishing it here. If you’re interested in following this project, you can watch the syntax_tree repository or check/subscribe to this blog.

← Back to home