diff --git a/lib/get-active-path.js b/lib/get-active-path.js new file mode 100644 index 0000000..e75ed7e --- /dev/null +++ b/lib/get-active-path.js @@ -0,0 +1,45 @@ +function getActivePath (target) { + if (!target) { + return atom.project.getPaths()[0] + } + + const treeView = target.closest('.tree-view') + if (treeView) { + // called from treeview + const selected = treeView.querySelector('.selected > .list-item > .name, .selected > .name') + if (selected) { + return selected.dataset.path + } + return + } + + const tab = target.closest('.tab-bar > .tab') + if (tab) { + // called from tab + const title = tab.querySelector('.title') + if (title && title.dataset.path) { + return title.dataset.path + } + return + } + + const paneItem = atom.workspace.getActivePaneItem() + if (paneItem && typeof paneItem.getPath === 'function') { + // called from active pane + return paneItem.getPath() + } + + const textEditor = atom.workspace.getActiveTextEditor() + if (textEditor && typeof textEditor.getPath === 'function') { + // fallback to activeTextEditor if activePaneItem is not a file + return textEditor.getPath() + } + + const projects = atom.project.getPaths() + if (projects.length === 1) { + // use project is nothing is open + return projects[0] + } +} + +module.exports = getActivePath diff --git a/lib/main.js b/lib/main.js index 4090fc8..84ac790 100644 --- a/lib/main.js +++ b/lib/main.js @@ -1,11 +1,14 @@ const {Disposable} = require('atom') const GitHubFile = require('./github-file') +const getActivePath = require('./get-active-path') -function getActivePath () { - const activePaneItem = atom.workspace.getActivePaneItem() +function pathCommand (func) { + return function (e) { + const itemPath = getActivePath(e.target) - if (activePaneItem && typeof activePaneItem.getPath === 'function') { - return activePaneItem.getPath() + if (itemPath) { + func(itemPath) + } } } @@ -21,77 +24,41 @@ module.exports = { activate () { this.commandsSubscription = new Disposable() this.commandsSubscription = atom.commands.add('atom-pane', { - 'open-on-github:file': () => { - const itemPath = getActivePath() - - if (itemPath) { - GitHubFile.fromPath(itemPath).open(getSelectedRange()) - } - }, - - 'open-on-github:file-on-master': () => { - const itemPath = getActivePath() - - if (itemPath) { - GitHubFile.fromPath(itemPath).openOnMaster(getSelectedRange()) - } - }, - - 'open-on-github:blame': () => { - const itemPath = getActivePath() - - if (itemPath) { - GitHubFile.fromPath(itemPath).blame(getSelectedRange()) - } - }, - - 'open-on-github:history': () => { - const itemPath = getActivePath() - - if (itemPath) { - GitHubFile.fromPath(itemPath).history() - } - }, - - 'open-on-github:issues': () => { - const itemPath = getActivePath() - - if (itemPath) { - GitHubFile.fromPath(itemPath).openIssues() - } - }, + 'open-on-github:file': pathCommand((itemPath) => { + GitHubFile.fromPath(itemPath).open(getSelectedRange()) + }), - 'open-on-github:pull-requests': () => { - const itemPath = getActivePath() + 'open-on-github:file-on-master': pathCommand((itemPath) => { + GitHubFile.fromPath(itemPath).openOnMaster(getSelectedRange()) + }), - if (itemPath) { - return GitHubFile.fromPath(itemPath).openPullRequests() - } - }, + 'open-on-github:blame': pathCommand((itemPath) => { + GitHubFile.fromPath(itemPath).blame(getSelectedRange()) + }), - 'open-on-github:copy-url': () => { - const itemPath = getActivePath() + 'open-on-github:history': pathCommand((itemPath) => { + GitHubFile.fromPath(itemPath).history() + }), - if (itemPath) { - GitHubFile.fromPath(itemPath).copyURL(getSelectedRange()) - } - }, + 'open-on-github:issues': pathCommand((itemPath) => { + GitHubFile.fromPath(itemPath).openIssues() + }), - 'open-on-github:branch-compare': () => { - const itemPath = getActivePath() + 'open-on-github:pull-requests': pathCommand((itemPath) => { + GitHubFile.fromPath(itemPath).openPullRequests() + }), - if (itemPath) { - GitHubFile.fromPath(itemPath).openBranchCompare() - } - }, + 'open-on-github:copy-url': pathCommand((itemPath) => { + GitHubFile.fromPath(itemPath).copyURL(getSelectedRange()) + }), - 'open-on-github:repository': () => { - const itemPath = getActivePath() + 'open-on-github:branch-compare': pathCommand((itemPath) => { + GitHubFile.fromPath(itemPath).openBranchCompare() + }), - if (itemPath) { - GitHubFile.fromPath(itemPath).openRepository() - } - } + 'open-on-github:repository': pathCommand((itemPath) => { + GitHubFile.fromPath(itemPath).openRepository() + }) }) }, diff --git a/spec/fixtures/project/file1.txt b/spec/fixtures/project/file1.txt new file mode 100644 index 0000000..e69de29 diff --git a/spec/fixtures/project/file2.txt b/spec/fixtures/project/file2.txt new file mode 100644 index 0000000..e69de29 diff --git a/spec/fixtures/project/img1.jpg b/spec/fixtures/project/img1.jpg new file mode 100644 index 0000000..14465a5 Binary files /dev/null and b/spec/fixtures/project/img1.jpg differ diff --git a/spec/get-active-path-spec.js b/spec/get-active-path-spec.js new file mode 100644 index 0000000..261909f --- /dev/null +++ b/spec/get-active-path-spec.js @@ -0,0 +1,75 @@ +const path = require('path') +const getActivePath = require('../lib/get-active-path') + +const { it, fit, beforeEach, afterEach } = require('./async-spec-helpers') // eslint-disable-line no-unused-vars + +const projectPath = path.resolve(__dirname, './fixtures/project/') +const file1 = path.resolve(__dirname, './fixtures/project/file1.txt') +const file2 = path.resolve(__dirname, './fixtures/project/file2.txt') +const img1 = path.resolve(__dirname, './fixtures/project/img1.png') + +describe('getActivePath', function () { + let workspaceElement + beforeEach(async function () { + workspaceElement = atom.views.getView(atom.workspace) + await atom.packages.activatePackage('tabs') + await atom.packages.activatePackage('tree-view') + atom.project.setPaths([projectPath]) + }) + + it('returns project path when no target', function () { + const itemPath = getActivePath() + expect(itemPath).toBe(projectPath) + }) + + it('returns project path when nothing open', function () { + const itemPath = getActivePath(workspaceElement) + expect(itemPath).toBe(projectPath) + }) + + it('returns active file path when workspace is selected', async function () { + await atom.workspace.open(file1) + await atom.workspace.open(file2) + + const itemPath = getActivePath(workspaceElement) + expect(itemPath).toBe(file2) + }) + + it('returns file path when tree view is selected', async function () { + await atom.workspace.open(file1) + await atom.workspace.open(file2) + + const { treeView } = atom.packages.getLoadedPackage('tree-view').mainModule + const file1Target = treeView.selectEntryForPath(file1) + + const itemPath = getActivePath(file1Target) + expect(itemPath).toBe(file1) + }) + + it('returns file path when tab is selected', async function () { + await atom.workspace.open(file1) + await atom.workspace.open(file2) + const file1Target = workspaceElement.querySelector(".tab-bar [data-name='file1.txt']") + + const itemPath = getActivePath(file1Target) + expect(itemPath).toBe(file1) + }) + + it('returns project when active pane is not a file', async function () { + await atom.packages.activatePackage('settings-view') + await atom.workspace.open(file1) + await atom.workspace.open('atom://config') + + const itemPath = getActivePath(workspaceElement) + expect(itemPath).toBe(projectPath) + }) + + it('returns active pane path when it is not a text file', async function () { + await atom.packages.activatePackage('image-view') + await atom.workspace.open(file1) + await atom.workspace.open(img1) + + const itemPath = getActivePath(workspaceElement) + expect(itemPath).toBe(img1) + }) +})