mirror of
https://github.com/kahole/edamagit.git
synced 2024-09-11 07:15:31 +03:00
doing work
This commit is contained in:
parent
6a4aa81e68
commit
bfdcf3e0ba
29
README.md
29
README.md
@ -4,7 +4,7 @@
|
||||
TAB on view toggles fold v unfold propert
|
||||
-> Trigger rerender
|
||||
Also much simpler to save and reload the folding state.
|
||||
|
||||
Makes everything else hard af
|
||||
----------
|
||||
### VSCode folding
|
||||
editor.foldLevel2 fixes a lot!
|
||||
@ -28,22 +28,24 @@ FIRST TIME OPENING: default fold levels
|
||||
- Stash zero levels
|
||||
- Recent commits zero levels
|
||||
|
||||
## BUGS (also remember MINOR FUTURE)
|
||||
## TODO: BUGS (also remember MINOR FUTURE)
|
||||
|
||||
Bug#2
|
||||
After commiting, sometimes another magit status window is next to the existing one.
|
||||
- How to reproduce? Never happens in debug, or?
|
||||
|
||||
Bug#3
|
||||
Section model is responsible for too much
|
||||
Must fix. Fine for deciding what section something is. But changes and hunks should use another enum, because it isnt one-to-one between them
|
||||
|
||||
## Feature requests
|
||||
Feature#1
|
||||
magit-dispatch-popup - from any file
|
||||
magit-file-popup
|
||||
- Staging
|
||||
- Log
|
||||
- Blaming
|
||||
|
||||
Also, make all commands available so long as there is an active editor.
|
||||
This means commands need to be able to handle no VIEW.
|
||||
This should really be no extra effort
|
||||
Might just need to prime a bit smarter?
|
||||
|
||||
## FUTURE: Eie egen modell
|
||||
Burde ikke extende git modellen kanskje.
|
||||
@ -52,7 +54,6 @@ med mappere i mellom?
|
||||
|
||||
## FUTURE: injection for repo etc?
|
||||
@command('magit.branching', { repository: true })
|
||||
|
||||
https://github.com/microsoft/vscode/blob/master/extensions/git/src/commands.ts
|
||||
|
||||
## Workspaces
|
||||
@ -60,11 +61,6 @@ https://github.com/microsoft/vscode/blob/master/extensions/git/src/commands.ts
|
||||
- Find out how to deal with status views and other views
|
||||
- Dispose of stuff when quit workspace etc..
|
||||
|
||||
## UI
|
||||
- icons
|
||||
https://code.visualstudio.com/api/references/icons-in-labels
|
||||
e.g $(git-branch)
|
||||
|
||||
## Dispose
|
||||
- Proper use of dispose()
|
||||
https://vscode-docs.readthedocs.io/en/stable/extensions/patterns-and-principles/#disposables
|
||||
@ -79,17 +75,16 @@ https://github.com/microsoft/vscode/blob/master/extensions/git/src/commands.ts
|
||||
o GPL2/3, MIT, etc
|
||||
o git.d.ts microsoft licence, effects?
|
||||
|
||||
- VsVim?
|
||||
Maybe.. Is it possible to disable VSVim for certain languages / file extensions / etc?
|
||||
|
||||
-----
|
||||
|
||||
## TODO: Release ALPHA, MVP
|
||||
# RELEASE ALPHA MVP
|
||||
|
||||
## Github sponsor skru på donasjoner på github?
|
||||
https://github.com/sponsors
|
||||
|
||||
# Magit for VSCode
|
||||
# Magit for VSCode (alpha)
|
||||
|
||||
!alpha: use at own your own risk ??
|
||||
|
||||
Inspired by the original (Magit)[https://magit.vc/] for Emacs
|
||||
|
||||
|
42
package.json
42
package.json
@ -11,7 +11,9 @@
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onCommand:extension.magit"
|
||||
"onCommand:extension.magit",
|
||||
"onCommand:extension.magit-dispatch",
|
||||
"onCommand:extension.magit-file-popup"
|
||||
],
|
||||
"main": "./out/extension.js",
|
||||
"contributes": {
|
||||
@ -20,6 +22,14 @@
|
||||
"command": "extension.magit",
|
||||
"title": "Magit Status"
|
||||
},
|
||||
{
|
||||
"command": "extension.magit-dispatch",
|
||||
"title": "Magit Dispatch"
|
||||
},
|
||||
{
|
||||
"command": "extension.magit-file-popup",
|
||||
"title": "Magit File Popup"
|
||||
},
|
||||
{
|
||||
"command": "extension.magit-visit-at-point",
|
||||
"title": "Magit Visit-at-point"
|
||||
@ -44,10 +54,18 @@
|
||||
"command": "extension.magit-merging",
|
||||
"title": "Magit Merging"
|
||||
},
|
||||
{
|
||||
"command": "extension.magit-rebasing",
|
||||
"title": "Magit Rebasing"
|
||||
},
|
||||
{
|
||||
"command": "extension.magit-pushing",
|
||||
"title": "Magit Pushing"
|
||||
},
|
||||
{
|
||||
"command": "extension.magit-pulling",
|
||||
"title": "Magit Pulling"
|
||||
},
|
||||
{
|
||||
"command": "extension.magit-stage",
|
||||
"title": "Magit Stage"
|
||||
@ -75,6 +93,10 @@
|
||||
],
|
||||
"menus": {
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "extension.magit-help",
|
||||
"when": "editorLangId == magit"
|
||||
},
|
||||
{
|
||||
"command": "extension.magit-branching",
|
||||
"when": "editorLangId == magit"
|
||||
@ -83,6 +105,10 @@
|
||||
"command": "extension.magit-merging",
|
||||
"when": "editorLangId == magit"
|
||||
},
|
||||
{
|
||||
"command": "extension.magit-rebasing",
|
||||
"when": "editorLangId == magit"
|
||||
},
|
||||
{
|
||||
"command": "extension.magit-visit-at-point",
|
||||
"when": "editorLangId == magit"
|
||||
@ -119,6 +145,10 @@
|
||||
"command": "extension.magit-pushing",
|
||||
"when": "editorLangId == magit"
|
||||
},
|
||||
{
|
||||
"command": "extension.magit-pulling",
|
||||
"when": "editorLangId == magit"
|
||||
},
|
||||
{
|
||||
"command": "extension.magit-stashing",
|
||||
"when": "editorLangId == magit"
|
||||
@ -150,6 +180,11 @@
|
||||
}
|
||||
],
|
||||
"keybindings": [
|
||||
{
|
||||
"command": "extension.magit",
|
||||
"key": "ctrl+x g",
|
||||
"when": "editorTextFocus"
|
||||
},
|
||||
{
|
||||
"command": "editor.toggleFold",
|
||||
"key": "tab",
|
||||
@ -195,6 +230,11 @@
|
||||
"key": "m",
|
||||
"when": "editorTextFocus && editorLangId == magit"
|
||||
},
|
||||
{
|
||||
"command": "extension.magit-rebasing",
|
||||
"key": "r",
|
||||
"when": "editorTextFocus && editorLangId == magit"
|
||||
},
|
||||
{
|
||||
"command": "extension.magit-pushing",
|
||||
"key": "shift+p",
|
||||
|
@ -3,7 +3,7 @@ import { MagitRepository } from '../models/magitRepository';
|
||||
import { TextEditor, window } from 'vscode';
|
||||
import { DocumentView } from '../views/general/documentView';
|
||||
|
||||
export class CommandPrimer {
|
||||
export class Command {
|
||||
|
||||
// static primeRepo(command: (repository: MagitRepository) => Promise<void>) {
|
||||
// return (editor: TextEditor) => {
|
||||
@ -26,9 +26,6 @@ export class CommandPrimer {
|
||||
await command(repository, currentView);
|
||||
} catch (error) {
|
||||
if (error.gitErrorCode) {
|
||||
// This needs to be cleared somehow as well?
|
||||
// Maybe it gets removed once it is rendered. So next render will not have it?
|
||||
// e.g: GitError! Your local changes to the following files would be overwritten by checkout
|
||||
repository.magitState!.latestGitError = error.stderr ?? error.message;
|
||||
} else {
|
||||
// This error type, too heavy for most errors?
|
||||
|
@ -26,14 +26,11 @@ export async function fetching(repository: MagitRepository, currentView: Documen
|
||||
|
||||
fetchingMenuItems.push({ label: 'o', description: 'another branch', action: fetchAnotherBranch });
|
||||
|
||||
// MINOR: more fetching options exist in magit
|
||||
// - explicit refspec
|
||||
// - submodules
|
||||
//fetchingMenuItems.push({ label: 'o', description: 'another branch', action: () => { } });
|
||||
|
||||
return MenuUtil.showMenu({ title: 'Fetching', commands: fetchingMenuItems }, { repository, currentView });
|
||||
}
|
||||
|
||||
// TODO: fetching: some work remains for MVP
|
||||
|
||||
async function fetchFromPushRemote() {
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import { DocumentView } from '../views/general/documentView';
|
||||
import { gitRun } from '../utils/gitRawRunner';
|
||||
import * as CommitCommands from '../commands/commitCommands';
|
||||
|
||||
// TODO: merging: some work remains for MVP
|
||||
|
||||
const mergingMenu = {
|
||||
title: 'Merging',
|
||||
commands: [
|
||||
@ -12,7 +14,7 @@ const mergingMenu = {
|
||||
{ label: 'e', description: 'Merge and edit message', action: merge },
|
||||
{ label: 'n', description: 'Merge, don\'t commit', action: merge },
|
||||
{ label: 'a', description: 'Absorb', action: absorb },
|
||||
{ label: 'p', description: 'Preview Merge', action: mergePreview },
|
||||
// { label: 'p', description: 'Preview Merge', action: mergePreview },
|
||||
{ label: 's', description: 'Squash Merge', action: merge },
|
||||
{ label: 's', description: 'Merge into', action: merge },
|
||||
]
|
||||
@ -52,12 +54,12 @@ async function absorb({ repository }: MenuState) {
|
||||
}
|
||||
}
|
||||
|
||||
async function mergePreview() {
|
||||
// Commands to preview a merge between ref1 and ref2:
|
||||
// git merge-base HEAD {ref2}
|
||||
// git merge-tree {MERGE-BASE} HEAD {ref2}
|
||||
// https://stackoverflow.com/questions/501407/is-there-a-git-merge-dry-run-option/6283843#6283843
|
||||
}
|
||||
// async function mergePreview() {
|
||||
// // Commands to preview a merge between ref1 and ref2:
|
||||
// // git merge-base HEAD {ref2}
|
||||
// // git merge-tree {MERGE-BASE} HEAD {ref2}
|
||||
// // https://stackoverflow.com/questions/501407/is-there-a-git-merge-dry-run-option/6283843#6283843
|
||||
// }
|
||||
|
||||
async function _merge(repository: MagitRepository, ref: string, noCommit = false, squashMerge = false, editMessage = false) {
|
||||
|
||||
|
89
src/commands/rebasingCommands.ts
Normal file
89
src/commands/rebasingCommands.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import { window, commands } from 'vscode';
|
||||
import { Menu, MenuState, MenuUtil } from '../menu/menu';
|
||||
import { MagitRepository } from '../models/magitRepository';
|
||||
import { DocumentView } from '../views/general/documentView';
|
||||
import { gitRun } from '../utils/gitRawRunner';
|
||||
import * as CommitCommands from '../commands/commitCommands';
|
||||
|
||||
// TODO: rebasing: some work remains for MVP
|
||||
|
||||
const whileRebasingMenu = {
|
||||
title: 'Rebasing',
|
||||
commands: [
|
||||
{ label: 'r', description: 'Continue', action: (state: MenuState) => rebaseControlCommand(state, '--continue') },
|
||||
{ label: 's', description: 'Skip', action: (state: MenuState) => rebaseControlCommand(state, '--skip') },
|
||||
{ label: 'e', description: 'Edit', action: (state: MenuState) => rebaseControlCommand(state, '--edit-todo') },
|
||||
{ label: 'a', description: 'Abort', action: (state: MenuState) => rebaseControlCommand(state, '--abort') }
|
||||
]
|
||||
};
|
||||
|
||||
export async function rebasing(repository: MagitRepository, currentView: DocumentView) {
|
||||
|
||||
const HEAD = repository.magitState?.HEAD;
|
||||
const rebasingMenu = {
|
||||
title: `Rebasing ${HEAD?.name}`,
|
||||
commands: [
|
||||
{ label: 'p', description: `onto ${HEAD?.pushRemote?.remote}/${HEAD?.pushRemote?.name}`, action: rebase },
|
||||
{ label: 'u', description: `onto ${HEAD?.upstreamRemote?.remote}/${HEAD?.upstreamRemote?.name}`, action: rebase },
|
||||
{ label: 'e', description: `onto elsewhere`, action: rebase },
|
||||
{ label: 'i', description: `interactively`, action: rebase },
|
||||
]
|
||||
};
|
||||
|
||||
if (repository.magitState?.rebasingState) {
|
||||
return MenuUtil.showMenu(whileRebasingMenu, { repository, currentView });
|
||||
} else {
|
||||
return MenuUtil.showMenu(rebasingMenu, { repository, currentView });
|
||||
}
|
||||
}
|
||||
|
||||
async function rebase({ repository }: MenuState) {
|
||||
const ref = await window.showQuickPick(repository.state.refs.map(r => r.name!), { placeHolder: 'Merge' });
|
||||
|
||||
if (ref) {
|
||||
return _merge(repository, ref);
|
||||
}
|
||||
}
|
||||
|
||||
async function absorb({ repository }: MenuState) {
|
||||
const ref = await window.showQuickPick(repository.state.refs.map(r => r.name!), { placeHolder: 'Merge' });
|
||||
|
||||
if (ref) {
|
||||
await _merge(repository, ref);
|
||||
return await repository.deleteBranch(ref, false);
|
||||
}
|
||||
}
|
||||
|
||||
async function mergePreview() {
|
||||
// Commands to preview a merge between ref1 and ref2:
|
||||
// git merge-base HEAD {ref2}
|
||||
// git merge-tree {MERGE-BASE} HEAD {ref2}
|
||||
// https://stackoverflow.com/questions/501407/is-there-a-git-merge-dry-run-option/6283843#6283843
|
||||
}
|
||||
|
||||
async function _merge(repository: MagitRepository, ref: string, noCommit = false, squashMerge = false, editMessage = false) {
|
||||
|
||||
const args = ['merge', ref];
|
||||
|
||||
if (noCommit) {
|
||||
args.push(...['--no-commit', '--no-ff']);
|
||||
}
|
||||
|
||||
if (squashMerge) {
|
||||
args.push('--squash');
|
||||
}
|
||||
|
||||
if (editMessage) {
|
||||
// TODO: This might need a separate handler, because of message editing??
|
||||
args.push(...['--edit', '--no-ff']);
|
||||
} else {
|
||||
args.push('--no-edit');
|
||||
}
|
||||
|
||||
return gitRun(repository, args);
|
||||
}
|
||||
|
||||
async function rebaseControlCommand({ repository }: MenuState, command: string) {
|
||||
const args = ['rebase', command];
|
||||
return gitRun(repository, args);
|
||||
}
|
@ -11,10 +11,11 @@ import { MagitBranch } from '../models/magitBranch';
|
||||
import { Section } from '../views/general/sectionHeader';
|
||||
import { gitRun } from '../utils/gitRawRunner';
|
||||
import * as Constants from '../common/constants';
|
||||
import { getCommit } from '../utils/commitCache';
|
||||
|
||||
export async function magitRefresh() { }
|
||||
|
||||
export async function magitStatus(preserveFocus = false) {
|
||||
export async function magitStatus(preserveFocus = false): Promise<any> {
|
||||
|
||||
if (window.activeTextEditor) {
|
||||
|
||||
@ -42,9 +43,8 @@ export async function magitStatus(preserveFocus = false) {
|
||||
// Open and focus magit status view
|
||||
// Run update
|
||||
await MagitUtils.magitStatusAndUpdate(repository, view);
|
||||
workspace.openTextDocument(view.uri).then(doc => window.showTextDocument(doc, { viewColumn: ViewColumn.Beside, preserveFocus, preview: false }));
|
||||
console.log('Update existing view');
|
||||
return;
|
||||
return workspace.openTextDocument(view.uri).then(doc => window.showTextDocument(doc, { viewColumn: ViewColumn.Beside, preserveFocus, preview: false }));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -56,35 +56,39 @@ export async function magitStatus(preserveFocus = false) {
|
||||
const magitRepo: MagitRepository = repository;
|
||||
magitRepositories.set(repository.rootUri.path, repository);
|
||||
|
||||
internalMagitStatus(magitRepo)
|
||||
.then(() => {
|
||||
const uri = MagitStatusView.encodeLocation(magitRepo.rootUri.path);
|
||||
views.set(uri.toString(), new MagitStatusView(uri, magitRepo.magitState!));
|
||||
workspace.openTextDocument(uri).then(doc => window.showTextDocument(doc, { viewColumn: ViewColumn.Beside, preserveFocus, preview: false }))
|
||||
await internalMagitStatus(magitRepo);
|
||||
|
||||
// TODO LATE PRI: branch highlighting...
|
||||
// THIS WORKS
|
||||
// Decorations could be added by the views in the view hierarchy?
|
||||
// yes as we go down the hierarchy make these decorations at exactly the points wanted
|
||||
// and should be pretty simple to collect them and set the editors decorations
|
||||
// needs something super smart.. https://github.com/Microsoft/vscode/issues/585
|
||||
// .then(e => e.setDecorations(
|
||||
// window.createTextEditorDecorationType({
|
||||
// color: 'rgba(100,200,100,0.5)',
|
||||
// border: '0.1px solid grey'
|
||||
// }), [new Range(0, 11, 0, 17)]))
|
||||
// MINOR: clean up all of this
|
||||
.then(() => {
|
||||
return commands.executeCommand('editor.foldLevel2');
|
||||
});
|
||||
const uri = MagitStatusView.encodeLocation(magitRepo.rootUri.path);
|
||||
views.set(uri.toString(), new MagitStatusView(uri, magitRepo.magitState!));
|
||||
|
||||
return workspace.openTextDocument(uri).then(doc => window.showTextDocument(doc, { viewColumn: ViewColumn.Beside, preserveFocus, preview: false }))
|
||||
|
||||
// TODO LATE PRI: branch highlighting...
|
||||
// THIS WORKS
|
||||
// Decorations could be added by the views in the view hierarchy?
|
||||
// yes as we go down the hierarchy make these decorations at exactly the points wanted
|
||||
// and should be pretty simple to collect them and set the editors decorations
|
||||
// needs something super smart.. https://github.com/Microsoft/vscode/issues/585
|
||||
// .then(e => e.setDecorations(
|
||||
// window.createTextEditorDecorationType({
|
||||
// color: 'rgba(100,200,100,0.5)',
|
||||
// border: '0.1px solid grey'
|
||||
// }), [new Range(0, 11, 0, 17)]))
|
||||
// MINOR: clean up all of this
|
||||
.then(() => {
|
||||
return commands.executeCommand('editor.foldLevel2');
|
||||
});
|
||||
|
||||
} else {
|
||||
// Prompt to create repo
|
||||
await commands.executeCommand('git.init');
|
||||
magitStatus();
|
||||
const newRepo = await commands.executeCommand('git.init');
|
||||
if (newRepo) {
|
||||
return magitStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// MINOR: could be nice to rather show the list of repos to choose from?
|
||||
throw new Error('Current file not part of a workspace');
|
||||
}
|
||||
}
|
||||
@ -166,78 +170,73 @@ export async function internalMagitStatus(repository: MagitRepository): Promise<
|
||||
|
||||
const rebaseHeadNamePath = Uri.parse(dotGitPath + 'rebase-apply/head-name');
|
||||
const rebaseOntoPath = Uri.parse(dotGitPath + 'rebase-apply/onto');
|
||||
const rebaseHeadNameFileTask = repository.state.rebaseCommit ? workspace.fs.readFile(rebaseHeadNamePath).then(f => f.toString().replace(Constants.FinalLineBreakRegex, '')) : undefined;
|
||||
const rebaseOntoPathFileTask = repository.state.rebaseCommit ? workspace.fs.readFile(rebaseOntoPath).then(f => f.toString().replace(Constants.FinalLineBreakRegex, '')) : undefined;
|
||||
|
||||
const rebaseCommitListTask = repository.state.rebaseCommit ? workspace.fs.readFile(Uri.parse(dotGitPath + 'rebase-apply/last')).then(f => f.toString().replace(Constants.FinalLineBreakRegex, '')).then(Number.parseInt)
|
||||
.then(last => Promise.all(Array.from(Array(last).keys()).map(
|
||||
index => workspace.fs.readFile(Uri.parse(dotGitPath + 'rebase-apply/' + (index + 1).toString().padStart(4, '0'))).then(f => f.toString().replace(Constants.FinalLineBreakRegex, ''))
|
||||
.then(GitTextUtils.commitDetailTextToCommit)
|
||||
))) : undefined;
|
||||
let rebaseHeadNameFileTask: Thenable<string>;
|
||||
let rebaseOntoPathFileTask: Thenable<string>;
|
||||
let rebaseCommitListTask: Thenable<Commit[]> | undefined = undefined;
|
||||
let rebaseNextIndex: number = 0;
|
||||
|
||||
if (repository.state.rebaseCommit) {
|
||||
rebaseHeadNameFileTask = workspace.fs.readFile(rebaseHeadNamePath).then(f => f.toString().replace(Constants.FinalLineBreakRegex, ''));
|
||||
rebaseOntoPathFileTask = workspace.fs.readFile(rebaseOntoPath).then(f => f.toString().replace(Constants.FinalLineBreakRegex, ''));
|
||||
|
||||
const rebaseLastIndexTask = workspace.fs.readFile(Uri.parse(dotGitPath + 'rebase-apply/last')).then(f => f.toString().replace(Constants.FinalLineBreakRegex, '')).then(Number.parseInt);
|
||||
rebaseNextIndex = await workspace.fs.readFile(Uri.parse(dotGitPath + 'rebase-apply/next')).then(f => f.toString().replace(Constants.FinalLineBreakRegex, '')).then(Number.parseInt);
|
||||
|
||||
const indices: number[] = [];
|
||||
|
||||
for (let i = await rebaseLastIndexTask; i > rebaseNextIndex; i--) {
|
||||
indices.push(i);
|
||||
}
|
||||
|
||||
rebaseCommitListTask =
|
||||
Promise.all(
|
||||
indices.map(
|
||||
index => workspace.fs.readFile(Uri.parse(dotGitPath + 'rebase-apply/' + index.toString().padStart(4, '0'))).then(f => f.toString().replace(Constants.FinalLineBreakRegex, ''))
|
||||
.then(GitTextUtils.commitDetailTextToCommit)
|
||||
));
|
||||
}
|
||||
|
||||
// TODO: drop the interesting commit thing?
|
||||
const commitTasks = Promise.all(
|
||||
interestingCommits
|
||||
.map(c => repository.getCommit(c)));
|
||||
.map(c => getCommit(repository, c)));
|
||||
|
||||
|
||||
//TODO: await stuff only where its needed?
|
||||
|
||||
const [commits, workingTreeChanges, indexChanges, mergeChanges, stashes, log] =
|
||||
await Promise.all([
|
||||
commitTasks,
|
||||
workingTreeChangesTasks,
|
||||
indexChangesTasks,
|
||||
mergeChangesTasks,
|
||||
stashTask,
|
||||
logTask
|
||||
]);
|
||||
|
||||
// TODO: load details about the merging commits, ONLY if there is a mergingState !
|
||||
// make a nice chain of commands that can be awaited for, like the ones above.
|
||||
let mergingState;
|
||||
try {
|
||||
mergingState =
|
||||
await Promise.all([
|
||||
mergeHeadFileTask,
|
||||
mergeMsgFileTask
|
||||
])
|
||||
.then(([mergeHeadFile, mergeMsgFile]) => (GitTextUtils.parseMergeStatus(mergeHeadFile, mergeMsgFile)));
|
||||
const parsedMergeState = GitTextUtils.parseMergeStatus(await mergeHeadFileTask, await mergeMsgFileTask);
|
||||
|
||||
if (parsedMergeState) {
|
||||
const [mergeCommits, mergingBranches] = parsedMergeState;
|
||||
mergingState = {
|
||||
mergingBranches,
|
||||
commits: await Promise.all(mergeCommits.map(c => getCommit(repository, c)))
|
||||
};
|
||||
}
|
||||
} catch { }
|
||||
|
||||
const log = await logTask;
|
||||
|
||||
let rebasingState;
|
||||
if (repository.state.rebaseCommit) {
|
||||
const ontoCommit = await rebaseOntoPathFileTask!;
|
||||
|
||||
const ontoBranch = repository.state.refs.find(ref => ref.commit === ontoCommit && ref.type !== RefType.RemoteHead) as MagitBranch;
|
||||
const ontoCommit = await getCommit(repository, await rebaseOntoPathFileTask!);
|
||||
|
||||
const rebaseCommits = await rebaseCommitListTask;
|
||||
const ontoBranch = repository.state.refs.find(ref => ref.commit === ontoCommit.hash && ref.type !== RefType.RemoteHead) as MagitBranch;
|
||||
ontoBranch.commitDetails = ontoCommit;
|
||||
|
||||
const doneCommits: Commit[] = [];
|
||||
const upcomingCommits: Commit[] = [];
|
||||
|
||||
let pastCurrent = false;
|
||||
for (const c of rebaseCommits ?? []) {
|
||||
if (c.hash === repository.state.rebaseCommit.hash) {
|
||||
pastCurrent = true;
|
||||
} else if (pastCurrent) {
|
||||
upcomingCommits.push(c);
|
||||
} else {
|
||||
doneCommits.push(c);
|
||||
}
|
||||
}
|
||||
const doneCommits: Commit[] = log.slice(0, rebaseNextIndex - 1);
|
||||
const upcomingCommits: Commit[] = (await rebaseCommitListTask) ?? [];
|
||||
|
||||
rebasingState = {
|
||||
currentCommit: repository.state.rebaseCommit,
|
||||
origBranchName: await rebaseHeadNameFileTask!,
|
||||
origBranchName: (await rebaseHeadNameFileTask!).split('/')[2],
|
||||
ontoBranch,
|
||||
doneCommits,
|
||||
upcomingCommits
|
||||
};
|
||||
}
|
||||
|
||||
const commitMap: { [id: string]: Commit; } = commits.reduce((prev, commit) => ({ ...prev, [commit.hash]: commit }), {});
|
||||
const commitMap: { [id: string]: Commit; } = (await commitTasks).reduce((prev, commit) => ({ ...prev, [commit.hash]: commit }), {});
|
||||
|
||||
const HEAD = repository.state.HEAD as MagitBranch | undefined;
|
||||
|
||||
@ -251,8 +250,23 @@ export async function internalMagitStatus(repository: MagitRepository): Promise<
|
||||
|
||||
// MINOR: clean up?
|
||||
try {
|
||||
const remote = await repository.getConfig(`branch.${HEAD.name}.pushRemote`);
|
||||
HEAD.pushRemote = { remote, name: HEAD!.name! };
|
||||
const pushRemote = await repository.getConfig(`branch.${HEAD.name}.pushRemote`);
|
||||
|
||||
const upstreamRemote = HEAD.upstream?.remote;
|
||||
|
||||
const upstreamRemoteCommit = repository.state.refs.find(ref => ref.remote === upstreamRemote && ref.name === `${upstreamRemote}/${HEAD.upstream?.name}`)?.commit;
|
||||
const upstreamRemoteCommitDetails = upstreamRemoteCommit ? getCommit(repository, upstreamRemoteCommit) : undefined;
|
||||
|
||||
const pushRemoteCommit = repository.state.refs.find(ref => ref.remote === pushRemote && ref.name === `${pushRemote}/${HEAD.name}`)?.commit;
|
||||
const pushRemoteCommitDetails = pushRemoteCommit ? getCommit(repository, pushRemoteCommit) : undefined;
|
||||
|
||||
HEAD.pushRemote = { remote: pushRemote, name: HEAD.name!, commit: await pushRemoteCommitDetails };
|
||||
|
||||
if (HEAD.upstream) {
|
||||
HEAD.upstreamRemote = HEAD.upstream;
|
||||
HEAD.upstreamRemote.commit = await upstreamRemoteCommitDetails;
|
||||
|
||||
}
|
||||
} catch { }
|
||||
}
|
||||
|
||||
@ -263,11 +277,11 @@ export async function internalMagitStatus(repository: MagitRepository): Promise<
|
||||
|
||||
repository.magitState = {
|
||||
HEAD,
|
||||
stashes,
|
||||
stashes: await stashTask,
|
||||
log,
|
||||
workingTreeChanges,
|
||||
indexChanges,
|
||||
mergeChanges,
|
||||
workingTreeChanges: await workingTreeChangesTasks,
|
||||
indexChanges: await indexChangesTasks,
|
||||
mergeChanges: await mergeChangesTasks,
|
||||
untrackedFiles,
|
||||
rebasingState,
|
||||
mergingState,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { workspace, extensions, commands, ExtensionContext, Disposable, languages } from 'vscode';
|
||||
import { workspace, extensions, commands, ExtensionContext, Disposable, languages, window } from 'vscode';
|
||||
import ContentProvider from './providers/contentProvider';
|
||||
import { GitExtension, API } from './typings/git';
|
||||
import { pushing } from './commands/pushingCommands';
|
||||
@ -12,7 +12,7 @@ import { magitStage, magitStageAll, magitUnstageAll, magitUnstage } from './comm
|
||||
import { saveClose } from './commands/macros';
|
||||
import FoldingRangeProvider from './providers/foldingRangeProvider';
|
||||
import HighlightProvider from './providers/highlightProvider';
|
||||
import { CommandPrimer } from './commands/commandPrimer';
|
||||
import { Command } from './commands/commandPrimer';
|
||||
import * as Constants from './common/constants';
|
||||
import { fetching } from './commands/fetchingCommands';
|
||||
import { pulling } from './commands/pullingCommands';
|
||||
@ -21,6 +21,7 @@ import { DocumentView } from './views/general/documentView';
|
||||
import { magitApplyEntityAtPoint } from './commands/applyCommands';
|
||||
import { magitDiscardAtPoint } from './commands/discardCommands';
|
||||
import { merging } from './commands/mergingCommands';
|
||||
import { rebasing } from './commands/rebasingCommands';
|
||||
|
||||
export const magitRepositories: Map<string, MagitRepository> = new Map<string, MagitRepository>();
|
||||
export const views: Map<string, DocumentView> = new Map<string, DocumentView>();
|
||||
@ -56,28 +57,43 @@ export function activate(context: ExtensionContext) {
|
||||
);
|
||||
|
||||
context.subscriptions.push(commands.registerCommand('extension.magit', magitStatus));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-refresh', CommandPrimer.primeRepoAndView(magitRefresh)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-commit', CommandPrimer.primeRepoAndView(magitCommit)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-visit-at-point', CommandPrimer.primeRepoAndView(magitVisitAtPoint, false)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-apply-at-point', CommandPrimer.primeRepoAndView(magitApplyEntityAtPoint)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-discard-at-point', CommandPrimer.primeRepoAndView(magitDiscardAtPoint)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-refresh', Command.primeRepoAndView(magitRefresh)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-commit', Command.primeRepoAndView(magitCommit)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-visit-at-point', Command.primeRepoAndView(magitVisitAtPoint, false)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-apply-at-point', Command.primeRepoAndView(magitApplyEntityAtPoint)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-discard-at-point', Command.primeRepoAndView(magitDiscardAtPoint)));
|
||||
|
||||
context.subscriptions.push(commands.registerCommand('extension.magit-help', magitHelp));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-pulling', CommandPrimer.primeRepoAndView(pulling)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-pushing', CommandPrimer.primeRepoAndView(pushing)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-stashing', CommandPrimer.primeRepoAndView(stashing)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-pulling', Command.primeRepoAndView(pulling)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-pushing', Command.primeRepoAndView(pushing)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-stashing', Command.primeRepoAndView(stashing)));
|
||||
|
||||
context.subscriptions.push(commands.registerCommand('extension.magit-fetching', fetching));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-branching', CommandPrimer.primeRepoAndView(branching)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-merging', CommandPrimer.primeRepoAndView(merging)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-stage', CommandPrimer.primeRepoAndView(magitStage)));
|
||||
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)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-fetching', Command.primeRepoAndView(fetching)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-branching', Command.primeRepoAndView(branching)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-merging', Command.primeRepoAndView(merging)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-rebasing', Command.primeRepoAndView(rebasing)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-stage', Command.primeRepoAndView(magitStage)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-stage-all', Command.primeRepoAndView(magitStageAll)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-unstage', Command.primeRepoAndView(magitUnstage)));
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-unstage-all', Command.primeRepoAndView(magitUnstageAll)));
|
||||
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-file-popup', (textEditor) => {
|
||||
const file = textEditor.document.uri.fsPath;
|
||||
|
||||
// TODO: refactor and show menu
|
||||
window.showInformationMessage(file);
|
||||
|
||||
}));
|
||||
|
||||
context.subscriptions.push(commands.registerTextEditorCommand('extension.magit-dispatch', async () => {
|
||||
// MINOR: this command should be usable without needing to pull up the status view
|
||||
await magitStatus();
|
||||
return magitHelp();
|
||||
}));
|
||||
|
||||
context.subscriptions.push(commands.registerCommand('extension.magit-save-and-close-commit-msg', saveClose));
|
||||
}
|
||||
|
||||
export function deactivate() {
|
||||
// clean up? views, repositories etc??
|
||||
// MINOR: clean up? views, repositories etc??
|
||||
}
|
||||
|
@ -33,7 +33,15 @@ export class MenuUtil {
|
||||
|
||||
_quickPick.items = menu.commands;
|
||||
|
||||
// Select with single key stroke
|
||||
|
||||
const eventListenerDisposable = _quickPick.onDidChangeValue(async (e) => {
|
||||
if (_quickPick.value === 'q') {
|
||||
_quickPick.dispose();
|
||||
eventListenerDisposable.dispose();
|
||||
acceptListenerDisposable.dispose();
|
||||
resolve();
|
||||
}
|
||||
const chosenItems = _quickPick.activeItems.filter(i => i.label === _quickPick.value);
|
||||
_quickPick.value = '';
|
||||
_quickPick.dispose();
|
||||
@ -47,7 +55,7 @@ export class MenuUtil {
|
||||
}
|
||||
});
|
||||
|
||||
// Keep both of these (Select with key or with arrows + enter)
|
||||
// Select with key or with arrows + enter
|
||||
|
||||
const acceptListenerDisposable = _quickPick.onDidAccept(async () => {
|
||||
|
||||
|
@ -2,8 +2,13 @@ import { Branch, Commit, UpstreamRef, Ref } from '../typings/git';
|
||||
|
||||
export interface MagitBranch extends Branch {
|
||||
commitDetails: Commit;
|
||||
pushRemote?: UpstreamRef;
|
||||
upstreamRemote: MagitUpstreamRef;
|
||||
pushRemote?: MagitUpstreamRef;
|
||||
commitsAhead?: Commit[];
|
||||
commitsBehind?: Commit[];
|
||||
tag?: Ref;
|
||||
}
|
||||
|
||||
export interface MagitUpstreamRef extends UpstreamRef {
|
||||
commit?: Commit;
|
||||
}
|
11
src/utils/commitCache.ts
Normal file
11
src/utils/commitCache.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Commit } from '../typings/git';
|
||||
import { MagitRepository } from '../models/magitRepository';
|
||||
|
||||
const commitCache: { [hash: string]: Commit; } = {};
|
||||
|
||||
export async function getCommit(repository: MagitRepository, hash: string) {
|
||||
return commitCache[hash] ?? repository.getCommit(hash).then(c => {
|
||||
commitCache[c.hash] = c;
|
||||
return c;
|
||||
});
|
||||
}
|
@ -19,18 +19,17 @@ export default class GitTextUtils {
|
||||
.map(hunkText => ({ diff: hunkText, diffHeader, uri, section }));
|
||||
}
|
||||
|
||||
public static parseMergeStatus(mergeHashes: string, mergeMessage: string): MagitMergingState | undefined {
|
||||
public static parseMergeStatus(mergeHashes: string, mergeMessage: string): [string[], string[]] | undefined {
|
||||
|
||||
const mergingBranches = mergeMessage.match(/'(.*?)'/g)
|
||||
?.map(b => b.slice(1, b.length - 1));
|
||||
|
||||
const commits = mergeHashes
|
||||
.replace(Constants.FinalLineBreakRegex, '')
|
||||
.split(Constants.LineSplitterRegex)
|
||||
.map(c => ({ hash: c, message: '', parents: [] }));
|
||||
.split(Constants.LineSplitterRegex);
|
||||
|
||||
if (mergingBranches) {
|
||||
return { commits, mergingBranches };
|
||||
return [commits, mergingBranches];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ export class BranchSectionView extends View {
|
||||
this.addSubview(new BranchHeaderView('Head', HEAD));
|
||||
|
||||
if (HEAD.upstream) {
|
||||
this.addSubview(new RemoteBranchHeaderView('Merge', HEAD.upstream));
|
||||
this.addSubview(new RemoteBranchHeaderView('Merge', HEAD.upstreamRemote));
|
||||
}
|
||||
|
||||
if (HEAD.pushRemote) {
|
||||
|
@ -1,15 +1,11 @@
|
||||
import { TextView } from '../general/textView';
|
||||
import { UpstreamRef } from '../../typings/git';
|
||||
import { MagitUpstreamRef } from '../../models/magitBranch';
|
||||
|
||||
export class RemoteBranchHeaderView extends TextView {
|
||||
|
||||
constructor(name: string, upstreamRef: UpstreamRef) {
|
||||
constructor(name: string, upstreamRef: MagitUpstreamRef) {
|
||||
super();
|
||||
// TODO: ${upstreamRef.commit.message}
|
||||
// repository.state.refs INNEHOLDER commit hashen for f.eks refs: [{ name: 'origin/master', commit: 'blabla'}]
|
||||
// LOSNING: MagitBranch blir egen model. Ikke noe arv fra noe den git modellen.
|
||||
// GitTextUtils.shortCommitMessage(
|
||||
const nameLabel = `${name}:`.padEnd(10);
|
||||
this.textContent = `${nameLabel}${upstreamRef.remote}/${upstreamRef.name}`;
|
||||
this.textContent = `${nameLabel}${upstreamRef.remote}/${upstreamRef.name} ${upstreamRef.commit?.message}`;
|
||||
}
|
||||
}
|
@ -20,8 +20,8 @@ export class CommitSectionView extends View {
|
||||
|
||||
export class CommitItemView extends TextView {
|
||||
|
||||
constructor(public commit: Commit) {
|
||||
constructor(public commit: Commit, qualifier?: string) {
|
||||
super();
|
||||
this.textContent = `${GitTextUtils.shortHash(commit.hash)} ${GitTextUtils.shortCommitMessage(commit.message)}`;
|
||||
this.textContent = `${qualifier ? qualifier + ' ' : ''}${GitTextUtils.shortHash(commit.hash)} ${GitTextUtils.shortCommitMessage(commit.message)}`;
|
||||
}
|
||||
}
|
3
src/views/logView.ts
Normal file
3
src/views/logView.ts
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
// TODO: log view
|
@ -14,6 +14,7 @@ import { MergingSectionView } from './merging/mergingSectionView';
|
||||
import { UnsourcedCommitSectionView } from './commits/unsourcedCommitsSectionView';
|
||||
import { MagitRepository } from '../models/magitRepository';
|
||||
import GitTextUtils from '../utils/gitTextUtils';
|
||||
import { RebasingSectionView } from './rebasing/rebasingSectionView';
|
||||
|
||||
export default class MagitStatusView extends DocumentView {
|
||||
|
||||
@ -41,25 +42,8 @@ export default class MagitStatusView extends DocumentView {
|
||||
this.addSubview(new MergingSectionView(magitState.mergingState));
|
||||
}
|
||||
|
||||
// TODO: Rebasing status
|
||||
// Data location:
|
||||
//
|
||||
// index of next commit in rebase:
|
||||
// .git/rebase-apply/next
|
||||
//
|
||||
|
||||
if (magitState.rebasingState) {
|
||||
// TODO: refactor into own view
|
||||
this.addSubview(
|
||||
new TextView(`Rebasing ${magitState.rebasingState.origBranchName} onto ${magitState.rebasingState.ontoBranch.name}`),
|
||||
...magitState.rebasingState.upcomingCommits.map(c => new CommitItemView(c)),
|
||||
new TextView(`join ${GitTextUtils.shortHash(magitState.rebasingState.currentCommit.hash)} ${GitTextUtils.shortCommitMessage(magitState.rebasingState.currentCommit.message)}`),
|
||||
// TODO: Wrong order, wrong hashes! fix in data steps
|
||||
...magitState.rebasingState.doneCommits.map(c => new CommitItemView(c)),
|
||||
new TextView(`done ${GitTextUtils.shortHash(magitState.HEAD?.commitDetails.hash)} ${GitTextUtils.shortCommitMessage(magitState.HEAD?.commitDetails.message)}`),
|
||||
new TextView(`onto ${GitTextUtils.shortHash(magitState.rebasingState.ontoBranch.commit)} ${GitTextUtils.shortCommitMessage(magitState.rebasingState.ontoBranch.commitDetails?.message)}`),
|
||||
new LineBreakView()
|
||||
);
|
||||
this.addSubview(new RebasingSectionView(magitState.rebasingState));
|
||||
}
|
||||
|
||||
if (magitState.untrackedFiles.length) {
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { View } from '../general/view';
|
||||
import { Section, SectionHeaderView } from '../general/sectionHeader';
|
||||
import { Stash } from '../../common/gitApiExtensions';
|
||||
import { TextView } from '../general/textView';
|
||||
import { LineBreakView } from '../general/lineBreakView';
|
||||
import { MagitMergingState } from '../../models/magitMergingState';
|
||||
|
23
src/views/rebasing/rebasingSectionView.ts
Normal file
23
src/views/rebasing/rebasingSectionView.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { View } from '../general/view';
|
||||
import { Section, SectionHeaderView } from '../general/sectionHeader';
|
||||
import { TextView } from '../general/textView';
|
||||
import { LineBreakView } from '../general/lineBreakView';
|
||||
import { CommitItemView } from '../commits/commitSectionView';
|
||||
import { MagitRebasingState } from '../../models/magitRebasingState';
|
||||
import GitTextUtils from '../../utils/gitTextUtils';
|
||||
|
||||
export class RebasingSectionView extends View {
|
||||
isFoldable = true;
|
||||
|
||||
constructor(rebasingState: MagitRebasingState) {
|
||||
super();
|
||||
this.subViews = [
|
||||
new TextView(`Rebasing ${rebasingState.origBranchName} onto ${rebasingState.ontoBranch.name}`),
|
||||
...rebasingState.upcomingCommits.map(c => new CommitItemView(c, 'pick')),
|
||||
new CommitItemView(rebasingState.currentCommit, 'join'),
|
||||
...rebasingState.doneCommits.map(c => new CommitItemView(c, 'done')),
|
||||
new CommitItemView(rebasingState.ontoBranch.commitDetails, 'onto'),
|
||||
new LineBreakView()
|
||||
];
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user