Skip to main content

searchfox_lib/
definition.rs

1use crate::client::SearchfoxClient;
2use crate::search::SearchOptions;
3use crate::utils::extract_complete_method;
4use anyhow::Result;
5use log::{debug, error};
6
7impl SearchfoxClient {
8    pub async fn get_definition_context(
9        &self,
10        file_path: &str,
11        line_number: usize,
12        context_lines: usize,
13    ) -> Result<String> {
14        let file_content = self.get_file(file_path).await?;
15        let lines: Vec<&str> = file_content.lines().collect();
16
17        let (_, method_lines) = extract_complete_method(&lines, line_number);
18
19        if method_lines.len() > 1 {
20            return Ok(method_lines.join("\n"));
21        }
22
23        let start_line = if line_number > context_lines {
24            line_number - context_lines
25        } else {
26            1
27        };
28        let end_line = std::cmp::min(line_number + context_lines, lines.len());
29
30        let mut result = String::new();
31        for (i, line) in lines.iter().enumerate() {
32            let line_num = i + 1;
33            if line_num >= start_line && line_num <= end_line {
34                let marker = if line_num == line_number {
35                    ">>>"
36                } else {
37                    "   "
38                };
39                result.push_str(&format!("{marker} {line_num:4}: {line}\n"));
40            }
41        }
42
43        Ok(result)
44    }
45
46    pub async fn find_and_display_definition(
47        &self,
48        symbol: &str,
49        path_filter: Option<&str>,
50        options: &SearchOptions,
51    ) -> Result<String> {
52        debug!("Finding potential definition locations...");
53        let file_locations = self
54            .find_symbol_locations(symbol, path_filter, options)
55            .await?;
56
57        if file_locations.is_empty() {
58            error!("No potential definitions found for '{symbol}'");
59            return Ok(String::new());
60        }
61
62        debug!(
63            "Found {} potential definition location(s)",
64            file_locations.len()
65        );
66
67        let is_ctor = symbol.rfind("::").is_some_and(|pos| {
68            let class_part = &symbol[..pos];
69            let method_part = &symbol[pos + 2..];
70            let class_name = class_part.split("::").last().unwrap_or(class_part);
71            class_name == method_part
72        });
73
74        let mut results = Vec::new();
75        for (file_path, line_number) in &file_locations {
76            let context_lines = if is_ctor { 2 } else { 10 };
77            match self
78                .get_definition_context(file_path, *line_number, context_lines)
79                .await
80            {
81                Ok(context) => {
82                    if !context.is_empty() {
83                        results.push(context);
84                    }
85                }
86                Err(e) => {
87                    error!("Could not fetch context: {e}");
88                }
89            }
90        }
91
92        if results.is_empty() {
93            error!("No definition found for symbol '{symbol}'");
94            Ok(String::new())
95        } else if results.len() == 1 {
96            Ok(results[0].clone())
97        } else {
98            Ok(results.join("\n\n"))
99        }
100    }
101}