Skip to main content

matrixcode_core/memory/
keywords_config.rs

1//! Keywords configuration for memory detection.
2//! Loads from ~/.matrix/keywords.json or uses embedded defaults.
3
4use std::collections::{HashMap, HashSet};
5use std::env::var_os;
6use std::path::PathBuf;
7
8use serde::{Deserialize, Serialize};
9
10use super::types::MemoryCategory;
11
12fn home_dir() -> Option<PathBuf> {
13    var_os("HOME").or_else(|| var_os("USERPROFILE")).map(PathBuf::from)
14}
15
16// ============================================================================
17// Embedded Defaults (simplified)
18// ============================================================================
19
20pub fn get_default_keywords() -> KeywordsConfig {
21    KeywordsConfig {
22        version: 1,
23        patterns: default_patterns(),
24        stop_words: default_stop_words(),
25        contradiction_signals: default_contradiction_signals(),
26    }
27}
28
29fn default_patterns() -> HashMap<String, Vec<String>> {
30    let data: [(&str, &[&str]); 6] = [
31        ("decision", &["决定", "选择", "采用", "定下", "decided", "chose"]),
32        ("preference", &["偏好", "习惯", "喜欢", "首选", "prefer", "like"]),
33        ("solution", &["解决", "修复", "搞定", "改成", "fixed", "solved"]),
34        ("finding", &["发现", "原来", "原因", "定位", "found", "reason"]),
35        ("technical", &["技术栈", "框架", "用的", "基于", "stack", "using"]),
36        ("structure", &["入口", "主文件", "目录", "位于", "entry", "main"]),
37    ];
38    data.into_iter()
39        .map(|(k, v)| (k.to_string(), v.iter().map(|s| s.to_string()).collect()))
40        .collect()
41}
42
43fn default_stop_words() -> Vec<String> {
44    // Common Chinese + English stop words (simplified)
45    vec![
46        // Chinese
47        "的", "了", "是", "在", "我", "有", "和", "就", "不", "都", "一", "也", "很", "到", "要", "去",
48        "你", "会", "着", "没有", "看", "好", "这", "那", "什么", "怎么", "请", "能", "可以", "需要",
49        // English
50        "the", "a", "an", "is", "are", "was", "were", "be", "have", "has", "do", "will", "would",
51        "could", "should", "can", "to", "of", "in", "for", "on", "with", "at", "by", "from", "and",
52        "but", "or", "not", "if", "then", "this", "that", "it", "i", "me", "my", "we", "you", "he",
53        "she", "they", "please", "help", "need", "want", "let", "use",
54    ].into_iter().map(|s| s.to_string()).collect()
55}
56
57fn default_contradiction_signals() -> Vec<String> {
58    vec!["改用", "换成", "改为", "不再", "弃用", "switched", "changed", "replaced", "deprecated"]
59        .into_iter().map(|s| s.to_string()).collect()
60}
61
62// ============================================================================
63// Configuration Structure
64// ============================================================================
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct KeywordsConfig {
68    pub version: u32,
69    pub patterns: HashMap<String, Vec<String>>,
70    pub stop_words: Vec<String>,
71    pub contradiction_signals: Vec<String>,
72}
73
74impl KeywordsConfig {
75    pub fn load() -> Self {
76        // Try ~/.matrix/keywords.json
77        if let Some(home) = home_dir() {
78            let path = home.join(".matrix").join("keywords.json");
79            if path.exists() {
80                if let Ok(content) = std::fs::read_to_string(&path) {
81                    if let Ok(config) = serde_json::from_str::<Self>(&content) {
82                        return config;
83                    }
84                }
85            }
86        }
87        get_default_keywords()
88    }
89
90    pub fn get_patterns(&self, category: MemoryCategory) -> &[String] {
91        let key = match category {
92            MemoryCategory::Decision | MemoryCategory::KeyDecision => "decision",
93            MemoryCategory::Preference | MemoryCategory::UserIntentPattern => "preference",
94            MemoryCategory::Solution | MemoryCategory::FailedApproach | MemoryCategory::TaskPattern => "solution",
95            MemoryCategory::Finding => "finding",
96            MemoryCategory::Technical => "technical",
97            MemoryCategory::Structure => "structure",
98        };
99        self.patterns.get(key).map(|v| v.as_slice()).unwrap_or(&[])
100    }
101
102    pub fn get_stop_words_set(&self) -> HashSet<&str> {
103        self.stop_words.iter().map(|s| s.as_str()).collect()
104    }
105
106    pub fn get_aliases() -> Vec<(&'static str, &'static str)> {
107        // Static aliases (most common mappings)
108        vec![
109            ("数据库", "database"), ("db", "database"),
110            ("前端", "frontend"), ("ui", "frontend"),
111            ("后端", "backend"), ("服务", "service"),
112            ("接口", "api"), ("配置", "config"),
113            ("测试", "test"), ("缓存", "cache"),
114            ("认证", "auth"), ("登录", "login"),
115        ]
116    }
117}
118
119impl Default for KeywordsConfig {
120    fn default() -> Self {
121        Self::load()
122    }
123}