ricecoder_storage/industry/
windsurf.rs1use crate::config::{Config, SteeringRule};
7use crate::error::StorageResult;
8use crate::types::DocumentFormat;
9use std::path::Path;
10use tracing::debug;
11
12use super::adapter::IndustryFileAdapter;
13
14pub struct WindsurfAdapter;
16
17impl WindsurfAdapter {
18 pub fn new() -> Self {
20 WindsurfAdapter
21 }
22
23 fn read_windsurfrules(&self, project_root: &Path) -> StorageResult<Option<String>> {
25 let windsurfrules_path = project_root.join(".windsurfrules");
26
27 if !windsurfrules_path.exists() {
28 debug!("No .windsurfrules file found at {:?}", windsurfrules_path);
29 return Ok(None);
30 }
31
32 debug!("Reading .windsurfrules from {:?}", windsurfrules_path);
33 let content = std::fs::read_to_string(&windsurfrules_path).map_err(|e| {
34 crate::error::StorageError::io_error(
35 windsurfrules_path.clone(),
36 crate::error::IoOperation::Read,
37 e,
38 )
39 })?;
40
41 Ok(Some(content))
42 }
43}
44
45impl Default for WindsurfAdapter {
46 fn default() -> Self {
47 Self::new()
48 }
49}
50
51impl IndustryFileAdapter for WindsurfAdapter {
52 fn name(&self) -> &'static str {
53 "windsurf"
54 }
55
56 fn can_handle(&self, project_root: &Path) -> bool {
57 project_root.join(".windsurfrules").exists()
58 }
59
60 fn read_config(&self, project_root: &Path) -> StorageResult<Config> {
61 let mut config = Config::default();
62
63 if let Ok(Some(rules_content)) = self.read_windsurfrules(project_root) {
64 debug!("Adding Windsurf rules as steering rule");
65 config.steering.push(SteeringRule {
66 name: "windsurf-rules".to_string(),
67 content: rules_content,
68 format: DocumentFormat::Markdown,
69 });
70 }
71
72 Ok(config)
73 }
74
75 fn priority(&self) -> u32 {
76 50
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use std::fs;
85 use tempfile::TempDir;
86
87 #[test]
88 fn test_windsurf_adapter_detects_windsurfrules() {
89 let temp_dir = TempDir::new().unwrap();
90 let windsurfrules_path = temp_dir.path().join(".windsurfrules");
91 fs::write(&windsurfrules_path, "# Windsurf rules").unwrap();
92
93 let adapter = WindsurfAdapter::new();
94 assert!(adapter.can_handle(temp_dir.path()));
95 }
96
97 #[test]
98 fn test_windsurf_adapter_no_file() {
99 let temp_dir = TempDir::new().unwrap();
100
101 let adapter = WindsurfAdapter::new();
102 assert!(!adapter.can_handle(temp_dir.path()));
103 }
104
105 #[test]
106 fn test_windsurf_adapter_reads_windsurfrules() {
107 let temp_dir = TempDir::new().unwrap();
108 let windsurfrules_path = temp_dir.path().join(".windsurfrules");
109 let rules = "# Windsurf Rules\nBe productive";
110 fs::write(&windsurfrules_path, rules).unwrap();
111
112 let adapter = WindsurfAdapter::new();
113 let config = adapter.read_config(temp_dir.path()).unwrap();
114
115 assert_eq!(config.steering.len(), 1);
116 assert_eq!(config.steering[0].name, "windsurf-rules");
117 assert_eq!(config.steering[0].content, rules);
118 assert_eq!(config.steering[0].format, DocumentFormat::Markdown);
119 }
120
121 #[test]
122 fn test_windsurf_adapter_priority() {
123 let adapter = WindsurfAdapter::new();
124 assert_eq!(adapter.priority(), 50);
125 }
126
127 #[test]
128 fn test_windsurf_adapter_name() {
129 let adapter = WindsurfAdapter::new();
130 assert_eq!(adapter.name(), "windsurf");
131 }
132}