Skip to content

Commit

Permalink
feat: add basic support for command-palette-plus
Browse files Browse the repository at this point in the history
- add basic POC for the new command pallete
- add first link parsing to determine repo name in standardised format
- add palette support for all platforms for issues & PRs
- remove some debugging messages from console
  • Loading branch information
keevan committed Mar 5, 2022
1 parent 22cbca7 commit f7c97ae
Show file tree
Hide file tree
Showing 15 changed files with 12,356 additions and 8,155 deletions.
13 changes: 13 additions & 0 deletions .babelrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = {
sourceMaps: "inline",
plugins: [
"@babel/plugin-proposal-object-rest-spread",
"add-module-exports"
],
presets: [
["@babel/preset-env", {
targets: {electron: process.versions.electron || process.env.ELECTRON_VERSION}
}],
"@babel/preset-react"
],
}
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ Please take a look at our [contributing guidelines](./.github/CONTRIBUTING.md) i
- Open a file locally based on a copied link.
- Add option to disable default behaviour for 'Opening links on double copy'.
- Custom tracker integration linking (e.g. copy / open link to relevant ticket this last change)
- Open blame view for file in browser
- Open history view for file in browser
- Open issues view for file in browser
- Open PR/MR view for file in browser
- Open/Copy compare view/link e.g. to current branch or a commit for file in browser
- Detect PR branch and have a link ready for that as well (quickly jump to current PR in atom/browser) e.g. when doing a review
- Open README in browser

### Support

Expand Down
7 changes: 6 additions & 1 deletion commitlint.config.js
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
module.exports = {extends: ['@commitlint/config-conventional']}
module.exports = {
extends: ['@commitlint/config-conventional'],
ignores: [
(message) => (message.includes('WIP') || message.trim() === 'fix')
]
}
81 changes: 79 additions & 2 deletions lib/git-link.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export default {
const relativePath = await this.getRelativePath(filePath())
const commitHash = await this.getCommitHash()

const [start, startColumn, endColumn] = this.getCurrentSelection()
const [start, , startColumn, endColumn] = this.getCurrentSelection()

// [Special foo - to make it visually clearer which part of text was highlighted if any]
// If:
Expand Down Expand Up @@ -284,6 +284,83 @@ export default {
const commitHash = await this.getCommitHash()
const link = p.getFileLink({ commitHash, relativePath })
shell.openExternal(link);
}
},

async consumePallete(service) {
// Added ensure the current 'scope' is defined. For example, if a
// selection is made, the scope can be 'selection', if the main git
// repository, is at the project path, the scope can be 'project'. If the
// closest git repository is not the same path as the project, it might be
// a submodule, so check for that and return that scope.
// Ideally, it should check and return at most one scope, but multiple
// scopes should be possible. (e.g. different packges) It would be better
// to arrive at a consensus when same scope different names occur (e.g. project vs repo)
service.addScopeCallback(async () => {

const [start, end, startColumn, endColumn] = this.getCurrentSelection()
if (start !== end || startColumn !== endColumn) {
service.addScope('selection')
return
}

// service.addScope('git')
// service.addScope('submodule')
// service.addScope('project')
})

service.addSuggestionCallback(async ({ scopes }) => {
console.log('[git-link] Getting suggestions..');
const p = await this.getPlatform()

// If a selection is made, then add selection related options (e.g. open on the VCS)
if (scopes.includes('selection')) {
service.addSuggestion({
title: `Open selection on ${p.type}`,
icon: 'browser',
callback: async () => this.openSelection()
})
return; // If a selection is made, assume other options aren't relevant for a cleaner experience
}

// Link to repo
service.addSuggestion({
title: p.getRepoDisplay(),
icon: 'repo',
callback: async () => shell.openExternal(p.getRepo())
})

// Link to issues (if a relevant page exists)
if (p?.getIssuesLink) {
service.addSuggestion({
title: 'Issues',
icon: 'issue-opened',
callback: async () => shell.openExternal(p.getIssuesLink())
})
}

// Link to Pull (Merge) Requests - only gitlab seems to use the term
// Merge so going with pull request throughout this codebase.
service.addSuggestion({
title: 'Pull Requests',
icon: 'git-pull-request',
callback: async () => shell.openExternal(p.getPullRequestsLink())
})

// Scope - In a git repo (based on current file backwards)
const test = [
// {group: 'Browser', title: 'Discussions', icon: 'comment-discussion'},
// {group: 'Browser', title: 'Actions', icon: 'playback-play'},
// {group: 'Browser', title: 'Projects', icon: 'tasklist'},
// {group: 'Browser', title: 'Settings', icon: 'gear'},
]

test.forEach(t => {
// Add various commands for now to test service
service.addSuggestion(t)
})


})

}
};
73 changes: 36 additions & 37 deletions lib/git.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use babel';

