1use once_cell::sync::Lazy;
2use regex::Regex;
3
4pub fn detect_language_from_snippet(code: &str) -> Option<&'static str> {
5 let trimmed = code.trim_start();
6 if trimmed.is_empty() {
7 return None;
8 }
9
10 if PYTHON_SIGNATURE.is_match(trimmed) {
11 return Some("python");
12 }
13 if RUST_SIGNATURE.is_match(trimmed) {
14 return Some("rust");
15 }
16 if GO_SIGNATURE.is_match(trimmed) {
17 return Some("go");
18 }
19 if C_SHARP_SIGNATURE.is_match(trimmed) {
20 return Some("csharp");
21 }
22 if CPP_SIGNATURE.is_match(trimmed) {
23 return Some("cpp");
24 }
25 if C_SIGNATURE.is_match(trimmed) {
26 return Some("c");
27 }
28 if JAVA_SIGNATURE.is_match(trimmed) {
29 return Some("java");
30 }
31 if GROOVY_SIGNATURE.is_match(trimmed) {
32 return Some("groovy");
33 }
34 if TYPESCRIPT_SIGNATURE.is_match(trimmed) {
35 return Some("typescript");
36 }
37 if JAVASCRIPT_SIGNATURE.is_match(trimmed) {
38 return Some("javascript");
39 }
40 if RUBY_SIGNATURE.is_match(trimmed) {
41 return Some("ruby");
42 }
43 if KOTLIN_SIGNATURE.is_match(trimmed) {
44 return Some("kotlin");
45 }
46 if PHP_SIGNATURE.is_match(trimmed) {
47 return Some("php");
48 }
49 if LUA_SIGNATURE.is_match(trimmed) {
50 return Some("lua");
51 }
52 if BASH_SIGNATURE.is_match(trimmed) {
53 return Some("bash");
54 }
55 if R_SIGNATURE.is_match(trimmed) {
56 return Some("r");
57 }
58 if DART_SIGNATURE.is_match(trimmed) {
59 return Some("dart");
60 }
61 if SWIFT_SIGNATURE.is_match(trimmed) {
62 return Some("swift");
63 }
64 if PERL_SIGNATURE.is_match(trimmed) {
65 return Some("perl");
66 }
67 if JULIA_SIGNATURE.is_match(trimmed) {
68 return Some("julia");
69 }
70 if HASKELL_SIGNATURE.is_match(trimmed) {
71 return Some("haskell");
72 }
73 if ELIXIR_SIGNATURE.is_match(trimmed) {
74 return Some("elixir");
75 }
76 if CRYSTAL_SIGNATURE.is_match(trimmed) {
77 return Some("crystal");
78 }
79 if ZIG_SIGNATURE.is_match(trimmed) {
80 return Some("zig");
81 }
82 if NIM_SIGNATURE.is_match(trimmed) {
83 return Some("nim");
84 }
85
86 None
87}
88
89static PYTHON_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
90 Regex::new(
91 r"(?m)^(from\s+[\w\.]+\s+import|import\s+[\w\.]+|def\s+[A-Za-z_][\w]*\(|class\s+[A-Za-z_])",
92 )
93 .expect("valid python regex")
94});
95
96static RUST_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
97 Regex::new(r#"(?m)^(fn\s+main\s*\(|use\s+[\w:]+::|#!\[[^\n]+\]|mod\s+[A-Za-z_])"#)
98 .expect("valid rust regex")
99});
100
101static GO_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
102 Regex::new(r#"(?m)^(package\s+main|func\s+main\s*\(|import\s+(?:\w+\s+)?"[^"]+")"#)
103 .expect("valid go regex")
104});
105
106static C_SHARP_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
107 Regex::new(r#"(?m)^(using\s+System|namespace\s+[A-Za-z_][\w\.]*\s*\{|class\s+[A-Za-z_][\w]*\s*\{|\[assembly:)"#)
108 .expect("valid csharp regex")
109});
110
111static C_SIGNATURE: Lazy<Regex> =
112 Lazy::new(|| Regex::new(r#"(?m)^(#include\s+<|int\s+main\s*\()"#).expect("valid c regex"));
113
114static CPP_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
115 Regex::new(r#"(?m)^(?:#include\s+<[^>]+>|using\s+namespace\s+std;|std::|int\s+main\s*\()"#)
116 .expect("valid cpp regex")
117});
118
119static JAVA_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
120 Regex::new(r#"(?m)^(package\s+[\w\.]+;|import\s+java\.|public\s+class\s+|class\s+\w+\s*\{\s*\n\s*public\s+static\s+void\s+main)"#)
121 .expect("valid java regex")
122});
123
124static GROOVY_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
125 Regex::new(
126 r#"(?m)^(?:@Grab|@Grapes|println\s|def\s+\w+\s*=|import\s+groovy\.|class\s+\w+\s*\{|package\s+[\w\.]+)"#,
127 )
128 .expect("valid groovy regex")
129});
130
131static TYPESCRIPT_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
132 Regex::new(r"(?m)^(import\s+\{|type\s+\w+\s*=|interface\s+\w+|class\s+\w+\s+implements)")
133 .expect("valid ts regex")
134});
135
136static JAVASCRIPT_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
137 Regex::new(r#"(?m)^(import\s+(?:\w+\s+from\s+)?["']|console\.log|function\s+\w+\s*\(|module\.exports)"#)
138 .expect("valid js regex")
139});
140
141static RUBY_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
142 Regex::new(r#"(?m)^(require\s+['"]|class\s+\w+|module\s+\w+|puts\s)"#)
143 .expect("valid ruby regex")
144});
145
146static KOTLIN_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
147 Regex::new(r#"(?m)^(package\s+[\w\.]+|import\s+|fun\s+main\s*\(|val\s+\w+\s*=)"#)
148 .expect("valid kotlin regex")
149});
150
151static PHP_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
152 Regex::new(r#"(?m)^(?:<\?php|echo\s+['"]|function\s+\w+\s*\()"#).expect("valid php regex")
153});
154
155static LUA_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
156 Regex::new(r#"(?m)^(local\s+function|function\s+\w+|print\s*\(|--\s)"#)
157 .expect("valid lua regex")
158});
159
160static BASH_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
161 Regex::new(r#"(?m)(^#!\s*/(?:usr/)?bin/(?:env\s+)?(?:bash|sh)|^(?:echo|export|read)\s+|\$\([\w\s]+\))"#)
162 .expect("valid bash regex")
163});
164
165static R_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
166 Regex::new(r"(?m)^(library\(|require\(|print\(|cat\(|[A-Za-z_][\w.]*\s*<-|#[^!]|plot\()")
167 .expect("valid r regex")
168});
169
170static DART_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
171 Regex::new(r"(?m)^(import\s+'dart:|void\s+main\s*\(|class\s+\w+\s*\{|@override)")
172 .expect("valid dart regex")
173});
174
175static SWIFT_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
176 Regex::new(
177 r"(?m)^(import\s+Foundation|func\s+main\s*\(|print\(|class\s+\w+\s*:|struct\s+\w+\s*\{)",
178 )
179 .expect("valid swift regex")
180});
181
182static PERL_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
183 Regex::new(
184 r"(?m)^(?:#!\s*/(?:usr/)?bin/(?:env\s+)?perl|use\s+(?:strict|warnings|feature)\b|my\s+\$|our\s+\$|sub\s+\w|print\s|say\s)"
185 )
186 .expect("valid perl regex")
187});
188
189static JULIA_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
190 Regex::new(
191 r"(?m)^(using\s+|import\s+|function\s+\w|println\(|struct\s+\w|mutable\s+struct\s+\w)",
192 )
193 .expect("valid julia regex")
194});
195
196static HASKELL_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
197 Regex::new(
198 r"(?m)^(module\s+\w+\s+where|import\s+[A-Z][\w\.]*|main\s*::\s*IO\s*\(|main\s*=|data\s+\w+\s*=|type\s+\w+|class\s+\w+|^\s*let\s+\w+\s*=)",
199 )
200 .expect("valid haskell regex")
201});
202
203static ELIXIR_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
204 Regex::new(
205 r"(?m)^(defmodule\s+[A-Z][\w\.]*|defp?\s+\w+\s*\(|IO\.puts|IO\.inspect|alias\s+[A-Z][\w\.]*|use\s+[A-Z][\w\.]*|require\s+[A-Z][\w\.]*)",
206 )
207 .expect("valid elixir regex")
208});
209
210static CRYSTAL_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
211 Regex::new(
212 r"(?m)^(?:@[A-Z][\w]*(?:\([^)]*\))?|struct\s+\w+|enum\s+\w+|record\s+\w+|macro\s+\w+|def\s+\w+\s*(?:\([^)]*\))?\s*:\s*[A-Z])",
213 )
214 .expect("valid crystal regex")
215});
216
217static ZIG_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
218 Regex::new(
219 r#"(?m)^(const\s+\w+\s*=\s*@import\("std"\)|pub\s+fn\s+main\s*\(|fn\s+main\s*\(\)\s*!?void)"#,
220 )
221 .expect("valid zig regex")
222});
223
224static NIM_SIGNATURE: Lazy<Regex> = Lazy::new(|| {
225 Regex::new(
226 r"(?m)^(proc\s+\w+\s*\(|import\s+[\w/]+|echo\s+|let\s+\w+\s*=|var\s+\w+\s*:\s*|template\s+\w+\s*\()",
227 )
228 .expect("valid nim regex")
229});