ricecoder_external_lsp/merger/
hover.rs

1//! Hover merging
2
3use crate::types::MergeConfig;
4
5/// Merges hover information from external LSP and internal providers
6pub struct HoverMerger;
7
8impl HoverMerger {
9    /// Create a new hover merger
10    pub fn new() -> Self {
11        Self
12    }
13
14    /// Merge hover information from external LSP and internal provider
15    ///
16    /// # Arguments
17    ///
18    /// * `external` - Hover information from external LSP server (if available)
19    /// * `internal` - Hover information from internal provider
20    /// * `config` - Merge configuration
21    ///
22    /// # Returns
23    ///
24    /// Merged hover information (external takes precedence)
25    pub fn merge(
26        external: Option<String>,
27        internal: Option<String>,
28        config: &MergeConfig,
29    ) -> Option<String> {
30        // External hover takes precedence
31        if let Some(ext) = external {
32            return Some(ext);
33        }
34
35        // Fall back to internal if configured
36        if config.include_internal {
37            return internal;
38        }
39
40        None
41    }
42
43    /// Combine hover information from multiple sources
44    ///
45    /// # Arguments
46    ///
47    /// * `external` - Hover information from external LSP server (if available)
48    /// * `internal` - Hover information from internal provider
49    ///
50    /// # Returns
51    ///
52    /// Combined hover information with both sources
53    pub fn combine(external: Option<String>, internal: Option<String>) -> Option<String> {
54        match (external, internal) {
55            (Some(ext), Some(int)) => {
56                // Combine both sources
57                Some(format!("{}\n\n---\n\n{}", ext, int))
58            }
59            (Some(ext), None) => Some(ext),
60            (None, Some(int)) => Some(int),
61            (None, None) => None,
62        }
63    }
64}
65
66impl Default for HoverMerger {
67    fn default() -> Self {
68        Self::new()
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn test_merge_external_only() {
78        let external = Some("External hover".to_string());
79        let internal = Some("Internal hover".to_string());
80        let config = MergeConfig::default();
81
82        let result = HoverMerger::merge(external, internal, &config);
83
84        assert_eq!(result, Some("External hover".to_string()));
85    }
86
87    #[test]
88    fn test_merge_internal_only() {
89        let external = None;
90        let internal = Some("Internal hover".to_string());
91        let config = MergeConfig::default();
92
93        let result = HoverMerger::merge(external, internal, &config);
94
95        assert_eq!(result, Some("Internal hover".to_string()));
96    }
97
98    #[test]
99    fn test_merge_without_internal() {
100        let external = None;
101        let internal = Some("Internal hover".to_string());
102        let config = MergeConfig {
103            include_internal: false,
104            deduplicate: true,
105        };
106
107        let result = HoverMerger::merge(external, internal, &config);
108
109        assert_eq!(result, None);
110    }
111
112    #[test]
113    fn test_merge_both_none() {
114        let external = None;
115        let internal = None;
116        let config = MergeConfig::default();
117
118        let result = HoverMerger::merge(external, internal, &config);
119
120        assert_eq!(result, None);
121    }
122
123    #[test]
124    fn test_combine_both() {
125        let external = Some("External hover".to_string());
126        let internal = Some("Internal hover".to_string());
127
128        let result = HoverMerger::combine(external, internal);
129
130        assert!(result.is_some());
131        let combined = result.unwrap();
132        assert!(combined.contains("External hover"));
133        assert!(combined.contains("Internal hover"));
134        assert!(combined.contains("---"));
135    }
136
137    #[test]
138    fn test_combine_external_only() {
139        let external = Some("External hover".to_string());
140        let internal = None;
141
142        let result = HoverMerger::combine(external, internal);
143
144        assert_eq!(result, Some("External hover".to_string()));
145    }
146
147    #[test]
148    fn test_combine_internal_only() {
149        let external = None;
150        let internal = Some("Internal hover".to_string());
151
152        let result = HoverMerger::combine(external, internal);
153
154        assert_eq!(result, Some("Internal hover".to_string()));
155    }
156
157    #[test]
158    fn test_combine_both_none() {
159        let external = None;
160        let internal = None;
161
162        let result = HoverMerger::combine(external, internal);
163
164        assert_eq!(result, None);
165    }
166}