GitHub Diff Filename

A userscript that highlights filename & permission alterations

目前为 2022-02-28 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name GitHub Diff Filename
  3. // @version 1.1.5
  4. // @description A userscript that highlights filename & permission alterations
  5. // @license MIT
  6. // @author Rob Garrison
  7. // @namespace https://github.com/Mottie
  8. // @include https://github.com/*
  9. // @run-at document-end
  10. // @grant GM_getValue
  11. // @grant GM_setValue
  12. // @require https://greasyfork.org/scripts/28721-mutations/code/mutations.js?version=952601
  13. // @require https://greasyfork.org/scripts/398877-utils-js/code/utilsjs.js?version=952600
  14. // @icon https://github.githubassets.com/pinned-octocat.svg
  15. // @supportURL https://github.com/Mottie/GitHub-userscripts/issues
  16. // ==/UserScript==
  17. /* global $ $$ on */
  18. (() => {
  19. "use strict";
  20.  
  21. const arrow = "\u2192"; // "→"
  22. const regex = new RegExp(`\\s${arrow}\\s`);
  23.  
  24. function processFileInfo(el) {
  25. if (!$(".ghdfn", el)) {
  26. // A file can be moved AND include permission changes
  27. // e.g. main.js → scripts/main.js 100755 → 100644
  28. // see https://github.com/openstyles/stylus/pull/110/files#diff-5186ece9a52b5e8b0d2e221fdf139ae963ae774267b2f52653c7e45e2a0bda52
  29.  
  30. const link = $("a[title]", el);
  31. // file name/location changes are inside the link
  32. if (link && regex.test(link.textContent)) {
  33. modifyLinkText(link);
  34. }
  35. // permission changes in a text node as a direct child of the wrapper
  36. // process permission change (if it exists)
  37. const node = findTextNode(el)[0];
  38. processNode(node);
  39. }
  40. }
  41.  
  42. function modifyLinkText(link) {
  43. if (link) {
  44. const [oldFile, newFile] = (link.title || "").split(regex);
  45. link.innerHTML = `
  46. <span class="ghdfn color-fg-danger">${oldFile}</span> ${arrow}
  47. <span class="ghdfn color-fg-success">${newFile}</span>`;
  48. }
  49. }
  50.  
  51. function processNode(node) {
  52. if (node) {
  53. let txt = node.textContent,
  54. // modify right node first to maintain node text indexing
  55. middle = txt.indexOf(arrow);
  56. if (middle > -1) {
  57. wrapParts({
  58. start: middle + 2,
  59. end: txt.length,
  60. name: "ghdfn color-fg-success",
  61. node
  62. });
  63. }
  64. middle = node.textContent.indexOf(arrow);
  65. if (middle > -1) {
  66. wrapParts({
  67. start: 0,
  68. end: middle - 1,
  69. name: "ghdfn color-fg-danger",
  70. node
  71. });
  72. }
  73. }
  74. }
  75.  
  76. function findTextNode(el) {
  77. return [...el.childNodes].filter(
  78. node => regex.test(node.textContent) && node.nodeType === 3
  79. );
  80. }
  81.  
  82. function wrapParts(data) {
  83. let newNode, tmpNode;
  84. const {start, end, name, node} = data;
  85. if (node && node.nodeType === 3) {
  86. tmpNode = node.splitText(start);
  87. tmpNode.splitText(end - start);
  88. newNode = document.createElement("span");
  89. newNode.className = name;
  90. newNode.textContent = tmpNode.textContent;
  91. tmpNode.parentNode.replaceChild(newNode, tmpNode);
  92. }
  93. }
  94.  
  95. function init() {
  96. if ($("#files")) {
  97. $$("#files .file-info").forEach(processFileInfo);
  98. }
  99. }
  100.  
  101. on(document, "ghmo:container ghmo:diff", init);
  102. init();
  103.  
  104. })();