Skip to content
Merged
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
2 changes: 1 addition & 1 deletion extensions/github1s/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions extensions/github1s/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
],
"browser": "./dist/extension",
"engines": {
"vscode": "^1.48.0"
"vscode": "^1.96.0"
},
"contributes": {
"resourceLabelFormatters": [
Expand Down Expand Up @@ -244,7 +244,7 @@
"dark": "assets/icons/dark/open-left-file.svg",
"light": "assets/icons/light/open-left-file.svg"
},
"enablement": "isInDiffEditor && resourceScheme =~ /^(github1s|gitlab1s|bitbucket1s)/ && resource =~ /^(?![^?]*\\?[^#]*(%26|\\b)base(=|%3D|%3d)github1s-empty-file)/"
"enablement": "isInDiffEditor && diffEditorOriginalUri && !(diffEditorOriginalUri =~ /^github1s-empty-file:/)"
},
{
"command": "github1s.commands.diffViewOpenRightFile",
Expand All @@ -254,21 +254,21 @@
"dark": "assets/icons/dark/open-right-file.svg",
"light": "assets/icons/light/open-right-file.svg"
},
"enablement": "isInDiffEditor && resourceScheme =~ /^(github1s|gitlab1s|bitbucket1s)/ && resource =~ /^(?![^?]*\\?[^#]*(%26|\\b)head(=|%3D|%3d)github1s-empty-file)/"
"enablement": "isInDiffEditor && diffEditorModifiedUri && !(diffEditorModifiedUri =~ /^github1s-empty-file:/)"
},
{
"command": "github1s.commands.openFilePreviousRevision",
"title": "Open Previous Revision",
"category": "GitHub1s",
"icon": "$(arrow-left)",
"enablement": "resourceScheme =~ /^(github1s|gitlab1s|bitbucket1s)$/ && resource =~ /^(?![^?]*\\?[^#]*(%26|\\b)base(=|%3D|%3d)github1s-empty-file)/"
"enablement": "(!isInDiffEditor && resourceScheme =~ /^(github1s|gitlab1s|bitbucket1s)$/) || (isInDiffEditor && diffEditorOriginalUri =~ /^(github1s|gitlab1s|bitbucket1s):/)"
},
{
"command": "github1s.commands.openFileNextRevision",
"title": "Open Next Revision",
"category": "GitHub1s",
"icon": "$(arrow-right)",
"enablement": "resource =~ /^[^?]*\\?[^#]*(%26|\\b)hasNextRevision(=|%3D|%3d)true/"
"enablement": "resourceScheme =~ /^(github1s|gitlab1s|bitbucket1s)$/ && resource =~ /^[^?]*\\?([^#]*(&|%26))?hasNext(=|%3D|%3d)true/"
},
{
"command": "github1s.commands.toggleEditorGutterBlame",
Expand Down Expand Up @@ -588,12 +588,12 @@
},
{
"command": "github1s.commands.openFilePreviousRevision",
"when": "resourceScheme =~ /^(github1s|gitlab1s|bitbucket1s)/",
"when": "resourceScheme =~ /^(github1s|gitlab1s|bitbucket1s)$/ || (isInDiffEditor && diffEditorOriginalUri =~ /^(github1s|gitlab1s|bitbucket1s):/)",
"group": "navigation@4"
},
{
"command": "github1s.commands.openFileNextRevision",
"when": "resourceScheme =~ /^(github1s|gitlab1s|bitbucket1s)/",
"when": "resourceScheme =~ /^(github1s|gitlab1s|bitbucket1s)$/ || (isInDiffEditor && diffEditorOriginalUri =~ /^(github1s|gitlab1s|bitbucket1s):/)",
"group": "navigation@5"
},
{
Expand Down
2 changes: 1 addition & 1 deletion extensions/github1s/src/adapters/github1s/data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ export class GitHub1sDataSource extends DataSource {
page: options?.page,
per_page: options?.pageSize,
sha: options?.from,
path: isString(options?.path) ? trimStart(options.path, '/') : undefined,
path: trimStart(options?.path || '', '/') || undefined,
author: options?.author,
};
const requestParams = { owner, repo, ...queryParams };
Expand Down
2 changes: 1 addition & 1 deletion extensions/github1s/src/adapters/gitlab1s/data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ export class GitLab1sDataSource extends DataSource {
page: options?.page,
per_page: options?.pageSize,
sha: options?.from,
path: isString(options?.path) ? trimStart(options.path, '/') : undefined,
path: trimStart(options?.path || '', '/') || undefined,
author: options?.author,
};
const requestParams = { repo, ...queryParams };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ export class SourcegraphDataSource extends DataSource {
let commits = await getCommits(
this.buildRepository(repo),
options?.from || 'HEAD',
options?.path === undefined ? undefined : trimStart(options.path, '/'),
trimStart(options?.path || '', '/') || undefined,
options?.pageSize ? options.pageSize * (options.page || 1) : undefined,
);
if (options?.path && options.path !== '/' && commits.length) {
Expand Down
8 changes: 1 addition & 7 deletions extensions/github1s/src/changes/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*/

import * as vscode from 'vscode';
import queryString from 'query-string';
import * as adapterTypes from '@/adapters/types';
import router from '@/router';
import { basename } from '@/helpers/util';
Expand Down Expand Up @@ -117,15 +116,10 @@ export const getChangedFileDiffCommand = (changedFile: VSCodeChangedFile): vscod
}

const title = getChangedFileDiffTitle(baseFileUri, headFileUri, status);
const query = queryString.stringify({
status,
base: baseFileUri.with({ query: '' }).toString(),
head: headFileUri.with({ query: '' }).toString(),
});

return {
title: 'Diff',
command: 'vscode.diff',
arguments: [baseFileUri.with({ query }), headFileUri.with({ query }), title],
arguments: [baseFileUri, headFileUri, title],
};
};
13 changes: 2 additions & 11 deletions extensions/github1s/src/changes/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,21 +95,12 @@ export class GitHub1sHistoryProvider implements vscode.SourceControlHistoryProvi
// A missing side makes VS Code open the existing file directly for additions/deletions.
const originalUri = !parentId || file.status === FileChangeStatus.Added ? undefined : file.baseFileUri;
const modifiedUri = file.status === FileChangeStatus.Removed ? undefined : file.headFileUri;
// Carry context for our diff editor commands (open either side, previous/next revision).
const query =
originalUri && modifiedUri
? queryString.stringify({
base: originalUri.with({ query: '' }).toString(),
head: modifiedUri.with({ query: '' }).toString(),
status: file.status,
})
: '';
return {
// Display resource for the file label and status badge, including deleted files.
uri: file.headFileUri.with({ query: queryString.stringify({ changeStatus: file.status }) }),
// Content resources for the diff's left (before) and right (after) sides.
originalUri: originalUri?.with({ query }),
modifiedUri: modifiedUri?.with({ query }),
originalUri,
modifiedUri,
};
});
}
Expand Down
8 changes: 5 additions & 3 deletions extensions/github1s/src/commands/commit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,11 @@ const commandDiffCommitFile = async (commitItem: CommitTreeItem) => {
if (!activeDocumentUri) {
return;
}
const fileUri = router.buildUri({ ref: commitSha }, activeDocumentUri).with({
query: queryString.stringify({ from: router.getState().ref }),
});
const from = await Repository.getCurrentInstance().getCommitItem(router.getState().ref);
if (!from) {
return;
}
const fileUri = router.buildUri({ ref: commitSha }, activeDocumentUri);
return vscode.commands.executeCommand('github1s.commands.openFilePreviousRevision', fileUri);
};

