1use std::{collections::HashMap, sync::LazyLock};
5
6use super::FileType;
7use duat_core::{mode::Cursor, text::RegexHaystack};
8
9pub trait AutoPrefix {
11 fn add_comment(&mut self) -> bool;
19}
20
21impl AutoPrefix for Cursor<'_> {
22 fn add_comment(&mut self) -> bool {
23 let Some(prev_lnum) = self.caret().line().checked_sub(1) else {
24 return false;
25 };
26
27 if let Some(filetype) = self.filetype()
28 && let Some(prefixes) = PREFIXES.get(filetype)
29 {
30 let line = self.text().line(prev_lnum);
31 for prefix in prefixes.iter() {
32 if let Some(range) = line.search(prefix.from).next()
33 && prefix.blocker.is_none_or(|blocker| {
34 line.search(blocker)
35 .next()
36 .is_none_or(|blocker_range| blocker_range.end <= range.start)
37 })
38 {
39 self.insert(prefix.set);
40 self.move_hor(prefix.set.chars().count() as i32);
41
42 return true;
43 }
44 }
45 }
46
47 false
48 }
49}
50
51struct Prefix {
52 from: &'static str,
53 set: &'static str,
54 blocker: Option<&'static str>,
55}
56
57const fn pf(from: &'static str, set: &'static str, blocker: Option<&'static str>) -> Prefix {
58 Prefix { from, set, blocker }
59}
60
61static PREFIXES: LazyLock<HashMap<&str, &[Prefix]>> = LazyLock::new(|| {
63 const HASH: Prefix = pf(r"^\s*#", "#", None);
64 const DOUBLE_HASH: &[Prefix] = &[pf(r"^\s*##", "##", None)];
65
66 const SLASHES: Prefix = pf(r"^\s*//", "//", None);
67 const DOC_SLASHES: Prefix = pf(r"^\s*///", "///", None);
68 const INNER_DOC_SLASHES: Prefix = pf(r"^\s*//!", "//!", None);
69 const ASTERISK: Prefix = pf(r"^\s*\*", " *", Some(r#"\*/"#));
70 const SLASH_ASTERISK: Prefix = pf(r"^\s*/\*", " *", Some(r#"\*/"#));
71 const SLASH_ASTERISK_LINE: &[Prefix] = &[pf(r"^\s*/\*", "/*", None)];
72
73 const QUOTE: Prefix = pf(r"^\s*'", "'", None);
74 const DQUOTE: Prefix = pf(r#"^\s*""#, r#"""#, None);
75 const SEMICOLON: Prefix = pf(r"^\s;", ";", None);
76 const PERCENT: Prefix = pf(r"^\s*%", "%", None);
77 const EXCLAMATION: Prefix = pf(r"^\s*!", "!", None);
78 const DOLLAR_SIGN: Prefix = pf(r"^\s*$", "$", None);
79 const SLASH: Prefix = pf(r"^\s*/", "/", None);
80
81 const DASHES: Prefix = pf(r"^\s*--", "--", None);
82 const REM: Prefix = pf("^REM", "REM", None);
83 const DOT_ESCAPED_DQUOTE: &[Prefix] = &[pf(r#"^\s\.\\""#, r#".\""#, None)];
84 const DOUBLE_COLON: Prefix = pf(r"^\s*::", "::", None);
85 const ASTERISK_LINE: Prefix = pf(r"^\s*\*", "*", None);
86 const LISP: &[Prefix] = &[
87 const { pf(r"^\s*;;;;", ";;;;", None) },
88 const { pf(r"^\s*;;;", ";;;", None) },
89 const { pf(r"^\s*;;", ";;", None) },
90 SEMICOLON,
91 ];
92
93 HashMap::from_iter([
94 ("aap", &[HASH] as &[Prefix]),
96 ("ampl", &[HASH]),
97 ("ansible", &[HASH]),
98 ("apache", &[HASH]),
99 ("apachestyle", &[HASH]),
100 ("awk", &[HASH]),
101 ("bc", &[HASH]),
102 ("cairo", &[HASH]),
103 ("cfg", &[HASH]),
104 ("cl", &[HASH]),
105 ("cmake", &[HASH]),
106 ("coffeescript", &[HASH]),
107 ("conkyrc", &[HASH]),
108 ("crontab", &[HASH]),
109 ("cucumber", &[HASH]),
110 ("cython", &[HASH]),
111 ("dakota", &[HASH]),
112 ("debcontrol", &[HASH]),
113 ("debsources", &[HASH]),
114 ("desktop", &[HASH]),
115 ("dhcpd", &[HASH]),
116 ("diff", &[HASH]),
117 ("dockerfile", &[HASH]),
118 ("ebuild", &[HASH]),
119 ("ecd", &[HASH]),
120 ("eclass", &[HASH]),
121 ("elixir", &[HASH]),
122 ("elmfilt", &[HASH]),
123 ("ember-script", &[HASH]),
124 ("esmtprc", &[HASH]),
125 ("exim", &[HASH]),
126 ("expect", &[HASH]),
127 ("exports", &[HASH]),
128 ("fancy", &[HASH]),
129 ("fgl", &[HASH]),
130 ("fluent", &[HASH]),
131 ("fstab", &[HASH]),
132 ("fvwm", &[HASH]),
133 ("gdb", &[HASH]),
134 ("gdscript3", &[HASH]),
135 ("gentoo-conf-d", &[HASH]),
136 ("gentoo-env-d", &[HASH]),
137 ("gentoo-init-d", &[HASH]),
138 ("gentoo-make-conf", &[HASH]),
139 ("gentoo-package-keywords", &[HASH]),
140 ("gentoo-package-mask", &[HASH]),
141 ("gentoo-package-use", &[HASH]),
142 ("gitcommit", &[HASH]),
143 ("gitignore", &[HASH]),
144 ("gitrebase", &[HASH]),
145 ("gnuplot", &[HASH]),
146 ("gtkrc", &[HASH]),
147 ("hb", &[HASH]),
148 ("hog", &[HASH]),
149 ("hostsaccess", &[HASH]),
150 ("hxml", &[HASH]),
151 ("ia64", &[HASH]),
152 ("icon", &[HASH]),
153 ("inittab", &[HASH]),
154 ("jproperties", &[HASH]),
155 ("julia", &[HASH]),
156 ("kivy", &[HASH]),
157 ("ldif", &[HASH]),
158 ("lilo", &[HASH]),
159 ("lout", &[HASH]),
160 ("lss", &[HASH]),
161 ("lynx", &[HASH]),
162 ("mako", DOUBLE_HASH),
163 ("maple", &[HASH]),
164 ("meson", &[HASH]),
165 ("mips", &[HASH]),
166 ("mirah", &[HASH]),
167 ("mush", &[HASH]),
168 ("nginx", &[HASH]),
169 ("nimrod", &[HASH]),
170 ("nix", &[HASH]),
171 ("nsis", &[HASH]),
172 ("ntp", &[HASH]),
173 ("ora", &[HASH]),
174 ("paludis-use-conf", &[HASH]),
175 ("pcap", &[HASH]),
176 ("perl", &[HASH]),
177 ("pine", &[HASH]),
178 ("po", &[HASH]),
179 ("praat", &[HASH]),
180 ("privoxy", &[HASH]),
181 ("ps1", &[HASH]),
182 ("psf", &[HASH]),
183 ("ptcap", &[HASH]),
184 ("puppet", &[HASH]),
185 ("pyrex", &[HASH]),
186 ("python", &[HASH]),
187 ("radiance", &[HASH]),
188 ("ratpoison", &[HASH]),
189 ("rego", &[HASH]),
190 ("remind", &[HASH]),
191 ("resolv", &[HASH]),
192 ("rib", &[HASH]),
193 ("robot", &[HASH]),
194 ("robots", &[HASH]),
195 ("rspec", &[HASH]),
196 ("ruby", &[HASH]),
197 ("scons", &[HASH]),
198 ("sdc", &[HASH]),
199 ("sed", &[HASH]),
200 ("sh", &[HASH]),
201 ("shader_test", &[HASH]),
202 ("sls", &[HASH]),
203 ("sm", &[HASH]),
204 ("snakemake", &[HASH]),
205 ("snippets", &[HASH]),
206 ("snnsnet", &[HASH]),
207 ("snnspat", &[HASH]),
208 ("snnsres", &[HASH]),
209 ("spec", &[HASH]),
210 ("squid", &[HASH]),
211 ("sshconfig", &[HASH]),
212 ("sshdconfig", &[HASH]),
213 ("tcl", &[HASH]),
214 ("tf", &[HASH]),
215 ("tidy", &[HASH]),
216 ("tli", &[HASH]),
217 ("tmux", &[HASH]),
218 ("toml", &[HASH]),
219 ("tsscl", &[HASH]),
220 ("ttl", &[HASH]),
221 ("tup", &[HASH]),
222 ("upstart", &[HASH]),
223 ("vgrindefs", &[HASH]),
224 ("vrml", &[HASH]),
225 ("wget", &[HASH]),
226 ("wml", &[HASH]),
227 ("xmath", &[HASH]),
228 ("yaml", &[HASH]),
229 ("r", &[HASH]),
230 ("renpy", &[HASH]),
231 ("htmlcheetah", DOUBLE_HASH),
232 ("velocity", DOUBLE_HASH),
233 ("webmacro", DOUBLE_HASH),
234 ("groff", const { &[pf(r"^\s*\#", r"\#", None)] }),
236 ("acedb", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
237 ("actionscript", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
238 ("asy", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
239 ("bind-named", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
240 ("cg", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
241 ("ch", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
242 ("clean", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
243 ("clipper", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
244 ("cs", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
245 ("cuda", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
246 ("d", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
247 ("dot", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
248 ("dylan", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
249 ("fx", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
250 ("glsl", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
251 ("go", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
252 ("groovy", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
253 ("h", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
254 ("haxe", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
255 ("hercules", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
256 ("hyphy", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
257 ("idl", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
258 ("ishd", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
259 ("java", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
260 ("javacc", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
261 ("javascript", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
262 ("javascript.jquery", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
263 ("json5", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
264 ("jsonc", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
265 ("jsonnet", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
266 ("kscript", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
267 ("lpc", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
268 ("mel", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
269 ("named", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
270 ("objc", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
271 ("objcpp", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
272 ("objj", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
273 ("ooc", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
274 ("pccts", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
275 ("php", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
276 ("pike", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
277 ("pilrc", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
278 ("plm", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
279 ("pov", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
280 ("processing", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
281 ("proto", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
282 ("rc", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
283 ("scala", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
284 ("scss", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
285 ("slice", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
286 ("stan", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
287 ("stp", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
288 ("supercollider", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
289 ("swift", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
290 ("systemverilog", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
291 ("tads", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
292 ("teak", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
293 ("tsalt", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
294 ("typescript", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
295 ("uc", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
296 ("vala", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
297 ("vera", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
298 ("verilog", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
299 (
300 "verilog_systemverilog",
301 &[SLASH_ASTERISK, ASTERISK, SLASHES],
302 ),
303 ("sass", &[SLASH_ASTERISK, ASTERISK, SLASHES]),
304 ("asciidoc", &[SLASHES]),
305 ("ats", &[SLASHES]),
306 ("bib", &[SLASHES]),
307 ("calibre", &[SLASHES]),
308 ("cocci", &[SLASHES]),
309 ("cypher", &[SLASHES]),
310 ("faust", &[SLASHES]),
311 ("fsharp", &[SLASHES]),
312 ("openroad", &[SLASHES]),
313 ("ox", &[SLASHES]),
314 ("pfmain", &[SLASHES]),
315 ("scilab", &[SLASHES]),
316 ("specman", &[SLASHES]),
317 ("xkb", &[SLASHES]),
318 ("c", &[SLASH_ASTERISK, ASTERISK, DOC_SLASHES, SLASHES]),
319 ("cpp", &[SLASH_ASTERISK, ASTERISK, DOC_SLASHES, SLASHES]),
320 (
321 "rust",
322 &[
323 SLASH_ASTERISK,
324 ASTERISK,
325 DOC_SLASHES,
326 INNER_DOC_SLASHES,
327 SLASHES,
328 ],
329 ),
330 ("zig", &[DOC_SLASHES, INNER_DOC_SLASHES, SLASHES]),
331 ("spectre", &[SLASHES, const { pf(r"^\s*\*", "*", None) }]),
332 ("emblem", &[const { pf(r"^\s*/", "/", None) }]),
333 ("aml", SLASH_ASTERISK_LINE),
334 ("natural", SLASH_ASTERISK_LINE),
335 ("vsejcl", SLASH_ASTERISK_LINE),
336 ("less", &[SLASH_ASTERISK]),
337 ("aspvbs", &[QUOTE]),
339 ("ada", &[DASHES]),
341 ("ahdl", &[DASHES]),
342 ("applescript", &[DASHES]),
343 ("asn", &[DASHES]),
344 ("cabal", &[DASHES]),
345 ("csp", &[DASHES]),
346 ("eiffel", &[DASHES]),
347 ("elm", &[DASHES]),
348 ("gdmo", &[DASHES]),
349 ("haskell", &[DASHES]),
350 ("hive", &[DASHES]),
351 ("idris", &[DASHES]),
352 ("lace", &[DASHES]),
353 ("lean", &[DASHES]),
354 ("lua", &[DASHES]),
355 ("mib", &[DASHES]),
356 ("occam", &[DASHES]),
357 ("sa", &[DASHES]),
358 ("sather", &[DASHES]),
359 ("sqlforms", &[DASHES]),
360 ("sqlj", &[DASHES]),
361 ("vhdl", &[DASHES]),
362 ("lhaskell", const { &[pf(r"^\s*>--", ">--", None)] }),
363 ("amiga", &[SEMICOLON]),
365 ("armasm", &[SEMICOLON]),
366 ("asm68k", &[SEMICOLON]),
367 ("autohotkey", &[SEMICOLON]),
368 ("asterisk", &[SEMICOLON]),
369 ("autoit", &[SEMICOLON]),
370 ("bindzone", &[SEMICOLON]),
371 ("clojure", &[SEMICOLON]),
372 ("def", &[SEMICOLON]),
373 ("dns", &[SEMICOLON]),
374 ("dosini", &[SEMICOLON]),
375 ("dracula", &[SEMICOLON]),
376 ("dsl", &[SEMICOLON]),
377 ("fasm", &[SEMICOLON]),
378 ("gitconfig", &[SEMICOLON]),
379 ("idlang", &[SEMICOLON]),
380 ("iss", &[SEMICOLON]),
381 ("jess", &[SEMICOLON]),
382 ("kix", &[SEMICOLON]),
383 ("llvm", &[SEMICOLON]),
384 ("masm", &[SEMICOLON]),
385 ("monk", &[SEMICOLON]),
386 ("nagios", &[SEMICOLON]),
387 ("nasm", &[SEMICOLON]),
388 ("ncf", &[SEMICOLON]),
389 ("newlisp", &[SEMICOLON]),
390 ("omnimark", &[SEMICOLON]),
391 ("pic", &[SEMICOLON]),
392 ("povini", &[SEMICOLON]),
393 ("racket", &[SEMICOLON]),
394 ("rebol", &[SEMICOLON]),
395 ("registry", &[SEMICOLON]),
396 ("scsh", &[SEMICOLON]),
397 ("skill", &[SEMICOLON]),
398 ("smith", &[SEMICOLON]),
399 ("ss", &[SEMICOLON]),
400 ("tags", &[SEMICOLON]),
401 ("tasm", &[SEMICOLON]),
402 ("winbatch", &[SEMICOLON]),
403 ("wvdial", &[SEMICOLON]),
404 ("z8a", &[SEMICOLON]),
405 ("ppwiz", &[SEMICOLON]),
406 ("asm", &[SEMICOLON, HASH]),
407 ("samba", &[SEMICOLON, HASH]),
408 ("ledger", &[SEMICOLON, HASH]),
409 ("closure", LISP),
410 ("fennel", LISP),
411 ("lisp", LISP),
412 ("m17ndb", LISP),
413 ("scheme", LISP),
414 ("basic", &[QUOTE, REM]),
416 ("simula", &[PERCENT]),
417 ("cvs", const { &[pf("^CVS:", "^CVS:", None)] }),
418 ("dosbatch", &[REM, DOUBLE_COLON]),
419 ("m4", const { &[pf(r"^\s*dnl", "dnl", None)] }),
420 ("opl", &[REM]),
421 (
422 "texinfo",
423 const {
424 &[
425 pf(r"^\s*@comment", "@comment", None),
426 pf(r"^\s*@c", "@c", None),
427 ]
428 },
429 ),
430 ("abc", &[PERCENT]),
432 ("asp", &[PERCENT]),
433 ("bbx", &[PERCENT]),
434 ("bst", &[PERCENT]),
435 ("ist", &[PERCENT]),
436 ("lilypond", &[PERCENT]),
437 ("lprolog", &[PERCENT]),
438 ("lytex", &[PERCENT]),
439 ("map", &[PERCENT]),
440 ("matlab", &[PERCENT]),
441 ("pdf", &[PERCENT]),
442 ("postscr", &[PERCENT]),
443 ("ppd", &[PERCENT]),
444 ("slang", &[PERCENT]),
445 ("slrnrc", &[PERCENT]),
446 ("tex", &[PERCENT]),
447 ("texmf", &[PERCENT]),
448 ("txt2tags", &[PERCENT]),
449 ("virata", &[PERCENT]),
450 ("sile", &[PERCENT]),
451 ("erlang", &[PERCENT]),
452 ("ave", &[QUOTE]),
454 ("elf", &[QUOTE]),
455 ("lscript", &[QUOTE]),
456 ("spin", &[QUOTE]),
457 ("vb", &[QUOTE]),
458 ("man", const { &[pf(r#"^\s\.""#, r#".""#, None)] }),
459 ("mandoc", DOT_ESCAPED_DQUOTE),
460 ("troff", DOT_ESCAPED_DQUOTE),
461 ("nroff", &[DQUOTE]),
462 ("st", &[DQUOTE]),
463 ("vim", &[DQUOTE]),
464 ("apdl", &[EXCLAMATION]),
466 ("fortran", &[EXCLAMATION]),
467 ("incar", &[EXCLAMATION]),
468 ("inform", &[EXCLAMATION]),
469 ("molpro", &[EXCLAMATION]),
470 ("poscar", &[EXCLAMATION]),
471 ("rgb", &[EXCLAMATION]),
472 ("sqr", &[EXCLAMATION]),
473 ("uc4", &[EXCLAMATION]),
474 ("uil", &[EXCLAMATION]),
475 ("vasp", &[EXCLAMATION]),
476 ("xdefaults", &[EXCLAMATION]),
477 ("xpm2", &[EXCLAMATION]),
478 (
479 "factor",
480 &[EXCLAMATION, const { pf(r"^\s*!#", "!#", None) }],
481 ),
482 ("master", &[DOLLAR_SIGN]),
484 ("nastran", &[DOLLAR_SIGN]),
485 ("patran", &[DOLLAR_SIGN]),
486 ("sinda", &[DOLLAR_SIGN]),
487 ("spice", &[DOLLAR_SIGN]),
488 ("tak", &[DOLLAR_SIGN]),
489 ("trasys", &[DOLLAR_SIGN]),
490 ("dcl", const { &[pf(r"^\s*$!", "$!", None)] }),
491 ("hocon", &[SLASHES, HASH]),
493 ("octave", &[PERCENT, HASH]),
494 ("plsql", &[DASHES]),
495 ("sql", &[DASHES]),
496 ("prolog", &[PERCENT]),
497 ("minizinc", &[PERCENT]),
498 ("sentinel", &[HASH]),
499 ("terraform", &[HASH]),
500 ("btm", &[DOUBLE_COLON]),
502 ("caos", &[ASTERISK_LINE]),
503 ("cterm", &[ASTERISK_LINE]),
504 ("form", &[ASTERISK_LINE]),
505 ("foxpro", &[ASTERISK_LINE]),
506 ("gams", &[ASTERISK_LINE]),
507 ("sicad", &[ASTERISK_LINE]),
508 ("snobol4", &[ASTERISK_LINE]),
509 ("focexec", const { &[pf(r"^\s*-\*", "-*", None)] }),
510 ("haml", &[const { pf(r"^\s*-#", "-#", None) }, SLASH]),
511 ("haml", &[SLASH, const { pf(r"^\s*/!", "/!", None) }]),
512 ])
513});