#[derive(Debug, Clone, PartialEq)]
pub struct LanguageInfo {
pub line_comment: Option<String>,
pub block_comment: Option<(String, String)>,
pub indent_char: String,
}
impl LanguageInfo {
pub fn new(
line_comment: Option<String>,
block_comment: Option<(String, String)>,
indent_char: String,
) -> Self {
Self {
line_comment,
block_comment,
indent_char,
}
}
}
pub struct LanguageRegistry;
impl LanguageRegistry {
pub fn get_language_info(language_id: &str) -> LanguageInfo {
match language_id.to_lowercase().as_str() {
"rust" => LanguageInfo::new(
Some("//".to_string()),
Some(("/*".to_string(), "*/".to_string())),
" ".to_string(),
),
"javascript" | "js" => LanguageInfo::new(
Some("//".to_string()),
Some(("/*".to_string(), "*/".to_string())),
" ".to_string(),
),
"typescript" | "ts" => LanguageInfo::new(
Some("//".to_string()),
Some(("/*".to_string(), "*/".to_string())),
" ".to_string(),
),
"python" => LanguageInfo::new(
Some("#".to_string()),
Some(("\"\"\"".to_string(), "\"\"\"".to_string())),
" ".to_string(),
),
"go" => LanguageInfo::new(
Some("//".to_string()),
Some(("/*".to_string(), "*/".to_string())),
"\t".to_string(),
),
"java" => LanguageInfo::new(
Some("//".to_string()),
Some(("/*".to_string(), "*/".to_string())),
" ".to_string(),
),
"c" => LanguageInfo::new(
Some("//".to_string()),
Some(("/*".to_string(), "*/".to_string())),
" ".to_string(),
),
"cpp" | "c++" => LanguageInfo::new(
Some("//".to_string()),
Some(("/*".to_string(), "*/".to_string())),
" ".to_string(),
),
"html" => LanguageInfo::new(
None,
Some(("<!--".to_string(), "-->".to_string())),
" ".to_string(),
),
"css" => LanguageInfo::new(
None,
Some(("/*".to_string(), "*/".to_string())),
" ".to_string(),
),
"scss" => LanguageInfo::new(
Some("//".to_string()),
Some(("/*".to_string(), "*/".to_string())),
" ".to_string(),
),
"ruby" => LanguageInfo::new(
Some("#".to_string()),
Some(("=begin".to_string(), "=end".to_string())),
" ".to_string(),
),
"php" => LanguageInfo::new(
Some("//".to_string()),
Some(("/*".to_string(), "*/".to_string())),
" ".to_string(),
),
"swift" => LanguageInfo::new(
Some("//".to_string()),
Some(("/*".to_string(), "*/".to_string())),
" ".to_string(),
),
"kotlin" => LanguageInfo::new(
Some("//".to_string()),
Some(("/*".to_string(), "*/".to_string())),
" ".to_string(),
),
"shell" | "bash" | "sh" => {
LanguageInfo::new(Some("#".to_string()), None, " ".to_string())
}
"yaml" | "yml" => LanguageInfo::new(Some("#".to_string()), None, " ".to_string()),
"json" => LanguageInfo::new(None, None, " ".to_string()),
"markdown" | "md" => LanguageInfo::new(
None,
Some(("<!--".to_string(), "-->".to_string())),
" ".to_string(),
),
"xml" => LanguageInfo::new(
None,
Some(("<!--".to_string(), "-->".to_string())),
" ".to_string(),
),
"vim" | "viml" => LanguageInfo::new(Some("\"".to_string()), None, " ".to_string()),
_ => LanguageInfo::new(Some("#".to_string()), None, " ".to_string()),
}
}
pub fn get_comment_syntax(file_path: &str) -> &'static str {
let extension = std::path::Path::new(file_path)
.extension()
.and_then(|s| s.to_str())
.unwrap_or("");
let language_id = Self::extension_to_language_id(extension);
match language_id {
"rust" | "javascript" | "typescript" | "go" | "java" | "c" | "cpp" | "swift"
| "kotlin" | "scss" | "php" => "//",
"python" | "shell" | "yaml" => "#",
"html" | "markdown" | "xml" => "<!--",
"css" => "/*",
"vim" => "\"",
_ => "#",
}
}
fn extension_to_language_id(extension: &str) -> &str {
match extension {
"rs" => "rust",
"js" | "mjs" => "javascript",
"ts" | "tsx" => "typescript",
"py" | "pyw" => "python",
"go" => "go",
"java" => "java",
"c" | "h" => "c",
"cpp" | "cc" | "cxx" | "hpp" => "cpp",
"html" | "htm" => "html",
"css" => "css",
"scss" => "scss",
"rb" => "ruby",
"php" => "php",
"swift" => "swift",
"kt" | "kts" => "kotlin",
"sh" | "bash" | "zsh" => "shell",
"yaml" | "yml" => "yaml",
"json" => "json",
"md" | "markdown" => "markdown",
"xml" => "xml",
"vim" => "vim",
_ => "unknown",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn given_rust_language_when_getting_info_then_returns_correct_settings() {
let language_id = "rust";
let language_info = LanguageRegistry::get_language_info(language_id);
assert_eq!(language_info.line_comment, Some("//".to_string()));
assert_eq!(
language_info.block_comment,
Some(("/*".to_string(), "*/".to_string()))
);
assert_eq!(language_info.indent_char, " ");
}
#[test]
fn given_python_language_when_getting_info_then_returns_correct_settings() {
let language_id = "python";
let language_info = LanguageRegistry::get_language_info(language_id);
assert_eq!(language_info.line_comment, Some("#".to_string()));
assert_eq!(
language_info.block_comment,
Some(("\"\"\"".to_string(), "\"\"\"".to_string()))
);
assert_eq!(language_info.indent_char, " ");
}
#[test]
fn given_unknown_language_when_getting_info_then_returns_default_settings() {
let language_id = "unknownlang";
let language_info = LanguageRegistry::get_language_info(language_id);
assert_eq!(language_info.line_comment, Some("#".to_string()));
assert_eq!(language_info.block_comment, None);
assert_eq!(language_info.indent_char, " ");
}
#[test]
fn given_rust_file_when_getting_comment_syntax_then_returns_double_slash() {
let file_path = "test.rs";
let comment_syntax = LanguageRegistry::get_comment_syntax(file_path);
assert_eq!(comment_syntax, "//");
}
#[test]
fn given_python_file_when_getting_comment_syntax_then_returns_hash() {
let file_path = "test.py";
let comment_syntax = LanguageRegistry::get_comment_syntax(file_path);
assert_eq!(comment_syntax, "#");
}
}