1
1
mirror of https://github.com/oxalica/nil.git synced 2024-11-23 03:57:06 +03:00

Add add_to_top_level_lambda_param assist

This commit is contained in:
figsoda 2022-12-04 00:36:36 -05:00 committed by oxalica
parent cbc6298c7a
commit 101387fb2f
3 changed files with 95 additions and 0 deletions

View File

@ -0,0 +1,91 @@
//! Add an undefined name to the top-level lambda.
//!
//! ```nix
//! { foo }: foo + bar
//! ```
//! =>
//! ```nix
//! { foo, bar }: foo + bar
//! ```
use super::{AssistKind, AssistsCtx};
use crate::TextEdit;
use syntax::ast::{self, AstNode};
use syntax::{SyntaxNodePtr, TextRange, TextSize};
pub(super) fn add_to_top_level_lambda_param(ctx: &mut AssistsCtx<'_>) -> Option<()> {
let node = ctx.covering_node::<ast::Ref>()?;
let name = node.token()?;
let name = name.text();
// The whole file should be a lambda.
let pat = ast::Lambda::cast(ctx.ast.syntax().first_child()?)?
.param()?
.pat()?;
// Name should be undefined.
let expr = ctx
.db
.source_map(ctx.frange.file_id)
.expr_for_node(SyntaxNodePtr::new(node.syntax()))?;
if ctx
.db
.name_resolution(ctx.frange.file_id)
.get(expr)
.is_some()
{
return None;
};
let (pos, insert) = if let Some(field) = pat.fields().last() {
let field = field.syntax();
let mut pos = field.text_range().end();
// Insert before the space if the field ends with a space.
if matches!(field.last_token(), Some(tok) if tok.text().ends_with(' ')) {
pos -= TextSize::from(1);
}
(pos, format!(", {name}"))
} else if let Some(ellipsis) = pat.ellipsis_token() {
(ellipsis.text_range().start(), format!("{name}, "))
} else if let Some(curly) = pat.r_curly_token() {
(curly.text_range().start(), format!("{name} "))
} else {
(pat.syntax().text_range().start(), name.into())
};
ctx.add(
"add_to_top_level_lambda_param",
format!("Add `{name}` to the top-level lambda parameter"),
AssistKind::QuickFix,
vec![TextEdit {
delete: TextRange::new(pos, pos),
insert: insert.into(),
}],
);
Some(())
}
#[cfg(test)]
mod tests {
use expect_test::expect;
define_check_assist!(super::add_to_top_level_lambda_param);
#[test]
fn simple() {
check("{ }: foo$0", expect!["{ foo }: foo"]);
check("{}: foo$0", expect!["{foo }: foo"]);
check("{ foo }: b$0ar", expect!["{ foo, bar }: bar"]);
check("{foo}: $0bar", expect!["{foo, bar}: bar"]);
check("{ ... }: foo$0", expect!["{ foo, ... }: foo"]);
check("{...}: foo$0", expect!["{foo, ...}: foo"]);
check("{foo, ...}: $0bar", expect!["{foo, bar, ...}: bar"]);
check("{foo,...}: $0bar", expect!["{foo, bar,...}: bar"]);
check_no("{ foo }: fo$0o");
check_no("{ }: foo.$0bar");
check_no("{ }: let foo = bar; in f$0oo");
check_no("{ bar }: { fo$0o = bar; }");
check_no("bar: fo$0o");
}
}

View File

@ -10,6 +10,7 @@ macro_rules! define_check_assist {
};
}
mod add_to_top_level_lambda_param;
mod convert_to_inherit;
mod flatten_attrset;
mod pack_bindings;
@ -30,11 +31,13 @@ pub struct Assist {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AssistKind {
QuickFix,
RefactorRewrite,
}
pub(crate) fn assists(db: &dyn DefDatabase, frange: FileRange) -> Vec<Assist> {
let handlers = [
add_to_top_level_lambda_param::add_to_top_level_lambda_param,
convert_to_inherit::convert_to_inherit,
flatten_attrset::flatten_attrset,
pack_bindings::pack_bindings,

View File

@ -306,6 +306,7 @@ pub(crate) fn to_code_action(vfs: &Vfs, assist: Assist) -> CodeActionOrCommand {
CodeActionOrCommand::CodeAction(CodeAction {
title: assist.label,
kind: Some(match assist.kind {
AssistKind::QuickFix => CodeActionKind::QUICKFIX,
AssistKind::RefactorRewrite => CodeActionKind::REFACTOR_REWRITE,
}),
diagnostics: None,