formatter: Add support for a few common functions and fix an LSP startup issue (#3190)

This commit is contained in:
Tyler Wilding 2023-11-11 17:51:55 -05:00 committed by GitHub
parent 288624b90f
commit 2b1876f862
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 249 additions and 49 deletions

View File

@ -267,8 +267,8 @@
"type" : "default", "type" : "default",
"project" : "CMakeLists.txt", "project" : "CMakeLists.txt",
"projectTarget" : "formatter.exe (bin\\formatter.exe)", "projectTarget" : "formatter.exe (bin\\formatter.exe)",
"name" : "Tools - Formatter", "name" : "Tools - Formatter - Inplace",
"args" : ["--new", "--file", "C:\\Users\\xtvas\\Repos\\opengoal\\jak-project\\test-formatter.gc"] "args" : ["--write", "--file", "C:\\Users\\xtvas\\Repos\\opengoal\\jak-project\\goal_src\\jak2\\pc\\util\\popup-menu-h.gc"]
}, },
{ {
"type": "default", "type": "default",

View File

@ -114,6 +114,8 @@ void apply_formatting_config(
if (predefined_config && if (predefined_config &&
predefined_config->index_configs.find(i) != predefined_config->index_configs.end()) { predefined_config->index_configs.find(i) != predefined_config->index_configs.end()) {
apply_formatting_config(ref, predefined_config->index_configs.at(i)); apply_formatting_config(ref, predefined_config->index_configs.at(i));
} else if (predefined_config && predefined_config->default_index_config) {
apply_formatting_config(ref, predefined_config->default_index_config);
} else { } else {
apply_formatting_config(ref); apply_formatting_config(ref);
} }
@ -179,7 +181,7 @@ bool can_node_be_inlined(const FormatterTreeNode& curr_node, int cursor_pos) {
return false; return false;
} }
// If this is set in the config, then the form is intended to be partially inlined // If this is set in the config, then the form is intended to be partially inlined
if (curr_node.formatting_config.inline_until_index != -1) { if (curr_node.formatting_config.inline_until_index({})) {
return false; return false;
} }
// let's see if we can inline the form all on one line to do that, we recursively explore // let's see if we can inline the form all on one line to do that, we recursively explore
@ -193,7 +195,8 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
int cursor_pos = 0) { int cursor_pos = 0) {
using namespace formatter_rules; using namespace formatter_rules;
if (!curr_node.token && curr_node.refs.empty()) { if (!curr_node.token && curr_node.refs.empty()) {
return output; // special case to handle an empty list
return {"()"};
} }
// If its a token, just print the token and move on // If its a token, just print the token and move on
@ -211,6 +214,7 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
// //
// This means we may combine elements onto the same line in this step. // This means we may combine elements onto the same line in this step.
std::vector<std::string> form_lines = {}; std::vector<std::string> form_lines = {};
for (int i = 0; i < (int)curr_node.refs.size(); i++) { for (int i = 0; i < (int)curr_node.refs.size(); i++) {
const auto& ref = curr_node.refs.at(i); const auto& ref = curr_node.refs.at(i);
// Add new line entry // Add new line entry
@ -265,10 +269,10 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
} }
// Consolidate any lines if the configuration requires it // Consolidate any lines if the configuration requires it
if (curr_node.formatting_config.inline_until_index != -1) { if (curr_node.formatting_config.inline_until_index(form_lines)) {
std::vector<std::string> new_form_lines = {}; std::vector<std::string> new_form_lines = {};
for (int i = 0; i < (int)form_lines.size(); i++) { for (int i = 0; i < (int)form_lines.size(); i++) {
if (i < curr_node.formatting_config.inline_until_index) { if (i < curr_node.formatting_config.inline_until_index(form_lines)) {
if (new_form_lines.empty()) { if (new_form_lines.empty()) {
new_form_lines.push_back(form_lines.at(i)); new_form_lines.push_back(form_lines.at(i));
} else { } else {
@ -311,7 +315,7 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
} }
std::string join_formatted_lines(const std::vector<std::string> lines) { std::string join_formatted_lines(const std::vector<std::string> lines) {
// TODO - respect original file line endings? // TODO - respect original file line endings
return fmt::format("{}", fmt::join(lines, "\n")); return fmt::format("{}", fmt::join(lines, "\n"));
} }

View File

@ -5,13 +5,34 @@
namespace formatter_rules { namespace formatter_rules {
namespace config { namespace config {
// TODO - populate these more
// TODO - this could be greatly simplified with C++20's designated initialization // TODO - this could be greatly simplified with C++20's designated initialization
FormFormattingConfig new_flow_rule(int start_index) { FormFormattingConfig new_flow_rule(int start_index) {
FormFormattingConfig cfg; FormFormattingConfig cfg;
cfg.hang_forms = false; cfg.hang_forms = false;
cfg.inline_until_index = start_index; cfg.inline_until_index = [start_index](const std::vector<std::string>& curr_lines) {
return start_index;
};
return cfg;
}
FormFormattingConfig new_flow_rule_prevent_inlining_indexes(
int start_index,
const std::vector<int>& inlining_preventation_indices) {
FormFormattingConfig cfg;
cfg.hang_forms = false;
cfg.inline_until_index = [start_index](std::vector<std::string> curr_lines) {
if (curr_lines.size() >= 4 && curr_lines.at(3) == "()") {
return 4;
}
return start_index;
};
for (const auto& index : inlining_preventation_indices) {
auto temp_config = std::make_shared<FormFormattingConfig>();
temp_config->prevent_inlining = true;
temp_config->hang_forms = false;
temp_config->indentation_width = 1;
cfg.index_configs.emplace(index, temp_config);
}
return cfg; return cfg;
} }
@ -41,9 +62,27 @@ FormFormattingConfig new_binding_rule() {
return cfg; return cfg;
} }
FormFormattingConfig new_pair_rule(bool combine_first_two_expr) {
FormFormattingConfig cfg;
cfg.hang_forms = false;
cfg.prevent_inlining = true;
cfg.combine_first_two_lines = combine_first_two_expr;
auto pair_config = std::make_shared<FormFormattingConfig>();
pair_config->hang_forms = false;
pair_config->indentation_width = 1;
cfg.default_index_config = pair_config;
return cfg;
}
const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config = { const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config = {
{"case", new_pair_rule(true)},
{"cond", new_pair_rule(false)},
{"defmethod", new_flow_rule(3)},
{"deftype", new_flow_rule_prevent_inlining_indexes(3, {3, 4, 5})},
{"defun", new_flow_rule(3)}, {"defun", new_flow_rule(3)},
{"defmethod", new_flow_rule(4)}, {"dotimes", new_flow_rule(2)},
{"let", new_binding_rule()}}; {"let", new_binding_rule()},
{"when", new_flow_rule(2)},
{"with-dma-buffer-add-bucket", new_flow_rule(2)}};
} // namespace config } // namespace config
} // namespace formatter_rules } // namespace formatter_rules

View File

@ -19,13 +19,16 @@ struct FormFormattingConfig {
std::function<int(FormFormattingConfig, int)> indentation_width_for_index = std::function<int(FormFormattingConfig, int)> indentation_width_for_index =
[](FormFormattingConfig config, int /*index*/) { return config.indentation_width; }; [](FormFormattingConfig config, int /*index*/) { return config.indentation_width; };
bool combine_first_two_lines = bool combine_first_two_lines =
false; // NOTE - basically hang, but will probably stick around after hang is gone false; // NOTE - basically hang, but will probably stick around after hang is gone, may be
int inline_until_index = -1; // redundant (inline_until_index!)
std::function<std::optional<int>(const std::vector<std::string>& curr_lines)> inline_until_index =
[](std::vector<std::string> curr_lines) { return std::nullopt; };
bool has_constant_pairs = false; bool has_constant_pairs = false;
bool prevent_inlining = false; bool prevent_inlining = false; // TODO - duplicate of below
std::function<bool(FormFormattingConfig, int num_refs)> should_prevent_inlining = std::function<bool(FormFormattingConfig, int num_refs)> should_prevent_inlining =
[](FormFormattingConfig config, int /*num_refs*/) { return config.prevent_inlining; }; [](FormFormattingConfig config, int /*num_refs*/) { return config.prevent_inlining; };
int parent_mutable_extra_indent = 0; int parent_mutable_extra_indent = 0;
std::optional<std::shared_ptr<FormFormattingConfig>> default_index_config;
std::unordered_map<int, std::shared_ptr<FormFormattingConfig>> index_configs = {}; std::unordered_map<int, std::shared_ptr<FormFormattingConfig>> index_configs = {};
}; };

View File

@ -153,8 +153,10 @@ void set_file(const std::string& filename,
} }
} }
} else { } else {
if (!str_util::ends_with(complete_filename, ".log")) {
complete_filename += ".log"; complete_filename += ".log";
} }
}
if (append) { if (append) {
gLogger.fp = file_util::open_file(complete_filename.c_str(), "a"); gLogger.fp = file_util::open_file(complete_filename.c_str(), "a");

View File

@ -17,12 +17,16 @@
(set! (-> font-ctx origin y) 75.0) (set! (-> font-ctx origin y) 75.0)
(with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf)) (bucket-id debug-no-zbuf1)) (with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf)) (bucket-id debug-no-zbuf1))
;; background border ;; background border
(draw-sprite2d-xy buf 6 64 (draw-sprite2d-xy buf
6
64
(+ 17 (the int (get-widest-label this font-ctx))) ;; width (+ 17 (the int (get-widest-label this font-ctx))) ;; width
(+ 17 (* 15 (-> this entries length))) ;; height (+ 17 (* 15 (-> this entries length))) ;; height
(new 'static 'rgba :r 255 :g 255 :b 255 :a 75)) (new 'static 'rgba :r 255 :g 255 :b 255 :a 75))
;; background ;; background
(draw-sprite2d-xy buf 7 65 (draw-sprite2d-xy buf
7
65
(+ 15 (the int (get-widest-label this font-ctx))) ;; width (+ 15 (the int (get-widest-label this font-ctx))) ;; width
(+ 15 (* 15 (-> this entries length))) ;; height (+ 15 (* 15 (-> this entries length))) ;; height
(new 'static 'rgba :r 0 :g 0 :b 0 :a 255)) (new 'static 'rgba :r 0 :g 0 :b 0 :a 255))
@ -30,19 +34,13 @@
(dotimes (i (-> this entries length)) (dotimes (i (-> this entries length))
(cond (cond
;; TODO - probably just handle this in the draw methods ;; TODO - probably just handle this in the draw methods
((type? (-> this entries i) popup-menu-label) ((type? (-> this entries i) popup-menu-label) (set! (-> font-ctx color) (font-color progress-option-off)))
(set! (-> font-ctx color) (font-color progress-option-off)))
((type? (-> this entries i) popup-menu-flag) ((type? (-> this entries i) popup-menu-flag)
(set! (-> font-ctx color) (set! (-> font-ctx color)
(if (or ((-> (the-as popup-menu-flag (-> this entries i)) is-toggled?)) (if (or ((-> (the-as popup-menu-flag (-> this entries i)) is-toggled?)) (= i (-> this curr-entry-index)))
(= i (-> this curr-entry-index)))
(font-color cyan) (font-color cyan)
(font-color default)))) (font-color default))))
(else (else (set! (-> font-ctx color) (if (= i (-> this curr-entry-index)) (font-color cyan) (font-color default)))))
(set! (-> font-ctx color)
(if (= i (-> this curr-entry-index))
(font-color cyan)
(font-color default)))))
(draw! (-> this entries i) font-ctx buf) (draw! (-> this entries i) font-ctx buf)
(set! (-> font-ctx origin y) (+ 15.0 (-> font-ctx origin y)))))) (set! (-> font-ctx origin y) (+ 15.0 (-> font-ctx origin y))))))
(none)) (none))
@ -62,8 +60,7 @@
(none)) (none))
(defmethod press! ((this popup-menu)) (defmethod press! ((this popup-menu))
(let ((entry (-> this entries (-> this curr-entry-index)))) (let ((entry (-> this entries (-> this curr-entry-index)))) ((-> entry on-press)))
((-> entry on-press)))
(none)) (none))
(defmethod get-widest-label ((this popup-menu) (font-ctx font-context)) (defmethod get-widest-label ((this popup-menu) (font-ctx font-context))

View File

@ -36,7 +36,8 @@
void setup_logging(bool verbose, std::string log_file, bool disable_ansi_colors) { void setup_logging(bool verbose, std::string log_file, bool disable_ansi_colors) {
if (!log_file.empty()) { if (!log_file.empty()) {
lg::set_file(log_file, false, true, fs::path(log_file).parent_path().string()); lg::set_file(fs::path(log_file).filename().string(), false, true,
fs::path(log_file).parent_path().string());
} }
if (verbose) { if (verbose) {
lg::set_file_level(lg::level::debug); lg::set_file_level(lg::level::debug);

View File

@ -0,0 +1,91 @@
===
Cond - Only Inlinable
===
(cond
((type? (-> this entries i) popup-menu-label)
(set! x 1))
((type? (-> this entries i) popup-menu-flag)
(set! x 2))
(else
(set! x 3)))
---
(cond
((type? (-> this entries i) popup-menu-label) (set! x 1))
((type? (-> this entries i) popup-menu-flag) (set! x 2))
(else (set! x 3)))
===
Cond - Mix and Match Inlining
===
(cond
((type? (-> this entries i) popup-menu-flag)
(set! x (+ 89716239781623717236123 1239817239817298319287312 31298371298371239817231 231892739182739129837 231892739182739129837 231892739182739129837)))
((type? (-> this entries i) popup-menu-label)
(set! x 1))
(else
(set! x 3)))
---
(cond
((type? (-> this entries i) popup-menu-flag)
(set! x
(+ 89716239781623717236123
1239817239817298319287312
31298371298371239817231
231892739182739129837
231892739182739129837
231892739182739129837)))
((type? (-> this entries i) popup-menu-label) (set! x 1))
(else (set! x 3)))
===
Case - Only Inlinable
===
(case (-> arg3 param 0)
(('dark)
(set! x 1))
(('light)
(set! x 2))
(else
(set! x 3)))
---
(case (-> arg3 param 0)
(('dark) (set! x 1))
(('light) (set! x 2))
(else (set! x 3)))
===
Case - Mix and Match Inlining
===
(case (-> arg3 param 0)
(('dark)
(set! x 1))
(('light)
(set! x (+ 89716239781623717236123 1239817239817298319287312 31298371298371239817231 231892739182739129837 231892739182739129837 231892739182739129837 231892739182739129837 231892739182739129837)))
(else
(set! x 3)))
---
(case (-> arg3 param 0)
(('dark) (set! x 1))
(('light)
(set! x
(+ 89716239781623717236123
1239817239817298319287312
31298371298371239817231
231892739182739129837
231892739182739129837
231892739182739129837
231892739182739129837
231892739182739129837)))
(else (set! x 3)))

View File

@ -0,0 +1,15 @@
===
dotimes
===
(dotimes (i (-> this entries length))
(let ((label-len (-> (get-string-length (-> this entries i label) font-ctx) length)))
(when (> label-len max-len)
(set! max-len label-len))))
---
(dotimes (i (-> this entries length))
(let ((label-len (-> (get-string-length (-> this entries i label) font-ctx) length)))
(when (> label-len max-len)
(set! max-len label-len))))

View File

@ -22,3 +22,13 @@ Constant List - Too Long to Inline
444444444444444444444444444 444444444444444444444444444
555555555555555555555555555555555 555555555555555555555555555555555
666666666666666666666666666666666666666) 666666666666666666666666666666666666666)
===
Empty List
===
()
---
()

View File

@ -0,0 +1,35 @@
===
Types - With Methods
===
(deftype popup-menu (basic)
((entries (array popup-menu-entry))
(curr-entry-index int32))
(:methods
(draw! (_type_) none)
(move-up! (_type_) none)
(move-down! (_type_) none)
(press! (_type_) none)
(get-widest-label (_type_ font-context) float)))
---
(deftype popup-menu (basic)
((entries (array popup-menu-entry))
(curr-entry-index int32))
(:methods
(draw! (_type_) none)
(move-up! (_type_) none)
(move-down! (_type_) none)
(press! (_type_) none)
(get-widest-label (_type_ font-context) float)))
===
Types - Empty
===
(deftype popup-menu-label (popup-menu-entry) ())
---
(deftype popup-menu-label (popup-menu-entry) ())

View File

@ -47,15 +47,18 @@ int main(int argc, char** argv) {
// TODO - support recursing directories // TODO - support recursing directories
// Read in source code // Read in source code
const auto source_code = file_util::read_text_file(file_path); const auto source_code = file_util::read_text_file(file_path);
const auto result = formatter::format_code(source_code); const auto result = formatter::format_code(source_code);
if (write_newfile && result) { if (result) {
// TODO - i don't like this implementation, return a new string instead // TODO - i don't like this implementation, return a new string instead
if (write_inplace) {
file_util::write_text_file(file_path, result.value());
} else if (write_newfile) {
if (str_util::replace(file_path, ".gc", ".new.gc")) { if (str_util::replace(file_path, ".gc", ".new.gc")) {
file_util::write_text_file(file_path, result.value()); file_util::write_text_file(file_path, result.value());
} }
} }
}
return 0; return 0;
} }