Skip to content

Commit cb668b5

Browse files
committed
support external tool range format
1 parent 2e7b259 commit cb668b5

File tree

6 files changed

+143
-20
lines changed

6 files changed

+143
-20
lines changed

crates/emmylua_code_analysis/resources/schema.json

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"$ref": "#/$defs/EmmyrcReformat",
6565
"default": {
6666
"externalTool": null,
67+
"externalToolRangeFormat": null,
6768
"useDiff": false
6869
}
6970
},
@@ -678,6 +679,7 @@
678679
"default": ""
679680
},
680681
"timeout": {
682+
"description": "The timeout for the external tool in milliseconds.",
681683
"type": "integer",
682684
"format": "uint64",
683685
"default": 5000,
@@ -873,7 +875,19 @@
873875
"type": "object",
874876
"properties": {
875877
"externalTool": {
876-
"description": "Whether to enable internal code reformatting.",
878+
"description": "Whether to enable external tool formatting.",
879+
"anyOf": [
880+
{
881+
"$ref": "#/$defs/EmmyrcExternalTool"
882+
},
883+
{
884+
"type": "null"
885+
}
886+
],
887+
"default": null
888+
},
889+
"externalToolRangeFormat": {
890+
"description": "Whether to enable external tool range formatting.",
877891
"anyOf": [
878892
{
879893
"$ref": "#/$defs/EmmyrcExternalTool"

crates/emmylua_code_analysis/src/config/configs/reformat.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ use serde::{Deserialize, Serialize};
44
#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone, Default)]
55
#[serde(rename_all = "camelCase")]
66
pub struct EmmyrcReformat {
7-
/// Whether to enable internal code reformatting.
7+
/// Whether to enable external tool formatting.
88
#[serde(default)]
99
pub external_tool: Option<EmmyrcExternalTool>,
1010

11+
/// Whether to enable external tool range formatting.
12+
#[serde(default)]
13+
pub external_tool_range_format: Option<EmmyrcExternalTool>,
14+
1115
/// Whether to use the diff algorithm for formatting.
1216
#[serde(default = "default_false")]
1317
pub use_diff: bool,
@@ -22,6 +26,7 @@ pub struct EmmyrcExternalTool {
2226
/// The arguments to pass to the external tool.
2327
#[serde(default)]
2428
pub args: Vec<String>,
29+
/// The timeout for the external tool in milliseconds.
2530
#[serde(default = "default_timeout")]
2631
pub timeout: u64,
2732
}

crates/emmylua_ls/src/handlers/document_formatting/external_format.rs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
use emmylua_code_analysis::{EmmyrcExternalTool, FormattingOptions};
2+
use rowan::TextSize;
23
use std::process::Stdio;
34
use std::time::Duration;
45
use tokio::io::AsyncWriteExt;
56
use tokio::process::Command;
67
use tokio::time::timeout;
78

9+
pub struct FormattingRange {
10+
pub start_offset: TextSize,
11+
pub end_offset: TextSize,
12+
pub start_line: u32,
13+
pub end_line: u32,
14+
}
15+
816
pub async fn external_tool_format(
917
emmyrc_external_tool: &EmmyrcExternalTool,
1018
text: &str,
1119
file_path: &str,
20+
range: Option<FormattingRange>,
1221
options: FormattingOptions,
1322
) -> Option<String> {
1423
let exe_path = &emmyrc_external_tool.program;
@@ -18,7 +27,7 @@ pub async fn external_tool_format(
1827
let mut cmd = Command::new(exe_path);
1928

2029
for arg in args {
21-
if let Some(processed_arg) = parse_macro_arg(arg, file_path, &options) {
30+
if let Some(processed_arg) = parse_macro_arg(arg, file_path, &range, &options) {
2231
cmd.arg(processed_arg);
2332
}
2433
}
@@ -82,7 +91,12 @@ pub async fn external_tool_format(
8291
}
8392
}
8493

85-
fn parse_macro_arg(arg: &str, file_path: &str, options: &FormattingOptions) -> Option<String> {
94+
fn parse_macro_arg(
95+
arg: &str,
96+
file_path: &str,
97+
range: &Option<FormattingRange>,
98+
options: &FormattingOptions,
99+
) -> Option<String> {
86100
let mut result = String::new();
87101
let mut chars = arg.chars().peekable();
88102

@@ -160,6 +174,34 @@ fn parse_macro_arg(arg: &str, file_path: &str, options: &FormattingOptions) -> O
160174
match content.trim() {
161175
"file" => file_path.to_string(),
162176
"indent_size" => options.indent_size.to_string(),
177+
"start_offset" => {
178+
if let Some(r) = range {
179+
u32::from(r.start_offset).to_string()
180+
} else {
181+
"".to_string()
182+
}
183+
}
184+
"end_offset" => {
185+
if let Some(r) = range {
186+
u32::from(r.end_offset).to_string()
187+
} else {
188+
"".to_string()
189+
}
190+
}
191+
"start_line" => {
192+
if let Some(r) = range {
193+
r.start_line.to_string()
194+
} else {
195+
"".to_string()
196+
}
197+
}
198+
"end_line" => {
199+
if let Some(r) = range {
200+
r.end_line.to_string()
201+
} else {
202+
"".to_string()
203+
}
204+
}
163205
_ => "".to_string(),
164206
}
165207
};

crates/emmylua_ls/src/handlers/document_formatting/mod.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@ use lsp_types::{
88
use tokio_util::sync::CancellationToken;
99

1010
use crate::{
11-
context::ServerContextSnapshot,
12-
handlers::document_formatting::{
13-
external_format::external_tool_format, format_diff::format_diff,
14-
},
11+
context::ServerContextSnapshot, handlers::document_formatting::format_diff::format_diff,
1512
};
13+
pub use external_format::{FormattingRange, external_tool_format};
1614

1715
use super::RegisterCapabilities;
1816

@@ -54,7 +52,14 @@ pub async fn on_formatting_handler(
5452
};
5553

5654
let mut formatted_text = if let Some(external_config) = &emmyrc.format.external_tool {
57-
external_tool_format(&external_config, text, &normalized_path, formatting_options).await?
55+
external_tool_format(
56+
&external_config,
57+
text,
58+
&normalized_path,
59+
None,
60+
formatting_options,
61+
)
62+
.await?
5863
} else {
5964
reformat_code(text, &normalized_path, formatting_options)
6065
};
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use crate::handlers::document_formatting::{FormattingRange, external_tool_format};
2+
use emmylua_code_analysis::{
3+
EmmyrcExternalTool, FormattingOptions, LuaDocument, RangeFormatResult,
4+
};
5+
6+
pub async fn external_tool_range_format<'a>(
7+
emmyrc_external_tool: &EmmyrcExternalTool,
8+
document: &'a LuaDocument<'_>,
9+
range: &lsp_types::Range,
10+
file_path: &str,
11+
options: FormattingOptions,
12+
) -> Option<RangeFormatResult> {
13+
let start_offset =
14+
document.get_offset(range.start.line as usize, range.start.character as usize)?;
15+
let end_offset = document.get_offset(range.end.line as usize, range.end.character as usize)?;
16+
17+
let formatting_range = FormattingRange {
18+
start_offset,
19+
end_offset,
20+
start_line: range.start.line,
21+
end_line: range.end.line,
22+
};
23+
24+
let text = document.get_text();
25+
let document_range = document.get_document_lsp_range();
26+
let formatted_text = external_tool_format(
27+
emmyrc_external_tool,
28+
&text,
29+
file_path,
30+
Some(formatting_range),
31+
options,
32+
)
33+
.await?;
34+
35+
Some(RangeFormatResult {
36+
text: formatted_text,
37+
start_line: document_range.start.line as i32,
38+
start_col: document_range.start.character as i32,
39+
end_line: document_range.end.line as i32,
40+
end_col: document_range.end.character as i32,
41+
})
42+
}

crates/emmylua_ls/src/handlers/document_range_formatting/mod.rs

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1+
mod external_range_format;
2+
13
use emmylua_code_analysis::{FormattingOptions, range_format_code};
24
use lsp_types::{
35
ClientCapabilities, DocumentRangeFormattingParams, OneOf, Position, Range, ServerCapabilities,
46
TextEdit,
57
};
68
use tokio_util::sync::CancellationToken;
79

8-
use crate::context::ServerContextSnapshot;
10+
use crate::{
11+
context::ServerContextSnapshot,
12+
handlers::document_range_formatting::external_range_format::external_tool_range_format,
13+
};
914

1015
use super::RegisterCapabilities;
1116

@@ -44,18 +49,28 @@ pub async fn on_range_formatting_handler(
4449
insert_final_newline: params.options.insert_final_newline.unwrap_or(true),
4550
non_standard_symbol: !emmyrc.runtime.nonstandard_symbol.is_empty(),
4651
};
47-
let formatted_result = range_format_code(
48-
text,
49-
&normalized_path,
50-
request_range.start.line as i32,
51-
0,
52-
request_range.end.line as i32 + 1,
53-
0,
54-
formatting_options,
55-
)?;
52+
let formatted_result = if let Some(external_tool) = &emmyrc.format.external_tool_range_format {
53+
external_tool_range_format(
54+
external_tool,
55+
&document,
56+
&request_range,
57+
&normalized_path,
58+
formatting_options,
59+
)
60+
.await?
61+
} else {
62+
range_format_code(
63+
text,
64+
&normalized_path,
65+
request_range.start.line as i32,
66+
0,
67+
request_range.end.line as i32 + 1,
68+
0,
69+
formatting_options,
70+
)?
71+
};
5672

5773
let mut formatted_text = formatted_result.text;
58-
5974
if client_id.is_intellij() || client_id.is_other() {
6075
formatted_text = formatted_text.replace("\r\n", "\n");
6176
}

0 commit comments

Comments
 (0)