Skip to content
This repository was archived by the owner on Dec 15, 2022. It is now read-only.
Closed
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
7 changes: 7 additions & 0 deletions interfaces/atom.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ declare module 'atom' {
destroyItem(item: any): boolean;
}

declare class Range {
intersectsRow(row: number): boolean;
start: Point;
end: Point;
copy(): Range;
}

declare class TextBuffer {
onDidSave(fn: Function): Disposable;
onDidReload(fn: Function): Disposable;
Expand Down
62 changes: 62 additions & 0 deletions lib/editor-ops.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* @flow */

import GitStore from './git-store'
import FileListViewModel from './file-list-view-model'
import FileDiff from './file-diff'
import HunkLine from './hunk-line'

import type {Range} from 'atom'

export function stageOrUnstageSelectedLines (gitStore: GitStore, fileListViewModel: FileListViewModel): void {
const editor = atom.workspace.getActiveTextEditor()
if (editor) {
const selectedRanges = editor.getSelectedBufferRanges()
const [_projectPath, relativePath] = editor.project.relativizePath(editor.getPath())
stageBufferRanges(selectedRanges, relativePath, gitStore, fileListViewModel)
}
}

export async function stageBufferRanges (ranges: Array<Range>, filePath: string, gitStore: GitStore, fileListViewModel: FileListViewModel): Promise<void> {
await gitStore.loadFromGit()
const fileDiff = fileListViewModel.getDiffForPathName(filePath)
const [changedLines, stageOrUnstage] = getChangedLinesAndStagingType(fileDiff, ranges)
await gitStore.stageLines(changedLines, stageOrUnstage)
}

export function getChangedLinesAndStagingType (fileDiff: FileDiff, ranges: Array<Range>): [Array<HunkLine>, boolean] {
let lineOffsetSoFar = 0

ranges = ranges.map(range => {
// If a range spans at least one line, and ends on column zero we don't
// want to stage the last line (since no text on that line is selected).
// So, copy the range and rewind the ending row by 1.
if (range.end.column === 0 && range.start.row !== range.end.row) {
range = range.copy()
range.end.row = range.end.row - 1
}
return range
})

const anyRangesIntersectLine = (ranges, line) => {
// Added/deleted lines mess up the row offset; account for them
let row
if (line.isAddition()) {
row = line.getNewLineNumber() - 1
lineOffsetSoFar++
} else {
row = line.getOldLineNumber()
lineOffsetSoFar--
}
if (line.isDeletion()) row += lineOffsetSoFar
return ranges.some(range => range.intersectsRow(row))
}

const linesChangedInRange = fileDiff.getHunks()
.map(hunk => hunk.getLines())
.reduce((acc, lines) => acc.concat(lines), [])
.filter(line => line.isChanged() && anyRangesIntersectLine(ranges, line))

const linesToStage = linesChangedInRange.filter(line => !line.isStaged())

return linesToStage.length ? [linesToStage, true] : [linesChangedInRange, false]
}
5 changes: 5 additions & 0 deletions lib/git-package.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import DiffViewModel from './diff-view-model'
import StatusBarViewModel from './status-bar-view-model'
import GitService from './git-service'
import {DiffURI} from './common'
import {stageOrUnstageSelectedLines} from './editor-ops'

import type {Panel, Pane} from 'atom'
import type {StatusBar, Tile} from 'status-bar'
Expand Down Expand Up @@ -43,6 +44,10 @@ export default class GitPackage {

atom.commands.add('atom-workspace', 'git:refresh-status', () => this.update('reload'))

atom.commands.add('atom-workspace', 'git:stage-or-unstage-selected-lines', () => {
stageOrUnstageSelectedLines(this.getGitStore(), this.getFileListViewModel())
})

this.update('reload')

if (state.panelVisible) {
Expand Down
23 changes: 23 additions & 0 deletions spec/editor-ops-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/** @babel */

import {it} from './async-spec-helpers'

describe('Editor ops', function () {
describe('staging and unstaging lines', () => {
describe('when no highlighted lines are staged', () => {
it('stages changed lines', () => {

})
})
describe('when some highlighted lines are staged and some are unstaged', () => {
it('stages all unstaged changed lines', () => {

})
})
describe('when all highlighted lines are staged', () => {
it('unstages all staged lines', () => {

})
})
})
})