GitHub Code Guides

A userscript that allows you to add one or more vertical guidelines to the code

目前为 2023-07-01 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name GitHub Code Guides
  3. // @version 1.1.14
  4. // @description A userscript that allows you to add one or more vertical guidelines to the code
  5. // @license MIT
  6. // @author Rob Garrison
  7. // @namespace https://github.com/Mottie
  8. // @match https://github.com/*
  9. // @run-at document-idle
  10. // @grant GM_getValue
  11. // @grant GM_setValue
  12. // @grant GM_registerMenuCommand
  13. // @icon https://github.githubassets.com/pinned-octocat.svg
  14. // @supportURL https://github.com/Mottie/GitHub-userscripts/issues
  15. // ==/UserScript==
  16. /* copy into textarea to check the guides
  17. 1 2 3 4 5 6 7 8
  18. 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345
  19. */
  20. (() => {
  21. "use strict";
  22. const style = document.createElement("style");
  23. // eslint-disable-next-line one-var
  24. let guides = GM_getValue("ghcg-guides", [{
  25. chars: 80,
  26. color: "rgba(0, 0, 0, .3)",
  27. width: 0.2
  28. }]),
  29. font = GM_getValue("ghcg-font", "Menlo"),
  30. tabSize = GM_getValue("ghcg-tabs", 2);
  31.  
  32. function adjust(val) {
  33. return `${val.toFixed(1)}ch`;
  34. }
  35.  
  36. function addDefinition(start, end, color) {
  37. return `
  38. transparent ${start},
  39. ${color} ${start},
  40. ${color} ${end},
  41. transparent ${end},
  42. `;
  43. }
  44.  
  45. function addGuides(vals) {
  46. let css = "";
  47. // to align the guides *after* the setting, we need to subtract 0.5, then
  48. // add another 0.1 to give the guide a tiny bit of white space to the left
  49. vals.forEach(guide => {
  50. let start = parseFloat(guide.chars) - 0.5,
  51. size = parseFloat(guide.width) || 0.2;
  52. const color = guide.color || "rgba(0, 0, 0, .3)";
  53. // each line needs to be at least 0.2ch in width to be visible
  54. size = size > 0.2 ? size : 0.2;
  55. css += addDefinition(adjust(start), adjust(start + size), color);
  56. });
  57. style.textContent = `
  58. table.tab-size[data-tab-size] {
  59. tab-size: ${tabSize};
  60. -moz-tab-size: ${tabSize};
  61. }
  62. span.blob-code-inner:before,
  63. td.blob-code-inner:not(.blob-code-hunk):before,
  64. .blob-code-context .blob-code-inner:before,
  65. .blob-code-addition .blob-code-inner:before,
  66. .blob-code-deletion .blob-code-inner:before {
  67. display: block;
  68. position: absolute;
  69. top: 0;
  70. left: 1em;
  71. width: 100%;
  72. height: 100%;
  73. text-indent: -1em;
  74. }
  75. .blob-code span.blob-code-inner {
  76. display: block !important;
  77. }
  78. span.blob-code-inner,
  79. td.blob-code-inner:not(.blob-code-hunk),
  80. .blob-code-inner:before {
  81. font-family: "${font}", Consolas, "Liberation Mono", Menlo, Courier, monospace !important;
  82. }
  83. span.blob-code-inner:before,
  84. td.blob-code-inner:not(.blob-code-hunk):before {
  85. background: linear-gradient(to right, transparent 0%, ${css} transparent 100%) !important;
  86. pointer-events: none;
  87. content: '';
  88. }
  89. `;
  90. }
  91.  
  92. function validateGuides(vals) {
  93. let last = 0;
  94. const valid = [];
  95. if (!Array.isArray(vals)) {
  96. console.log("Code-Guides Userscript: Invalid guidelines", vals);
  97. return;
  98. }
  99. // Object.keys() creates an array of string values
  100. const lines = vals.sort((a, b) => parseFloat(a.chars) - parseFloat(b.chars));
  101. lines.forEach(line => {
  102. const num = parseFloat(line.chars);
  103. // 0.2 is the width of the "ch" in CSS to make it visible
  104. if (num >= last + line.width) {
  105. valid.push(line);
  106. last = num;
  107. }
  108. });
  109. if (valid.length) {
  110. guides = valid;
  111. GM_setValue("ghcg-guides", valid);
  112. GM_setValue("ghcg-font", font);
  113. GM_setValue("ghcg-tabs", tabSize);
  114. addGuides(valid);
  115. }
  116. }
  117.  
  118. document.querySelector("head").appendChild(style);
  119. validateGuides(guides);
  120.  
  121. // Add GM options
  122. GM_registerMenuCommand("Set code guideline position & color", () => {
  123. let val = prompt(
  124. `Enter valid JSON [{ "chars":80, "color":"#f00", "width":0.2 }, ...}]`,
  125. JSON.stringify(guides)
  126. );
  127. if (val !== null) {
  128. try {
  129. val = JSON.parse(val);
  130. validateGuides(val);
  131. } catch (err) {
  132. console.log(err);
  133. }
  134. }
  135. });
  136.  
  137. GM_registerMenuCommand("Set code guideline default font", () => {
  138. const val = prompt("Enter code font (monospaced)", font);
  139. if (val !== null) {
  140. font = val;
  141. validateGuides(guides);
  142. }
  143. });
  144.  
  145. GM_registerMenuCommand("Set code guideline tab size", () => {
  146. const val = prompt("Enter code guideline tab size", tabSize);
  147. if (val !== null) {
  148. tabSize = val;
  149. validateGuides(guides);
  150. }
  151. });
  152.  
  153. })();