summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/lsp/language_server.rs16
-rw-r--r--cli/lsp/tsc.rs198
-rw-r--r--cli/tsc/99_main_compiler.js13
-rw-r--r--cli/tsc/compiler.d.ts5
4 files changed, 213 insertions, 19 deletions
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs
index f0da80bab..f532430c8 100644
--- a/cli/lsp/language_server.rs
+++ b/cli/lsp/language_server.rs
@@ -69,6 +69,7 @@ use super::text;
use super::tsc;
use super::tsc::Assets;
use super::tsc::AssetsSnapshot;
+use super::tsc::GetCompletionDetailsArgs;
use super::tsc::TsServer;
use super::urls;
use super::urls::LspClientUrl;
@@ -1899,6 +1900,7 @@ impl Inner {
line_index.offset_tsc(diagnostic.range.start)?
..line_index.offset_tsc(diagnostic.range.end)?,
codes,
+ (&self.fmt_options.options).into(),
)
.await;
for action in actions {
@@ -2007,7 +2009,11 @@ impl Inner {
})?;
let combined_code_actions = self
.ts_server
- .get_combined_code_fix(self.snapshot(), &code_action_data)
+ .get_combined_code_fix(
+ self.snapshot(),
+ &code_action_data,
+ (&self.fmt_options.options).into(),
+ )
.await?;
if combined_code_actions.commands.is_some() {
error!("Deno does not support code actions with commands.");
@@ -2047,6 +2053,7 @@ impl Inner {
.get_edits_for_refactor(
self.snapshot(),
action_data.specifier,
+ (&self.fmt_options.options).into(),
line_index.offset_tsc(action_data.range.start)?
..line_index.offset_tsc(action_data.range.end)?,
action_data.refactor_name,
@@ -2402,6 +2409,7 @@ impl Inner {
trigger_character,
trigger_kind,
},
+ (&self.fmt_options.options).into(),
)
.await;
@@ -2436,9 +2444,13 @@ impl Inner {
})?;
if let Some(data) = &data.tsc {
let specifier = &data.specifier;
+ let args = GetCompletionDetailsArgs {
+ format_code_settings: Some((&self.fmt_options.options).into()),
+ ..data.into()
+ };
let result = self
.ts_server
- .get_completion_details(self.snapshot(), data.into())
+ .get_completion_details(self.snapshot(), args)
.await;
match result {
Ok(maybe_completion_info) => {
diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs
index 75ed8ebe3..99dd92193 100644
--- a/cli/lsp/tsc.rs
+++ b/cli/lsp/tsc.rs
@@ -21,6 +21,7 @@ use super::urls::LspClientUrl;
use super::urls::LspUrlMap;
use super::urls::INVALID_SPECIFIER;
+use crate::args::FmtOptionsConfig;
use crate::args::TsConfig;
use crate::cache::HttpCache;
use crate::lsp::cache::CacheMetadata;
@@ -95,6 +96,35 @@ type Request = (
CancellationToken,
);
+/// Relevant subset of https://github.com/denoland/deno/blob/80331d1fe5b85b829ac009fdc201c128b3427e11/cli/tsc/dts/typescript.d.ts#L6658.
+#[derive(Clone, Debug, Default, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct FormatCodeSettings {
+ convert_tabs_to_spaces: Option<bool>,
+ indent_size: Option<u8>,
+ semicolons: Option<SemicolonPreference>,
+}
+
+impl From<&FmtOptionsConfig> for FormatCodeSettings {
+ fn from(config: &FmtOptionsConfig) -> Self {
+ FormatCodeSettings {
+ convert_tabs_to_spaces: Some(!config.use_tabs.unwrap_or(false)),
+ indent_size: Some(config.indent_width.unwrap_or(2)),
+ semicolons: match config.semi_colons {
+ Some(false) => Some(SemicolonPreference::Remove),
+ _ => Some(SemicolonPreference::Insert),
+ },
+ }
+ }
+}
+
+#[derive(Clone, Debug, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub enum SemicolonPreference {
+ Insert,
+ Remove,
+}
+
#[derive(Clone, Debug)]
pub struct TsServer(mpsc::UnboundedSender<Request>);
@@ -202,9 +232,15 @@ impl TsServer {
specifier: ModuleSpecifier,
range: Range<u32>,
codes: Vec<String>,
+ format_code_settings: FormatCodeSettings,
) -> Vec<CodeFixAction> {
- let req =
- RequestMethod::GetCodeFixes((specifier, range.start, range.end, codes));
+ let req = RequestMethod::GetCodeFixes((
+ specifier,
+ range.start,
+ range.end,
+ codes,
+ format_code_settings,
+ ));
match self.request(snapshot, req).await {
Ok(items) => items,
Err(err) => {
@@ -243,10 +279,12 @@ impl TsServer {
&self,
snapshot: Arc<StateSnapshot>,
code_action_data: &CodeActionData,
+ format_code_settings: FormatCodeSettings,
) -> Result<CombinedCodeActions, LspError> {
let req = RequestMethod::GetCombinedCodeFix((
code_action_data.specifier.clone(),
json!(code_action_data.fix_id.clone()),
+ format_code_settings,
));
self.request(snapshot, req).await.map_err(|err| {
log::error!("Unable to get combined fix from TypeScript: {}", err);
@@ -258,12 +296,14 @@ impl TsServer {
&self,
snapshot: Arc<StateSnapshot>,
specifier: ModuleSpecifier,
+ format_code_settings: FormatCodeSettings,
range: Range<u32>,
refactor_name: String,
action_name: String,
) -> Result<RefactorEditInfo, LspError> {
let req = RequestMethod::GetEditsForRefactor((
specifier,
+ format_code_settings,
TextSpan {
start: range.start,
length: range.end - range.start,
@@ -330,8 +370,14 @@ impl TsServer {
specifier: ModuleSpecifier,
position: u32,
options: GetCompletionsAtPositionOptions,
+ format_code_settings: FormatCodeSettings,
) -> Option<CompletionInfo> {
- let req = RequestMethod::GetCompletions((specifier, position, options));
+ let req = RequestMethod::GetCompletions((
+ specifier,
+ position,
+ options,
+ format_code_settings,
+ ));
match self.request(snapshot, req).await {
Ok(maybe_info) => maybe_info,
Err(err) => {
@@ -3542,6 +3588,8 @@ pub struct GetCompletionDetailsArgs {
pub position: u32,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
+ pub format_code_settings: Option<FormatCodeSettings>,
+ #[serde(skip_serializing_if = "Option::is_none")]
pub source: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub preferences: Option<UserPreferences>,
@@ -3557,6 +3605,7 @@ impl From<&CompletionItemData> for GetCompletionDetailsArgs {
name: item_data.name.clone(),
source: item_data.source.clone(),
preferences: None,
+ format_code_settings: None,
data: item_data.data.clone(),
}
}
@@ -3586,15 +3635,30 @@ enum RequestMethod {
/// Retrieve the possible refactor info for a range of a file.
GetApplicableRefactors((ModuleSpecifier, TextSpan, String)),
/// Retrieve the refactor edit info for a range.
- GetEditsForRefactor((ModuleSpecifier, TextSpan, String, String)),
+ GetEditsForRefactor(
+ (
+ ModuleSpecifier,
+ FormatCodeSettings,
+ TextSpan,
+ String,
+ String,
+ ),
+ ),
/// Retrieve code fixes for a range of a file with the provided error codes.
- GetCodeFixes((ModuleSpecifier, u32, u32, Vec<String>)),
+ GetCodeFixes((ModuleSpecifier, u32, u32, Vec<String>, FormatCodeSettings)),
/// Get completion information at a given position (IntelliSense).
- GetCompletions((ModuleSpecifier, u32, GetCompletionsAtPositionOptions)),
+ GetCompletions(
+ (
+ ModuleSpecifier,
+ u32,
+ GetCompletionsAtPositionOptions,
+ FormatCodeSettings,
+ ),
+ ),
/// Get details about a specific completion entry.
GetCompletionDetails(GetCompletionDetailsArgs),
/// Retrieve the combined code fixes for a fix id for a module.
- GetCombinedCodeFix((ModuleSpecifier, Value)),
+ GetCombinedCodeFix((ModuleSpecifier, Value, FormatCodeSettings)),
/// Get declaration information for a specific position.
GetDefinition((ModuleSpecifier, u32)),
/// Return diagnostics for given file.
@@ -3680,6 +3744,7 @@ impl RequestMethod {
}),
RequestMethod::GetEditsForRefactor((
specifier,
+ format_code_settings,
span,
refactor_name,
action_name,
@@ -3687,6 +3752,7 @@ impl RequestMethod {
"id": id,
"method": "getEditsForRefactor",
"specifier": state.denormalize_specifier(specifier),
+ "formatCodeSettings": format_code_settings,
"range": { "pos": span.start, "end": span.start + span.length},
"refactorName": refactor_name,
"actionName": action_name,
@@ -3696,6 +3762,7 @@ impl RequestMethod {
start_pos,
end_pos,
error_codes,
+ format_code_settings,
)) => json!({
"id": id,
"method": "getCodeFixes",
@@ -3703,25 +3770,37 @@ impl RequestMethod {
"startPosition": start_pos,
"endPosition": end_pos,
"errorCodes": error_codes,
+ "formatCodeSettings": format_code_settings,
}),
- RequestMethod::GetCombinedCodeFix((specifier, fix_id)) => json!({
+ RequestMethod::GetCombinedCodeFix((
+ specifier,
+ fix_id,
+ format_code_settings,
+ )) => json!({
"id": id,
"method": "getCombinedCodeFix",
"specifier": state.denormalize_specifier(specifier),
"fixId": fix_id,
+ "formatCodeSettings": format_code_settings,
}),
RequestMethod::GetCompletionDetails(args) => json!({
"id": id,
"method": "getCompletionDetails",
"args": args
}),
- RequestMethod::GetCompletions((specifier, position, preferences)) => {
+ RequestMethod::GetCompletions((
+ specifier,
+ position,
+ preferences,
+ format_code_settings,
+ )) => {
json!({
"id": id,
"method": "getCompletions",
"specifier": state.denormalize_specifier(specifier),
"position": position,
"preferences": preferences,
+ "formatCodeSettings": format_code_settings,
})
}
RequestMethod::GetDefinition((specifier, position)) => json!({
@@ -4589,6 +4668,7 @@ mod tests {
trigger_character: Some(".".to_string()),
trigger_kind: None,
},
+ Default::default(),
)),
Default::default(),
);
@@ -4605,6 +4685,7 @@ mod tests {
name: "log".to_string(),
source: None,
preferences: None,
+ format_code_settings: None,
data: None,
}),
Default::default(),
@@ -4701,6 +4782,105 @@ mod tests {
}
#[test]
+ fn test_completions_fmt() {
+ let fixture_a = r#"
+ console.log(someLongVaria)
+ "#;
+ let fixture_b = r#"
+ export const someLongVariable = 1
+ "#;
+ let line_index = LineIndex::new(fixture_a);
+ let position = line_index
+ .offset_tsc(lsp::Position {
+ line: 1,
+ character: 33,
+ })
+ .unwrap();
+ let temp_dir = TempDir::new();
+ let (mut runtime, state_snapshot, _) = setup(
+ &temp_dir,
+ false,
+ json!({
+ "target": "esnext",
+ "module": "esnext",
+ "lib": ["deno.ns", "deno.window"],
+ "noEmit": true,
+ }),
+ &[
+ ("file:///a.ts", fixture_a, 1, LanguageId::TypeScript),
+ ("file:///b.ts", fixture_b, 1, LanguageId::TypeScript),
+ ],
+ );
+ let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
+ let result = request(
+ &mut runtime,
+ state_snapshot.clone(),
+ RequestMethod::GetDiagnostics(vec![specifier.clone()]),
+ Default::default(),
+ );
+ assert!(result.is_ok());
+ let fmt_options_config = FmtOptionsConfig {
+ semi_colons: Some(false),
+ ..Default::default()
+ };
+ let result = request(
+ &mut runtime,
+ state_snapshot.clone(),
+ RequestMethod::GetCompletions((
+ specifier.clone(),
+ position,
+ GetCompletionsAtPositionOptions {
+ user_preferences: UserPreferences {
+ allow_incomplete_completions: Some(true),
+ allow_text_changes_in_new_files: Some(true),
+ include_completions_for_module_exports: Some(true),
+ include_completions_with_insert_text: Some(true),
+ ..Default::default()
+ },
+ ..Default::default()
+ },
+ (&fmt_options_config).into(),
+ )),
+ Default::default(),
+ )
+ .unwrap();
+ let info: CompletionInfo = serde_json::from_value(result).unwrap();
+ let entry = info
+ .entries
+ .iter()
+ .find(|e| &e.name == "someLongVariable")
+ .unwrap();
+ let result = request(
+ &mut runtime,
+ state_snapshot,
+ RequestMethod::GetCompletionDetails(GetCompletionDetailsArgs {
+ specifier,
+ position,
+ name: entry.name.clone(),
+ source: entry.source.clone(),
+ preferences: None,
+ format_code_settings: Some((&fmt_options_config).into()),
+ data: entry.data.clone(),
+ }),
+ Default::default(),
+ )
+ .unwrap();
+ let details: CompletionEntryDetails =
+ serde_json::from_value(result).unwrap();
+ let actions = details.code_actions.unwrap();
+ let action = actions
+ .iter()
+ .find(|a| &a.description == r#"Add import from "./b.ts""#)
+ .unwrap();
+ let changes = action.changes.first().unwrap();
+ let change = changes.text_changes.first().unwrap();
+ assert_eq!(
+ change.new_text,
+ "import { someLongVariable } from \"./b.ts\"\n"
+ );
+ }
+
+ #[test]
fn test_update_import_statement() {
let fixtures = vec![
(
diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js
index 43a3c3bcf..f2ccec466 100644
--- a/cli/tsc/99_main_compiler.js
+++ b/cli/tsc/99_main_compiler.js
@@ -1035,10 +1035,8 @@ delete Object.prototype.__proto__;
languageService.getEditsForRefactor(
request.specifier,
{
- indentSize: 2,
+ ...request.formatCodeSettings,
indentStyle: ts.IndentStyle.Smart,
- semicolons: ts.SemicolonPreference.Insert,
- convertTabsToSpaces: true,
insertSpaceBeforeAndAfterBinaryOperators: true,
insertSpaceAfterCommaDelimiter: true,
},
@@ -1060,9 +1058,8 @@ delete Object.prototype.__proto__;
request.endPosition,
request.errorCodes.map((v) => Number(v)),
{
- indentSize: 2,
+ ...request.formatCodeSettings,
indentStyle: ts.IndentStyle.Block,
- semicolons: ts.SemicolonPreference.Insert,
},
{
quotePreference: "double",
@@ -1080,9 +1077,8 @@ delete Object.prototype.__proto__;
},
request.fixId,
{
- indentSize: 2,
+ ...request.formatCodeSettings,
indentStyle: ts.IndentStyle.Block,
- semicolons: ts.SemicolonPreference.Insert,
},
{
quotePreference: "double",
@@ -1100,7 +1096,7 @@ delete Object.prototype.__proto__;
request.args.specifier,
request.args.position,
request.args.name,
- {},
+ request.args.formatCodeSettings ?? {},
request.args.source,
request.args.preferences,
request.args.data,
@@ -1114,6 +1110,7 @@ delete Object.prototype.__proto__;
request.specifier,
request.position,
request.preferences,
+ request.formatCodeSettings,
),
);
}
diff --git a/cli/tsc/compiler.d.ts b/cli/tsc/compiler.d.ts
index 66c094697..da713a1bd 100644
--- a/cli/tsc/compiler.d.ts
+++ b/cli/tsc/compiler.d.ts
@@ -121,6 +121,7 @@ declare global {
interface GetEditsForRefactor extends BaseLanguageServerRequest {
method: "getEditsForRefactor";
specifier: string;
+ formatCodeSettings: ts.FormatCodeSettings;
range: ts.TextRange;
refactorName: string;
actionName: string;
@@ -132,6 +133,7 @@ declare global {
startPosition: number;
endPosition: number;
errorCodes: string[];
+ formatCodeSettings: ts.FormatCodeSettings;
}
interface GetCombinedCodeFix extends BaseLanguageServerRequest {
@@ -139,6 +141,7 @@ declare global {
specifier: string;
// deno-lint-ignore ban-types
fixId: {};
+ formatCodeSettings: ts.FormatCodeSettings;
}
interface GetCompletionDetails extends BaseLanguageServerRequest {
@@ -147,6 +150,7 @@ declare global {
specifier: string;
position: number;
name: string;
+ formatCodeSettings: ts.FormatCodeSettings;
source?: string;
preferences?: ts.UserPreferences;
data?: ts.CompletionEntryData;
@@ -158,6 +162,7 @@ declare global {
specifier: string;
position: number;
preferences: ts.GetCompletionsAtPositionOptions;
+ formatCodeSettings: ts.FormatCodeSettings;
}
interface GetDiagnosticsRequest extends BaseLanguageServerRequest {