import { BufferedProcess } from 'atom';
import { fileDirectory, filePath } from './path';

Expand All @@ -10,45 +8,46 @@ import { fileDirectory, filePath } from './path';
* @param string cwd: the current working directory for the git exec (defaults to current file's directory)
*/
const git = (args, cwd) => {
if (typeof cwd === "undefined" || cwd === null) {
cwd = fileDirectory(filePath());
}
var stdout = ''
var errors = ''
const myPromise = new Promise((resolve, reject) => {
try {
new BufferedProcess({
command: 'git',
args,
options: { cwd },
stdout(output) {
stdout += output
},
stderr(errorOutput) {
if (typeof errorOutput !== "undefined" && errorOutput !== null) {
console.error(errorOutput);
if (typeof cwd === "undefined" || cwd === null) {
const fp = filePath()
cwd = fileDirectory(fp);
}
let stdout = ''
let errors = ''
const myPromise = new Promise((resolve, reject) => {
try {
new BufferedProcess({
command: 'git',
args,
options: { cwd },
stdout(output) {
stdout += output
},
stderr(errorOutput) {
if (typeof errorOutput !== "undefined" && errorOutput !== null) {
console.error(errorOutput);
}
errors += errorOutput
},
exit(code) {
console.group("`git " + (args.join(' ')) + "`" + `, exit code: ${code}`);
console.log(stdout) // Show all output at once after the caller command
console.groupEnd()
resolve({ code, stdout, errors })
}
errors += errorOutput
},
exit(code) {
console.group("`git " + (args.join(' ')) + "`" + `, exit code: ${code}`);
console.log(stdout) // Show all output at once after the caller command
console.groupEnd()
resolve({ code, stdout, errors })
}
})
} catch (e) {
console.error(e);
reject(e)
}
})
return myPromise
})
} catch (e) {
console.error(e);
reject(e)
}
})
return myPromise
}

export const toShortHash = (commitHash) => {
return commitHash
// Short hash should be 7 characters
.substring(0, 7)
return commitHash
// Short hash should be 7 characters
.substring(0, 7)
}


Expand Down
1 change: 0 additions & 1 deletion lib/path.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
'use babel';

const filePath = () => {
return atom.workspace.getActiveTextEditor().getBuffer().getPath();
Expand Down
11 changes: 4 additions & 7 deletions lib/platform.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use babel';

import * as platforms from './platforms'
import https from 'https'
import http from 'http'
Expand Down Expand Up @@ -50,7 +48,7 @@ export default {
try {
const response = await promise
const matchingType = Object.keys(platforms).find(type => {
const p = new platforms[type](attributes)
const p = new (platforms[type])(attributes)
console.log(`[git-link]: Checking ${type}`)
return p.hostsRepo({ repo, response, host: url.host })
})
Expand All @@ -68,12 +66,11 @@ export default {
async create(attributes) {
const type = await this.resolve(attributes)
const Platform = platforms[type]
console.log({ platform: new Platform(attributes) })
const p = new Platform(attributes)
p.type = type // For later referencing
if (!p.getRepo) {
p.getRepo = (new (platforms.default)(attributes)).getRepo
}
const defaultPlatform = new (platforms.default)(attributes)
p.getRepo = p.getRepo ?? defaultPlatform.getRepo
p.getRepoDisplay = p.getRepoDisplay ?? defaultPlatform.getRepoDisplay
return p
}
}
18 changes: 11 additions & 7 deletions lib/platforms/azure.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
'use babel';
import tmpl from 'reverse-string-template'

const azure = ({
repo,
}) => {
export default function ({ repo }) {
const regex = /ssh.dev.azure.com\/v3\/([^\/]+)\/([^\/]+)/gm;
const subst = `dev.azure.com/$1/$2/_git`;
this.repo = repo.replace(regex, subst);

return {
getRepoDisplay: () => {
const template = 'https://{%endpoint%}/{%username%}/{%project%}/_git/{{repository}}'
const { username, project, repository } = tmpl(repo, template)
return `${username}/${project}/${repository}`
},
getPullRequestsLink: () => {
return `${repo}/pullrequests`
},
getRepo: () => this.repo,
hostsRepo: ({ host }) => {
// If has a fragment of the known public domain (azure.com)
Expand All @@ -28,6 +34,4 @@ const azure = ({
getLineLink: ({ commitHash, relativePath, start, startColumn = 1, endColumn = 2 }) => `${this.repo}?path=${relativePath}&version=GC${commitHash}&line=${start}&lineEnd=${start}&lineStartColumn=${startColumn}&lineEndColumn=${endColumn}`,
getFileLink: ({ commitHash, relativePath }) => `${this.repo}?path=${relativePath}&version=GC${commitHash}`,
}
}

export default azure
}
49 changes: 25 additions & 24 deletions lib/platforms/bitbucket.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
'use babel';

import { toShortHash } from '../git'
import tmpl from 'reverse-string-template'

const bitbucket = ({
repo,
}) => ({
hostsRepo: ({ host, response }) => {
// If it's the known public domain (BitBucket.org)
if (host.toLowerCase() === 'bitbucket.org') {
return true
}

// If the header has the x-view-name
if (response.headers['x-view-name'].indexOf('bitbucket') !== -1) {
return true
}

// Otherwise..
return false
},
getSelectionLink: ({ commitHash, relativePath, start, end }) => `${repo}/src/${toShortHash(commitHash)}${relativePath}#lines-${start}:${end}`,
getLineLink: ({ commitHash, relativePath, start }) => `${repo}/src/${toShortHash(commitHash)}${relativePath}#lines-${start}`,
getFileLink: ({ commitHash, relativePath }) => `${repo}/src/${toShortHash(commitHash)}${relativePath}`,
export default function ({ repo }) {
return {
getRepoDisplay: () => {
const template = 'https://{%endpoint%}/{%username%}/{{repository}}'
const { username, repository } = tmpl(repo, template)
return `${username}/${repository}`
},
hostsRepo: ({ host, response }) => {
// If it's the known public domain (BitBucket.org)
if (host.toLowerCase() === 'bitbucket.org') {
return true
}

})
// If the header has the x-view-name
if (response.headers['x-view-name']?.includes('bitbucket')) {
return true
}

export default bitbucket
// Otherwise..
return false
},
getSelectionLink: ({ commitHash, relativePath, start, end }) => `${repo}/src/${toShortHash(commitHash)}${relativePath}#lines-${start}:${end}`,
getLineLink: ({ commitHash, relativePath, start }) => `${repo}/src/${toShortHash(commitHash)}${relativePath}#lines-${start}`,
getFileLink: ({ commitHash, relativePath }) => `${repo}/src/${toShortHash(commitHash)}${relativePath}`,
}
}
23 changes: 10 additions & 13 deletions lib/platforms/default.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
'use babel';

// Generic fallback for everything else, based on GitLab's format, without any special GitHub support.
const genericDefault = ({
repo,
}) => ({
getRepo: () => repo,
hostsRepo: () => false,
getSelectionLink: ({ commitHash, relativePath, start, end }) => `${repo}/blob/${commitHash}${relativePath}#L${start}-${end}`,
getLineLink: ({ commitHash, relativePath, start }) => `${repo}/blob/${commitHash}${relativePath}#L${start}`,
getFileLink: ({ commitHash, relativePath }) => `${repo}/blob/${commitHash}${relativePath}`,
})

export default genericDefault
export default function ({ repo }) {
return {
getRepo: () => repo,
getRepoDisplay: () => 'Current Repository', // e.g. for this package, it would be "keevan/git-link"
hostsRepo: () => false,
getSelectionLink: ({ commitHash, relativePath, start, end }) => `${repo}/blob/${commitHash}${relativePath}#L${start}-${end}`,
getLineLink: ({ commitHash, relativePath, start }) => `${repo}/blob/${commitHash}${relativePath}#L${start}`,
getFileLink: ({ commitHash, relativePath }) => `${repo}/blob/${commitHash}${relativePath}`,
}
}
Loading

0 comments on commit f7c97ae

Please sign in to comment.