Skip to main content

pytest_language_server/providers/
code_lens.rs

1//! Code Lens provider for pytest fixtures.
2//!
3//! Shows "N usages" above fixture definitions.
4
5use super::Backend;
6use tower_lsp_server::jsonrpc::Result;
7use tower_lsp_server::ls_types::*;
8use tracing::info;
9
10impl Backend {
11    /// Handle code lens request - returns lenses for all fixtures in the file
12    pub async fn handle_code_lens(&self, params: CodeLensParams) -> Result<Option<Vec<CodeLens>>> {
13        let uri = &params.text_document.uri;
14
15        info!("code_lens request: uri={:?}", uri);
16
17        let Some(file_path) = self.uri_to_path(uri) else {
18            return Ok(None);
19        };
20
21        // Get all definitions in this file
22        let mut lenses = Vec::new();
23
24        for entry in self.fixture_db.definitions.iter() {
25            for def in entry.value() {
26                // Only show lenses for fixtures defined in this file
27                if def.file_path != file_path || def.is_third_party {
28                    continue;
29                }
30
31                // Count usages for this definition
32                let references = self.fixture_db.find_references_for_definition(def);
33                let usage_count = references.len();
34
35                let line = Self::internal_line_to_lsp(def.line);
36                let range = Self::create_range(line, 0, line, 0);
37
38                let title = if usage_count == 1 {
39                    "1 usage".to_string()
40                } else {
41                    format!("{} usages", usage_count)
42                };
43
44                // Build command arguments - these serializations should not fail
45                // for simple types like strings and numbers
46                let arguments = match (
47                    serde_json::to_value(uri.to_string()),
48                    serde_json::to_value(line),
49                    serde_json::to_value(def.start_char),
50                ) {
51                    (Ok(uri_val), Ok(line_val), Ok(char_val)) => {
52                        Some(vec![uri_val, line_val, char_val])
53                    }
54                    _ => {
55                        tracing::warn!(
56                            "Failed to serialize code lens arguments for fixture: {}",
57                            def.name
58                        );
59                        continue;
60                    }
61                };
62
63                let lens = CodeLens {
64                    range,
65                    command: Some(Command {
66                        title,
67                        command: "pytest-lsp.findReferences".to_string(),
68                        arguments,
69                    }),
70                    data: None,
71                };
72
73                lenses.push(lens);
74            }
75        }
76
77        info!("Returning {} code lenses for {:?}", lenses.len(), file_path);
78
79        if lenses.is_empty() {
80            Ok(None)
81        } else {
82            Ok(Some(lenses))
83        }
84    }
85}