Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

highlight character selections in GitHub #63

Merged
merged 15 commits into from
Jun 2, 2024
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## 3.1.0 - 2024-06-02

### Added

- Selections in VSCode will now highlight the same span of characters on GitHub. (#63)

## 3.0.0 - 2023-04-19

### Changed
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "githubinator",
"displayName": "Githubinator",
"description": "Quickly open files on Github and other providers. View blame information, copy permalinks and more. See the \"commands\" section of the README for more details.",
"version": "3.0.0",
"version": "3.1.0",
"publisher": "chdsbd",
"license": "SEE LICENSE IN LICENSE",
"icon": "images/logo256.png",
Expand Down
9 changes: 5 additions & 4 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,15 +196,16 @@ async function githubinator({
const editor = vscode.window.activeTextEditor
let urls: IUrlInfo | null = null
for (const provider of providers) {
const selection = editor?.selection
if (selection == null) {
return err("Could not find editor")
}
const parsedUrl = await new provider(
providersConfig,
globalDefaultRemote,
remote => git.origin(gitDir, remote),
).getUrls({
selection: [
editor ? editor.selection.start.line : null,
editor ? editor.selection.end.line : null,
],
selection,
// priority: permalink > branch > branch from HEAD
// If branchName could not be found (null) then we generate a permalink
// using the SHA.
Expand Down
25 changes: 14 additions & 11 deletions src/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ import { cleanHostname } from "./utils"
import { flatten } from "lodash"
import gitUrlParse from "git-url-parse"

interface ISelection {
start: { line: number; character: number }
end: { line: number; character: number }
}

interface IBaseGetUrls {
readonly selection: [number | null, number | null]
readonly selection: ISelection
readonly head: Head
readonly relativeFilePath: string | null
}
Expand Down Expand Up @@ -116,10 +121,10 @@ export class Github extends BaseProvider {
return null
}
const rootUrl = `https://${repoInfo.hostname}/`
const [start, end] = selection
const { start, end } = selection
// Github uses 1-based indexing
const lines =
start != null && end != null ? `L${start + 1}-L${end + 1}` : null
const lines = `L${start.line + 1}C${start.character + 1}-L${end.line +
1}C${end.character + 1}`
const repoUrl = new url.URL(
path.join(repoInfo.org, repoInfo.repo),
rootUrl,
Expand All @@ -138,7 +143,7 @@ export class Github extends BaseProvider {
),
rootUrl,
)
if (hash && lines) {
if (hash) {
u.hash = lines
}
return u.toString()
Expand Down Expand Up @@ -178,10 +183,9 @@ export class Gitlab extends BaseProvider {
return null
}
const rootUrl = `https://${repoInfo.hostname}/`
const [start, end] = selection
const { start, end } = selection
// The format is L34-56 (this is one character off from Github)
const lines =
start != null && end != null ? `L${start + 1}-${end + 1}` : null
const lines = `L${start.line + 1}-${end.line + 1}`
const repoUrl = new url.URL(
pathJoin(repoInfo.org, repoInfo.repo),
rootUrl,
Expand Down Expand Up @@ -243,9 +247,8 @@ export class Bitbucket extends BaseProvider {
}
// https://bitbucket.org/recipeyak/recipeyak/src/master/app/main.py#lines-12:15
const rootUrl = `https://${repoInfo.hostname}/`
const [start, end] = selection
const lines =
start != null && end != null ? `lines-${start + 1}:${end + 1}` : null
const { start, end } = selection
const lines = `lines-${start.line + 1}:${end.line + 1}`
const repoUrl = new url.URL(
pathJoin(repoInfo.org, repoInfo.repo),
rootUrl,
Expand Down
38 changes: 28 additions & 10 deletions src/test/suite/providers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,18 @@ suite("Github", async () => {
}
const gh = new Github({}, "origin", findRemote)
const result = await gh.getUrls({
selection: [17, 24],
selection: {
start: { line: 17, character: 0 },
end: { line: 24, character: 0 },
},
head: createSha("db99a912f5c4bffe11d91e163cd78ed96589611b"),
relativeFilePath: "frontend/src/components/App.tsx",
})
const expected = {
blobUrl:
"https://github.com/recipeyak/recipeyak/blob/db99a912f5c4bffe11d91e163cd78ed96589611b/frontend/src/components/App.tsx#L18-L25",
"https://github.com/recipeyak/recipeyak/blob/db99a912f5c4bffe11d91e163cd78ed96589611b/frontend/src/components/App.tsx#L18C1-L25C1",
blameUrl:
"https://github.com/recipeyak/recipeyak/blame/db99a912f5c4bffe11d91e163cd78ed96589611b/frontend/src/components/App.tsx#L18-L25",
"https://github.com/recipeyak/recipeyak/blame/db99a912f5c4bffe11d91e163cd78ed96589611b/frontend/src/components/App.tsx#L18C1-L25C1",
compareUrl:
"https://github.com/recipeyak/recipeyak/compare/db99a912f5c4bffe11d91e163cd78ed96589611b",
historyUrl:
Expand Down Expand Up @@ -83,15 +86,18 @@ suite("Github", async () => {
findRemote,
)
const result = await gh.getUrls({
selection: [17, 24],
selection: {
start: { line: 17, character: 0 },
end: { line: 24, character: 0 },
},
head: createBranch("master"),
relativeFilePath: "frontend/src/components/App.tsx",
})
const expected = {
blobUrl:
"https://github.mycompany.com/recipeyak/recipeyak/blob/master/frontend/src/components/App.tsx#L18-L25",
"https://github.mycompany.com/recipeyak/recipeyak/blob/master/frontend/src/components/App.tsx#L18C1-L25C1",
blameUrl:
"https://github.mycompany.com/recipeyak/recipeyak/blame/master/frontend/src/components/App.tsx#L18-L25",
"https://github.mycompany.com/recipeyak/recipeyak/blame/master/frontend/src/components/App.tsx#L18C1-L25C1",
compareUrl:
"https://github.mycompany.com/recipeyak/recipeyak/compare/master",
historyUrl:
Expand All @@ -113,7 +119,10 @@ suite("Gitlab", async () => {
async _ => "[email protected]:recipeyak/recipeyak.git",
)
const result = await gl.getUrls({
selection: [17, 24],
selection: {
start: { line: 17, character: 0 },
end: { line: 24, character: 0 },
},
head: createSha("db99a912f5c4bffe11d91e163cd78ed96589611b"),
relativeFilePath: "frontend/src/components/App.tsx",
})
Expand Down Expand Up @@ -141,7 +150,10 @@ suite("Gitlab", async () => {
async _ => "https://gitlab.mycompany.com/recipeyak/recipeyak.git",
)
const result = await gl.getUrls({
selection: [17, 24],
selection: {
start: { line: 17, character: 0 },
end: { line: 24, character: 0 },
},
head: createBranch("master"),
relativeFilePath: "frontend/src/components/App.tsx",
})
Expand Down Expand Up @@ -171,7 +183,10 @@ suite("Bitbucket", async () => {
async _ => "[email protected]:recipeyak/recipeyak.git",
)
const result = await bb.getUrls({
selection: [17, 24],
selection: {
start: { line: 17, character: 0 },
end: { line: 24, character: 0 },
},
head: createSha("db99a912f5c4bffe11d91e163cd78ed96589611b"),
relativeFilePath: "frontend/src/components/App.tsx",
})
Expand Down Expand Up @@ -204,7 +219,10 @@ suite("Bitbucket", async () => {
getOrigin,
)
const result = await bb.getUrls({
selection: [17, 24],
selection: {
start: { line: 17, character: 0 },
end: { line: 24, character: 0 },
},
head: createBranch("master"),
relativeFilePath: "frontend/src/components/App.tsx",
})
Expand Down
Loading