html_languageservice/
html_language_service.rs

1use crate::html_language_types::HTMLLanguageServiceOptions;
2use crate::language_facts::data_provider::IHTMLDataProvider;
3use crate::parser::html_document::HTMLDocument;
4use crate::parser::html_parse::HTMLParser;
5use crate::parser::html_scanner::{Scanner, ScannerState};
6#[cfg(feature = "completion")]
7use crate::participant::ICompletionParticipant;
8#[cfg(feature = "hover")]
9use crate::participant::IHoverParticipant;
10#[cfg(feature = "completion")]
11use crate::services::html_completion::HTMLCompletion;
12#[cfg(feature = "folding")]
13use crate::services::html_folding;
14#[cfg(feature = "formatter")]
15use crate::services::html_formatter;
16#[cfg(feature = "highlight")]
17use crate::services::html_highlight;
18#[cfg(feature = "hover")]
19use crate::services::html_hover::HTMLHover;
20#[cfg(feature = "linked_editing")]
21use crate::services::html_linked_editing;
22#[cfg(feature = "links")]
23use crate::services::html_links;
24#[cfg(feature = "matching_tag_position")]
25use crate::services::html_matching_tag_position;
26#[cfg(feature = "rename")]
27use crate::services::html_rename;
28#[cfg(feature = "selection_range")]
29use crate::services::html_selection_range;
30#[cfg(feature = "symbols")]
31use crate::services::html_symbols;
32
33#[cfg(feature = "formatter")]
34use crate::HTMLFormatConfiguration;
35
36#[cfg(feature = "completion")]
37use crate::CompletionConfiguration;
38#[cfg(any(feature = "completion", feature = "links"))]
39use crate::DocumentContext;
40#[cfg(feature = "folding")]
41use crate::FoldingRangeContext;
42use crate::HTMLDataManager;
43#[cfg(feature = "hover")]
44use crate::HoverSettings;
45
46#[cfg(feature = "completion")]
47use lsp_types::CompletionList;
48#[cfg(feature = "highlight")]
49use lsp_types::DocumentHighlight;
50#[cfg(feature = "links")]
51use lsp_types::DocumentLink;
52#[cfg(feature = "folding")]
53use lsp_types::FoldingRange;
54#[cfg(feature = "hover")]
55use lsp_types::Hover;
56#[cfg(any(
57    feature = "formatter",
58    feature = "completion",
59    feature = "hover",
60    feature = "highlight",
61    feature = "selection_range",
62    feature = "rename",
63    feature = "matching_tag_position",
64    feature = "linked_editing"
65))]
66use lsp_types::Position;
67#[cfg(any(feature = "formatter", feature = "linked_editing"))]
68use lsp_types::Range;
69#[cfg(feature = "selection_range")]
70use lsp_types::SelectionRange;
71#[cfg(feature = "formatter")]
72use lsp_types::TextEdit;
73#[cfg(any(feature = "links", feature = "symbols", feature = "rename"))]
74use lsp_types::Uri;
75#[cfg(feature = "rename")]
76use lsp_types::WorkspaceEdit;
77#[cfg(feature = "symbols")]
78use lsp_types::{DocumentSymbol, SymbolInformation};
79
80use lsp_textdocument::FullTextDocument;
81
82/// This is a collection of features necessary to implement an HTML language server
83///
84/// Make sure you activated the features you need of the `html-languageservice` crate on `Cargo.toml`
85///
86/// # Features
87///
88/// - completion
89/// - hover
90/// - formatter
91/// - highlight
92/// - links
93/// - symbols
94/// - folding
95/// - selection_range
96/// - rename
97/// - matching_tag_position
98/// - linked_editing
99#[derive(Debug)]
100pub struct HTMLLanguageService {
101    #[cfg(feature = "completion")]
102    html_completion: HTMLCompletion,
103    #[cfg(feature = "hover")]
104    html_hover: HTMLHover,
105    case_sensitive: bool,
106}
107
108impl HTMLLanguageService {
109    pub fn new(options: &HTMLLanguageServiceOptions) -> HTMLLanguageService {
110        HTMLLanguageService {
111            #[cfg(feature = "completion")]
112            html_completion: HTMLCompletion::new(options),
113            #[cfg(feature = "hover")]
114            html_hover: HTMLHover::new(options),
115            case_sensitive: options.case_sensitive.unwrap_or(false),
116        }
117    }
118
119    pub fn create_scanner<'a>(&self, input: &'a str, initial_offset: usize) -> Scanner<'a> {
120        Scanner::new(
121            input,
122            initial_offset,
123            ScannerState::WithinContent,
124            false,
125            self.case_sensitive,
126        )
127    }
128
129    pub fn create_data_manager(
130        &self,
131        use_default_data_provider: bool,
132        custom_data_providers: Option<Vec<Box<dyn IHTMLDataProvider>>>,
133    ) -> HTMLDataManager {
134        HTMLDataManager::new(
135            use_default_data_provider,
136            custom_data_providers,
137            self.case_sensitive,
138        )
139    }
140
141    pub fn parse_html_document(
142        &self,
143        document: &FullTextDocument,
144        data_manager: &HTMLDataManager,
145    ) -> HTMLDocument {
146        HTMLParser::parse_document(document, data_manager, self.case_sensitive)
147    }
148
149    /// Provide completion proposals for a given location
150    #[cfg(feature = "completion")]
151    pub fn do_complete(
152        &self,
153        document: &FullTextDocument,
154        position: &Position,
155        html_document: &HTMLDocument,
156        document_context: &impl DocumentContext,
157        settings: Option<&CompletionConfiguration>,
158        data_manager: &HTMLDataManager,
159    ) -> CompletionList {
160        self.html_completion.do_complete(
161            document,
162            position,
163            html_document,
164            document_context,
165            settings,
166            data_manager,
167        )
168    }
169
170    /// Add additional completion items to the completion proposal
171    #[cfg(feature = "completion")]
172    pub fn set_completion_participants(
173        &mut self,
174        completion_participants: Vec<Box<dyn ICompletionParticipant>>,
175    ) {
176        self.html_completion
177            .set_completion_participants(completion_participants);
178    }
179
180    /// Provide quotes completion when `=` is entered
181    #[cfg(feature = "completion")]
182    pub fn do_quote_complete(
183        &self,
184        document: &FullTextDocument,
185        position: &Position,
186        html_document: &HTMLDocument,
187        settings: Option<&CompletionConfiguration>,
188    ) -> Option<String> {
189        self.html_completion
190            .do_quote_complete(document, position, html_document, settings)
191    }
192
193    /// Completes the tag when `>` or `/` is entered
194    #[cfg(feature = "completion")]
195    pub fn do_tag_complete(
196        &self,
197        document: &FullTextDocument,
198        position: &Position,
199        html_document: &HTMLDocument,
200        data_manager: &HTMLDataManager,
201    ) -> Option<String> {
202        self.html_completion
203            .do_tag_complete(document, position, html_document, data_manager)
204    }
205
206    /// Provides hover information at a given location
207    #[cfg(feature = "hover")]
208    pub fn do_hover(
209        &self,
210        document: &FullTextDocument,
211        position: &Position,
212        html_document: &HTMLDocument,
213        options: Option<HoverSettings>,
214        data_manager: &HTMLDataManager,
215    ) -> Option<Hover> {
216        self.html_hover
217            .do_hover(document, position, html_document, options, data_manager)
218    }
219
220    /// Add additional hover to the hover proposal
221    #[cfg(feature = "hover")]
222    pub fn set_hover_participants(&mut self, hover_participants: Vec<Box<dyn IHoverParticipant>>) {
223        self.html_hover.set_hover_participants(hover_participants);
224    }
225
226    /// Formats the code at the given range
227    ///
228    /// Note: `format` is not prefect, it's under development
229    #[cfg(feature = "formatter")]
230    pub fn format(
231        &self,
232        document: &FullTextDocument,
233        range: Option<Range>,
234        options: &HTMLFormatConfiguration,
235    ) -> Vec<TextEdit> {
236        html_formatter::format(document, &range, options, self.case_sensitive)
237    }
238
239    /// Provides document highlights capability
240    #[cfg(feature = "highlight")]
241    pub fn find_document_highlights(
242        &self,
243        document: &FullTextDocument,
244        position: &Position,
245        html_document: &HTMLDocument,
246    ) -> Vec<DocumentHighlight> {
247        html_highlight::find_document_highlights(
248            document,
249            position,
250            html_document,
251            self.case_sensitive,
252        )
253    }
254
255    /// Finds all links in the document
256    #[cfg(feature = "links")]
257    pub fn find_document_links(
258        &self,
259        uri: &Uri,
260        document: &FullTextDocument,
261        document_context: &impl DocumentContext,
262        data_manager: &HTMLDataManager,
263    ) -> Vec<DocumentLink> {
264        html_links::find_document_links(
265            uri,
266            document,
267            document_context,
268            data_manager,
269            self.case_sensitive,
270        )
271    }
272
273    /// Finds all the symbols in the document, it returns `SymbolInformation`
274    #[cfg(feature = "symbols")]
275    pub fn find_document_symbols(
276        uri: &Uri,
277        document: &FullTextDocument,
278        html_document: &HTMLDocument,
279    ) -> Vec<SymbolInformation> {
280        html_symbols::find_document_symbols(uri, document, html_document)
281    }
282
283    /// Finds all the symbols in the document, it returns `DocumentSymbol`
284    #[cfg(feature = "symbols")]
285    pub fn find_document_symbols2(
286        document: &FullTextDocument,
287        html_document: &HTMLDocument,
288    ) -> Vec<DocumentSymbol> {
289        html_symbols::find_document_symbols2(document, html_document)
290    }
291
292    /// Get folding ranges for the given document
293    #[cfg(feature = "folding")]
294    pub fn get_folding_ranges(
295        &self,
296        document: &FullTextDocument,
297        context: FoldingRangeContext,
298        data_manager: &HTMLDataManager,
299    ) -> Vec<FoldingRange> {
300        html_folding::get_folding_ranges(document, context, data_manager, self.case_sensitive)
301    }
302
303    /// Get the selection ranges for the given document
304    #[cfg(feature = "selection_range")]
305    pub fn get_selection_ranges(
306        &self,
307        document: &FullTextDocument,
308        positions: &Vec<Position>,
309        html_document: &HTMLDocument,
310    ) -> Vec<SelectionRange> {
311        html_selection_range::get_selection_ranges(
312            document,
313            positions,
314            html_document,
315            self.case_sensitive,
316        )
317    }
318
319    /// Rename the matching tag
320    #[cfg(feature = "rename")]
321    pub fn do_rename(
322        uri: Uri,
323        document: &FullTextDocument,
324        position: Position,
325        new_name: &str,
326        html_document: &HTMLDocument,
327    ) -> Option<WorkspaceEdit> {
328        html_rename::do_rename(uri, document, position, new_name, html_document)
329    }
330
331    /// Get the location of the matching tag
332    #[cfg(feature = "matching_tag_position")]
333    pub fn find_matching_tag_position(
334        document: &FullTextDocument,
335        position: Position,
336        html_document: &HTMLDocument,
337    ) -> Option<Position> {
338        html_matching_tag_position::find_matching_tag_position(document, position, html_document)
339    }
340
341    /// Provides linked editing range capability
342    #[cfg(feature = "linked_editing")]
343    pub fn find_linked_editing_ranges(
344        document: &FullTextDocument,
345        position: Position,
346        html_document: &HTMLDocument,
347    ) -> Option<Vec<Range>> {
348        html_linked_editing::find_linked_editing_ranges(document, position, html_document)
349    }
350}