Skip to content

Commit

Permalink
Merge pull request #137 from hdpoliveira/quickpick
Browse files Browse the repository at this point in the history
Fix #116: Show 'heads(draft())' and 'max(public())' revisions in "Hg: Update to..."
  • Loading branch information
hdpoliveira authored Jul 28, 2020
2 parents a87d753 + bbbbbcd commit cffead7
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 69 deletions.
105 changes: 51 additions & 54 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {
TextEditor,
} from "vscode";
import {
Ref,
RefType,
ShelveOptions,
Hg,
Expand Down Expand Up @@ -1050,53 +1049,55 @@ export class CommandCenter {
}
}

private async checkThenWarnOutstandingMergeOrUnclean(
repository: Repository,
scenario: WarnScenario
): Promise<boolean> {
if (
(await interaction.checkThenWarnOutstandingMerge(repository)) ||
(await interaction.checkThenWarnUnclean(repository, scenario))
) {
this.focusScm();
return true;
}
return false;
}

@command("hg.update", { repository: true })
async update(repository: Repository): Promise<void> {
let refs: Ref[];
let unclean = false;

if (typedConfig.useBookmarks) {
// bookmarks
const bookmarkRefs = (await repository.getRefs()) as Bookmark[];
const { isClean, repoStatus } = repository;
unclean = !isClean || (repoStatus && repoStatus.isMerge) || false;
if (unclean) {
// unclean: only allow bookmarks already on the parents
const parents = await repository.getParents();
refs = bookmarkRefs.filter((b) =>
parents.some((p) => p.hash.startsWith(b.commit!))
);
if (refs.length === 0) {
// no current bookmarks, so fall back to warnings
(await interaction.checkThenWarnOutstandingMerge(
repository
)) ||
(await interaction.checkThenWarnUnclean(
repository,
WarnScenario.Update
));
return;
}
} else {
// clean: allow all bookmarks
refs = bookmarkRefs;
}
} else {
// branches/tags
if (
(await interaction.checkThenWarnOutstandingMerge(repository)) ||
(await interaction.checkThenWarnUnclean(
repository,
WarnScenario.Update
))
) {
this.focusScm();
return;
}
refs = await repository.getRefs();
const useBookmarks = typedConfig.useBookmarks;

if (
!useBookmarks &&
(await this.checkThenWarnOutstandingMergeOrUnclean(
repository,
WarnScenario.Update
))
) {
return;
}

const { isClean, repoStatus } = repository;
const uncleanBookmarks =
useBookmarks && (!isClean || (repoStatus && repoStatus.isMerge));

const refs = await repository.getUpdateCandidates(
useBookmarks,
uncleanBookmarks
);

if (uncleanBookmarks && refs.length === 0) {
this.checkThenWarnOutstandingMergeOrUnclean(
repository,
WarnScenario.Update
);
return;
}

const choice = await interaction.pickUpdateRevision(refs, unclean);
const choice = await interaction.pickUpdateRevision(
refs,
uncleanBookmarks
);

if (choice) {
await choice.run(repository);
Expand Down Expand Up @@ -1150,13 +1151,11 @@ export class CommandCenter {
@command("hg.mergeWithLocal", { repository: true })
async mergeWithLocal(repository: Repository): Promise<void> {
if (
(await interaction.checkThenWarnOutstandingMerge(repository)) ||
(await interaction.checkThenWarnUnclean(
await this.checkThenWarnOutstandingMergeOrUnclean(
repository,
WarnScenario.Merge
))
)
) {
this.focusScm();
return;
}

Expand All @@ -1174,13 +1173,11 @@ export class CommandCenter {
@command("hg.mergeHeads", { repository: true })
async mergeHeads(repository: Repository): Promise<void> {
if (
(await interaction.checkThenWarnOutstandingMerge(repository)) ||
(await interaction.checkThenWarnUnclean(
await this.checkThenWarnOutstandingMergeOrUnclean(
repository,
WarnScenario.Merge
))
)
) {
this.focusScm();
return;
}

Expand Down Expand Up @@ -1502,7 +1499,7 @@ export class CommandCenter {
const bookmarkName = await interaction.inputBookmarkName();

if (bookmarkName) {
const bookmarkRefs = await repository.getRefs();
const bookmarkRefs = await repository.getBookmarks();
const existingBookmarks = bookmarkRefs.filter(
(ref) => ref.type === RefType.Bookmark
) as Bookmark[];
Expand Down Expand Up @@ -1546,7 +1543,7 @@ export class CommandCenter {
}
}

const bookmarkRefs = await repository.getRefs();
const bookmarkRefs = await repository.getBookmarks();
const existingBookmarks = bookmarkRefs.filter(
(ref) => ref.type === RefType.Bookmark
) as Bookmark[];
Expand Down
62 changes: 57 additions & 5 deletions src/hg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ export interface ICommitDetails {
affectedFiles: IFileStatus[];
}

export interface GetRefsOptions {
excludeBookmarks?: boolean;
excludeTags?: boolean;
}

export enum RefType {
Branch,
Tag,
Expand Down Expand Up @@ -1473,13 +1478,13 @@ export class Repository {
return activeBookmark;
}

async getLogEntries({
private async getNativeCommits({
revQuery,
branch,
filePaths,
follow,
limit,
}: LogEntryRepositoryOptions = {}): Promise<Commit[]> {
}: LogEntryRepositoryOptions = {}): Promise<NativeCommit[]> {
const args = ["log", "-T", "json"];

if (revQuery) {
Expand All @@ -1503,8 +1508,16 @@ export class Repository {
}

const result = await this.run(args);
const logEntries = JSON.parse(result.stdout.trim()).map(
(commit: NativeCommit): Commit | null => {
return JSON.parse(result.stdout.trim()) as NativeCommit[];
}

async getLogEntries(
options: LogEntryRepositoryOptions = {}
): Promise<Commit[]> {
const nativeCommits = await this.getNativeCommits(options);

return nativeCommits.map(
(commit: NativeCommit): Commit => {
return {
revision: commit.rev,
date: new Date(commit.date[0] * 1000),
Expand All @@ -1516,7 +1529,6 @@ export class Repository {
} as Commit;
}
);
return logEntries;
}

async getParents(revision?: string): Promise<Commit[]> {
Expand Down Expand Up @@ -1586,6 +1598,46 @@ export class Repository {
return branchRefs;
}

async getDraftHeads(opts: GetRefsOptions): Promise<Ref[]> {
const draftHeads = await this.getNativeCommits({
revQuery: "head() and draft()",
});

return draftHeads
.filter(
(c) =>
(!opts.excludeTags || c.tags.length === 0) &&
(!opts.excludeBookmarks || c.bookmarks.length === 0)
)
.map((c) => {
return {
type: RefType.Commit,
commit: c.node.substr(0, 12),
};
});
}

async getPublicTip(opts: GetRefsOptions): Promise<Ref[]> {
const maxPublic = await this.getNativeCommits({
revQuery: "max(public())",
limit: 1,
});

return maxPublic
.filter(
(c) =>
(!opts.excludeTags || c.tags.length === 0) &&
(!opts.excludeBookmarks || c.bookmarks.length === 0)
)
.map((c) => {
return {
name: "public tip",
type: RefType.Commit,
commit: c.node.substr(0, 12),
};
});
}

async getBookmarks(): Promise<Bookmark[]> {
const bookmarksResult = await this.run(["bookmarks"]);
const bookmarkRefs = bookmarksResult.stdout
Expand Down
18 changes: 14 additions & 4 deletions src/interaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -616,10 +616,13 @@ export namespace interaction {
.map((ref) => new UpdateTagItem(ref))
: [];

const picks = [...branches, ...bookmarks, ...tags];
const revType = useBookmarks ? "bookmark" : "branch/tag";
const commits = refs
.filter((ref) => ref.type === RefType.Commit)
.map((ref) => new UpdateCommitItem(ref));

const placeHolder = `Select a ${revType} to update to: ${
const picks = [...branches, ...bookmarks, ...tags, ...commits];

const placeHolder = `Select a revision to update to: ${
unclean
? "(only showing local bookmarks while working directory unclean)"
: ""
Expand Down Expand Up @@ -1249,7 +1252,8 @@ class UpdateRefItem implements QuickPickItem {
constructor(protected ref: Ref) {}

async run(repository: Repository): Promise<void> {
const ref = this.treeish;
const ref =
this.ref.type === RefType.Commit ? this.ref.commit : this.treeish;

if (!ref) {
return;
Expand All @@ -1274,6 +1278,12 @@ class UpdateBookmarkItem extends UpdateRefItem {
}
}

class UpdateCommitItem extends UpdateRefItem {
protected get icon(): string {
return "$(git-commit) ";
}
}

class FileStatusQuickPickItem extends RunnableQuickPickItem {
get basename(): string {
return path.basename(this.status.path);
Expand Down
43 changes: 37 additions & 6 deletions src/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
HgRollbackDetails,
ShelveOptions,
UnshelveOptions,
GetRefsOptions,
RefType,
} from "./hg";
import {
Expand Down Expand Up @@ -1433,19 +1434,49 @@ export class Repository implements IDisposable {
}

@throttle
public async getRefs(): Promise<Ref[]> {
if (typedConfig.useBookmarks) {
const bookmarks = await this.repository.getBookmarks();
return bookmarks;
public async getUpdateCandidates(
useBookmarks: boolean,
uncleanBookmarks?: boolean
): Promise<Ref[]> {
if (useBookmarks) {
// bookmarks
if (uncleanBookmarks) {
// unclean: only allow bookmarks already on the parents
const [bookmarks, parents] = await Promise.all([
this.repository.getBookmarks(),
this.repository.getParents(),
]);
return bookmarks.filter((b) =>
parents.some((p) => p.hash.startsWith(b.commit!))
);
} else {
// clean: allow all bookmarks and other commits
const opts = { excludeBookmarks: true } as GetRefsOptions;
const [bookmarks, maxPublic, draftHeads] = await Promise.all([
this.repository.getBookmarks(),
this.repository.getPublicTip(opts),
this.repository.getDraftHeads(opts),
]);
return [...bookmarks, ...maxPublic, ...draftHeads];
}
} else {
const [branches, tags] = await Promise.all([
// branches/tags
const opts = { excludeTags: true } as GetRefsOptions;
const [branches, tags, maxPublic, draftHeads] = await Promise.all([
this.repository.getBranches(),
this.repository.getTags(),
this.repository.getPublicTip(opts),
this.repository.getDraftHeads(opts),
]);
return [...branches, ...tags];
return [...branches, ...tags, ...maxPublic, ...draftHeads];
}
}

@throttle
public async getBookmarks(): Promise<Bookmark[]> {
return this.repository.getBookmarks();
}

@throttle
public getParents(revision?: string): Promise<Commit[]> {
return this.repository.getParents(revision);
Expand Down

0 comments on commit cffead7

Please sign in to comment.