123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- const _ = require("underscore-plus");
- const { CompositeDisposable, GitRepositoryAsync } = require("atom");
- module.exports =
- class GitView {
- constructor() {
- this.element = document.createElement('status-bar-git');
- this.element.classList.add('git-view');
- this.createBranchArea();
- this.createCommitsArea();
- this.createStatusArea();
- this.activeItemSubscription = atom.workspace.getCenter().onDidChangeActivePaneItem(() => {
- this.subscribeToActiveItem();
- });
- this.projectPathSubscription = atom.project.onDidChangePaths(() => {
- this.subscribeToRepositories();
- });
- this.subscribeToRepositories();
- this.subscribeToActiveItem();
- }
- createBranchArea() {
- this.branchArea = document.createElement('div');
- this.branchArea.classList.add('git-branch', 'inline-block');
- this.element.appendChild(this.branchArea);
- this.element.branchArea = this.branchArea;
- const branchIcon = document.createElement('span');
- branchIcon.classList.add('icon', 'icon-git-branch');
- this.branchArea.appendChild(branchIcon);
- this.branchLabel = document.createElement('span');
- this.branchLabel.classList.add('branch-label');
- this.branchArea.appendChild(this.branchLabel);
- this.element.branchLabel = this.branchLabel;
- }
- createCommitsArea() {
- this.commitsArea = document.createElement('div');
- this.commitsArea.classList.add('git-commits', 'inline-block');
- this.element.appendChild(this.commitsArea);
- this.commitsAhead = document.createElement('span');
- this.commitsAhead.classList.add('icon', 'icon-arrow-up', 'commits-ahead-label');
- this.commitsArea.appendChild(this.commitsAhead);
- this.commitsBehind = document.createElement('span');
- this.commitsBehind.classList.add('icon', 'icon-arrow-down', 'commits-behind-label');
- this.commitsArea.appendChild(this.commitsBehind);
- }
- createStatusArea() {
- this.gitStatus = document.createElement('div');
- this.gitStatus.classList.add('git-status', 'inline-block');
- this.element.appendChild(this.gitStatus);
- this.gitStatusIcon = document.createElement('span');
- this.gitStatusIcon.classList.add('icon');
- this.gitStatus.appendChild(this.gitStatusIcon);
- this.element.gitStatusIcon = this.gitStatusIcon;
- }
- subscribeToActiveItem() {
- const activeItem = this.getActiveItem();
- this.savedSubscription?.dispose();
- this.savedSubscription = activeItem?.onDidSave?.(() => this.update());
- this.update();
- }
- subscribeToRepositories() {
- this.repositorySubscriptions?.dispose();
- this.repositorySubscriptions = new CompositeDisposable;
- const result = [];
- for (let repo of atom.project.getRepositories()) {
- if (repo != null) {
- this.repositorySubscriptions.add(
- repo.onDidChangeStatus(({ path, status }) => {
- if (path === this.getActiveItemPath()) {
- this.update();
- }
- })
- );
- result.push(this.repositorySubscriptions.add(
- repo.onDidChangeStatuses(() => {
- this.update();
- })
- ));
- }
- }
- return result;
- }
- destroy() {
- this.activeItemSubscription?.dispose();
- this.projectPathSubscription?.dispose();
- this.savedSubscription?.dispose();
- this.repositorySubscriptions?.dispose();
- this.branchTooltipDisposable?.dispose();
- this.commitsAheadTooltipDisposable?.dispose();
- this.commitsBehindTooltipDisposable?.dispose();
- this.statusTooltipDisposable?.dispose();
- }
- getActiveItemPath() {
- return this.getActiveItem()?.getPath?.();
- }
- getRepositoryForActiveItem() {
- const [rootDir] = atom.project.relativizePath(this.getActiveItemPath());
- const rootDirIndex = atom.project.getPaths().indexOf(rootDir);
- if (rootDirIndex >= 0) {
- return atom.project.getRepositories()[rootDirIndex];
- } else {
- for (let repo of atom.project.getRepositories()) {
- if (repo) {
- return repo;
- }
- }
- }
- }
- getActiveItem() {
- return atom.workspace.getCenter().getActivePaneItem();
- }
- update() {
- const repo = this.getRepositoryForActiveItem();
- this.updateBranchText(repo);
- this.updateAheadBehindCount(repo);
- this.updateStatusText(repo);
- }
- updateBranchText(repo) {
- if (this.showGitInformation(repo)) {
- const head = repo.getShortHead(this.getActiveItemPath());
- this.branchLabel.textContent = head;
- if (head) { this.branchArea.style.display = ''; }
- this.branchTooltipDisposable?.dispose();
- this.branchTooltipDisposable = atom.tooltips.add(this.branchArea, {title: `On branch ${head}`});
- } else {
- this.branchArea.style.display = 'none';
- }
- }
- showGitInformation(repo) {
- if (repo == null) { return false; }
- const itemPath = this.getActiveItemPath();
- if (itemPath) {
- return atom.project.contains(itemPath);
- } else {
- return (this.getActiveItem() == null);
- }
- }
- updateAheadBehindCount(repo) {
- if (!this.showGitInformation(repo)) {
- this.commitsArea.style.display = 'none';
- return;
- }
- const itemPath = this.getActiveItemPath();
- const {ahead, behind} = repo.getCachedUpstreamAheadBehindCount(itemPath);
- if (ahead > 0) {
- this.commitsAhead.textContent = ahead;
- this.commitsAhead.style.display = '';
- this.commitsAheadTooltipDisposable?.dispose();
- this.commitsAheadTooltipDisposable = atom.tooltips.add(this.commitsAhead, {title: `${_.pluralize(ahead, 'commit')} ahead of upstream`});
- } else {
- this.commitsAhead.style.display = 'none';
- }
- if (behind > 0) {
- this.commitsBehind.textContent = behind;
- this.commitsBehind.style.display = '';
- this.commitsBehindTooltipDisposable?.dispose();
- this.commitsBehindTooltipDisposable = atom.tooltips.add(this.commitsBehind, {title: `${_.pluralize(behind, 'commit')} behind upstream`});
- } else {
- this.commitsBehind.style.display = 'none';
- }
- if ((ahead > 0) || (behind > 0)) {
- this.commitsArea.style.display = '';
- } else {
- this.commitsArea.style.display = 'none';
- }
- }
- clearStatus() {
- this.gitStatusIcon.classList.remove('icon-diff-modified', 'status-modified', 'icon-diff-added', 'status-added', 'icon-diff-ignored', 'status-ignored');
- }
- updateAsNewFile() {
- this.clearStatus();
- const textEditor = atom.workspace.getActiveTextEditor();
- this.gitStatusIcon.classList.add('icon-diff-added', 'status-added');
- if (textEditor) {
- this.gitStatusIcon.textContent = `+${textEditor.getLineCount()}`;
- this.updateTooltipText(`${_.pluralize(textEditor.getLineCount(), 'line')} in this new file not yet committed`);
- } else {
- this.gitStatusIcon.textContent = '';
- this.updateTooltipText();
- }
- this.gitStatus.style.display = '';
- }
- updateAsModifiedFile(repo, path) {
- const stats = repo.getDiffStats(path);
- this.clearStatus();
- this.gitStatusIcon.classList.add('icon-diff-modified', 'status-modified');
- if (stats.added && stats.deleted) {
- this.gitStatusIcon.textContent = `+${stats.added}, -${stats.deleted}`;
- this.updateTooltipText(`${_.pluralize(stats.added, 'line')} added and ${_.pluralize(stats.deleted, 'line')} deleted in this file not yet committed`);
- } else if (stats.added) {
- this.gitStatusIcon.textContent = `+${stats.added}`;
- this.updateTooltipText(`${_.pluralize(stats.added, 'line')} added to this file not yet committed`);
- } else if (stats.deleted) {
- this.gitStatusIcon.textContent = `-${stats.deleted}`;
- this.updateTooltipText(`${_.pluralize(stats.deleted, 'line')} deleted from this file not yet committed`);
- } else {
- this.gitStatusIcon.textContent = '';
- this.updateTooltipText();
- }
- this.gitStatus.style.display = '';
- }
- updateAsIgnoredFile() {
- this.clearStatus();
- this.gitStatusIcon.classList.add('icon-diff-ignored', 'status-ignored');
- this.gitStatusIcon.textContent = '';
- this.gitStatus.style.display = '';
- this.updateTooltipText("File is ignored by git");
- }
- updateTooltipText(text) {
- this.statusTooltipDisposable?.dispose();
- if (text) {
- this.statusTooltipDisposable = atom.tooltips.add(this.gitStatusIcon, {title: text});
- }
- }
- updateStatusText(repo) {
- const hideStatus = () => {
- this.clearStatus();
- this.gitStatus.style.display = 'none';
- };
- const itemPath = this.getActiveItemPath();
- if (this.showGitInformation(repo) && (itemPath != null)) {
- const status = repo.getCachedPathStatus(itemPath) ?? 0;
- if (repo.isStatusNew(status)) {
- return this.updateAsNewFile();
- }
- if (repo.isStatusModified(status)) {
- return this.updateAsModifiedFile(repo, itemPath);
- }
- if (repo.isPathIgnored(itemPath)) {
- return this.updateAsIgnoredFile();
- } else {
- return hideStatus();
- }
- } else {
- return hideStatus();
- }
- }
- }
|