Skip to content
This repository was archived by the owner on Dec 15, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions keymaps/git-experiment.cson
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'atom-workspace':
'cmd-shift-c': 'git:view-and-commit-changes'
'cmd-alt-r': 'git:refresh-status'

'.git-diff-container':
'/': 'git:toggle-selection-mode'
Expand Down
67 changes: 55 additions & 12 deletions lib/diff-hunk.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,61 @@
/** @babel */

import {Emitter, CompositeDisposable} from 'atom'
import HunkLine from './hunk-line'
import EventTransactor from './event-transactor'

import _ from 'underscore-contrib'

// DiffHunk contains diff information for a single hunk within a single file. It
// holds a list of HunkLine objects.
export default class DiffHunk {
constructor(options) {
this.lines = []
this.emitter = new Emitter
this.transactor = new EventTransactor(this.emitter)
this.setLines([])
}

onDidChange(callback) {
return this.emitter.on('did-change', callback)
}

didChange() {
this.transactor.didChange()
}

getHeader() { return this.header }

setHeader(header) {
this.header = header
this.didChange()
}

getLines() { return this.lines }

setLines(lines) {
if (this.lineSubscriptions)
this.lineSubscriptions.dispose()
this.lineSubscriptions = new CompositeDisposable
this.lines = lines

for (const line of lines) {
this.lineSubscriptions.add(line.onDidChange(this.didChange.bind(this)))
}
this.didChange()
}

stage() {
for (let line of this.lines)
line.stage()
this.transactor.transact(() => {
for (let line of this.lines)
line.stage()
})
}

unstage() {
for (let line of this.lines)
line.unstage()
this.transactor.transact(() => {
for (let line of this.lines)
line.unstage()
})
}

// Returns {String} one of 'staged', 'unstaged', 'partial'
Expand Down Expand Up @@ -50,7 +83,7 @@ export default class DiffHunk {
return `HUNK ${this.getHeader()}\n${lines}`
}

static fromString(hunkStr) {
fromString(hunkStr) {
let linesStr = hunkStr.trim().split('\n')
let metadata = /HUNK (.+)/.exec(linesStr[0])
if (!metadata) return null;
Expand All @@ -63,17 +96,22 @@ export default class DiffHunk {
lines.push(line)
}

this.transactor.transact(() => {
this.setHeader(header)
this.setLines(lines)
})
}

static fromString(hunkStr) {
let diffHunk = new DiffHunk()
diffHunk.header = header
diffHunk.lines = lines
diffHunk.fromString(hunkStr)
return diffHunk
}

async fromGitUtilsObject({hunk, stagedLines}) {
if (!hunk) return;

this.header = hunk.header()

let lines = []
for (let line of (await hunk.lines())) {
let hunkLine = new HunkLine()
hunkLine.fromGitUtilsObject({line: line})
Expand All @@ -84,10 +122,15 @@ export default class DiffHunk {
}))
if (staged) {
console.log('staged:')
console.log(hunkLine.getContent())
console.log(hunkLine.toString())
}
hunkLine.setIsStaged(staged)
this.lines.push(hunkLine)
lines.push(hunkLine)
}

this.transactor.transact(() => {
this.setHeader(hunk.header())
this.setLines(lines)
})
}
}
13 changes: 7 additions & 6 deletions lib/diff-view-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import {Emitter, CompositeDisposable} from 'atom'
import DiffSelection from './diff-selection'

