mirror of
https://github.com/atom/atom.git
synced 2026-01-25 06:48:28 -05:00
164 lines
5.3 KiB
JavaScript
164 lines
5.3 KiB
JavaScript
const {CompositeDisposable} = require('atom')
|
|
const {repositoryForPath} = require('./helpers')
|
|
|
|
const MAX_BUFFER_LENGTH_TO_DIFF = 2 * 1024 * 1024
|
|
|
|
module.exports =
|
|
class GitDiffView {
|
|
constructor (editor) {
|
|
this.updateDiffs = this.updateDiffs.bind(this)
|
|
this.editor = editor
|
|
this.subscriptions = new CompositeDisposable()
|
|
this.decorations = {}
|
|
this.markers = []
|
|
}
|
|
|
|
start () {
|
|
const editorElement = this.editor.getElement()
|
|
|
|
this.subscribeToRepository()
|
|
|
|
this.subscriptions.add(
|
|
this.editor.onDidStopChanging(this.updateDiffs),
|
|
this.editor.onDidChangePath(this.updateDiffs),
|
|
atom.project.onDidChangePaths(() => this.subscribeToRepository()),
|
|
atom.commands.add(editorElement, 'git-diff:move-to-next-diff', () => this.moveToNextDiff()),
|
|
atom.commands.add(editorElement, 'git-diff:move-to-previous-diff', () => this.moveToPreviousDiff()),
|
|
atom.config.onDidChange('git-diff.showIconsInEditorGutter', () => this.updateIconDecoration()),
|
|
atom.config.onDidChange('editor.showLineNumbers', () => this.updateIconDecoration()),
|
|
editorElement.onDidAttach(() => this.updateIconDecoration()),
|
|
this.editor.onDidDestroy(() => {
|
|
this.cancelUpdate()
|
|
this.removeDecorations()
|
|
this.subscriptions.dispose()
|
|
})
|
|
)
|
|
|
|
this.updateIconDecoration()
|
|
this.scheduleUpdate()
|
|
}
|
|
|
|
moveToNextDiff () {
|
|
const cursorLineNumber = this.editor.getCursorBufferPosition().row + 1
|
|
let nextDiffLineNumber = null
|
|
let firstDiffLineNumber = null
|
|
if (this.diffs) {
|
|
for (const {newStart} of this.diffs) {
|
|
if (newStart > cursorLineNumber) {
|
|
if (nextDiffLineNumber == null) nextDiffLineNumber = newStart - 1
|
|
nextDiffLineNumber = Math.min(newStart - 1, nextDiffLineNumber)
|
|
}
|
|
|
|
if (firstDiffLineNumber == null) firstDiffLineNumber = newStart - 1
|
|
firstDiffLineNumber = Math.min(newStart - 1, firstDiffLineNumber)
|
|
}
|
|
}
|
|
|
|
// Wrap around to the first diff in the file
|
|
if (atom.config.get('git-diff.wrapAroundOnMoveToDiff') && nextDiffLineNumber == null) {
|
|
nextDiffLineNumber = firstDiffLineNumber
|
|
}
|
|
|
|
this.moveToLineNumber(nextDiffLineNumber)
|
|
}
|
|
|
|
updateIconDecoration () {
|
|
const gutter = this.editor.getElement().querySelector('.gutter')
|
|
if (gutter) {
|
|
if (atom.config.get('editor.showLineNumbers') && atom.config.get('git-diff.showIconsInEditorGutter')) {
|
|
gutter.classList.add('git-diff-icon')
|
|
} else {
|
|
gutter.classList.remove('git-diff-icon')
|
|
}
|
|
}
|
|
}
|
|
|
|
moveToPreviousDiff () {
|
|
const cursorLineNumber = this.editor.getCursorBufferPosition().row + 1
|
|
let previousDiffLineNumber = -1
|
|
let lastDiffLineNumber = -1
|
|
if (this.diffs) {
|
|
for (const {newStart} of this.diffs) {
|
|
if (newStart < cursorLineNumber) {
|
|
previousDiffLineNumber = Math.max(newStart - 1, previousDiffLineNumber)
|
|
}
|
|
lastDiffLineNumber = Math.max(newStart - 1, lastDiffLineNumber)
|
|
}
|
|
}
|
|
|
|
// Wrap around to the last diff in the file
|
|
if (atom.config.get('git-diff.wrapAroundOnMoveToDiff') && previousDiffLineNumber === -1) {
|
|
previousDiffLineNumber = lastDiffLineNumber
|
|
}
|
|
|
|
this.moveToLineNumber(previousDiffLineNumber)
|
|
}
|
|
|
|
moveToLineNumber (lineNumber) {
|
|
if (lineNumber != null && lineNumber >= 0) {
|
|
this.editor.setCursorBufferPosition([lineNumber, 0])
|
|
this.editor.moveToFirstCharacterOfLine()
|
|
}
|
|
}
|
|
|
|
subscribeToRepository () {
|
|
this.repository = repositoryForPath(this.editor.getPath())
|
|
if (this.repository) {
|
|
this.subscriptions.add(this.repository.onDidChangeStatuses(() => {
|
|
this.scheduleUpdate()
|
|
}))
|
|
this.subscriptions.add(this.repository.onDidChangeStatus(changedPath => {
|
|
if (changedPath === this.editor.getPath()) this.scheduleUpdate()
|
|
}))
|
|
}
|
|
}
|
|
|
|
cancelUpdate () {
|
|
clearImmediate(this.immediateId)
|
|
}
|
|
|
|
scheduleUpdate () {
|
|
this.cancelUpdate()
|
|
this.immediateId = setImmediate(this.updateDiffs)
|
|
}
|
|
|
|
updateDiffs () {
|
|
if (this.editor.isDestroyed()) return
|
|
this.removeDecorations()
|
|
const path = this.editor && this.editor.getPath()
|
|
if (path && this.editor.getBuffer().getLength() < MAX_BUFFER_LENGTH_TO_DIFF) {
|
|
this.diffs = this.repository && this.repository.getLineDiffs(path, this.editor.getText())
|
|
if (this.diffs) this.addDecorations(this.diffs)
|
|
}
|
|
}
|
|
|
|
addDecorations (diffs) {
|
|
for (const {newStart, oldLines, newLines} of diffs) {
|
|
const startRow = newStart - 1
|
|
const endRow = (newStart + newLines) - 1
|
|
if (oldLines === 0 && newLines > 0) {
|
|
this.markRange(startRow, endRow, 'git-line-added')
|
|
} else if (newLines === 0 && oldLines > 0) {
|
|
if (startRow < 0) {
|
|
this.markRange(0, 0, 'git-previous-line-removed')
|
|
} else {
|
|
this.markRange(startRow, startRow, 'git-line-removed')
|
|
}
|
|
} else {
|
|
this.markRange(startRow, endRow, 'git-line-modified')
|
|
}
|
|
}
|
|
}
|
|
|
|
removeDecorations () {
|
|
for (let marker of this.markers) marker.destroy()
|
|
this.markers = []
|
|
}
|
|
|
|
markRange (startRow, endRow, klass) {
|
|
const marker = this.editor.markBufferRange([[startRow, 0], [endRow, 0]], {invalidate: 'never'})
|
|
this.editor.decorateMarker(marker, {type: 'line-number', class: klass})
|
|
this.markers.push(marker)
|
|
}
|
|
}
|