1#![doc = include_str!("README.md")]
2
3pub mod lsp;
4pub mod treesitter;
5
6use lsp::{
7 HierarchyClient as LspHierarchyClient, LspProvider,
8 WorkspaceSymbolClient as LspWorkspaceSymbolClient,
9};
10use treesitter::{
11 HierarchyClient as TreeSitterHierarchyClient, TreeSitterProvider,
12 WorkspaceSymbolClient as TreeSitterWorkspaceSymbolClient,
13};
14
15use crate::state::{HierarchyDirection, SymbolIdentity};
16use tower_lsp::lsp_types::{Range, SymbolKind, Url};
17
18#[derive(Clone, Debug, Eq, PartialEq)]
19pub struct WorkspaceSymbolMatch {
20 pub name: String,
23 pub kind: SymbolKind,
24 pub container_name: Option<String>,
25 pub uri: Url,
26 pub range: Option<Range>,
27}
28
29impl WorkspaceSymbolMatch {
30 pub fn display_name(&self) -> String {
31 self.name.clone()
32 }
33}
34
35#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub enum FetchSource {
37 Lsp,
38 TreeSitter,
39}
40
41#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
42pub enum CachePolicy {
43 #[default]
44 UseCache,
45 Refresh,
46}
47
48#[derive(Clone, Debug, Eq, PartialEq)]
50pub struct HierarchyQuery {
51 pub symbol: SymbolIdentity,
52 pub direction: HierarchyDirection,
53}
54
55#[derive(Clone, Debug, Eq, PartialEq)]
57pub struct HierarchyResponse {
58 pub query: HierarchyQuery,
59 pub children: Vec<SymbolIdentity>,
60 pub source: FetchSource,
61}
62
63#[derive(Clone, Debug)]
64pub enum WorkspaceSymbolClient {
65 Lsp(LspWorkspaceSymbolClient),
66 TreeSitter(TreeSitterWorkspaceSymbolClient),
67}
68
69impl WorkspaceSymbolClient {
70 pub async fn query(&self, query: &str) -> anyhow::Result<Vec<WorkspaceSymbolMatch>> {
71 match self {
72 Self::Lsp(client) => client.query(query).await,
73 Self::TreeSitter(client) => client.query(query).await,
74 }
75 }
76}
77
78impl From<LspWorkspaceSymbolClient> for WorkspaceSymbolClient {
79 fn from(client: LspWorkspaceSymbolClient) -> Self {
80 Self::Lsp(client)
81 }
82}
83
84impl From<TreeSitterWorkspaceSymbolClient> for WorkspaceSymbolClient {
85 fn from(client: TreeSitterWorkspaceSymbolClient) -> Self {
86 Self::TreeSitter(client)
87 }
88}
89
90#[derive(Clone, Debug)]
91pub enum HierarchyClient {
92 Lsp(LspHierarchyClient),
93 TreeSitter(TreeSitterHierarchyClient),
94}
95
96impl HierarchyClient {
97 pub async fn query(&self, query: HierarchyQuery) -> anyhow::Result<HierarchyResponse> {
98 match self {
99 Self::Lsp(client) => client.query(query).await,
100 Self::TreeSitter(client) => client.query(query).await,
101 }
102 }
103}
104
105impl From<LspHierarchyClient> for HierarchyClient {
106 fn from(client: LspHierarchyClient) -> Self {
107 Self::Lsp(client)
108 }
109}
110
111impl From<TreeSitterHierarchyClient> for HierarchyClient {
112 fn from(client: TreeSitterHierarchyClient) -> Self {
113 Self::TreeSitter(client)
114 }
115}
116
117#[derive(Debug, Default)]
118pub struct FetchCoordinator {
119 lsp: Option<LspProvider>,
120 tree_sitter: Option<TreeSitterProvider>,
121}
122
123impl FetchCoordinator {
124 pub fn with_lsp(lsp: LspProvider) -> Self {
125 Self {
126 lsp: Some(lsp),
127 tree_sitter: None,
128 }
129 }
130
131 pub fn with_tree_sitter(tree_sitter: TreeSitterProvider) -> Self {
132 Self {
133 lsp: None,
134 tree_sitter: Some(tree_sitter),
135 }
136 }
137
138 pub fn lsp(&self) -> Option<&LspProvider> {
139 self.lsp.as_ref()
140 }
141
142 pub fn workspace_symbol_client(&self) -> Option<WorkspaceSymbolClient> {
143 self.lsp
144 .as_ref()
145 .map(LspProvider::workspace_symbol_client)
146 .map(WorkspaceSymbolClient::from)
147 .or_else(|| {
148 self.tree_sitter
149 .as_ref()
150 .map(TreeSitterProvider::workspace_symbol_client)
151 .map(WorkspaceSymbolClient::from)
152 })
153 }
154
155 pub fn hierarchy_client(&self) -> Option<HierarchyClient> {
156 self.lsp
157 .as_ref()
158 .map(LspProvider::hierarchy_client)
159 .map(HierarchyClient::from)
160 .or_else(|| {
161 self.tree_sitter
162 .as_ref()
163 .map(TreeSitterProvider::hierarchy_client)
164 .map(HierarchyClient::from)
165 })
166 }
167
168 pub async fn workspace_symbols(
169 &self,
170 query: &str,
171 ) -> anyhow::Result<Vec<WorkspaceSymbolMatch>> {
172 self.workspace_symbol_client()
173 .ok_or_else(|| anyhow::anyhow!("no workspace-symbol provider is configured"))?
174 .query(query)
175 .await
176 }
177
178 pub async fn hierarchy(&self, query: HierarchyQuery) -> anyhow::Result<HierarchyResponse> {
179 self.hierarchy_client()
180 .ok_or_else(|| anyhow::anyhow!("no hierarchy provider is configured"))?
181 .query(query)
182 .await
183 }
184}