formatter: handle top level blank lines and better handle comments (#2702)

This commit is contained in:
Tyler Wilding
2023-06-06 19:34:50 -05:00
committed by GitHub
parent 3ecb3e4bc8
commit 3dbaee1ecc
11 changed files with 202 additions and 88 deletions
+49 -14
View File
@@ -5,11 +5,52 @@
#include "config/rule_config.h"
namespace formatter {
const std::shared_ptr<FormattingRule> default_rule = std::make_shared<FormattingRule>();
const std::shared_ptr<IndentationRule> default_rule = std::make_shared<IndentationRule>();
}
std::shared_ptr<FormattingRule> FormatterTreeNode::get_formatting_rule(const int depth,
const int index) const {
std::string get_source_code(const std::string& source, const TSNode& node) {
uint32_t start = ts_node_start_byte(node);
uint32_t end = ts_node_end_byte(node);
// TODO - comments end with a \n, this is likely a tree-sitter grammar problem
return str_util::rtrim(source.substr(start, end - start));
}
int num_blank_lines_following_node(const std::string& source, const TSNode& node) {
int num_lines = 0;
uint32_t cursor = ts_node_end_byte(node);
while (cursor < source.length() && source.at(cursor) == '\n') {
num_lines++;
cursor++;
}
return num_lines;
}
// Check if the original source only has whitespace up to a new-line after it's token
bool node_preceeded_by_only_whitespace(const std::string& source, const TSNode& node) {
uint32_t pos = ts_node_start_byte(node);
while (pos > 0) {
const auto& c = source.at(pos);
if (c == '\n') {
return true;
} else if (c == ' ' || c == '\t') {
pos--;
continue;
}
return false;
}
return true;
}
FormatterTreeNode::FormatterTreeNode(const std::string& source, const TSNode& node)
: token(get_source_code(source, node)) {
// Set any metadata based on the value of the token
metadata.is_comment = str_util::starts_with(str_util::ltrim(token.value()), ";");
metadata.num_blank_lines_following = num_blank_lines_following_node(source, node);
metadata.is_inline = !node_preceeded_by_only_whitespace(source, node);
};
std::shared_ptr<IndentationRule> FormatterTreeNode::get_formatting_rule(const int depth,
const int index) const {
// TODO - really lazy for now
if (!rules.empty()) {
return rules.at(0);
@@ -41,16 +82,9 @@ bool nodes_on_same_line(const std::string& source, const TSNode& n1, const TSNod
return !str_util::contains(code_between, "\n");
}
std::string get_source_code(const std::string& source, const TSNode& node) {
uint32_t start = ts_node_start_byte(node);
uint32_t end = ts_node_end_byte(node);
// TODO - comments end with a \n, this is likely a tree-sitter grammar problem
return str_util::rtrim(source.substr(start, end - start));
}
FormatterTree::FormatterTree(const std::string& source, const TSNode& root_node) {
root = FormatterTreeNode();
root.metadata.is_root = true;
root.metadata.is_top_level = true;
construct_formatter_tree_recursive(source, root_node, root);
}
@@ -59,7 +93,7 @@ void FormatterTree::construct_formatter_tree_recursive(const std::string& source
TSNode curr_node,
FormatterTreeNode& tree_node) {
if (ts_node_child_count(curr_node) == 0) {
tree_node.refs.push_back(FormatterTreeNode(get_source_code(source, curr_node)));
tree_node.refs.push_back(FormatterTreeNode(source, curr_node));
return;
}
const std::string curr_node_type = ts_node_type(curr_node);
@@ -80,8 +114,9 @@ void FormatterTree::construct_formatter_tree_recursive(const std::string& source
list_node.metadata.multiple_elements_first_line =
!node_followed_by_only_whitespace(source, child_node);
// Peek at the first element of the list to determine formatting rules
if (formatter::opengoal_rules.find(contents) != formatter::opengoal_rules.end()) {
list_node.rules = formatter::opengoal_rules.at(contents);
if (formatter::opengoal_indentation_rules.find(contents) !=
formatter::opengoal_indentation_rules.end()) {
list_node.rules = formatter::opengoal_indentation_rules.at(contents);
}
}
construct_formatter_tree_recursive(source, child_node, list_node);