Expand Down
207 changes: 115 additions & 92 deletions extensions/github1s/src/commands/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { emptyFileUri } from '@/providers';
import { FileChangeStatus } from '@/adapters/types';
import { Repository } from '@/repository';
import { getChangedFiles, getChangedFileDiffCommand, getChangedFileDiffTitle } from '@/changes/files';
import { omit } from '@/helpers/util';

export const getChangedFileFromSourceControl = async (fileUri: vscode.Uri) => {
// the file should belong to current workspace
Expand All @@ -35,114 +36,136 @@ const commandDiffChangedFile = async (fileUri: vscode.Uri) => {
vscode.commands.executeCommand(command.command, ...(command.arguments || []));
};

const openFileToEditor = async (fileUri) => {
return vscode.commands.executeCommand('vscode.open', fileUri, { preview: false });
const isRepositoryFileUri = (uri: vscode.Uri | undefined): uri is vscode.Uri => {
return !!uri && /^(github1s|gitlab1s|bitbucket1s)$/.test(uri.scheme);
};

// open the left file in the diff editor title
const commandDiffViewOpenLeftFile = async (fileUri: vscode.Uri) => {
const query = queryString.parse(fileUri?.query || '');
return query.base ? openFileToEditor(vscode.Uri.parse(query.base as string)) : null;
};

// open the right file in the diff editor title
const commandDiffViewOpenRightFile = async (fileUri: vscode.Uri) => {
const query = queryString.parse(fileUri?.query || '');
return query.head ? openFileToEditor(vscode.Uri.parse(query.head as string)) : null;
};

// get the file uri with the concrete commit sha, the `ref` in
// `fileUri.authority` maybe newer but not related this file
const getConcreteFileUri = async (fileUri: vscode.Uri) => {
const { scheme, repo, ref, path } = router.parseUri(fileUri);
const repository = Repository.getInstance(scheme, repo);
const commit = await repository.getFileLatestCommit(ref, path);
const latestCommitSha = commit?.sha || (await repository.getCommitItem(ref))?.sha;
const getActiveDiffInput = (resource?: vscode.Uri): vscode.TabInputTextDiff | undefined => {
const input = vscode.window.tabGroups.activeTabGroup.activeTab?.input;
if (!(input instanceof vscode.TabInputTextDiff)) {
return;
}

return router.buildUri({ ref: latestCommitSha }, fileUri);
// Title actions receive the modified URI. Ignore actions targeting another diff.
if (resource && resource.toString() !== input.modified.toString()) {
return;
}
return input;
};

// show the file's diff between current commit and previous commit
const commandOpenFilePreviousRevision = async (fileUri: vscode.Uri) => {
const queryParams = queryString.parse(fileUri.query);
const queryBaseUriStr = queryParams.base;
const headFileUri = typeof queryParams.head === 'string' ? vscode.Uri.parse(queryParams.head) : undefined;
const from =
typeof queryParams.from === 'string'
? queryParams.from
: router.parseUri(headFileUri && headFileUri.scheme !== emptyFileUri.scheme ? headFileUri : fileUri).ref;
const rightFileUri = await getConcreteFileUri(
// if the `queryBaseUriStr` is empty, which means this command is called from
// a normal file editor (not a diff editor), just use `fileUri` in this case
queryBaseUriStr ? vscode.Uri.parse(queryBaseUriStr as string) : fileUri,
);
const { scheme, repo, ref: rightCommitSha } = router.parseUri(rightFileUri);
const repository = Repository.getInstance(scheme, repo);
const leftCommit = await repository.getPreviousCommit(rightCommitSha, rightFileUri.path, from);
// if we can't find previous commit, use the `emptyFileUri` as the leftFileUri
const leftFileUri = leftCommit ? router.buildUri({ ref: leftCommit.sha }, rightFileUri) : emptyFileUri;

const changedStatus = leftCommit ? FileChangeStatus.Modified : FileChangeStatus.Added;
const hasNextRevision = !!(await repository.getNextCommit(rightCommitSha, rightFileUri.path, from));

const query = queryString.stringify({
base: leftFileUri.with({ query: '' }).toString(),
head: rightFileUri.with({ query: '' }).toString(),
from,
status: changedStatus,
// if we can't find a newer commit for this file,
// the `Show Next Commit` Button would be disabled.
hasNextRevision,
});

return vscode.commands.executeCommand(
'vscode.diff',
leftFileUri.with({ query }),
rightFileUri.with({ query }),
getChangedFileDiffTitle(leftFileUri, rightFileUri, changedStatus),
);
const createCommandDiffViewOpenFile = (side: 'original' | 'modified') => async (resource?: vscode.Uri) => {
const fileUri = getActiveDiffInput(resource)?.[side];
if (fileUri && fileUri?.scheme !== emptyFileUri.scheme) {
await vscode.commands.executeCommand('workbench.action.keepEditor');
return vscode.commands.executeCommand('vscode.open', fileUri, {});
}
};

// show the file's diff between current commit and next commit
const commandOpenFileNextRevision = async (fileUri: vscode.Uri) => {
const queryParams = queryString.parse(fileUri.query);
const headFileUri = typeof queryParams.head === 'string' ? vscode.Uri.parse(queryParams.head) : fileUri;
const from = typeof queryParams.from === 'string' ? queryParams.from : router.parseUri(headFileUri).ref;
const leftFileUri = await getConcreteFileUri(headFileUri);

const { scheme, repo, ref: leftCommitSha } = router.parseUri(leftFileUri);
const repository = Repository.getInstance(scheme, repo);
const rightCommit = await repository.getNextCommit(leftCommitSha, leftFileUri.path, from);
const resolveOpenFileRevisionArgs = async (
fileUri: vscode.Uri | undefined,
direction: 'previous' | 'next',
): Promise<[vscode.Uri, string]> => {
let baseUri: vscode.Uri | undefined, from: string | undefined;
const getQueryFrom = (uri: vscode.Uri): string | undefined => {
return queryString.parse(uri.query).from as string | undefined;
};

const textDiffInput = getActiveDiffInput(fileUri);
if (textDiffInput) {
// this is a diff editor
const { original, modified } = textDiffInput;
const hasLeftFile = isRepositoryFileUri(original);
const hasRightFile = isRepositoryFileUri(modified);

if (direction === 'previous' && hasLeftFile) {
baseUri = original;
}
if (direction === 'next' && hasRightFile) {
baseUri = modified;
}
if (hasRightFile) {
from = getQueryFrom(modified);
}
} else if (isRepositoryFileUri(fileUri)) {
// this is a single file editor
from = getQueryFrom(fileUri);
baseUri = fileUri;
}

if (!rightCommit) {
return vscode.window.showInformationMessage('There is no next commit found.');
if (!baseUri) {
throw new Error('Unable to resolve the target file.');
}

const rightFileUri = router.buildUri({ ref: rightCommit.sha }, leftFileUri);
const hasNextRevision = !!(await repository.getNextCommit(rightCommit.sha, rightFileUri.path, from));
if (!from) {
// If 'from' cannot be obtained in the query, use the ref of baseUri as 'from'
const { scheme, repo, ref, path } = router.parseUri(baseUri);
const repository = Repository.getInstance(scheme, repo);
from = (await repository.getFileLatestCommit(ref, path))?.sha;
if (!from) {
throw new Error('Unable to resolve the latest commit for this file.');
}
baseUri = router.buildUri({ ref: from }, baseUri);
}

const query = queryString.stringify({
base: leftFileUri.with({ query: '' }).toString(),
head: rightFileUri.with({ query: '' }).toString(),
from,
status: FileChangeStatus.Modified,
hasNextRevision,
});
return [baseUri, from];
};

return vscode.commands.executeCommand(
'vscode.diff',
leftFileUri.with({ query }),
rightFileUri.with({ query }),
getChangedFileDiffTitle(leftFileUri, rightFileUri, FileChangeStatus.Modified),
);
const createCommandOpenFileRevision = (direction: 'previous' | 'next') => async (fileUri?: vscode.Uri) => {
try {
const [baseUri, from] = await resolveOpenFileRevisionArgs(fileUri, direction);
const { scheme, repo, ref, path } = router.parseUri(baseUri);
const repository = Repository.getInstance(scheme, repo);
const baseSha = (await repository.getCommitItem(ref))?.sha;
if (!baseSha) {
throw new Error('Unable to resolve the commit for this file.');
}

let leftFileUri: vscode.Uri | undefined, rightFileUri: vscode.Uri | undefined;
if (direction === 'previous') {
const prevCommit = await repository.getPreviousCommit(baseSha, path, from);
leftFileUri = prevCommit ? router.buildUri({ ref: prevCommit.sha }, baseUri) : emptyFileUri;
rightFileUri = baseUri;
} else {
const nextCommit = await repository.getNextCommit(baseSha, path, from);
if (!nextCommit) throw new Error('Unable to find next commit for this file.');
leftFileUri = baseUri;
rightFileUri = router.buildUri({ ref: nextCommit.sha }, baseUri);
}

const hasNext = router.parseUri(rightFileUri).ref !== from || undefined;
const leftQuery = queryString.stringify(omit(queryString.parse(baseUri.query), ['from']));
const rightQuery = queryString.stringify({ ...queryString.parse(baseUri.query), from, hasNext });

if (fileUri && !queryString.parse(fileUri.query).from) {
await vscode.commands.executeCommand('workbench.action.keepEditor');
}

return await vscode.commands.executeCommand(
'vscode.diff',
leftFileUri.with({ query: leftQuery }),
rightFileUri.with({ query: rightQuery }),
getChangedFileDiffTitle(leftFileUri, rightFileUri, FileChangeStatus.Modified),
);
} catch (error) {
return vscode.window.showErrorMessage(`Unable to open file revision: ${error.message}`);
}
};

export const registerEditorCommands = (context: vscode.ExtensionContext) => {
return context.subscriptions.push(
vscode.commands.registerCommand('github1s.commands.diffChangedFile', commandDiffChangedFile),
vscode.commands.registerCommand('github1s.commands.diffViewOpenLeftFile', commandDiffViewOpenLeftFile),
vscode.commands.registerCommand('github1s.commands.diffViewOpenRightFile', commandDiffViewOpenRightFile),
vscode.commands.registerCommand('github1s.commands.openFilePreviousRevision', commandOpenFilePreviousRevision),
vscode.commands.registerCommand('github1s.commands.openFileNextRevision', commandOpenFileNextRevision),
vscode.commands.registerCommand(
'github1s.commands.diffViewOpenLeftFile',
createCommandDiffViewOpenFile('original'),
),
vscode.commands.registerCommand(
'github1s.commands.diffViewOpenRightFile',
createCommandDiffViewOpenFile('modified'),
),
vscode.commands.registerCommand(
'github1s.commands.openFilePreviousRevision',
createCommandOpenFileRevision('previous'),
),
vscode.commands.registerCommand('github1s.commands.openFileNextRevision', createCommandOpenFileRevision('next')),
);
};
Loading
Loading