Skip to content

Commit 58b3e83

Browse files
committed
update builtin formatter
1 parent 4e2adb0 commit 58b3e83

File tree

7 files changed

+216
-107
lines changed

7 files changed

+216
-107
lines changed

crates/emmylua_code_analysis/src/semantic/overload_resolve/resolve_signature_by_args.rs

Lines changed: 0 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,3 @@
1-
// use std::sync::Arc;
2-
3-
// use crate::{
4-
// InferFailReason, check_type_compact,
5-
// db_index::{DbIndex, LuaFunctionType, LuaType},
6-
// semantic::infer::InferCallFuncResult,
7-
// };
8-
9-
// pub fn resolve_signature_by_args(
10-
// db: &DbIndex,
11-
// overloads: &[Arc<LuaFunctionType>],
12-
// expr_types: &[LuaType],
13-
// is_colon_call: bool,
14-
// arg_count: Option<usize>,
15-
// ) -> InferCallFuncResult {
16-
// let arg_count = arg_count.unwrap_or(0);
17-
// let mut opt_funcs = Vec::with_capacity(overloads.len());
18-
19-
// for func in overloads {
20-
// let params = func.get_params();
21-
// if params.len() < arg_count {
22-
// continue;
23-
// }
24-
// let mut total_weight = 0; // 总权重
25-
26-
// let mut fake_expr_len = expr_types.len();
27-
// let jump_param;
28-
// if is_colon_call && !func.is_colon_define() {
29-
// jump_param = 1;
30-
// fake_expr_len += 1;
31-
// } else {
32-
// jump_param = 0;
33-
// };
34-
35-
// // 如果在不计算可空参数的情况下, 参数数量完全匹配, 则认为其权重更高
36-
// if params.len() == fake_expr_len {
37-
// total_weight += params.len() as i32 + 1;
38-
// }
39-
40-
// // 冒号定义且冒号调用
41-
// if is_colon_call && func.is_colon_define() {
42-
// total_weight += 100;
43-
// }
44-
45-
// // 检查每个参数的匹配情况
46-
// for (i, param) in params.iter().enumerate() {
47-
// if i == 0 && jump_param > 0 {
48-
// // 非冒号定义但是冒号调用, 直接认为匹配
49-
// total_weight += 100;
50-
// continue;
51-
// }
52-
// let param_type = param.1.as_ref().unwrap_or(&LuaType::Any);
53-
// let expr_idx = i - jump_param;
54-
55-
// if expr_idx >= expr_types.len() {
56-
// // 没有传入参数, 但参数是可空类型
57-
// if param_type.is_nullable() {
58-
// total_weight += 1;
59-
// fake_expr_len += 1;
60-
// }
61-
// continue;
62-
// }
63-
64-
// let expr_type = &expr_types[expr_idx];
65-
// if *param_type == LuaType::Any || check_type_compact(db, param_type, expr_type).is_ok()
66-
// {
67-
// total_weight += 100; // 类型完全匹配
68-
// }
69-
// }
70-
// // 如果参数数量完全匹配, 则认为其权重更高
71-
// if params.len() == fake_expr_len {
72-
// total_weight += 50000;
73-
// }
74-
75-
// opt_funcs.push((func, total_weight));
76-
// }
77-
78-
// // 按权重降序排序
79-
// opt_funcs.sort_by(|a, b| b.1.cmp(&a.1));
80-
// // 返回权重最高的签名,若无则取最后一个重载作为默认
81-
// opt_funcs
82-
// .first()
83-
// .filter(|(_, weight)| *weight > i32::MIN) // 确保不是无效签名
84-
// .map(|(func, _)| Arc::clone(func))
85-
// .or_else(|| overloads.last().cloned())
86-
// .ok_or(InferFailReason::None)
87-
// }
88-
891
use std::sync::Arc;
902

