Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use emmylua_parser::{
LuaSyntaxKind,
};
use rowan::{NodeOrToken, TextRange};
use serde_json::json;

use crate::{
DiagnosticCode, LuaDeclId, LuaSemanticDeclId, SemanticDeclLevel, SemanticModel,
Expand Down Expand Up @@ -247,7 +248,9 @@ fn check_index_expr_preference(
name = alias_info.preferred_name
)
.to_string(),
None,
Some(json!({
"preferredAlias": alias_info.preferred_name.clone(),
})),
);
}

Expand Down
3 changes: 3 additions & 0 deletions crates/emmylua_ls/locales/action/zh_CN.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ Do you want to modify the require path?: |

Modify: |
修改

Replace with local alias '%{name}': |
替换为本地变量别名 '%{name}'
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,29 @@ pub fn build_add_doc_tag(

Some(())
}

pub fn build_preferred_local_alias_fix(
semantic_model: &SemanticModel,
actions: &mut Vec<CodeActionOrCommand>,
range: Range,
data: &Option<serde_json::Value>,
) -> Option<()> {
let alias_name = data.as_ref()?.get("preferredAlias")?.as_str()?;
let document = semantic_model.get_document();
let text_edit = TextEdit {
range,
new_text: alias_name.to_string(),
};

actions.push(CodeActionOrCommand::CodeAction(CodeAction {
title: t!("Replace with local alias '%{name}'", name = alias_name).to_string(),
kind: Some(CodeActionKind::QUICKFIX),
edit: Some(WorkspaceEdit {
changes: Some(HashMap::from([(document.get_uri(), vec![text_edit])])),
..Default::default()
}),
..Default::default()
}));

Some(())
}
9 changes: 5 additions & 4 deletions crates/emmylua_ls/src/handlers/code_actions/build_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ use lsp_types::{

use super::actions::{
build_add_doc_tag, build_disable_file_changes, build_disable_next_line_changes,
build_need_check_nil, build_preferred_local_alias_fix,
};
use crate::handlers::{
code_actions::actions::build_need_check_nil,
command::{DisableAction, make_disable_code_command},
};
use crate::handlers::command::{DisableAction, make_disable_code_command};

pub fn build_actions(
semantic_model: &SemanticModel,
Expand Down Expand Up @@ -71,6 +69,9 @@ fn add_fix_code_action(
match diagnostic_code {
DiagnosticCode::NeedCheckNil => build_need_check_nil(semantic_model, actions, range, data),
DiagnosticCode::UnknownDocTag => build_add_doc_tag(semantic_model, actions, range, data),
DiagnosticCode::PreferredLocalAlias => {
build_preferred_local_alias_fix(semantic_model, actions, range, data)
}
_ => Some(()),
}
}
Expand Down
68 changes: 60 additions & 8 deletions crates/emmylua_ls/src/handlers/document_symbol/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,25 +45,48 @@ impl<'a> DocumentSymbolBuilder<'a> {
.clone()
}

pub fn add_node_symbol(&mut self, node: LuaSyntaxNode, symbol: LuaSymbol) {
pub fn add_node_symbol(
&mut self,
node: LuaSyntaxNode,
symbol: LuaSymbol,
parent: Option<LuaSyntaxId>,
) -> LuaSyntaxId {
let syntax_id = LuaSyntaxId::new(node.kind(), node.text_range());
self.document_symbols.insert(syntax_id, Box::new(symbol));
let mut node = node;
while let Some(parent) = node.parent() {
let parent_syntax_id = LuaSyntaxId::new(parent.kind(), parent.text_range());
if let Some(symbol) = self.document_symbols.get_mut(&parent_syntax_id) {
symbol.add_child(syntax_id);

if let Some(parent_id) = parent {
self.link_parent_child(parent_id, syntax_id);
return syntax_id;
}

let mut current = node;
while let Some(parent_node) = current.parent() {
let parent_syntax_id = LuaSyntaxId::new(parent_node.kind(), parent_node.text_range());
if let Some(parent_symbol) = self.document_symbols.get_mut(&parent_syntax_id) {
parent_symbol.add_child(syntax_id);
break;
}

node = parent;
current = parent_node;
}

syntax_id
}

pub fn add_token_symbol(&mut self, token: LuaSyntaxToken, symbol: LuaSymbol) {
pub fn add_token_symbol(
&mut self,
token: LuaSyntaxToken,
symbol: LuaSymbol,
parent: Option<LuaSyntaxId>,
) -> LuaSyntaxId {
let syntax_id = LuaSyntaxId::new(token.kind(), token.text_range());
self.document_symbols.insert(syntax_id, Box::new(symbol));

if let Some(parent_id) = parent {
self.link_parent_child(parent_id, syntax_id);
return syntax_id;
}

let mut node = token.parent();
while let Some(parent_node) = node {
let parent_syntax_id = LuaSyntaxId::new(parent_node.kind(), parent_node.text_range());
Expand All @@ -74,6 +97,27 @@ impl<'a> DocumentSymbolBuilder<'a> {

node = parent_node.parent();
}

syntax_id
}

pub fn contains_symbol(&self, id: &LuaSyntaxId) -> bool {
self.document_symbols.contains_key(id)
}

pub fn with_symbol_mut<F>(&mut self, id: &LuaSyntaxId, func: F) -> Option<()>
where
F: FnOnce(&mut LuaSymbol),
{
let symbol = self.document_symbols.get_mut(id)?;
func(symbol);
Some(())
}

fn link_parent_child(&mut self, parent: LuaSyntaxId, child: LuaSyntaxId) {
if let Some(parent_symbol) = self.document_symbols.get_mut(&parent) {
parent_symbol.add_child(child);
}
}

#[allow(deprecated)]
Expand Down Expand Up @@ -241,4 +285,12 @@ impl LuaSymbol {
pub fn add_child(&mut self, child: LuaSyntaxId) {
self.children.push(child);
}

pub fn set_kind(&mut self, kind: SymbolKind) {
self.kind = kind;
}

pub fn set_detail(&mut self, detail: Option<String>) {
self.detail = detail;
}
}
14 changes: 6 additions & 8 deletions crates/emmylua_ls/src/handlers/document_symbol/comment.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use emmylua_parser::{LuaAstNode, LuaComment, LuaTokenKind};
use emmylua_parser::{LuaAstNode, LuaComment, LuaSyntaxId, LuaTokenKind};
use lsp_types::SymbolKind;
use rowan::NodeOrToken;

Expand All @@ -7,7 +7,8 @@ use super::builder::{DocumentSymbolBuilder, LuaSymbol};
pub fn build_doc_region_symbol(
builder: &mut DocumentSymbolBuilder,
comment: LuaComment,
) -> Option<()> {
parent_id: LuaSyntaxId,
) -> Option<LuaSyntaxId> {
let mut region_token = None;
for child in comment.syntax().children_with_tokens() {
if let NodeOrToken::Token(token) = child {
Expand All @@ -18,10 +19,7 @@ pub fn build_doc_region_symbol(
}
}

let region_token = match region_token {
Some(token) => token,
None => return Some(()),
};
let region_token = region_token?;

let description = comment
.get_description()
Expand All @@ -46,7 +44,7 @@ pub fn build_doc_region_symbol(
selection_range,
);

builder.add_node_symbol(comment.syntax().clone(), symbol);
let symbol_id = builder.add_node_symbol(comment.syntax().clone(), symbol, Some(parent_id));

Some(())
Some(symbol_id)
}
95 changes: 72 additions & 23 deletions crates/emmylua_ls/src/handlers/document_symbol/expr.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,71 @@
use emmylua_code_analysis::LuaDeclId;
use emmylua_parser::{LuaAstNode, LuaClosureExpr, LuaIndexKey, LuaSyntaxKind, LuaTableExpr};
use emmylua_parser::{
LuaAstNode, LuaClosureExpr, LuaIndexKey, LuaSyntaxId, LuaSyntaxKind, LuaTableExpr,
};
use lsp_types::SymbolKind;

use super::builder::{DocumentSymbolBuilder, LuaSymbol};

pub fn build_closure_expr_symbol(
builder: &mut DocumentSymbolBuilder,
closure: LuaClosureExpr,
) -> Option<()> {
let parent = closure.syntax().parent()?;
if !matches!(
parent.kind().into(),
LuaSyntaxKind::LocalFuncStat | LuaSyntaxKind::FuncStat
) {
parent_id: LuaSyntaxId,
) -> Option<LuaSyntaxId> {
let parent_kind = closure.syntax().parent().map(|parent| parent.kind().into());
let convert_parent_to_function = matches!(
parent_kind,
Some(LuaSyntaxKind::TableFieldAssign | LuaSyntaxKind::TableFieldValue)
);
let needs_own_symbol = match parent_kind {
Some(LuaSyntaxKind::LocalFuncStat | LuaSyntaxKind::FuncStat) => false,
Some(_) if convert_parent_to_function => false,
_ => true,
};

let param_list = closure.get_params_list()?;
let params: Vec<_> = param_list.get_params().collect();
let detail_text = format!(
"({})",
params
.iter()
.map(|param| {
if param.is_dots() {
"...".to_string()
} else {
param
.get_name_token()
.map(|token| token.get_name_text().to_string())
.unwrap_or_default()
}
})
.filter(|name| !name.is_empty())
.collect::<Vec<_>>()
.join(", ")
);
let detail = Some(detail_text.clone());

let mut effective_parent = parent_id;

if needs_own_symbol {
let symbol = LuaSymbol::new(
"closure".to_string(),
None,
detail.clone(),
SymbolKind::MODULE,
closure.get_range(),
);

builder.add_node_symbol(closure.syntax().clone(), symbol);
effective_parent =
builder.add_node_symbol(closure.syntax().clone(), symbol, Some(parent_id));
} else if convert_parent_to_function {
let detail_clone = detail.clone();
builder.with_symbol_mut(&parent_id, |symbol| {
symbol.set_kind(SymbolKind::FUNCTION);
symbol.set_detail(detail_clone);
})?;
}

let file_id = builder.get_file_id();
let param_list = closure.get_params_list()?;
for param in param_list.get_params() {
for param in params {
let decl_id = LuaDeclId::new(file_id, param.get_position());
let decl = builder.get_decl(&decl_id)?;
let typ = builder.get_type(decl_id.into());
Expand All @@ -37,21 +77,30 @@ pub fn build_closure_expr_symbol(
decl.get_range(),
);

builder.add_node_symbol(param.syntax().clone(), symbol);
builder.add_node_symbol(param.syntax().clone(), symbol, Some(effective_parent));
}

Some(())
Some(effective_parent)
}

pub fn build_table_symbol(builder: &mut DocumentSymbolBuilder, table: LuaTableExpr) -> Option<()> {
let symbol = LuaSymbol::new(
"table".to_string(),
None,
SymbolKind::STRUCT,
table.get_range(),
);
pub fn build_table_symbol(
builder: &mut DocumentSymbolBuilder,
table: LuaTableExpr,
parent_id: LuaSyntaxId,
inline_to_parent: bool,
) -> Option<LuaSyntaxId> {
let table_id = if inline_to_parent {
parent_id
} else {
let symbol = LuaSymbol::new(
"table".to_string(),
None,
SymbolKind::STRUCT,
table.get_range(),
);

builder.add_node_symbol(table.syntax().clone(), symbol);
builder.add_node_symbol(table.syntax().clone(), symbol, Some(parent_id))
};

if table.is_object() {
for field in table.get_fields() {
Expand All @@ -65,9 +114,9 @@ pub fn build_table_symbol(builder: &mut DocumentSymbolBuilder, table: LuaTableEx

let symbol = LuaSymbol::new(str_key, None, SymbolKind::FIELD, field.get_range());

builder.add_node_symbol(field.syntax().clone(), symbol);
builder.add_node_symbol(field.syntax().clone(), symbol, Some(table_id));
}
}

Some(())
Some(table_id)
}
Loading