summaryrefslogtreecommitdiff
path: root/support/texlab/crates/texlab/src/features/symbols.rs
blob: 65e92a5b177eb28b2ebb3e6cec4e99d8bb717041 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use base_db::{data::BibtexEntryTypeCategory, Document, Workspace};
use lsp_types::{
    ClientCapabilities, DocumentSymbol, DocumentSymbolResponse, Location, WorkspaceSymbolResponse,
};

use crate::util::{capabilities::ClientCapabilitiesExt, line_index_ext::LineIndexExt};

pub fn document_symbols(
    workspace: &Workspace,
    document: &Document,
    capabilities: &ClientCapabilities,
) -> DocumentSymbolResponse {
    let symbols = symbols::document_symbols(workspace, document);
    if capabilities.has_hierarchical_document_symbol_support() {
        let results = symbols
            .into_iter()
            .filter_map(|symbol| convert_to_nested_symbol(symbol, document))
            .collect();

        DocumentSymbolResponse::Nested(results)
    } else {
        let mut results = Vec::new();
        for symbol in symbols {
            convert_to_flat_symbols(symbol, document, &mut results);
        }

        DocumentSymbolResponse::Flat(results)
    }
}

pub fn workspace_symbols(workspace: &Workspace, query: &str) -> WorkspaceSymbolResponse {
    let symbols = symbols::workspace_symbols(workspace, query);
    let mut results = Vec::new();
    for symbols::SymbolLocation { symbol, document } in symbols {
        convert_to_flat_symbols(symbol, document, &mut results);
    }

    WorkspaceSymbolResponse::Flat(results)
}

fn convert_to_nested_symbol(
    symbol: symbols::Symbol,
    document: &Document,
) -> Option<DocumentSymbol> {
    let children = symbol
        .children
        .into_iter()
        .filter_map(|child| convert_to_nested_symbol(child, document))
        .collect();

    #[allow(deprecated)]
    Some(DocumentSymbol {
        name: symbol.name,
        detail: symbol.label.map(|label| label.text),
        kind: convert_symbol_kind(symbol.kind),
        deprecated: Some(false),
        range: document.line_index.line_col_lsp_range(symbol.full_range)?,
        selection_range: document
            .line_index
            .line_col_lsp_range(symbol.selection_range)?,
        children: Some(children),
        tags: None,
    })
}

fn convert_to_flat_symbols(
    symbol: symbols::Symbol,
    document: &Document,
    results: &mut Vec<lsp_types::SymbolInformation>,
) {
    let Some(range) = document.line_index.line_col_lsp_range(symbol.full_range) else {
        return;
    };

    #[allow(deprecated)]
    results.push(lsp_types::SymbolInformation {
        name: symbol.name,
        kind: convert_symbol_kind(symbol.kind),
        deprecated: Some(false),
        location: Location::new(document.uri.clone(), range),
        tags: None,
        container_name: None,
    });

    for child in symbol.children {
        convert_to_flat_symbols(child, document, results);
    }
}

fn convert_symbol_kind(value: symbols::SymbolKind) -> lsp_types::SymbolKind {
    match value {
        symbols::SymbolKind::Section => lsp_types::SymbolKind::MODULE,
        symbols::SymbolKind::Figure => lsp_types::SymbolKind::METHOD,
        symbols::SymbolKind::Algorithm => lsp_types::SymbolKind::METHOD,
        symbols::SymbolKind::Table => lsp_types::SymbolKind::METHOD,
        symbols::SymbolKind::Listing => lsp_types::SymbolKind::METHOD,
        symbols::SymbolKind::Enumeration => lsp_types::SymbolKind::ENUM,
        symbols::SymbolKind::EnumerationItem => lsp_types::SymbolKind::ENUM_MEMBER,
        symbols::SymbolKind::Theorem => lsp_types::SymbolKind::VARIABLE,
        symbols::SymbolKind::Equation => lsp_types::SymbolKind::CONSTANT,
        symbols::SymbolKind::Entry(category) => match category {
            BibtexEntryTypeCategory::Misc => lsp_types::SymbolKind::INTERFACE,
            BibtexEntryTypeCategory::String => lsp_types::SymbolKind::STRING,
            BibtexEntryTypeCategory::Article => lsp_types::SymbolKind::EVENT,
            BibtexEntryTypeCategory::Thesis => lsp_types::SymbolKind::OBJECT,
            BibtexEntryTypeCategory::Book => lsp_types::SymbolKind::STRUCT,
            BibtexEntryTypeCategory::Part => lsp_types::SymbolKind::OPERATOR,
            BibtexEntryTypeCategory::Collection => lsp_types::SymbolKind::TYPE_PARAMETER,
        },
        symbols::SymbolKind::Field => lsp_types::SymbolKind::FIELD,
    }
}