lsp_types/
formatting.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{
4    DocumentSelector, DynamicRegistrationClientCapabilities, Range, TextDocumentIdentifier,
5    TextDocumentPositionParams, WorkDoneProgressParams,
6};
7
8use std::collections::HashMap;
9
10pub type DocumentFormattingClientCapabilities = DynamicRegistrationClientCapabilities;
11pub type DocumentRangeFormattingClientCapabilities = DynamicRegistrationClientCapabilities;
12pub type DocumentOnTypeFormattingClientCapabilities = DynamicRegistrationClientCapabilities;
13
14/// Format document on type options
15#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
16#[serde(rename_all = "camelCase")]
17pub struct DocumentOnTypeFormattingOptions {
18    /// A character on which formatting should be triggered, like `}`.
19    pub first_trigger_character: String,
20
21    /// More trigger characters.
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub more_trigger_character: Option<Vec<String>>,
24}
25
26#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
27#[serde(rename_all = "camelCase")]
28pub struct DocumentFormattingParams {
29    /// The document to format.
30    pub text_document: TextDocumentIdentifier,
31
32    /// The format options.
33    pub options: FormattingOptions,
34
35    #[serde(flatten)]
36    pub work_done_progress_params: WorkDoneProgressParams,
37}
38
39/// Value-object describing what options formatting should use.
40#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
41#[serde(rename_all = "camelCase")]
42pub struct FormattingOptions {
43    /// Size of a tab in spaces.
44    pub tab_size: u32,
45
46    /// Prefer spaces over tabs.
47    pub insert_spaces: bool,
48
49    /// Signature for further properties.
50    #[serde(flatten)]
51    pub properties: HashMap<String, FormattingProperty>,
52
53    /// Trim trailing whitespace on a line.
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub trim_trailing_whitespace: Option<bool>,
56
57    /// Insert a newline character at the end of the file if one does not exist.
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub insert_final_newline: Option<bool>,
60
61    /// Trim all newlines after the final newline at the end of the file.
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub trim_final_newlines: Option<bool>,
64}
65
66#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
67#[serde(untagged)]
68pub enum FormattingProperty {
69    Bool(bool),
70    Number(i32),
71    String(String),
72}
73
74#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
75#[serde(rename_all = "camelCase")]
76pub struct DocumentRangeFormattingParams {
77    /// The document to format.
78    pub text_document: TextDocumentIdentifier,
79
80    /// The range to format
81    pub range: Range,
82
83    /// The format options
84    pub options: FormattingOptions,
85
86    #[serde(flatten)]
87    pub work_done_progress_params: WorkDoneProgressParams,
88}
89
90#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
91#[serde(rename_all = "camelCase")]
92pub struct DocumentOnTypeFormattingParams {
93    /// Text Document and Position fields.
94    #[serde(flatten)]
95    pub text_document_position: TextDocumentPositionParams,
96
97    /// The character that has been typed.
98    pub ch: String,
99
100    /// The format options.
101    pub options: FormattingOptions,
102}
103
104/// Extends TextDocumentRegistrationOptions
105#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
106#[serde(rename_all = "camelCase")]
107pub struct DocumentOnTypeFormattingRegistrationOptions {
108    /// A document selector to identify the scope of the registration. If set to null
109    /// the document selector provided on the client side will be used.
110    pub document_selector: Option<DocumentSelector>,
111
112    /// A character on which formatting should be triggered, like `}`.
113    pub first_trigger_character: String,
114
115    /// More trigger characters.
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub more_trigger_character: Option<Vec<String>>,
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123    use crate::tests::test_serialization;
124
125    #[test]
126    fn formatting_options() {
127        test_serialization(
128            &FormattingOptions {
129                tab_size: 123,
130                insert_spaces: true,
131                properties: HashMap::new(),
132                trim_trailing_whitespace: None,
133                insert_final_newline: None,
134                trim_final_newlines: None,
135            },
136            r#"{"tabSize":123,"insertSpaces":true}"#,
137        );
138
139        test_serialization(
140            &FormattingOptions {
141                tab_size: 123,
142                insert_spaces: true,
143                properties: vec![("prop".to_string(), FormattingProperty::Number(1))]
144                    .into_iter()
145                    .collect(),
146                trim_trailing_whitespace: None,
147                insert_final_newline: None,
148                trim_final_newlines: None,
149            },
150            r#"{"tabSize":123,"insertSpaces":true,"prop":1}"#,
151        );
152    }
153}