Skip to content

Commit 1353ef9

Browse files
wtfbbqhaxbug-ops
authored andcommitted
Fix lsp_servers[].file_patterns
Problem While using `mcpls` in a C++ project I noticed that it always return the following error when calling get references from a '.h' header file: Error: tool call error: tool call failed for `mcpls/get_references` Caused by: tools/call failed: Mcp error: -32603: no LSP server configured for language: c After reviewing the documentation and creating an mcpls.toml with the following, it continued to not work [[lsp_servers]] language_id = "cpp" command = "clangd" args = ["--background-index", "--clang-tidy"] file_patterns = ["**/*.cpp", "**/*.cc", "**/*.cxx", "**/*.hpp", "**/*.c", "**/*.h"] # and/or with [[lsp_servers]] language_id = "c" command = "clangd" args = ["--background-index", "--clang-tidy"] file_patterns = ["**/*.c", "**/*.h"] With the above changing resulting in the language detection for matching file patterns to "plaintext" Error: tool call error: tool call failed for `mcpls/get_references` Caused by: tools/call failed: Mcp error: -32603: no LSP server configured for language: plaintext What changed - serve() now initializes the translator with an effective extension map built from both workspace mappings and LSP server file patterns: - crates/mcpls-core/src/lib.rs:114:114 - Added ServerConfig::build_effective_extension_map() to overlay extensions inferred from file_patterns: - crates/mcpls-core/src/config/mod.rs:287:287 - Added a small parser for simple glob extensions (e.g. **/*.h, *.c): - crates/mcpls-core/src/config/mod.rs:123:123 Tests added - Pattern-derived mapping overrides default extension mapping (.c/.h -> cpp): - crates/mcpls-core/src/config/mod.rs:700:700 - Complex non-simple patterns are ignored safely: - crates/mcpls-core/src/config/mod.rs:721:721 Verification - New tests passed. - Full mcpls-core unit/integration tests passed. - Existing unrelated doctest failure remains in lsp/types.rs (pre-existing visibility issue). Fix was implemented by Codex
1 parent 122780f commit 1353ef9

2 files changed

Lines changed: 83 additions & 1 deletion

File tree

crates/mcpls-core/src/config/mod.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,27 @@ impl WorkspaceConfig {
116116
}
117117
}
118118

119+
/// Extract a file extension from a glob-like file pattern.
120+
///
121+
/// Supports common patterns such as `**/*.rs` and `*.h`.
122+
/// Returns `None` for patterns without a simple trailing extension.
123+
fn extract_extension_from_pattern(pattern: &str) -> Option<String> {
124+
let (_, ext) = pattern.rsplit_once('.')?;
125+
if ext.is_empty() {
126+
return None;
127+
}
128+
129+
// Keep this conservative: only accept plain extension-like tokens.
130+
if ext
131+
.chars()
132+
.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
133+
{
134+
Some(ext.to_string())
135+
} else {
136+
None
137+
}
138+
}
139+
119140
fn default_position_encodings() -> Vec<String> {
120141
vec!["utf-8".to_string(), "utf-16".to_string()]
121142
}
@@ -258,6 +279,25 @@ fn default_language_extensions() -> Vec<LanguageExtensionMapping> {
258279
}
259280

260281
impl ServerConfig {
282+
/// Build the effective extension map used for language detection.
283+
///
284+
/// Starts with workspace mappings and overlays mappings inferred from
285+
/// configured LSP server `file_patterns`.
286+
#[must_use]
287+
pub fn build_effective_extension_map(&self) -> HashMap<String, String> {
288+
let mut map = self.workspace.build_extension_map();
289+
290+
for server in &self.lsp_servers {
291+
for pattern in &server.file_patterns {
292+
if let Some(ext) = extract_extension_from_pattern(pattern) {
293+
map.insert(ext, server.language_id.clone());
294+
}
295+
}
296+
}
297+
298+
map
299+
}
300+
261301
/// Load configuration from the default path.
262302
///
263303
/// Default paths checked in order:
@@ -656,6 +696,48 @@ mod tests {
656696
assert_eq!(map.get("unknown"), None);
657697
}
658698

699+
#[test]
700+
fn test_build_effective_extension_map_overrides_with_file_patterns() {
701+
let config = ServerConfig {
702+
workspace: WorkspaceConfig::default(),
703+
lsp_servers: vec![LspServerConfig {
704+
language_id: "cpp".to_string(),
705+
command: "clangd".to_string(),
706+
args: vec![],
707+
env: HashMap::new(),
708+
file_patterns: vec!["**/*.c".to_string(), "**/*.h".to_string()],
709+
initialization_options: None,
710+
timeout_seconds: 30,
711+
heuristics: None,
712+
}],
713+
};
714+
715+
let map = config.build_effective_extension_map();
716+
assert_eq!(map.get("c"), Some(&"cpp".to_string()));
717+
assert_eq!(map.get("h"), Some(&"cpp".to_string()));
718+
}
719+
720+
#[test]
721+
fn test_build_effective_extension_map_ignores_complex_patterns_without_extension() {
722+
let config = ServerConfig {
723+
workspace: WorkspaceConfig::default(),
724+
lsp_servers: vec![LspServerConfig {
725+
language_id: "cpp".to_string(),
726+
command: "clangd".to_string(),
727+
args: vec![],
728+
env: HashMap::new(),
729+
file_patterns: vec!["**/*".to_string(), "**/*.{h,hpp}".to_string()],
730+
initialization_options: None,
731+
timeout_seconds: 30,
732+
heuristics: None,
733+
}],
734+
};
735+
736+
let map = config.build_effective_extension_map();
737+
// Default C/C++ mappings remain unchanged when patterns cannot be parsed.
738+
assert_eq!(map.get("h"), Some(&"c".to_string()));
739+
}
740+
659741
#[test]
660742
fn test_get_language_for_extension() {
661743
let workspace = WorkspaceConfig {

crates/mcpls-core/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub async fn serve(config: ServerConfig) -> Result<(), Error> {
111111
info!("Starting MCPLS server...");
112112

113113
let workspace_roots = resolve_workspace_roots(&config.workspace.roots);
114-
let extension_map = config.workspace.build_extension_map();
114+
let extension_map = config.build_effective_extension_map();
115115
let max_depth = Some(config.workspace.heuristics_max_depth);
116116

117117
let mut translator = Translator::new().with_extensions(extension_map);

0 commit comments

Comments
 (0)