913
use crate::{
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use crate::format::TokenExpected;
2+
3+
#[derive(Debug)]
4+
pub struct FormatterContext {
5+
pub current_expected: Option<TokenExpected>,
6+
pub is_line_first_token: bool,
7+
pub text: String,
8+
}
9+
10+
impl FormatterContext {
11+
pub fn new() -> Self {
12+
Self {
13+
current_expected: None,
14+
is_line_first_token: true,
15+
text: String::new(),
16+
}
17+
}
18+
19+
pub fn reset_whitespace(&mut self) {
20+
while self.text.ends_with(' ') {
21+
self.text.pop();
22+
}
23+
}
24+
}
Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1+
mod formatter_context;
12
mod syntax_node_change;
23

34
use std::collections::HashMap;
45

5-
use emmylua_parser::{LuaAst, LuaAstNode, LuaSyntaxId};
6+
use emmylua_parser::{LuaAst, LuaAstNode, LuaSyntaxId, LuaTokenKind};
67
use rowan::NodeOrToken;
78

8-
use crate::format::syntax_node_change::TokenNodeChange;
9+
use crate::format::formatter_context::FormatterContext;
10+
pub use crate::format::syntax_node_change::{TokenExpected, TokenNodeChange};
911

1012
#[allow(unused)]
1113
#[derive(Debug)]
1214
pub struct LuaFormatter {
1315
root: LuaAst,
1416
token_changes: HashMap<LuaSyntaxId, TokenNodeChange>,
17+
token_left_expected: HashMap<LuaSyntaxId, TokenExpected>,
18+
token_right_expected: HashMap<LuaSyntaxId, TokenExpected>,
1519
}
1620

1721
#[allow(unused)]
@@ -20,43 +24,97 @@ impl LuaFormatter {
2024
Self {
2125
root,
2226
token_changes: HashMap::new(),
27+
token_left_expected: HashMap::new(),
28+
token_right_expected: HashMap::new(),
2329
}
2430
}
2531

2632
pub fn add_token_change(&mut self, syntax_id: LuaSyntaxId, change: TokenNodeChange) {
2733
self.token_changes.insert(syntax_id, change);
2834
}
2935

36+
pub fn add_token_left_expected(&mut self, syntax_id: LuaSyntaxId, expected: TokenExpected) {
37+
self.token_left_expected.insert(syntax_id, expected);
38+
}
39+
40+
pub fn add_token_right_expected(&mut self, syntax_id: LuaSyntaxId, expected: TokenExpected) {
41+
self.token_right_expected.insert(syntax_id, expected);
42+
}
43+
3044
pub fn get_token_change(&self, syntax_id: &LuaSyntaxId) -> Option<&TokenNodeChange> {
3145
self.token_changes.get(syntax_id)
3246
}
3347

48+
pub fn get_root(&self) -> LuaAst {
49+
self.root.clone()
50+
}
51+
3452
pub fn get_formatted_text(&self) -> String {
35-
let mut formatted_text = String::new();
53+
let mut context = FormatterContext::new();
3654
for node_or_token in self.root.syntax().descendants_with_tokens() {
3755
if let NodeOrToken::Token(token) = node_or_token {
56+
let token_kind = token.kind().to_token();
57+
match (context.current_expected.take(), token_kind) {
58+
(Some(TokenExpected::Space(n)), LuaTokenKind::TkWhitespace) => {
59+
if !context.is_line_first_token {
60+
context.text.push_str(&" ".repeat(n));
61+
continue;
62+
}
63+
}
64+
(_, LuaTokenKind::TkEndOfLine) => {
65+
// No space expected
66+
context.reset_whitespace();
67+
context.text.push_str("\n");
68+
context.is_line_first_token = true;
69+
continue;
70+
}
71+
(Some(TokenExpected::Space(n)), _) => {
72+
if !context.is_line_first_token {
73+
context.text.push_str(&" ".repeat(n));
74+
}
75+
}
76+
_ => {}
77+
}
78+
3879
let syntax_id = LuaSyntaxId::from_token(&token);
80+
if let Some(expected) = self.token_left_expected.get(&syntax_id) {
81+
match expected {
82+
TokenExpected::Space(n) => {
83+
if !context.is_line_first_token {
84+
context.reset_whitespace();
85+
context.text.push_str(&" ".repeat(*n));
86+
}
87+
}
88+
}
89+
}
90+
91+
if token_kind != LuaTokenKind::TkWhitespace {
92+
context.is_line_first_token = false;
93+
}
94+
3995
if let Some(change) = self.token_changes.get(&syntax_id) {
4096
match change {
4197
TokenNodeChange::Remove => continue,
4298
TokenNodeChange::AddLeft(s) => {
43-
formatted_text.push_str(s);
44-
formatted_text.push_str(&token.text());
99+
context.text.push_str(s);
100+
context.text.push_str(&token.text());
45101
}
46102
TokenNodeChange::AddRight(s) => {
47-
formatted_text.push_str(&token.text());
48-
formatted_text.push_str(s);
103+
context.text.push_str(&token.text());
104+
context.text.push_str(s);
49105
}
50106
TokenNodeChange::ReplaceWith(s) => {
51-
formatted_text.push_str(s);
107+
context.text.push_str(s);
52108
}
53109
}
54110
} else {
55-
formatted_text.push_str(&token.text());
111+
context.text.push_str(&token.text());
56112
}
113+
114+
context.current_expected = self.token_right_expected.get(&syntax_id).cloned();
57115
}
58116
}
59117

60-
formatted_text
118+
context.text
61119
}
62120
}

