AtCoder Submission Language Detector

Automatically detects the language used based on the information in the source code comments and selects it as the one to be submitted.

  1. // ==UserScript==
  2. // @name AtCoder Submission Language Detector
  3. // @namespace https://twitter.com/KakurenboUni
  4. // @version 1.1.1
  5. // @description Automatically detects the language used based on the information in the source code comments and selects it as the one to be submitted.
  6. // @author uni-kakurenbo
  7. // @match https://atcoder.jp/contests/*/tasks/*
  8. // @match https://atcoder.jp/contests/*/submit*
  9. // @match https://atcoder.jp/contests/*/custom_test*
  10. // @license MIT
  11. // @supportURL https://twitter.com/KakurenboUni
  12. // ==/UserScript==
  13.  
  14. (async function () {
  15. "use strict";
  16.  
  17. const DETECTION_REG_EXP = /#.*lang(?:uage)?:?(?<args>\s+[^\n\r*/#]+)/;
  18.  
  19. await rendered();
  20.  
  21. const $editor = ace.edit("editor");
  22. const $plainTextarea = $("#plain-textarea");
  23.  
  24. const $selectLanguage = $("#select-lang select");
  25. const $languageOptions = $selectLanguage[0].querySelectorAll("option");
  26. const languageOptions = [].map.call($languageOptions, ({ value, label, dataset: { mime } = {} }) => {
  27. return {
  28. id: value,
  29. label: label.toLowerCase() ?? "",
  30. code: mime?.toLowerCase().replaceAll(/^.+\/x?|src$/g, "") ?? "",
  31. };
  32. });
  33.  
  34. $editor.getSession().on("change", updateLanguageSettings);
  35. $plainTextarea.on("input", updateLanguageSettings);
  36. document.addEventListener("paste", updateLanguageSettings);
  37. $("#input-open-file").on("change", () => { setTimeout(updateLanguageSettings, 0); });
  38.  
  39. function getSourceCode() {
  40. if($editor.isFocused()) return $editor.getValue();
  41. else return $plainTextarea[0].value;
  42. }
  43.  
  44. function updateLanguageSettings() {
  45. const sourceCode = getSourceCode();
  46. console.log(sourceCode);
  47.  
  48. const languageInfomation = sourceCode.match(DETECTION_REG_EXP);
  49. if (!languageInfomation || !languageInfomation?.groups?.args) return;
  50.  
  51. let languageSelectors = languageInfomation.groups.args?.trim().replace(/\s+/g, " ").split(" ");
  52. languageSelectors = languageSelectors.map((selector) => selector.toLowerCase());
  53.  
  54. const selectedOption = languageOptions.find((option) => {
  55. return (
  56. languageSelectors.includes(option.id) ||
  57. languageSelectors.every((selector) => option.label.includes(selector)) ||
  58. languageSelectors.every((selector) => option.code.includes(selector))
  59. );
  60. });
  61.  
  62. if (!selectedOption) return;
  63.  
  64. $selectLanguage.val(selectedOption.id).trigger("change");
  65. }
  66.  
  67. async function rendered() {
  68. let timer;
  69. await new Promise((resolve) => {
  70. observer();
  71. function observer() {
  72. console.log(getLS)
  73. if (typeof getLS == "function") {
  74. resolve();
  75. }
  76. timer = setTimeout(observer, 10);
  77. }
  78. });
  79. clearTimeout(timer);
  80. }
  81. })();