export default class DiffViewModel {
constructor({fileDiffs, uri, title}) {
constructor({fileList, uri, title}) {
this.uri = uri
this.fileDiffs = fileDiffs
this.fileList = fileList
this.fileList.onDidChange(this.emitChangeEvent.bind(this))

this.title = title
if (!this.title) {
this.title = fileDiffs[0].getNewPathName()
this.title = this.fileList.getFiles()[0].getNewPathName()
}

// mode is stored here _and_ in the selection. Mouse interactions store
Expand Down Expand Up @@ -154,7 +155,7 @@ export default class DiffViewModel {
let fileEnd = selectionEnd[0]
for (var fileIndex = fileStart; fileIndex <= fileEnd; fileIndex++) {

let file = this.fileDiffs[fileIndex]
let file = this.getFileDiffs()[fileIndex]
let hunkStart = 0
let hunkEnd = file.getHunks().length - 1
if (fileIndex == fileStart) hunkStart = selectionStart[1]
Expand Down Expand Up @@ -192,7 +193,7 @@ export default class DiffViewModel {
for (let fileDiffIndex in this.selectionState) {
let selectedHunkIndices = this.selectionState[fileDiffIndex]
for (let diffHunkIndex in selectedHunkIndices) {
let selectedHunk = this.fileDiffs[fileDiffIndex].getHunks()[diffHunkIndex]
let selectedHunk = this.getFileDiffs()[fileDiffIndex].getHunks()[diffHunkIndex]
let selectedLineIndices = selectedHunkIndices[diffHunkIndex]
if (selectedLineIndices instanceof Set)
this.toggleLinesStageStatus(selectedHunk, selectedLineIndices)
Expand Down Expand Up @@ -234,6 +235,6 @@ export default class DiffViewModel {
}

getFileDiffs() {
return this.fileDiffs
return this.fileList.getFiles()
}
}
41 changes: 41 additions & 0 deletions lib/event-transactor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/** @babel */

// Implements event transactions--roll several events into one!
export default class EventTransactor {
constructor(emitter) {
this.emitter = emitter
this.transactions = []
}

transact(fn) {
this.transactions.push({didChange: false})
fn()
const transaction = this.transactions.pop()
if (transaction && transaction.didChange)
this.recordEvent(transaction.eventName)
}

didChange() {
this.recordEvent('did-change')
}

recordEvent(eventName) {
// TODO: we could roll up all the events at some point if we need to know
// what changed.
const transaction = this.getLastTransaction()
if (transaction) {
transaction.didChange = true
transaction.eventName = eventName // TODO: not ideal, but for now, everything is `did-change`
}
else
this.emitEvent(eventName)
}

emitEvent(eventName) {
this.emitter.emit(eventName)
}

getLastTransaction() {
return this.transactions[this.transactions.length - 1]
}
}
84 changes: 64 additions & 20 deletions lib/file-diff.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,50 @@
import path from 'path'
import DiffHunk from './diff-hunk'
import HunkLine from './hunk-line'
import EventTransactor from './event-transactor'
import {createObjectsFromString} from './common'
import {Emitter, CompositeDisposable} from 'atom'

// FileDiff contains diff information for a single file. It holds a list of
// DiffHunk objects.
export default class FileDiff {
constructor(options) {
this.hunks = []
this.emitter = new Emitter()
this.transactor = new EventTransactor(this.emitter)
this.setHunks([])
this.setOldPathName('unknown')
this.setNewPathName('unknown')
this.setChangeStatus('modified')
}

onDidChange(callback) {
return this.emitter.on('did-change', callback)
}

didChange() {
this.transactor.didChange()
}

getHunks() { return this.hunks }

setHunks(hunks) {
if (this.hunkSubscriptions)
this.hunkSubscriptions.dispose()
this.hunkSubscriptions = new CompositeDisposable
this.hunks = hunks

for (const hunk of hunks)
this.hunkSubscriptions.add(hunk.onDidChange(this.didChange.bind(this)))
this.didChange()
}

getOldFileName() { return path.basename(this.getOldPathName()) }

getOldPathName() { return this.oldPathName }

setOldPathName(oldPathName) {
this.oldPathName = oldPathName
this.didChange()
}

getNewFileName() { return path.basename(this.getNewPathName()) }
Expand All @@ -31,6 +55,7 @@ export default class FileDiff {

setNewPathName(newPathName) {
this.newPathName = newPathName
this.didChange()
}

size() { return this.size }
Expand Down Expand Up @@ -69,16 +94,21 @@ export default class FileDiff {
this.deleted = false
break;
}
this.didChange()
}

stage() {
for (let hunk of this.hunks)
hunk.stage()
this.transactor.transact(() => {
for (let hunk of this.hunks)
hunk.stage()
})
}

unstage() {
for (let hunk of this.hunks)
hunk.unstage()
this.transactor.transact(() => {
for (let hunk of this.hunks)
hunk.unstage()
})
}

getStageStatus() {
Expand Down Expand Up @@ -115,33 +145,31 @@ export default class FileDiff {
return `FILE ${this.getNewPathName()} - ${this.getChangeStatus()} - ${this.getStageStatus()}\n${hunks}`
}

static fromString(diffStr) {
fromString(diffStr) {
let metadata = /FILE (.+) - (.+) - (.+)/.exec(diffStr.trim().split('\n')[0])
if (!metadata) return null;

let [__, pathName, changeStatus, stagedStatus] = metadata
let hunks = createObjectsFromString(diffStr, 'HUNK', DiffHunk)

let fileDiff = new FileDiff()
fileDiff.setNewPathName(pathName)
fileDiff.setOldPathName(pathName)
fileDiff.setChangeStatus(changeStatus)
fileDiff.hunks = hunks
this.transactor.transact(() => {
this.setNewPathName(pathName)
this.setOldPathName(pathName)
this.setChangeStatus(changeStatus)
this.setHunks(hunks)
})
}

static fromString(diffStr) {
let fileDiff = new FileDiff()
fileDiff.fromString(diffStr)
return fileDiff
}

async fromGitUtilsObject({diff, stagedDiff}) {
if (!diff) return;

this.oldPathName = diff.oldFile().path()
this.newPathName = diff.newFile().path()
this.size = diff.size()
this.renamed = diff.isRenamed()
this.added = diff.isAdded()
this.untracked = diff.isUntracked()
this.deleted = diff.isDeleted()

let hunks = []
let stagedLines = []
if (stagedDiff) {
// TODO: This all happens sequentially which is a bit of a bummer.
Expand All @@ -156,10 +184,26 @@ export default class FileDiff {
.map(line => HunkLine.fromGitUtilsObject({line}))
.filter(line => line.isChanged())

console.log('all staged:');
for (const l of stagedLines) {
console.log(l.toString());
}

for (let hunk of (await diff.hunks())) {
let diffHunk = new DiffHunk()
diffHunk.fromGitUtilsObject({hunk, stagedLines})
this.hunks.push(diffHunk)
hunks.push(diffHunk)
}

this.transactor.transact(() => {
this.size = diff.size()
this.renamed = diff.isRenamed()
this.added = diff.isAdded()
this.untracked = diff.isUntracked()
this.deleted = diff.isDeleted()
this.setOldPathName(diff.oldFile().path())
this.setNewPathName(diff.newFile().path())
this.setHunks(hunks)
})
}
}
Loading