mirror of
https://github.com/kahole/edamagit.git
synced 2024-10-26 09:00:54 +03:00
refactors
This commit is contained in:
parent
f686d5fad4
commit
0bd845e2d8
@ -1,13 +1,13 @@
|
||||
|
||||
## General
|
||||
- Use existing tooling as much as possible
|
||||
make magit, but the fancy stuff should be vscode like
|
||||
- Go for MVP consisting of 90% of common use
|
||||
- plus all convenient features that come along with it
|
||||
|
||||
## Auto refresh
|
||||
- FileChangeEvent
|
||||
|
||||
## Workspaces
|
||||
- Needs to support multiple workspaces (Already does this somewhat)
|
||||
- Needs to support multiple workspaces (Already do this somewhat)
|
||||
- Find out how to deal with status views and other views
|
||||
- Dispose of stuff when quit workspace etc..
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
## UI
|
||||
- icons
|
||||
https://code.visualstudio.com/api/references/icons-in-labels
|
||||
e.g $(git-branch)
|
||||
|
||||
- Transient interface:
|
||||
CONFIGURE should be just one action in the list.
|
||||
|
@ -1,47 +1,47 @@
|
||||
import { window, commands } from "vscode";
|
||||
import { Menu, MenuState } from "../menu/menu";
|
||||
import { window } from "vscode";
|
||||
import { Menu, MenuState, MenuUtil } from "../menu/menu";
|
||||
import { MagitRepository } from "../models/magitRepository";
|
||||
import MagitUtils from "../utils/magitUtils";
|
||||
import MagitStatusView from "../views/magitStatusView";
|
||||
import { Ref } from "../typings/git";
|
||||
|
||||
export async function branching(repository: MagitRepository, currentView: MagitStatusView, switches: any = {}) {
|
||||
const branchingMenu = {
|
||||
title: "Branching",
|
||||
commands: [
|
||||
{ label: "b", description: "Checkout", action: checkout },
|
||||
{ label: "l", description: "Checkout local branch", action: checkoutLocal },
|
||||
{ label: "c", description: "Checkout new branch", action: checkoutNewBranch },
|
||||
// { label: "w", description: "Checkout new worktree", action: checkout },
|
||||
// { label: "y", description: "Checkout pull-request", action: checkout },
|
||||
{ label: "s", description: "Create new spin-off", action: createNewSpinoff },
|
||||
{ label: "n", description: "Create new branch", action: createNewBranch },
|
||||
// { label: "W", description: "Create new worktree", action: checkout },
|
||||
// { label: "Y", description: "Create from pull-request", action: checkout },
|
||||
{ label: "C", description: "Configure", action: checkout },
|
||||
{ label: "m", description: "Rename", action: renameBranch },
|
||||
{ label: "x", description: "Reset", action: resetBranch },
|
||||
{ label: "k", description: "Delete", action: deleteBranch },
|
||||
]
|
||||
};
|
||||
|
||||
export async function branching(repository: MagitRepository, currentView: MagitStatusView) {
|
||||
// commands.executeCommand('setContext', 'magit.branching', true);
|
||||
|
||||
Menu.showMenu(branchingMap, { repository, currentView });
|
||||
return MenuUtil.showMenu(branchingMenu, { repository, currentView });
|
||||
}
|
||||
|
||||
const branchingMap = [
|
||||
{ label: "b", description: "$(git-branch) Checkout", action: checkout },
|
||||
{ label: "l", description: "Checkout local branch", action: checkoutLocal },
|
||||
{ label: "c", description: "Checkout new branch", action: checkoutNewBranch },
|
||||
{ label: "w", description: "Checkout new worktree", action: checkout },
|
||||
{ label: "y", description: "Checkout pull-request", action: checkout },
|
||||
{ label: "s", description: "Create new spin-off", action: createNewSpinoff },
|
||||
{ label: "n", description: "Create new branch", action: createNewBranch },
|
||||
{ label: "W", description: "Create new worktree", action: checkout },
|
||||
{ label: "Y", description: "Create from pull-request", action: checkout },
|
||||
{ label: "C", description: "Configure", action: checkout },
|
||||
{ label: "m", description: "Rename", action: renameBranch },
|
||||
{ label: "x", description: "Reset", action: checkout },
|
||||
{ label: "k", description: "Delete", action: deleteBranch },
|
||||
];
|
||||
|
||||
async function checkout(menuState: MenuState) {
|
||||
_checkout(menuState, menuState.repository.state.refs);
|
||||
return _checkout(menuState, menuState.repository.state.refs);
|
||||
}
|
||||
|
||||
async function checkoutLocal(menuState: MenuState) {
|
||||
_checkout(menuState, menuState.repository.state.refs);
|
||||
return _checkout(menuState, menuState.repository.state.refs);
|
||||
}
|
||||
|
||||
async function checkoutNewBranch(menuState: MenuState) {
|
||||
_createBranch(menuState, true);
|
||||
return _createBranch(menuState, true);
|
||||
}
|
||||
|
||||
async function createNewBranch(menuState: MenuState) {
|
||||
_createBranch(menuState, false);
|
||||
return _createBranch(menuState, false);
|
||||
}
|
||||
|
||||
async function createNewSpinoff(menuState: MenuState) {
|
||||
@ -52,85 +52,78 @@ async function createNewSpinoff(menuState: MenuState) {
|
||||
// C-h F magit-branch-spinoff
|
||||
}
|
||||
|
||||
async function renameBranch(menuState: MenuState) {
|
||||
async function renameBranch({ repository, currentView }: MenuState) {
|
||||
|
||||
let { repository, currentView } = menuState;
|
||||
let ref = await window.showQuickPick(repository.state.refs.map(r => r.name!), { placeHolder: "Rename branch" });
|
||||
|
||||
let ref = await window.showQuickPick(repository.state.refs.map(r => r.name!), { placeHolder: "Create and checkout branch starting at:" });
|
||||
|
||||
if (ref) {
|
||||
let newName = await window.showInputBox({ prompt: `Rename branch '${ref}' to:` });
|
||||
|
||||
if (newName && newName.length > 0) {
|
||||
try {
|
||||
// TODO: denne kan kun rename current branch
|
||||
await repository._repository.renameBranch(newName);
|
||||
MagitUtils.magitStatusAndUpdate(repository, currentView);
|
||||
} catch (error) {
|
||||
window.showErrorMessage(error.stderr);
|
||||
}
|
||||
|
||||
// TODO: denne kan kun rename current branch
|
||||
return await repository._repository.renameBranch(newName);
|
||||
|
||||
} else {
|
||||
window.showErrorMessage("No name given");
|
||||
throw new Error("No name given for branch rename");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteBranch(menuState: MenuState) {
|
||||
async function deleteBranch({ repository, currentView }: MenuState) {
|
||||
|
||||
let { repository, currentView } = menuState;
|
||||
|
||||
// TODO: menu-title
|
||||
let ref = await window.showQuickPick(repository.state.refs.map(r => r.name!), { placeHolder: "Delete" });
|
||||
|
||||
// TODO
|
||||
let force = false;
|
||||
|
||||
// TODO:
|
||||
// If unmerged
|
||||
// How: maybe try deleting and check the error response for "not fully merged"?
|
||||
let confirmed = await window.showInputBox({ prompt: `Delete unmerged branch ${ref}?` });
|
||||
if (confirmed !== undefined) {
|
||||
force = true;
|
||||
}
|
||||
|
||||
if (ref) {
|
||||
try {
|
||||
await repository.deleteBranch(ref, force);
|
||||
MagitUtils.magitStatusAndUpdate(repository, currentView);
|
||||
} catch (error) {
|
||||
window.showErrorMessage(error.stderr);
|
||||
}
|
||||
return repository.deleteBranch(ref, force);
|
||||
}
|
||||
}
|
||||
|
||||
async function resetBranch({ repository, currentView }: MenuState) {
|
||||
|
||||
// TODO
|
||||
|
||||
let ref = await window.showQuickPick(repository.state.refs.map(r => r.name!), { placeHolder: "Rename branch" });
|
||||
|
||||
let resetToRef = await window.showQuickPick(repository.state.refs.map(r => r.name!), { placeHolder: "Rename branch" });
|
||||
|
||||
if (ref) {
|
||||
// repository._repository.reset()
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
|
||||
async function _checkout(menuState: MenuState, refs: Ref[]) {
|
||||
async function _checkout({ repository, currentView }: MenuState, refs: Ref[]) {
|
||||
|
||||
let { repository, currentView } = menuState;
|
||||
|
||||
// TODO: menu-title
|
||||
let ref = await window.showQuickPick(refs.map(r => r.name!), { placeHolder: "Checkout" });
|
||||
|
||||
if (ref) {
|
||||
try {
|
||||
await repository.checkout(ref);
|
||||
MagitUtils.magitStatusAndUpdate(repository, currentView);
|
||||
} catch (error) {
|
||||
window.showErrorMessage(error.stderr);
|
||||
}
|
||||
return repository.checkout(ref);
|
||||
}
|
||||
}
|
||||
|
||||
async function _createBranch(menuState: MenuState, checkout: boolean) {
|
||||
async function _createBranch({ repository, currentView }: MenuState, checkout: boolean) {
|
||||
|
||||
let ref = await window.showQuickPick(repository.state.refs.map(r => r.name!), { placeHolder: "Create and checkout branch starting at" });
|
||||
|
||||
let { repository, currentView } = menuState;
|
||||
|
||||
let ref = await window.showQuickPick(repository.state.refs.map(r => r.name!), { placeHolder: "Create and checkout branch starting at:" });
|
||||
|
||||
if (ref) {
|
||||
let newBranchName = await window.showInputBox({ prompt: "Name for new branch" });
|
||||
|
||||
if (newBranchName && newBranchName.length > 0) {
|
||||
|
||||
try {
|
||||
await repository.createBranch(newBranchName, checkout, ref);
|
||||
MagitUtils.magitStatusAndUpdate(repository, currentView);
|
||||
} catch (error) {
|
||||
window.showErrorMessage(error.stderr);
|
||||
}
|
||||
return repository.createBranch(newBranchName, checkout, ref);
|
||||
|
||||
} else {
|
||||
window.showErrorMessage("No name given for new branch");
|
||||
}
|
||||
|
@ -1,27 +1,41 @@
|
||||
import MagitUtils from "../utils/magitUtils";
|
||||
import { MagitRepository } from "../models/magitRepository";
|
||||
import MagitStatusView from "../views/magitStatusView";
|
||||
import { TextEditor } from "vscode";
|
||||
import { TextEditor, window } from "vscode";
|
||||
|
||||
export class CommandPrimer {
|
||||
|
||||
static primeRepo(command: (repository: MagitRepository) => Promise<void>) {
|
||||
return (editor: TextEditor) => {
|
||||
let repository = MagitUtils.getCurrentMagitRepo(editor.document);
|
||||
// static primeRepo(command: (repository: MagitRepository) => Promise<void>) {
|
||||
// return (editor: TextEditor) => {
|
||||
// let repository = MagitUtils.getCurrentMagitRepo(editor.document);
|
||||
|
||||
if (repository) {
|
||||
command(repository);
|
||||
}
|
||||
};
|
||||
}
|
||||
// if (repository) {
|
||||
// command(repository);
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
static primeRepoAndView(command: (repository: MagitRepository, view: MagitStatusView) => Promise<void>): (editor: TextEditor) => void {
|
||||
static primeRepoAndView(command: (repository: MagitRepository, view: MagitStatusView) => Promise<void>): (editor: TextEditor) => Promise<void> {
|
||||
|
||||
return (editor: TextEditor) => {
|
||||
return async (editor: TextEditor) => {
|
||||
let [repository, currentView] = MagitUtils.getCurrentMagitRepoAndView(editor);
|
||||
|
||||
if (repository && currentView) {
|
||||
command(repository, currentView);
|
||||
|
||||
try {
|
||||
await command(repository, currentView);
|
||||
MagitUtils.magitStatusAndUpdate(repository, currentView);
|
||||
} catch (error) {
|
||||
|
||||
// TODO: statusView error message:
|
||||
// e.g top: GitError! Your local changes to the following files would be overwritten by checkout
|
||||
|
||||
// This error type, too heavy for most errors?
|
||||
// statusBar message might be better
|
||||
// but then custom, shorter messages are needed
|
||||
|
||||
window.showErrorMessage(error.stderr ?? error.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { gitApi } from "../extension";
|
||||
import { exec, spawn, ExecException } from "child_process";
|
||||
import { window } from "vscode";
|
||||
import MagitUtils from "../utils/magitUtils";
|
||||
import { LineSplitterRegex } from "../common/constants";
|
||||
import * as Constants from "../common/constants";
|
||||
import { execPath } from "process";
|
||||
import { MagitRepository } from "../models/magitRepository";
|
||||
import MagitStatusView from "../views/magitStatusView";
|
||||
@ -18,9 +18,8 @@ export async function magitCommit(repository: MagitRepository, currentView: Magi
|
||||
let vscodeExecutablePath = execPath; // Different in debug / developing extension mode than normal vscode mode??
|
||||
console.log(vscodeExecutablePath);
|
||||
|
||||
let gitExecutablePath = gitApi.git.path;
|
||||
|
||||
let cwd = repository.rootUri.fsPath;
|
||||
// let gitExecutablePath = gitApi.git.path;
|
||||
// let cwd = repository.rootUri.fsPath;
|
||||
|
||||
let userEditor: string | undefined;
|
||||
try {
|
||||
@ -35,17 +34,19 @@ export async function magitCommit(repository: MagitRepository, currentView: Magi
|
||||
window.setStatusBarMessage(`Type C-c C-c to finish, or C-c C-k to cancel`);
|
||||
|
||||
// TODO:
|
||||
// Is spawn faster? doesnt spawn a shell
|
||||
// spawn(gitExecutablePath, ["commit"], { cwd: currentRepository.rootUri.fsPath });
|
||||
// Which one:
|
||||
|
||||
let commitSuccessMessage = await execPromise(`${gitExecutablePath} commit`, cwd);
|
||||
// let commitSuccessMessage = await execPromise(`${gitExecutablePath} commit`, cwd);
|
||||
|
||||
window.setStatusBarMessage(`Git finished: ${commitSuccessMessage.replace(LineSplitterRegex, ' ')}`);
|
||||
// TODO: this needs to be wrapped, and it needs to decide between run and exec!
|
||||
let args = ["commit"];
|
||||
let commitSuccessMessage = await repository._repository.repository.run(args);
|
||||
|
||||
window.setStatusBarMessage(`Git finished: ${commitSuccessMessage.stdout.replace(Constants.LineSplitterRegex, ' ')}`, Constants.StatusMessageDisplayTimeout);
|
||||
|
||||
} catch (e) {
|
||||
//YES: Aborting due to empty commit message will appear here
|
||||
window.setStatusBarMessage(`Commit canceled.`);
|
||||
console.log(e);
|
||||
window.setStatusBarMessage(`Commit canceled.`, Constants.StatusMessageDisplayTimeout);
|
||||
} finally {
|
||||
if (userEditor) {
|
||||
repository.setConfig("core.editor", userEditor);
|
||||
@ -54,19 +55,19 @@ export async function magitCommit(repository: MagitRepository, currentView: Magi
|
||||
}
|
||||
}
|
||||
|
||||
function execPromise(command: string, cwd: string): Promise<string> {
|
||||
return new Promise( (resolve, reject) => {
|
||||
// function execPromise(command: string, cwd: string): Promise<string> {
|
||||
// return new Promise( (resolve, reject) => {
|
||||
|
||||
exec(command, { cwd }, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
reject(stderr);
|
||||
}
|
||||
else {
|
||||
resolve(stdout);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
// exec(command, { cwd }, (error, stdout, stderr) => {
|
||||
// if (error) {
|
||||
// reject(stderr);
|
||||
// }
|
||||
// else {
|
||||
// resolve(stdout);
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
// function spawnPromise(command: string, args: string[], cwd: string): Promise<string> {
|
||||
// return new Promise( async (resolve, reject) => {
|
||||
|
@ -1,8 +1,6 @@
|
||||
import { commands } from "vscode";
|
||||
|
||||
export function saveClose() {
|
||||
commands.executeCommand("workbench.action.files.save")
|
||||
.then(() => {
|
||||
commands.executeCommand("workbench.action.closeActiveEditor");
|
||||
});
|
||||
export async function saveClose() {
|
||||
await commands.executeCommand("workbench.action.files.save");
|
||||
return commands.executeCommand("workbench.action.closeActiveEditor");
|
||||
}
|
@ -1,15 +1,13 @@
|
||||
import { MagitPicker } from "../menus/magitPicker";
|
||||
import { PushingMenu } from "../menus/pushing/pushingMenu";
|
||||
import MagitUtils from "../utils/magitUtils";
|
||||
import { MagitRepository } from "../models/magitRepository";
|
||||
import MagitStatusView from "../views/magitStatusView";
|
||||
|
||||
export function pushing(repository: MagitRepository, currentView: MagitStatusView) {
|
||||
export async function pushing(repository: MagitRepository, currentView: MagitStatusView) {
|
||||
|
||||
console.log("Working tree changes, but from pushing command");
|
||||
console.log(repository.magitState!.workingTreeChanges);
|
||||
|
||||
MagitPicker.showMagitPicker(new PushingMenu(undefined, undefined));
|
||||
|
||||
|
||||
// Hvordan git push kommandoen bygges opp:
|
||||
// https://github.com/microsoft/vscode/blob/master/extensions/git/src/git.ts#L1491
|
||||
|
@ -10,75 +10,57 @@ import { MagitRepository } from "../models/magitRepository";
|
||||
import MagitStatusView from "../views/magitStatusView";
|
||||
import { Status } from "../typings/git";
|
||||
|
||||
export async function magitStage(repository: MagitRepository, currentView: MagitStatusView) {
|
||||
export async function magitStage(repository: MagitRepository, currentView: MagitStatusView): Promise<any> {
|
||||
|
||||
// TODO:
|
||||
// Bytt til ASYNC-AWAIT!!!!!??????
|
||||
|
||||
let selectedView = currentView.click(window.activeTextEditor!.selection.active);
|
||||
const selectedView = currentView.click(window.activeTextEditor!.selection.active);
|
||||
|
||||
if (selectedView instanceof HunkView) {
|
||||
let changeHunkDiff = (selectedView as HunkView).changeHunk.diff;
|
||||
const changeHunk = (selectedView as HunkView).changeHunk;
|
||||
|
||||
// Clean up
|
||||
var enc = new TextEncoder();
|
||||
let tmpPatchFilePath = "/tmp/minmagitdiffpatchting";
|
||||
workspace.fs.writeFile(Uri.parse("file://" + tmpPatchFilePath),
|
||||
// TODO: this linebreak might be fucked on windows
|
||||
enc.encode(selectedView.changeHunk.diffHeader + changeHunkDiff + "\n"))
|
||||
.then(async () => {
|
||||
// stage hunk
|
||||
// await currentRepository
|
||||
// .apply("/tmp/minmagitdiffpatchting");
|
||||
const patch = changeHunk.diffHeader + changeHunk.diff + "\n";
|
||||
|
||||
let args = ["apply", tmpPatchFilePath, "--cached"];
|
||||
// TODO: this needs to be wrapped, and it needs to decide between run and exec!
|
||||
const args = ["apply", "--cached"];
|
||||
return repository._repository.repository.run(args, { input: patch});
|
||||
|
||||
let result = await repository._repository.repository.run(args);
|
||||
console.log(result);
|
||||
MagitUtils.magitStatusAndUpdate(repository, currentView);
|
||||
|
||||
});
|
||||
|
||||
} else if (selectedView instanceof ChangeView) {
|
||||
|
||||
let magitChange = (selectedView as ChangeView).change;
|
||||
const magitChange = (selectedView as ChangeView).change;
|
||||
|
||||
await repository
|
||||
return repository
|
||||
._repository
|
||||
.add([magitChange.uri], { update: false/*magitChange.status !== Status.UNTRACKED*/ }); // TODO: litt usikker om update eller ikke
|
||||
|
||||
MagitUtils.magitStatusAndUpdate(repository, currentView);
|
||||
|
||||
} else if (selectedView instanceof ChangeSectionView) {
|
||||
let section = (selectedView as ChangeSectionView).section;
|
||||
|
||||
// TODO: Add confirmation question?
|
||||
// only for lowercase s command, not for big S
|
||||
|
||||
switch (section) {
|
||||
case Section.Untracked:
|
||||
magitStageAll(repository, currentView, StageAllKind.AllUntracked);
|
||||
break;
|
||||
return magitStageAll(repository, currentView, StageAllKind.AllUntracked);
|
||||
case Section.Unstaged:
|
||||
magitStageAll(repository, currentView, StageAllKind.AllTracked);
|
||||
break;
|
||||
return magitStageAll(repository, currentView, StageAllKind.AllTracked);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// TODO:
|
||||
// Switch to a quick pick where i can pass data, and have a title
|
||||
// Maybe make a simple wrapper
|
||||
// This should NOT be the same as a menu!
|
||||
await window.showQuickPick([
|
||||
|
||||
const choosenFilePath = await window.showQuickPick([
|
||||
...repository.magitState?.workingTreeChanges!,
|
||||
...repository.magitState?.indexChanges!,
|
||||
...repository.magitState?.untrackedFiles!,
|
||||
// ...currentRepository.magitState?.mergeChanges
|
||||
].map(c => FilePathUtils.pathRelativeTo(c.uri, repository.rootUri)),
|
||||
{ placeHolder: "Stage" }
|
||||
)
|
||||
.then(chosenFilePath => {
|
||||
);
|
||||
|
||||
// TODO: stage file
|
||||
// return repo . add ( filePath )
|
||||
|
||||
});
|
||||
MagitUtils.magitStatusAndUpdate(repository, currentView);
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,14 +70,9 @@ export enum StageAllKind {
|
||||
AllUntracked = "stageAllUntracked"
|
||||
}
|
||||
|
||||
export async function magitStageAll(repository: MagitRepository, currentView: MagitStatusView, kind: StageAllKind = StageAllKind.AllTracked) {
|
||||
export async function magitStageAll(repository: MagitRepository, currentView: MagitStatusView, kind: StageAllKind = StageAllKind.AllTracked): Promise<void> {
|
||||
|
||||
// if (currentView instanceof MagitStatusView) {
|
||||
|
||||
await commands.executeCommand("git." + kind.valueOf());
|
||||
MagitUtils.magitStatusAndUpdate(repository, currentView);
|
||||
|
||||
// }
|
||||
return commands.executeCommand("git." + kind.valueOf());
|
||||
}
|
||||
|
||||
export async function magitUnstage(repository: MagitRepository, currentView: MagitStatusView) {
|
||||
@ -103,19 +80,19 @@ export async function magitUnstage(repository: MagitRepository, currentView: Mag
|
||||
// TODO
|
||||
|
||||
// For files:
|
||||
// repository._repository.reset()
|
||||
// repository._repository.reset(, false);
|
||||
|
||||
// For hunks:
|
||||
// git apply --cached --reverse
|
||||
|
||||
// return async task
|
||||
|
||||
}
|
||||
|
||||
export async function magitUnstageAll(repository: MagitRepository, currentView: MagitStatusView) {
|
||||
export async function magitUnstageAll(repository: MagitRepository, currentView: MagitStatusView): Promise<void> {
|
||||
|
||||
let response = await window.showInputBox({ prompt: "Unstage all changes?" });
|
||||
|
||||
if (response !== undefined) {
|
||||
await commands.executeCommand("git.unstageAll");
|
||||
MagitUtils.magitStatusAndUpdate(repository, currentView);
|
||||
let confirmed = await window.showInputBox({ prompt: "Unstage all changes?" });
|
||||
if (confirmed !== undefined) {
|
||||
return commands.executeCommand("git.unstageAll");
|
||||
}
|
||||
}
|
@ -2,3 +2,5 @@
|
||||
export const LineSplitterRegex: RegExp = /\r?\n/g;
|
||||
|
||||
export const FinalLineBreakRegex: RegExp = /\r?\n$/g;
|
||||
|
||||
export const StatusMessageDisplayTimeout: number = 5;
|
@ -1,6 +1,6 @@
|
||||
import { Repository } from "../typings/git";
|
||||
import { Uri } from "vscode";
|
||||
import { SpawnOptions } from "child_process";
|
||||
import * as cp from "child_process";
|
||||
|
||||
interface BaseBaseRepository {
|
||||
run(args: string[], options?: SpawnOptions): Promise<IExecutionResult<string>>;
|
||||
@ -54,4 +54,12 @@ export interface Stash {
|
||||
export enum ForcePushMode {
|
||||
Force,
|
||||
ForceWithLease
|
||||
}
|
||||
|
||||
interface SpawnOptions extends cp.SpawnOptions {
|
||||
input?: string;
|
||||
encoding?: string;
|
||||
log?: boolean;
|
||||
// cancellationToken?: CancellationToken;
|
||||
// onSpawn?: (childProcess: cp.ChildProcess) => void;
|
||||
}
|
@ -59,7 +59,7 @@ export function activate(context: ExtensionContext) {
|
||||
context.subscriptions.push(commands.registerCommand('extension.magit-pushing', pushing));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-branching', CommandPrimer.primeRepoAndView(branching)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-stage', CommandPrimer.primeRepoAndView(magitStage)));
|
||||
context.subscriptions.push(commands.registerCommand('extension.magit-stage-all', CommandPrimer.primeRepoAndView(magitStageAll)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-stage-all', CommandPrimer.primeRepoAndView(magitStageAll)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-unstage', CommandPrimer.primeRepoAndView(magitUnstage)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-unstage-all', CommandPrimer.primeRepoAndView(magitUnstageAll)));
|
||||
|
||||
|
113
src/menu/menu.ts
113
src/menu/menu.ts
@ -1,9 +1,13 @@
|
||||
import { QuickPick, window, QuickPickItem, Disposable } from "vscode";
|
||||
import { window } from "vscode";
|
||||
import { MenuItem } from "./menuItem";
|
||||
import { MagitRepository } from "../models/magitRepository";
|
||||
import MagitStatusView from "../views/magitStatusView";
|
||||
import { DocumentView } from "../views/general/documentView";
|
||||
|
||||
export interface Menu {
|
||||
title: string;
|
||||
commands: MenuItem[];
|
||||
isSwitchesMenu?: boolean;
|
||||
}
|
||||
|
||||
export interface MenuState {
|
||||
repository: MagitRepository;
|
||||
@ -12,65 +16,58 @@ export interface MenuState {
|
||||
switches?: any;
|
||||
}
|
||||
|
||||
export class Menu {
|
||||
export class MenuUtil {
|
||||
|
||||
private _quickPick: QuickPick<MenuItem>;
|
||||
activeSwitches: any[] = [];
|
||||
static showMenu(menu: Menu, menuState: MenuState): Promise<void> {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let _quickPick = window.createQuickPick<MenuItem>();
|
||||
|
||||
_quickPick.title = menu.title;
|
||||
_quickPick.ignoreFocusOut = true;
|
||||
|
||||
constructor(menu: MenuItem[], menuState: MenuState, isSwitchesMenu?: boolean) {
|
||||
|
||||
this._quickPick = window.createQuickPick<MenuItem>();
|
||||
|
||||
this._quickPick.title = "Wow wow we we C - Configure";
|
||||
|
||||
if (isSwitchesMenu) {
|
||||
this._quickPick.canSelectMany = true;
|
||||
this._quickPick.title = "Switches (select with <space>)";
|
||||
}
|
||||
|
||||
this._quickPick.items = menu;
|
||||
|
||||
// Experiments
|
||||
// TODO: THIS ALSO WORKS PRETTY NICELY
|
||||
// no duplicate definitions of keybindings+menu keys
|
||||
// menu becomes actual menu, not just a visual element
|
||||
// and if it cant be enabled=false anyways, might as well just do it like this
|
||||
// but keep the notes about the other method
|
||||
this._quickPick.onDidChangeValue( (e) => {
|
||||
console.log(e);
|
||||
console.log(this._quickPick.value);
|
||||
// TODO
|
||||
// clean up
|
||||
let selectedItem = this._quickPick.activeItems.filter(i => i.label === this._quickPick.value);
|
||||
this._quickPick.value = "";
|
||||
console.log(selectedItem);
|
||||
selectedItem[0].action(menuState);
|
||||
this._quickPick.dispose(); //??
|
||||
});
|
||||
|
||||
// end Experiments
|
||||
|
||||
this._quickPick.onDidAccept(() => {
|
||||
|
||||
if (this._quickPick.activeItems.length > 0) {
|
||||
let chosenItem = this._quickPick.activeItems[0] as MenuItem;
|
||||
chosenItem.action(menuState);
|
||||
if (menu.isSwitchesMenu) {
|
||||
_quickPick.canSelectMany = true;
|
||||
_quickPick.title = "Switches (select with <space>)";
|
||||
}
|
||||
|
||||
_quickPick.items = menu.commands;
|
||||
|
||||
let eventListenerDisposable = _quickPick.onDidChangeValue( async (e) => {
|
||||
console.log(e);
|
||||
console.log(_quickPick.value);
|
||||
// TODO
|
||||
// clean up
|
||||
let chosenItem = _quickPick.activeItems.filter(i => i.label === _quickPick.value);
|
||||
_quickPick.value = "";
|
||||
try {
|
||||
await chosenItem[0].action(menuState);
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
_quickPick.dispose(); //??
|
||||
eventListenerDisposable.dispose(); //??
|
||||
});
|
||||
|
||||
// Keep both of these (Select with key or with arrows + enter)
|
||||
|
||||
_quickPick.onDidAccept(async () => {
|
||||
|
||||
if (_quickPick.activeItems.length > 0) {
|
||||
let chosenItem = _quickPick.activeItems[0] as MenuItem;
|
||||
try {
|
||||
await chosenItem.action(menuState);
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_quickPick.show();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
show() {
|
||||
|
||||
this._quickPick.show();
|
||||
this._quickPick.ignoreFocusOut = true;
|
||||
// this._quickPick.enabled = false;
|
||||
|
||||
// this._quickPick.dispose();
|
||||
|
||||
}
|
||||
|
||||
static showMenu(menu: MenuItem[], menuState: MenuState, isSwitchesMenu?: boolean) {
|
||||
new Menu(menu, menuState, isSwitchesMenu).show();
|
||||
}
|
||||
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import { MenuItem } from "./menuItem";
|
||||
|
||||
export interface Menu {
|
||||
title?: string;
|
||||
items: MenuItem[];
|
||||
onDidAcceptItems(acceptedItems: readonly MenuItem[]): Menu | undefined;
|
||||
isSwitchesMenu?: boolean;
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
import { QuickPick, QuickPickItem, window } from "vscode";
|
||||
|
||||
export interface MenuItem extends QuickPickItem {
|
||||
id: number;
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
import { Menu } from "../abstract/menu";
|
||||
import { MenuItem } from "../abstract/menuItem";
|
||||
import { MagitState } from "../../models/magitState";
|
||||
import { BranchingMenuItem } from "./branchingMenuSelection";
|
||||
|
||||
|
||||
export class BranchingMenu implements Menu {
|
||||
|
||||
title: string = "Branching";
|
||||
items: MenuItem[];
|
||||
|
||||
constructor() {
|
||||
this.items = [
|
||||
{id: BranchingMenuItem.Checkout , label: "b", description: "Checkout"},
|
||||
{id: BranchingMenuItem.Configure , label: "C", description: "Configure"},
|
||||
{id: BranchingMenuItem.CreateNewSpinoff , label: "s", description: "Create new spin-off"},
|
||||
{id: BranchingMenuItem.CheckoutNewBranch , label: "c", description: "Checkout new branch"},
|
||||
{id: BranchingMenuItem.Reset , label: "x", description: "Reset"},
|
||||
{id: BranchingMenuItem.CreateNewWorktree , label: "W", description: "Create new worktree"},
|
||||
{id: BranchingMenuItem.CheckoutPullRequest , label: "y", description: "Checkout pull-request"},
|
||||
{id: BranchingMenuItem.CheckoutLocalBranch , label: "l", description: "Checkout local branch"},
|
||||
{id: BranchingMenuItem.Rename , label: "m", description: "Rename"},
|
||||
{id: BranchingMenuItem.CreateNewBranch , label: "n", description: "Create new branch"},
|
||||
{id: BranchingMenuItem.CheckoutNewWorktree , label: "w", description: "Checkout new worktree"},
|
||||
{id: BranchingMenuItem.Delete , label: "k", description: "Delete"},
|
||||
{id: BranchingMenuItem.CreateFromPullRequest , label: "Y", description: "Create from pull-request"}
|
||||
];
|
||||
}
|
||||
|
||||
onDidAcceptItems(acceptedItems: readonly MenuItem[]): Menu | undefined {
|
||||
|
||||
// Weak abstraction in this function
|
||||
let firstItem = acceptedItems[0];
|
||||
|
||||
switch (firstItem.id) {
|
||||
case BranchingMenuItem.Checkout:
|
||||
// branchQuickPick.hide();
|
||||
// window.showQuickPick(["master", "exp", "origin/master"]);
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import { BranchingMenu } from "./branchingMenu";
|
||||
|
||||
export enum BranchingMenuItem {
|
||||
Checkout,
|
||||
Configure,
|
||||
CreateNewSpinoff,
|
||||
CheckoutNewBranch,
|
||||
Reset,
|
||||
CreateNewWorktree,
|
||||
CheckoutPullRequest,
|
||||
CheckoutLocalBranch,
|
||||
Rename,
|
||||
CreateNewBranch,
|
||||
CheckoutNewWorktree,
|
||||
Delete,
|
||||
CreateFromPullRequest
|
||||
}
|
||||
|
||||
export interface BranchingMenuSelection {
|
||||
item: BranchingMenuItem;
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
import { QuickPick, window } from "vscode";
|
||||
import { MenuItem } from "./abstract/menuItem";
|
||||
import { Menu } from "./abstract/menu";
|
||||
|
||||
export class MagitPicker {
|
||||
|
||||
private _quickPick: QuickPick<MenuItem>;
|
||||
|
||||
static showMagitPicker(menu: Menu) {
|
||||
new MagitPicker(menu).show();
|
||||
}
|
||||
|
||||
constructor(private _menu: Menu) {
|
||||
this._quickPick = window.createQuickPick();
|
||||
|
||||
this.loadMenu(this._menu);
|
||||
|
||||
this._quickPick.onDidAccept(() => {
|
||||
let nextMenu = this._menu.onDidAcceptItems(this._quickPick.activeItems);
|
||||
if (nextMenu) {
|
||||
this._menu = nextMenu;
|
||||
this.loadMenu(this._menu);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadMenu(menu: Menu) {
|
||||
this._quickPick.title = menu.title;
|
||||
|
||||
if (menu.isSwitchesMenu) {
|
||||
this._quickPick.canSelectMany = true;
|
||||
this._quickPick.title = "Switches (select with <space>)";
|
||||
}
|
||||
|
||||
this._quickPick.items = menu.items;
|
||||
}
|
||||
|
||||
show() {
|
||||
this._quickPick.show();
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import { ForcePushMode } from "../../../common/gitApiExtensions";
|
||||
|
||||
export interface PushingOutput {
|
||||
remote?: string;
|
||||
name?: string;
|
||||
setUpstream?: boolean;
|
||||
forcePushMode?: ForcePushMode;
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
import { Menu } from "../abstract/menu";
|
||||
import { MenuItem } from "../abstract/menuItem";
|
||||
import { PushingSwitches } from "./switches";
|
||||
|
||||
enum Items {
|
||||
Switches
|
||||
}
|
||||
|
||||
export class PushingMenu implements Menu {
|
||||
|
||||
title: string = "Pushing";
|
||||
items: MenuItem[];
|
||||
|
||||
constructor(remote?: string, upstream?: string) {
|
||||
// TODO: take in some state to customize and narrow selection!
|
||||
this.items = [{id: Items.Switches, label: "-", description: "Switches"}];
|
||||
}
|
||||
|
||||
onDidAcceptItems(acceptedItems: readonly MenuItem[]): Menu | undefined {
|
||||
|
||||
// Weak abstraction in this function
|
||||
let firstItem = acceptedItems[0];
|
||||
|
||||
switch (firstItem.id) {
|
||||
case Items.Switches:
|
||||
return new PushingSwitches();
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
import { Menu } from "../abstract/menu";
|
||||
import { MenuItem } from "../abstract/menuItem";
|
||||
import { MagitState } from "../../models/magitState";
|
||||
|
||||
enum Items {
|
||||
ForceWithLease,
|
||||
Force,
|
||||
DisableHooks,
|
||||
DryRun
|
||||
}
|
||||
|
||||
export class PushingSwitches implements Menu {
|
||||
|
||||
items: MenuItem[];
|
||||
isSwitchesMenu = true;
|
||||
|
||||
constructor() {
|
||||
this.items = [
|
||||
{ id: Items.ForceWithLease, label: "-f", description: "force with lease (--force-with-lease)" },
|
||||
{ id: Items.Force, label: "-F", description: "force (--force)" },
|
||||
{ id: Items.DisableHooks, label: "-h", description: "disable hooks (--no-verify)" },
|
||||
{ id: Items.DryRun, label: "-d", description: "Dry run (--dry-run)" },
|
||||
];
|
||||
}
|
||||
|
||||
onDidAcceptItems(acceptedItems: readonly MenuItem[]): Menu | undefined {
|
||||
|
||||
// Weak abstraction in this function
|
||||
let firstItem = acceptedItems[0];
|
||||
|
||||
switch (firstItem.id) {
|
||||
case Items.ForceWithLease:
|
||||
return undefined;
|
||||
case Items.Force:
|
||||
return undefined;
|
||||
case Items.DisableHooks:
|
||||
return undefined;
|
||||
case Items.DryRun:
|
||||
return undefined;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
import { Uri } from "vscode";
|
||||
|
||||
export interface MagitChangeHunk {
|
||||
diff: string;
|
||||
diffHeader: string;
|
||||
uri: Uri; // TODO: blir ikke brukt?
|
||||
}
|
@ -2,7 +2,7 @@ import { View } from "../general/view";
|
||||
import { MagitChange } from "../../models/magitChange";
|
||||
import { ChangeView } from "./changeView";
|
||||
import { Section, SectionHeaderView } from "../sectionHeader";
|
||||
import { LineBreakView } from "../lineBreakView";
|
||||
import { LineBreakView } from "../general/lineBreakView";
|
||||
|
||||
export class ChangeSectionView extends View {
|
||||
isFoldable = true;
|
||||
|
@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
// TODO: husk at alle keybindings virker her også. Akkurat som statusView
|
||||
|
||||
// Derfor må documentView sendes rundt
|
@ -1,9 +1,8 @@
|
||||
import { View } from "../general/view";
|
||||
import { Section, SectionHeaderView } from "../sectionHeader";
|
||||
import { LineBreakView } from "../lineBreakView";
|
||||
import { Stash } from "../../common/gitApiExtensions";
|
||||
import { TextView } from "../general/textView";
|
||||
import { Commit } from "../../typings/git";
|
||||
import { LineBreakView } from "../general/lineBreakView";
|
||||
|
||||
export class CommitSectionView extends View {
|
||||
isFoldable = true;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { TextView } from "./general/textView";
|
||||
import { TextView } from "./textView";
|
||||
|
||||
export class LineBreakView extends TextView {
|
||||
|
@ -7,7 +7,7 @@ import { StashSectionView } from './stashes/stashSectionView';
|
||||
import { CommitSectionView } from './commits/commitSectionView';
|
||||
import { BranchHeaderView } from './branches/branchHeaderView';
|
||||
import { TextView } from './general/textView';
|
||||
import { LineBreakView } from './lineBreakView';
|
||||
import { LineBreakView } from './general/lineBreakView';
|
||||
|
||||
export default class MagitStatusView extends DocumentView implements vscode.Disposable {
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { View } from "../general/view";
|
||||
import { Section, SectionHeaderView } from "../sectionHeader";
|
||||
import { LineBreakView } from "../lineBreakView";
|
||||
import { Stash } from "../../common/gitApiExtensions";
|
||||
import { TextView } from "../general/textView";
|
||||
import { LineBreakView } from "../general/lineBreakView";
|
||||
|
||||
export class StashSectionView extends View {
|
||||
isFoldable = true;
|
||||
|
Loading…
Reference in New Issue
Block a user