summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKitson Kelly <me@kitsonkelly.com>2022-10-16 13:39:43 +1100
committerGitHub <noreply@github.com>2022-10-16 13:39:43 +1100
commit7d78f58187cdcb9bed632992cde347fd5f3c83eb (patch)
tree80bd06e16db12e7578b2946eaf0b72ca0ac34c6c
parent6d2656fd56e8ac0f1b1443e28d474bf3ceca89bb (diff)
feat: support inlay hints (#16287)
Closes: #11853
-rw-r--r--cli/lsp/capabilities.rs2
-rw-r--r--cli/lsp/config.rs131
-rw-r--r--cli/lsp/language_server.rs51
-rw-r--r--cli/lsp/lsp_custom.rs3
-rw-r--r--cli/lsp/mod.rs1
-rw-r--r--cli/lsp/repl.rs1
-rw-r--r--cli/lsp/tsc.rs113
-rw-r--r--cli/tests/integration/lsp_tests.rs207
-rw-r--r--cli/tests/testdata/lsp/initialize_params_hints.json102
-rw-r--r--cli/tsc/99_main_compiler.js9
-rw-r--r--cli/tsc/compiler.d.ts10
11 files changed, 628 insertions, 2 deletions
diff --git a/cli/lsp/capabilities.rs b/cli/lsp/capabilities.rs
index 0e9c93e63..03192f597 100644
--- a/cli/lsp/capabilities.rs
+++ b/cli/lsp/capabilities.rs
@@ -141,6 +141,6 @@ pub fn server_capabilities(
"denoConfigTasks": true,
"testingApi":true,
})),
- inlay_hint_provider: None,
+ inlay_hint_provider: Some(OneOf::Left(true)),
}
}
diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs
index 98ba5afb5..3c44ebe05 100644
--- a/cli/lsp/config.rs
+++ b/cli/lsp/config.rs
@@ -106,6 +106,101 @@ impl Default for CompletionSettings {
}
}
+#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq)]
+#[serde(rename_all = "camelCase")]
+pub struct InlayHintsSettings {
+ #[serde(default)]
+ pub parameter_names: InlayHintsParamNamesOptions,
+ #[serde(default)]
+ pub parameter_types: InlayHintsParamTypesOptions,
+ #[serde(default)]
+ pub variable_types: InlayHintsVarTypesOptions,
+ #[serde(default)]
+ pub property_declaration_types: InlayHintsPropDeclTypesOptions,
+ #[serde(default)]
+ pub function_like_return_types: InlayHintsFuncLikeReturnTypesOptions,
+ #[serde(default)]
+ pub enum_member_values: InlayHintsEnumMemberValuesOptions,
+}
+
+#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
+#[serde(rename_all = "camelCase")]
+pub struct InlayHintsParamNamesOptions {
+ #[serde(default)]
+ pub enabled: InlayHintsParamNamesEnabled,
+ #[serde(default = "is_true")]
+ pub suppress_when_argument_matches_name: bool,
+}
+
+impl Default for InlayHintsParamNamesOptions {
+ fn default() -> Self {
+ Self {
+ enabled: InlayHintsParamNamesEnabled::None,
+ suppress_when_argument_matches_name: true,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
+#[serde(rename_all = "camelCase")]
+pub enum InlayHintsParamNamesEnabled {
+ None,
+ Literals,
+ All,
+}
+
+impl Default for InlayHintsParamNamesEnabled {
+ fn default() -> Self {
+ Self::None
+ }
+}
+
+#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq)]
+#[serde(rename_all = "camelCase")]
+pub struct InlayHintsParamTypesOptions {
+ #[serde(default)]
+ pub enabled: bool,
+}
+
+#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
+#[serde(rename_all = "camelCase")]
+pub struct InlayHintsVarTypesOptions {
+ #[serde(default)]
+ pub enabled: bool,
+ #[serde(default = "is_true")]
+ pub suppress_when_argument_matches_name: bool,
+}
+
+impl Default for InlayHintsVarTypesOptions {
+ fn default() -> Self {
+ Self {
+ enabled: false,
+ suppress_when_argument_matches_name: true,
+ }
+ }
+}
+
+#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq)]
+#[serde(rename_all = "camelCase")]
+pub struct InlayHintsPropDeclTypesOptions {
+ #[serde(default)]
+ pub enabled: bool,
+}
+
+#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq)]
+#[serde(rename_all = "camelCase")]
+pub struct InlayHintsFuncLikeReturnTypesOptions {
+ #[serde(default)]
+ pub enabled: bool,
+}
+
+#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq)]
+#[serde(rename_all = "camelCase")]
+pub struct InlayHintsEnumMemberValuesOptions {
+ #[serde(default)]
+ pub enabled: bool,
+}
+
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ImportCompletionSettings {
@@ -202,6 +297,9 @@ pub struct WorkspaceSettings {
#[serde(default)]
pub code_lens: CodeLensSettings,
+ #[serde(default)]
+ pub inlay_hints: InlayHintsSettings,
+
/// A flag that indicates if internal debug logging should be made available.
#[serde(default)]
pub internal_debug: bool,
@@ -238,6 +336,19 @@ impl WorkspaceSettings {
pub fn enabled_code_lens(&self) -> bool {
self.code_lens.implementations || self.code_lens.references
}
+
+ /// Determine if any inlay hints are enabled. This allows short circuiting
+ /// when there are no inlay hints enabled.
+ pub fn enabled_inlay_hints(&self) -> bool {
+ !matches!(
+ self.inlay_hints.parameter_names.enabled,
+ InlayHintsParamNamesEnabled::None
+ ) || self.inlay_hints.parameter_types.enabled
+ || self.inlay_hints.variable_types.enabled
+ || self.inlay_hints.property_declaration_types.enabled
+ || self.inlay_hints.function_like_return_types.enabled
+ || self.inlay_hints.enum_member_values.enabled
+ }
}
#[derive(Debug, Clone, Default)]
@@ -566,6 +677,26 @@ mod tests {
references_all_functions: false,
test: true,
},
+ inlay_hints: InlayHintsSettings {
+ parameter_names: InlayHintsParamNamesOptions {
+ enabled: InlayHintsParamNamesEnabled::None,
+ suppress_when_argument_matches_name: true
+ },
+ parameter_types: InlayHintsParamTypesOptions { enabled: false },
+ variable_types: InlayHintsVarTypesOptions {
+ enabled: false,
+ suppress_when_argument_matches_name: true
+ },
+ property_declaration_types: InlayHintsPropDeclTypesOptions {
+ enabled: false
+ },
+ function_like_return_types: InlayHintsFuncLikeReturnTypesOptions {
+ enabled: false
+ },
+ enum_member_values: InlayHintsEnumMemberValuesOptions {
+ enabled: false
+ },
+ },
internal_debug: false,
lint: true,
suggest: CompletionSettings {
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs
index 64c7adeb6..c4617df9f 100644
--- a/cli/lsp/language_server.rs
+++ b/cli/lsp/language_server.rs
@@ -196,6 +196,13 @@ impl LanguageServer {
}
}
+ pub async fn inlay_hint(
+ &self,
+ params: InlayHintParams,
+ ) -> LspResult<Option<Vec<InlayHint>>> {
+ self.0.lock().await.inlay_hint(params).await
+ }
+
pub async fn virtual_text_document(
&self,
params: Option<Value>,
@@ -2896,6 +2903,50 @@ impl Inner {
)
}
+ async fn inlay_hint(
+ &self,
+ params: InlayHintParams,
+ ) -> LspResult<Option<Vec<InlayHint>>> {
+ let specifier = self.url_map.normalize_url(&params.text_document.uri);
+ let workspace_settings = self.config.get_workspace_settings();
+ if !self.is_diagnosable(&specifier)
+ || !self.config.specifier_enabled(&specifier)
+ || !workspace_settings.enabled_inlay_hints()
+ {
+ return Ok(None);
+ }
+
+ let mark = self.performance.mark("inlay_hint", Some(&params));
+ let asset_or_doc = self.get_asset_or_document(&specifier)?;
+ let line_index = asset_or_doc.line_index();
+ let range = tsc::TextSpan::from_range(&params.range, line_index.clone())
+ .map_err(|err| {
+ error!("Failed to convert range to text_span: {}", err);
+ LspError::internal_error()
+ })?;
+ let req = tsc::RequestMethod::ProvideInlayHints((
+ specifier.clone(),
+ range,
+ (&workspace_settings).into(),
+ ));
+ let maybe_inlay_hints: Option<Vec<tsc::InlayHint>> = self
+ .ts_server
+ .request(self.snapshot(), req)
+ .await
+ .map_err(|err| {
+ error!("Unable to get inlay hints: {}", err);
+ LspError::internal_error()
+ })?;
+ let maybe_inlay_hints = maybe_inlay_hints.map(|hints| {
+ hints
+ .iter()
+ .map(|hint| hint.to_lsp(line_index.clone()))
+ .collect()
+ });
+ self.performance.measure(mark);
+ Ok(maybe_inlay_hints)
+ }
+
async fn reload_import_registries(&mut self) -> LspResult<Option<Value>> {
fs_util::remove_dir_all_if_exists(&self.module_registries_location)
.await
diff --git a/cli/lsp/lsp_custom.rs b/cli/lsp/lsp_custom.rs
index 49c06e15c..b154234c7 100644
--- a/cli/lsp/lsp_custom.rs
+++ b/cli/lsp/lsp_custom.rs
@@ -11,6 +11,9 @@ pub const RELOAD_IMPORT_REGISTRIES_REQUEST: &str =
"deno/reloadImportRegistries";
pub const VIRTUAL_TEXT_DOCUMENT: &str = "deno/virtualTextDocument";
+// While lsp_types supports inlay hints currently, tower_lsp does not.
+pub const INLAY_HINT: &str = "textDocument/inlayHint";
+
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CacheParams {
diff --git a/cli/lsp/mod.rs b/cli/lsp/mod.rs
index 2ee22510f..7161c5209 100644
--- a/cli/lsp/mod.rs
+++ b/cli/lsp/mod.rs
@@ -58,6 +58,7 @@ pub async fn start() -> Result<(), AnyError> {
lsp_custom::VIRTUAL_TEXT_DOCUMENT,
LanguageServer::virtual_text_document,
)
+ .custom_method(lsp_custom::INLAY_HINT, LanguageServer::inlay_hint)
.finish();
Server::new(stdin, stdout, socket).serve(service).await;
diff --git a/cli/lsp/repl.rs b/cli/lsp/repl.rs
index b6329205a..60354f2d0 100644
--- a/cli/lsp/repl.rs
+++ b/cli/lsp/repl.rs
@@ -288,6 +288,7 @@ pub fn get_repl_workspace_settings() -> WorkspaceSettings {
cache: None,
import_map: None,
code_lens: Default::default(),
+ inlay_hints: Default::default(),
internal_debug: false,
lint: false,
tls_certificate: None,
diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs
index 51dd74240..6c2136990 100644
--- a/cli/lsp/tsc.rs
+++ b/cli/lsp/tsc.rs
@@ -618,6 +618,15 @@ pub struct TextSpan {
}
impl TextSpan {
+ pub fn from_range(
+ range: &lsp::Range,
+ line_index: Arc<LineIndex>,
+ ) -> Result<Self, AnyError> {
+ let start = line_index.offset_tsc(range.start)?;
+ let length = line_index.offset_tsc(range.end)? - start;
+ Ok(Self { start, length })
+ }
+
pub fn to_range(&self, line_index: Arc<LineIndex>) -> lsp::Range {
lsp::Range {
start: line_index.position_tsc(self.start.into()),
@@ -933,6 +942,48 @@ impl NavigateToItem {
}
#[derive(Debug, Clone, Deserialize)]
+pub enum InlayHintKind {
+ Type,
+ Parameter,
+ Enum,
+}
+
+impl InlayHintKind {
+ pub fn to_lsp(&self) -> Option<lsp::InlayHintKind> {
+ match self {
+ Self::Enum => None,
+ Self::Parameter => Some(lsp::InlayHintKind::PARAMETER),
+ Self::Type => Some(lsp::InlayHintKind::TYPE),
+ }
+ }
+}
+
+#[derive(Debug, Clone, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct InlayHint {
+ pub text: String,
+ pub position: u32,
+ pub kind: InlayHintKind,
+ pub whitespace_before: Option<bool>,
+ pub whitespace_after: Option<bool>,
+}
+
+impl InlayHint {
+ pub fn to_lsp(&self, line_index: Arc<LineIndex>) -> lsp::InlayHint {
+ lsp::InlayHint {
+ position: line_index.position_tsc(self.position.into()),
+ label: lsp::InlayHintLabel::String(self.text.clone()),
+ kind: self.kind.to_lsp(),
+ padding_left: self.whitespace_before,
+ padding_right: self.whitespace_after,
+ text_edits: None,
+ tooltip: None,
+ data: None,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NavigationTree {
pub text: String,
@@ -2830,6 +2881,18 @@ pub enum IncludeInlayParameterNameHints {
All,
}
+impl From<&config::InlayHintsParamNamesEnabled>
+ for IncludeInlayParameterNameHints
+{
+ fn from(setting: &config::InlayHintsParamNamesEnabled) -> Self {
+ match setting {
+ config::InlayHintsParamNamesEnabled::All => Self::All,
+ config::InlayHintsParamNamesEnabled::Literals => Self::Literals,
+ config::InlayHintsParamNamesEnabled::None => Self::None,
+ }
+ }
+}
+
#[derive(Debug, Serialize)]
#[serde(rename_all = "kebab-case")]
#[allow(dead_code)]
@@ -2910,6 +2973,8 @@ pub struct UserPreferences {
#[serde(skip_serializing_if = "Option::is_none")]
pub include_inlay_variable_type_hints: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
+ pub include_inlay_variable_type_hints_when_type_matches_name: Option<bool>,
+ #[serde(skip_serializing_if = "Option::is_none")]
pub include_inlay_property_declaration_type_hints: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub include_inlay_function_like_return_type_hints: Option<bool>,
@@ -2921,6 +2986,43 @@ pub struct UserPreferences {
pub auto_import_file_exclude_patterns: Option<Vec<String>>,
}
+impl From<&config::WorkspaceSettings> for UserPreferences {
+ fn from(workspace_settings: &config::WorkspaceSettings) -> Self {
+ let inlay_hints = &workspace_settings.inlay_hints;
+ Self {
+ include_inlay_parameter_name_hints: Some(
+ (&inlay_hints.parameter_names.enabled).into(),
+ ),
+ include_inlay_parameter_name_hints_when_argument_matches_name: Some(
+ inlay_hints
+ .parameter_names
+ .suppress_when_argument_matches_name,
+ ),
+ include_inlay_function_parameter_type_hints: Some(
+ inlay_hints.parameter_types.enabled,
+ ),
+ include_inlay_variable_type_hints: Some(
+ inlay_hints.variable_types.enabled,
+ ),
+ include_inlay_variable_type_hints_when_type_matches_name: Some(
+ inlay_hints
+ .variable_types
+ .suppress_when_argument_matches_name,
+ ),
+ include_inlay_property_declaration_type_hints: Some(
+ inlay_hints.property_declaration_types.enabled,
+ ),
+ include_inlay_function_like_return_type_hints: Some(
+ inlay_hints.function_like_return_types.enabled,
+ ),
+ include_inlay_enum_member_value_hints: Some(
+ inlay_hints.enum_member_values.enabled,
+ ),
+ ..Default::default()
+ }
+ }
+}
+
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SignatureHelpItemsOptions {
@@ -3053,6 +3155,8 @@ pub enum RequestMethod {
ProvideCallHierarchyIncomingCalls((ModuleSpecifier, u32)),
/// Resolve outgoing call hierarchy items for a specific position.
ProvideCallHierarchyOutgoingCalls((ModuleSpecifier, u32)),
+ /// Resolve inlay hints for a specific text span
+ ProvideInlayHints((ModuleSpecifier, TextSpan, UserPreferences)),
// Special request, used only internally by the LSP
Restart,
@@ -3269,6 +3373,15 @@ impl RequestMethod {
"position": position
})
}
+ RequestMethod::ProvideInlayHints((specifier, span, preferences)) => {
+ json!({
+ "id": id,
+ "method": "provideInlayHints",
+ "specifier": state.denormalize_specifier(specifier),
+ "span": span,
+ "preferences": preferences,
+ })
+ }
RequestMethod::Restart => json!({
"id": id,
"method": "restart",
diff --git a/cli/tests/integration/lsp_tests.rs b/cli/tests/integration/lsp_tests.rs
index cc8625476..7dc5ff02d 100644
--- a/cli/tests/integration/lsp_tests.rs
+++ b/cli/tests/integration/lsp_tests.rs
@@ -1072,6 +1072,213 @@ fn lsp_hover_disabled() {
}
#[test]
+fn lsp_inlay_hints() {
+ let mut client = init("initialize_params_hints.json");
+ did_open(
+ &mut client,
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "languageId": "typescript",
+ "version": 1,
+ "text": r#"function a(b: string) {
+ return b;
+ }
+
+ a("foo");
+
+ enum C {
+ A,
+ }
+
+ parseInt("123", 8);
+
+ const d = Date.now();
+
+ class E {
+ f = Date.now();
+ }
+
+ ["a"].map((v) => v + v);
+ "#
+ }
+ }),
+ );
+ let (maybe_res, maybe_err) = client
+ .write_request::<_, _, Value>(
+ "textDocument/inlayHint",
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ },
+ "range": {
+ "start": {
+ "line": 0,
+ "character": 0
+ },
+ "end": {
+ "line": 19,
+ "character": 0,
+ }
+ }
+ }),
+ )
+ .unwrap();
+ assert!(maybe_err.is_none());
+ assert_eq!(
+ json!(maybe_res),
+ json!([
+ {
+ "position": {
+ "line": 0,
+ "character": 21
+ },
+ "label": ": string",
+ "kind": 1,
+ "paddingLeft": true
+ },
+ {
+ "position": {
+ "line": 4,
+ "character": 10
+ },
+ "label": "b:",
+ "kind": 2,
+ "paddingRight": true
+ },
+ {
+ "position": {
+ "line": 7,
+ "character": 11
+ },
+ "label": "= 0",
+ "paddingLeft": true
+ },
+ {
+ "position": {
+ "line": 10,
+ "character": 17
+ },
+ "label": "string:",
+ "kind": 2,
+ "paddingRight": true
+ },
+ {
+ "position": {
+ "line": 10,
+ "character": 24
+ },
+ "label": "radix:",
+ "kind": 2,
+ "paddingRight": true
+ },
+ {
+ "position": {
+ "line": 12,
+ "character": 15
+ },
+ "label": ": number",
+ "kind": 1,
+ "paddingLeft": true
+ },
+ {
+ "position": {
+ "line": 15,
+ "character": 11
+ },
+ "label": ": number",
+ "kind": 1,
+ "paddingLeft": true
+ },
+ {
+ "position": {
+ "line": 18,
+ "character": 18
+ },
+ "label": "callbackfn:",
+ "kind": 2,
+ "paddingRight": true
+ },
+ {
+ "position": {
+ "line": 18,
+ "character": 20
+ },
+ "label": ": string",
+ "kind": 1,
+ "paddingLeft": true
+ },
+ {
+ "position": {
+ "line": 18,
+ "character": 21
+ },
+ "label": ": string",
+ "kind": 1,
+ "paddingLeft": true
+ }
+ ])
+ );
+}
+
+#[test]
+fn lsp_inlay_hints_not_enabled() {
+ let mut client = init("initialize_params.json");
+ did_open(
+ &mut client,
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "languageId": "typescript",
+ "version": 1,
+ "text": r#"function a(b: string) {
+ return b;
+ }
+
+ a("foo");
+
+ enum C {
+ A,
+ }
+
+ parseInt("123", 8);
+
+ const d = Date.now();
+
+ class E {
+ f = Date.now();
+ }
+
+ ["a"].map((v) => v + v);
+ "#
+ }
+ }),
+ );
+ let (maybe_res, maybe_err) = client
+ .write_request::<_, _, Value>(
+ "textDocument/inlayHint",
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ },
+ "range": {
+ "start": {
+ "line": 0,
+ "character": 0
+ },
+ "end": {
+ "line": 19,
+ "character": 0,
+ }
+ }
+ }),
+ )
+ .unwrap();
+ assert!(maybe_err.is_none());
+ assert_eq!(json!(maybe_res), json!(null));
+}
+
+#[test]
fn lsp_workspace_enable_paths() {
let mut params: lsp::InitializeParams = serde_json::from_value(load_fixture(
"initialize_params_workspace_enable_paths.json",
diff --git a/cli/tests/testdata/lsp/initialize_params_hints.json b/cli/tests/testdata/lsp/initialize_params_hints.json
new file mode 100644
index 000000000..1bab6e86d
--- /dev/null
+++ b/cli/tests/testdata/lsp/initialize_params_hints.json
@@ -0,0 +1,102 @@
+{
+ "processId": 0,
+ "clientInfo": {
+ "name": "test-harness",
+ "version": "1.0.0"
+ },
+ "rootUri": null,
+ "initializationOptions": {
+ "enable": true,
+ "cache": null,
+ "certificateStores": null,
+ "codeLens": {
+ "implementations": true,
+ "references": true,
+ "test": true
+ },
+ "config": null,
+ "importMap": null,
+ "inlayHints": {
+ "parameterNames": {
+ "enabled": "all"
+ },
+ "parameterTypes": {
+ "enabled": true
+ },
+ "variableTypes": {
+ "enabled": true
+ },
+ "propertyDeclarationTypes": {
+ "enabled": true
+ },
+ "functionLikeReturnTypes": {
+ "enabled": true
+ },
+ "enumMemberValues": {
+ "enabled": true
+ }
+ },
+ "lint": true,
+ "suggest": {
+ "autoImports": true,
+ "completeFunctionCalls": false,
+ "names": true,
+ "paths": true,
+ "imports": {
+ "hosts": {}
+ }
+ },
+ "testing": {
+ "args": [
+ "--allow-all"
+ ],
+ "enable": true
+ },
+ "tlsCertificate": null,
+ "unsafelyIgnoreCertificateErrors": null,
+ "unstable": false
+ },
+ "capabilities": {
+ "textDocument": {
+ "codeAction": {
+ "codeActionLiteralSupport": {
+ "codeActionKind": {
+ "valueSet": [
+ "quickfix",
+ "refactor"
+ ]
+ }
+ },
+ "isPreferredSupport": true,
+ "dataSupport": true,
+ "disabledSupport": true,
+ "resolveSupport": {
+ "properties": [
+ "edit"
+ ]
+ }
+ },
+ "completion": {
+ "completionItem": {
+ "snippetSupport": true
+ }
+ },
+ "foldingRange": {
+ "lineFoldingOnly": true
+ },
+ "synchronization": {
+ "dynamicRegistration": true,
+ "willSave": true,
+ "willSaveWaitUntil": true,
+ "didSave": true
+ }
+ },
+ "workspace": {
+ "configuration": true,
+ "workspaceFolders": true
+ },
+ "experimental": {
+ "testingApi": true
+ }
+ }
+}
diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js
index ab43af38d..b39f56cf6 100644
--- a/cli/tsc/99_main_compiler.js
+++ b/cli/tsc/99_main_compiler.js
@@ -898,6 +898,15 @@ delete Object.prototype.__proto__;
),
);
}
+ case "provideInlayHints":
+ return respond(
+ id,
+ languageService.provideInlayHints(
+ request.specifier,
+ request.span,
+ request.preferences,
+ ),
+ );
default:
throw new TypeError(
// @ts-ignore exhausted case statement sets type to never
diff --git a/cli/tsc/compiler.d.ts b/cli/tsc/compiler.d.ts
index 31c8b8c64..ffd4695ae 100644
--- a/cli/tsc/compiler.d.ts
+++ b/cli/tsc/compiler.d.ts
@@ -77,7 +77,8 @@ declare global {
| GetTypeDefinitionRequest
| PrepareCallHierarchy
| ProvideCallHierarchyIncomingCalls
- | ProvideCallHierarchyOutgoingCalls;
+ | ProvideCallHierarchyOutgoingCalls
+ | ProvideInlayHints;
interface BaseLanguageServerRequest {
id: number;
@@ -255,6 +256,13 @@ declare global {
position: number;
}
+ interface ProvideInlayHints extends BaseLanguageServerRequest {
+ method: "provideInlayHints";
+ specifier: string;
+ span: ts.TextSpan;
+ preferences?: ts.UserPreferences;
+ }
+
interface Restart extends BaseLanguageServerRequest {
method: "restart";
}