crates/emmylua_code_style/src/format/syntax_node_change.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,9 @@ pub enum TokenNodeChange {
66
AddRight(String),
77
ReplaceWith(String),
88
}
9+
10+
#[allow(unused)]
11+
#[derive(Debug, Clone, Copy)]
12+
pub enum TokenExpected {
13+
Space(usize),
14+
}

crates/emmylua_code_style/src/lib.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1+
mod format;
2+
mod style_ruler;
3+
mod styles;
14
mod test;
25

36
use emmylua_parser::{LuaAst, LuaParser, ParserConfig};
47
use styles::LuaCodeStyle;
58

6-
mod format;
7-
mod style_ruler;
8-
mod styles;
9-
109
pub fn reformat_lua_code(code: &str, styles: &LuaCodeStyle) -> String {
1110
let tree = LuaParser::parse(code, ParserConfig::default());
1211

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,119 @@
1-
use crate::{format::LuaFormatter, styles::LuaCodeStyle};
1+
use emmylua_parser::{LuaAstNode, LuaSyntaxId, LuaSyntaxKind, LuaSyntaxToken, LuaTokenKind};
2+
use rowan::NodeOrToken;
3+
4+
use crate::{
5+
format::{LuaFormatter, TokenExpected},
6+
styles::LuaCodeStyle,
7+
};
28

39
use super::StyleRuler;
410

511
pub struct BasicSpaceRuler;
612

713
impl StyleRuler for BasicSpaceRuler {
8-
fn apply_style(_: &mut LuaFormatter, _: &LuaCodeStyle) {}
14+
fn apply_style(f: &mut LuaFormatter, _: &LuaCodeStyle) {
15+
let root = f.get_root();
16+
for node_or_token in root.syntax().descendants_with_tokens() {
17+
if let NodeOrToken::Token(token) = node_or_token {
18+
let syntax_id = LuaSyntaxId::from_token(&token);
19+
match token.kind().to_token() {
20+
LuaTokenKind::TkLeftParen | LuaTokenKind::TkLeftBracket => {
21+
f.add_token_right_expected(syntax_id, TokenExpected::Space(0));
22+
}
23+
LuaTokenKind::TkRightBracket | LuaTokenKind::TkRightParen => {
24+
f.add_token_left_expected(syntax_id, TokenExpected::Space(0));
25+
}
26+
LuaTokenKind::TkLeftBrace => {
27+
f.add_token_right_expected(syntax_id, TokenExpected::Space(1));
28+
}
29+
LuaTokenKind::TkRightBrace => {
30+
f.add_token_left_expected(syntax_id, TokenExpected::Space(1));
31+
}
32+
LuaTokenKind::TkComma => {
33+
f.add_token_left_expected(syntax_id, TokenExpected::Space(0));
34+
f.add_token_right_expected(syntax_id, TokenExpected::Space(1));
35+
}
36+
LuaTokenKind::TkPlus | LuaTokenKind::TkMinus => {
37+
if is_parent_syntax(&token, LuaSyntaxKind::UnaryExpr) {
38+
f.add_token_right_expected(syntax_id, TokenExpected::Space(0));
39+
continue;
40+
}
41+
42+
f.add_token_left_expected(syntax_id, TokenExpected::Space(1));
43+
f.add_token_right_expected(syntax_id, TokenExpected::Space(1));
44+
}
45+
LuaTokenKind::TkLt => {
46+
if is_parent_syntax(&token, LuaSyntaxKind::Attribute) {
47+
f.add_token_left_expected(syntax_id, TokenExpected::Space(1));
48+
f.add_token_right_expected(syntax_id, TokenExpected::Space(0));
49+
continue;
50+
}
51+
52+
f.add_token_left_expected(syntax_id, TokenExpected::Space(1));
53+
f.add_token_right_expected(syntax_id, TokenExpected::Space(1));
54+
}
55+
LuaTokenKind::TkGt => {
56+
if is_parent_syntax(&token, LuaSyntaxKind::Attribute) {
57+
f.add_token_left_expected(syntax_id, TokenExpected::Space(0));
58+
f.add_token_right_expected(syntax_id, TokenExpected::Space(1));
59+
continue;
60+
}
61+
62+
f.add_token_left_expected(syntax_id, TokenExpected::Space(1));
63+
f.add_token_right_expected(syntax_id, TokenExpected::Space(1));
64+
}
65+
LuaTokenKind::TkMul
66+
| LuaTokenKind::TkDiv
67+
| LuaTokenKind::TkIDiv
68+
| LuaTokenKind::TkMod
69+
| LuaTokenKind::TkPow
70+
| LuaTokenKind::TkConcat
71+
| LuaTokenKind::TkAssign
72+
| LuaTokenKind::TkBitAnd
73+
| LuaTokenKind::TkBitOr
74+
| LuaTokenKind::TkBitXor
75+
| LuaTokenKind::TkEq
76+
| LuaTokenKind::TkGe
77+
| LuaTokenKind::TkLe
78+
| LuaTokenKind::TkNe
79+
| LuaTokenKind::TkAnd
80+
| LuaTokenKind::TkOr
81+
| LuaTokenKind::TkShl
82+
| LuaTokenKind::TkShr => {
83+
f.add_token_left_expected(syntax_id, TokenExpected::Space(1));
84+
f.add_token_right_expected(syntax_id, TokenExpected::Space(1));
85+
}
86+
LuaTokenKind::TkColon | LuaTokenKind::TkDot => {
87+
f.add_token_left_expected(syntax_id, TokenExpected::Space(0));
88+
f.add_token_right_expected(syntax_id, TokenExpected::Space(0));
89+
}
90+
LuaTokenKind::TkLocal
91+
| LuaTokenKind::TkFunction
92+
| LuaTokenKind::TkIf
93+
| LuaTokenKind::TkWhile
94+
| LuaTokenKind::TkFor
95+
| LuaTokenKind::TkRepeat
96+
| LuaTokenKind::TkReturn
97+
| LuaTokenKind::TkDo
98+
| LuaTokenKind::TkElseIf
99+
| LuaTokenKind::TkElse
100+
| LuaTokenKind::TkThen
101+
| LuaTokenKind::TkUntil
102+
| LuaTokenKind::TkIn
103+
| LuaTokenKind::TkNot => {
104+
f.add_token_left_expected(syntax_id, TokenExpected::Space(1));
105+
f.add_token_right_expected(syntax_id, TokenExpected::Space(1));
106+
}
107+
_ => {}
108+
}
109+
}
110+
}
111+
}
112+
}
113+
114+
fn is_parent_syntax(token: &LuaSyntaxToken, kind: LuaSyntaxKind) -> bool {
115+
if let Some(parent) = token.parent() {
116+
return parent.kind().to_syntax() == kind;
117+
}
118+
false
9119
}

0 commit comments

Comments
 (0)