diff --git a/crates/squawk_ide/src/code_actions/mod.rs b/crates/squawk_ide/src/code_actions/mod.rs index 13495793..d0acbc29 100644 --- a/crates/squawk_ide/src/code_actions/mod.rs +++ b/crates/squawk_ide/src/code_actions/mod.rs @@ -17,6 +17,7 @@ mod rewrite_at_time_zone_as_timezone; mod rewrite_between_as_binary_expression; mod rewrite_cast_to_double_colon; mod rewrite_collation_for_as_function_call; +mod rewrite_colon_eq_as_fat_arrow; mod rewrite_create_table_as_as_select_into; mod rewrite_double_colon_to_cast; mod rewrite_extract_as_function_call; @@ -24,6 +25,7 @@ mod rewrite_from; mod rewrite_in_as_expression; mod rewrite_integer_radix; mod rewrite_is_normalized_as_function_call; +mod rewrite_json_value_as_colon; mod rewrite_leading_from; mod rewrite_normalize_as_function_call; mod rewrite_not_equals_operator; @@ -63,6 +65,7 @@ use rewrite_at_time_zone_as_timezone::rewrite_at_time_zone_as_timezone; use rewrite_between_as_binary_expression::rewrite_between_as_binary_expression; use rewrite_cast_to_double_colon::rewrite_cast_to_double_colon; use rewrite_collation_for_as_function_call::rewrite_collation_for_as_function_call; +use rewrite_colon_eq_as_fat_arrow::rewrite_colon_eq_as_fat_arrow; use rewrite_create_table_as_as_select_into::rewrite_create_table_as_as_select_into; use rewrite_double_colon_to_cast::rewrite_double_colon_to_cast; use rewrite_extract_as_function_call::rewrite_extract_as_function_call; @@ -70,6 +73,7 @@ use rewrite_from::rewrite_from; use rewrite_in_as_expression::rewrite_in_as_expression; use rewrite_integer_radix::rewrite_integer_radix; use rewrite_is_normalized_as_function_call::rewrite_is_normalized_as_function_call; +use rewrite_json_value_as_colon::rewrite_json_value_as_colon; use rewrite_leading_from::rewrite_leading_from; use rewrite_normalize_as_function_call::rewrite_normalize_as_function_call; use rewrite_not_equals_operator::rewrite_not_equals_operator; @@ -130,6 +134,8 @@ pub fn code_actions(db: &dyn Db, position: InFile) -> Option, + actions: &mut Vec, +) -> Option<()> { + let token = token_from_offset(db, position)?; + let named_arg = token.parent_ancestors().find_map(ast::NamedArg::cast)?; + let colon_eq = named_arg.colon_eq_token()?; + + actions.push(CodeAction { + title: "Rewrite `:=` as `=>`".to_owned(), + edits: vec![Edit::replace(colon_eq.text_range(), "=>".to_owned())], + kind: ActionKind::RefactorRewrite, + }); + + Some(()) +} + +#[cfg(test)] +mod test { + use insta::assert_snapshot; + + use crate::code_actions::test_utils::{apply_code_action, code_action_not_applicable}; + + use super::rewrite_colon_eq_as_fat_arrow; + + #[test] + fn rewrites_colon_equals_as_fat_arrow() { + assert_snapshot!( + apply_code_action(rewrite_colon_eq_as_fat_arrow, "select f(name :$0= 1);"), + @"select f(name => 1);" + ); + } + + #[test] + fn applies_when_cursor_is_on_argument_value() { + assert_snapshot!( + apply_code_action( + rewrite_colon_eq_as_fat_arrow, + "select f(name := lower($0value));", + ), + @"select f(name => lower(value));" + ); + } + + #[test] + fn not_applicable_to_fat_arrow() { + assert!(code_action_not_applicable( + rewrite_colon_eq_as_fat_arrow, + "select f(name =$0> 1);" + )); + } +} diff --git a/crates/squawk_ide/src/code_actions/rewrite_json_value_as_colon.rs b/crates/squawk_ide/src/code_actions/rewrite_json_value_as_colon.rs new file mode 100644 index 00000000..5bf8fe9d --- /dev/null +++ b/crates/squawk_ide/src/code_actions/rewrite_json_value_as_colon.rs @@ -0,0 +1,84 @@ +use rowan::{TextRange, TextSize}; +use salsa::Database as Db; +use squawk_linter::Edit; +use squawk_syntax::{ + SyntaxKind, + ast::{self, AstNode}, +}; + +use crate::{file::InFile, offsets::token_from_offset}; + +use super::{ActionKind, CodeAction}; + +pub(super) fn rewrite_json_value_as_colon( + db: &dyn Db, + position: InFile, + actions: &mut Vec, +) -> Option<()> { + let token = token_from_offset(db, position)?; + let key_value = token.parent_ancestors().find_map(ast::JsonKeyValue::cast)?; + let value = key_value.value_token()?; + let start = value + .prev_token() + .filter(|token| token.kind() == SyntaxKind::WHITESPACE) + .map_or(value.text_range().start(), |token| { + token.text_range().start() + }); + + actions.push(CodeAction { + title: "Rewrite `value` as `:`".to_owned(), + edits: vec![Edit::replace( + TextRange::new(start, value.text_range().end()), + ":".to_owned(), + )], + kind: ActionKind::RefactorRewrite, + }); + + Some(()) +} + +#[cfg(test)] +mod test { + use insta::assert_snapshot; + + use crate::code_actions::test_utils::{apply_code_action, code_action_not_applicable}; + + use super::rewrite_json_value_as_colon; + + #[test] + fn rewrites_value_as_colon() { + assert_snapshot!( + apply_code_action( + rewrite_json_value_as_colon, + "select json_object('key' VAL$0UE value);", + ), + @"select json_object('key': value);" + ); + assert_snapshot!( + apply_code_action( + rewrite_json_value_as_colon, + "select json_object('key'VAL$0UE value);", + ), + @"select json_object('key': value);" + ); + } + + #[test] + fn rewrites_json_objectagg_value_as_colon() { + assert_snapshot!( + apply_code_action( + rewrite_json_value_as_colon, + "select json_objectagg(lower($0key) VALUE value);", + ), + @"select json_objectagg(lower(key): value);" + ); + } + + #[test] + fn not_applicable_to_colon() { + assert!(code_action_not_applicable( + rewrite_json_value_as_colon, + "select json_object('key' $0: value);" + )); + } +}