| 29 | } |
| 30 | |
| 31 | func NewLSPManager(servers map[string]LSPServerConfig) *LSPManager { |
| 32 | // Sort keys for deterministic normalization order so that when two keys |
| 33 | // collapse to the same lowercase value (e.g. "TypeScript" and "typescript"), |
| 34 | // the lexicographically first original key always wins and the duplicate is |
| 35 | // logged rather than silently lost. |
| 36 | keys := make([]string, 0, len(servers)) |
| 37 | for k := range servers { |
| 38 | keys = append(keys, k) |
| 39 | } |
| 40 | sort.Strings(keys) |
| 41 | |
| 42 | normalized := make(map[string]LSPServerConfig, len(servers)) |
| 43 | for _, key := range keys { |
| 44 | language := strings.TrimSpace(strings.ToLower(key)) |
| 45 | if language == "" { |
| 46 | lspManagerLog.Printf("Skipping invalid LSP language key: %q", key) |
| 47 | continue |
| 48 | } |
| 49 | if _, exists := normalized[language]; exists { |
| 50 | lspManagerLog.Printf("Duplicate LSP language key %q (normalizes to %q): entry ignored", key, language) |
| 51 | continue |
| 52 | } |
| 53 | config := servers[key] |
| 54 | config.Command = strings.TrimSpace(config.Command) |
| 55 | normalized[language] = config |
| 56 | } |
| 57 | return &LSPManager{servers: normalized} |
| 58 | } |
| 59 | |
| 60 | func (m *LSPManager) HasServers() bool { |
| 61 | return m != nil && len(m.servers) > 0 |