Merge branch 'release/v2025.25'
@@ -12,7 +12,6 @@ indent_style = space
|
||||
indent_size = 4
|
||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||
tab_width = 4
|
||||
end_of_line = crlf
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||
|
||||
14
.github/workflows/build.yml
vendored
@@ -7,10 +7,10 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- name : Windows x64
|
||||
os: windows-2019
|
||||
os: windows-2022
|
||||
runtime: win-x64
|
||||
- name : Windows ARM64
|
||||
os: windows-2019
|
||||
os: windows-2022
|
||||
runtime: win-arm64
|
||||
- name : macOS (Intel)
|
||||
os: macos-13
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
container: ${{ matrix.container || '' }}
|
||||
steps:
|
||||
- name: Install common CLI tools
|
||||
if: ${{ startsWith(matrix.runtime, 'linux-') }}
|
||||
if: startsWith(matrix.runtime, 'linux-')
|
||||
run: |
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
- name: Configure arm64 packages
|
||||
if: ${{ matrix.runtime == 'linux-arm64' }}
|
||||
if: matrix.runtime == 'linux-arm64'
|
||||
run: |
|
||||
sudo dpkg --add-architecture arm64
|
||||
echo 'deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ focal main restricted
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
sudo sed -i -e 's/^deb http/deb [arch=amd64] http/g' /etc/apt/sources.list
|
||||
sudo sed -i -e 's/^deb mirror/deb [arch=amd64] mirror/g' /etc/apt/sources.list
|
||||
- name: Install cross-compiling dependencies
|
||||
if: ${{ matrix.runtime == 'linux-arm64' }}
|
||||
if: matrix.runtime == 'linux-arm64'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y llvm gcc-aarch64-linux-gnu
|
||||
@@ -64,10 +64,10 @@ jobs:
|
||||
- name: Publish
|
||||
run: dotnet publish src/SourceGit.csproj -c Release -o publish -r ${{ matrix.runtime }}
|
||||
- name: Rename executable file
|
||||
if: ${{ startsWith(matrix.runtime, 'linux-') }}
|
||||
if: startsWith(matrix.runtime, 'linux-')
|
||||
run: mv publish/SourceGit publish/sourcegit
|
||||
- name: Tar artifact
|
||||
if: ${{ startsWith(matrix.runtime, 'linux-') || startsWith(matrix.runtime, 'osx-') }}
|
||||
if: startsWith(matrix.runtime, 'linux-') || startsWith(matrix.runtime, 'osx-')
|
||||
run: |
|
||||
tar -cvf "sourcegit.${{ matrix.runtime }}.tar" -C publish .
|
||||
rm -r publish/*
|
||||
|
||||
22
.github/workflows/format-check.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Format Check
|
||||
on:
|
||||
push:
|
||||
branches: [ develop ]
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
format-check:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
|
||||
- name: Run formatting check
|
||||
run: dotnet format --verify-no-changes
|
||||
2
.github/workflows/package.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
jobs:
|
||||
windows:
|
||||
name: Package Windows
|
||||
runs-on: windows-2019
|
||||
runs-on: windows-2022
|
||||
strategy:
|
||||
matrix:
|
||||
runtime: [ win-x64, win-arm64 ]
|
||||
|
||||
@@ -152,6 +152,7 @@ This app supports open repository in external tools listed in the table below.
|
||||
| Visual Studio Code | YES | YES | YES |
|
||||
| Visual Studio Code - Insiders | YES | YES | YES |
|
||||
| VSCodium | YES | YES | YES |
|
||||
| Cursor | YES | YES | YES |
|
||||
| Fleet | YES | YES | YES |
|
||||
| Sublime Text | YES | YES | YES |
|
||||
| Zed | NO | YES | YES |
|
||||
|
||||
@@ -18,6 +18,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{
|
||||
.github\workflows\package.yml = .github\workflows\package.yml
|
||||
.github\workflows\release.yml = .github\workflows\release.yml
|
||||
.github\workflows\localization-check.yml = .github\workflows\localization-check.yml
|
||||
.github\workflows\format-check.yml = .github\workflows\format-check.yml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{49A7C2D6-558C-4FAA-8F5D-EEE81497AED7}"
|
||||
|
||||
201
TRANSLATION.md
@@ -6,11 +6,62 @@ This document shows the translation status of each locale file in the repository
|
||||
|
||||
### 
|
||||
|
||||
### 
|
||||
### 
|
||||
|
||||
### 
|
||||
<details>
|
||||
<summary>Missing keys in de_DE.axaml</summary>
|
||||
|
||||
### 
|
||||
- Text.ChangeSubmoduleUrl
|
||||
- Text.ChangeSubmoduleUrl.Submodule
|
||||
- Text.ChangeSubmoduleUrl.URL
|
||||
- Text.CommitCM.CopyCommitMessage
|
||||
- Text.MoveSubmodule
|
||||
- Text.MoveSubmodule.MoveTo
|
||||
- Text.MoveSubmodule.Submodule
|
||||
- Text.SetSubmoduleBranch
|
||||
- Text.SetSubmoduleBranch.Submodule
|
||||
- Text.SetSubmoduleBranch.Current
|
||||
- Text.SetSubmoduleBranch.New
|
||||
- Text.SetSubmoduleBranch.New.Tip
|
||||
- Text.Submodule.Branch
|
||||
- Text.Submodule.Histories
|
||||
- Text.Submodule.Move
|
||||
- Text.Submodule.SetBranch
|
||||
- Text.Submodule.SetURL
|
||||
- Text.Submodule.Update
|
||||
|
||||
</details>
|
||||
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in es_ES.axaml</summary>
|
||||
|
||||
- Text.ChangeSubmoduleUrl
|
||||
- Text.ChangeSubmoduleUrl.Submodule
|
||||
- Text.ChangeSubmoduleUrl.URL
|
||||
- Text.CommitCM.CopyCommitMessage
|
||||
- Text.ConfigureCustomActionControls.Options
|
||||
- Text.ConfigureCustomActionControls.Options.Tip
|
||||
- Text.DirHistories
|
||||
- Text.MoveSubmodule
|
||||
- Text.MoveSubmodule.MoveTo
|
||||
- Text.MoveSubmodule.Submodule
|
||||
- Text.SetSubmoduleBranch
|
||||
- Text.SetSubmoduleBranch.Submodule
|
||||
- Text.SetSubmoduleBranch.Current
|
||||
- Text.SetSubmoduleBranch.New
|
||||
- Text.SetSubmoduleBranch.New.Tip
|
||||
- Text.Submodule.Branch
|
||||
- Text.Submodule.Histories
|
||||
- Text.Submodule.Move
|
||||
- Text.Submodule.SetBranch
|
||||
- Text.Submodule.SetURL
|
||||
- Text.Submodule.Update
|
||||
|
||||
</details>
|
||||
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in fr_FR.axaml</summary>
|
||||
@@ -27,11 +78,15 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Bisect.Skip
|
||||
- Text.Bisect.WaitingForRange
|
||||
- Text.BranchCM.ResetToSelectedCommit
|
||||
- Text.ChangeSubmoduleUrl
|
||||
- Text.ChangeSubmoduleUrl.Submodule
|
||||
- Text.ChangeSubmoduleUrl.URL
|
||||
- Text.Checkout.RecurseSubmodules
|
||||
- Text.Checkout.WarnLostCommits
|
||||
- Text.Checkout.WithFastForward
|
||||
- Text.Checkout.WithFastForward.Upstream
|
||||
- Text.CommitCM.CopyAuthor
|
||||
- Text.CommitCM.CopyCommitMessage
|
||||
- Text.CommitCM.CopyCommitter
|
||||
- Text.CommitCM.CopySubject
|
||||
- Text.CommitCM.PushRevision
|
||||
@@ -47,10 +102,11 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ConfigureCustomActionControls.CheckedValue
|
||||
- Text.ConfigureCustomActionControls.CheckedValue.Tip
|
||||
- Text.ConfigureCustomActionControls.Description
|
||||
- Text.ConfigureCustomActionControls.Description.Tip
|
||||
- Text.ConfigureCustomActionControls.DefaultValue
|
||||
- Text.ConfigureCustomActionControls.IsFolder
|
||||
- Text.ConfigureCustomActionControls.Label
|
||||
- Text.ConfigureCustomActionControls.Options
|
||||
- Text.ConfigureCustomActionControls.Options.Tip
|
||||
- Text.ConfigureCustomActionControls.Type
|
||||
- Text.ConfirmEmptyCommit.Continue
|
||||
- Text.ConfirmEmptyCommit.NoLocalChanges
|
||||
@@ -61,6 +117,7 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.DeinitSubmodule.Force
|
||||
- Text.DeinitSubmodule.Path
|
||||
- Text.Diff.Submodule.Deleted
|
||||
- Text.DirHistories
|
||||
- Text.ExecuteCustomAction.Target
|
||||
- Text.ExecuteCustomAction.Repository
|
||||
- Text.GitFlow.FinishWithPush
|
||||
@@ -71,6 +128,9 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Launcher.Workspaces
|
||||
- Text.Launcher.Pages
|
||||
- Text.Merge.Edit
|
||||
- Text.MoveSubmodule
|
||||
- Text.MoveSubmodule.MoveTo
|
||||
- Text.MoveSubmodule.Submodule
|
||||
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
|
||||
- Text.Pull.RecurseSubmodules
|
||||
- Text.Push.Revision
|
||||
@@ -87,14 +147,27 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ResetWithoutCheckout
|
||||
- Text.ResetWithoutCheckout.MoveTo
|
||||
- Text.ResetWithoutCheckout.Target
|
||||
- Text.SetSubmoduleBranch
|
||||
- Text.SetSubmoduleBranch.Submodule
|
||||
- Text.SetSubmoduleBranch.Current
|
||||
- Text.SetSubmoduleBranch.New
|
||||
- Text.SetSubmoduleBranch.New.Tip
|
||||
- Text.Stash.Mode
|
||||
- Text.StashCM.CopyMessage
|
||||
- Text.Submodule.Branch
|
||||
- Text.Submodule.Deinit
|
||||
- Text.Submodule.Histories
|
||||
- Text.Submodule.Move
|
||||
- Text.Submodule.RelativePath
|
||||
- Text.Submodule.RelativePath.Placeholder
|
||||
- Text.Submodule.SetBranch
|
||||
- Text.Submodule.SetURL
|
||||
- Text.Submodule.Status
|
||||
- Text.Submodule.Status.Modified
|
||||
- Text.Submodule.Status.NotInited
|
||||
- Text.Submodule.Status.RevisionChanged
|
||||
- Text.Submodule.Status.Unmerged
|
||||
- Text.Submodule.Update
|
||||
- Text.Submodule.URL
|
||||
- Text.TagCM.CustomAction
|
||||
- Text.ViewLogs
|
||||
@@ -112,7 +185,7 @@ This document shows the translation status of each locale file in the repository
|
||||
|
||||
</details>
|
||||
|
||||
### 
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in it_IT.axaml</summary>
|
||||
@@ -122,9 +195,13 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.AddToIgnore.Storage
|
||||
- Text.Avatar.Load
|
||||
- Text.BranchCM.ResetToSelectedCommit
|
||||
- Text.ChangeSubmoduleUrl
|
||||
- Text.ChangeSubmoduleUrl.Submodule
|
||||
- Text.ChangeSubmoduleUrl.URL
|
||||
- Text.Checkout.WarnLostCommits
|
||||
- Text.Checkout.WithFastForward
|
||||
- Text.Checkout.WithFastForward.Upstream
|
||||
- Text.CommitCM.CopyCommitMessage
|
||||
- Text.CommitCM.PushRevision
|
||||
- Text.CommitDetail.Changes.Count
|
||||
- Text.Configure.CustomAction.Arguments.Tip
|
||||
@@ -136,16 +213,18 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ConfigureCustomActionControls.CheckedValue
|
||||
- Text.ConfigureCustomActionControls.CheckedValue.Tip
|
||||
- Text.ConfigureCustomActionControls.Description
|
||||
- Text.ConfigureCustomActionControls.Description.Tip
|
||||
- Text.ConfigureCustomActionControls.DefaultValue
|
||||
- Text.ConfigureCustomActionControls.IsFolder
|
||||
- Text.ConfigureCustomActionControls.Label
|
||||
- Text.ConfigureCustomActionControls.Options
|
||||
- Text.ConfigureCustomActionControls.Options.Tip
|
||||
- Text.ConfigureCustomActionControls.Type
|
||||
- Text.CreateBranch.OverwriteExisting
|
||||
- Text.DeinitSubmodule
|
||||
- Text.DeinitSubmodule.Force
|
||||
- Text.DeinitSubmodule.Path
|
||||
- Text.Diff.Submodule.Deleted
|
||||
- Text.DirHistories
|
||||
- Text.ExecuteCustomAction.Target
|
||||
- Text.ExecuteCustomAction.Repository
|
||||
- Text.Hotkeys.Global.SwitchWorkspace
|
||||
@@ -153,6 +232,9 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Launcher.Workspaces
|
||||
- Text.Launcher.Pages
|
||||
- Text.Merge.Edit
|
||||
- Text.MoveSubmodule
|
||||
- Text.MoveSubmodule.MoveTo
|
||||
- Text.MoveSubmodule.Submodule
|
||||
- Text.Pull.RecurseSubmodules
|
||||
- Text.Push.Revision
|
||||
- Text.Push.Revision.Title
|
||||
@@ -161,9 +243,20 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ResetWithoutCheckout
|
||||
- Text.ResetWithoutCheckout.MoveTo
|
||||
- Text.ResetWithoutCheckout.Target
|
||||
- Text.SetSubmoduleBranch
|
||||
- Text.SetSubmoduleBranch.Submodule
|
||||
- Text.SetSubmoduleBranch.Current
|
||||
- Text.SetSubmoduleBranch.New
|
||||
- Text.SetSubmoduleBranch.New.Tip
|
||||
- Text.Stash.Mode
|
||||
- Text.StashCM.CopyMessage
|
||||
- Text.Submodule.Branch
|
||||
- Text.Submodule.Deinit
|
||||
- Text.Submodule.Histories
|
||||
- Text.Submodule.Move
|
||||
- Text.Submodule.SetBranch
|
||||
- Text.Submodule.SetURL
|
||||
- Text.Submodule.Update
|
||||
- Text.TagCM.CustomAction
|
||||
- Text.WorkingCopy.AddToGitIgnore.InFolder
|
||||
- Text.WorkingCopy.ConfirmCommitWithDetachedHead
|
||||
@@ -171,7 +264,7 @@ This document shows the translation status of each locale file in the repository
|
||||
|
||||
</details>
|
||||
|
||||
### 
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in ja_JP.axaml</summary>
|
||||
@@ -189,11 +282,15 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Bisect.WaitingForRange
|
||||
- Text.BranchCM.CompareWithCurrent
|
||||
- Text.BranchCM.ResetToSelectedCommit
|
||||
- Text.ChangeSubmoduleUrl
|
||||
- Text.ChangeSubmoduleUrl.Submodule
|
||||
- Text.ChangeSubmoduleUrl.URL
|
||||
- Text.Checkout.RecurseSubmodules
|
||||
- Text.Checkout.WarnLostCommits
|
||||
- Text.Checkout.WithFastForward
|
||||
- Text.Checkout.WithFastForward.Upstream
|
||||
- Text.CommitCM.CopyAuthor
|
||||
- Text.CommitCM.CopyCommitMessage
|
||||
- Text.CommitCM.CopyCommitter
|
||||
- Text.CommitCM.CopySubject
|
||||
- Text.CommitCM.PushRevision
|
||||
@@ -209,10 +306,11 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ConfigureCustomActionControls.CheckedValue
|
||||
- Text.ConfigureCustomActionControls.CheckedValue.Tip
|
||||
- Text.ConfigureCustomActionControls.Description
|
||||
- Text.ConfigureCustomActionControls.Description.Tip
|
||||
- Text.ConfigureCustomActionControls.DefaultValue
|
||||
- Text.ConfigureCustomActionControls.IsFolder
|
||||
- Text.ConfigureCustomActionControls.Label
|
||||
- Text.ConfigureCustomActionControls.Options
|
||||
- Text.ConfigureCustomActionControls.Options.Tip
|
||||
- Text.ConfigureCustomActionControls.Type
|
||||
- Text.ConfirmEmptyCommit.Continue
|
||||
- Text.ConfirmEmptyCommit.NoLocalChanges
|
||||
@@ -223,6 +321,7 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.DeinitSubmodule.Force
|
||||
- Text.DeinitSubmodule.Path
|
||||
- Text.Diff.Submodule.Deleted
|
||||
- Text.DirHistories
|
||||
- Text.ExecuteCustomAction.Target
|
||||
- Text.ExecuteCustomAction.Repository
|
||||
- Text.GitFlow.FinishWithPush
|
||||
@@ -233,6 +332,9 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Launcher.Workspaces
|
||||
- Text.Launcher.Pages
|
||||
- Text.Merge.Edit
|
||||
- Text.MoveSubmodule
|
||||
- Text.MoveSubmodule.MoveTo
|
||||
- Text.MoveSubmodule.Submodule
|
||||
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
|
||||
- Text.Pull.RecurseSubmodules
|
||||
- Text.Push.Revision
|
||||
@@ -250,14 +352,25 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ResetWithoutCheckout
|
||||
- Text.ResetWithoutCheckout.MoveTo
|
||||
- Text.ResetWithoutCheckout.Target
|
||||
- Text.SetSubmoduleBranch
|
||||
- Text.SetSubmoduleBranch.Submodule
|
||||
- Text.SetSubmoduleBranch.Current
|
||||
- Text.SetSubmoduleBranch.New
|
||||
- Text.SetSubmoduleBranch.New.Tip
|
||||
- Text.Stash.Mode
|
||||
- Text.StashCM.CopyMessage
|
||||
- Text.Submodule.Branch
|
||||
- Text.Submodule.Deinit
|
||||
- Text.Submodule.Histories
|
||||
- Text.Submodule.Move
|
||||
- Text.Submodule.SetBranch
|
||||
- Text.Submodule.SetURL
|
||||
- Text.Submodule.Status
|
||||
- Text.Submodule.Status.Modified
|
||||
- Text.Submodule.Status.NotInited
|
||||
- Text.Submodule.Status.RevisionChanged
|
||||
- Text.Submodule.Status.Unmerged
|
||||
- Text.Submodule.Update
|
||||
- Text.Submodule.URL
|
||||
- Text.TagCM.CustomAction
|
||||
- Text.ViewLogs
|
||||
@@ -275,7 +388,7 @@ This document shows the translation status of each locale file in the repository
|
||||
|
||||
</details>
|
||||
|
||||
### 
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in pt_BR.axaml</summary>
|
||||
@@ -301,12 +414,16 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.BranchCM.MergeMultiBranches
|
||||
- Text.BranchCM.ResetToSelectedCommit
|
||||
- Text.BranchUpstreamInvalid
|
||||
- Text.ChangeSubmoduleUrl
|
||||
- Text.ChangeSubmoduleUrl.Submodule
|
||||
- Text.ChangeSubmoduleUrl.URL
|
||||
- Text.Checkout.RecurseSubmodules
|
||||
- Text.Checkout.WarnLostCommits
|
||||
- Text.Checkout.WithFastForward
|
||||
- Text.Checkout.WithFastForward.Upstream
|
||||
- Text.Clone.RecurseSubmodules
|
||||
- Text.CommitCM.CopyAuthor
|
||||
- Text.CommitCM.CopyCommitMessage
|
||||
- Text.CommitCM.CopyCommitter
|
||||
- Text.CommitCM.CopySubject
|
||||
- Text.CommitCM.Merge
|
||||
@@ -330,10 +447,11 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ConfigureCustomActionControls.CheckedValue
|
||||
- Text.ConfigureCustomActionControls.CheckedValue.Tip
|
||||
- Text.ConfigureCustomActionControls.Description
|
||||
- Text.ConfigureCustomActionControls.Description.Tip
|
||||
- Text.ConfigureCustomActionControls.DefaultValue
|
||||
- Text.ConfigureCustomActionControls.IsFolder
|
||||
- Text.ConfigureCustomActionControls.Label
|
||||
- Text.ConfigureCustomActionControls.Options
|
||||
- Text.ConfigureCustomActionControls.Options.Tip
|
||||
- Text.ConfigureCustomActionControls.Type
|
||||
- Text.ConfirmEmptyCommit.Continue
|
||||
- Text.ConfirmEmptyCommit.NoLocalChanges
|
||||
@@ -352,6 +470,7 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Diff.Last
|
||||
- Text.Diff.Submodule.Deleted
|
||||
- Text.Diff.UseBlockNavigation
|
||||
- Text.DirHistories
|
||||
- Text.ExecuteCustomAction.Target
|
||||
- Text.ExecuteCustomAction.Repository
|
||||
- Text.Fetch.Force
|
||||
@@ -374,6 +493,9 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.MergeMultiple.CommitChanges
|
||||
- Text.MergeMultiple.Strategy
|
||||
- Text.MergeMultiple.Targets
|
||||
- Text.MoveSubmodule
|
||||
- Text.MoveSubmodule.MoveTo
|
||||
- Text.MoveSubmodule.Submodule
|
||||
- Text.Preferences.AI.Streaming
|
||||
- Text.Preferences.Appearance.EditorTabWidth
|
||||
- Text.Preferences.General.DateFormat
|
||||
@@ -408,6 +530,11 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ResetWithoutCheckout
|
||||
- Text.ResetWithoutCheckout.MoveTo
|
||||
- Text.ResetWithoutCheckout.Target
|
||||
- Text.SetSubmoduleBranch
|
||||
- Text.SetSubmoduleBranch.Submodule
|
||||
- Text.SetSubmoduleBranch.Current
|
||||
- Text.SetSubmoduleBranch.New
|
||||
- Text.SetSubmoduleBranch.New.Tip
|
||||
- Text.SetUpstream
|
||||
- Text.SetUpstream.Local
|
||||
- Text.SetUpstream.Unset
|
||||
@@ -416,12 +543,18 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Stash.Mode
|
||||
- Text.StashCM.CopyMessage
|
||||
- Text.StashCM.SaveAsPatch
|
||||
- Text.Submodule.Branch
|
||||
- Text.Submodule.Deinit
|
||||
- Text.Submodule.Histories
|
||||
- Text.Submodule.Move
|
||||
- Text.Submodule.SetBranch
|
||||
- Text.Submodule.SetURL
|
||||
- Text.Submodule.Status
|
||||
- Text.Submodule.Status.Modified
|
||||
- Text.Submodule.Status.NotInited
|
||||
- Text.Submodule.Status.RevisionChanged
|
||||
- Text.Submodule.Status.Unmerged
|
||||
- Text.Submodule.Update
|
||||
- Text.Submodule.URL
|
||||
- Text.TagCM.CustomAction
|
||||
- Text.ViewLogs
|
||||
@@ -443,7 +576,7 @@ This document shows the translation status of each locale file in the repository
|
||||
|
||||
### 
|
||||
|
||||
### 
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in ta_IN.axaml</summary>
|
||||
@@ -461,11 +594,15 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Bisect.WaitingForRange
|
||||
- Text.BranchCM.CompareWithCurrent
|
||||
- Text.BranchCM.ResetToSelectedCommit
|
||||
- Text.ChangeSubmoduleUrl
|
||||
- Text.ChangeSubmoduleUrl.Submodule
|
||||
- Text.ChangeSubmoduleUrl.URL
|
||||
- Text.Checkout.RecurseSubmodules
|
||||
- Text.Checkout.WarnLostCommits
|
||||
- Text.Checkout.WithFastForward
|
||||
- Text.Checkout.WithFastForward.Upstream
|
||||
- Text.CommitCM.CopyAuthor
|
||||
- Text.CommitCM.CopyCommitMessage
|
||||
- Text.CommitCM.CopyCommitter
|
||||
- Text.CommitCM.CopySubject
|
||||
- Text.CommitCM.PushRevision
|
||||
@@ -481,10 +618,11 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ConfigureCustomActionControls.CheckedValue
|
||||
- Text.ConfigureCustomActionControls.CheckedValue.Tip
|
||||
- Text.ConfigureCustomActionControls.Description
|
||||
- Text.ConfigureCustomActionControls.Description.Tip
|
||||
- Text.ConfigureCustomActionControls.DefaultValue
|
||||
- Text.ConfigureCustomActionControls.IsFolder
|
||||
- Text.ConfigureCustomActionControls.Label
|
||||
- Text.ConfigureCustomActionControls.Options
|
||||
- Text.ConfigureCustomActionControls.Options.Tip
|
||||
- Text.ConfigureCustomActionControls.Type
|
||||
- Text.ConfirmEmptyCommit.Continue
|
||||
- Text.ConfirmEmptyCommit.NoLocalChanges
|
||||
@@ -495,6 +633,7 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.DeinitSubmodule.Force
|
||||
- Text.DeinitSubmodule.Path
|
||||
- Text.Diff.Submodule.Deleted
|
||||
- Text.DirHistories
|
||||
- Text.ExecuteCustomAction.Target
|
||||
- Text.ExecuteCustomAction.Repository
|
||||
- Text.GitFlow.FinishWithPush
|
||||
@@ -505,6 +644,9 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Launcher.Workspaces
|
||||
- Text.Launcher.Pages
|
||||
- Text.Merge.Edit
|
||||
- Text.MoveSubmodule
|
||||
- Text.MoveSubmodule.MoveTo
|
||||
- Text.MoveSubmodule.Submodule
|
||||
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
|
||||
- Text.Pull.RecurseSubmodules
|
||||
- Text.Push.Revision
|
||||
@@ -521,14 +663,25 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ResetWithoutCheckout
|
||||
- Text.ResetWithoutCheckout.MoveTo
|
||||
- Text.ResetWithoutCheckout.Target
|
||||
- Text.SetSubmoduleBranch
|
||||
- Text.SetSubmoduleBranch.Submodule
|
||||
- Text.SetSubmoduleBranch.Current
|
||||
- Text.SetSubmoduleBranch.New
|
||||
- Text.SetSubmoduleBranch.New.Tip
|
||||
- Text.Stash.Mode
|
||||
- Text.StashCM.CopyMessage
|
||||
- Text.Submodule.Branch
|
||||
- Text.Submodule.Deinit
|
||||
- Text.Submodule.Histories
|
||||
- Text.Submodule.Move
|
||||
- Text.Submodule.SetBranch
|
||||
- Text.Submodule.SetURL
|
||||
- Text.Submodule.Status
|
||||
- Text.Submodule.Status.Modified
|
||||
- Text.Submodule.Status.NotInited
|
||||
- Text.Submodule.Status.RevisionChanged
|
||||
- Text.Submodule.Status.Unmerged
|
||||
- Text.Submodule.Update
|
||||
- Text.Submodule.URL
|
||||
- Text.TagCM.CustomAction
|
||||
- Text.UpdateSubmodules.Target
|
||||
@@ -546,7 +699,7 @@ This document shows the translation status of each locale file in the repository
|
||||
|
||||
</details>
|
||||
|
||||
### 
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in uk_UA.axaml</summary>
|
||||
@@ -563,11 +716,15 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Bisect.Skip
|
||||
- Text.Bisect.WaitingForRange
|
||||
- Text.BranchCM.ResetToSelectedCommit
|
||||
- Text.ChangeSubmoduleUrl
|
||||
- Text.ChangeSubmoduleUrl.Submodule
|
||||
- Text.ChangeSubmoduleUrl.URL
|
||||
- Text.Checkout.RecurseSubmodules
|
||||
- Text.Checkout.WarnLostCommits
|
||||
- Text.Checkout.WithFastForward
|
||||
- Text.Checkout.WithFastForward.Upstream
|
||||
- Text.CommitCM.CopyAuthor
|
||||
- Text.CommitCM.CopyCommitMessage
|
||||
- Text.CommitCM.CopyCommitter
|
||||
- Text.CommitCM.CopySubject
|
||||
- Text.CommitCM.PushRevision
|
||||
@@ -582,10 +739,11 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ConfigureCustomActionControls.CheckedValue
|
||||
- Text.ConfigureCustomActionControls.CheckedValue.Tip
|
||||
- Text.ConfigureCustomActionControls.Description
|
||||
- Text.ConfigureCustomActionControls.Description.Tip
|
||||
- Text.ConfigureCustomActionControls.DefaultValue
|
||||
- Text.ConfigureCustomActionControls.IsFolder
|
||||
- Text.ConfigureCustomActionControls.Label
|
||||
- Text.ConfigureCustomActionControls.Options
|
||||
- Text.ConfigureCustomActionControls.Options.Tip
|
||||
- Text.ConfigureCustomActionControls.Type
|
||||
- Text.ConfigureWorkspace.Name
|
||||
- Text.CreateBranch.OverwriteExisting
|
||||
@@ -593,6 +751,7 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.DeinitSubmodule.Force
|
||||
- Text.DeinitSubmodule.Path
|
||||
- Text.Diff.Submodule.Deleted
|
||||
- Text.DirHistories
|
||||
- Text.ExecuteCustomAction.Target
|
||||
- Text.ExecuteCustomAction.Repository
|
||||
- Text.GitFlow.FinishWithPush
|
||||
@@ -603,6 +762,9 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Launcher.Workspaces
|
||||
- Text.Launcher.Pages
|
||||
- Text.Merge.Edit
|
||||
- Text.MoveSubmodule
|
||||
- Text.MoveSubmodule.MoveTo
|
||||
- Text.MoveSubmodule.Submodule
|
||||
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
|
||||
- Text.Pull.RecurseSubmodules
|
||||
- Text.Push.Revision
|
||||
@@ -619,14 +781,25 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ResetWithoutCheckout
|
||||
- Text.ResetWithoutCheckout.MoveTo
|
||||
- Text.ResetWithoutCheckout.Target
|
||||
- Text.SetSubmoduleBranch
|
||||
- Text.SetSubmoduleBranch.Submodule
|
||||
- Text.SetSubmoduleBranch.Current
|
||||
- Text.SetSubmoduleBranch.New
|
||||
- Text.SetSubmoduleBranch.New.Tip
|
||||
- Text.Stash.Mode
|
||||
- Text.StashCM.CopyMessage
|
||||
- Text.Submodule.Branch
|
||||
- Text.Submodule.Deinit
|
||||
- Text.Submodule.Histories
|
||||
- Text.Submodule.Move
|
||||
- Text.Submodule.SetBranch
|
||||
- Text.Submodule.SetURL
|
||||
- Text.Submodule.Status
|
||||
- Text.Submodule.Status.Modified
|
||||
- Text.Submodule.Status.NotInited
|
||||
- Text.Submodule.Status.RevisionChanged
|
||||
- Text.Submodule.Status.Unmerged
|
||||
- Text.Submodule.Update
|
||||
- Text.Submodule.URL
|
||||
- Text.TagCM.CustomAction
|
||||
- Text.ViewLogs
|
||||
|
||||
|
Before Width: | Height: | Size: 804 KiB After Width: | Height: | Size: 491 KiB |
|
Before Width: | Height: | Size: 712 KiB After Width: | Height: | Size: 471 KiB |
@@ -37,22 +37,21 @@ namespace SourceGit
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly Command OpenPreferencesCommand = new Command(_ => ShowWindow(new Views.Preferences(), false));
|
||||
public static readonly Command OpenHotkeysCommand = new Command(_ => ShowWindow(new Views.Hotkeys(), false));
|
||||
public static readonly Command OpenPreferencesCommand = new Command(async _ => await ShowDialog(new Views.Preferences()));
|
||||
public static readonly Command OpenHotkeysCommand = new Command(async _ => await ShowDialog(new Views.Hotkeys()));
|
||||
public static readonly Command OpenAppDataDirCommand = new Command(_ => Native.OS.OpenInFileManager(Native.OS.DataDir));
|
||||
public static readonly Command OpenAboutCommand = new Command(_ => ShowWindow(new Views.About(), false));
|
||||
public static readonly Command OpenAboutCommand = new Command(async _ => await ShowDialog(new Views.About()));
|
||||
public static readonly Command CheckForUpdateCommand = new Command(_ => (Current as App)?.Check4Update(true));
|
||||
public static readonly Command QuitCommand = new Command(_ => Quit(0));
|
||||
public static readonly Command CopyTextBlockCommand = new Command(p =>
|
||||
public static readonly Command CopyTextBlockCommand = new Command(async p =>
|
||||
{
|
||||
var textBlock = p as TextBlock;
|
||||
if (textBlock == null)
|
||||
if (p is not TextBlock textBlock)
|
||||
return;
|
||||
|
||||
if (textBlock.Inlines is { Count: > 0 } inlines)
|
||||
CopyText(inlines.Text);
|
||||
await CopyTextAsync(inlines.Text);
|
||||
else if (!string.IsNullOrEmpty(textBlock.Text))
|
||||
CopyText(textBlock.Text);
|
||||
await CopyTextAsync(textBlock.Text);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,20 @@ namespace SourceGit
|
||||
}
|
||||
}
|
||||
|
||||
public class DataGridLengthConverter : JsonConverter<DataGridLength>
|
||||
{
|
||||
public override DataGridLength Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var size = reader.GetDouble();
|
||||
return new DataGridLength(size, DataGridLengthUnitType.Pixel, 0, size);
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, DataGridLength value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteNumberValue(value.DisplayValue);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(
|
||||
WriteIndented = true,
|
||||
IgnoreReadOnlyFields = true,
|
||||
@@ -41,6 +55,7 @@ namespace SourceGit
|
||||
Converters = [
|
||||
typeof(ColorConverter),
|
||||
typeof(GridLengthConverter),
|
||||
typeof(DataGridLengthConverter),
|
||||
]
|
||||
)]
|
||||
[JsonSerializable(typeof(Models.ExternalToolPaths))]
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
|
||||
<StyleInclude Source="avares://AvaloniaEdit/Themes/Fluent/AvaloniaEdit.xaml" />
|
||||
<StyleInclude Source="/Resources/Styles.axaml"/>
|
||||
</Application.Styles>
|
||||
|
||||
174
src/App.axaml.cs
@@ -83,88 +83,112 @@ namespace SourceGit
|
||||
if (ex == null)
|
||||
return;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.Append($"Crash::: {ex.GetType().FullName}: {ex.Message}\n\n");
|
||||
builder.Append("----------------------------\n");
|
||||
builder.Append($"Version: {Assembly.GetExecutingAssembly().GetName().Version}\n");
|
||||
builder.Append($"OS: {Environment.OSVersion}\n");
|
||||
builder.Append($"Framework: {AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName}\n");
|
||||
builder.Append($"Source: {ex.Source}\n");
|
||||
builder.Append($"Thread Name: {Thread.CurrentThread.Name ?? "Unnamed"}\n");
|
||||
builder.Append($"User: {Environment.UserName}\n");
|
||||
builder.Append($"App Start Time: {Process.GetCurrentProcess().StartTime}\n");
|
||||
builder.Append($"Exception Time: {DateTime.Now}\n");
|
||||
builder.Append($"Memory Usage: {Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024} MB\n");
|
||||
builder.Append("---------------------------\n\n");
|
||||
builder.Append(ex);
|
||||
|
||||
var time = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
|
||||
var file = Path.Combine(Native.OS.DataDir, $"crash_{time}.log");
|
||||
File.WriteAllText(file, builder.ToString());
|
||||
using var writer = new StreamWriter(file);
|
||||
writer.WriteLine($"Crash::: {ex.GetType().FullName}: {ex.Message}");
|
||||
writer.WriteLine();
|
||||
writer.WriteLine("----------------------------");
|
||||
writer.WriteLine($"Version: {Assembly.GetExecutingAssembly().GetName().Version}");
|
||||
writer.WriteLine($"OS: {Environment.OSVersion}");
|
||||
writer.WriteLine($"Framework: {AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName}");
|
||||
writer.WriteLine($"Source: {ex.Source}");
|
||||
writer.WriteLine($"Thread Name: {Thread.CurrentThread.Name ?? "Unnamed"}");
|
||||
writer.WriteLine($"User: {Environment.UserName}");
|
||||
writer.WriteLine($"App Start Time: {Process.GetCurrentProcess().StartTime}");
|
||||
writer.WriteLine($"Exception Time: {DateTime.Now}");
|
||||
writer.WriteLine($"Memory Usage: {Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024} MB");
|
||||
writer.WriteLine("----------------------------");
|
||||
writer.WriteLine();
|
||||
writer.WriteLine(ex);
|
||||
writer.Flush();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Utility Functions
|
||||
public static void ShowWindow(object data, bool showAsDialog)
|
||||
public static object CreateViewForViewModel(object data)
|
||||
{
|
||||
var impl = (Views.ChromelessWindow target, bool isDialog) =>
|
||||
{
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner })
|
||||
{
|
||||
if (isDialog)
|
||||
target.ShowDialog(owner);
|
||||
else
|
||||
target.Show(owner);
|
||||
}
|
||||
else
|
||||
{
|
||||
target.Show();
|
||||
}
|
||||
};
|
||||
|
||||
if (data is Views.ChromelessWindow window)
|
||||
{
|
||||
impl(window, showAsDialog);
|
||||
return;
|
||||
}
|
||||
|
||||
var dataTypeName = data.GetType().FullName;
|
||||
if (string.IsNullOrEmpty(dataTypeName) || !dataTypeName.Contains(".ViewModels.", StringComparison.Ordinal))
|
||||
return;
|
||||
return null;
|
||||
|
||||
var viewTypeName = dataTypeName.Replace(".ViewModels.", ".Views.");
|
||||
var viewType = Type.GetType(viewTypeName);
|
||||
if (viewType == null || !viewType.IsSubclassOf(typeof(Views.ChromelessWindow)))
|
||||
return;
|
||||
if (viewType != null)
|
||||
return Activator.CreateInstance(viewType);
|
||||
|
||||
window = Activator.CreateInstance(viewType) as Views.ChromelessWindow;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Task ShowDialog(object data, Window owner = null)
|
||||
{
|
||||
if (owner == null)
|
||||
{
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } mainWindow })
|
||||
owner = mainWindow;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
if (data is Views.ChromelessWindow window)
|
||||
return window.ShowDialog(owner);
|
||||
|
||||
window = CreateViewForViewModel(data) as Views.ChromelessWindow;
|
||||
if (window != null)
|
||||
{
|
||||
window.DataContext = data;
|
||||
impl(window, showAsDialog);
|
||||
return window.ShowDialog(owner);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void ShowWindow(object data)
|
||||
{
|
||||
if (data is Views.ChromelessWindow window)
|
||||
{
|
||||
window.Show();
|
||||
return;
|
||||
}
|
||||
|
||||
window = CreateViewForViewModel(data) as Views.ChromelessWindow;
|
||||
if (window != null)
|
||||
{
|
||||
window.DataContext = data;
|
||||
window.Show();
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<bool> AskConfirmAsync(string message, Action onSure)
|
||||
{
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner })
|
||||
{
|
||||
var confirm = new Views.Confirm();
|
||||
confirm.Message.Text = message;
|
||||
confirm.OnSure = onSure;
|
||||
return await confirm.ShowDialog<bool>(owner);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void RaiseException(string context, string message)
|
||||
{
|
||||
if (Current is App app && app._launcher != null)
|
||||
if (Current is App { _launcher: not null } app)
|
||||
app._launcher.DispatchNotification(context, message, true);
|
||||
}
|
||||
|
||||
public static void SendNotification(string context, string message)
|
||||
{
|
||||
if (Current is App app && app._launcher != null)
|
||||
if (Current is App { _launcher: not null } app)
|
||||
app._launcher.DispatchNotification(context, message, false);
|
||||
}
|
||||
|
||||
public static void SetLocale(string localeKey)
|
||||
{
|
||||
var app = Current as App;
|
||||
if (app == null)
|
||||
return;
|
||||
|
||||
var targetLocale = app.Resources[localeKey] as ResourceDictionary;
|
||||
if (targetLocale == null || targetLocale == app._activeLocale)
|
||||
if (Current is not App app ||
|
||||
app.Resources[localeKey] is not ResourceDictionary targetLocale ||
|
||||
targetLocale == app._activeLocale)
|
||||
return;
|
||||
|
||||
if (app._activeLocale != null)
|
||||
@@ -176,8 +200,7 @@ namespace SourceGit
|
||||
|
||||
public static void SetTheme(string theme, string themeOverridesFile)
|
||||
{
|
||||
var app = Current as App;
|
||||
if (app == null)
|
||||
if (Current is not App app)
|
||||
return;
|
||||
|
||||
if (theme.Equals("Light", StringComparison.OrdinalIgnoreCase))
|
||||
@@ -230,8 +253,7 @@ namespace SourceGit
|
||||
|
||||
public static void SetFonts(string defaultFont, string monospaceFont, bool onlyUseMonospaceFontInEditor)
|
||||
{
|
||||
var app = Current as App;
|
||||
if (app == null)
|
||||
if (Current is not App app)
|
||||
return;
|
||||
|
||||
if (app._fontsOverrides != null)
|
||||
@@ -283,24 +305,16 @@ namespace SourceGit
|
||||
}
|
||||
}
|
||||
|
||||
public static async void CopyText(string data)
|
||||
public static async Task CopyTextAsync(string data)
|
||||
{
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
if (desktop.MainWindow?.Clipboard is { } clipboard)
|
||||
await clipboard.SetTextAsync(data ?? "");
|
||||
}
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow.Clipboard: { } clipboard })
|
||||
await clipboard.SetTextAsync(data ?? "");
|
||||
}
|
||||
|
||||
public static async Task<string> GetClipboardTextAsync()
|
||||
{
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
if (desktop.MainWindow?.Clipboard is { } clipboard)
|
||||
{
|
||||
return await clipboard.GetTextAsync();
|
||||
}
|
||||
}
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow.Clipboard: { } clipboard })
|
||||
return await clipboard.GetTextAsync();
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -436,33 +450,33 @@ namespace SourceGit
|
||||
return true;
|
||||
|
||||
var collection = JsonSerializer.Deserialize(File.ReadAllText(jobsFile), JsonCodeGen.Default.InteractiveRebaseJobCollection);
|
||||
var lines = new List<string>();
|
||||
using var writer = new StreamWriter(file);
|
||||
foreach (var job in collection.Jobs)
|
||||
{
|
||||
switch (job.Action)
|
||||
{
|
||||
case Models.InteractiveRebaseAction.Pick:
|
||||
lines.Add($"p {job.SHA}");
|
||||
writer.WriteLine($"p {job.SHA}");
|
||||
break;
|
||||
case Models.InteractiveRebaseAction.Edit:
|
||||
lines.Add($"e {job.SHA}");
|
||||
writer.WriteLine($"e {job.SHA}");
|
||||
break;
|
||||
case Models.InteractiveRebaseAction.Reword:
|
||||
lines.Add($"r {job.SHA}");
|
||||
writer.WriteLine($"r {job.SHA}");
|
||||
break;
|
||||
case Models.InteractiveRebaseAction.Squash:
|
||||
lines.Add($"s {job.SHA}");
|
||||
writer.WriteLine($"s {job.SHA}");
|
||||
break;
|
||||
case Models.InteractiveRebaseAction.Fixup:
|
||||
lines.Add($"f {job.SHA}");
|
||||
writer.WriteLine($"f {job.SHA}");
|
||||
break;
|
||||
default:
|
||||
lines.Add($"d {job.SHA}");
|
||||
writer.WriteLine($"d {job.SHA}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
File.WriteAllLines(file, lines);
|
||||
writer.Flush();
|
||||
|
||||
exitCode = 0;
|
||||
return true;
|
||||
@@ -561,7 +575,7 @@ namespace SourceGit
|
||||
Models.AvatarManager.Instance.Start();
|
||||
|
||||
string startupRepo = null;
|
||||
if (desktop.Args != null && desktop.Args.Length == 1 && Directory.Exists(desktop.Args[0]))
|
||||
if (desktop.Args is { Length: 1 } && Directory.Exists(desktop.Args[0]))
|
||||
startupRepo = desktop.Args[0];
|
||||
|
||||
var pref = ViewModels.Preferences.Instance;
|
||||
@@ -581,7 +595,7 @@ namespace SourceGit
|
||||
{
|
||||
if (!string.IsNullOrEmpty(repo) && Directory.Exists(repo))
|
||||
{
|
||||
var test = new Commands.QueryRepositoryRootPath(repo).ReadToEnd();
|
||||
var test = new Commands.QueryRepositoryRootPath(repo).GetResultAsync().Result;
|
||||
if (test.IsSuccess && !string.IsNullOrEmpty(test.StdOut))
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
@@ -648,9 +662,9 @@ namespace SourceGit
|
||||
|
||||
private void ShowSelfUpdateResult(object data)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
ShowWindow(new ViewModels.SelfUpdate() { Data = data }, true);
|
||||
await ShowDialog(new ViewModels.SelfUpdate { Data = data });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -19,9 +20,9 @@ namespace SourceGit.Commands
|
||||
_result.File = file;
|
||||
}
|
||||
|
||||
public Models.BlameData Result()
|
||||
public async Task<Models.BlameData> ReadAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return _result;
|
||||
|
||||
@@ -39,9 +40,7 @@ namespace SourceGit.Commands
|
||||
foreach (var line in _result.LineInfos)
|
||||
{
|
||||
if (line.CommitSHA.Length > _minSHALen)
|
||||
{
|
||||
line.CommitSHA = line.CommitSHA.Substring(0, _minSHALen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public static class Branch
|
||||
{
|
||||
public static string ShowCurrent(string repo)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Args = "branch --show-current";
|
||||
return cmd.ReadToEnd().StdOut.Trim();
|
||||
}
|
||||
|
||||
public static bool Create(string repo, string name, string basedOn, bool force, Models.ICommandLog log)
|
||||
public static async Task<bool> CreateAsync(string repo, string name, string basedOn, bool force, Models.ICommandLog log)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("branch ");
|
||||
@@ -28,20 +20,20 @@ namespace SourceGit.Commands
|
||||
cmd.Context = repo;
|
||||
cmd.Args = builder.ToString();
|
||||
cmd.Log = log;
|
||||
return cmd.Exec();
|
||||
return await cmd.ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static bool Rename(string repo, string name, string to, Models.ICommandLog log)
|
||||
public static async Task<bool> RenameAsync(string repo, string name, string to, Models.ICommandLog log)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Args = $"branch -M {name} {to}";
|
||||
cmd.Log = log;
|
||||
return cmd.Exec();
|
||||
return await cmd.ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static bool SetUpstream(string repo, string name, string upstream, Models.ICommandLog log)
|
||||
public static async Task<bool> SetUpstreamAsync(string repo, string name, string upstream, Models.ICommandLog log)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
@@ -53,31 +45,31 @@ namespace SourceGit.Commands
|
||||
else
|
||||
cmd.Args = $"branch {name} -u {upstream}";
|
||||
|
||||
return cmd.Exec();
|
||||
return await cmd.ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static bool DeleteLocal(string repo, string name, Models.ICommandLog log)
|
||||
public static async Task<bool> DeleteLocalAsync(string repo, string name, Models.ICommandLog log)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Args = $"branch -D {name}";
|
||||
cmd.Log = log;
|
||||
return cmd.Exec();
|
||||
return await cmd.ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static bool DeleteRemote(string repo, string remote, string name, Models.ICommandLog log)
|
||||
public static async Task<bool> DeleteRemoteAsync(string repo, string remote, string name, Models.ICommandLog log)
|
||||
{
|
||||
bool exists = new Remote(repo).HasBranch(remote, name);
|
||||
bool exists = await new Remote(repo).HasBranchAsync(remote, name).ConfigureAwait(false);
|
||||
if (exists)
|
||||
return new Push(repo, remote, $"refs/heads/{name}", true) { Log = log }.Exec();
|
||||
return await new Push(repo, remote, $"refs/heads/{name}", true) { Log = log }.RunAsync().ConfigureAwait(false);
|
||||
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Args = $"branch -D -r {remote}/{name}";
|
||||
cmd.Log = log;
|
||||
return cmd.Exec();
|
||||
return await cmd.ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -11,7 +12,7 @@ namespace SourceGit.Commands
|
||||
Context = repo;
|
||||
}
|
||||
|
||||
public bool Branch(string branch, bool force)
|
||||
public async Task<bool> BranchAsync(string branch, bool force)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("checkout --progress ");
|
||||
@@ -20,10 +21,10 @@ namespace SourceGit.Commands
|
||||
builder.Append(branch);
|
||||
|
||||
Args = builder.ToString();
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Branch(string branch, string basedOn, bool force, bool allowOverwrite)
|
||||
public async Task<bool> BranchAsync(string branch, string basedOn, bool force, bool allowOverwrite)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("checkout --progress ");
|
||||
@@ -35,17 +36,17 @@ namespace SourceGit.Commands
|
||||
builder.Append(basedOn);
|
||||
|
||||
Args = builder.ToString();
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Commit(string commitId, bool force)
|
||||
public async Task<bool> CommitAsync(string commitId, bool force)
|
||||
{
|
||||
var option = force ? "--force" : string.Empty;
|
||||
Args = $"checkout {option} --detach --progress {commitId}";
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool UseTheirs(List<string> files)
|
||||
public async Task<bool> UseTheirsAsync(List<string> files)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("checkout --theirs --");
|
||||
@@ -56,10 +57,10 @@ namespace SourceGit.Commands
|
||||
builder.Append("\"");
|
||||
}
|
||||
Args = builder.ToString();
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool UseMine(List<string> files)
|
||||
public async Task<bool> UseMineAsync(List<string> files)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("checkout --ours --");
|
||||
@@ -69,14 +70,15 @@ namespace SourceGit.Commands
|
||||
builder.Append(f);
|
||||
builder.Append("\"");
|
||||
}
|
||||
|
||||
Args = builder.ToString();
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool FileWithRevision(string file, string revision)
|
||||
public async Task<bool> FileWithRevisionAsync(string file, string revision)
|
||||
{
|
||||
Args = $"checkout --no-overlay {revision} -- \"{file}\"";
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,18 +4,19 @@ using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
|
||||
using Avalonia.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public partial class Command
|
||||
{
|
||||
public class ReadToEndResult
|
||||
public class Result
|
||||
{
|
||||
public bool IsSuccess { get; set; } = false;
|
||||
public string StdOut { get; set; } = "";
|
||||
public string StdErr { get; set; } = "";
|
||||
public string StdOut { get; set; } = string.Empty;
|
||||
public string StdErr { get; set; } = string.Empty;
|
||||
|
||||
public static Result Failed(string reason) => new Result() { StdErr = reason };
|
||||
}
|
||||
|
||||
public enum EditorType
|
||||
@@ -26,15 +27,17 @@ namespace SourceGit.Commands
|
||||
}
|
||||
|
||||
public string Context { get; set; } = string.Empty;
|
||||
public CancellationToken CancellationToken { get; set; } = CancellationToken.None;
|
||||
public string WorkingDirectory { get; set; } = null;
|
||||
public EditorType Editor { get; set; } = EditorType.CoreEditor; // Only used in Exec() mode
|
||||
public EditorType Editor { get; set; } = EditorType.CoreEditor;
|
||||
public string SSHKey { get; set; } = string.Empty;
|
||||
public string Args { get; set; } = string.Empty;
|
||||
|
||||
// Only used in `ExecAsync` mode.
|
||||
public CancellationToken CancellationToken { get; set; } = CancellationToken.None;
|
||||
public bool RaiseError { get; set; } = true;
|
||||
public Models.ICommandLog Log { get; set; } = null;
|
||||
|
||||
public bool Exec()
|
||||
public async Task<bool> ExecAsync()
|
||||
{
|
||||
Log?.AppendLine($"$ git {Args}\n");
|
||||
|
||||
@@ -45,7 +48,7 @@ namespace SourceGit.Commands
|
||||
proc.OutputDataReceived += (_, e) => HandleOutput(e.Data, errs);
|
||||
proc.ErrorDataReceived += (_, e) => HandleOutput(e.Data, errs);
|
||||
|
||||
var dummy = null as Process;
|
||||
Process dummy = null;
|
||||
var dummyProcLock = new object();
|
||||
try
|
||||
{
|
||||
@@ -68,7 +71,7 @@ namespace SourceGit.Commands
|
||||
catch (Exception e)
|
||||
{
|
||||
if (RaiseError)
|
||||
Dispatcher.UIThread.Post(() => App.RaiseException(Context, e.Message));
|
||||
App.RaiseException(Context, e.Message);
|
||||
|
||||
Log?.AppendLine(string.Empty);
|
||||
return false;
|
||||
@@ -76,7 +79,15 @@ namespace SourceGit.Commands
|
||||
|
||||
proc.BeginOutputReadLine();
|
||||
proc.BeginErrorReadLine();
|
||||
proc.WaitForExit();
|
||||
|
||||
try
|
||||
{
|
||||
await proc.WaitForExitAsync(CancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
HandleOutput(e.Message, errs);
|
||||
}
|
||||
|
||||
if (dummy != null)
|
||||
{
|
||||
@@ -96,7 +107,7 @@ namespace SourceGit.Commands
|
||||
{
|
||||
var errMsg = string.Join("\n", errs).Trim();
|
||||
if (!string.IsNullOrEmpty(errMsg))
|
||||
Dispatcher.UIThread.Post(() => App.RaiseException(Context, errMsg));
|
||||
App.RaiseException(Context, errMsg);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -105,7 +116,7 @@ namespace SourceGit.Commands
|
||||
return true;
|
||||
}
|
||||
|
||||
public ReadToEndResult ReadToEnd()
|
||||
protected async Task<Result> ReadToEndAsync()
|
||||
{
|
||||
var start = CreateGitStartInfo();
|
||||
var proc = new Process() { StartInfo = start };
|
||||
@@ -116,24 +127,16 @@ namespace SourceGit.Commands
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new ReadToEndResult()
|
||||
{
|
||||
IsSuccess = false,
|
||||
StdOut = string.Empty,
|
||||
StdErr = e.Message,
|
||||
};
|
||||
return Result.Failed(e.Message);
|
||||
}
|
||||
|
||||
var rs = new ReadToEndResult()
|
||||
{
|
||||
StdOut = proc.StandardOutput.ReadToEnd(),
|
||||
StdErr = proc.StandardError.ReadToEnd(),
|
||||
};
|
||||
var rs = new Result() { IsSuccess = true };
|
||||
rs.StdOut = await proc.StandardOutput.ReadToEndAsync(CancellationToken).ConfigureAwait(false);
|
||||
rs.StdErr = await proc.StandardError.ReadToEndAsync(CancellationToken).ConfigureAwait(false);
|
||||
await proc.WaitForExitAsync(CancellationToken).ConfigureAwait(false);
|
||||
|
||||
proc.WaitForExit();
|
||||
rs.IsSuccess = proc.ExitCode == 0;
|
||||
proc.Close();
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -7,7 +8,7 @@ namespace SourceGit.Commands
|
||||
public Commit(string repo, string message, bool signOff, bool amend, bool resetAuthor)
|
||||
{
|
||||
_tmpFile = Path.GetTempFileName();
|
||||
File.WriteAllText(_tmpFile, message);
|
||||
_message = message;
|
||||
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
@@ -18,22 +19,22 @@ namespace SourceGit.Commands
|
||||
Args += resetAuthor ? " --amend --reset-author --no-edit" : " --amend --no-edit";
|
||||
}
|
||||
|
||||
public bool Run()
|
||||
public async Task<bool> RunAsync()
|
||||
{
|
||||
var succ = Exec();
|
||||
|
||||
try
|
||||
{
|
||||
await File.WriteAllTextAsync(_tmpFile, _message).ConfigureAwait(false);
|
||||
var succ = await ExecAsync().ConfigureAwait(false);
|
||||
File.Delete(_tmpFile);
|
||||
return succ;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore
|
||||
return false;
|
||||
}
|
||||
|
||||
return succ;
|
||||
}
|
||||
|
||||
private readonly string _tmpFile;
|
||||
private readonly string _tmpFile = string.Empty;
|
||||
private readonly string _message = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -29,21 +30,22 @@ namespace SourceGit.Commands
|
||||
Args = $"diff --name-status {based} {end} -- \"{path}\"";
|
||||
}
|
||||
|
||||
public List<Models.Change> Result()
|
||||
public async Task<List<Models.Change>> ReadAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var changes = new List<Models.Change>();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return _changes;
|
||||
return changes;
|
||||
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
ParseLine(line);
|
||||
ParseLine(changes, line);
|
||||
|
||||
_changes.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path));
|
||||
return _changes;
|
||||
changes.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path));
|
||||
return changes;
|
||||
}
|
||||
|
||||
private void ParseLine(string line)
|
||||
private void ParseLine(List<Models.Change> outs, string line)
|
||||
{
|
||||
var match = REG_FORMAT().Match(line);
|
||||
if (!match.Success)
|
||||
@@ -53,7 +55,7 @@ namespace SourceGit.Commands
|
||||
{
|
||||
var renamed = new Models.Change() { Path = match.Groups[1].Value };
|
||||
renamed.Set(Models.ChangeState.Renamed);
|
||||
_changes.Add(renamed);
|
||||
outs.Add(renamed);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -66,23 +68,21 @@ namespace SourceGit.Commands
|
||||
{
|
||||
case 'M':
|
||||
change.Set(Models.ChangeState.Modified);
|
||||
_changes.Add(change);
|
||||
outs.Add(change);
|
||||
break;
|
||||
case 'A':
|
||||
change.Set(Models.ChangeState.Added);
|
||||
_changes.Add(change);
|
||||
outs.Add(change);
|
||||
break;
|
||||
case 'D':
|
||||
change.Set(Models.ChangeState.Deleted);
|
||||
_changes.Add(change);
|
||||
outs.Add(change);
|
||||
break;
|
||||
case 'C':
|
||||
change.Set(Models.ChangeState.Copied);
|
||||
_changes.Add(change);
|
||||
outs.Add(change);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<Models.Change> _changes = new List<Models.Change>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -17,15 +18,13 @@ namespace SourceGit.Commands
|
||||
Context = repository;
|
||||
_isLocal = true;
|
||||
}
|
||||
|
||||
RaiseError = false;
|
||||
}
|
||||
|
||||
public Dictionary<string, string> ListAll()
|
||||
public async Task<Dictionary<string, string>> ReadAllAsync()
|
||||
{
|
||||
Args = "config -l";
|
||||
|
||||
var output = ReadToEnd();
|
||||
var output = await ReadToEndAsync().ConfigureAwait(false);
|
||||
var rs = new Dictionary<string, string>();
|
||||
if (output.IsSuccess)
|
||||
{
|
||||
@@ -45,13 +44,15 @@ namespace SourceGit.Commands
|
||||
return rs;
|
||||
}
|
||||
|
||||
public string Get(string key)
|
||||
public async Task<string> GetAsync(string key)
|
||||
{
|
||||
Args = $"config {key}";
|
||||
return ReadToEnd().StdOut.Trim();
|
||||
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
return rs.StdOut.Trim();
|
||||
}
|
||||
|
||||
public bool Set(string key, string value, bool allowEmpty = false)
|
||||
public async Task<bool> SetAsync(string key, string value, bool allowEmpty = false)
|
||||
{
|
||||
var scope = _isLocal ? "--local" : "--global";
|
||||
|
||||
@@ -60,7 +61,7 @@ namespace SourceGit.Commands
|
||||
else
|
||||
Args = $"config {scope} {key} \"{value}\"";
|
||||
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private bool _isLocal = false;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -11,9 +12,9 @@ namespace SourceGit.Commands
|
||||
Args = "--no-optional-locks status -uno --ignore-submodules=all --porcelain";
|
||||
}
|
||||
|
||||
public int Result()
|
||||
public async Task<int> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (rs.IsSuccess)
|
||||
{
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -35,9 +36,9 @@ namespace SourceGit.Commands
|
||||
Args = $"diff --no-ext-diff --patch --unified={unified} {opt}";
|
||||
}
|
||||
|
||||
public Models.DiffResult Result()
|
||||
public async Task<Models.DiffResult> ReadAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
var start = 0;
|
||||
var end = rs.StdOut.IndexOf('\n', start);
|
||||
while (end > 0)
|
||||
@@ -248,14 +249,10 @@ namespace SourceGit.Commands
|
||||
foreach (var chunk in chunks)
|
||||
{
|
||||
if (chunk.DeletedCount > 0)
|
||||
{
|
||||
left.Highlights.Add(new Models.TextInlineRange(chunk.DeletedStart, chunk.DeletedCount));
|
||||
}
|
||||
|
||||
if (chunk.AddedCount > 0)
|
||||
{
|
||||
right.Highlights.Add(new Models.TextInlineRange(chunk.AddedStart, chunk.AddedCount));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using Avalonia.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -14,9 +13,9 @@ namespace SourceGit.Commands
|
||||
/// <param name="repo"></param>
|
||||
/// <param name="includeIgnored"></param>
|
||||
/// <param name="log"></param>
|
||||
public static void All(string repo, bool includeIgnored, Models.ICommandLog log)
|
||||
public static async Task AllAsync(string repo, bool includeIgnored, Models.ICommandLog log)
|
||||
{
|
||||
var changes = new QueryLocalChanges(repo).Result();
|
||||
var changes = await new QueryLocalChanges(repo).GetResultAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
foreach (var c in changes)
|
||||
@@ -36,16 +35,13 @@ namespace SourceGit.Commands
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(repo, $"Failed to discard changes. Reason: {e.Message}");
|
||||
});
|
||||
App.RaiseException(repo, $"Failed to discard changes. Reason: {e.Message}");
|
||||
}
|
||||
|
||||
new Reset(repo, "HEAD", "--hard") { Log = log }.Exec();
|
||||
await new Reset(repo, "HEAD", "--hard") { Log = log }.ExecAsync().ConfigureAwait(false);
|
||||
|
||||
if (includeIgnored)
|
||||
new Clean(repo) { Log = log }.Exec();
|
||||
await new Clean(repo) { Log = log }.ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -54,7 +50,7 @@ namespace SourceGit.Commands
|
||||
/// <param name="repo"></param>
|
||||
/// <param name="changes"></param>
|
||||
/// <param name="log"></param>
|
||||
public static void Changes(string repo, List<Models.Change> changes, Models.ICommandLog log)
|
||||
public static async Task ChangesAsync(string repo, List<Models.Change> changes, Models.ICommandLog log)
|
||||
{
|
||||
var restores = new List<string>();
|
||||
|
||||
@@ -78,17 +74,14 @@ namespace SourceGit.Commands
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(repo, $"Failed to discard changes. Reason: {e.Message}");
|
||||
});
|
||||
App.RaiseException(repo, $"Failed to discard changes. Reason: {e.Message}");
|
||||
}
|
||||
|
||||
if (restores.Count > 0)
|
||||
{
|
||||
var pathSpecFile = Path.GetTempFileName();
|
||||
File.WriteAllLines(pathSpecFile, restores);
|
||||
new Restore(repo, pathSpecFile, false) { Log = log }.Exec();
|
||||
await File.WriteAllLinesAsync(pathSpecFile, restores).ConfigureAwait(false);
|
||||
await new Restore(repo, pathSpecFile, false) { Log = log }.ExecAsync().ConfigureAwait(false);
|
||||
File.Delete(pathSpecFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
namespace SourceGit.Commands
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Fetch : Command
|
||||
{
|
||||
public Fetch(string repo, string remote, bool noTags, bool force)
|
||||
{
|
||||
_remoteKey = $"remote.{remote}.sshkey";
|
||||
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||
Args = "fetch --progress --verbose ";
|
||||
|
||||
if (noTags)
|
||||
@@ -18,14 +21,24 @@
|
||||
Args += "--force ";
|
||||
|
||||
Args += remote;
|
||||
|
||||
}
|
||||
|
||||
public Fetch(string repo, Models.Branch local, Models.Branch remote)
|
||||
{
|
||||
_remoteKey = $"remote.{remote.Remote}.sshkey";
|
||||
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
SSHKey = new Config(repo).Get($"remote.{remote.Remote}.sshkey");
|
||||
Args = $"fetch --progress --verbose {remote.Remote} {remote.Name}:{local.Name}";
|
||||
}
|
||||
|
||||
public async Task<bool> RunAsync()
|
||||
{
|
||||
SSHKey = await new Config(WorkingDirectory).GetAsync(_remoteKey).ConfigureAwait(false);
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private readonly string _remoteKey;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
using Avalonia.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -20,6 +19,11 @@ namespace SourceGit.Commands
|
||||
Context = repo;
|
||||
Args = $"diff --diff-algorithm=minimal {opt}";
|
||||
}
|
||||
|
||||
public async Task<Result> ReadAsync()
|
||||
{
|
||||
return await ReadToEndAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public GenerateCommitMessage(Models.OpenAIService service, string repo, List<Models.Change> changes, CancellationToken cancelToken, Action<string> onResponse)
|
||||
@@ -31,7 +35,7 @@ namespace SourceGit.Commands
|
||||
_onResponse = onResponse;
|
||||
}
|
||||
|
||||
public void Exec()
|
||||
public async Task ExecAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -47,10 +51,10 @@ namespace SourceGit.Commands
|
||||
responseBuilder.Append("- ");
|
||||
summaryBuilder.Append("- ");
|
||||
|
||||
var rs = new GetDiffContent(_repo, new Models.DiffOption(change, false)).ReadToEnd();
|
||||
var rs = await new GetDiffContent(_repo, new Models.DiffOption(change, false)).ReadAsync();
|
||||
if (rs.IsSuccess)
|
||||
{
|
||||
_service.Chat(
|
||||
await _service.ChatAsync(
|
||||
_service.AnalyzeDiffPrompt,
|
||||
$"Here is the `git diff` output: {rs.StdOut}",
|
||||
_cancelToken,
|
||||
@@ -74,7 +78,7 @@ namespace SourceGit.Commands
|
||||
|
||||
var responseBody = responseBuilder.ToString();
|
||||
var subjectBuilder = new StringBuilder();
|
||||
_service.Chat(
|
||||
await _service.ChatAsync(
|
||||
_service.GenerateSubjectPrompt,
|
||||
$"Here are the summaries changes:\n{summaryBuilder}",
|
||||
_cancelToken,
|
||||
@@ -86,7 +90,7 @@ namespace SourceGit.Commands
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() => App.RaiseException(_repo, $"Failed to generate commit message: {e}"));
|
||||
App.RaiseException(_repo, $"Failed to generate commit message: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
using System.Text;
|
||||
using Avalonia.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public static class GitFlow
|
||||
{
|
||||
public static bool Init(string repo, string master, string develop, string feature, string release, string hotfix, string version, Models.ICommandLog log)
|
||||
public static async Task<bool> InitAsync(string repo, string master, string develop, string feature, string release, string hotfix, string version, Models.ICommandLog log)
|
||||
{
|
||||
var config = new Config(repo);
|
||||
config.Set("gitflow.branch.master", master);
|
||||
config.Set("gitflow.branch.develop", develop);
|
||||
config.Set("gitflow.prefix.feature", feature);
|
||||
config.Set("gitflow.prefix.bugfix", "bugfix/");
|
||||
config.Set("gitflow.prefix.release", release);
|
||||
config.Set("gitflow.prefix.hotfix", hotfix);
|
||||
config.Set("gitflow.prefix.support", "support/");
|
||||
config.Set("gitflow.prefix.versiontag", version, true);
|
||||
await config.SetAsync("gitflow.branch.master", master).ConfigureAwait(false);
|
||||
await config.SetAsync("gitflow.branch.develop", develop).ConfigureAwait(false);
|
||||
await config.SetAsync("gitflow.prefix.feature", feature).ConfigureAwait(false);
|
||||
await config.SetAsync("gitflow.prefix.bugfix", "bugfix/").ConfigureAwait(false);
|
||||
await config.SetAsync("gitflow.prefix.release", release).ConfigureAwait(false);
|
||||
await config.SetAsync("gitflow.prefix.hotfix", hotfix).ConfigureAwait(false);
|
||||
await config.SetAsync("gitflow.prefix.support", "support/").ConfigureAwait(false);
|
||||
await config.SetAsync("gitflow.prefix.versiontag", version, true).ConfigureAwait(false);
|
||||
|
||||
var init = new Command();
|
||||
init.WorkingDirectory = repo;
|
||||
init.Context = repo;
|
||||
init.Args = "flow init -d";
|
||||
init.Log = log;
|
||||
return init.Exec();
|
||||
return await init.ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static bool Start(string repo, Models.GitFlowBranchType type, string name, Models.ICommandLog log)
|
||||
public static async Task<bool> StartAsync(string repo, Models.GitFlowBranchType type, string name, Models.ICommandLog log)
|
||||
{
|
||||
var start = new Command();
|
||||
start.WorkingDirectory = repo;
|
||||
@@ -43,15 +43,15 @@ namespace SourceGit.Commands
|
||||
start.Args = $"flow hotfix start {name}";
|
||||
break;
|
||||
default:
|
||||
Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, "Bad git-flow branch type!!!"));
|
||||
App.RaiseException(repo, "Bad git-flow branch type!!!");
|
||||
return false;
|
||||
}
|
||||
|
||||
start.Log = log;
|
||||
return start.Exec();
|
||||
return await start.ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static bool Finish(string repo, Models.GitFlowBranchType type, string name, bool squash, bool push, bool keepBranch, Models.ICommandLog log)
|
||||
public static async Task<bool> FinishAsync(string repo, Models.GitFlowBranchType type, string name, bool squash, bool push, bool keepBranch, Models.ICommandLog log)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("flow ");
|
||||
@@ -68,7 +68,7 @@ namespace SourceGit.Commands
|
||||
builder.Append("hotfix");
|
||||
break;
|
||||
default:
|
||||
Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, "Bad git-flow branch type!!!"));
|
||||
App.RaiseException(repo, "Bad git-flow branch type!!!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace SourceGit.Commands
|
||||
finish.Context = repo;
|
||||
finish.Args = builder.ToString();
|
||||
finish.Log = log;
|
||||
return finish.Exec();
|
||||
return await finish.ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -10,14 +11,14 @@ namespace SourceGit.Commands
|
||||
Args = "rev-parse --is-bare-repository";
|
||||
}
|
||||
|
||||
public bool Result()
|
||||
public async Task<bool> GetResultAsync()
|
||||
{
|
||||
if (!Directory.Exists(Path.Combine(WorkingDirectory, "refs")) ||
|
||||
!Directory.Exists(Path.Combine(WorkingDirectory, "objects")) ||
|
||||
!File.Exists(Path.Combine(WorkingDirectory, "HEAD")))
|
||||
return false;
|
||||
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
return rs.IsSuccess && rs.StdOut.Trim() == "true";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -15,9 +16,10 @@ namespace SourceGit.Commands
|
||||
RaiseError = false;
|
||||
}
|
||||
|
||||
public bool Result()
|
||||
public async Task<bool> GetResultAsync()
|
||||
{
|
||||
return REG_TEST().IsMatch(ReadToEnd().StdOut);
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
return REG_TEST().IsMatch(rs.StdOut.Trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace SourceGit.Commands
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class IsCommitSHA : Command
|
||||
{
|
||||
@@ -8,9 +10,9 @@
|
||||
Args = $"cat-file -t {hash}";
|
||||
}
|
||||
|
||||
public bool Result()
|
||||
public async Task<bool> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
return rs.IsSuccess && rs.StdOut.Trim().Equals("commit");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace SourceGit.Commands
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class IsConflictResolved : Command
|
||||
{
|
||||
@@ -11,9 +13,10 @@
|
||||
Args = $"diff -a --ignore-cr-at-eol --check {opt}";
|
||||
}
|
||||
|
||||
public bool Result()
|
||||
public async Task<bool> GetResultAsync()
|
||||
{
|
||||
return ReadToEnd().IsSuccess;
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
return rs.IsSuccess;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace SourceGit.Commands
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class IsLFSFiltered : Command
|
||||
{
|
||||
@@ -18,9 +20,9 @@
|
||||
RaiseError = false;
|
||||
}
|
||||
|
||||
public bool Result()
|
||||
public async Task<bool> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
return rs.IsSuccess && rs.StdOut.Contains("filter\0lfs");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -19,6 +20,11 @@ namespace SourceGit.Commands
|
||||
Args = args;
|
||||
Log = log;
|
||||
}
|
||||
|
||||
public async Task<Result> ReadAsync()
|
||||
{
|
||||
return await ReadToEndAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public LFS(string repo)
|
||||
@@ -36,42 +42,42 @@ namespace SourceGit.Commands
|
||||
return content.Contains("git lfs pre-push");
|
||||
}
|
||||
|
||||
public bool Install(Models.ICommandLog log)
|
||||
public async Task<bool> InstallAsync(Models.ICommandLog log)
|
||||
{
|
||||
return new SubCmd(_repo, "lfs install --local", log).Exec();
|
||||
return await new SubCmd(_repo, "lfs install --local", log).ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Track(string pattern, bool isFilenameMode, Models.ICommandLog log)
|
||||
public async Task<bool> TrackAsync(string pattern, bool isFilenameMode, Models.ICommandLog log)
|
||||
{
|
||||
var opt = isFilenameMode ? "--filename" : "";
|
||||
return new SubCmd(_repo, $"lfs track {opt} \"{pattern}\"", log).Exec();
|
||||
return await new SubCmd(_repo, $"lfs track {opt} \"{pattern}\"", log).ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public void Fetch(string remote, Models.ICommandLog log)
|
||||
public async Task FetchAsync(string remote, Models.ICommandLog log)
|
||||
{
|
||||
new SubCmd(_repo, $"lfs fetch {remote}", log).Exec();
|
||||
await new SubCmd(_repo, $"lfs fetch {remote}", log).ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public void Pull(string remote, Models.ICommandLog log)
|
||||
public async Task PullAsync(string remote, Models.ICommandLog log)
|
||||
{
|
||||
new SubCmd(_repo, $"lfs pull {remote}", log).Exec();
|
||||
await new SubCmd(_repo, $"lfs pull {remote}", log).ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public void Push(string remote, Models.ICommandLog log)
|
||||
public async Task PushAsync(string remote, Models.ICommandLog log)
|
||||
{
|
||||
new SubCmd(_repo, $"lfs push {remote}", log).Exec();
|
||||
await new SubCmd(_repo, $"lfs push {remote}", log).ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public void Prune(Models.ICommandLog log)
|
||||
public async Task PruneAsync(Models.ICommandLog log)
|
||||
{
|
||||
new SubCmd(_repo, "lfs prune", log).Exec();
|
||||
await new SubCmd(_repo, "lfs prune", log).ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public List<Models.LFSLock> Locks(string remote)
|
||||
public async Task<List<Models.LFSLock>> GetLocksAsync(string remote)
|
||||
{
|
||||
var locks = new List<Models.LFSLock>();
|
||||
var cmd = new SubCmd(_repo, $"lfs locks --remote={remote}", null);
|
||||
var rs = cmd.ReadToEnd();
|
||||
var rs = await cmd.ReadAsync().ConfigureAwait(false);
|
||||
if (rs.IsSuccess)
|
||||
{
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
@@ -93,21 +99,21 @@ namespace SourceGit.Commands
|
||||
return locks;
|
||||
}
|
||||
|
||||
public bool Lock(string remote, string file, Models.ICommandLog log)
|
||||
public async Task<bool> LockAsync(string remote, string file, Models.ICommandLog log)
|
||||
{
|
||||
return new SubCmd(_repo, $"lfs lock --remote={remote} \"{file}\"", log).Exec();
|
||||
return await new SubCmd(_repo, $"lfs lock --remote={remote} \"{file}\"", log).ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Unlock(string remote, string file, bool force, Models.ICommandLog log)
|
||||
public async Task<bool> UnlockAsync(string remote, string file, bool force, Models.ICommandLog log)
|
||||
{
|
||||
var opt = force ? "-f" : "";
|
||||
return new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} \"{file}\"", log).Exec();
|
||||
return await new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} \"{file}\"", log).ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Unlock(string remote, long id, bool force, Models.ICommandLog log)
|
||||
public async Task<bool> UnlockAsync(string remote, long id, bool force, Models.ICommandLog log)
|
||||
{
|
||||
var opt = force ? "-f" : "";
|
||||
return new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} --id={id}", log).Exec();
|
||||
return await new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} --id={id}", log).ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private readonly string _repo;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
using System.IO;
|
||||
|
||||
using Avalonia.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public static class MergeTool
|
||||
{
|
||||
public static bool OpenForMerge(string repo, int toolType, string toolPath, string file)
|
||||
public static async Task<bool> OpenForMergeAsync(string repo, int toolType, string toolPath, string file)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
@@ -19,27 +18,27 @@ namespace SourceGit.Commands
|
||||
if (toolType == 0)
|
||||
{
|
||||
cmd.Args = $"mergetool {fileArg}";
|
||||
return cmd.Exec();
|
||||
return await cmd.ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (!File.Exists(toolPath))
|
||||
{
|
||||
Dispatcher.UIThread.Post(() => App.RaiseException(repo, $"Can NOT find external merge tool in '{toolPath}'!"));
|
||||
App.RaiseException(repo, $"Can NOT find external merge tool in '{toolPath}'!");
|
||||
return false;
|
||||
}
|
||||
|
||||
var supported = Models.ExternalMerger.Supported.Find(x => x.Type == toolType);
|
||||
if (supported == null)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() => App.RaiseException(repo, "Invalid merge tool in preference setting!"));
|
||||
App.RaiseException(repo, "Invalid merge tool in preference setting!");
|
||||
return false;
|
||||
}
|
||||
|
||||
cmd.Args = $"-c mergetool.sourcegit.cmd=\"\\\"{toolPath}\\\" {supported.Cmd}\" -c mergetool.writeToTemp=true -c mergetool.keepBackup=false -c mergetool.trustExitCode=true mergetool --tool=sourcegit {fileArg}";
|
||||
return cmd.Exec();
|
||||
return await cmd.ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static bool OpenForDiff(string repo, int toolType, string toolPath, Models.DiffOption option)
|
||||
public static async Task<bool> OpenForDiffAsync(string repo, int toolType, string toolPath, Models.DiffOption option)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
@@ -49,24 +48,24 @@ namespace SourceGit.Commands
|
||||
if (toolType == 0)
|
||||
{
|
||||
cmd.Args = $"difftool -g --no-prompt {option}";
|
||||
return cmd.Exec();
|
||||
return await cmd.ExecAsync();
|
||||
}
|
||||
|
||||
if (!File.Exists(toolPath))
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, $"Can NOT find external diff tool in '{toolPath}'!"));
|
||||
App.RaiseException(repo, $"Can NOT find external diff tool in '{toolPath}'!");
|
||||
return false;
|
||||
}
|
||||
|
||||
var supported = Models.ExternalMerger.Supported.Find(x => x.Type == toolType);
|
||||
if (supported == null)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() => App.RaiseException(repo, "Invalid merge tool in preference setting!"));
|
||||
App.RaiseException(repo, "Invalid merge tool in preference setting!");
|
||||
return false;
|
||||
}
|
||||
|
||||
cmd.Args = $"-c difftool.sourcegit.cmd=\"\\\"{toolPath}\\\" {supported.DiffCmd}\" difftool --tool=sourcegit --no-prompt {option}";
|
||||
return cmd.Exec();
|
||||
return await cmd.ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
25
src/Commands/Move.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Text;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Move : Command
|
||||
{
|
||||
public Move(string repo, string oldPath, string newPath, bool force)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("mv -v ");
|
||||
if (force)
|
||||
builder.Append("-f ");
|
||||
builder.Append('"');
|
||||
builder.Append(oldPath);
|
||||
builder.Append("\" \"");
|
||||
builder.Append(newPath);
|
||||
builder.Append('"');
|
||||
|
||||
Args = builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
namespace SourceGit.Commands
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Pull : Command
|
||||
{
|
||||
public Pull(string repo, string remote, string branch, bool useRebase)
|
||||
{
|
||||
_remote = remote;
|
||||
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||
Args = "pull --verbose --progress ";
|
||||
|
||||
if (useRebase)
|
||||
@@ -14,5 +17,13 @@
|
||||
|
||||
Args += $"{remote} {branch}";
|
||||
}
|
||||
|
||||
public async Task<bool> RunAsync()
|
||||
{
|
||||
SSHKey = await new Config(WorkingDirectory).GetAsync($"remote.{_remote}.sshkey").ConfigureAwait(false);
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private readonly string _remote;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
namespace SourceGit.Commands
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Push : Command
|
||||
{
|
||||
public Push(string repo, string local, string remote, string remoteBranch, bool withTags, bool checkSubmodules, bool track, bool force)
|
||||
{
|
||||
_remote = remote;
|
||||
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||
Args = "push --progress --verbose ";
|
||||
|
||||
if (withTags)
|
||||
@@ -23,9 +26,10 @@
|
||||
|
||||
public Push(string repo, string remote, string refname, bool isDelete)
|
||||
{
|
||||
_remote = remote;
|
||||
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
|
||||
Args = "push ";
|
||||
|
||||
if (isDelete)
|
||||
@@ -33,5 +37,13 @@
|
||||
|
||||
Args += $"{remote} {refname}";
|
||||
}
|
||||
|
||||
public async Task<bool> RunAsync()
|
||||
{
|
||||
SSHKey = await new Config(WorkingDirectory).GetAsync($"remote.{_remote}.sshkey").ConfigureAwait(false);
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private readonly string _remote;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -16,10 +17,10 @@ namespace SourceGit.Commands
|
||||
RaiseError = false;
|
||||
}
|
||||
|
||||
public List<string> Result()
|
||||
public async Task<List<string>> GetResultAsync()
|
||||
{
|
||||
var outs = new List<string>();
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -17,12 +18,10 @@ namespace SourceGit.Commands
|
||||
Args = "branch -l --all -v --format=\"%(refname)%00%(committerdate:unix)%00%(objectname)%00%(HEAD)%00%(upstream)%00%(upstream:trackshort)\"";
|
||||
}
|
||||
|
||||
public List<Models.Branch> Result(out int localBranchesCount)
|
||||
public async Task<List<Models.Branch>> GetResultAsync()
|
||||
{
|
||||
localBranchesCount = 0;
|
||||
|
||||
var branches = new List<Models.Branch>();
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return branches;
|
||||
|
||||
@@ -36,8 +35,6 @@ namespace SourceGit.Commands
|
||||
branches.Add(b);
|
||||
if (!b.IsLocal)
|
||||
remoteHeads.Add(b.FullName, b.Head);
|
||||
else
|
||||
localBranchesCount++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +45,7 @@ namespace SourceGit.Commands
|
||||
if (remoteHeads.TryGetValue(b.Upstream, out var upstreamHead))
|
||||
{
|
||||
b.IsUpstreamGone = false;
|
||||
b.TrackStatus ??= new QueryTrackStatus(WorkingDirectory, b.Head, upstreamHead).Result();
|
||||
b.TrackStatus ??= await new QueryTrackStatus(WorkingDirectory, b.Head, upstreamHead).GetResultAsync().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -13,9 +14,9 @@ namespace SourceGit.Commands
|
||||
Args = $"rev-list -{max} --parents --branches --remotes --ancestry-path ^{commit}";
|
||||
}
|
||||
|
||||
public List<string> Result()
|
||||
public async Task<List<string>> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
var outs = new List<string>();
|
||||
if (rs.IsSuccess)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryCommitFullMessage : Command
|
||||
@@ -9,12 +11,10 @@ namespace SourceGit.Commands
|
||||
Args = $"show --no-show-signature --format=%B -s {sha}";
|
||||
}
|
||||
|
||||
public string Result()
|
||||
public async Task<string> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
if (rs.IsSuccess)
|
||||
return rs.StdOut.TrimEnd();
|
||||
return string.Empty;
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
return rs.IsSuccess ? rs.StdOut.TrimEnd() : string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace SourceGit.Commands
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryCommitSignInfo : Command
|
||||
{
|
||||
@@ -12,9 +14,9 @@
|
||||
Args = $"{(useFakeSignersFile ? fakeSignersFileArg : string.Empty)} {baseArgs} {sha}";
|
||||
}
|
||||
|
||||
public Models.CommitSignInfo Result()
|
||||
public async Task<Models.CommitSignInfo> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return null;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -56,9 +57,9 @@ namespace SourceGit.Commands
|
||||
_findFirstMerged = false;
|
||||
}
|
||||
|
||||
public List<Models.Commit> Result()
|
||||
public async Task<List<Models.Commit>> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return _commits;
|
||||
|
||||
@@ -110,7 +111,7 @@ namespace SourceGit.Commands
|
||||
_current.Subject = rs.StdOut.Substring(start);
|
||||
|
||||
if (_findFirstMerged && !_isHeadFounded && _commits.Count > 0)
|
||||
MarkFirstMerged();
|
||||
await MarkFirstMergedAsync().ConfigureAwait(false);
|
||||
|
||||
return _commits;
|
||||
}
|
||||
@@ -120,21 +121,19 @@ namespace SourceGit.Commands
|
||||
if (data.Length < 8)
|
||||
return;
|
||||
|
||||
_current.Parents.AddRange(data.Split(separator: ' ', options: StringSplitOptions.RemoveEmptyEntries));
|
||||
_current.Parents.AddRange(data.Split(' ', StringSplitOptions.RemoveEmptyEntries));
|
||||
}
|
||||
|
||||
private void MarkFirstMerged()
|
||||
private async Task MarkFirstMergedAsync()
|
||||
{
|
||||
Args = $"log --since=\"{_commits[^1].CommitterTimeStr}\" --format=\"%H\"";
|
||||
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
var shas = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
if (shas.Length == 0)
|
||||
return;
|
||||
|
||||
var set = new HashSet<string>();
|
||||
foreach (var sha in shas)
|
||||
set.Add(sha);
|
||||
var set = new HashSet<string>(shas);
|
||||
|
||||
foreach (var c in _commits)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -14,9 +15,9 @@ namespace SourceGit.Commands
|
||||
Args = $"log --date-order --no-show-signature --decorate=full --format=\"%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%B%n{_boundary}\" {on}..HEAD";
|
||||
}
|
||||
|
||||
public List<Models.InteractiveCommit> Result()
|
||||
public async Task<List<Models.InteractiveCommit>> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return _commits;
|
||||
|
||||
@@ -85,7 +86,7 @@ namespace SourceGit.Commands
|
||||
if (data.Length < 8)
|
||||
return;
|
||||
|
||||
_current.Commit.Parents.AddRange(data.Split(separator: ' ', options: StringSplitOptions.RemoveEmptyEntries));
|
||||
_current.Commit.Parents.AddRange(data.Split(' ', StringSplitOptions.RemoveEmptyEntries));
|
||||
}
|
||||
|
||||
private List<Models.InteractiveCommit> _commits = [];
|
||||
|
||||
20
src/Commands/QueryCurrentBranch.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryCurrentBranch : Command
|
||||
{
|
||||
public QueryCurrentBranch(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = "branch --show-current";
|
||||
}
|
||||
|
||||
public async Task<string> GetResultAsync()
|
||||
{
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
return rs.StdOut.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public static class QueryFileContent
|
||||
{
|
||||
public static Stream Run(string repo, string revision, string file)
|
||||
public static async Task<Stream> RunAsync(string repo, string revision, string file)
|
||||
{
|
||||
var starter = new ProcessStartInfo();
|
||||
starter.WorkingDirectory = repo;
|
||||
@@ -22,8 +23,8 @@ namespace SourceGit.Commands
|
||||
{
|
||||
var proc = new Process() { StartInfo = starter };
|
||||
proc.Start();
|
||||
proc.StandardOutput.BaseStream.CopyTo(stream);
|
||||
proc.WaitForExit();
|
||||
await proc.StandardOutput.BaseStream.CopyToAsync(stream).ConfigureAwait(false);
|
||||
await proc.WaitForExitAsync().ConfigureAwait(false);
|
||||
proc.Close();
|
||||
|
||||
stream.Position = 0;
|
||||
@@ -36,7 +37,7 @@ namespace SourceGit.Commands
|
||||
return stream;
|
||||
}
|
||||
|
||||
public static Stream FromLFS(string repo, string oid, long size)
|
||||
public static async Task<Stream> FromLFSAsync(string repo, string oid, long size)
|
||||
{
|
||||
var starter = new ProcessStartInfo();
|
||||
starter.WorkingDirectory = repo;
|
||||
@@ -53,11 +54,11 @@ namespace SourceGit.Commands
|
||||
{
|
||||
var proc = new Process() { StartInfo = starter };
|
||||
proc.Start();
|
||||
proc.StandardInput.WriteLine("version https://git-lfs.github.com/spec/v1");
|
||||
proc.StandardInput.WriteLine($"oid sha256:{oid}");
|
||||
proc.StandardInput.WriteLine($"size {size}");
|
||||
proc.StandardOutput.BaseStream.CopyTo(stream);
|
||||
proc.WaitForExit();
|
||||
await proc.StandardInput.WriteLineAsync("version https://git-lfs.github.com/spec/v1").ConfigureAwait(false);
|
||||
await proc.StandardInput.WriteLineAsync($"oid sha256:{oid}").ConfigureAwait(false);
|
||||
await proc.StandardInput.WriteLineAsync($"size {size}").ConfigureAwait(false);
|
||||
await proc.StandardOutput.BaseStream.CopyToAsync(stream).ConfigureAwait(false);
|
||||
await proc.WaitForExitAsync().ConfigureAwait(false);
|
||||
proc.Close();
|
||||
|
||||
stream.Position = 0;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -14,9 +15,9 @@ namespace SourceGit.Commands
|
||||
Args = $"ls-tree {revision} -l -- \"{file}\"";
|
||||
}
|
||||
|
||||
public long Result()
|
||||
public async Task<long> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (rs.IsSuccess)
|
||||
{
|
||||
var match = REG_FORMAT().Match(rs.StdOut);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -8,19 +9,19 @@ namespace SourceGit.Commands
|
||||
{
|
||||
WorkingDirectory = workDir;
|
||||
Args = "rev-parse --git-common-dir";
|
||||
RaiseError = false;
|
||||
}
|
||||
|
||||
public string Result()
|
||||
public async Task<string> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd().StdOut;
|
||||
if (string.IsNullOrEmpty(rs))
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return null;
|
||||
|
||||
rs = rs.Trim();
|
||||
if (Path.IsPathRooted(rs))
|
||||
return rs;
|
||||
return Path.GetFullPath(Path.Combine(WorkingDirectory, rs));
|
||||
var stdout = rs.StdOut.Trim();
|
||||
if (string.IsNullOrEmpty(stdout))
|
||||
return null;
|
||||
|
||||
return Path.IsPathRooted(stdout) ? stdout : Path.GetFullPath(Path.Combine(WorkingDirectory, stdout));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -8,19 +9,19 @@ namespace SourceGit.Commands
|
||||
{
|
||||
WorkingDirectory = workDir;
|
||||
Args = "rev-parse --git-dir";
|
||||
RaiseError = false;
|
||||
}
|
||||
|
||||
public string Result()
|
||||
public async Task<string> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd().StdOut;
|
||||
if (string.IsNullOrEmpty(rs))
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return null;
|
||||
|
||||
rs = rs.Trim();
|
||||
if (Path.IsPathRooted(rs))
|
||||
return rs;
|
||||
return Path.GetFullPath(Path.Combine(WorkingDirectory, rs));
|
||||
var stdout = rs.StdOut.Trim();
|
||||
if (string.IsNullOrEmpty(stdout))
|
||||
return null;
|
||||
|
||||
return Path.IsPathRooted(stdout) ? stdout : Path.GetFullPath(Path.Combine(WorkingDirectory, stdout));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using Avalonia.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -19,13 +18,13 @@ namespace SourceGit.Commands
|
||||
Args = $"--no-optional-locks status -u{UNTRACKED[includeUntracked ? 1 : 0]} --ignore-submodules=dirty --porcelain";
|
||||
}
|
||||
|
||||
public List<Models.Change> Result()
|
||||
public async Task<List<Models.Change>> GetResultAsync()
|
||||
{
|
||||
var outs = new List<Models.Change>();
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() => App.RaiseException(Context, rs.StdErr));
|
||||
App.RaiseException(Context, rs.StdErr);
|
||||
return outs;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -12,29 +13,28 @@ namespace SourceGit.Commands
|
||||
Args = $"for-each-ref --format=\"%(refname)\" --contains {commit}";
|
||||
}
|
||||
|
||||
public List<Models.Decorator> Result()
|
||||
public async Task<List<Models.Decorator>> GetResultAsync()
|
||||
{
|
||||
var rs = new List<Models.Decorator>();
|
||||
var outs = new List<Models.Decorator>();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return outs;
|
||||
|
||||
var output = ReadToEnd();
|
||||
if (!output.IsSuccess)
|
||||
return rs;
|
||||
|
||||
var lines = output.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (line.EndsWith("/HEAD", StringComparison.Ordinal))
|
||||
continue;
|
||||
|
||||
if (line.StartsWith("refs/heads/", StringComparison.Ordinal))
|
||||
rs.Add(new() { Name = line.Substring("refs/heads/".Length), Type = Models.DecoratorType.LocalBranchHead });
|
||||
outs.Add(new() { Name = line.Substring("refs/heads/".Length), Type = Models.DecoratorType.LocalBranchHead });
|
||||
else if (line.StartsWith("refs/remotes/", StringComparison.Ordinal))
|
||||
rs.Add(new() { Name = line.Substring("refs/remotes/".Length), Type = Models.DecoratorType.RemoteBranchHead });
|
||||
outs.Add(new() { Name = line.Substring("refs/remotes/".Length), Type = Models.DecoratorType.RemoteBranchHead });
|
||||
else if (line.StartsWith("refs/tags/", StringComparison.Ordinal))
|
||||
rs.Add(new() { Name = line.Substring("refs/tags/".Length), Type = Models.DecoratorType.Tag });
|
||||
outs.Add(new() { Name = line.Substring("refs/tags/".Length), Type = Models.DecoratorType.Tag });
|
||||
}
|
||||
|
||||
return rs;
|
||||
return outs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -16,10 +17,10 @@ namespace SourceGit.Commands
|
||||
Args = "remote -v";
|
||||
}
|
||||
|
||||
public List<Models.Remote> Result()
|
||||
public async Task<List<Models.Remote>> GetResultAsync()
|
||||
{
|
||||
var outs = new List<Models.Remote>();
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return outs;
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace SourceGit.Commands
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryRepositoryRootPath : Command
|
||||
{
|
||||
@@ -7,5 +9,10 @@
|
||||
WorkingDirectory = path;
|
||||
Args = "rev-parse --show-toplevel";
|
||||
}
|
||||
|
||||
public async Task<Result> GetResultAsync()
|
||||
{
|
||||
return await ReadToEndAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace SourceGit.Commands
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryRevisionByRefName : Command
|
||||
{
|
||||
@@ -9,9 +11,9 @@
|
||||
Args = $"rev-parse {refname}";
|
||||
}
|
||||
|
||||
public string Result()
|
||||
public async Task<string> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (rs.IsSuccess && !string.IsNullOrEmpty(rs.StdOut))
|
||||
return rs.StdOut.Trim();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -11,17 +12,14 @@ namespace SourceGit.Commands
|
||||
Args = $"ls-tree -r -z --name-only {revision}";
|
||||
}
|
||||
|
||||
public List<string> Result()
|
||||
public async Task<List<string>> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return [];
|
||||
|
||||
var lines = rs.StdOut.Split('\0', System.StringSplitOptions.RemoveEmptyEntries);
|
||||
var outs = new List<string>();
|
||||
foreach (var line in lines)
|
||||
outs.Add(line);
|
||||
return outs;
|
||||
return [.. lines];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -18,9 +19,10 @@ namespace SourceGit.Commands
|
||||
Args += $" -- \"{parentFolder}\"";
|
||||
}
|
||||
|
||||
public List<Models.Object> Result()
|
||||
public async Task<List<Models.Object>> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var outs = new List<Models.Object>();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (rs.IsSuccess)
|
||||
{
|
||||
var start = 0;
|
||||
@@ -28,19 +30,19 @@ namespace SourceGit.Commands
|
||||
while (end > 0)
|
||||
{
|
||||
var line = rs.StdOut.Substring(start, end - start);
|
||||
Parse(line);
|
||||
Parse(outs, line);
|
||||
start = end + 1;
|
||||
end = rs.StdOut.IndexOf('\0', start);
|
||||
}
|
||||
|
||||
if (start < rs.StdOut.Length)
|
||||
Parse(rs.StdOut.Substring(start));
|
||||
Parse(outs, rs.StdOut.Substring(start));
|
||||
}
|
||||
|
||||
return _objects;
|
||||
return outs;
|
||||
}
|
||||
|
||||
private void Parse(string line)
|
||||
private void Parse(List<Models.Object> outs, string line)
|
||||
{
|
||||
var match = REG_FORMAT().Match(line);
|
||||
if (!match.Success)
|
||||
@@ -60,9 +62,7 @@ namespace SourceGit.Commands
|
||||
_ => obj.Type,
|
||||
};
|
||||
|
||||
_objects.Add(obj);
|
||||
outs.Add(obj);
|
||||
}
|
||||
|
||||
private List<Models.Object> _objects = new List<Models.Object>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -11,9 +12,9 @@ namespace SourceGit.Commands
|
||||
Args = $"show --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s -s {sha}";
|
||||
}
|
||||
|
||||
public Models.Commit Result()
|
||||
public async Task<Models.Commit> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (rs.IsSuccess && !string.IsNullOrEmpty(rs.StdOut))
|
||||
{
|
||||
var commit = new Models.Commit();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -19,9 +20,9 @@ namespace SourceGit.Commands
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
public List<Models.Change> Result()
|
||||
public async Task<List<Models.Change>> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return [];
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -14,16 +15,11 @@ namespace SourceGit.Commands
|
||||
Args = $"ls-files -s -- \"{file}\"";
|
||||
}
|
||||
|
||||
public string Result()
|
||||
public async Task<string> GetResultAsync()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
var match = REG_FORMAT().Match(rs.StdOut.Trim());
|
||||
if (match.Success)
|
||||
{
|
||||
return match.Groups[1].Value;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
return match.Success ? match.Groups[1].Value : string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -12,10 +13,10 @@ namespace SourceGit.Commands
|
||||
Args = "stash list -z --no-show-signature --format=\"%H%n%P%n%ct%n%gd%n%B\"";
|
||||
}
|
||||
|
||||
public List<Models.Stash> Result()
|
||||
public async Task<List<Models.Stash>> GetResultAsync()
|
||||
{
|
||||
var outs = new List<Models.Stash>();
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return outs;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -21,10 +22,10 @@ namespace SourceGit.Commands
|
||||
Args = "submodule status";
|
||||
}
|
||||
|
||||
public List<Models.Submodule> Result()
|
||||
public async Task<List<Models.Submodule>> GetResultAsync()
|
||||
{
|
||||
var submodules = new List<Models.Submodule>();
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
var map = new Dictionary<string, Models.Submodule>();
|
||||
@@ -64,11 +65,12 @@ namespace SourceGit.Commands
|
||||
if (submodules.Count > 0)
|
||||
{
|
||||
Args = "config --file .gitmodules --list";
|
||||
rs = ReadToEnd();
|
||||
rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (rs.IsSuccess)
|
||||
{
|
||||
var modules = new Dictionary<string, ModuleInfo>();
|
||||
lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var match = REG_FORMAT_MODULE_INFO().Match(line);
|
||||
@@ -80,21 +82,39 @@ namespace SourceGit.Commands
|
||||
|
||||
if (!modules.TryGetValue(name, out var m))
|
||||
{
|
||||
m = new ModuleInfo();
|
||||
modules.Add(name, m);
|
||||
// Find name alias.
|
||||
foreach (var kv in modules)
|
||||
{
|
||||
if (kv.Value.Path.Equals(name, StringComparison.Ordinal))
|
||||
{
|
||||
m = kv.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m == null)
|
||||
{
|
||||
m = new ModuleInfo();
|
||||
modules.Add(name, m);
|
||||
}
|
||||
}
|
||||
|
||||
if (key.Equals("path", StringComparison.Ordinal))
|
||||
m.Path = val;
|
||||
else if (key.Equals("url", StringComparison.Ordinal))
|
||||
m.URL = val;
|
||||
else if (key.Equals("branch", StringComparison.Ordinal))
|
||||
m.Branch = val;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var kv in modules)
|
||||
{
|
||||
if (map.TryGetValue(kv.Value.Path, out var m))
|
||||
{
|
||||
m.URL = kv.Value.URL;
|
||||
m.Branch = kv.Value.Branch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,7 +133,7 @@ namespace SourceGit.Commands
|
||||
}
|
||||
|
||||
Args = $"--no-optional-locks status --porcelain -- {builder}";
|
||||
rs = ReadToEnd();
|
||||
rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return submodules;
|
||||
|
||||
@@ -137,6 +157,7 @@ namespace SourceGit.Commands
|
||||
{
|
||||
public string Path { get; set; } = string.Empty;
|
||||
public string URL { get; set; } = string.Empty;
|
||||
public string Branch { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -14,10 +15,10 @@ namespace SourceGit.Commands
|
||||
Args = $"tag -l --format=\"{_boundary}%(refname)%00%(objecttype)%00%(objectname)%00%(*objectname)%00%(creatordate:unix)%00%(contents:subject)%0a%0a%(contents:body)\"";
|
||||
}
|
||||
|
||||
public List<Models.Tag> Result()
|
||||
public async Task<List<Models.Tag>> GetResultAsync()
|
||||
{
|
||||
var tags = new List<Models.Tag>();
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return tags;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -11,11 +12,11 @@ namespace SourceGit.Commands
|
||||
Args = $"rev-list --left-right {local}...{upstream}";
|
||||
}
|
||||
|
||||
public Models.BranchTrackStatus Result()
|
||||
public async Task<Models.BranchTrackStatus> GetResultAsync()
|
||||
{
|
||||
var status = new Models.BranchTrackStatus();
|
||||
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return status;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -16,10 +17,10 @@ namespace SourceGit.Commands
|
||||
Args = "submodule status";
|
||||
}
|
||||
|
||||
public List<string> Result()
|
||||
public async Task<List<string>> GetResultAsync()
|
||||
{
|
||||
var submodules = new List<string>();
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace SourceGit.Commands
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class Remote : Command
|
||||
{
|
||||
@@ -8,50 +10,50 @@
|
||||
Context = repo;
|
||||
}
|
||||
|
||||
public bool Add(string name, string url)
|
||||
public async Task<bool> AddAsync(string name, string url)
|
||||
{
|
||||
Args = $"remote add {name} {url}";
|
||||
return Exec();
|
||||
return await ExecAsync();
|
||||
}
|
||||
|
||||
public bool Delete(string name)
|
||||
public async Task<bool> DeleteAsync(string name)
|
||||
{
|
||||
Args = $"remote remove {name}";
|
||||
return Exec();
|
||||
return await ExecAsync();
|
||||
}
|
||||
|
||||
public bool Rename(string name, string to)
|
||||
public async Task<bool> RenameAsync(string name, string to)
|
||||
{
|
||||
Args = $"remote rename {name} {to}";
|
||||
return Exec();
|
||||
return await ExecAsync();
|
||||
}
|
||||
|
||||
public bool Prune(string name)
|
||||
public async Task<bool> PruneAsync(string name)
|
||||
{
|
||||
Args = $"remote prune {name}";
|
||||
return Exec();
|
||||
return await ExecAsync();
|
||||
}
|
||||
|
||||
public string GetURL(string name, bool isPush)
|
||||
public async Task<string> GetURLAsync(string name, bool isPush)
|
||||
{
|
||||
Args = "remote get-url" + (isPush ? " --push " : " ") + name;
|
||||
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync();
|
||||
return rs.IsSuccess ? rs.StdOut.Trim() : string.Empty;
|
||||
}
|
||||
|
||||
public bool SetURL(string name, string url, bool isPush)
|
||||
public async Task<bool> SetURLAsync(string name, string url, bool isPush)
|
||||
{
|
||||
Args = "remote set-url" + (isPush ? " --push " : " ") + $"{name} {url}";
|
||||
return Exec();
|
||||
return await ExecAsync();
|
||||
}
|
||||
|
||||
public bool HasBranch(string remote, string branch)
|
||||
public async Task<bool> HasBranchAsync(string remote, string branch)
|
||||
{
|
||||
SSHKey = new Config(WorkingDirectory).Get($"remote.{remote}.sshkey");
|
||||
SSHKey = await new Config(WorkingDirectory).GetAsync($"remote.{remote}.sshkey");
|
||||
Args = $"ls-remote {remote} {branch}";
|
||||
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync();
|
||||
return rs.IsSuccess && rs.StdOut.Trim().Length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,20 +2,19 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
using Avalonia.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public static class SaveChangesAsPatch
|
||||
{
|
||||
public static bool ProcessLocalChanges(string repo, List<Models.Change> changes, bool isUnstaged, string saveTo)
|
||||
public static async Task<bool> ProcessLocalChangesAsync(string repo, List<Models.Change> changes, bool isUnstaged, string saveTo)
|
||||
{
|
||||
using (var sw = File.Create(saveTo))
|
||||
await using (var sw = File.Create(saveTo))
|
||||
{
|
||||
foreach (var change in changes)
|
||||
{
|
||||
if (!ProcessSingleChange(repo, new Models.DiffOption(change, isUnstaged), sw))
|
||||
if (!await ProcessSingleChangeAsync(repo, new Models.DiffOption(change, isUnstaged), sw))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -23,13 +22,13 @@ namespace SourceGit.Commands
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ProcessRevisionCompareChanges(string repo, List<Models.Change> changes, string baseRevision, string targetRevision, string saveTo)
|
||||
public static async Task<bool> ProcessRevisionCompareChangesAsync(string repo, List<Models.Change> changes, string baseRevision, string targetRevision, string saveTo)
|
||||
{
|
||||
using (var sw = File.Create(saveTo))
|
||||
await using (var sw = File.Create(saveTo))
|
||||
{
|
||||
foreach (var change in changes)
|
||||
{
|
||||
if (!ProcessSingleChange(repo, new Models.DiffOption(baseRevision, targetRevision, change), sw))
|
||||
if (!await ProcessSingleChangeAsync(repo, new Models.DiffOption(baseRevision, targetRevision, change), sw))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -37,20 +36,20 @@ namespace SourceGit.Commands
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ProcessStashChanges(string repo, List<Models.DiffOption> opts, string saveTo)
|
||||
public static async Task<bool> ProcessStashChangesAsync(string repo, List<Models.DiffOption> opts, string saveTo)
|
||||
{
|
||||
using (var sw = File.Create(saveTo))
|
||||
await using (var sw = File.Create(saveTo))
|
||||
{
|
||||
foreach (var opt in opts)
|
||||
{
|
||||
if (!ProcessSingleChange(repo, opt, sw))
|
||||
if (!await ProcessSingleChangeAsync(repo, opt, sw))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool ProcessSingleChange(string repo, Models.DiffOption opt, FileStream writer)
|
||||
private static async Task<bool> ProcessSingleChangeAsync(string repo, Models.DiffOption opt, FileStream writer)
|
||||
{
|
||||
var starter = new ProcessStartInfo();
|
||||
starter.WorkingDirectory = repo;
|
||||
@@ -65,8 +64,8 @@ namespace SourceGit.Commands
|
||||
{
|
||||
var proc = new Process() { StartInfo = starter };
|
||||
proc.Start();
|
||||
proc.StandardOutput.BaseStream.CopyTo(writer);
|
||||
proc.WaitForExit();
|
||||
await proc.StandardOutput.BaseStream.CopyToAsync(writer).ConfigureAwait(false);
|
||||
await proc.WaitForExitAsync().ConfigureAwait(false);
|
||||
var rs = proc.ExitCode == 0;
|
||||
proc.Close();
|
||||
|
||||
@@ -74,10 +73,7 @@ namespace SourceGit.Commands
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(repo, "Save change to patch failed: " + e.Message);
|
||||
});
|
||||
App.RaiseException(repo, "Save change to patch failed: " + e.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
using Avalonia.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public static class SaveRevisionFile
|
||||
{
|
||||
public static void Run(string repo, string revision, string file, string saveTo)
|
||||
public static async Task RunAsync(string repo, string revision, string file, string saveTo)
|
||||
{
|
||||
var dir = Path.GetDirectoryName(saveTo);
|
||||
if (!Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
var isLFSFiltered = new IsLFSFiltered(repo, revision, file).Result();
|
||||
var isLFSFiltered = await new IsLFSFiltered(repo, revision, file).GetResultAsync().ConfigureAwait(false);
|
||||
if (isLFSFiltered)
|
||||
{
|
||||
var pointerStream = QueryFileContent.Run(repo, revision, file);
|
||||
ExecCmd(repo, "lfs smudge", saveTo, pointerStream);
|
||||
var pointerStream = await QueryFileContent.RunAsync(repo, revision, file).ConfigureAwait(false);
|
||||
await ExecCmdAsync(repo, "lfs smudge", saveTo, pointerStream).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExecCmd(repo, $"show {revision}:\"{file}\"", saveTo);
|
||||
await ExecCmdAsync(repo, $"show {revision}:\"{file}\"", saveTo).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ExecCmd(string repo, string args, string outputFile, Stream input = null)
|
||||
private static async Task ExecCmdAsync(string repo, string args, string outputFile, Stream input = null)
|
||||
{
|
||||
var starter = new ProcessStartInfo();
|
||||
starter.WorkingDirectory = repo;
|
||||
@@ -39,24 +38,21 @@ namespace SourceGit.Commands
|
||||
starter.RedirectStandardOutput = true;
|
||||
starter.RedirectStandardError = true;
|
||||
|
||||
using (var sw = File.OpenWrite(outputFile))
|
||||
await using (var sw = File.OpenWrite(outputFile))
|
||||
{
|
||||
try
|
||||
{
|
||||
var proc = new Process() { StartInfo = starter };
|
||||
proc.Start();
|
||||
if (input != null)
|
||||
proc.StandardInput.Write(new StreamReader(input).ReadToEnd());
|
||||
proc.StandardOutput.BaseStream.CopyTo(sw);
|
||||
proc.WaitForExit();
|
||||
await proc.StandardInput.WriteAsync(await new StreamReader(input).ReadToEndAsync());
|
||||
await proc.StandardOutput.BaseStream.CopyToAsync(sw);
|
||||
await proc.WaitForExitAsync();
|
||||
proc.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(repo, "Save file failed: " + e.Message);
|
||||
});
|
||||
App.RaiseException(repo, "Save file failed: " + e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -11,7 +12,7 @@ namespace SourceGit.Commands
|
||||
Context = repo;
|
||||
}
|
||||
|
||||
public bool Push(string message, bool includeUntracked = true, bool keepIndex = false)
|
||||
public async Task<bool> PushAsync(string message, bool includeUntracked = true, bool keepIndex = false)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("stash push ");
|
||||
@@ -24,10 +25,10 @@ namespace SourceGit.Commands
|
||||
builder.Append("\"");
|
||||
|
||||
Args = builder.ToString();
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Push(string message, List<Models.Change> changes, bool keepIndex)
|
||||
public async Task<bool> PushAsync(string message, List<Models.Change> changes, bool keepIndex)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("stash push --include-untracked ");
|
||||
@@ -41,10 +42,10 @@ namespace SourceGit.Commands
|
||||
builder.Append($"\"{c.Path}\" ");
|
||||
|
||||
Args = builder.ToString();
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Push(string message, string pathspecFromFile, bool keepIndex)
|
||||
public async Task<bool> PushAsync(string message, string pathspecFromFile, bool keepIndex)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("stash push --include-untracked --pathspec-from-file=\"");
|
||||
@@ -57,10 +58,10 @@ namespace SourceGit.Commands
|
||||
builder.Append("\"");
|
||||
|
||||
Args = builder.ToString();
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool PushOnlyStaged(string message, bool keepIndex)
|
||||
public async Task<bool> PushOnlyStagedAsync(string message, bool keepIndex)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("stash push --staged ");
|
||||
@@ -70,32 +71,32 @@ namespace SourceGit.Commands
|
||||
builder.Append(message);
|
||||
builder.Append("\"");
|
||||
Args = builder.ToString();
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Apply(string name, bool restoreIndex)
|
||||
public async Task<bool> ApplyAsync(string name, bool restoreIndex)
|
||||
{
|
||||
var opts = restoreIndex ? "--index" : string.Empty;
|
||||
Args = $"stash apply -q {opts} \"{name}\"";
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Pop(string name)
|
||||
public async Task<bool> PopAsync(string name)
|
||||
{
|
||||
Args = $"stash pop -q --index \"{name}\"";
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Drop(string name)
|
||||
public async Task<bool> DropAsync(string name)
|
||||
{
|
||||
Args = $"stash drop -q \"{name}\"";
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Clear()
|
||||
public async Task<bool> ClearAsync()
|
||||
{
|
||||
Args = "stash clear";
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -11,10 +12,10 @@ namespace SourceGit.Commands
|
||||
Args = $"log --date-order --branches --remotes -{max} --format=%ct$%aN±%aE";
|
||||
}
|
||||
|
||||
public Models.Statistics Result()
|
||||
public async Task<Models.Statistics> ReadAsync()
|
||||
{
|
||||
var statistics = new Models.Statistics();
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return statistics;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -11,25 +12,38 @@ namespace SourceGit.Commands
|
||||
Context = repo;
|
||||
}
|
||||
|
||||
public bool Add(string url, string relativePath, bool recursive)
|
||||
public async Task<bool> AddAsync(string url, string relativePath, bool recursive)
|
||||
{
|
||||
Args = $"-c protocol.file.allow=always submodule add \"{url}\" \"{relativePath}\"";
|
||||
if (!Exec())
|
||||
|
||||
var succ = await ExecAsync().ConfigureAwait(false);
|
||||
if (!succ)
|
||||
return false;
|
||||
|
||||
if (recursive)
|
||||
{
|
||||
Args = $"submodule update --init --recursive -- \"{relativePath}\"";
|
||||
return Exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
Args = $"submodule update --init -- \"{relativePath}\"";
|
||||
return true;
|
||||
}
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Update(List<string> modules, bool init, bool recursive, bool useRemote = false)
|
||||
public async Task<bool> SetURLAsync(string path, string url)
|
||||
{
|
||||
Args = $"submodule set-url -- \"{path}\" \"{url}\"";
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<bool> SetBranchAsync(string path, string branch)
|
||||
{
|
||||
if (string.IsNullOrEmpty(branch))
|
||||
Args = $"submodule set-branch -d -- \"{path}\"";
|
||||
else
|
||||
Args = $"submodule set-branch -b \"{branch}\" -- \"{path}\"";
|
||||
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAsync(List<string> modules, bool init, bool recursive, bool useRemote = false)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("submodule update");
|
||||
@@ -48,19 +62,19 @@ namespace SourceGit.Commands
|
||||
}
|
||||
|
||||
Args = builder.ToString();
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Deinit(string module, bool force)
|
||||
public async Task<bool> DeinitAsync(string module, bool force)
|
||||
{
|
||||
Args = force ? $"submodule deinit -f -- \"{module}\"" : $"submodule deinit -- \"{module}\"";
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Delete(string module)
|
||||
public async Task<bool> DeleteAsync(string module)
|
||||
{
|
||||
Args = $"rm -rf \"{module}\"";
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public static class Tag
|
||||
{
|
||||
public static bool Add(string repo, string name, string basedOn, Models.ICommandLog log)
|
||||
public static async Task<bool> AddAsync(string repo, string name, string basedOn, Models.ICommandLog log)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Args = $"tag --no-sign {name} {basedOn}";
|
||||
cmd.Log = log;
|
||||
return cmd.Exec();
|
||||
return await cmd.ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static bool Add(string repo, string name, string basedOn, string message, bool sign, Models.ICommandLog log)
|
||||
public static async Task<bool> AddAsync(string repo, string name, string basedOn, string message, bool sign, Models.ICommandLog log)
|
||||
{
|
||||
var param = sign ? "--sign -a" : "--no-sign -a";
|
||||
var cmd = new Command();
|
||||
@@ -26,26 +27,26 @@ namespace SourceGit.Commands
|
||||
if (!string.IsNullOrEmpty(message))
|
||||
{
|
||||
string tmp = Path.GetTempFileName();
|
||||
File.WriteAllText(tmp, message);
|
||||
await File.WriteAllTextAsync(tmp, message);
|
||||
cmd.Args += $"-F \"{tmp}\"";
|
||||
|
||||
var succ = cmd.Exec();
|
||||
var succ = await cmd.ExecAsync().ConfigureAwait(false);
|
||||
File.Delete(tmp);
|
||||
return succ;
|
||||
}
|
||||
|
||||
cmd.Args += $"-m {name}";
|
||||
return cmd.Exec();
|
||||
return await cmd.ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static bool Delete(string repo, string name, Models.ICommandLog log)
|
||||
public static async Task<bool> DeleteAsync(string repo, string name, Models.ICommandLog log)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = repo;
|
||||
cmd.Context = repo;
|
||||
cmd.Args = $"tag --delete {name}";
|
||||
cmd.Log = log;
|
||||
return cmd.Exec();
|
||||
return await cmd.ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
using Avalonia.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -49,7 +48,7 @@ namespace SourceGit.Commands
|
||||
}
|
||||
}
|
||||
|
||||
public bool Exec()
|
||||
public async Task<bool> ExecAsync()
|
||||
{
|
||||
var starter = new ProcessStartInfo();
|
||||
starter.WorkingDirectory = _repo;
|
||||
@@ -66,25 +65,22 @@ namespace SourceGit.Commands
|
||||
{
|
||||
var proc = new Process() { StartInfo = starter };
|
||||
proc.Start();
|
||||
proc.StandardInput.Write(_patchBuilder.ToString());
|
||||
await proc.StandardInput.WriteAsync(_patchBuilder.ToString());
|
||||
proc.StandardInput.Close();
|
||||
|
||||
var err = proc.StandardError.ReadToEnd();
|
||||
proc.WaitForExit();
|
||||
var err = await proc.StandardError.ReadToEndAsync().ConfigureAwait(false);
|
||||
await proc.WaitForExitAsync().ConfigureAwait(false);
|
||||
var rs = proc.ExitCode == 0;
|
||||
proc.Close();
|
||||
|
||||
if (!rs)
|
||||
Dispatcher.UIThread.Invoke(() => App.RaiseException(_repo, err));
|
||||
App.RaiseException(_repo, err);
|
||||
|
||||
return rs;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(_repo, "Failed to unstage changes: " + e.Message);
|
||||
});
|
||||
App.RaiseException(_repo, "Failed to unstage changes: " + e.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
@@ -12,13 +13,13 @@ namespace SourceGit.Commands
|
||||
Context = repo;
|
||||
}
|
||||
|
||||
public List<Models.Worktree> List()
|
||||
public async Task<List<Models.Worktree>> ReadAllAsync()
|
||||
{
|
||||
Args = "worktree list --porcelain";
|
||||
|
||||
var rs = ReadToEnd();
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
var worktrees = new List<Models.Worktree>();
|
||||
var last = null as Models.Worktree;
|
||||
Models.Worktree last = null;
|
||||
if (rs.IsSuccess)
|
||||
{
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
@@ -56,7 +57,7 @@ namespace SourceGit.Commands
|
||||
return worktrees;
|
||||
}
|
||||
|
||||
public bool Add(string fullpath, string name, bool createNew, string tracking)
|
||||
public async Task<bool> AddAsync(string fullpath, string name, bool createNew, string tracking)
|
||||
{
|
||||
Args = "worktree add ";
|
||||
|
||||
@@ -78,35 +79,35 @@ namespace SourceGit.Commands
|
||||
else if (!string.IsNullOrEmpty(name) && !createNew)
|
||||
Args += name;
|
||||
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Prune()
|
||||
public async Task<bool> PruneAsync()
|
||||
{
|
||||
Args = "worktree prune -v";
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Lock(string fullpath)
|
||||
public async Task<bool> LockAsync(string fullpath)
|
||||
{
|
||||
Args = $"worktree lock \"{fullpath}\"";
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Unlock(string fullpath)
|
||||
public async Task<bool> UnlockAsync(string fullpath)
|
||||
{
|
||||
Args = $"worktree unlock \"{fullpath}\"";
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public bool Remove(string fullpath, bool force)
|
||||
public async Task<bool> RemoveAsync(string fullpath, bool force)
|
||||
{
|
||||
if (force)
|
||||
Args = $"worktree remove -f \"{fullpath}\"";
|
||||
else
|
||||
Args = $"worktree remove \"{fullpath}\"";
|
||||
|
||||
return Exec();
|
||||
return await ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace SourceGit.Models
|
||||
{
|
||||
public class ApplyWhiteSpaceMode
|
||||
public class ApplyWhiteSpaceMode(string n, string d, string a)
|
||||
{
|
||||
public static readonly ApplyWhiteSpaceMode[] Supported =
|
||||
[
|
||||
@@ -10,15 +10,8 @@
|
||||
new ApplyWhiteSpaceMode("Error All", "Similar to 'error', but shows more", "error-all"),
|
||||
];
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Desc { get; set; }
|
||||
public string Arg { get; set; }
|
||||
|
||||
public ApplyWhiteSpaceMode(string n, string d, string a)
|
||||
{
|
||||
Name = n;
|
||||
Desc = d;
|
||||
Arg = a;
|
||||
}
|
||||
public string Name { get; set; } = n;
|
||||
public string Desc { get; set; } = d;
|
||||
public string Arg { get; set; } = a;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace SourceGit.Models
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var email = null as string;
|
||||
string email = null;
|
||||
|
||||
lock (_synclock)
|
||||
{
|
||||
@@ -79,7 +79,7 @@ namespace SourceGit.Models
|
||||
$"https://www.gravatar.com/avatar/{md5}?d=404";
|
||||
|
||||
var localFile = Path.Combine(_storePath, md5);
|
||||
var img = null as Bitmap;
|
||||
Bitmap img = null;
|
||||
try
|
||||
{
|
||||
var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(2) };
|
||||
@@ -113,7 +113,7 @@ namespace SourceGit.Models
|
||||
_requesting.Remove(email);
|
||||
}
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
_resources[email] = img;
|
||||
NotifyResourceChanged(email, img);
|
||||
@@ -197,7 +197,10 @@ namespace SourceGit.Models
|
||||
|
||||
_resources[email] = image;
|
||||
|
||||
_requesting.Remove(email);
|
||||
lock (_synclock)
|
||||
{
|
||||
_requesting.Remove(email);
|
||||
}
|
||||
|
||||
var store = Path.Combine(_storePath, GetEmailHash(email));
|
||||
File.Copy(file, store, true);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SourceGit.Models
|
||||
{
|
||||
@@ -29,7 +30,7 @@ namespace SourceGit.Models
|
||||
CommitterDate,
|
||||
}
|
||||
|
||||
public class Branch
|
||||
public partial class Branch
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string FullName { get; set; }
|
||||
@@ -44,5 +45,13 @@ namespace SourceGit.Models
|
||||
public bool IsUpstreamGone { get; set; }
|
||||
|
||||
public string FriendlyName => IsLocal ? Name : $"{Remote}/{Name}";
|
||||
|
||||
[GeneratedRegex(@"\s+")]
|
||||
private static partial Regex REG_FIX_NAME();
|
||||
|
||||
public static string FixName(string name)
|
||||
{
|
||||
return REG_FIX_NAME().Replace(name, "-");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,23 +2,16 @@
|
||||
|
||||
namespace SourceGit.Models
|
||||
{
|
||||
public class CRLFMode
|
||||
public class CRLFMode(string name, string value, string desc)
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Value { get; set; }
|
||||
public string Desc { get; set; }
|
||||
public string Name { get; set; } = name;
|
||||
public string Value { get; set; } = value;
|
||||
public string Desc { get; set; } = desc;
|
||||
|
||||
public static readonly List<CRLFMode> Supported = new List<CRLFMode>() {
|
||||
new CRLFMode("TRUE", "true", "Commit as LF, checkout as CRLF"),
|
||||
new CRLFMode("INPUT", "input", "Only convert for commit"),
|
||||
new CRLFMode("FALSE", "false", "Do NOT convert"),
|
||||
};
|
||||
|
||||
public CRLFMode(string name, string value, string desc)
|
||||
{
|
||||
Name = name;
|
||||
Value = value;
|
||||
Desc = desc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,13 @@ using Avalonia.Media;
|
||||
|
||||
namespace SourceGit.Models
|
||||
{
|
||||
public record CommitGraphLayout(double startY, double clipWidth, double rowHeight)
|
||||
{
|
||||
public double StartY { get; set; } = startY;
|
||||
public double ClipWidth { get; set; } = clipWidth;
|
||||
public double RowHeight { get; set; } = rowHeight;
|
||||
}
|
||||
|
||||
public class CommitGraph
|
||||
{
|
||||
public static List<Pen> Pens { get; } = [];
|
||||
@@ -75,7 +82,7 @@ namespace SourceGit.Models
|
||||
|
||||
foreach (var commit in commits)
|
||||
{
|
||||
var major = null as PathHelper;
|
||||
PathHelper major = null;
|
||||
var isMerged = commit.IsMerged;
|
||||
|
||||
// Update current y offset
|
||||
|
||||
@@ -27,19 +27,19 @@ namespace SourceGit.Models
|
||||
trimmedUrl = url.AsSpan(0, url.Length - 4);
|
||||
|
||||
if (url.StartsWith("https://github.com/", StringComparison.Ordinal))
|
||||
outs.Add(new($"Github ({trimmedUrl.Slice(19)})", $"{url}/commit/"));
|
||||
outs.Add(new($"Github ({trimmedUrl[19..]})", $"{url}/commit/"));
|
||||
else if (url.StartsWith("https://gitlab.", StringComparison.Ordinal))
|
||||
outs.Add(new($"GitLab ({trimmedUrl.Slice(trimmedUrl.Slice(15).IndexOf('/') + 16)})", $"{url}/-/commit/"));
|
||||
outs.Add(new($"GitLab ({trimmedUrl[(trimmedUrl[15..].IndexOf('/') + 16)..]})", $"{url}/-/commit/"));
|
||||
else if (url.StartsWith("https://gitee.com/", StringComparison.Ordinal))
|
||||
outs.Add(new($"Gitee ({trimmedUrl.Slice(18)})", $"{url}/commit/"));
|
||||
outs.Add(new($"Gitee ({trimmedUrl[18..]})", $"{url}/commit/"));
|
||||
else if (url.StartsWith("https://bitbucket.org/", StringComparison.Ordinal))
|
||||
outs.Add(new($"BitBucket ({trimmedUrl.Slice(22)})", $"{url}/commits/"));
|
||||
outs.Add(new($"BitBucket ({trimmedUrl[22..]})", $"{url}/commits/"));
|
||||
else if (url.StartsWith("https://codeberg.org/", StringComparison.Ordinal))
|
||||
outs.Add(new($"Codeberg ({trimmedUrl.Slice(21)})", $"{url}/commit/"));
|
||||
outs.Add(new($"Codeberg ({trimmedUrl[21..]})", $"{url}/commit/"));
|
||||
else if (url.StartsWith("https://gitea.org/", StringComparison.Ordinal))
|
||||
outs.Add(new($"Gitea ({trimmedUrl.Slice(18)})", $"{url}/commit/"));
|
||||
outs.Add(new($"Gitea ({trimmedUrl[18..]})", $"{url}/commit/"));
|
||||
else if (url.StartsWith("https://git.sr.ht/", StringComparison.Ordinal))
|
||||
outs.Add(new($"sourcehut ({trimmedUrl.Slice(18)})", $"{url}/commit/"));
|
||||
outs.Add(new($"sourcehut ({trimmedUrl[18..]})", $"{url}/commit/"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace SourceGit.Models
|
||||
TextBox = 0,
|
||||
PathSelector,
|
||||
CheckBox,
|
||||
ComboBox,
|
||||
}
|
||||
|
||||
public class CustomActionControl : ObservableObject
|
||||
|
||||
@@ -2,21 +2,15 @@
|
||||
|
||||
namespace SourceGit.Models
|
||||
{
|
||||
public class DealWithChangesAfterStashing
|
||||
public class DealWithChangesAfterStashing(string label, string desc)
|
||||
{
|
||||
public string Label { get; set; }
|
||||
public string Desc { get; set; }
|
||||
public string Label { get; set; } = label;
|
||||
public string Desc { get; set; } = desc;
|
||||
|
||||
public static readonly List<DealWithChangesAfterStashing> Supported = [
|
||||
new ("Discard", "All (or selected) changes will be discarded"),
|
||||
new ("Keep Index", "Staged changes are left intact"),
|
||||
new ("Keep All", "All (or selected) changes are left intact"),
|
||||
];
|
||||
|
||||
public DealWithChangesAfterStashing(string label, string desc)
|
||||
{
|
||||
Label = label;
|
||||
Desc = desc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace SourceGit.Models
|
||||
{
|
||||
_workingCopyChange = change;
|
||||
_isUnstaged = isUnstaged;
|
||||
_path = change.Path;
|
||||
_orgPath = change.OriginalPath;
|
||||
|
||||
if (isUnstaged)
|
||||
{
|
||||
@@ -37,13 +39,8 @@ namespace SourceGit.Models
|
||||
case ChangeState.Added:
|
||||
case ChangeState.Untracked:
|
||||
_extra = "--no-index";
|
||||
_path = change.Path;
|
||||
_orgPath = "/dev/null";
|
||||
break;
|
||||
default:
|
||||
_path = change.Path;
|
||||
_orgPath = change.OriginalPath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -52,9 +49,6 @@ namespace SourceGit.Models
|
||||
_extra = $"--cached {change.DataForAmend.ParentSHA}";
|
||||
else
|
||||
_extra = "--cached";
|
||||
|
||||
_path = change.Path;
|
||||
_orgPath = change.OriginalPath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using Avalonia;
|
||||
@@ -148,13 +148,13 @@ namespace SourceGit.Models
|
||||
var isTracked = !string.IsNullOrEmpty(fileBlobGuid);
|
||||
var fileGuid = isTracked ? fileBlobGuid : "00000000";
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("diff --git a/").Append(change.Path).Append(" b/").Append(change.Path).Append('\n');
|
||||
using var writer = new StreamWriter(output);
|
||||
writer.WriteLine($"diff --git a/{change.Path} b/{change.Path}");
|
||||
if (!revert && !isTracked)
|
||||
builder.Append("new file mode 100644\n");
|
||||
builder.Append("index 00000000...").Append(fileGuid).Append('\n');
|
||||
builder.Append("--- ").Append((revert || isTracked) ? $"a/{change.Path}\n" : "/dev/null\n");
|
||||
builder.Append("+++ b/").Append(change.Path).Append('\n');
|
||||
writer.WriteLine("new file mode 100644");
|
||||
writer.WriteLine($"index 00000000...{fileGuid}");
|
||||
writer.WriteLine($"--- {(revert || isTracked ? $"a/{change.Path}" : "/dev/null")}");
|
||||
writer.WriteLine($"+++ b/{change.Path}");
|
||||
|
||||
var additions = selection.EndLine - selection.StartLine;
|
||||
if (selection.StartLine != 1)
|
||||
@@ -163,43 +163,43 @@ namespace SourceGit.Models
|
||||
if (revert)
|
||||
{
|
||||
var totalLines = Lines.Count - 1;
|
||||
builder.Append("@@ -0,").Append(totalLines - additions).Append(" +0,").Append(totalLines).Append(" @@");
|
||||
writer.WriteLine($"@@ -0,{totalLines - additions} +0,{totalLines} @@");
|
||||
for (int i = 1; i <= totalLines; i++)
|
||||
{
|
||||
var line = Lines[i];
|
||||
if (line.Type != TextDiffLineType.Added)
|
||||
continue;
|
||||
builder.Append(selection.IsInRange(i) ? "\n+" : "\n ").Append(line.Content);
|
||||
writer.WriteLine($"{(selection.IsInRange(i) ? "+" : " ")}{line.Content}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append("@@ -0,0 +0,").Append(additions).Append(" @@");
|
||||
writer.WriteLine($"@@ -0,0 +0,{additions} @@");
|
||||
for (int i = selection.StartLine - 1; i < selection.EndLine; i++)
|
||||
{
|
||||
var line = Lines[i];
|
||||
if (line.Type != TextDiffLineType.Added)
|
||||
continue;
|
||||
builder.Append("\n+").Append(line.Content);
|
||||
writer.WriteLine($"+{line.Content}");
|
||||
}
|
||||
}
|
||||
|
||||
builder.Append("\n\\ No newline at end of file\n");
|
||||
System.IO.File.WriteAllText(output, builder.ToString());
|
||||
writer.WriteLine("\\ No newline at end of file");
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
public void GeneratePatchFromSelection(Change change, string fileTreeGuid, TextDiffSelection selection, bool revert, string output)
|
||||
{
|
||||
var orgFile = !string.IsNullOrEmpty(change.OriginalPath) ? change.OriginalPath : change.Path;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("diff --git a/").Append(change.Path).Append(" b/").Append(change.Path).Append('\n');
|
||||
builder.Append("index 00000000...").Append(fileTreeGuid).Append(" 100644\n");
|
||||
builder.Append("--- a/").Append(orgFile).Append('\n');
|
||||
builder.Append("+++ b/").Append(change.Path);
|
||||
using var writer = new StreamWriter(output);
|
||||
writer.WriteLine($"diff --git a/{change.Path} b/{change.Path}");
|
||||
writer.WriteLine($"index 00000000...{fileTreeGuid} 100644");
|
||||
writer.WriteLine($"--- a/{orgFile}");
|
||||
writer.WriteLine($"+++ b/{change.Path}");
|
||||
|
||||
// If last line of selection is a change. Find one more line.
|
||||
var tail = null as string;
|
||||
string tail = null;
|
||||
if (selection.EndLine < Lines.Count)
|
||||
{
|
||||
var lastLine = Lines[selection.EndLine - 1];
|
||||
@@ -210,21 +210,12 @@ namespace SourceGit.Models
|
||||
var line = Lines[i];
|
||||
if (line.Type == TextDiffLineType.Indicator)
|
||||
break;
|
||||
if (revert)
|
||||
if (line.Type == TextDiffLineType.Normal ||
|
||||
(revert && line.Type == TextDiffLineType.Added) ||
|
||||
(!revert && line.Type == TextDiffLineType.Deleted))
|
||||
{
|
||||
if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Added)
|
||||
{
|
||||
tail = line.Content;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Deleted)
|
||||
{
|
||||
tail = line.Content;
|
||||
break;
|
||||
}
|
||||
tail = line.Content;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,21 +255,21 @@ namespace SourceGit.Models
|
||||
var line = Lines[i];
|
||||
if (line.Type == TextDiffLineType.Indicator)
|
||||
{
|
||||
ProcessIndicatorForPatch(builder, line, i, selection.StartLine, selection.EndLine, ignoreRemoves, ignoreAdds, revert, tail != null);
|
||||
ProcessIndicatorForPatch(writer, line, i, selection.StartLine, selection.EndLine, ignoreRemoves, ignoreAdds, revert, tail != null);
|
||||
}
|
||||
else if (line.Type == TextDiffLineType.Added)
|
||||
{
|
||||
if (revert)
|
||||
builder.Append("\n ").Append(line.Content);
|
||||
writer.WriteLine($" {line.Content}");
|
||||
}
|
||||
else if (line.Type == TextDiffLineType.Deleted)
|
||||
{
|
||||
if (!revert)
|
||||
builder.Append("\n ").Append(line.Content);
|
||||
writer.WriteLine($" {line.Content}");
|
||||
}
|
||||
else if (line.Type == TextDiffLineType.Normal)
|
||||
{
|
||||
builder.Append("\n ").Append(line.Content);
|
||||
writer.WriteLine($" {line.Content}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -289,42 +280,39 @@ namespace SourceGit.Models
|
||||
var line = Lines[i];
|
||||
if (line.Type == TextDiffLineType.Indicator)
|
||||
{
|
||||
if (!ProcessIndicatorForPatch(builder, line, i, selection.StartLine, selection.EndLine, selection.IgnoredDeletes, selection.IgnoredAdds, revert, tail != null))
|
||||
{
|
||||
if (!ProcessIndicatorForPatch(writer, line, i, selection.StartLine, selection.EndLine, selection.IgnoredDeletes, selection.IgnoredAdds, revert, tail != null))
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (line.Type == TextDiffLineType.Normal)
|
||||
{
|
||||
builder.Append("\n ").Append(line.Content);
|
||||
writer.WriteLine($" {line.Content}");
|
||||
}
|
||||
else if (line.Type == TextDiffLineType.Added)
|
||||
{
|
||||
builder.Append("\n+").Append(line.Content);
|
||||
writer.WriteLine($"+{line.Content}");
|
||||
}
|
||||
else if (line.Type == TextDiffLineType.Deleted)
|
||||
{
|
||||
builder.Append("\n-").Append(line.Content);
|
||||
writer.WriteLine($"-{line.Content}");
|
||||
}
|
||||
}
|
||||
|
||||
builder.Append("\n ").Append(tail);
|
||||
builder.Append("\n");
|
||||
System.IO.File.WriteAllText(output, builder.ToString());
|
||||
writer.WriteLine($" {tail}");
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
public void GeneratePatchFromSelectionSingleSide(Change change, string fileTreeGuid, TextDiffSelection selection, bool revert, bool isOldSide, string output)
|
||||
{
|
||||
var orgFile = !string.IsNullOrEmpty(change.OriginalPath) ? change.OriginalPath : change.Path;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("diff --git a/").Append(change.Path).Append(" b/").Append(change.Path).Append('\n');
|
||||
builder.Append("index 00000000...").Append(fileTreeGuid).Append(" 100644\n");
|
||||
builder.Append("--- a/").Append(orgFile).Append('\n');
|
||||
builder.Append("+++ b/").Append(change.Path);
|
||||
using var writer = new StreamWriter(output);
|
||||
writer.WriteLine($"diff --git a/{change.Path} b/{change.Path}");
|
||||
writer.WriteLine($"index 00000000...{fileTreeGuid} 100644");
|
||||
writer.WriteLine($"--- a/{orgFile}");
|
||||
writer.WriteLine($"+++ b/{change.Path}");
|
||||
|
||||
// If last line of selection is a change. Find one more line.
|
||||
var tail = null as string;
|
||||
string tail = null;
|
||||
if (selection.EndLine < Lines.Count)
|
||||
{
|
||||
var lastLine = Lines[selection.EndLine - 1];
|
||||
@@ -389,21 +377,21 @@ namespace SourceGit.Models
|
||||
var line = Lines[i];
|
||||
if (line.Type == TextDiffLineType.Indicator)
|
||||
{
|
||||
ProcessIndicatorForPatchSingleSide(builder, line, i, selection.StartLine, selection.EndLine, ignoreRemoves, ignoreAdds, revert, isOldSide, tail != null);
|
||||
ProcessIndicatorForPatchSingleSide(writer, line, i, selection.StartLine, selection.EndLine, ignoreRemoves, ignoreAdds, revert, isOldSide, tail != null);
|
||||
}
|
||||
else if (line.Type == TextDiffLineType.Added)
|
||||
{
|
||||
if (revert)
|
||||
builder.Append("\n ").Append(line.Content);
|
||||
writer.WriteLine($" {line.Content}");
|
||||
}
|
||||
else if (line.Type == TextDiffLineType.Deleted)
|
||||
{
|
||||
if (!revert)
|
||||
builder.Append("\n ").Append(line.Content);
|
||||
writer.WriteLine($" {line.Content}");
|
||||
}
|
||||
else if (line.Type == TextDiffLineType.Normal)
|
||||
{
|
||||
builder.Append("\n ").Append(line.Content);
|
||||
writer.WriteLine($" {line.Content}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -414,14 +402,12 @@ namespace SourceGit.Models
|
||||
var line = Lines[i];
|
||||
if (line.Type == TextDiffLineType.Indicator)
|
||||
{
|
||||
if (!ProcessIndicatorForPatchSingleSide(builder, line, i, selection.StartLine, selection.EndLine, selection.IgnoredDeletes, selection.IgnoredAdds, revert, isOldSide, tail != null))
|
||||
{
|
||||
if (!ProcessIndicatorForPatchSingleSide(writer, line, i, selection.StartLine, selection.EndLine, selection.IgnoredDeletes, selection.IgnoredAdds, revert, isOldSide, tail != null))
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (line.Type == TextDiffLineType.Normal)
|
||||
{
|
||||
builder.Append("\n ").Append(line.Content);
|
||||
writer.WriteLine($" {line.Content}");
|
||||
}
|
||||
else if (line.Type == TextDiffLineType.Added)
|
||||
{
|
||||
@@ -429,7 +415,7 @@ namespace SourceGit.Models
|
||||
{
|
||||
if (revert)
|
||||
{
|
||||
builder.Append("\n ").Append(line.Content);
|
||||
writer.WriteLine($" {line.Content}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -438,20 +424,20 @@ namespace SourceGit.Models
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append("\n+").Append(line.Content);
|
||||
writer.WriteLine($"+{line.Content}");
|
||||
}
|
||||
}
|
||||
else if (line.Type == TextDiffLineType.Deleted)
|
||||
{
|
||||
if (isOldSide)
|
||||
{
|
||||
builder.Append("\n-").Append(line.Content);
|
||||
writer.WriteLine($"-{line.Content}");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!revert)
|
||||
{
|
||||
builder.Append("\n ").Append(line.Content);
|
||||
writer.WriteLine($" {line.Content}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -461,12 +447,11 @@ namespace SourceGit.Models
|
||||
}
|
||||
}
|
||||
|
||||
builder.Append("\n ").Append(tail);
|
||||
builder.Append("\n");
|
||||
System.IO.File.WriteAllText(output, builder.ToString());
|
||||
writer.WriteLine($" {tail}");
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
private bool ProcessIndicatorForPatch(StringBuilder builder, TextDiffLine indicator, int idx, int start, int end, int ignoreRemoves, int ignoreAdds, bool revert, bool tailed)
|
||||
private bool ProcessIndicatorForPatch(StreamWriter writer, TextDiffLine indicator, int idx, int start, int end, int ignoreRemoves, int ignoreAdds, bool revert, bool tailed)
|
||||
{
|
||||
var match = REG_INDICATOR().Match(indicator.Content);
|
||||
var oldStart = int.Parse(match.Groups[1].Value);
|
||||
@@ -531,11 +516,11 @@ namespace SourceGit.Models
|
||||
if (oldCount == 0 && newCount == 0)
|
||||
return false;
|
||||
|
||||
builder.Append($"\n@@ -{oldStart},{oldCount} +{newStart},{newCount} @@");
|
||||
writer.WriteLine($"@@ -{oldStart},{oldCount} +{newStart},{newCount} @@");
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ProcessIndicatorForPatchSingleSide(StringBuilder builder, TextDiffLine indicator, int idx, int start, int end, int ignoreRemoves, int ignoreAdds, bool revert, bool isOldSide, bool tailed)
|
||||
private bool ProcessIndicatorForPatchSingleSide(StreamWriter writer, TextDiffLine indicator, int idx, int start, int end, int ignoreRemoves, int ignoreAdds, bool revert, bool isOldSide, bool tailed)
|
||||
{
|
||||
var match = REG_INDICATOR().Match(indicator.Content);
|
||||
var oldStart = int.Parse(match.Groups[1].Value);
|
||||
@@ -611,7 +596,7 @@ namespace SourceGit.Models
|
||||
if (oldCount == 0 && newCount == 0)
|
||||
return false;
|
||||
|
||||
builder.Append($"\n@@ -{oldStart},{oldCount} +{newStart},{newCount} @@");
|
||||
writer.WriteLine($"@@ -{oldStart},{oldCount} +{newStart},{newCount} @@");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace SourceGit.Models
|
||||
new ExternalMerger(9, "p4merge", "P4Merge", "p4merge.exe", "-tw 4 \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", "-tw 4 \"$LOCAL\" \"$REMOTE\""),
|
||||
new ExternalMerger(10, "plastic_merge", "Plastic SCM", "mergetool.exe", "-s=\"$REMOTE\" -b=\"$BASE\" -d=\"$LOCAL\" -r=\"$MERGED\" --automatic", "-s=\"$LOCAL\" -d=\"$REMOTE\""),
|
||||
new ExternalMerger(11, "meld", "Meld", "Meld.exe", "\"$LOCAL\" \"$BASE\" \"$REMOTE\" --output \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
|
||||
new ExternalMerger(12, "cursor", "Cursor", "Cursor.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
|
||||
};
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
@@ -57,6 +58,7 @@ namespace SourceGit.Models
|
||||
new ExternalMerger(5, "beyond_compare", "Beyond Compare", "/Applications/Beyond Compare.app/Contents/MacOS/bcomp", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
|
||||
new ExternalMerger(6, "codium", "VSCodium", "/Applications/VSCodium.app/Contents/Resources/app/bin/codium", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
|
||||
new ExternalMerger(7, "p4merge", "P4Merge", "/Applications/p4merge.app/Contents/Resources/launchp4merge", "-tw 4 \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", "-tw 4 \"$LOCAL\" \"$REMOTE\""),
|
||||
new ExternalMerger(8, "cursor", "Cursor", "/Applications/Cursor.app/Contents/Resources/app/bin/cursor", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
|
||||
};
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
@@ -70,6 +72,7 @@ namespace SourceGit.Models
|
||||
new ExternalMerger(5, "meld", "Meld", "/usr/bin/meld", "\"$LOCAL\" \"$BASE\" \"$REMOTE\" --output \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
|
||||
new ExternalMerger(6, "codium", "VSCodium", "/usr/share/codium/bin/codium", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
|
||||
new ExternalMerger(7, "p4merge", "P4Merge", "/usr/local/bin/p4merge", "-tw 4 \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", "-tw 4 \"$LOCAL\" \"$REMOTE\""),
|
||||
new ExternalMerger(8, "cursor", "Cursor", "cursor", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
|
||||
};
|
||||
}
|
||||
else
|
||||
@@ -93,19 +96,10 @@ namespace SourceGit.Models
|
||||
public string[] GetPatterns()
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
return Exec.Split(';');
|
||||
}
|
||||
else
|
||||
{
|
||||
var patterns = new List<string>();
|
||||
var choices = Exec.Split(';', StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var c in choices)
|
||||
{
|
||||
patterns.Add(Path.GetFileName(c));
|
||||
}
|
||||
return patterns.ToArray();
|
||||
}
|
||||
|
||||
var choices = Exec.Split(';', StringSplitOptions.RemoveEmptyEntries);
|
||||
return Array.ConvertAll(choices, Path.GetFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +154,11 @@ namespace SourceGit.Models
|
||||
TryAdd("Zed", "zed", platformFinder);
|
||||
}
|
||||
|
||||
public void Cursor(Func<string> platformFinder)
|
||||
{
|
||||
TryAdd("Cursor", "cursor", platformFinder);
|
||||
}
|
||||
|
||||
public void FindJetBrainsFromToolbox(Func<string> platformFinder)
|
||||
{
|
||||
var exclude = new List<string> { "fleet", "dotmemory", "dottrace", "resharper-u", "androidstudio" };
|
||||
|
||||
@@ -1,25 +1,33 @@
|
||||
namespace SourceGit.Models
|
||||
{
|
||||
public class MergeMode
|
||||
public class MergeMode(string n, string d, string a)
|
||||
{
|
||||
public static readonly MergeMode Default =
|
||||
new MergeMode("Default", "Fast-forward if possible", "");
|
||||
|
||||
public static readonly MergeMode FastForward =
|
||||
new MergeMode("Fast-forward", "Refuse to merge when fast-forward is not possible", "--ff-only");
|
||||
|
||||
public static readonly MergeMode NoFastForward =
|
||||
new MergeMode("No Fast-forward", "Always create a merge commit", "--no-ff");
|
||||
|
||||
public static readonly MergeMode Squash =
|
||||
new MergeMode("Squash", "Squash merge", "--squash");
|
||||
|
||||
public static readonly MergeMode DontCommit
|
||||
= new MergeMode("Don't commit", "Merge without commit", "--no-ff --no-commit");
|
||||
|
||||
public static readonly MergeMode[] Supported =
|
||||
[
|
||||
new MergeMode("Default", "Fast-forward if possible", ""),
|
||||
new MergeMode("Fast-forward", "Refuse to merge when fast-forward is not possible", "--ff-only"),
|
||||
new MergeMode("No Fast-forward", "Always create a merge commit", "--no-ff"),
|
||||
new MergeMode("Squash", "Squash merge", "--squash"),
|
||||
new MergeMode("Don't commit", "Merge without commit", "--no-ff --no-commit"),
|
||||
Default,
|
||||
FastForward,
|
||||
NoFastForward,
|
||||
Squash,
|
||||
DontCommit,
|
||||
];
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Desc { get; set; }
|
||||
public string Arg { get; set; }
|
||||
|
||||
public MergeMode(string n, string d, string a)
|
||||
{
|
||||
Name = n;
|
||||
Desc = d;
|
||||
Arg = a;
|
||||
}
|
||||
public string Name { get; set; } = n;
|
||||
public string Desc { get; set; } = d;
|
||||
public string Arg { get; set; } = a;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.AI.OpenAI;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using OpenAI;
|
||||
@@ -173,7 +174,7 @@ namespace SourceGit.Models
|
||||
""";
|
||||
}
|
||||
|
||||
public void Chat(string prompt, string question, CancellationToken cancellation, Action<string> onUpdate)
|
||||
public async Task ChatAsync(string prompt, string question, CancellationToken cancellation, Action<string> onUpdate)
|
||||
{
|
||||
var server = new Uri(_server);
|
||||
var key = new ApiKeyCredential(_apiKey);
|
||||
@@ -191,9 +192,9 @@ namespace SourceGit.Models
|
||||
|
||||
if (_streaming)
|
||||
{
|
||||
var updates = client.CompleteChatStreaming(messages, null, cancellation);
|
||||
var updates = client.CompleteChatStreamingAsync(messages, null, cancellation);
|
||||
|
||||
foreach (var update in updates)
|
||||
await foreach (var update in updates)
|
||||
{
|
||||
if (update.ContentUpdate.Count > 0)
|
||||
rsp.Append(update.ContentUpdate[0].Text);
|
||||
@@ -201,7 +202,7 @@ namespace SourceGit.Models
|
||||
}
|
||||
else
|
||||
{
|
||||
var completion = client.CompleteChat(messages, null, cancellation);
|
||||
var completion = await client.CompleteChatAsync(messages, null, cancellation);
|
||||
|
||||
if (completion.Value.Content.Count > 0)
|
||||
rsp.Append(completion.Value.Content[0].Text);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace SourceGit.Models
|
||||
{
|
||||
public class ResetMode
|
||||
public class ResetMode(string n, string d, string a, string k, IBrush b)
|
||||
{
|
||||
public static readonly ResetMode[] Supported =
|
||||
[
|
||||
@@ -13,19 +13,10 @@ namespace SourceGit.Models
|
||||
new ResetMode("Hard", "Discard all changes", "--hard", "H", Brushes.Red),
|
||||
];
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Desc { get; set; }
|
||||
public string Arg { get; set; }
|
||||
public string Key { get; set; }
|
||||
public IBrush Color { get; set; }
|
||||
|
||||
public ResetMode(string n, string d, string a, string k, IBrush b)
|
||||
{
|
||||
Name = n;
|
||||
Desc = d;
|
||||
Arg = a;
|
||||
Key = k;
|
||||
Color = b;
|
||||
}
|
||||
public string Name { get; set; } = n;
|
||||
public string Desc { get; set; } = d;
|
||||
public string Arg { get; set; } = a;
|
||||
public string Key { get; set; } = k;
|
||||
public IBrush Color { get; set; } = b;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
public string Path { get; set; } = string.Empty;
|
||||
public string SHA { get; set; } = string.Empty;
|
||||
public string URL { get; set; } = string.Empty;
|
||||
public string Branch { get; set; } = string.Empty;
|
||||
public SubmoduleStatus Status { get; set; } = SubmoduleStatus.Normal;
|
||||
public bool IsDirty => Status > SubmoduleStatus.NotInited;
|
||||
}
|
||||
|
||||
@@ -88,9 +88,7 @@ namespace SourceGit.Models
|
||||
{
|
||||
var c = Peek();
|
||||
if (c is not null)
|
||||
{
|
||||
_pos++;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -129,7 +127,7 @@ namespace SourceGit.Models
|
||||
{
|
||||
case ESCAPE:
|
||||
// allow to escape only \ and $
|
||||
if (Peek() is { } nc && (nc == ESCAPE || nc == VARIABLE_ANCHOR))
|
||||
if (Peek() is ESCAPE or VARIABLE_ANCHOR)
|
||||
{
|
||||
esc = true;
|
||||
FlushText(tok, _pos - 1);
|
||||
@@ -320,9 +318,7 @@ namespace SourceGit.Models
|
||||
private static string EvalVariable(Context context, string name)
|
||||
{
|
||||
if (!s_variables.TryGetValue(name, out var getter))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
return getter(context);
|
||||
}
|
||||
|
||||
@@ -334,9 +330,7 @@ namespace SourceGit.Models
|
||||
private static string EvalVariable(Context context, SlicedVariable variable)
|
||||
{
|
||||
if (!s_slicedVariables.TryGetValue(variable.name, out var getter))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
return getter(context, variable.count);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace SourceGit.Models
|
||||
var ret = new List<TextInlineChange>();
|
||||
var posOld = 0;
|
||||
var posNew = 0;
|
||||
var last = null as TextInlineChange;
|
||||
TextInlineChange last = null;
|
||||
do
|
||||
{
|
||||
while (posOld < sizeOld && posNew < sizeNew && !chunksOld[posOld].Modified && !chunksNew[posNew].Modified)
|
||||
@@ -295,16 +295,12 @@ namespace SourceGit.Models
|
||||
|
||||
private static void AddChunk(List<Chunk> chunks, Dictionary<string, int> hashes, string data, int start)
|
||||
{
|
||||
if (hashes.TryGetValue(data, out var hash))
|
||||
{
|
||||
chunks.Add(new Chunk(hash, start, data.Length));
|
||||
}
|
||||
else
|
||||
if (!hashes.TryGetValue(data, out var hash))
|
||||
{
|
||||
hash = hashes.Count;
|
||||
hashes.Add(data, hash);
|
||||
chunks.Add(new Chunk(hash, start, data.Length));
|
||||
}
|
||||
chunks.Add(new Chunk(hash, start, data.Length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace SourceGit.Models
|
||||
var extension = Path.GetExtension(file);
|
||||
if (extension == ".h")
|
||||
extension = ".cpp";
|
||||
else if (extension == ".resx" || extension == ".plist" || extension == ".manifest")
|
||||
else if (extension is ".resx" or ".plist" or ".manifest")
|
||||
extension = ".xml";
|
||||
else if (extension == ".command")
|
||||
extension = ".sh";
|
||||
|
||||
@@ -256,6 +256,7 @@ namespace SourceGit.Models
|
||||
if (name.Equals(".gitmodules", StringComparison.Ordinal))
|
||||
{
|
||||
_updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
|
||||
_updateWC = DateTime.Now.AddSeconds(1).ToFileTime();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ namespace SourceGit.Native
|
||||
finder.VSCode(() => FindExecutable("code"));
|
||||
finder.VSCodeInsiders(() => FindExecutable("code-insiders"));
|
||||
finder.VSCodium(() => FindExecutable("codium"));
|
||||
finder.Cursor(() => FindExecutable("cursor"));
|
||||
finder.Fleet(FindJetBrainsFleet);
|
||||
finder.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}/JetBrains/Toolbox");
|
||||
finder.SublimeText(() => FindExecutable("subl"));
|
||||
|
||||
@@ -74,6 +74,7 @@ namespace SourceGit.Native
|
||||
finder.VSCode(() => "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code");
|
||||
finder.VSCodeInsiders(() => "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code");
|
||||
finder.VSCodium(() => "/Applications/VSCodium.app/Contents/Resources/app/bin/codium");
|
||||
finder.Cursor(() => "/Applications/Cursor.app/Contents/Resources/app/bin/cursor");
|
||||
finder.Fleet(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}/Applications/Fleet.app/Contents/MacOS/Fleet");
|
||||
finder.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}/Library/Application Support/JetBrains/Toolbox");
|
||||
finder.SublimeText(() => "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl");
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace SourceGit.Native
|
||||
window.ExtendClientAreaToDecorationsHint = true;
|
||||
window.Classes.Add("fix_maximized_padding");
|
||||
|
||||
Win32Properties.AddWndProcHookCallback(window, (IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, ref bool handled) =>
|
||||
Win32Properties.AddWndProcHookCallback(window, (IntPtr hWnd, uint msg, IntPtr _, IntPtr lParam, ref bool handled) =>
|
||||
{
|
||||
// Custom WM_NCHITTEST
|
||||
if (msg == 0x0084)
|
||||
@@ -184,6 +184,7 @@ namespace SourceGit.Native
|
||||
finder.VSCode(FindVSCode);
|
||||
finder.VSCodeInsiders(FindVSCodeInsiders);
|
||||
finder.VSCodium(FindVSCodium);
|
||||
finder.Cursor(FindCursor);
|
||||
finder.Fleet(() => $@"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\Programs\Fleet\Fleet.exe");
|
||||
finder.FindJetBrainsFromToolbox(() => $@"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\JetBrains\Toolbox");
|
||||
finder.SublimeText(FindSublimeText);
|
||||
@@ -257,7 +258,7 @@ namespace SourceGit.Native
|
||||
{
|
||||
// Schedule the DWM frame extension to run in the next render frame
|
||||
// to ensure proper timing with the window initialization sequence
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
var platformHandle = w.TryGetPlatformHandle();
|
||||
if (platformHandle == null)
|
||||
@@ -387,6 +388,20 @@ namespace SourceGit.Native
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private string FindCursor()
|
||||
{
|
||||
var cursorPath = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
"Programs",
|
||||
"Cursor",
|
||||
"Cursor.exe");
|
||||
|
||||
if (File.Exists(cursorPath))
|
||||
return cursorPath;
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void OpenFolderAndSelectFile(string folderPath)
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
<StreamGeometry x:Key="Icons.Modified">M896 64H128C96 64 64 96 64 128v768c0 32 32 64 64 64h768c32 0 64-32 64-64V128c0-32-32-64-64-64z m-64 736c0 16-17 32-32 32H224c-18 0-32-12-32-32V224c0-16 16-32 32-32h576c15 0 32 16 32 32v576zM512 384c-71 0-128 57-128 128s57 128 128 128 128-57 128-128-57-128-128-128z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.More">M0 512M1024 512M512 0M512 1024M813 448c-46 0-83 37-83 83 0 46 37 83 83 83 46 0 83-37 83-83 0-46-37-83-83-83zM211 448C165 448 128 485 128 531c0 46 37 83 83 83 46 0 83-37 83-83 0-46-37-83-83-83zM512 448c-46 0-83 37-83 83 0 46 37 83 83 83 46 0 83-37 83-83C595 485 558 448 512 448z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.Move">M299 811 299 725 384 725 384 811 299 811M469 811 469 725 555 725 555 811 469 811M640 811 640 725 725 725 725 811 640 811M299 640 299 555 384 555 384 640 299 640M469 640 469 555 555 555 555 640 469 640M640 640 640 555 725 555 725 640 640 640M299 469 299 384 384 384 384 469 299 469M469 469 469 384 555 384 555 469 469 469M640 469 640 384 725 384 725 469 640 469M299 299 299 213 384 213 384 299 299 299M469 299 469 213 555 213 555 299 469 299M640 299 640 213 725 213 725 299 640 299Z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.MoveToAnotherGroup">M64 363l0 204 265 0L329 460c0-11 6-18 14-20C349 437 355 437 362 441c93 60 226 149 226 149 33 22 34 60 0 82 0 0-133 89-226 149-14 9-32-3-32-18l-1-110L64 693l0 117c0 41 34 75 75 75l746 0c41 0 75-34 75-74L960 364c0-0 0-1 0-1L64 363zM64 214l0 75 650 0-33-80c-16-38-62-69-103-69l-440 0C97 139 64 173 64 214z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.MoveTo">M64 363l0 204 265 0L329 460c0-11 6-18 14-20C349 437 355 437 362 441c93 60 226 149 226 149 33 22 34 60 0 82 0 0-133 89-226 149-14 9-32-3-32-18l-1-110L64 693l0 117c0 41 34 75 75 75l746 0c41 0 75-34 75-74L960 364c0-0 0-1 0-1L64 363zM64 214l0 75 650 0-33-80c-16-38-62-69-103-69l-440 0C97 139 64 173 64 214z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.OpenWith">M683 409v204L1024 308 683 0v191c-413 0-427 526-427 526c117-229 203-307 427-307zm85 492H102V327h153s38-63 114-122H51c-28 0-51 27-51 61v697c0 34 23 61 51 61h768c28 0 51-27 51-61V614l-102 100v187z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.OrderByName">M841 627A43 43 0 00811 555h-299v85h196l-183 183A43 43 0 00555 896h299v-85h-196l183-183zM299 170H213v512H85l171 171 171-171H299zM725 128h-85c-18 0-34 11-40 28l-117 313h91L606 384h154l32 85h91l-117-313A43 43 0 00725 128zm-88 171 32-85h26l32 85h-90z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.OrderByTime">M512 0a512 512 0 01512 512 57 57 0 01-114 0 398 398 0 10-398 398 57 57 0 010 114A512 512 0 01512 0zm367 600 121 120a57 57 0 01-80 81l-40-40V967a57 57 0 01-50 57l-7 0a57 57 0 01-57-57v-205l-40 40a57 57 0 01-75 5l-5-5a57 57 0 01-0-80l120-121a80 80 0 01113-0zM512 272a57 57 0 0157 57V499h114a57 57 0 0156 50L740 556a57 57 0 01-57 57H512a57 57 0 01-57-57v-228a57 57 0 0150-57L512 272z</StreamGeometry>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.9 KiB |