Tucker McKnight <tmcknight@instructure.com> | Sun Aug 02 2026
[WIP] implement some functionality for commit language graph Adds "added" and "removed" fields to a commit, which has the number of lines added and deleted in that commit hunk. This is different from the length of the beforeText and afterText fields, since those have newlines added to them to balance them out in the side-by-side view. So the beforeText and afterText always have the same number of lines in them. added and removed says what the original diff sizes were. This is still a WIP and I need to figure out how to have shared language colors between this and the repo home graph, as well as implement the "other" length. And also do something for the average size of a commit -- a moving standard deviation?
17 18 19 20 21
lineNumber: number,
beforeText: string,
afterText: string,
}>
}
17 18 19 20 21 22 23
lineNumber: number,
beforeText: string,
afterText: string,
added: number,
removed: number,
}>
}
50 51 52 53 54 55 56 57 58 59
if (str.startsWith(' ')) { return str.replace(" ", "") }
}).join("\n")
const changeObject = (lastHunkBefore.length > 1000 || lastHunkAfter.length > 1000)
? []
: Diff.diffWordsWithSpace(lastHunkBefore, lastHunkAfter)
let beforeText = ""
let afterText = ""
changeObject.forEach((obj) => {
const numNewLines = obj.value.split('').filter(char => char === '\n').length50 51 52 53 54 55 56 57 58 59 60 61 62
if (str.startsWith(' ')) { return str.replace(" ", "") }
}).join("\n")
// TODO: don't split on \n again here, do this earlier? More efficiently?
const changeObject = (lastHunkBefore.split('\n').length > 1000 || lastHunkAfter.split('\n').length > 1000)
? []
: Diff.diffWordsWithSpace(lastHunkBefore, lastHunkAfter)
let beforeText = ""
let afterText = ""
let added = 0
let removed = 0
changeObject.forEach((obj) => {
const numNewLines = obj.value.split('').filter(char => char === '\n').length62 63 64 65 66 67 68 69
if (!obj.added && !obj.removed) {
beforeText = beforeText + escape(obj.value)
afterText = afterText + escape(obj.value)
}
if (obj.added) {
afterText = afterText + "<mark>" + escape(obj.value) + "</mark>"
if (numNewLines > 0) {
let insertAt = beforeText.lastIndexOf("\n")
insertAt = insertAt === -1 ? 0 : insertAt62 63 64 65 66 67 68 69 70 71 72
if (!obj.added && !obj.removed) {
beforeText = beforeText + escape(obj.value)
afterText = afterText + escape(obj.value)
added += obj.value.split('\n').length
removed += obj.value.split('\n').length
}
if (obj.added) {
afterText = afterText + "<mark>" + escape(obj.value) + "</mark>"
added += obj.value.split('\n').length
if (numNewLines > 0) {
let insertAt = beforeText.lastIndexOf("\n")
insertAt = insertAt === -1 ? 0 : insertAt74 75 76 77 78
}
if (obj.removed) {
beforeText = beforeText + "<mark>" + escape(obj.value) + "</mark>"
if (numNewLines > 0) {
let insertAt = afterText.lastIndexOf("\n")
insertAt = insertAt === -1 ? 0 : insertAt74 75 76 77 78 79
}
if (obj.removed) {
beforeText = beforeText + "<mark>" + escape(obj.value) + "</mark>"
removed += obj.value.split('\n').length
if (numNewLines > 0) {
let insertAt = afterText.lastIndexOf("\n")
insertAt = insertAt === -1 ? 0 : insertAt88 89 90 91 92
lineNumber: parseInt(lines[previousHunk].match(lineNumberRegex)[1]),
beforeText,
afterText,
})
previousFilename = ''
previousHunk = index88 89 90 91 92 93 94
lineNumber: parseInt(lines[previousHunk].match(lineNumberRegex)[1]),
beforeText,
afterText,
added,
removed,
})
previousFilename = ''
previousHunk = index