From 82aa450af2ef24cbdf480cb3ee6149a0ed69caab Mon Sep 17 00:00:00 2001 From: dean-starkware Date: Thu, 19 Sep 2024 15:31:14 +0300 Subject: [PATCH] add closing parenthesis to methods completion (#6380) --- .../src/formatter_impl.rs | 26 ++++++++- crates/cairo-lang-formatter/src/test.rs | 5 ++ .../cairo_files/sorted_mod_use.cairo | 17 ++++++ .../expected_results/sorted_mod_use.cairo | 16 ++++++ .../src/ide/completion/completions.rs | 3 +- .../tests/e2e/completions.rs | 3 ++ .../completions/methods_text_edits.txt | 54 +++++++++++++++++++ .../diagnostics/expr_diagnostics | 4 ++ .../src/parser_test_data/partial_trees/use | 51 +++++++++++++++--- scripts/cairo_fmt.sh | 2 +- 10 files changed, 171 insertions(+), 10 deletions(-) create mode 100644 crates/cairo-lang-formatter/test_data/cairo_files/sorted_mod_use.cairo create mode 100644 crates/cairo-lang-formatter/test_data/expected_results/sorted_mod_use.cairo diff --git a/crates/cairo-lang-formatter/src/formatter_impl.rs b/crates/cairo-lang-formatter/src/formatter_impl.rs index 07baccea800..10d8d9dc0a1 100644 --- a/crates/cairo-lang-formatter/src/formatter_impl.rs +++ b/crates/cairo-lang-formatter/src/formatter_impl.rs @@ -817,6 +817,7 @@ impl<'a> FormatterImpl<'a> { } self.append_break_line_point(node_break_points.trailing()); } + /// Formats an internal node and appends the formatted string to the result. fn format_internal(&mut self, syntax_node: &SyntaxNode) { let allowed_empty_between = syntax_node.allowed_empty_between(self.db); @@ -826,8 +827,19 @@ impl<'a> FormatterImpl<'a> { let mut children = self.db.get_children(syntax_node.clone()).to_vec(); let n_children = children.len(); if self.config.sort_module_level_items { - children.sort_by_key(|c| MovableNode::new(self.db, c)); - }; + let mut start_idx = 0; + while start_idx < children.len() { + let kind = Self::sort_kind(self.db, &children[start_idx]); + let mut end_idx = start_idx + 1; + while end_idx < children.len() + && Self::match_sort_kind(self.db, &children[end_idx], kind) + { + end_idx += 1; + } + children[start_idx..end_idx].sort_by_key(|c| MovableNode::new(self.db, c)); + start_idx = end_idx; + } + } for (i, child) in children.iter().enumerate() { if child.width(self.db) == TextWidth::default() { continue; @@ -843,6 +855,16 @@ impl<'a> FormatterImpl<'a> { self.empty_lines_allowance = allowed_empty_between; } } + + /// Determines the "kind" for sorting (e.g., mod, use) + fn sort_kind(db: &dyn SyntaxGroup, node: &SyntaxNode) -> SyntaxKind { + node.kind(db) + } + + /// Matches the current node's kind with the given kind + fn match_sort_kind(db: &dyn SyntaxGroup, node: &SyntaxNode, kind: SyntaxKind) -> bool { + node.kind(db) == kind + } /// Formats a terminal node and appends the formatted string to the result. fn format_terminal(&mut self, syntax_node: &SyntaxNode) { // TODO(spapini): Introduce a Terminal and a Token enum in ast.rs to make this cleaner. diff --git a/crates/cairo-lang-formatter/src/test.rs b/crates/cairo-lang-formatter/src/test.rs index b8f598dc3f9..c0665b6caf7 100644 --- a/crates/cairo-lang-formatter/src/test.rs +++ b/crates/cairo-lang-formatter/src/test.rs @@ -41,6 +41,11 @@ impl Upcast for DatabaseImpl { "test_data/expected_results/fmt_skip.cairo", false )] +#[test_case( + "test_data/cairo_files/sorted_mod_use.cairo", + "test_data/expected_results/sorted_mod_use.cairo", + false +)] fn format_and_compare_file(unformatted_filename: &str, expected_filename: &str, use_sorting: bool) { let db_val = SimpleParserDatabase::default(); let db = &db_val; diff --git a/crates/cairo-lang-formatter/test_data/cairo_files/sorted_mod_use.cairo b/crates/cairo-lang-formatter/test_data/cairo_files/sorted_mod_use.cairo new file mode 100644 index 00000000000..253bb7dc105 --- /dev/null +++ b/crates/cairo-lang-formatter/test_data/cairo_files/sorted_mod_use.cairo @@ -0,0 +1,17 @@ +mod zeta; +mod alpha; +mod gamma; + +use std::fs; +use std::io::Write; +use std::path::PathBuf; +use std::collections::HashMap; +use std::env; + +mod beta; +use crate::utils::{a, b, d, c}; + +fn main() { + // Example function + println!("Hello, world!"); +} diff --git a/crates/cairo-lang-formatter/test_data/expected_results/sorted_mod_use.cairo b/crates/cairo-lang-formatter/test_data/expected_results/sorted_mod_use.cairo new file mode 100644 index 00000000000..b1e451393ef --- /dev/null +++ b/crates/cairo-lang-formatter/test_data/expected_results/sorted_mod_use.cairo @@ -0,0 +1,16 @@ +mod alpha; +mod beta; +mod gamma; +mod zeta; + +use crate::utils::{a, b, c, d}; +use std::collections::HashMap; +use std::env; +use std::fs; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Example function + println!("Hello, world!"); +} diff --git a/crates/cairo-lang-language-server/src/ide/completion/completions.rs b/crates/cairo-lang-language-server/src/ide/completion/completions.rs index 452a3190bc8..f0ad3d21eee 100644 --- a/crates/cairo-lang-language-server/src/ide/completion/completions.rs +++ b/crates/cairo-lang-language-server/src/ide/completion/completions.rs @@ -281,7 +281,8 @@ pub fn completion_for_method( let completion = CompletionItem { label: format!("{}()", name), - insert_text: Some(format!("{}(", name)), + insert_text: Some(format!("{}($0)", name)), + insert_text_format: Some(tower_lsp::lsp_types::InsertTextFormat::SNIPPET), detail: Some(detail), kind: Some(CompletionItemKind::METHOD), additional_text_edits: Some(additional_text_edits), diff --git a/crates/cairo-lang-language-server/tests/e2e/completions.rs b/crates/cairo-lang-language-server/tests/e2e/completions.rs index 840e94eac45..e8901e84703 100644 --- a/crates/cairo-lang-language-server/tests/e2e/completions.rs +++ b/crates/cairo-lang-language-server/tests/e2e/completions.rs @@ -63,6 +63,9 @@ fn test_completions_text_edits( if let Some(text_edit) = completion.additional_text_edits { report.push_str("--------------------------\n"); report.push_str(format!("Completion: {}\n", completion.label).as_str()); + if let Some(text) = completion.insert_text { + report.push_str(format!("Insert text: {text}\n").as_str()); + } for edit in text_edit { report.push_str(format!("Text edit: {}", edit.new_text).as_str()); } diff --git a/crates/cairo-lang-language-server/tests/test_data/completions/methods_text_edits.txt b/crates/cairo-lang-language-server/tests/test_data/completions/methods_text_edits.txt index b950f2bcd45..799334c3c00 100644 --- a/crates/cairo-lang-language-server/tests/test_data/completions/methods_text_edits.txt +++ b/crates/cairo-lang-language-server/tests/test_data/completions/methods_text_edits.txt @@ -33,74 +33,101 @@ mod inner_mod { x.some_me -------------------------- Completion: add_eq() +Insert text: add_eq($0) Text edit: use core::traits::AddEq; -------------------------- Completion: sub_eq() +Insert text: sub_eq($0) Text edit: use core::traits::SubEq; -------------------------- Completion: mul_eq() +Insert text: mul_eq($0) Text edit: use core::traits::MulEq; -------------------------- Completion: into() +Insert text: into($0) -------------------------- Completion: try_into() +Insert text: try_into($0) -------------------------- Completion: destruct() +Insert text: destruct($0) -------------------------- Completion: panic_destruct() +Insert text: panic_destruct($0) -------------------------- Completion: new_inputs() +Insert text: new_inputs($0) Text edit: use core::circuit::CircuitInputs; -------------------------- Completion: get_descriptor() +Insert text: get_descriptor($0) -------------------------- Completion: clone() +Insert text: clone($0) -------------------------- Completion: is_zero() +Insert text: is_zero($0) Text edit: use core::num::traits::Zero; -------------------------- Completion: is_non_zero() +Insert text: is_non_zero($0) Text edit: use core::num::traits::Zero; -------------------------- Completion: is_one() +Insert text: is_one($0) Text edit: use core::num::traits::One; -------------------------- Completion: is_non_one() +Insert text: is_non_one($0) Text edit: use core::num::traits::One; -------------------------- Completion: add_assign() +Insert text: add_assign($0) Text edit: use core::ops::AddAssign; -------------------------- Completion: sub_assign() +Insert text: sub_assign($0) Text edit: use core::ops::SubAssign; -------------------------- Completion: mul_assign() +Insert text: mul_assign($0) Text edit: use core::ops::MulAssign; -------------------------- Completion: serialize() +Insert text: serialize($0) -------------------------- Completion: print() +Insert text: print($0) -------------------------- Completion: fmt() +Insert text: fmt($0) Text edit: use core::fmt::Display; -------------------------- Completion: fmt() +Insert text: fmt($0) Text edit: use core::fmt::Debug; -------------------------- Completion: fmt() +Insert text: fmt($0) Text edit: use core::fmt::LowerHex; -------------------------- Completion: is_zero() +Insert text: is_zero($0) -------------------------- Completion: is_non_zero() +Insert text: is_non_zero($0) -------------------------- Completion: append_formatted_to_byte_array() +Insert text: append_formatted_to_byte_array($0) Text edit: use core::to_byte_array::AppendFormattedToByteArray; -------------------------- Completion: format_as_byte_array() +Insert text: format_as_byte_array($0) Text edit: use core::to_byte_array::FormatAsByteArray; -------------------------- Completion: some_method() +Insert text: some_method($0) Text edit: use super::ATrait1; //! > ========================================================================== @@ -141,72 +168,99 @@ mod inner_mod { x.some_me -------------------------- Completion: add_eq() +Insert text: add_eq($0) Text edit: use core::traits::AddEq; -------------------------- Completion: sub_eq() +Insert text: sub_eq($0) Text edit: use core::traits::SubEq; -------------------------- Completion: mul_eq() +Insert text: mul_eq($0) Text edit: use core::traits::MulEq; -------------------------- Completion: into() +Insert text: into($0) -------------------------- Completion: try_into() +Insert text: try_into($0) -------------------------- Completion: destruct() +Insert text: destruct($0) -------------------------- Completion: panic_destruct() +Insert text: panic_destruct($0) -------------------------- Completion: new_inputs() +Insert text: new_inputs($0) Text edit: use core::circuit::CircuitInputs; -------------------------- Completion: get_descriptor() +Insert text: get_descriptor($0) -------------------------- Completion: clone() +Insert text: clone($0) -------------------------- Completion: is_zero() +Insert text: is_zero($0) Text edit: use core::num::traits::Zero; -------------------------- Completion: is_non_zero() +Insert text: is_non_zero($0) Text edit: use core::num::traits::Zero; -------------------------- Completion: is_one() +Insert text: is_one($0) Text edit: use core::num::traits::One; -------------------------- Completion: is_non_one() +Insert text: is_non_one($0) Text edit: use core::num::traits::One; -------------------------- Completion: add_assign() +Insert text: add_assign($0) Text edit: use core::ops::AddAssign; -------------------------- Completion: sub_assign() +Insert text: sub_assign($0) Text edit: use core::ops::SubAssign; -------------------------- Completion: mul_assign() +Insert text: mul_assign($0) Text edit: use core::ops::MulAssign; -------------------------- Completion: serialize() +Insert text: serialize($0) -------------------------- Completion: print() +Insert text: print($0) -------------------------- Completion: fmt() +Insert text: fmt($0) Text edit: use core::fmt::Display; -------------------------- Completion: fmt() +Insert text: fmt($0) Text edit: use core::fmt::Debug; -------------------------- Completion: fmt() +Insert text: fmt($0) Text edit: use core::fmt::LowerHex; -------------------------- Completion: is_zero() +Insert text: is_zero($0) -------------------------- Completion: is_non_zero() +Insert text: is_non_zero($0) -------------------------- Completion: append_formatted_to_byte_array() +Insert text: append_formatted_to_byte_array($0) Text edit: use core::to_byte_array::AppendFormattedToByteArray; -------------------------- Completion: format_as_byte_array() +Insert text: format_as_byte_array($0) Text edit: use core::to_byte_array::FormatAsByteArray; -------------------------- Completion: some_method() +Insert text: some_method($0) Text edit: use super::ATrait1; diff --git a/crates/cairo-lang-parser/src/parser_test_data/diagnostics/expr_diagnostics b/crates/cairo-lang-parser/src/parser_test_data/diagnostics/expr_diagnostics index 656cd43eadd..c3f3e74560a 100644 --- a/crates/cairo-lang-parser/src/parser_test_data/diagnostics/expr_diagnostics +++ b/crates/cairo-lang-parser/src/parser_test_data/diagnostics/expr_diagnostics @@ -22,6 +22,10 @@ error: Missing tokens. Expected an expression. get_diagnostics //! > cairo_code +use A; +use C; +use B; + fn f() { { 5 diff --git a/crates/cairo-lang-parser/src/parser_test_data/partial_trees/use b/crates/cairo-lang-parser/src/parser_test_data/partial_trees/use index a50854a6987..6028e60f08c 100644 --- a/crates/cairo-lang-parser/src/parser_test_data/partial_trees/use +++ b/crates/cairo-lang-parser/src/parser_test_data/partial_trees/use @@ -5,7 +5,7 @@ test_partial_parser_tree(expect_diagnostics: false) //! > cairo_code fn foo() { - use X::Y; + use A::{C, D::E::V, F::{G, H::I}}; } //! > top_level_kind @@ -22,12 +22,51 @@ ItemUse ├── use_kw (kind: TokenUse): 'use' ├── use_path (kind: UsePathSingle) │ ├── ident (kind: PathSegmentSimple) - │ │ └── ident (kind: TokenIdentifier): 'X' + │ │ └── ident (kind: TokenIdentifier): 'A' │ ├── colon_colon (kind: TokenColonColon): '::' - │ └── use_path (kind: UsePathLeaf) - │ ├── ident (kind: PathSegmentSimple) - │ │ └── ident (kind: TokenIdentifier): 'Y' - │ └── alias_clause (kind: OptionAliasClauseEmpty) [] + │ └── use_path (kind: UsePathMulti) + │ ├── lbrace (kind: TokenLBrace): '{' + │ ├── use_paths (kind: UsePathList) + │ │ ├── item #0 (kind: UsePathLeaf) + │ │ │ ├── ident (kind: PathSegmentSimple) + │ │ │ │ └── ident (kind: TokenIdentifier): 'C' + │ │ │ └── alias_clause (kind: OptionAliasClauseEmpty) [] + │ │ ├── separator #0 (kind: TokenComma): ',' + │ │ ├── item #1 (kind: UsePathSingle) + │ │ │ ├── ident (kind: PathSegmentSimple) + │ │ │ │ └── ident (kind: TokenIdentifier): 'D' + │ │ │ ├── colon_colon (kind: TokenColonColon): '::' + │ │ │ └── use_path (kind: UsePathSingle) + │ │ │ ├── ident (kind: PathSegmentSimple) + │ │ │ │ └── ident (kind: TokenIdentifier): 'E' + │ │ │ ├── colon_colon (kind: TokenColonColon): '::' + │ │ │ └── use_path (kind: UsePathLeaf) + │ │ │ ├── ident (kind: PathSegmentSimple) + │ │ │ │ └── ident (kind: TokenIdentifier): 'V' + │ │ │ └── alias_clause (kind: OptionAliasClauseEmpty) [] + │ │ ├── separator #1 (kind: TokenComma): ',' + │ │ └── item #2 (kind: UsePathSingle) + │ │ ├── ident (kind: PathSegmentSimple) + │ │ │ └── ident (kind: TokenIdentifier): 'F' + │ │ ├── colon_colon (kind: TokenColonColon): '::' + │ │ └── use_path (kind: UsePathMulti) + │ │ ├── lbrace (kind: TokenLBrace): '{' + │ │ ├── use_paths (kind: UsePathList) + │ │ │ ├── item #0 (kind: UsePathLeaf) + │ │ │ │ ├── ident (kind: PathSegmentSimple) + │ │ │ │ │ └── ident (kind: TokenIdentifier): 'G' + │ │ │ │ └── alias_clause (kind: OptionAliasClauseEmpty) [] + │ │ │ ├── separator #0 (kind: TokenComma): ',' + │ │ │ └── item #1 (kind: UsePathSingle) + │ │ │ ├── ident (kind: PathSegmentSimple) + │ │ │ │ └── ident (kind: TokenIdentifier): 'H' + │ │ │ ├── colon_colon (kind: TokenColonColon): '::' + │ │ │ └── use_path (kind: UsePathLeaf) + │ │ │ ├── ident (kind: PathSegmentSimple) + │ │ │ │ └── ident (kind: TokenIdentifier): 'I' + │ │ │ └── alias_clause (kind: OptionAliasClauseEmpty) [] + │ │ └── rbrace (kind: TokenRBrace): '}' + │ └── rbrace (kind: TokenRBrace): '}' └── semicolon (kind: TokenSemicolon): ';' //! > ========================================================================== diff --git a/scripts/cairo_fmt.sh b/scripts/cairo_fmt.sh index f85393e38f3..06cc412fe00 100755 --- a/scripts/cairo_fmt.sh +++ b/scripts/cairo_fmt.sh @@ -1,3 +1,3 @@ #!/bin/bash -cargo run --profile=ci-dev --bin cairo-format -- --recursive "$@" +cargo run --profile=ci-dev --bin cairo-format -- -s --recursive "$@"