mirror of
https://fastgit.cc/github.com/sourcegit-scm/sourcegit
synced 2026-04-20 21:01:06 +08:00
Merge branch 'release/v2026.09'
This commit is contained in:
169
TRANSLATION.md
169
TRANSLATION.md
@@ -6,32 +6,46 @@ This document shows the translation status of each locale file in the repository
|
||||
|
||||
### 
|
||||
|
||||
### 
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in de_DE.axaml</summary>
|
||||
|
||||
- Text.AIAssistant.Use
|
||||
- Text.App.HideOthers
|
||||
- Text.Apply.3Way
|
||||
- Text.CheckoutBranchFromStash
|
||||
- Text.CheckoutBranchFromStash.Branch
|
||||
- Text.CheckoutBranchFromStash.Stash
|
||||
- Text.Clone.Bookmark
|
||||
- Text.Clone.Group
|
||||
- Text.CommandPalette.Branches
|
||||
- Text.CommandPalette.BranchesAndTags
|
||||
- Text.CommandPalette.RepositoryActions
|
||||
- Text.CommandPalette.RevisionFiles
|
||||
- Text.CommitMessageTextBox.Column
|
||||
- Text.ConfigureCustomActionControls.StringFormatter
|
||||
- Text.ConfigureCustomActionControls.StringFormatter.Tip
|
||||
- Text.ConfigureCustomActionControls.UseFriendlyName
|
||||
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
|
||||
- Text.Diff.Submodule.UncommittedChanges
|
||||
- Text.Discard.IncludeModified
|
||||
- Text.GotoRevisionSelector
|
||||
- Text.Hotkeys.Global.OpenLocalRepository
|
||||
- Text.Hotkeys.Repo.CreateBranch
|
||||
- Text.Hotkeys.Repo.GoToChild
|
||||
- Text.Init.CommandTip
|
||||
- Text.Init.ErrorMessageTip
|
||||
- Text.OpenLocalRepository
|
||||
- Text.OpenLocalRepository.Bookmark
|
||||
- Text.OpenLocalRepository.Group
|
||||
- Text.OpenLocalRepository.Path
|
||||
- Text.Preferences.AI.AdditionalPrompt
|
||||
- Text.Preferences.General.Use24Hours
|
||||
- Text.StashCM.ApplyFileChanges
|
||||
- Text.StashCM.Branch
|
||||
- Text.SubmoduleRevisionCompare
|
||||
- Text.SubmoduleRevisionCompare.OpenDetails
|
||||
- Text.Worktree.Branch
|
||||
- Text.Worktree.Head
|
||||
- Text.Worktree.Path
|
||||
@@ -40,13 +54,14 @@ This document shows the translation status of each locale file in the repository
|
||||
|
||||
### 
|
||||
|
||||
### 
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in fr_FR.axaml</summary>
|
||||
|
||||
- Text.About.ReleaseDate
|
||||
- Text.AIAssistant.Use
|
||||
- Text.App.HideOthers
|
||||
- Text.Apply.3Way
|
||||
- Text.Blame.IgnoreWhitespace
|
||||
- Text.BranchCM.CompareTwo
|
||||
@@ -60,6 +75,8 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.CheckoutBranchFromStash
|
||||
- Text.CheckoutBranchFromStash.Branch
|
||||
- Text.CheckoutBranchFromStash.Stash
|
||||
- Text.Clone.Bookmark
|
||||
- Text.Clone.Group
|
||||
- Text.CommandPalette.Branches
|
||||
- Text.CommandPalette.BranchesAndTags
|
||||
- Text.CommandPalette.RepositoryActions
|
||||
@@ -68,7 +85,11 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.CommitMessageTextBox.Placeholder
|
||||
- Text.Compare.WithHead
|
||||
- Text.Configure.Git.AskBeforeAutoUpdatingSubmodules
|
||||
- Text.ConfigureCustomActionControls.StringFormatter
|
||||
- Text.ConfigureCustomActionControls.StringFormatter.Tip
|
||||
- Text.ConfigureCustomActionControls.UseFriendlyName
|
||||
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
|
||||
- Text.Diff.Submodule.UncommittedChanges
|
||||
- Text.Discard.IncludeModified
|
||||
- Text.EditBranchDescription
|
||||
- Text.EditBranchDescription.Target
|
||||
@@ -76,6 +97,7 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.GotoRevisionSelector
|
||||
- Text.Histories.Header.DateTime
|
||||
- Text.Histories.ShowColumns
|
||||
- Text.Hotkeys.Global.OpenLocalRepository
|
||||
- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu
|
||||
- Text.Hotkeys.Global.Zoom
|
||||
- Text.Hotkeys.Repo.CreateBranch
|
||||
@@ -101,6 +123,10 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.MergeConflictEditor.Undo
|
||||
- Text.No
|
||||
- Text.OpenFile
|
||||
- Text.OpenLocalRepository
|
||||
- Text.OpenLocalRepository.Bookmark
|
||||
- Text.OpenLocalRepository.Group
|
||||
- Text.OpenLocalRepository.Path
|
||||
- Text.PageTabBar.Tab.MoveToWorkspace
|
||||
- Text.PageTabBar.Tab.Refresh
|
||||
- Text.Preferences.AI.AdditionalPrompt
|
||||
@@ -120,6 +146,8 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.SquashOrFixup.Into
|
||||
- Text.StashCM.ApplyFileChanges
|
||||
- Text.StashCM.Branch
|
||||
- Text.SubmoduleRevisionCompare
|
||||
- Text.SubmoduleRevisionCompare.OpenDetails
|
||||
- Text.TagCM.CompareTwo
|
||||
- Text.TagCM.CompareWith
|
||||
- Text.TagCM.CompareWithHead
|
||||
@@ -132,7 +160,7 @@ This document shows the translation status of each locale file in the repository
|
||||
|
||||
</details>
|
||||
|
||||
### 
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in id_ID.axaml</summary>
|
||||
@@ -140,6 +168,7 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.About.ReleaseDate
|
||||
- Text.About.ReleaseNotes
|
||||
- Text.AIAssistant.Use
|
||||
- Text.App.HideOthers
|
||||
- Text.Apply.3Way
|
||||
- Text.Blame.BlameOnPreviousRevision
|
||||
- Text.Blame.IgnoreWhitespace
|
||||
@@ -156,6 +185,8 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.CheckoutBranchFromStash
|
||||
- Text.CheckoutBranchFromStash.Branch
|
||||
- Text.CheckoutBranchFromStash.Stash
|
||||
- Text.Clone.Bookmark
|
||||
- Text.Clone.Group
|
||||
- Text.CommandPalette.Branches
|
||||
- Text.CommandPalette.BranchesAndTags
|
||||
- Text.CommandPalette.RepositoryActions
|
||||
@@ -167,9 +198,13 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Configure.CommitMessageTemplate.BuiltinVars
|
||||
- Text.Configure.Git.AskBeforeAutoUpdatingSubmodules
|
||||
- Text.Configure.Git.ConventionalTypesOverride
|
||||
- Text.ConfigureCustomActionControls.StringFormatter
|
||||
- Text.ConfigureCustomActionControls.StringFormatter.Tip
|
||||
- Text.ConfigureCustomActionControls.StringValue.Tip
|
||||
- Text.ConfigureCustomActionControls.UseFriendlyName
|
||||
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
|
||||
- Text.DealWithLocalChanges.DoNothing
|
||||
- Text.Diff.Submodule.UncommittedChanges
|
||||
- Text.Discard.IncludeModified
|
||||
- Text.DropHead
|
||||
- Text.DropHead.Commit
|
||||
@@ -182,6 +217,7 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.GotoRevisionSelector
|
||||
- Text.Histories.Header.DateTime
|
||||
- Text.Histories.ShowColumns
|
||||
- Text.Hotkeys.Global.OpenLocalRepository
|
||||
- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu
|
||||
- Text.Hotkeys.Global.Zoom
|
||||
- Text.Hotkeys.Repo.CreateBranch
|
||||
@@ -212,6 +248,10 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Open
|
||||
- Text.Open.SystemDefaultEditor
|
||||
- Text.OpenFile
|
||||
- Text.OpenLocalRepository
|
||||
- Text.OpenLocalRepository.Bookmark
|
||||
- Text.OpenLocalRepository.Group
|
||||
- Text.OpenLocalRepository.Path
|
||||
- Text.PageTabBar.Tab.MoveToWorkspace
|
||||
- Text.PageTabBar.Tab.Refresh
|
||||
- Text.Preferences.AI.AdditionalPrompt
|
||||
@@ -233,6 +273,8 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.SquashOrFixup.Into
|
||||
- Text.StashCM.ApplyFileChanges
|
||||
- Text.StashCM.Branch
|
||||
- Text.SubmoduleRevisionCompare
|
||||
- Text.SubmoduleRevisionCompare.OpenDetails
|
||||
- Text.TagCM.CompareTwo
|
||||
- Text.TagCM.CompareWith
|
||||
- Text.TagCM.CompareWithHead
|
||||
@@ -245,80 +287,109 @@ This document shows the translation status of each locale file in the repository
|
||||
|
||||
</details>
|
||||
|
||||
### 
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in it_IT.axaml</summary>
|
||||
|
||||
- Text.AIAssistant.Use
|
||||
- Text.App.HideOthers
|
||||
- Text.Apply.3Way
|
||||
- Text.ChangeCM.ResetFileTo
|
||||
- Text.CheckoutBranchFromStash
|
||||
- Text.CheckoutBranchFromStash.Branch
|
||||
- Text.CheckoutBranchFromStash.Stash
|
||||
- Text.Clone.Bookmark
|
||||
- Text.Clone.Group
|
||||
- Text.CommandPalette.Branches
|
||||
- Text.CommandPalette.BranchesAndTags
|
||||
- Text.CommandPalette.RepositoryActions
|
||||
- Text.CommandPalette.RevisionFiles
|
||||
- Text.CommitMessageTextBox.Column
|
||||
- Text.ConfigureCustomActionControls.StringFormatter
|
||||
- Text.ConfigureCustomActionControls.StringFormatter.Tip
|
||||
- Text.ConfigureCustomActionControls.UseFriendlyName
|
||||
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
|
||||
- Text.Diff.Submodule.UncommittedChanges
|
||||
- Text.Discard.IncludeModified
|
||||
- Text.GotoRevisionSelector
|
||||
- Text.Histories.Header.DateTime
|
||||
- Text.Histories.ShowColumns
|
||||
- Text.Hotkeys.Global.OpenLocalRepository
|
||||
- Text.Hotkeys.Repo.CreateBranch
|
||||
- Text.Hotkeys.Repo.GoToChild
|
||||
- Text.Hotkeys.Repo.GoToParent
|
||||
- Text.Init.CommandTip
|
||||
- Text.Init.ErrorMessageTip
|
||||
- Text.OpenLocalRepository
|
||||
- Text.OpenLocalRepository.Bookmark
|
||||
- Text.OpenLocalRepository.Group
|
||||
- Text.OpenLocalRepository.Path
|
||||
- Text.Preferences.AI.AdditionalPrompt
|
||||
- Text.Preferences.General.Use24Hours
|
||||
- Text.SelfUpdate.CurrentVersion
|
||||
- Text.SelfUpdate.ReleaseDate
|
||||
- Text.StashCM.ApplyFileChanges
|
||||
- Text.StashCM.Branch
|
||||
- Text.SubmoduleRevisionCompare
|
||||
- Text.SubmoduleRevisionCompare.OpenDetails
|
||||
- Text.Worktree.Branch
|
||||
- Text.Worktree.Head
|
||||
- Text.Worktree.Path
|
||||
|
||||
</details>
|
||||
|
||||
### 
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in ja_JP.axaml</summary>
|
||||
|
||||
- Text.AIAssistant.Use
|
||||
- Text.App.HideOthers
|
||||
- Text.Apply.3Way
|
||||
- Text.CheckoutBranchFromStash
|
||||
- Text.CheckoutBranchFromStash.Branch
|
||||
- Text.CheckoutBranchFromStash.Stash
|
||||
- Text.Clone.Bookmark
|
||||
- Text.Clone.Group
|
||||
- Text.CommandPalette.Branches
|
||||
- Text.CommandPalette.BranchesAndTags
|
||||
- Text.CommandPalette.RepositoryActions
|
||||
- Text.CommandPalette.RevisionFiles
|
||||
- Text.ConfigureCustomActionControls.StringFormatter
|
||||
- Text.ConfigureCustomActionControls.StringFormatter.Tip
|
||||
- Text.ConfigureCustomActionControls.UseFriendlyName
|
||||
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
|
||||
- Text.DealWithLocalChanges.DoNothing
|
||||
- Text.Diff.Submodule.UncommittedChanges
|
||||
- Text.Discard.IncludeModified
|
||||
- Text.Hotkeys.Global.OpenLocalRepository
|
||||
- Text.Hotkeys.Repo.CreateBranch
|
||||
- Text.Init.CommandTip
|
||||
- Text.Init.ErrorMessageTip
|
||||
- Text.OpenLocalRepository
|
||||
- Text.OpenLocalRepository.Bookmark
|
||||
- Text.OpenLocalRepository.Group
|
||||
- Text.OpenLocalRepository.Path
|
||||
- Text.Preferences.AI.AdditionalPrompt
|
||||
- Text.Preferences.General.Use24Hours
|
||||
- Text.StashCM.Branch
|
||||
- Text.SubmoduleRevisionCompare
|
||||
- Text.SubmoduleRevisionCompare.OpenDetails
|
||||
- Text.Worktree.Branch
|
||||
- Text.Worktree.Head
|
||||
- Text.Worktree.Path
|
||||
|
||||
</details>
|
||||
|
||||
### 
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in ko_KR.axaml</summary>
|
||||
|
||||
- Text.About.ReleaseDate
|
||||
- Text.AIAssistant.Use
|
||||
- Text.App.HideOthers
|
||||
- Text.Apply.3Way
|
||||
- Text.Blame.BlameOnPreviousRevision
|
||||
- Text.Blame.IgnoreWhitespace
|
||||
@@ -336,6 +407,8 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.CheckoutBranchFromStash
|
||||
- Text.CheckoutBranchFromStash.Branch
|
||||
- Text.CheckoutBranchFromStash.Stash
|
||||
- Text.Clone.Bookmark
|
||||
- Text.Clone.Group
|
||||
- Text.CommandPalette.Branches
|
||||
- Text.CommandPalette.BranchesAndTags
|
||||
- Text.CommandPalette.RepositoryActions
|
||||
@@ -345,9 +418,13 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Compare.WithHead
|
||||
- Text.Configure.Git.AskBeforeAutoUpdatingSubmodules
|
||||
- Text.Configure.Git.ConventionalTypesOverride
|
||||
- Text.ConfigureCustomActionControls.StringFormatter
|
||||
- Text.ConfigureCustomActionControls.StringFormatter.Tip
|
||||
- Text.ConfigureCustomActionControls.StringValue.Tip
|
||||
- Text.ConfigureCustomActionControls.UseFriendlyName
|
||||
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
|
||||
- Text.DealWithLocalChanges.DoNothing
|
||||
- Text.Diff.Submodule.UncommittedChanges
|
||||
- Text.Discard.IncludeModified
|
||||
- Text.EditBranchDescription
|
||||
- Text.EditBranchDescription.Target
|
||||
@@ -357,6 +434,7 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.GotoRevisionSelector
|
||||
- Text.Histories.Header.DateTime
|
||||
- Text.Histories.ShowColumns
|
||||
- Text.Hotkeys.Global.OpenLocalRepository
|
||||
- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu
|
||||
- Text.Hotkeys.Global.Zoom
|
||||
- Text.Hotkeys.Repo.CreateBranch
|
||||
@@ -387,6 +465,10 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Open
|
||||
- Text.Open.SystemDefaultEditor
|
||||
- Text.OpenFile
|
||||
- Text.OpenLocalRepository
|
||||
- Text.OpenLocalRepository.Bookmark
|
||||
- Text.OpenLocalRepository.Group
|
||||
- Text.OpenLocalRepository.Path
|
||||
- Text.PageTabBar.Tab.MoveToWorkspace
|
||||
- Text.PageTabBar.Tab.Refresh
|
||||
- Text.Preferences.AI.AdditionalPrompt
|
||||
@@ -410,6 +492,8 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.StashCM.ApplyFileChanges
|
||||
- Text.StashCM.Branch
|
||||
- Text.Submodule.Status.Unmerged
|
||||
- Text.SubmoduleRevisionCompare
|
||||
- Text.SubmoduleRevisionCompare.OpenDetails
|
||||
- Text.TagCM.CompareTwo
|
||||
- Text.TagCM.CompareWith
|
||||
- Text.TagCM.CompareWithHead
|
||||
@@ -422,12 +506,13 @@ This document shows the translation status of each locale file in the repository
|
||||
|
||||
</details>
|
||||
|
||||
### 
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in pt_BR.axaml</summary>
|
||||
|
||||
- Text.AIAssistant.Use
|
||||
- Text.App.HideOthers
|
||||
- Text.Apply.3Way
|
||||
- Text.Blame.BlameOnPreviousRevision
|
||||
- Text.BranchCM.InteractiveRebase.Manually
|
||||
@@ -449,6 +534,8 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.CheckoutBranchFromStash
|
||||
- Text.CheckoutBranchFromStash.Branch
|
||||
- Text.CheckoutBranchFromStash.Stash
|
||||
- Text.Clone.Bookmark
|
||||
- Text.Clone.Group
|
||||
- Text.Clone.RecurseSubmodules
|
||||
- Text.CommandPalette.Branches
|
||||
- Text.CommandPalette.BranchesAndTags
|
||||
@@ -509,8 +596,11 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ConfigureCustomActionControls.Label
|
||||
- Text.ConfigureCustomActionControls.Options
|
||||
- Text.ConfigureCustomActionControls.Options.Tip
|
||||
- Text.ConfigureCustomActionControls.StringFormatter
|
||||
- Text.ConfigureCustomActionControls.StringFormatter.Tip
|
||||
- Text.ConfigureCustomActionControls.StringValue.Tip
|
||||
- Text.ConfigureCustomActionControls.Type
|
||||
- Text.ConfigureCustomActionControls.UseFriendlyName
|
||||
- Text.ConfirmEmptyCommit.Continue
|
||||
- Text.ConfirmEmptyCommit.NoLocalChanges
|
||||
- Text.ConfirmEmptyCommit.StageAllThenCommit
|
||||
@@ -538,6 +628,7 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Diff.New
|
||||
- Text.Diff.Old
|
||||
- Text.Diff.Submodule.Deleted
|
||||
- Text.Diff.Submodule.UncommittedChanges
|
||||
- Text.DirHistories
|
||||
- Text.DirtyState.HasLocalChanges
|
||||
- Text.DirtyState.HasPendingPullOrPush
|
||||
@@ -554,7 +645,6 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Fetch.Force
|
||||
- Text.FileCM.CustomAction
|
||||
- Text.FileCM.ResolveUsing
|
||||
- Text.GitFlow.FinishWithPush
|
||||
- Text.GitFlow.FinishWithSquash
|
||||
- Text.GitLFS.Locks.UnlockAllMyLocks
|
||||
- Text.GitLFS.Locks.UnlockAllMyLocks.Confirm
|
||||
@@ -562,6 +652,7 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Histories.Header.DateTime
|
||||
- Text.Histories.ShowColumns
|
||||
- Text.Hotkeys.Global.Clone
|
||||
- Text.Hotkeys.Global.OpenLocalRepository
|
||||
- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu
|
||||
- Text.Hotkeys.Global.SwitchTab
|
||||
- Text.Hotkeys.Global.Zoom
|
||||
@@ -610,6 +701,10 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Open
|
||||
- Text.Open.SystemDefaultEditor
|
||||
- Text.OpenFile
|
||||
- Text.OpenLocalRepository
|
||||
- Text.OpenLocalRepository.Bookmark
|
||||
- Text.OpenLocalRepository.Group
|
||||
- Text.OpenLocalRepository.Path
|
||||
- Text.PageTabBar.Tab.MoveToWorkspace
|
||||
- Text.PageTabBar.Tab.Refresh
|
||||
- Text.Preferences.AI.AdditionalPrompt
|
||||
@@ -706,6 +801,8 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Submodule.Status.Unmerged
|
||||
- Text.Submodule.Update
|
||||
- Text.Submodule.URL
|
||||
- Text.SubmoduleRevisionCompare
|
||||
- Text.SubmoduleRevisionCompare.OpenDetails
|
||||
- Text.Tag.Tagger
|
||||
- Text.Tag.Time
|
||||
- Text.TagCM.CompareTwo
|
||||
@@ -744,9 +841,29 @@ This document shows the translation status of each locale file in the repository
|
||||
|
||||
</details>
|
||||
|
||||
### 
|
||||
### 
|
||||
|
||||
### 
|
||||
<details>
|
||||
<summary>Missing keys in ru_RU.axaml</summary>
|
||||
|
||||
- Text.App.HideOthers
|
||||
- Text.Clone.Bookmark
|
||||
- Text.Clone.Group
|
||||
- Text.ConfigureCustomActionControls.StringFormatter
|
||||
- Text.ConfigureCustomActionControls.StringFormatter.Tip
|
||||
- Text.ConfigureCustomActionControls.UseFriendlyName
|
||||
- Text.Diff.Submodule.UncommittedChanges
|
||||
- Text.Hotkeys.Global.OpenLocalRepository
|
||||
- Text.OpenLocalRepository
|
||||
- Text.OpenLocalRepository.Bookmark
|
||||
- Text.OpenLocalRepository.Group
|
||||
- Text.OpenLocalRepository.Path
|
||||
- Text.SubmoduleRevisionCompare
|
||||
- Text.SubmoduleRevisionCompare.OpenDetails
|
||||
|
||||
</details>
|
||||
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in ta_IN.axaml</summary>
|
||||
@@ -758,6 +875,7 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.AddToIgnore.Storage
|
||||
- Text.AIAssistant.Use
|
||||
- Text.App.Hide
|
||||
- Text.App.HideOthers
|
||||
- Text.App.ShowAll
|
||||
- Text.Apply.3Way
|
||||
- Text.Askpass.Passphrase
|
||||
@@ -802,6 +920,8 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.CheckoutBranchFromStash
|
||||
- Text.CheckoutBranchFromStash.Branch
|
||||
- Text.CheckoutBranchFromStash.Stash
|
||||
- Text.Clone.Bookmark
|
||||
- Text.Clone.Group
|
||||
- Text.CommandPalette.Branches
|
||||
- Text.CommandPalette.BranchesAndTags
|
||||
- Text.CommandPalette.RepositoryActions
|
||||
@@ -853,8 +973,11 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ConfigureCustomActionControls.Label
|
||||
- Text.ConfigureCustomActionControls.Options
|
||||
- Text.ConfigureCustomActionControls.Options.Tip
|
||||
- Text.ConfigureCustomActionControls.StringFormatter
|
||||
- Text.ConfigureCustomActionControls.StringFormatter.Tip
|
||||
- Text.ConfigureCustomActionControls.StringValue.Tip
|
||||
- Text.ConfigureCustomActionControls.Type
|
||||
- Text.ConfigureCustomActionControls.UseFriendlyName
|
||||
- Text.ConfirmEmptyCommit.Continue
|
||||
- Text.ConfirmEmptyCommit.NoLocalChanges
|
||||
- Text.ConfirmEmptyCommit.StageAllThenCommit
|
||||
@@ -877,6 +1000,7 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Diff.New
|
||||
- Text.Diff.Old
|
||||
- Text.Diff.Submodule.Deleted
|
||||
- Text.Diff.Submodule.UncommittedChanges
|
||||
- Text.DirHistories
|
||||
- Text.DirtyState.HasLocalChanges
|
||||
- Text.DirtyState.HasPendingPullOrPush
|
||||
@@ -891,13 +1015,13 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ExecuteCustomAction.Target
|
||||
- Text.ExecuteCustomAction.Repository
|
||||
- Text.FileCM.CustomAction
|
||||
- Text.GitFlow.FinishWithPush
|
||||
- Text.GitFlow.FinishWithSquash
|
||||
- Text.GitLFS.Locks.UnlockAllMyLocks
|
||||
- Text.GitLFS.Locks.UnlockAllMyLocks.Confirm
|
||||
- Text.GotoRevisionSelector
|
||||
- Text.Histories.Header.DateTime
|
||||
- Text.Histories.ShowColumns
|
||||
- Text.Hotkeys.Global.OpenLocalRepository
|
||||
- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu
|
||||
- Text.Hotkeys.Global.SwitchTab
|
||||
- Text.Hotkeys.Global.Zoom
|
||||
@@ -937,6 +1061,10 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Open
|
||||
- Text.Open.SystemDefaultEditor
|
||||
- Text.OpenFile
|
||||
- Text.OpenLocalRepository
|
||||
- Text.OpenLocalRepository.Bookmark
|
||||
- Text.OpenLocalRepository.Group
|
||||
- Text.OpenLocalRepository.Path
|
||||
- Text.PageTabBar.Tab.MoveToWorkspace
|
||||
- Text.PageTabBar.Tab.Refresh
|
||||
- Text.Preferences.AI.AdditionalPrompt
|
||||
@@ -1012,6 +1140,8 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Submodule.Status.Unmerged
|
||||
- Text.Submodule.Update
|
||||
- Text.Submodule.URL
|
||||
- Text.SubmoduleRevisionCompare
|
||||
- Text.SubmoduleRevisionCompare.OpenDetails
|
||||
- Text.Tag.Tagger
|
||||
- Text.Tag.Time
|
||||
- Text.TagCM.CompareTwo
|
||||
@@ -1048,7 +1178,7 @@ This document shows the translation status of each locale file in the repository
|
||||
|
||||
</details>
|
||||
|
||||
### 
|
||||
### 
|
||||
|
||||
<details>
|
||||
<summary>Missing keys in uk_UA.axaml</summary>
|
||||
@@ -1060,6 +1190,7 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.AddToIgnore.Storage
|
||||
- Text.AIAssistant.Use
|
||||
- Text.App.Hide
|
||||
- Text.App.HideOthers
|
||||
- Text.App.ShowAll
|
||||
- Text.Apply.3Way
|
||||
- Text.Askpass.Passphrase
|
||||
@@ -1104,6 +1235,8 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.CheckoutBranchFromStash
|
||||
- Text.CheckoutBranchFromStash.Branch
|
||||
- Text.CheckoutBranchFromStash.Stash
|
||||
- Text.Clone.Bookmark
|
||||
- Text.Clone.Group
|
||||
- Text.CommandPalette.Branches
|
||||
- Text.CommandPalette.BranchesAndTags
|
||||
- Text.CommandPalette.RepositoryActions
|
||||
@@ -1154,8 +1287,11 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ConfigureCustomActionControls.Label
|
||||
- Text.ConfigureCustomActionControls.Options
|
||||
- Text.ConfigureCustomActionControls.Options.Tip
|
||||
- Text.ConfigureCustomActionControls.StringFormatter
|
||||
- Text.ConfigureCustomActionControls.StringFormatter.Tip
|
||||
- Text.ConfigureCustomActionControls.StringValue.Tip
|
||||
- Text.ConfigureCustomActionControls.Type
|
||||
- Text.ConfigureCustomActionControls.UseFriendlyName
|
||||
- Text.ConfigureWorkspace.Name
|
||||
- Text.ConfirmEmptyCommit.StageSelectedThenCommit
|
||||
- Text.ConfirmRestart.Title
|
||||
@@ -1175,6 +1311,7 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Diff.New
|
||||
- Text.Diff.Old
|
||||
- Text.Diff.Submodule.Deleted
|
||||
- Text.Diff.Submodule.UncommittedChanges
|
||||
- Text.DirHistories
|
||||
- Text.DirtyState.HasLocalChanges
|
||||
- Text.DirtyState.HasPendingPullOrPush
|
||||
@@ -1189,13 +1326,13 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.ExecuteCustomAction.Target
|
||||
- Text.ExecuteCustomAction.Repository
|
||||
- Text.FileCM.CustomAction
|
||||
- Text.GitFlow.FinishWithPush
|
||||
- Text.GitFlow.FinishWithSquash
|
||||
- Text.GitLFS.Locks.UnlockAllMyLocks
|
||||
- Text.GitLFS.Locks.UnlockAllMyLocks.Confirm
|
||||
- Text.GotoRevisionSelector
|
||||
- Text.Histories.Header.DateTime
|
||||
- Text.Histories.ShowColumns
|
||||
- Text.Hotkeys.Global.OpenLocalRepository
|
||||
- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu
|
||||
- Text.Hotkeys.Global.SwitchTab
|
||||
- Text.Hotkeys.Global.Zoom
|
||||
@@ -1235,6 +1372,10 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Open
|
||||
- Text.Open.SystemDefaultEditor
|
||||
- Text.OpenFile
|
||||
- Text.OpenLocalRepository
|
||||
- Text.OpenLocalRepository.Bookmark
|
||||
- Text.OpenLocalRepository.Group
|
||||
- Text.OpenLocalRepository.Path
|
||||
- Text.PageTabBar.Tab.MoveToWorkspace
|
||||
- Text.PageTabBar.Tab.Refresh
|
||||
- Text.Preferences.AI.AdditionalPrompt
|
||||
@@ -1310,6 +1451,8 @@ This document shows the translation status of each locale file in the repository
|
||||
- Text.Submodule.Status.Unmerged
|
||||
- Text.Submodule.Update
|
||||
- Text.Submodule.URL
|
||||
- Text.SubmoduleRevisionCompare
|
||||
- Text.SubmoduleRevisionCompare.OpenDetails
|
||||
- Text.Tag.Tagger
|
||||
- Text.Tag.Time
|
||||
- Text.TagCM.CompareTwo
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.ClientModel;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.AI.OpenAI;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using OpenAI;
|
||||
@@ -55,7 +54,7 @@ namespace SourceGit.AI
|
||||
set;
|
||||
} = string.Empty;
|
||||
|
||||
public async Task<List<string>> FetchAvailableModelsAsync()
|
||||
public void FetchAvailableModels()
|
||||
{
|
||||
var allModels = GetOpenAIClient().GetOpenAIModelClient().GetModels();
|
||||
AvailableModels = new List<string>();
|
||||
@@ -71,8 +70,6 @@ namespace SourceGit.AI
|
||||
{
|
||||
Model = null;
|
||||
}
|
||||
|
||||
return AvailableModels;
|
||||
}
|
||||
|
||||
public ChatClient GetChatClient()
|
||||
@@ -84,8 +81,8 @@ namespace SourceGit.AI
|
||||
{
|
||||
var credential = new ApiKeyCredential(ReadApiKeyFromEnv ? Environment.GetEnvironmentVariable(ApiKey) : ApiKey);
|
||||
return Server.Contains("openai.azure.com/", StringComparison.Ordinal)
|
||||
? new AzureOpenAIClient(new Uri(Server), credential, new AzureOpenAIClientOptions() { UserAgentApplicationId = string.Empty })
|
||||
: new OpenAIClient(credential, new() { Endpoint = new Uri(Server), UserAgentApplicationId = string.Empty });
|
||||
? new AzureOpenAIClient(new Uri(Server), credential)
|
||||
: new OpenAIClient(credential, new() { Endpoint = new Uri(Server) });
|
||||
}
|
||||
|
||||
private string _name = string.Empty;
|
||||
|
||||
@@ -37,23 +37,61 @@ namespace SourceGit
|
||||
}
|
||||
}
|
||||
|
||||
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(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 OpenPreferencesCommand = new Command(async _ =>
|
||||
{
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner })
|
||||
{
|
||||
var dialog = new Views.Preferences();
|
||||
await dialog.ShowDialog(owner);
|
||||
}
|
||||
});
|
||||
|
||||
public static readonly Command OpenHotkeysCommand = new Command(async _ =>
|
||||
{
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner })
|
||||
{
|
||||
var dialog = new Views.Hotkeys();
|
||||
await dialog.ShowDialog(owner);
|
||||
}
|
||||
});
|
||||
|
||||
public static readonly Command OpenAppDataDirCommand = new Command(_ =>
|
||||
{
|
||||
Native.OS.OpenInFileManager(Native.OS.DataDir);
|
||||
});
|
||||
|
||||
public static readonly Command OpenAboutCommand = new Command(async _ =>
|
||||
{
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner })
|
||||
{
|
||||
var dialog = new Views.About();
|
||||
await dialog.ShowDialog(owner);
|
||||
}
|
||||
});
|
||||
|
||||
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 HideAppCommand = new Command(_ =>
|
||||
{
|
||||
if (Current is App app && app.TryGetFeature(typeof(IActivatableLifetime)) is IActivatableLifetime lifetime)
|
||||
lifetime.TryEnterBackground();
|
||||
Native.OS.HideSelf();
|
||||
});
|
||||
|
||||
public static readonly Command ShowAppCommand = new Command(_ =>
|
||||
public static readonly Command HideOtherApplicationsCommand = new Command(_ =>
|
||||
{
|
||||
if (Current is App app && app.TryGetFeature(typeof(IActivatableLifetime)) is IActivatableLifetime lifetime)
|
||||
lifetime.TryLeaveBackground();
|
||||
Native.OS.HideOtherApplications();
|
||||
});
|
||||
|
||||
public static readonly Command ShowAllApplicationsCommand = new Command(_ =>
|
||||
{
|
||||
Native.OS.ShowAllApplications();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace SourceGit
|
||||
{
|
||||
@@ -14,6 +17,47 @@ namespace SourceGit
|
||||
{
|
||||
return value.Replace("\"", "\\\"", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public static string FormatFontNames(string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
return string.Empty;
|
||||
|
||||
var parts = input.Split(',');
|
||||
var trimmed = new List<string>();
|
||||
|
||||
foreach (var part in parts)
|
||||
{
|
||||
var t = part.Trim();
|
||||
if (string.IsNullOrEmpty(t))
|
||||
continue;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
var prevChar = '\0';
|
||||
|
||||
foreach (var c in t)
|
||||
{
|
||||
if (c == ' ' && prevChar == ' ')
|
||||
continue;
|
||||
sb.Append(c);
|
||||
prevChar = c;
|
||||
}
|
||||
|
||||
var name = sb.ToString();
|
||||
try
|
||||
{
|
||||
var fontFamily = FontFamily.Parse(name);
|
||||
if (fontFamily.FamilyTypefaces.Count > 0)
|
||||
trimmed.Add(name);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore exceptions.
|
||||
}
|
||||
}
|
||||
|
||||
return trimmed.Count > 0 ? string.Join(',', trimmed) : string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CommandExtensions
|
||||
|
||||
@@ -45,7 +45,8 @@
|
||||
<NativeMenuItem Header="{DynamicResource Text.OpenAppDataDir}" Command="{x:Static s:App.OpenAppDataDirCommand}"/>
|
||||
<NativeMenuItemSeparator/>
|
||||
<NativeMenuItem Header="{DynamicResource Text.App.Hide}" Command="{x:Static s:App.HideAppCommand}" Gesture="⌘+H"/>
|
||||
<NativeMenuItem Header="{DynamicResource Text.App.ShowAll}" Command="{x:Static s:App.ShowAppCommand}"/>
|
||||
<NativeMenuItem Header="{DynamicResource Text.App.HideOthers}" Command="{x:Static s:App.HideOtherApplicationsCommand}" Gesture="⌘+Alt+H"/>
|
||||
<NativeMenuItem Header="{DynamicResource Text.App.ShowAll}" Command="{x:Static s:App.ShowAllApplicationsCommand}"/>
|
||||
<NativeMenuItemSeparator/>
|
||||
<NativeMenuItem Header="{DynamicResource Text.Quit}" Command="{x:Static s:App.QuitCommand}" Gesture="⌘+Q"/>
|
||||
</NativeMenu>
|
||||
|
||||
154
src/App.axaml.cs
154
src/App.axaml.cs
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -75,79 +73,6 @@ namespace SourceGit
|
||||
#endregion
|
||||
|
||||
#region Utility Functions
|
||||
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 = Views.ControlExtensions.CreateFromViewModels(data) as Views.ChromelessWindow;
|
||||
if (window != null)
|
||||
{
|
||||
window.DataContext = data;
|
||||
return window.ShowDialog(owner);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void ShowWindow(object data)
|
||||
{
|
||||
if (data is not Views.ChromelessWindow window)
|
||||
{
|
||||
window = Views.ControlExtensions.CreateFromViewModels(data) as Views.ChromelessWindow;
|
||||
if (window == null)
|
||||
return;
|
||||
|
||||
window.DataContext = data;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { Windows: { Count: > 0 } windows })
|
||||
{
|
||||
// Try to find the actived window (fall back to `MainWindow`)
|
||||
Window actived = windows[0];
|
||||
if (!actived.IsActive)
|
||||
{
|
||||
for (var i = 1; i < windows.Count; i++)
|
||||
{
|
||||
var test = windows[i];
|
||||
if (test.IsActive)
|
||||
{
|
||||
actived = test;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the screen where current window locates.
|
||||
var screen = actived.Screens.ScreenFromWindow(actived) ?? actived.Screens.Primary;
|
||||
if (screen == null)
|
||||
break;
|
||||
|
||||
// Calculate the startup position (Center Screen Mode) of target window
|
||||
var rect = new PixelRect(PixelSize.FromSize(window.ClientSize, actived.DesktopScaling));
|
||||
var centeredRect = screen.WorkingArea.CenterRect(rect);
|
||||
if (actived.Screens.ScreenFromPoint(centeredRect.Position) == null)
|
||||
break;
|
||||
|
||||
// Use the startup position
|
||||
window.WindowStartupLocation = WindowStartupLocation.Manual;
|
||||
window.Position = centeredRect.Position;
|
||||
}
|
||||
} while (false);
|
||||
|
||||
window.Show();
|
||||
}
|
||||
|
||||
public static async Task<bool> AskConfirmAsync(string message, Models.ConfirmButtonType buttonType = Models.ConfirmButtonType.OkCancel)
|
||||
{
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner })
|
||||
@@ -253,8 +178,8 @@ namespace SourceGit
|
||||
app._fontsOverrides = null;
|
||||
}
|
||||
|
||||
defaultFont = app.FixFontFamilyName(defaultFont);
|
||||
monospaceFont = app.FixFontFamilyName(monospaceFont);
|
||||
defaultFont = StringExtensions.FormatFontNames(defaultFont);
|
||||
monospaceFont = StringExtensions.FormatFontNames(monospaceFont);
|
||||
|
||||
var resDic = new ResourceDictionary();
|
||||
if (!string.IsNullOrEmpty(defaultFont))
|
||||
@@ -303,15 +228,9 @@ namespace SourceGit
|
||||
public static void Quit(int exitCode)
|
||||
{
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown;
|
||||
desktop.MainWindow?.Close();
|
||||
desktop.Shutdown(exitCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
Environment.Exit(exitCode);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -547,10 +466,27 @@ namespace SourceGit
|
||||
|
||||
var pref = ViewModels.Preferences.Instance;
|
||||
pref.SetCanModify();
|
||||
pref.UpdateAvailableAIModels();
|
||||
|
||||
_launcher = new ViewModels.Launcher(startupRepo);
|
||||
desktop.MainWindow = new Views.Launcher() { DataContext = _launcher };
|
||||
desktop.ShutdownMode = ShutdownMode.OnMainWindowClose;
|
||||
desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown;
|
||||
|
||||
// Fix macOS crash when quiting from Dock
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
desktop.ShutdownRequested += (_, e) =>
|
||||
{
|
||||
e.Cancel = true;
|
||||
Dispatcher.UIThread.Post(() => Quit(0));
|
||||
};
|
||||
}
|
||||
|
||||
desktop.Exit += (_, _) =>
|
||||
{
|
||||
_ipcChannel?.Dispose();
|
||||
_ipcChannel = null;
|
||||
};
|
||||
|
||||
_ipcChannel.MessageReceived += repo =>
|
||||
{
|
||||
@@ -562,8 +498,6 @@ namespace SourceGit
|
||||
});
|
||||
};
|
||||
|
||||
desktop.Exit += (_, _) => _ipcChannel.Dispose();
|
||||
|
||||
#if !DISABLE_UPDATE_DETECTION
|
||||
if (pref.ShouldCheck4UpdateOnStartup())
|
||||
Check4Update();
|
||||
@@ -619,7 +553,12 @@ namespace SourceGit
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(async () =>
|
||||
{
|
||||
await ShowDialog(new ViewModels.SelfUpdate { Data = data });
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner })
|
||||
{
|
||||
var ctx = new ViewModels.SelfUpdate { Data = data };
|
||||
var dialog = new Views.SelfUpdate() { DataContext = ctx };
|
||||
await dialog.ShowDialog(owner);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch
|
||||
@@ -629,47 +568,6 @@ namespace SourceGit
|
||||
}
|
||||
#endregion
|
||||
|
||||
private string FixFontFamilyName(string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
return string.Empty;
|
||||
|
||||
var parts = input.Split(',');
|
||||
var trimmed = new List<string>();
|
||||
|
||||
foreach (var part in parts)
|
||||
{
|
||||
var t = part.Trim();
|
||||
if (string.IsNullOrEmpty(t))
|
||||
continue;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
var prevChar = '\0';
|
||||
|
||||
foreach (var c in t)
|
||||
{
|
||||
if (c == ' ' && prevChar == ' ')
|
||||
continue;
|
||||
sb.Append(c);
|
||||
prevChar = c;
|
||||
}
|
||||
|
||||
var name = sb.ToString();
|
||||
try
|
||||
{
|
||||
var fontFamily = FontFamily.Parse(name);
|
||||
if (fontFamily.FamilyTypefaces.Count > 0)
|
||||
trimmed.Add(name);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore exceptions.
|
||||
}
|
||||
}
|
||||
|
||||
return trimmed.Count > 0 ? string.Join(',', trimmed) : string.Empty;
|
||||
}
|
||||
|
||||
private Models.IpcChannel _ipcChannel = null;
|
||||
private ViewModels.Launcher _launcher = null;
|
||||
private ResourceDictionary _activeLocale = null;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
@@ -46,23 +47,28 @@ namespace SourceGit.Commands
|
||||
proc.StartInfo = CreateGitStartInfo(true);
|
||||
proc.Start();
|
||||
|
||||
var text = await proc.StandardOutput.ReadToEndAsync().ConfigureAwait(false);
|
||||
using var ms = new MemoryStream();
|
||||
await proc.StandardOutput.BaseStream.CopyToAsync(ms, CancellationToken).ConfigureAwait(false);
|
||||
|
||||
var bytes = ms.ToArray();
|
||||
var start = 0;
|
||||
var end = text.IndexOf('\n', start);
|
||||
while (end > 0)
|
||||
while (start < bytes.Length)
|
||||
{
|
||||
var line = text[start..end];
|
||||
ParseLine(line);
|
||||
var end = Array.IndexOf(bytes, (byte)'\n', start);
|
||||
if (end < 0)
|
||||
{
|
||||
ParseLine(bytes[start..]);
|
||||
break;
|
||||
}
|
||||
|
||||
ParseLine(bytes[start..end]);
|
||||
if (_result.IsBinary)
|
||||
break;
|
||||
|
||||
start = end + 1;
|
||||
end = text.IndexOf('\n', start);
|
||||
}
|
||||
|
||||
if (start < text.Length)
|
||||
ParseLine(text[start..]);
|
||||
|
||||
await proc.WaitForExitAsync().ConfigureAwait(false);
|
||||
await proc.WaitForExitAsync(CancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -82,66 +88,14 @@ namespace SourceGit.Commands
|
||||
return _result;
|
||||
}
|
||||
|
||||
private void ParseLine(string line)
|
||||
private void ParseLine(byte[] lineBytes)
|
||||
{
|
||||
if (_result.IsBinary)
|
||||
var line = Encoding.UTF8.GetString(lineBytes);
|
||||
if (ParseFileModeChange(line))
|
||||
return;
|
||||
|
||||
if (line.StartsWith("old mode ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.OldMode = line.Substring(9);
|
||||
if (ParseLFSChange(line))
|
||||
return;
|
||||
}
|
||||
|
||||
if (line.StartsWith("new mode ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.NewMode = line.Substring(9);
|
||||
return;
|
||||
}
|
||||
|
||||
if (line.StartsWith("deleted file mode ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.OldMode = line.Substring(18);
|
||||
return;
|
||||
}
|
||||
|
||||
if (line.StartsWith("new file mode ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.NewMode = line.Substring(14);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_result.IsLFS)
|
||||
{
|
||||
var ch = line[0];
|
||||
if (ch == '-')
|
||||
{
|
||||
if (line.StartsWith("-oid sha256:", StringComparison.Ordinal))
|
||||
{
|
||||
_result.LFSDiff.Old.Oid = line.Substring(12);
|
||||
}
|
||||
else if (line.StartsWith("-size ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.LFSDiff.Old.Size = long.Parse(line.AsSpan(6));
|
||||
}
|
||||
}
|
||||
else if (ch == '+')
|
||||
{
|
||||
if (line.StartsWith("+oid sha256:", StringComparison.Ordinal))
|
||||
{
|
||||
_result.LFSDiff.New.Oid = line.Substring(12);
|
||||
}
|
||||
else if (line.StartsWith("+size ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.LFSDiff.New.Size = long.Parse(line.AsSpan(6));
|
||||
}
|
||||
}
|
||||
else if (line.StartsWith(" size ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.LFSDiff.New.Size = _result.LFSDiff.Old.Size = long.Parse(line.AsSpan(6));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_result.TextDiff.Lines.Count == 0)
|
||||
{
|
||||
@@ -168,7 +122,7 @@ namespace SourceGit.Commands
|
||||
|
||||
_oldLine = int.Parse(match.Groups[1].Value);
|
||||
_newLine = int.Parse(match.Groups[2].Value);
|
||||
_last = new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0);
|
||||
_last = new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, lineBytes, 0, 0);
|
||||
_result.TextDiff.Lines.Add(_last);
|
||||
}
|
||||
}
|
||||
@@ -177,7 +131,7 @@ namespace SourceGit.Commands
|
||||
if (line.Length == 0)
|
||||
{
|
||||
ProcessInlineHighlights();
|
||||
_last = new Models.TextDiffLine(Models.TextDiffLineType.Normal, "", _oldLine, _newLine);
|
||||
_last = new Models.TextDiffLine(Models.TextDiffLineType.Normal, "", [], _oldLine, _newLine);
|
||||
_result.TextDiff.Lines.Add(_last);
|
||||
_oldLine++;
|
||||
_newLine++;
|
||||
@@ -187,29 +141,15 @@ namespace SourceGit.Commands
|
||||
var ch = line[0];
|
||||
if (ch == '-')
|
||||
{
|
||||
if (_oldLine == 1 && _newLine == 0 && line.StartsWith(PREFIX_LFS_DEL, StringComparison.Ordinal))
|
||||
{
|
||||
_result.IsLFS = true;
|
||||
_result.LFSDiff = new Models.LFSDiff();
|
||||
return;
|
||||
}
|
||||
|
||||
_result.TextDiff.DeletedLines++;
|
||||
_last = new Models.TextDiffLine(Models.TextDiffLineType.Deleted, line.Substring(1), _oldLine, 0);
|
||||
_last = new Models.TextDiffLine(Models.TextDiffLineType.Deleted, line.Substring(1), lineBytes[1..], _oldLine, 0);
|
||||
_deleted.Add(_last);
|
||||
_oldLine++;
|
||||
}
|
||||
else if (ch == '+')
|
||||
{
|
||||
if (_oldLine == 0 && _newLine == 1 && line.StartsWith(PREFIX_LFS_NEW, StringComparison.Ordinal))
|
||||
{
|
||||
_result.IsLFS = true;
|
||||
_result.LFSDiff = new Models.LFSDiff();
|
||||
return;
|
||||
}
|
||||
|
||||
_result.TextDiff.AddedLines++;
|
||||
_last = new Models.TextDiffLine(Models.TextDiffLineType.Added, line.Substring(1), 0, _newLine);
|
||||
_last = new Models.TextDiffLine(Models.TextDiffLineType.Added, line.Substring(1), lineBytes[1..], 0, _newLine);
|
||||
_added.Add(_last);
|
||||
_newLine++;
|
||||
}
|
||||
@@ -221,19 +161,12 @@ namespace SourceGit.Commands
|
||||
{
|
||||
_oldLine = int.Parse(match.Groups[1].Value);
|
||||
_newLine = int.Parse(match.Groups[2].Value);
|
||||
_last = new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0);
|
||||
_last = new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, lineBytes, 0, 0);
|
||||
_result.TextDiff.Lines.Add(_last);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_oldLine == 1 && _newLine == 1 && line.StartsWith(PREFIX_LFS_MODIFY, StringComparison.Ordinal))
|
||||
{
|
||||
_result.IsLFS = true;
|
||||
_result.LFSDiff = new Models.LFSDiff();
|
||||
return;
|
||||
}
|
||||
|
||||
_last = new Models.TextDiffLine(Models.TextDiffLineType.Normal, line.Substring(1), _oldLine, _newLine);
|
||||
_last = new Models.TextDiffLine(Models.TextDiffLineType.Normal, line.Substring(1), lineBytes[1..], _oldLine, _newLine);
|
||||
_result.TextDiff.Lines.Add(_last);
|
||||
_oldLine++;
|
||||
_newLine++;
|
||||
@@ -246,6 +179,70 @@ namespace SourceGit.Commands
|
||||
}
|
||||
}
|
||||
|
||||
private bool ParseFileModeChange(string line)
|
||||
{
|
||||
if (line.StartsWith("old mode ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.OldMode = line.Substring(9);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (line.StartsWith("new mode ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.NewMode = line.Substring(9);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (line.StartsWith("deleted file mode ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.OldMode = line.Substring(18);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (line.StartsWith("new file mode ", StringComparison.Ordinal))
|
||||
{
|
||||
_result.NewMode = line.Substring(14);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool ParseLFSChange(string line)
|
||||
{
|
||||
if (_result.IsLFS)
|
||||
{
|
||||
if (line.StartsWith("-oid sha256:", StringComparison.Ordinal))
|
||||
_result.LFSDiff.Old.Oid = line.Substring(12);
|
||||
else if (line.StartsWith("-size ", StringComparison.Ordinal))
|
||||
_result.LFSDiff.Old.Size = long.Parse(line.AsSpan(6));
|
||||
else if (line.StartsWith("+oid sha256:", StringComparison.Ordinal))
|
||||
_result.LFSDiff.New.Oid = line.Substring(12);
|
||||
else if (line.StartsWith("+size ", StringComparison.Ordinal))
|
||||
_result.LFSDiff.New.Size = long.Parse(line.AsSpan(6));
|
||||
else if (line.StartsWith(" size ", StringComparison.Ordinal))
|
||||
_result.LFSDiff.New.Size = _result.LFSDiff.Old.Size = long.Parse(line.AsSpan(6));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_result.TextDiff.Lines.Count != 1)
|
||||
return false;
|
||||
|
||||
var isLFS = (_oldLine == 1 && _newLine == 1 && line.StartsWith(PREFIX_LFS_MODIFY, StringComparison.Ordinal)) ||
|
||||
(_oldLine == 1 && _newLine == 0 && line.StartsWith(PREFIX_LFS_DEL, StringComparison.Ordinal)) ||
|
||||
(_oldLine == 0 && _newLine == 1 && line.StartsWith(PREFIX_LFS_NEW, StringComparison.Ordinal));
|
||||
|
||||
if (isLFS)
|
||||
{
|
||||
_result.IsLFS = true;
|
||||
_result.LFSDiff = new Models.LFSDiff();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ProcessInlineHighlights()
|
||||
{
|
||||
if (_deleted.Count > 0)
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace SourceGit.Commands
|
||||
return await start.Use(log).ExecAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task<bool> FinishAsync(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 keepBranch, Models.ICommandLog log)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append("flow ");
|
||||
@@ -73,8 +73,6 @@ namespace SourceGit.Commands
|
||||
builder.Append(" finish ");
|
||||
if (squash)
|
||||
builder.Append("--squash ");
|
||||
if (push)
|
||||
builder.Append("--push ");
|
||||
if (keepBranch)
|
||||
builder.Append("-k ");
|
||||
builder.Append(name);
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace SourceGit.Commands
|
||||
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"log --topo-order --cherry-pick --right-only --no-merges --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";
|
||||
Args = $"log --topo-order --cherry-pick --right-only --no-merges --no-show-signature --decorate=full --format=\"%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s%n%B%n{_boundary}\" {on}...HEAD";
|
||||
}
|
||||
|
||||
public async Task<List<Models.InteractiveCommit>> GetResultAsync()
|
||||
@@ -58,6 +58,9 @@ namespace SourceGit.Commands
|
||||
case 6:
|
||||
current.Commit.CommitterTime = ulong.Parse(line);
|
||||
break;
|
||||
case 7:
|
||||
current.Commit.Subject = line;
|
||||
break;
|
||||
default:
|
||||
var boundary = rs.StdOut.IndexOf(_boundary, end + 1, StringComparison.Ordinal);
|
||||
if (boundary > end)
|
||||
|
||||
@@ -19,6 +19,8 @@ namespace SourceGit.Models
|
||||
PathSelector,
|
||||
CheckBox,
|
||||
ComboBox,
|
||||
LocalBranchSelector,
|
||||
RemoteBranchSelector,
|
||||
}
|
||||
|
||||
public record CustomActionTargetFile(string File, Commit Revision);
|
||||
@@ -49,6 +51,12 @@ namespace SourceGit.Models
|
||||
set => SetProperty(ref _stringValue, value);
|
||||
}
|
||||
|
||||
public string StringFormatter
|
||||
{
|
||||
get => _stringFormatter;
|
||||
set => SetProperty(ref _stringFormatter, value);
|
||||
}
|
||||
|
||||
public bool BoolValue
|
||||
{
|
||||
get => _boolValue;
|
||||
@@ -59,6 +67,7 @@ namespace SourceGit.Models
|
||||
private string _label = string.Empty;
|
||||
private string _description = string.Empty;
|
||||
private string _stringValue = string.Empty;
|
||||
private string _stringFormatter = string.Empty;
|
||||
private bool _boolValue = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace SourceGit.Models
|
||||
public class TextDiffLine
|
||||
{
|
||||
public TextDiffLineType Type { get; set; } = TextDiffLineType.None;
|
||||
public byte[] RawContent { get; set; } = [];
|
||||
public string Content { get; set; } = "";
|
||||
public int OldLineNumber { get; set; } = 0;
|
||||
public int NewLineNumber { get; set; } = 0;
|
||||
@@ -33,10 +34,11 @@ namespace SourceGit.Models
|
||||
public string NewLine => NewLineNumber == 0 ? string.Empty : NewLineNumber.ToString();
|
||||
|
||||
public TextDiffLine() { }
|
||||
public TextDiffLine(TextDiffLineType type, string content, int oldLine, int newLine)
|
||||
public TextDiffLine(TextDiffLineType type, string line, byte[] rawContent, int oldLine, int newLine)
|
||||
{
|
||||
Type = type;
|
||||
Content = content;
|
||||
Content = line;
|
||||
RawContent = rawContent;
|
||||
OldLineNumber = oldLine;
|
||||
NewLineNumber = newLine;
|
||||
}
|
||||
@@ -97,19 +99,19 @@ namespace SourceGit.Models
|
||||
return rs;
|
||||
}
|
||||
|
||||
public void GenerateNewPatchFromSelection(Change change, string fileBlobGuid, TextDiffSelection selection, bool revert, string output)
|
||||
public void GenerateNewPatchFromSelection(string file, string fileBlobGuid, TextDiffSelection selection, bool revert, string output)
|
||||
{
|
||||
var isTracked = !string.IsNullOrEmpty(fileBlobGuid);
|
||||
var fileGuid = isTracked ? fileBlobGuid : "00000000";
|
||||
|
||||
using var writer = new StreamWriter(output);
|
||||
writer.NewLine = "\n";
|
||||
writer.WriteLine($"diff --git a/{change.Path} b/{change.Path}");
|
||||
writer.WriteLine($"diff --git a/{file} b/{file}");
|
||||
if (!revert && !isTracked)
|
||||
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}");
|
||||
writer.WriteLine($"--- {(revert || isTracked ? $"a/{file}" : "/dev/null")}");
|
||||
writer.WriteLine($"+++ b/{file}");
|
||||
|
||||
var additions = selection.EndLine - selection.StartLine;
|
||||
if (selection.StartLine != 1)
|
||||
@@ -146,19 +148,17 @@ namespace SourceGit.Models
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
public void GeneratePatchFromSelection(Change change, string fileTreeGuid, TextDiffSelection selection, bool revert, string output)
|
||||
public void GeneratePatchFromSelection(string file, string fileTreeGuid, TextDiffSelection selection, bool revert, string output)
|
||||
{
|
||||
var orgFile = !string.IsNullOrEmpty(change.OriginalPath) ? change.OriginalPath : change.Path;
|
||||
|
||||
using var writer = new StreamWriter(output);
|
||||
writer.NewLine = "\n";
|
||||
writer.WriteLine($"diff --git a/{change.Path} b/{change.Path}");
|
||||
writer.WriteLine($"diff --git a/{file} b/{file}");
|
||||
writer.WriteLine($"index 00000000...{fileTreeGuid} 100644");
|
||||
writer.WriteLine($"--- a/{orgFile}");
|
||||
writer.WriteLine($"+++ b/{change.Path}");
|
||||
writer.WriteLine($"--- a/{file}");
|
||||
writer.WriteLine($"+++ b/{file}");
|
||||
|
||||
// If last line of selection is a change. Find one more line.
|
||||
string tail = null;
|
||||
TextDiffLine tail = null;
|
||||
if (selection.EndLine < Lines.Count)
|
||||
{
|
||||
var lastLine = Lines[selection.EndLine - 1];
|
||||
@@ -173,7 +173,7 @@ namespace SourceGit.Models
|
||||
(revert && line.Type == TextDiffLineType.Added) ||
|
||||
(!revert && line.Type == TextDiffLineType.Deleted))
|
||||
{
|
||||
tail = line.Content;
|
||||
tail = line;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -256,24 +256,22 @@ namespace SourceGit.Models
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tail))
|
||||
writer.WriteLine($" {tail}");
|
||||
if (tail != null)
|
||||
WriteLine(writer, ' ', tail);
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
public void GeneratePatchFromSelectionSingleSide(Change change, string fileTreeGuid, TextDiffSelection selection, bool revert, bool isOldSide, string output)
|
||||
public void GeneratePatchFromSelectionSingleSide(string file, string fileTreeGuid, TextDiffSelection selection, bool revert, bool isOldSide, string output)
|
||||
{
|
||||
var orgFile = !string.IsNullOrEmpty(change.OriginalPath) ? change.OriginalPath : change.Path;
|
||||
|
||||
using var writer = new StreamWriter(output);
|
||||
writer.NewLine = "\n";
|
||||
writer.WriteLine($"diff --git a/{change.Path} b/{change.Path}");
|
||||
writer.WriteLine($"diff --git a/{file} b/{file}");
|
||||
writer.WriteLine($"index 00000000...{fileTreeGuid} 100644");
|
||||
writer.WriteLine($"--- a/{orgFile}");
|
||||
writer.WriteLine($"+++ b/{change.Path}");
|
||||
writer.WriteLine($"--- a/{file}");
|
||||
writer.WriteLine($"+++ b/{file}");
|
||||
|
||||
// If last line of selection is a change. Find one more line.
|
||||
string tail = null;
|
||||
TextDiffLine tail = null;
|
||||
if (selection.EndLine < Lines.Count)
|
||||
{
|
||||
var lastLine = Lines[selection.EndLine - 1];
|
||||
@@ -288,7 +286,7 @@ namespace SourceGit.Models
|
||||
{
|
||||
if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Added)
|
||||
{
|
||||
tail = line.Content;
|
||||
tail = line;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -296,7 +294,7 @@ namespace SourceGit.Models
|
||||
{
|
||||
if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Deleted)
|
||||
{
|
||||
tail = line.Content;
|
||||
tail = line;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -408,8 +406,8 @@ namespace SourceGit.Models
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tail))
|
||||
writer.WriteLine($" {tail}");
|
||||
if (tail != null)
|
||||
WriteLine(writer, ' ', tail);
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
@@ -564,7 +562,11 @@ namespace SourceGit.Models
|
||||
|
||||
private static void WriteLine(StreamWriter writer, char prefix, TextDiffLine line)
|
||||
{
|
||||
writer.WriteLine($"{prefix}{line.Content}");
|
||||
writer.Flush();
|
||||
|
||||
writer.BaseStream.WriteByte((byte)prefix);
|
||||
writer.BaseStream.Write(line.RawContent);
|
||||
writer.BaseStream.WriteByte((byte)'\n');
|
||||
|
||||
if (line.NoNewLineEndOfFile)
|
||||
writer.WriteLine("\\ No newline at end of file");
|
||||
@@ -602,8 +604,13 @@ namespace SourceGit.Models
|
||||
|
||||
public class SubmoduleDiff
|
||||
{
|
||||
public string FullPath { get; set; } = string.Empty;
|
||||
public RevisionSubmodule Old { get; set; } = null;
|
||||
public RevisionSubmodule New { get; set; } = null;
|
||||
|
||||
public bool CanOpenDetails => File.Exists(Path.Combine(FullPath, ".git")) &&
|
||||
Old != null && Old.Commit.Author != User.Invalid &&
|
||||
New != null && New.Commit.Author != User.Invalid;
|
||||
}
|
||||
|
||||
public class DiffResult
|
||||
|
||||
@@ -39,5 +39,6 @@ namespace SourceGit.Models
|
||||
{
|
||||
public Commit Commit { get; set; } = null;
|
||||
public CommitFullMessage FullMessage { get; set; } = null;
|
||||
public int UncommittedChanges { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,21 @@ namespace SourceGit.Native
|
||||
}
|
||||
}
|
||||
|
||||
public void HideSelf()
|
||||
{
|
||||
// Do Nothing. Never used.
|
||||
}
|
||||
|
||||
public void HideOtherApplications()
|
||||
{
|
||||
// Do Nothing. Never used.
|
||||
}
|
||||
|
||||
public void ShowAllApplications()
|
||||
{
|
||||
// Do Nothing. Never used.
|
||||
}
|
||||
|
||||
public string GetDataDir()
|
||||
{
|
||||
// AppImage supports portable mode
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
using Avalonia;
|
||||
@@ -13,6 +14,18 @@ namespace SourceGit.Native
|
||||
[SupportedOSPlatform("macOS")]
|
||||
internal class MacOS : OS.IBackend
|
||||
{
|
||||
[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_getClass")]
|
||||
public static extern IntPtr objc_getClass(string name);
|
||||
|
||||
[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "sel_registerName")]
|
||||
public static extern IntPtr sel_registerName(string name);
|
||||
|
||||
[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
|
||||
public static extern IntPtr objc_msgSend(IntPtr receiver, IntPtr selector);
|
||||
|
||||
[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
|
||||
public static extern IntPtr objc_msgSendWithArg(IntPtr receiver, IntPtr selector, IntPtr arg);
|
||||
|
||||
public void SetupApp(AppBuilder builder)
|
||||
{
|
||||
builder.With(new MacOSPlatformOptions()
|
||||
@@ -44,6 +57,39 @@ namespace SourceGit.Native
|
||||
window.ExtendClientAreaToDecorationsHint = true;
|
||||
}
|
||||
|
||||
public void HideSelf()
|
||||
{
|
||||
IntPtr nsApplicationClass = objc_getClass("NSApplication");
|
||||
IntPtr nsSharedApplicationSelector = sel_registerName("sharedApplication");
|
||||
IntPtr nsApp = objc_msgSend(nsApplicationClass, nsSharedApplicationSelector);
|
||||
IntPtr nsMethodSelector = sel_registerName("hide:");
|
||||
IntPtr nsDelegateSelector = sel_registerName("delegate");
|
||||
IntPtr nsDelegate = objc_msgSend(nsApp, nsDelegateSelector);
|
||||
objc_msgSendWithArg(nsApp, nsMethodSelector, nsDelegate);
|
||||
}
|
||||
|
||||
public void HideOtherApplications()
|
||||
{
|
||||
IntPtr nsApplicationClass = objc_getClass("NSApplication");
|
||||
IntPtr nsSharedApplicationSelector = sel_registerName("sharedApplication");
|
||||
IntPtr nsApp = objc_msgSend(nsApplicationClass, nsSharedApplicationSelector);
|
||||
IntPtr nsMethodSelector = sel_registerName("hideOtherApplications:");
|
||||
IntPtr nsDelegateSelector = sel_registerName("delegate");
|
||||
IntPtr nsDelegate = objc_msgSend(nsApp, nsDelegateSelector);
|
||||
objc_msgSendWithArg(nsApp, nsMethodSelector, nsDelegate);
|
||||
}
|
||||
|
||||
public void ShowAllApplications()
|
||||
{
|
||||
IntPtr nsApplicationClass = objc_getClass("NSApplication");
|
||||
IntPtr nsSharedApplicationSelector = sel_registerName("sharedApplication");
|
||||
IntPtr nsApp = objc_msgSend(nsApplicationClass, nsSharedApplicationSelector);
|
||||
IntPtr nsMethodSelector = sel_registerName("unhideAllApplications:");
|
||||
IntPtr nsDelegateSelector = sel_registerName("delegate");
|
||||
IntPtr nsDelegate = objc_msgSend(nsApp, nsDelegateSelector);
|
||||
objc_msgSendWithArg(nsApp, nsMethodSelector, nsDelegate);
|
||||
}
|
||||
|
||||
public string GetDataDir()
|
||||
{
|
||||
return Path.Combine(
|
||||
|
||||
@@ -18,6 +18,10 @@ namespace SourceGit.Native
|
||||
void SetupApp(AppBuilder builder);
|
||||
void SetupWindow(Window window);
|
||||
|
||||
void HideSelf();
|
||||
void HideOtherApplications();
|
||||
void ShowAllApplications();
|
||||
|
||||
string GetDataDir();
|
||||
string FindGitExecutable();
|
||||
string FindTerminal(Models.ShellOrTerminal shell);
|
||||
@@ -154,6 +158,21 @@ namespace SourceGit.Native
|
||||
_backend.SetupWindow(window);
|
||||
}
|
||||
|
||||
public static void HideSelf()
|
||||
{
|
||||
_backend.HideSelf();
|
||||
}
|
||||
|
||||
public static void HideOtherApplications()
|
||||
{
|
||||
_backend.HideOtherApplications();
|
||||
}
|
||||
|
||||
public static void ShowAllApplications()
|
||||
{
|
||||
_backend.ShowAllApplications();
|
||||
}
|
||||
|
||||
public static void LogException(Exception ex)
|
||||
{
|
||||
if (ex == null)
|
||||
|
||||
@@ -58,6 +58,21 @@ namespace SourceGit.Native
|
||||
window.BorderThickness = new Thickness(1);
|
||||
}
|
||||
|
||||
public void HideSelf()
|
||||
{
|
||||
// Do Nothing. Never used.
|
||||
}
|
||||
|
||||
public void HideOtherApplications()
|
||||
{
|
||||
// Do Nothing. Never used.
|
||||
}
|
||||
|
||||
public void ShowAllApplications()
|
||||
{
|
||||
// Do Nothing. Never used.
|
||||
}
|
||||
|
||||
public string GetDataDir()
|
||||
{
|
||||
var execFile = Process.GetCurrentProcess().MainModule!.FileName;
|
||||
|
||||
@@ -425,7 +425,6 @@ $1, $2, … Werte der Eingabe-Steuerelemente</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">FLOW – Hotfix fertigstellen</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">FLOW – Release fertigstellen</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">Ziel:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithPush" xml:space="preserve">Push zu Remote(s) nach Abschluss</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithSquash" xml:space="preserve">Squash beim Merge</x:String>
|
||||
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">Hotfix:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">Hotfix-Präfix:</x:String>
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<x:String x:Key="Text.AIAssistant.Tip" xml:space="preserve">Use AI to generate commit message</x:String>
|
||||
<x:String x:Key="Text.AIAssistant.Use" xml:space="preserve">Use</x:String>
|
||||
<x:String x:Key="Text.App.Hide" xml:space="preserve">Hide SourceGit</x:String>
|
||||
<x:String x:Key="Text.App.HideOthers" xml:space="preserve">Hide Others</x:String>
|
||||
<x:String x:Key="Text.App.ShowAll" xml:space="preserve">Show All</x:String>
|
||||
<x:String x:Key="Text.Apply" xml:space="preserve">Patch</x:String>
|
||||
<x:String x:Key="Text.Apply.3Way" xml:space="preserve">3-Way Merge</x:String>
|
||||
@@ -130,6 +131,8 @@
|
||||
<x:String x:Key="Text.Clone" xml:space="preserve">Clone Remote Repository</x:String>
|
||||
<x:String x:Key="Text.Clone.AdditionalParam" xml:space="preserve">Extra Parameters:</x:String>
|
||||
<x:String x:Key="Text.Clone.AdditionalParam.Placeholder" xml:space="preserve">Additional arguments to clone repository. Optional.</x:String>
|
||||
<x:String x:Key="Text.Clone.Bookmark" xml:space="preserve">Bookmark:</x:String>
|
||||
<x:String x:Key="Text.Clone.Group" xml:space="preserve">Group:</x:String>
|
||||
<x:String x:Key="Text.Clone.LocalName" xml:space="preserve">Local Name:</x:String>
|
||||
<x:String x:Key="Text.Clone.LocalName.Placeholder" xml:space="preserve">Repository name. Optional.</x:String>
|
||||
<x:String x:Key="Text.Clone.ParentFolder" xml:space="preserve">Parent Folder:</x:String>
|
||||
@@ -275,8 +278,11 @@
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Label" xml:space="preserve">Label:</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Options" xml:space="preserve">Options:</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Options.Tip" xml:space="preserve">Use '|' as delimiter for options</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.StringFormatter" xml:space="preserve">String Formatter:</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.StringFormatter.Tip" xml:space="preserve">Optional. Used to format output string. Ignored when input is empty. Please use `${VALUE}` to represent the input string.</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.StringValue.Tip" xml:space="preserve">The built-in variables ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE}, and ${TAG} remain available here</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Type" xml:space="preserve">Type:</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.UseFriendlyName" xml:space="preserve">Use Friendly Name:</x:String>
|
||||
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Workspaces</x:String>
|
||||
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Color</x:String>
|
||||
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">Name</x:String>
|
||||
@@ -370,6 +376,7 @@
|
||||
<x:String x:Key="Text.Diff.Submodule" xml:space="preserve">SUBMODULE</x:String>
|
||||
<x:String x:Key="Text.Diff.Submodule.Deleted" xml:space="preserve">DELETED</x:String>
|
||||
<x:String x:Key="Text.Diff.Submodule.New" xml:space="preserve">NEW</x:String>
|
||||
<x:String x:Key="Text.Diff.Submodule.UncommittedChanges" xml:space="preserve">+ {0} Uncommitted Changes</x:String>
|
||||
<x:String x:Key="Text.Diff.SwapCommits" xml:space="preserve">Swap</x:String>
|
||||
<x:String x:Key="Text.Diff.SyntaxHighlight" xml:space="preserve">Syntax Highlighting</x:String>
|
||||
<x:String x:Key="Text.Diff.ToggleWordWrap" xml:space="preserve">Line Word Wrap</x:String>
|
||||
@@ -433,7 +440,6 @@
|
||||
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">FLOW - Finish Hotfix</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">FLOW - Finish Release</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">Target:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithPush" xml:space="preserve">Push to remote(s) after performing finish</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithSquash" xml:space="preserve">Squash during merge</x:String>
|
||||
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">Hotfix:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">Hotfix Prefix:</x:String>
|
||||
@@ -499,6 +505,7 @@
|
||||
<x:String x:Key="Text.Hotkeys.Global.GotoNextTab" xml:space="preserve">Go to next tab</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.GotoPrevTab" xml:space="preserve">Go to previous tab</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">Create new tab</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.OpenLocalRepository" xml:space="preserve">Open local repository</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.OpenPreferences" xml:space="preserve">Open Preferences dialog</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.ShowWorkspaceDropdownMenu" xml:space="preserve">Show workspace dropdown menu</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.SwitchTab" xml:space="preserve">Switch active tab</x:String>
|
||||
@@ -592,6 +599,10 @@
|
||||
<x:String x:Key="Text.OpenAppDataDir" xml:space="preserve">Open Data Storage Directory</x:String>
|
||||
<x:String x:Key="Text.OpenFile" xml:space="preserve">Open File</x:String>
|
||||
<x:String x:Key="Text.OpenInExternalMergeTool" xml:space="preserve">Open in External Merge Tool</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository" xml:space="preserve">Open Local Repository</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository.Bookmark" xml:space="preserve">Bookmark:</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository.Group" xml:space="preserve">Group:</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository.Path" xml:space="preserve">Folder:</x:String>
|
||||
<x:String x:Key="Text.Optional" xml:space="preserve">Optional.</x:String>
|
||||
<x:String x:Key="Text.PageTabBar.New" xml:space="preserve">Create New Tab</x:String>
|
||||
<x:String x:Key="Text.PageTabBar.Tab.Close" xml:space="preserve">Close Tab</x:String>
|
||||
@@ -898,6 +909,8 @@
|
||||
<x:String x:Key="Text.Submodule.Status.Unmerged" xml:space="preserve">unmerged</x:String>
|
||||
<x:String x:Key="Text.Submodule.Update" xml:space="preserve">Update</x:String>
|
||||
<x:String x:Key="Text.Submodule.URL" xml:space="preserve">URL</x:String>
|
||||
<x:String x:Key="Text.SubmoduleRevisionCompare" xml:space="preserve">Submodule Change Details</x:String>
|
||||
<x:String x:Key="Text.SubmoduleRevisionCompare.OpenDetails" xml:space="preserve">OPEN DETAILS</x:String>
|
||||
<x:String x:Key="Text.Sure" xml:space="preserve">OK</x:String>
|
||||
<x:String x:Key="Text.Tag.Tagger" xml:space="preserve">TAGGER</x:String>
|
||||
<x:String x:Key="Text.Tag.Time" xml:space="preserve">TIME</x:String>
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
<x:String x:Key="Text.AIAssistant.Tip" xml:space="preserve">Usar OpenAI para generar mensaje de commit</x:String>
|
||||
<x:String x:Key="Text.AIAssistant.Use" xml:space="preserve">Usar</x:String>
|
||||
<x:String x:Key="Text.App.Hide" xml:space="preserve">Ocultar SourceGit</x:String>
|
||||
<x:String x:Key="Text.App.HideOthers" xml:space="preserve">Ocultar Otros</x:String>
|
||||
<x:String x:Key="Text.App.ShowAll" xml:space="preserve">Mostrar Todo</x:String>
|
||||
<x:String x:Key="Text.Apply" xml:space="preserve">Aplicar Parche</x:String>
|
||||
<x:String x:Key="Text.Apply.3Way" xml:space="preserve">Merge a 3 vías (3-Way)</x:String>
|
||||
@@ -134,6 +135,8 @@
|
||||
<x:String x:Key="Text.Clone" xml:space="preserve">Clonar Repositorio Remoto</x:String>
|
||||
<x:String x:Key="Text.Clone.AdditionalParam" xml:space="preserve">Parámetros Adicionales:</x:String>
|
||||
<x:String x:Key="Text.Clone.AdditionalParam.Placeholder" xml:space="preserve">Argumentos adicionales para clonar el repositorio. Opcional.</x:String>
|
||||
<x:String x:Key="Text.Clone.Bookmark" xml:space="preserve">Marcador:</x:String>
|
||||
<x:String x:Key="Text.Clone.Group" xml:space="preserve">Grupo:</x:String>
|
||||
<x:String x:Key="Text.Clone.LocalName" xml:space="preserve">Nombre Local:</x:String>
|
||||
<x:String x:Key="Text.Clone.LocalName.Placeholder" xml:space="preserve">Nombre del repositorio. Opcional.</x:String>
|
||||
<x:String x:Key="Text.Clone.ParentFolder" xml:space="preserve">Carpeta Padre:</x:String>
|
||||
@@ -279,8 +282,11 @@
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Label" xml:space="preserve">Etiqueta:</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Options" xml:space="preserve">Opciones:</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Options.Tip" xml:space="preserve">Usar '|' como delimitador para las opciones</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.StringFormatter" xml:space="preserve">Formateador de Cadenas de texto:</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.StringFormatter.Tip" xml:space="preserve">Opcional. Utilizado para formatear la cadena de salida. Ignorado cuando la entrada está vacía. Por favor utiliza `${VALUE}` para representar la cadena de entrada.</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.StringValue.Tip" xml:space="preserve">La variables incorporadas ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE}, y ${TAG} permanecen disponibles aquí</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Type" xml:space="preserve">Tipo:</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.UseFriendlyName" xml:space="preserve">Utilizar Nombre Amigable:</x:String>
|
||||
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Espacios de Trabajo</x:String>
|
||||
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Color</x:String>
|
||||
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">Nombre</x:String>
|
||||
@@ -374,6 +380,7 @@
|
||||
<x:String x:Key="Text.Diff.Submodule" xml:space="preserve">SUBMÓDULO</x:String>
|
||||
<x:String x:Key="Text.Diff.Submodule.Deleted" xml:space="preserve">BORRADO</x:String>
|
||||
<x:String x:Key="Text.Diff.Submodule.New" xml:space="preserve">NUEVO</x:String>
|
||||
<x:String x:Key="Text.Diff.Submodule.UncommittedChanges" xml:space="preserve">+ {0} Cambios Sin confirmar</x:String>
|
||||
<x:String x:Key="Text.Diff.SwapCommits" xml:space="preserve">Intercambiar</x:String>
|
||||
<x:String x:Key="Text.Diff.SyntaxHighlight" xml:space="preserve">Resaltado de Sintaxis</x:String>
|
||||
<x:String x:Key="Text.Diff.ToggleWordWrap" xml:space="preserve">Ajuste de Línea</x:String>
|
||||
@@ -437,7 +444,6 @@
|
||||
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">FLOW - Finalizar Hotfix</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">FLOW - Finalizar Release</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">Destino:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithPush" xml:space="preserve">Push al/los remoto(s) después de Finalizar</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithSquash" xml:space="preserve">Squash durante el merge</x:String>
|
||||
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">Hotfix:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">Prefijo de Hotfix:</x:String>
|
||||
@@ -503,6 +509,7 @@
|
||||
<x:String x:Key="Text.Hotkeys.Global.GotoNextTab" xml:space="preserve">Ir a la siguiente página</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.GotoPrevTab" xml:space="preserve">Ir a la página anterior</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">Crear nueva página</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.OpenLocalRepository" xml:space="preserve">Abrir repositorio local</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.OpenPreferences" xml:space="preserve">Abrir diálogo de preferencias</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.ShowWorkspaceDropdownMenu" xml:space="preserve">Mostrar menú desplegable del espacio de trabajo</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.SwitchTab" xml:space="preserve">Cambiar página activa</x:String>
|
||||
@@ -596,6 +603,10 @@
|
||||
<x:String x:Key="Text.OpenAppDataDir" xml:space="preserve">Abrir Directorio de Datos de la App</x:String>
|
||||
<x:String x:Key="Text.OpenFile" xml:space="preserve">Abrir Archivo</x:String>
|
||||
<x:String x:Key="Text.OpenInExternalMergeTool" xml:space="preserve">Abrir en Herramienta de Merge</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository" xml:space="preserve">Abrir Repositorio Local</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository.Bookmark" xml:space="preserve">Marcador:</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository.Group" xml:space="preserve">Grupo:</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository.Path" xml:space="preserve">Carpeta:</x:String>
|
||||
<x:String x:Key="Text.Optional" xml:space="preserve">Opcional.</x:String>
|
||||
<x:String x:Key="Text.PageTabBar.New" xml:space="preserve">Crear Nueva Página</x:String>
|
||||
<x:String x:Key="Text.PageTabBar.Tab.Close" xml:space="preserve">Cerrar Pestaña</x:String>
|
||||
@@ -902,6 +913,8 @@
|
||||
<x:String x:Key="Text.Submodule.Status.Unmerged" xml:space="preserve">unmerged</x:String>
|
||||
<x:String x:Key="Text.Submodule.Update" xml:space="preserve">Actualizar</x:String>
|
||||
<x:String x:Key="Text.Submodule.URL" xml:space="preserve">URL</x:String>
|
||||
<x:String x:Key="Text.SubmoduleRevisionCompare" xml:space="preserve">Cambiar Detalles del Submódulo</x:String>
|
||||
<x:String x:Key="Text.SubmoduleRevisionCompare.OpenDetails" xml:space="preserve">ABRIR DETALLES</x:String>
|
||||
<x:String x:Key="Text.Sure" xml:space="preserve">OK</x:String>
|
||||
<x:String x:Key="Text.Tag.Tagger" xml:space="preserve">ETIQUETADOR</x:String>
|
||||
<x:String x:Key="Text.Tag.Time" xml:space="preserve">HORA</x:String>
|
||||
|
||||
@@ -409,7 +409,6 @@
|
||||
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">FLOW - Terminer Hotfix</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">FLOW - Terminer Release</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">Cible:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithPush" xml:space="preserve">Pousser vers le(s) dépôt(s) distant(s) après avoir terminé</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithSquash" xml:space="preserve">Squash lors de la fusion</x:String>
|
||||
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">Hotfix:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">Hotfix Prefix:</x:String>
|
||||
|
||||
@@ -390,7 +390,6 @@
|
||||
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">FLOW - Selesaikan Hotfix</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">FLOW - Selesaikan Release</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">Target:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithPush" xml:space="preserve">Push ke remote setelah selesai</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithSquash" xml:space="preserve">Squash saat merge</x:String>
|
||||
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">Hotfix:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">Prefix Hotfix:</x:String>
|
||||
|
||||
@@ -424,7 +424,6 @@ ${pure_files:N} Come ${files:N}, ma senza cartelle</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">FLOW - Completa Hotfix</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">FLOW - Completa Rilascio</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">Target:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithPush" xml:space="preserve">Invia al remote dopo aver finito</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithSquash" xml:space="preserve">Esegui squash durante il merge</x:String>
|
||||
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">Hotfix:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">Prefisso Hotfix:</x:String>
|
||||
|
||||
@@ -425,7 +425,6 @@
|
||||
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">フロー - 緊急のバグ修正を完了</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">フロー - リリース作業を完了</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">対象:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithPush" xml:space="preserve">コミットの完了後、リモートにプッシュ</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithSquash" xml:space="preserve">スカッシュしてマージ</x:String>
|
||||
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">緊急のバグ修正:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">緊急のバグ修正用のプレフィックス:</x:String>
|
||||
|
||||
@@ -392,7 +392,6 @@
|
||||
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">FLOW - Hotfix 완료</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">FLOW - Release 완료</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">대상:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithPush" xml:space="preserve">완료 후 원격(들)에 푸시</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithSquash" xml:space="preserve">병합 시 스쿼시</x:String>
|
||||
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">핫픽스:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">Hotfix 접두사:</x:String>
|
||||
|
||||
@@ -437,7 +437,6 @@
|
||||
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">ПРОЦЕСС - Закончить исправление</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">ПРОЦЕСС - Завершить выпуск</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">Цель:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithPush" xml:space="preserve">Выложить на удалённый(ые) после завершения</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithSquash" xml:space="preserve">Втиснуть при слиянии</x:String>
|
||||
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">Исправление:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">Префикс исправлений:</x:String>
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
<x:String x:Key="Text.AIAssistant.Tip" xml:space="preserve">使用AI助手生成提交信息</x:String>
|
||||
<x:String x:Key="Text.AIAssistant.Use" xml:space="preserve">应用所选</x:String>
|
||||
<x:String x:Key="Text.App.Hide" xml:space="preserve">隐藏 SourceGit</x:String>
|
||||
<x:String x:Key="Text.App.ShowAll" xml:space="preserve">显示所有窗口</x:String>
|
||||
<x:String x:Key="Text.App.HideOthers" xml:space="preserve">隐藏其他</x:String>
|
||||
<x:String x:Key="Text.App.ShowAll" xml:space="preserve">显示全部</x:String>
|
||||
<x:String x:Key="Text.Apply" xml:space="preserve">应用补丁(apply)</x:String>
|
||||
<x:String x:Key="Text.Apply.3Way" xml:space="preserve">尝试三路合并</x:String>
|
||||
<x:String x:Key="Text.Apply.File" xml:space="preserve">补丁文件 :</x:String>
|
||||
@@ -134,6 +135,8 @@
|
||||
<x:String x:Key="Text.Clone" xml:space="preserve">克隆远程仓库</x:String>
|
||||
<x:String x:Key="Text.Clone.AdditionalParam" xml:space="preserve">额外参数 :</x:String>
|
||||
<x:String x:Key="Text.Clone.AdditionalParam.Placeholder" xml:space="preserve">其他克隆参数,选填。</x:String>
|
||||
<x:String x:Key="Text.Clone.Bookmark" xml:space="preserve">书签 :</x:String>
|
||||
<x:String x:Key="Text.Clone.Group" xml:space="preserve">自定义分组 :</x:String>
|
||||
<x:String x:Key="Text.Clone.LocalName" xml:space="preserve">本地仓库名 :</x:String>
|
||||
<x:String x:Key="Text.Clone.LocalName.Placeholder" xml:space="preserve">本地仓库目录的名字,选填。</x:String>
|
||||
<x:String x:Key="Text.Clone.ParentFolder" xml:space="preserve">父级目录 :</x:String>
|
||||
@@ -279,8 +282,11 @@
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Label" xml:space="preserve">名称 :</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Options" xml:space="preserve">选项列表 :</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Options.Tip" xml:space="preserve">选项之间请使用英文 '|' 作为分隔符</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.StringFormatter" xml:space="preserve">输出内容格式化字串:</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.StringFormatter.Tip" xml:space="preserve">可选。用于格式化输出结果。当用户输入为空时忽略该操作。请使用`${VALUE}`代替用户输入。 </x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.StringValue.Tip" xml:space="preserve">内置变量 ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE} 与 ${TAG} 在这里仍然可用</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Type" xml:space="preserve">类型 :</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.UseFriendlyName" xml:space="preserve">输出结果带有远程名:</x:String>
|
||||
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">工作区</x:String>
|
||||
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">颜色</x:String>
|
||||
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">名称</x:String>
|
||||
@@ -374,6 +380,7 @@
|
||||
<x:String x:Key="Text.Diff.Submodule" xml:space="preserve">子模块</x:String>
|
||||
<x:String x:Key="Text.Diff.Submodule.Deleted" xml:space="preserve">删除</x:String>
|
||||
<x:String x:Key="Text.Diff.Submodule.New" xml:space="preserve">新增</x:String>
|
||||
<x:String x:Key="Text.Diff.Submodule.UncommittedChanges" xml:space="preserve">+ {0} 项未提交变更</x:String>
|
||||
<x:String x:Key="Text.Diff.SwapCommits" xml:space="preserve">交换比对双方</x:String>
|
||||
<x:String x:Key="Text.Diff.SyntaxHighlight" xml:space="preserve">语法高亮</x:String>
|
||||
<x:String x:Key="Text.Diff.ToggleWordWrap" xml:space="preserve">自动换行</x:String>
|
||||
@@ -437,7 +444,6 @@
|
||||
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">结束修复分支</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">结束版本分支</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">目标分支 :</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithPush" xml:space="preserve">完成后自动推送</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithSquash" xml:space="preserve">压缩变更为单一提交后合并分支</x:String>
|
||||
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">修复分支 :</x:String>
|
||||
<x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">修复分支名前缀 :</x:String>
|
||||
@@ -503,6 +509,7 @@
|
||||
<x:String x:Key="Text.Hotkeys.Global.GotoNextTab" xml:space="preserve">切换到下一个页面</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.GotoPrevTab" xml:space="preserve">切换到上一个页面</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">新建页面</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.OpenLocalRepository" xml:space="preserve">打开本地仓库</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.OpenPreferences" xml:space="preserve">打开偏好设置面板</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.ShowWorkspaceDropdownMenu" xml:space="preserve">显示工作区下拉菜单</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.SwitchTab" xml:space="preserve">切换显示页面</x:String>
|
||||
@@ -596,6 +603,10 @@
|
||||
<x:String x:Key="Text.OpenAppDataDir" xml:space="preserve">浏览应用数据目录</x:String>
|
||||
<x:String x:Key="Text.OpenFile" xml:space="preserve">打开文件</x:String>
|
||||
<x:String x:Key="Text.OpenInExternalMergeTool" xml:space="preserve">使用外部对比工具查看</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository" xml:space="preserve">打开本地仓库</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository.Bookmark" xml:space="preserve">书签 :</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository.Group" xml:space="preserve">分组 :</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository.Path" xml:space="preserve">仓库位置 :</x:String>
|
||||
<x:String x:Key="Text.Optional" xml:space="preserve">选填。</x:String>
|
||||
<x:String x:Key="Text.PageTabBar.New" xml:space="preserve">新建空白页</x:String>
|
||||
<x:String x:Key="Text.PageTabBar.Tab.Close" xml:space="preserve">关闭标签页</x:String>
|
||||
@@ -902,6 +913,8 @@
|
||||
<x:String x:Key="Text.Submodule.Status.Unmerged" xml:space="preserve">未解决冲突</x:String>
|
||||
<x:String x:Key="Text.Submodule.Update" xml:space="preserve">更新</x:String>
|
||||
<x:String x:Key="Text.Submodule.URL" xml:space="preserve">仓库</x:String>
|
||||
<x:String x:Key="Text.SubmoduleRevisionCompare" xml:space="preserve">子模块变更详情</x:String>
|
||||
<x:String x:Key="Text.SubmoduleRevisionCompare.OpenDetails" xml:space="preserve">查看变更详情</x:String>
|
||||
<x:String x:Key="Text.Sure" xml:space="preserve">确 定</x:String>
|
||||
<x:String x:Key="Text.Tag.Tagger" xml:space="preserve">创建者</x:String>
|
||||
<x:String x:Key="Text.Tag.Time" xml:space="preserve">创建时间</x:String>
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
<x:String x:Key="Text.AIAssistant.Tip" xml:space="preserve">使用 AI 產生提交訊息</x:String>
|
||||
<x:String x:Key="Text.AIAssistant.Use" xml:space="preserve">套用選取</x:String>
|
||||
<x:String x:Key="Text.App.Hide" xml:space="preserve">隱藏 SourceGit</x:String>
|
||||
<x:String x:Key="Text.App.ShowAll" xml:space="preserve">顯示所有</x:String>
|
||||
<x:String x:Key="Text.App.HideOthers" xml:space="preserve">隱藏其他</x:String>
|
||||
<x:String x:Key="Text.App.ShowAll" xml:space="preserve">顯示全部</x:String>
|
||||
<x:String x:Key="Text.Apply" xml:space="preserve">套用修補檔 (apply patch)</x:String>
|
||||
<x:String x:Key="Text.Apply.3Way" xml:space="preserve">嘗試三向合併</x:String>
|
||||
<x:String x:Key="Text.Apply.File" xml:space="preserve">修補檔:</x:String>
|
||||
@@ -134,6 +135,8 @@
|
||||
<x:String x:Key="Text.Clone" xml:space="preserve">複製 (clone) 遠端存放庫</x:String>
|
||||
<x:String x:Key="Text.Clone.AdditionalParam" xml:space="preserve">額外參數:</x:String>
|
||||
<x:String x:Key="Text.Clone.AdditionalParam.Placeholder" xml:space="preserve">其他複製參數,選填。</x:String>
|
||||
<x:String x:Key="Text.Clone.Bookmark" xml:space="preserve">書籤:</x:String>
|
||||
<x:String x:Key="Text.Clone.Group" xml:space="preserve">群組:</x:String>
|
||||
<x:String x:Key="Text.Clone.LocalName" xml:space="preserve">本機存放庫名稱:</x:String>
|
||||
<x:String x:Key="Text.Clone.LocalName.Placeholder" xml:space="preserve">本機存放庫目錄的名稱,選填。</x:String>
|
||||
<x:String x:Key="Text.Clone.ParentFolder" xml:space="preserve">上層目錄:</x:String>
|
||||
@@ -279,8 +282,11 @@
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Label" xml:space="preserve">名稱:</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Options" xml:space="preserve">選項列表:</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Options.Tip" xml:space="preserve">請使用英文「|」符號分隔選項</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.StringFormatter" xml:space="preserve">字串格式化器:</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.StringFormatter.Tip" xml:space="preserve">可選。用於格式化輸出字串。當輸入為空時將被忽略。請使用 `${VALUE}` 來表示輸入字串。</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.StringValue.Tip" xml:space="preserve">內建變數 ${REPO}、${REMOTE}、${BRANCH}、${BRANCH_FRIENDLY_NAME}、${SHA}、${FILE} 及 ${TAG} 在此處仍可使用</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.Type" xml:space="preserve">類型:</x:String>
|
||||
<x:String x:Key="Text.ConfigureCustomActionControls.UseFriendlyName" xml:space="preserve">輸出包含遠端的名稱:</x:String>
|
||||
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">工作區</x:String>
|
||||
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">顏色</x:String>
|
||||
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">名稱</x:String>
|
||||
@@ -374,6 +380,7 @@
|
||||
<x:String x:Key="Text.Diff.Submodule" xml:space="preserve">子模組</x:String>
|
||||
<x:String x:Key="Text.Diff.Submodule.Deleted" xml:space="preserve">已刪除</x:String>
|
||||
<x:String x:Key="Text.Diff.Submodule.New" xml:space="preserve">新增</x:String>
|
||||
<x:String x:Key="Text.Diff.Submodule.UncommittedChanges" xml:space="preserve">+ {0} 項未提交變更</x:String>
|
||||
<x:String x:Key="Text.Diff.SwapCommits" xml:space="preserve">交換比對雙方</x:String>
|
||||
<x:String x:Key="Text.Diff.SyntaxHighlight" xml:space="preserve">語法上色</x:String>
|
||||
<x:String x:Key="Text.Diff.ToggleWordWrap" xml:space="preserve">自動換行</x:String>
|
||||
@@ -437,7 +444,6 @@
|
||||
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">完成修復分支</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">完成發行分支</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">目標分支:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithPush" xml:space="preserve">完成後自動推送</x:String>
|
||||
<x:String x:Key="Text.GitFlow.FinishWithSquash" xml:space="preserve">壓縮為單一提交後合併</x:String>
|
||||
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">修復分支:</x:String>
|
||||
<x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">修復分支前置詞:</x:String>
|
||||
@@ -503,6 +509,7 @@
|
||||
<x:String x:Key="Text.Hotkeys.Global.GotoNextTab" xml:space="preserve">切換到下一個頁面</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.GotoPrevTab" xml:space="preserve">切換到上一個頁面</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">新增頁面</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.OpenLocalRepository" xml:space="preserve">開啟本機存放庫</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.OpenPreferences" xml:space="preserve">開啟偏好設定面板</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.ShowWorkspaceDropdownMenu" xml:space="preserve">顯示工作區的下拉式選單</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.SwitchTab" xml:space="preserve">切換目前頁面</x:String>
|
||||
@@ -596,6 +603,10 @@
|
||||
<x:String x:Key="Text.OpenAppDataDir" xml:space="preserve">瀏覽程式資料目錄</x:String>
|
||||
<x:String x:Key="Text.OpenFile" xml:space="preserve">開啟檔案</x:String>
|
||||
<x:String x:Key="Text.OpenInExternalMergeTool" xml:space="preserve">使用外部比對工具檢視</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository" xml:space="preserve">開啟本機存放庫</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository.Bookmark" xml:space="preserve">書籤:</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository.Group" xml:space="preserve">群組:</x:String>
|
||||
<x:String x:Key="Text.OpenLocalRepository.Path" xml:space="preserve">存放庫位置:</x:String>
|
||||
<x:String x:Key="Text.Optional" xml:space="preserve">選填。</x:String>
|
||||
<x:String x:Key="Text.PageTabBar.New" xml:space="preserve">新增分頁</x:String>
|
||||
<x:String x:Key="Text.PageTabBar.Tab.Close" xml:space="preserve">關閉分頁</x:String>
|
||||
@@ -902,6 +913,8 @@
|
||||
<x:String x:Key="Text.Submodule.Status.Unmerged" xml:space="preserve">未解決的衝突</x:String>
|
||||
<x:String x:Key="Text.Submodule.Update" xml:space="preserve">更新</x:String>
|
||||
<x:String x:Key="Text.Submodule.URL" xml:space="preserve">存放庫</x:String>
|
||||
<x:String x:Key="Text.SubmoduleRevisionCompare" xml:space="preserve">子模組變更詳細資訊</x:String>
|
||||
<x:String x:Key="Text.SubmoduleRevisionCompare.OpenDetails" xml:space="preserve">開啟變更詳細資訊</x:String>
|
||||
<x:String x:Key="Text.Sure" xml:space="preserve">確 定</x:String>
|
||||
<x:String x:Key="Text.Tag.Tagger" xml:space="preserve">建立者</x:String>
|
||||
<x:String x:Key="Text.Tag.Time" xml:space="preserve">建立時間</x:String>
|
||||
|
||||
@@ -65,14 +65,12 @@ namespace SourceGit.ViewModels
|
||||
Filter = string.Empty;
|
||||
}
|
||||
|
||||
public void Launch()
|
||||
public Blame Launch()
|
||||
{
|
||||
_repoFiles.Clear();
|
||||
_visibleFiles.Clear();
|
||||
Close();
|
||||
|
||||
if (!string.IsNullOrEmpty(_selectedFile))
|
||||
App.ShowWindow(new Blame(_repo, _selectedFile, _head));
|
||||
return !string.IsNullOrEmpty(_selectedFile) ? new Blame(_repo, _selectedFile, _head) : null;
|
||||
}
|
||||
|
||||
private void UpdateVisible()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
@@ -45,6 +46,28 @@ namespace SourceGit.ViewModels
|
||||
set => SetProperty(ref _local, value);
|
||||
}
|
||||
|
||||
public List<RepositoryNode> Groups
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public RepositoryNode SelectedGroup
|
||||
{
|
||||
get => _selectedGroup;
|
||||
set => SetProperty(ref _selectedGroup, value);
|
||||
}
|
||||
|
||||
public List<int> Bookmarks
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public int Bookmark
|
||||
{
|
||||
get => _bookmark;
|
||||
set => SetProperty(ref _bookmark, value);
|
||||
}
|
||||
|
||||
public string ExtraArgs
|
||||
{
|
||||
get => _extraArgs;
|
||||
@@ -61,6 +84,15 @@ namespace SourceGit.ViewModels
|
||||
{
|
||||
_pageId = pageId;
|
||||
|
||||
Groups = new List<RepositoryNode>();
|
||||
Groups.Add(new RepositoryNode { Name = "No Group (Uncategorized)", Id = string.Empty });
|
||||
SelectedGroup = Groups[0];
|
||||
CollectGroups(Groups, Preferences.Instance.RepositoryNodes);
|
||||
|
||||
Bookmarks = new List<int>();
|
||||
for (var i = 0; i < Models.Bookmarks.Brushes.Length; i++)
|
||||
Bookmarks.Add(i);
|
||||
|
||||
var activeWorkspace = Preferences.Instance.GetActiveWorkspace();
|
||||
_parentFolder = activeWorkspace?.DefaultCloneDir;
|
||||
if (string.IsNullOrEmpty(ParentFolder))
|
||||
@@ -134,7 +166,9 @@ namespace SourceGit.ViewModels
|
||||
|
||||
log.Complete();
|
||||
|
||||
var node = Preferences.Instance.FindOrAddNodeByRepositoryPath(path, null, true);
|
||||
var parent = _selectedGroup is { Id: not "" } ? _selectedGroup : null;
|
||||
var node = Preferences.Instance.FindOrAddNodeByRepositoryPath(path, parent, true);
|
||||
node.Bookmark = _bookmark;
|
||||
await node.UpdateStatusAsync(false, null);
|
||||
|
||||
var launcher = App.GetLauncher();
|
||||
@@ -153,6 +187,18 @@ namespace SourceGit.ViewModels
|
||||
return true;
|
||||
}
|
||||
|
||||
private void CollectGroups(List<RepositoryNode> outs, List<RepositoryNode> collections)
|
||||
{
|
||||
foreach (var node in collections)
|
||||
{
|
||||
if (!node.IsRepository)
|
||||
{
|
||||
outs.Add(node);
|
||||
CollectGroups(outs, node.SubNodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _pageId = string.Empty;
|
||||
private string _remote = string.Empty;
|
||||
private bool _useSSH = false;
|
||||
@@ -160,5 +206,7 @@ namespace SourceGit.ViewModels
|
||||
private string _parentFolder = string.Empty;
|
||||
private string _local = string.Empty;
|
||||
private string _extraArgs = string.Empty;
|
||||
private RepositoryNode _selectedGroup = null;
|
||||
private int _bookmark = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,13 +44,11 @@ namespace SourceGit.ViewModels
|
||||
Filter = string.Empty;
|
||||
}
|
||||
|
||||
public void Launch()
|
||||
public Compare Launch()
|
||||
{
|
||||
_refs.Clear();
|
||||
Close();
|
||||
|
||||
if (_compareTo != null)
|
||||
App.ShowWindow(new Compare(_repo, _basedOn, _compareTo));
|
||||
return _compareTo != null ? new Compare(_repo, _basedOn, _compareTo) : null;
|
||||
}
|
||||
|
||||
private void UpdateRefs()
|
||||
|
||||
@@ -73,10 +73,9 @@ namespace SourceGit.ViewModels
|
||||
await _wc.UseMineAsync([_change]);
|
||||
}
|
||||
|
||||
public async Task MergeAsync()
|
||||
public MergeConflictEditor CreateOpenMergeEditorRequest()
|
||||
{
|
||||
if (CanMerge)
|
||||
await App.ShowDialog(new MergeConflictEditor(_repo, _head, _change.Path));
|
||||
return CanMerge ? new MergeConflictEditor(_repo, _head, _change.Path) : null;
|
||||
}
|
||||
|
||||
public async Task MergeExternalAsync()
|
||||
|
||||
@@ -190,7 +190,10 @@ namespace SourceGit.ViewModels
|
||||
}
|
||||
|
||||
if (isSubmodule)
|
||||
{
|
||||
submoduleDiff.FullPath = submoduleRoot;
|
||||
rs = submoduleDiff;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isSubmodule)
|
||||
@@ -288,6 +291,16 @@ namespace SourceGit.ViewModels
|
||||
|
||||
private async Task<Models.RevisionSubmodule> QuerySubmoduleRevisionAsync(string repo, string sha)
|
||||
{
|
||||
if (!File.Exists(Path.Combine(repo, ".git")))
|
||||
return new Models.RevisionSubmodule() { Commit = new Models.Commit() { SHA = sha } };
|
||||
|
||||
var uncommittedChangesCount = 0;
|
||||
if (sha.EndsWith("-dirty", StringComparison.Ordinal))
|
||||
{
|
||||
sha = sha.Substring(0, sha.Length - 6);
|
||||
uncommittedChangesCount = await new Commands.CountLocalChanges(repo, true).GetResultAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var commit = await new Commands.QuerySingleCommit(repo, sha).GetResultAsync().ConfigureAwait(false);
|
||||
if (commit == null)
|
||||
return new Models.RevisionSubmodule() { Commit = new Models.Commit() { SHA = sha } };
|
||||
@@ -296,7 +309,8 @@ namespace SourceGit.ViewModels
|
||||
return new Models.RevisionSubmodule()
|
||||
{
|
||||
Commit = commit,
|
||||
FullMessage = new Models.CommitFullMessage { Message = body }
|
||||
FullMessage = new Models.CommitFullMessage { Message = body },
|
||||
UncommittedChanges = uncommittedChangesCount
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -18,15 +18,22 @@ namespace SourceGit.ViewModels
|
||||
public string Label { get; set; }
|
||||
public string Placeholder { get; set; }
|
||||
public string Text { get; set; }
|
||||
public string Formatter { get; set; }
|
||||
|
||||
public CustomActionControlTextBox(string label, string placeholder, string defaultValue)
|
||||
public CustomActionControlTextBox(string label, string placeholder, string defaultValue, string formatter)
|
||||
{
|
||||
Label = label + ":";
|
||||
Placeholder = placeholder;
|
||||
Text = defaultValue;
|
||||
Formatter = formatter;
|
||||
}
|
||||
|
||||
public string GetValue() => Text;
|
||||
public string GetValue()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Text))
|
||||
return string.Empty;
|
||||
return string.IsNullOrEmpty(Formatter) ? Text : Formatter.Replace("${VALUE}", Text);
|
||||
}
|
||||
}
|
||||
|
||||
public class CustomActionControlPathSelector : ObservableObject, ICustomActionControlParameter
|
||||
@@ -77,12 +84,7 @@ namespace SourceGit.ViewModels
|
||||
public string Label { get; set; }
|
||||
public string Description { get; set; }
|
||||
public List<string> Options { get; set; } = [];
|
||||
|
||||
public string Value
|
||||
{
|
||||
get => _value;
|
||||
set => SetProperty(ref _value, value);
|
||||
}
|
||||
public string Value { get; set; }
|
||||
|
||||
public CustomActionControlComboBox(string label, string description, string options)
|
||||
{
|
||||
@@ -93,13 +95,45 @@ namespace SourceGit.ViewModels
|
||||
if (parts.Length > 0)
|
||||
{
|
||||
Options.AddRange(parts);
|
||||
_value = parts[0];
|
||||
Value = parts[0];
|
||||
}
|
||||
}
|
||||
|
||||
public string GetValue() => _value;
|
||||
public string GetValue() => Value;
|
||||
}
|
||||
|
||||
private string _value = string.Empty;
|
||||
public class CustomActionControlBranchSelector : ObservableObject, ICustomActionControlParameter
|
||||
{
|
||||
public string Label { get; set; }
|
||||
public string Description { get; set; }
|
||||
public List<Models.Branch> Branches { get; set; } = [];
|
||||
public Models.Branch SelectedBranch { get; set; }
|
||||
|
||||
public CustomActionControlBranchSelector(string label, string description, Repository repo, bool isLocal, bool useFriendlyName)
|
||||
{
|
||||
Label = label;
|
||||
Description = description;
|
||||
_useFriendlyName = useFriendlyName;
|
||||
|
||||
foreach (var b in repo.Branches)
|
||||
{
|
||||
if (b.IsLocal == isLocal && !b.IsDetachedHead)
|
||||
Branches.Add(b);
|
||||
}
|
||||
|
||||
if (Branches.Count > 0)
|
||||
SelectedBranch = Branches[0];
|
||||
}
|
||||
|
||||
public string GetValue()
|
||||
{
|
||||
if (SelectedBranch == null)
|
||||
return string.Empty;
|
||||
|
||||
return _useFriendlyName ? SelectedBranch.FriendlyName : SelectedBranch.Name;
|
||||
}
|
||||
|
||||
private bool _useFriendlyName = false;
|
||||
}
|
||||
|
||||
public class ExecuteCustomAction : Popup
|
||||
@@ -124,7 +158,31 @@ namespace SourceGit.ViewModels
|
||||
_repo = repo;
|
||||
CustomAction = action;
|
||||
Target = scopeTarget ?? new Models.Null();
|
||||
PrepareControlParameters();
|
||||
|
||||
foreach (var ctl in CustomAction.Controls)
|
||||
{
|
||||
switch (ctl.Type)
|
||||
{
|
||||
case Models.CustomActionControlType.TextBox:
|
||||
ControlParameters.Add(new CustomActionControlTextBox(ctl.Label, ctl.Description, PrepareStringByTarget(ctl.StringValue), ctl.StringFormatter));
|
||||
break;
|
||||
case Models.CustomActionControlType.PathSelector:
|
||||
ControlParameters.Add(new CustomActionControlPathSelector(ctl.Label, ctl.Description, ctl.BoolValue, PrepareStringByTarget(ctl.StringValue)));
|
||||
break;
|
||||
case Models.CustomActionControlType.CheckBox:
|
||||
ControlParameters.Add(new CustomActionControlCheckBox(ctl.Label, ctl.Description, ctl.StringValue, ctl.BoolValue));
|
||||
break;
|
||||
case Models.CustomActionControlType.ComboBox:
|
||||
ControlParameters.Add(new CustomActionControlComboBox(ctl.Label, ctl.Description, PrepareStringByTarget(ctl.StringValue)));
|
||||
break;
|
||||
case Models.CustomActionControlType.LocalBranchSelector:
|
||||
ControlParameters.Add(new CustomActionControlBranchSelector(ctl.Label, ctl.Description, _repo, true, false));
|
||||
break;
|
||||
case Models.CustomActionControlType.RemoteBranchSelector:
|
||||
ControlParameters.Add(new CustomActionControlBranchSelector(ctl.Label, ctl.Description, _repo, false, ctl.BoolValue));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<bool> Sure()
|
||||
@@ -153,31 +211,10 @@ namespace SourceGit.ViewModels
|
||||
return true;
|
||||
}
|
||||
|
||||
private void PrepareControlParameters()
|
||||
{
|
||||
foreach (var ctl in CustomAction.Controls)
|
||||
{
|
||||
switch (ctl.Type)
|
||||
{
|
||||
case Models.CustomActionControlType.TextBox:
|
||||
ControlParameters.Add(new CustomActionControlTextBox(ctl.Label, ctl.Description, PrepareStringByTarget(ctl.StringValue)));
|
||||
break;
|
||||
case Models.CustomActionControlType.PathSelector:
|
||||
ControlParameters.Add(new CustomActionControlPathSelector(ctl.Label, ctl.Description, ctl.BoolValue, PrepareStringByTarget(ctl.StringValue)));
|
||||
break;
|
||||
case Models.CustomActionControlType.CheckBox:
|
||||
ControlParameters.Add(new CustomActionControlCheckBox(ctl.Label, ctl.Description, ctl.StringValue, ctl.BoolValue));
|
||||
break;
|
||||
case Models.CustomActionControlType.ComboBox:
|
||||
ControlParameters.Add(new CustomActionControlComboBox(ctl.Label, ctl.Description, PrepareStringByTarget(ctl.StringValue)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string PrepareStringByTarget(string org)
|
||||
{
|
||||
org = org.Replace("${REPO}", GetWorkdir());
|
||||
var repoPath = OperatingSystem.IsWindows() ? _repo.FullPath.Replace("/", "\\") : _repo.FullPath;
|
||||
org = org.Replace("${REPO}", repoPath);
|
||||
|
||||
return Target switch
|
||||
{
|
||||
@@ -186,15 +223,10 @@ namespace SourceGit.ViewModels
|
||||
Models.Tag t => org.Replace("${TAG}", t.Name),
|
||||
Models.Remote r => org.Replace("${REMOTE}", r.Name),
|
||||
Models.CustomActionTargetFile f => org.Replace("${FILE}", f.File).Replace("${SHA}", f.Revision?.SHA ?? string.Empty),
|
||||
_ => org
|
||||
_ => org.Replace("${BRANCH}", _repo.CurrentBranch?.Name ?? "HEAD")
|
||||
};
|
||||
}
|
||||
|
||||
private string GetWorkdir()
|
||||
{
|
||||
return OperatingSystem.IsWindows() ? _repo.FullPath.Replace("/", "\\") : _repo.FullPath;
|
||||
}
|
||||
|
||||
private void Run(string args)
|
||||
{
|
||||
var start = new ProcessStartInfo();
|
||||
|
||||
@@ -60,14 +60,12 @@ namespace SourceGit.ViewModels
|
||||
Filter = string.Empty;
|
||||
}
|
||||
|
||||
public void Launch()
|
||||
public FileHistories Launch()
|
||||
{
|
||||
_repoFiles.Clear();
|
||||
_visibleFiles.Clear();
|
||||
Close();
|
||||
|
||||
if (!string.IsNullOrEmpty(_selectedFile))
|
||||
App.ShowWindow(new FileHistories(_repo, _selectedFile));
|
||||
return !string.IsNullOrEmpty(_selectedFile) ? new FileHistories(_repo, _selectedFile) : null;
|
||||
}
|
||||
|
||||
private void UpdateVisible()
|
||||
|
||||
@@ -21,12 +21,6 @@ namespace SourceGit.ViewModels
|
||||
set;
|
||||
} = false;
|
||||
|
||||
public bool AutoPush
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = false;
|
||||
|
||||
public bool KeepBranch
|
||||
{
|
||||
get;
|
||||
@@ -50,7 +44,7 @@ namespace SourceGit.ViewModels
|
||||
|
||||
var prefix = _repo.GitFlow.GetPrefix(Type);
|
||||
var name = Branch.Name.StartsWith(prefix) ? Branch.Name.Substring(prefix.Length) : Branch.Name;
|
||||
var succ = await Commands.GitFlow.FinishAsync(_repo.FullPath, Type, name, Squash, AutoPush, KeepBranch, log);
|
||||
var succ = await Commands.GitFlow.FinishAsync(_repo.FullPath, Type, name, Squash, KeepBranch, log);
|
||||
|
||||
log.Complete();
|
||||
return succ;
|
||||
|
||||
@@ -418,22 +418,6 @@ namespace SourceGit.ViewModels
|
||||
_repo.ShowPopup(new DropHead(_repo, head, parent));
|
||||
}
|
||||
|
||||
public async Task InteractiveRebaseAsync(Models.Commit commit, Models.InteractiveRebaseAction act)
|
||||
{
|
||||
var prefill = new InteractiveRebasePrefill(commit.SHA, act);
|
||||
var start = act switch
|
||||
{
|
||||
Models.InteractiveRebaseAction.Squash or Models.InteractiveRebaseAction.Fixup => $"{commit.SHA}~~",
|
||||
_ => $"{commit.SHA}~",
|
||||
};
|
||||
|
||||
var on = await new Commands.QuerySingleCommit(_repo.FullPath, start).GetResultAsync();
|
||||
if (on == null)
|
||||
_repo.SendNotification($"Can not squash current commit into parent!", true);
|
||||
else
|
||||
await App.ShowDialog(new InteractiveRebase(_repo, on, prefill));
|
||||
}
|
||||
|
||||
public async Task<string> GetCommitFullMessageAsync(Models.Commit commit)
|
||||
{
|
||||
return await new Commands.QueryCommitFullMessage(_repo.FullPath, commit.SHA)
|
||||
|
||||
@@ -13,6 +13,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
||||
namespace SourceGit.ViewModels
|
||||
{
|
||||
public record InteractiveRebasePrefill(string SHA, Models.InteractiveRebaseAction Action);
|
||||
public record InteractiveRebaseReorderItem(string Key, InteractiveRebaseItem Item);
|
||||
|
||||
public class InteractiveRebaseItem : ObservableObject
|
||||
{
|
||||
@@ -172,10 +173,57 @@ namespace SourceGit.ViewModels
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var list = new List<InteractiveRebaseItem>();
|
||||
var needReorder = new List<InteractiveRebaseReorderItem>();
|
||||
for (var i = 0; i < commits.Count; i++)
|
||||
{
|
||||
var c = commits[i];
|
||||
list.Add(new InteractiveRebaseItem(commits.Count - i, c.Commit, c.Message));
|
||||
var item = new InteractiveRebaseItem(commits.Count - i, c.Commit, c.Message);
|
||||
var subject = c.Commit.Subject;
|
||||
|
||||
if (item.OriginalOrder > 1)
|
||||
{
|
||||
if (subject.StartsWith("fixup! ", StringComparison.Ordinal))
|
||||
{
|
||||
item.Action = Models.InteractiveRebaseAction.Fixup;
|
||||
needReorder.Add(new(subject.Substring(7), item));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (subject.StartsWith("squash! ", StringComparison.Ordinal))
|
||||
{
|
||||
item.Action = Models.InteractiveRebaseAction.Squash;
|
||||
needReorder.Add(new(subject.Substring(8), item));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var reordered = new List<InteractiveRebaseReorderItem>();
|
||||
foreach (var o in needReorder)
|
||||
{
|
||||
if (subject.StartsWith(o.Key, StringComparison.Ordinal))
|
||||
{
|
||||
list.Add(o.Item);
|
||||
reordered.Add(o);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var k in reordered)
|
||||
needReorder.Remove(k);
|
||||
|
||||
list.Add(item);
|
||||
}
|
||||
|
||||
foreach (var v in needReorder)
|
||||
{
|
||||
for (var i = 0; i < list.Count; i++)
|
||||
{
|
||||
if (v.Item.OriginalOrder > list[i].OriginalOrder)
|
||||
{
|
||||
v.Item.Action = Models.InteractiveRebaseAction.Pick; // For safety, reset to pick if the target commit is not found
|
||||
list.Insert(i, v.Item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var selected = list.Count > 0 ? list[0] : null;
|
||||
@@ -363,7 +411,18 @@ namespace SourceGit.ViewModels
|
||||
item.IsMessageUserEdited = false;
|
||||
|
||||
if (item.Action == Models.InteractiveRebaseAction.Squash)
|
||||
pendingMessages.Add(item.OriginalFullMessage);
|
||||
{
|
||||
if (item.OriginalFullMessage.StartsWith("squash! ", StringComparison.Ordinal))
|
||||
{
|
||||
var firstLineEnd = item.OriginalFullMessage.IndexOf('\n');
|
||||
if (firstLineEnd > 0)
|
||||
pendingMessages.Add(item.OriginalFullMessage.Substring(firstLineEnd + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
pendingMessages.Add(item.OriginalFullMessage);
|
||||
}
|
||||
}
|
||||
|
||||
hasPending = true;
|
||||
continue;
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace SourceGit.ViewModels
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Quit()
|
||||
public void CloseAll()
|
||||
{
|
||||
_ignoreIndexChange = true;
|
||||
|
||||
|
||||
115
src/ViewModels/OpenLocalRepository.cs
Normal file
115
src/ViewModels/OpenLocalRepository.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SourceGit.ViewModels
|
||||
{
|
||||
public class OpenLocalRepository : Popup
|
||||
{
|
||||
[Required(ErrorMessage = "Repository folder is required")]
|
||||
[CustomValidation(typeof(OpenLocalRepository), nameof(ValidateRepoPath))]
|
||||
public string RepoPath
|
||||
{
|
||||
get => _repoPath;
|
||||
set => SetProperty(ref _repoPath, value, true);
|
||||
}
|
||||
|
||||
public List<RepositoryNode> Groups
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public RepositoryNode Group
|
||||
{
|
||||
get => _group;
|
||||
set => SetProperty(ref _group, value);
|
||||
}
|
||||
|
||||
public List<int> Bookmarks
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public int Bookmark
|
||||
{
|
||||
get => _bookmark;
|
||||
set => SetProperty(ref _bookmark, value);
|
||||
}
|
||||
|
||||
public OpenLocalRepository(string pageId, RepositoryNode group)
|
||||
{
|
||||
_pageId = pageId;
|
||||
|
||||
Groups = new List<RepositoryNode>();
|
||||
Groups.Add(new RepositoryNode { Name = "No Group (Uncategorized)", Id = string.Empty });
|
||||
Group = group ?? Groups[0];
|
||||
CollectGroups(Groups, Preferences.Instance.RepositoryNodes);
|
||||
|
||||
Bookmarks = new List<int>();
|
||||
for (var i = 0; i < Models.Bookmarks.Brushes.Length; i++)
|
||||
Bookmarks.Add(i);
|
||||
}
|
||||
|
||||
public static ValidationResult ValidateRepoPath(string folder, ValidationContext _)
|
||||
{
|
||||
if (!Directory.Exists(folder))
|
||||
return new ValidationResult("Given path can NOT be found");
|
||||
return ValidationResult.Success;
|
||||
}
|
||||
|
||||
public override async Task<bool> Sure()
|
||||
{
|
||||
var isBare = await new Commands.IsBareRepository(_repoPath).GetResultAsync();
|
||||
var parent = _group is { Id: not "" } ? _group : null;
|
||||
var repoRoot = _repoPath;
|
||||
if (!isBare)
|
||||
{
|
||||
var test = await new Commands.QueryRepositoryRootPath(_repoPath).GetResultAsync();
|
||||
if (test.IsSuccess && !string.IsNullOrWhiteSpace(test.StdOut))
|
||||
{
|
||||
repoRoot = test.StdOut.Trim();
|
||||
}
|
||||
else
|
||||
{
|
||||
var launcher = App.GetLauncher();
|
||||
foreach (var page in launcher.Pages)
|
||||
{
|
||||
if (page.Node.Id.Equals(_pageId, StringComparison.Ordinal))
|
||||
{
|
||||
page.Popup = new Init(page.Node.Id, _repoPath, parent, test.StdErr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var node = Preferences.Instance.FindOrAddNodeByRepositoryPath(repoRoot, parent, true);
|
||||
node.Bookmark = _bookmark;
|
||||
await node.UpdateStatusAsync(false, null);
|
||||
Welcome.Instance.Refresh();
|
||||
node.Open();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void CollectGroups(List<RepositoryNode> outs, List<RepositoryNode> collections)
|
||||
{
|
||||
foreach (var node in collections)
|
||||
{
|
||||
if (!node.IsRepository)
|
||||
{
|
||||
outs.Add(node);
|
||||
CollectGroups(outs, node.SubNodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _pageId = string.Empty;
|
||||
private string _repoPath = string.Empty;
|
||||
private RepositoryNode _group = null;
|
||||
private int _bookmark = 0;
|
||||
}
|
||||
}
|
||||
@@ -629,19 +629,22 @@ namespace SourceGit.ViewModels
|
||||
RemoveInvalidRepositoriesRecursive(RepositoryNodes);
|
||||
}
|
||||
|
||||
public async Task UpdateAvailableAIModelsAsync()
|
||||
public void UpdateAvailableAIModels()
|
||||
{
|
||||
foreach (var service in OpenAIServices)
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
foreach (var service in OpenAIServices)
|
||||
{
|
||||
await service.FetchAvailableModelsAsync();
|
||||
try
|
||||
{
|
||||
service.FetchAvailableModels();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore errors.
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore errors.
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Save()
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace SourceGit.ViewModels
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _selectedRemoteBranch, value, true))
|
||||
IsSetTrackOptionVisible = value != null && _selectedLocalBranch.Upstream != value.FullName;
|
||||
IsSetTrackOptionVisible = value != null && (value.Head == null || _selectedLocalBranch.Upstream != value.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1887,7 +1887,7 @@ namespace SourceGit.ViewModels
|
||||
|
||||
try
|
||||
{
|
||||
if (Preferences.Instance.EnableAutoFetch || !CanCreatePopup())
|
||||
if (!Preferences.Instance.EnableAutoFetch || !CanCreatePopup())
|
||||
{
|
||||
_lastFetchTime = DateTime.Now;
|
||||
return;
|
||||
|
||||
@@ -73,7 +73,6 @@ namespace SourceGit.ViewModels
|
||||
_cmds.Add(new("Push", "push", "Push", async () => await repo.PushAsync(false)));
|
||||
_cmds.Add(new("Stash.Title", "stash", "Stashes.Add", async () => await repo.StashAllAsync(false)));
|
||||
_cmds.Add(new("Apply.Title", "apply", "Diff", () => repo.ApplyPatch()));
|
||||
_cmds.Add(new("Configure", "configure", "Settings", async () => await App.ShowDialog(new RepositoryConfigure(repo))));
|
||||
|
||||
_cmds.Sort((l, r) => l.Label.CompareTo(r.Label));
|
||||
_visibleCmds = _cmds;
|
||||
|
||||
177
src/ViewModels/SubmoduleRevisionCompare.cs
Normal file
177
src/ViewModels/SubmoduleRevisionCompare.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Threading;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace SourceGit.ViewModels
|
||||
{
|
||||
public class SubmoduleRevisionCompare : ObservableObject
|
||||
{
|
||||
public bool IsLoading
|
||||
{
|
||||
get => _isLoading;
|
||||
private set => SetProperty(ref _isLoading, value);
|
||||
}
|
||||
|
||||
public Models.Commit Base
|
||||
{
|
||||
get => _base;
|
||||
private set => SetProperty(ref _base, value);
|
||||
}
|
||||
|
||||
public Models.Commit To
|
||||
{
|
||||
get => _to;
|
||||
private set => SetProperty(ref _to, value);
|
||||
}
|
||||
|
||||
public int TotalChanges
|
||||
{
|
||||
get => _totalChanges;
|
||||
private set => SetProperty(ref _totalChanges, value);
|
||||
}
|
||||
|
||||
public List<Models.Change> VisibleChanges
|
||||
{
|
||||
get => _visibleChanges;
|
||||
private set => SetProperty(ref _visibleChanges, value);
|
||||
}
|
||||
|
||||
public List<Models.Change> SelectedChanges
|
||||
{
|
||||
get => _selectedChanges;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _selectedChanges, value))
|
||||
{
|
||||
if (value is { Count: 1 })
|
||||
DiffContext = new DiffContext(_repo, new Models.DiffOption(_base.SHA, _to.SHA, value[0]), _diffContext);
|
||||
else
|
||||
DiffContext = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string SearchFilter
|
||||
{
|
||||
get => _searchFilter;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _searchFilter, value))
|
||||
RefreshVisible();
|
||||
}
|
||||
}
|
||||
|
||||
public DiffContext DiffContext
|
||||
{
|
||||
get => _diffContext;
|
||||
private set => SetProperty(ref _diffContext, value);
|
||||
}
|
||||
|
||||
public SubmoduleRevisionCompare(Models.SubmoduleDiff diff)
|
||||
{
|
||||
_repo = diff.FullPath;
|
||||
_base = diff.Old.Commit;
|
||||
_to = diff.New.Commit;
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public void Swap()
|
||||
{
|
||||
(Base, To) = (To, Base);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public void ClearSearchFilter()
|
||||
{
|
||||
SearchFilter = string.Empty;
|
||||
}
|
||||
|
||||
public string GetAbsPath(string path)
|
||||
{
|
||||
return Native.OS.GetAbsPath(_repo, path);
|
||||
}
|
||||
|
||||
public void OpenInExternalDiffTool(Models.Change change)
|
||||
{
|
||||
new Commands.DiffTool(_repo, new Models.DiffOption(_base.SHA, _to.SHA, change)).Open();
|
||||
}
|
||||
|
||||
public async Task<bool> SaveChangesAsPatchAsync(List<Models.Change> changes, string saveTo)
|
||||
{
|
||||
return await Commands.SaveChangesAsPatch.ProcessRevisionCompareChangesAsync(_repo, changes, _base.SHA, _to.SHA, saveTo);
|
||||
}
|
||||
|
||||
private void Refresh()
|
||||
{
|
||||
IsLoading = true;
|
||||
VisibleChanges = [];
|
||||
SelectedChanges = [];
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
_changes = await new Commands.CompareRevisions(_repo, _base.SHA, _to.SHA)
|
||||
.ReadAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var visible = _changes;
|
||||
if (!string.IsNullOrWhiteSpace(_searchFilter))
|
||||
{
|
||||
visible = new List<Models.Change>();
|
||||
foreach (var c in _changes)
|
||||
{
|
||||
if (c.Path.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase))
|
||||
visible.Add(c);
|
||||
}
|
||||
}
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
TotalChanges = _changes.Count;
|
||||
VisibleChanges = visible;
|
||||
IsLoading = false;
|
||||
|
||||
if (VisibleChanges.Count > 0)
|
||||
SelectedChanges = [VisibleChanges[0]];
|
||||
else
|
||||
SelectedChanges = [];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void RefreshVisible()
|
||||
{
|
||||
if (_changes == null)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrEmpty(_searchFilter))
|
||||
{
|
||||
VisibleChanges = _changes;
|
||||
}
|
||||
else
|
||||
{
|
||||
var visible = new List<Models.Change>();
|
||||
foreach (var c in _changes)
|
||||
{
|
||||
if (c.Path.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase))
|
||||
visible.Add(c);
|
||||
}
|
||||
|
||||
VisibleChanges = visible;
|
||||
}
|
||||
}
|
||||
|
||||
private string _repo;
|
||||
private bool _isLoading = true;
|
||||
private Models.Commit _base = null;
|
||||
private Models.Commit _to = null;
|
||||
private int _totalChanges = 0;
|
||||
private List<Models.Change> _changes = null;
|
||||
private List<Models.Change> _visibleChanges = null;
|
||||
private List<Models.Change> _selectedChanges = null;
|
||||
private string _searchFilter = string.Empty;
|
||||
private DiffContext _diffContext = null;
|
||||
}
|
||||
}
|
||||
@@ -128,19 +128,6 @@ namespace SourceGit.ViewModels
|
||||
return rs.StdOut.Trim();
|
||||
}
|
||||
|
||||
public void InitRepository(string path, RepositoryNode parent, string reason)
|
||||
{
|
||||
if (!Preferences.Instance.IsGitConfigured())
|
||||
{
|
||||
Models.Notification.Send(null, App.Text("NotConfigured"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
var activePage = App.GetLauncher().ActivePage;
|
||||
if (activePage != null && activePage.CanCreatePopup())
|
||||
activePage.Popup = new Init(activePage.Node.Id, path, parent, reason);
|
||||
}
|
||||
|
||||
public async Task AddRepositoryAsync(string path, RepositoryNode parent, bool moveNode, bool open)
|
||||
{
|
||||
var node = Preferences.Instance.FindOrAddNodeByRepositoryPath(path, parent, moveNode);
|
||||
@@ -163,6 +150,19 @@ namespace SourceGit.ViewModels
|
||||
activePage.Popup = new Clone(activePage.Node.Id);
|
||||
}
|
||||
|
||||
public void OpenLocalRepository()
|
||||
{
|
||||
if (!Preferences.Instance.IsGitConfigured())
|
||||
{
|
||||
Models.Notification.Send(null, App.Text("NotConfigured"), true);
|
||||
return;
|
||||
}
|
||||
|
||||
var activePage = App.GetLauncher().ActivePage;
|
||||
if (activePage != null && activePage.CanCreatePopup())
|
||||
activePage.Popup = new OpenLocalRepository(activePage.Node.Id, null);
|
||||
}
|
||||
|
||||
public void OpenTerminal()
|
||||
{
|
||||
if (!Preferences.Instance.IsGitConfigured())
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="120"
|
||||
mc:Ignorable="d" d:DesignWidth="520" d:DesignHeight="400"
|
||||
x:Class="SourceGit.Views.AIAssistant"
|
||||
x:DataType="vm:AIAssistant"
|
||||
x:Name="ThisControl"
|
||||
Icon="/App.ico"
|
||||
Title="{DynamicResource Text.AIAssistant}"
|
||||
Width="520" SizeToContent="Height"
|
||||
CanResize="False"
|
||||
Width="520" Height="400"
|
||||
CanResize="True"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid RowDefinitions="Auto,Auto,Auto">
|
||||
<Grid RowDefinitions="Auto,*,Auto">
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" Height="28" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
|
||||
<Border Background="{DynamicResource Brush.TitleBar}"
|
||||
@@ -39,7 +39,6 @@
|
||||
<!-- AI response -->
|
||||
<v:AIResponseView Grid.Row="1"
|
||||
Margin="8"
|
||||
Height="320"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"
|
||||
Background="{DynamicResource Brush.Contents}"
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace SourceGit.Views
|
||||
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
vm.Launch();
|
||||
this.ShowWindow(vm.Launch());
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == Key.Up)
|
||||
@@ -55,7 +55,7 @@ namespace SourceGit.Views
|
||||
{
|
||||
if (DataContext is ViewModels.BlameCommandPalette vm)
|
||||
{
|
||||
vm.Launch();
|
||||
this.ShowWindow(vm.Launch());
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,7 +537,7 @@ namespace SourceGit.Views
|
||||
compare.Icon = this.CreateMenuIcon("Icons.Compare");
|
||||
compare.Click += (_, ev) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.Compare(repo, branches[0], branches[1]));
|
||||
this.ShowWindow(new ViewModels.Compare(repo, branches[0], branches[1]));
|
||||
ev.Handled = true;
|
||||
};
|
||||
menu.Items.Add(compare);
|
||||
@@ -819,7 +819,7 @@ namespace SourceGit.Views
|
||||
interactiveRebase.Click += async (_, e) =>
|
||||
{
|
||||
var commit = await new Commands.QuerySingleCommit(repo.FullPath, branch.Head).GetResultAsync();
|
||||
await App.ShowDialog(new ViewModels.InteractiveRebase(repo, commit));
|
||||
await this.ShowDialogAsync(new ViewModels.InteractiveRebase(repo, commit));
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -853,7 +853,7 @@ namespace SourceGit.Views
|
||||
compareWithCurrent.Icon = this.CreateMenuIcon("Icons.Compare");
|
||||
compareWithCurrent.Click += (_, _) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.Compare(repo, branch, current));
|
||||
this.ShowWindow(new ViewModels.Compare(repo, branch, current));
|
||||
};
|
||||
|
||||
var compareWith = new MenuItem();
|
||||
@@ -1154,7 +1154,7 @@ namespace SourceGit.Views
|
||||
interactiveRebase.Click += async (_, e) =>
|
||||
{
|
||||
var commit = await new Commands.QuerySingleCommit(repo.FullPath, branch.Head).GetResultAsync();
|
||||
await App.ShowDialog(new ViewModels.InteractiveRebase(repo, commit));
|
||||
await this.ShowDialogAsync(new ViewModels.InteractiveRebase(repo, commit));
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -1163,7 +1163,7 @@ namespace SourceGit.Views
|
||||
compareWithHead.Icon = this.CreateMenuIcon("Icons.Compare");
|
||||
compareWithHead.Click += (_, _) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.Compare(repo, branch, current));
|
||||
this.ShowWindow(new ViewModels.Compare(repo, branch, current));
|
||||
};
|
||||
|
||||
var compareWith = new MenuItem();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Clone"
|
||||
x:DataType="vm:Clone">
|
||||
@@ -19,7 +20,7 @@
|
||||
Text="{DynamicResource Text.Clone}"/>
|
||||
</StackPanel>
|
||||
|
||||
<Grid Margin="8,16,0,0" RowDefinitions="32,Auto,32,32,32,32" ColumnDefinitions="Auto,*">
|
||||
<Grid Margin="8,16,0,0" RowDefinitions="32,Auto,32,32,32,32,32,32" ColumnDefinitions="Auto,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,8,0"
|
||||
@@ -102,7 +103,44 @@
|
||||
Watermark="{DynamicResource Text.Clone.AdditionalParam.Placeholder}"
|
||||
Text="{Binding ExtraArgs, Mode=TwoWay}"/>
|
||||
|
||||
<CheckBox Grid.Row="5" Grid.Column="1"
|
||||
<TextBlock Grid.Row="5" Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Clone.Group}"/>
|
||||
<ComboBox Grid.Row="5" Grid.Column="1"
|
||||
Height="28" Padding="8,0"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding Groups}"
|
||||
SelectedItem="{Binding SelectedGroup, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate DataType="vm:RepositoryNode">
|
||||
<TextBlock Text="{Binding Name, Mode=OneWay}"/>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock Grid.Row="6" Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Clone.Bookmark}"/>
|
||||
<ComboBox Grid.Row="6" Grid.Column="1"
|
||||
Height="28" Padding="8,0"
|
||||
VerticalAlignment="Center"
|
||||
ItemsSource="{Binding Bookmarks}"
|
||||
SelectedItem="{Binding Bookmark, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Height="20">
|
||||
<Path Width="12" Height="12"
|
||||
Fill="{Binding Converter={x:Static c:IntConverters.ToBookmarkBrush}}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Data="{StaticResource Icons.Bookmark}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<CheckBox Grid.Row="7" Grid.Column="1"
|
||||
Content="{DynamicResource Text.Clone.RecurseSubmodules}"
|
||||
IsChecked="{Binding InitAndUpdateSubmodules, Mode=TwoWay}"
|
||||
ToolTip.Tip="--recurse-submodules"/>
|
||||
|
||||
@@ -62,7 +62,10 @@
|
||||
<TextBlock Text="{Binding SHA}" Margin="12,0,4,0" VerticalAlignment="Center"/>
|
||||
|
||||
<Button Classes="icon_button" Width="24" Cursor="Hand" Click="OnCopyCommitSHA" ToolTip.Tip="{DynamicResource Text.Copy}">
|
||||
<Path Width="12" Height="12" Data="{StaticResource Icons.Copy}"/>
|
||||
<Grid>
|
||||
<Path Width="12" Height="12" Data="{StaticResource Icons.Copy}" IsVisible="{Binding #ThisControl.IsSHACopied, Mode=OneWay, Converter={x:Static BoolConverters.Not}}"/>
|
||||
<Path Width="14" Height="14" Margin="0,2,0,0" Data="{StaticResource Icons.Check}" Fill="Green" IsVisible="{Binding #ThisControl.IsSHACopied, Mode=OneWay}"/>
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
<Button Classes="icon_button" Width="24" Cursor="Hand" Click="OnOpenContainsIn" IsVisible="{Binding #ThisControl.SupportsContainsIn}" ToolTip.Tip="{DynamicResource Text.CommitDetail.Info.ContainsIn}">
|
||||
|
||||
@@ -5,6 +5,7 @@ using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
@@ -55,16 +56,51 @@ namespace SourceGit.Views
|
||||
set => SetValue(ChildrenProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<bool> IsSHACopiedProperty =
|
||||
AvaloniaProperty.Register<CommitBaseInfo, bool>(nameof(IsSHACopied));
|
||||
|
||||
public bool IsSHACopied
|
||||
{
|
||||
get => GetValue(IsSHACopiedProperty);
|
||||
set => SetValue(IsSHACopiedProperty, value);
|
||||
}
|
||||
|
||||
public CommitBaseInfo()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
|
||||
if (change.Property == ContentProperty)
|
||||
{
|
||||
_iconResetTimer?.Dispose();
|
||||
SetCurrentValue(IsSHACopiedProperty, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnUnloaded(RoutedEventArgs e)
|
||||
{
|
||||
base.OnUnloaded(e);
|
||||
_iconResetTimer?.Dispose();
|
||||
}
|
||||
|
||||
private async void OnCopyCommitSHA(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button { DataContext: Models.Commit commit })
|
||||
await this.CopyTextAsync(commit.SHA);
|
||||
|
||||
_iconResetTimer = DispatcherTimer.RunOnce(() =>
|
||||
{
|
||||
if (IsSHACopied)
|
||||
IsSHACopied = false;
|
||||
|
||||
_iconResetTimer = null;
|
||||
}, TimeSpan.FromSeconds(2));
|
||||
|
||||
IsSHACopied = true;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
@@ -190,5 +226,7 @@ namespace SourceGit.Views
|
||||
await this.CopyTextAsync(detail.FullMessage.Message);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private IDisposable _iconResetTimer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace SourceGit.Views
|
||||
history.Icon = this.CreateMenuIcon("Icons.Histories");
|
||||
history.Click += (_, ev) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.DirHistories(repo, node.FullPath, commit.SHA));
|
||||
this.ShowWindow(new ViewModels.DirHistories(repo, node.FullPath, commit.SHA));
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
@@ -273,7 +273,7 @@ namespace SourceGit.Views
|
||||
history.Icon = this.CreateMenuIcon("Icons.Histories");
|
||||
history.Click += (_, ev) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.FileHistories(repo.FullPath, change.Path, commit.SHA));
|
||||
this.ShowWindow(new ViewModels.FileHistories(repo.FullPath, change.Path, commit.SHA));
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
@@ -283,7 +283,7 @@ namespace SourceGit.Views
|
||||
blame.IsEnabled = change.Index != Models.ChangeState.Deleted;
|
||||
blame.Click += (_, ev) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.Blame(repo.FullPath, change.Path, commit));
|
||||
this.ShowWindow(new ViewModels.Blame(repo.FullPath, change.Path, commit));
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -565,7 +565,7 @@ namespace SourceGit.Views
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private async void OnOpenOpenAIHelper(object sender, RoutedEventArgs e)
|
||||
private void OnOpenOpenAIHelper(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.WorkingCopy vm && sender is Button button && ShowAdvancedOptions)
|
||||
{
|
||||
@@ -588,7 +588,7 @@ namespace SourceGit.Views
|
||||
|
||||
if (services.Count == 1)
|
||||
{
|
||||
await App.ShowDialog(new ViewModels.AIAssistant(repo, services[0], vm.Staged));
|
||||
DoOpenAIAssistant(repo, services[0], vm.Staged);
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
@@ -599,9 +599,9 @@ namespace SourceGit.Views
|
||||
var dup = service;
|
||||
var item = new MenuItem();
|
||||
item.Header = service.Name;
|
||||
item.Click += async (_, ev) =>
|
||||
item.Click += (_, ev) =>
|
||||
{
|
||||
await App.ShowDialog(new ViewModels.AIAssistant(repo, dup, vm.Staged));
|
||||
DoOpenAIAssistant(repo, dup, vm.Staged);
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
@@ -637,5 +637,16 @@ namespace SourceGit.Views
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void DoOpenAIAssistant(ViewModels.Repository repo, AI.Service service, List<Models.Change> changes)
|
||||
{
|
||||
var owner = TopLevel.GetTopLevel(this) as Window;
|
||||
if (owner == null)
|
||||
return;
|
||||
|
||||
var assistant = new ViewModels.AIAssistant(repo, service, changes);
|
||||
var view = new AIAssistant() { DataContext = assistant };
|
||||
view.Show(owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,13 +105,9 @@ namespace SourceGit.Views
|
||||
|
||||
_refreshTimer = DispatcherTimer.Run(() =>
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
var text = GetDisplayText();
|
||||
if (!text.Equals(Text, StringComparison.Ordinal))
|
||||
Text = text;
|
||||
});
|
||||
|
||||
var text = GetDisplayText();
|
||||
if (!text.Equals(Text, StringComparison.Ordinal))
|
||||
Text = text;
|
||||
return true;
|
||||
}, TimeSpan.FromSeconds(10));
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace SourceGit.Views
|
||||
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
vm.Launch();
|
||||
this.ShowWindow(vm.Launch());
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == Key.Up)
|
||||
@@ -55,7 +55,7 @@ namespace SourceGit.Views
|
||||
{
|
||||
if (DataContext is ViewModels.CompareCommandPalette vm)
|
||||
{
|
||||
vm.Launch();
|
||||
this.ShowWindow(vm.Launch());
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,9 +129,11 @@
|
||||
<TextBlock Margin="0,12,0,0" Text="{DynamicResource Text.ConfigureCustomActionControls.Type}"/>
|
||||
<ComboBox Margin="0,4,0,0" Height="28" HorizontalAlignment="Stretch" SelectedIndex="{Binding Type, Mode=TwoWay}">
|
||||
<ComboBoxItem Content="TextBox"/>
|
||||
<ComboBoxItem Content="PathSelector"/>
|
||||
<ComboBoxItem Content="Path Selector"/>
|
||||
<ComboBoxItem Content="CheckBox"/>
|
||||
<ComboBoxItem Content="ComboBox"/>
|
||||
<ComboBoxItem Content="Local Branch Selector"/>
|
||||
<ComboBoxItem Content="Remote Branch Selector"/>
|
||||
</ComboBox>
|
||||
|
||||
<!-- Description -->
|
||||
@@ -160,7 +162,14 @@
|
||||
<TextBox Margin="0,4,0,0"
|
||||
CornerRadius="3"
|
||||
Height="28"
|
||||
Text="{Binding StringValue, Mode=TwoWay}"/>
|
||||
Text="{Binding StringValue, Mode=TwoWay}">
|
||||
<TextBox.IsVisible>
|
||||
<MultiBinding Converter="{x:Static BoolConverters.And}">
|
||||
<Binding Path="Type" Converter="{x:Static ObjectConverters.NotEqual}" ConverterParameter="{x:Static m:CustomActionControlType.LocalBranchSelector}"/>
|
||||
<Binding Path="Type" Converter="{x:Static ObjectConverters.NotEqual}" ConverterParameter="{x:Static m:CustomActionControlType.RemoteBranchSelector}"/>
|
||||
</MultiBinding>
|
||||
</TextBox.IsVisible>
|
||||
</TextBox>
|
||||
<TextBlock Margin="0,2,0,0"
|
||||
Classes="small"
|
||||
TextWrapping="Wrap"
|
||||
@@ -187,12 +196,29 @@
|
||||
</TextBlock.IsVisible>
|
||||
</TextBlock>
|
||||
|
||||
<!-- String Formatter -->
|
||||
<TextBlock Margin="0,12,0,0"
|
||||
Text="{DynamicResource Text.ConfigureCustomActionControls.StringFormatter}"
|
||||
IsVisible="{Binding Type, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:CustomActionControlType.TextBox}}"/>
|
||||
<TextBox Margin="0,4,0,0"
|
||||
CornerRadius="3"
|
||||
Height="28"
|
||||
Text="{Binding StringFormatter, Mode=TwoWay}"
|
||||
IsVisible="{Binding Type, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:CustomActionControlType.TextBox}}"/>
|
||||
<TextBlock Margin="0,2,0,0"
|
||||
Classes="small"
|
||||
TextWrapping="Wrap"
|
||||
Text="{DynamicResource Text.ConfigureCustomActionControls.StringFormatter.Tip}"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
IsVisible="{Binding Type, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:CustomActionControlType.TextBox}}"/>
|
||||
|
||||
<!-- BoolValue is needed by CheckBox/PathSelector -->
|
||||
<Grid Margin="0,8,0,0" ColumnDefinitions="Auto,*">
|
||||
<Grid.IsVisible>
|
||||
<MultiBinding Converter="{x:Static BoolConverters.Or}">
|
||||
<Binding Path="Type" Converter="{x:Static ObjectConverters.Equal}" ConverterParameter="{x:Static m:CustomActionControlType.CheckBox}"/>
|
||||
<Binding Path="Type" Converter="{x:Static ObjectConverters.Equal}" ConverterParameter="{x:Static m:CustomActionControlType.PathSelector}"/>
|
||||
<Binding Path="Type" Converter="{x:Static ObjectConverters.Equal}" ConverterParameter="{x:Static m:CustomActionControlType.RemoteBranchSelector}"/>
|
||||
</MultiBinding>
|
||||
</Grid.IsVisible>
|
||||
<TextBlock Grid.Column="0"
|
||||
@@ -201,6 +227,9 @@
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="{DynamicResource Text.ConfigureCustomActionControls.IsFolder}"
|
||||
IsVisible="{Binding Type, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:CustomActionControlType.PathSelector}}"/>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="{DynamicResource Text.ConfigureCustomActionControls.UseFriendlyName}"
|
||||
IsVisible="{Binding Type, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:CustomActionControlType.RemoteBranchSelector}}"/>
|
||||
<CheckBox Grid.Column="1"
|
||||
Margin="8,0,0,0"
|
||||
Height="28"
|
||||
|
||||
@@ -40,7 +40,10 @@ namespace SourceGit.Views
|
||||
private async void OnMerge(object _, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.Conflict vm)
|
||||
await vm.MergeAsync();
|
||||
{
|
||||
var request = vm.CreateOpenMergeEditorRequest();
|
||||
await this.ShowDialogAsync(request);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Shapes;
|
||||
using Avalonia.Media;
|
||||
@@ -44,5 +46,63 @@ namespace SourceGit.Views
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void ShowWindow(this Control control, object data)
|
||||
{
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
if (data is not ChromelessWindow window)
|
||||
{
|
||||
window = CreateFromViewModels(data) as ChromelessWindow;
|
||||
if (window == null)
|
||||
return;
|
||||
|
||||
window.DataContext = data;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
var owner = TopLevel.GetTopLevel(control) as Window;
|
||||
if (owner != null)
|
||||
{
|
||||
// Get the screen where current window locates.
|
||||
var screen = owner.Screens.ScreenFromWindow(owner) ?? owner.Screens.Primary;
|
||||
if (screen == null)
|
||||
break;
|
||||
|
||||
// Calculate the startup position (Center Screen Mode) of target window
|
||||
var rect = new PixelRect(PixelSize.FromSize(window.ClientSize, owner.DesktopScaling));
|
||||
var centeredRect = screen.WorkingArea.CenterRect(rect);
|
||||
if (owner.Screens.ScreenFromPoint(centeredRect.Position) == null)
|
||||
break;
|
||||
|
||||
// Use the startup position
|
||||
window.WindowStartupLocation = WindowStartupLocation.Manual;
|
||||
window.Position = centeredRect.Position;
|
||||
}
|
||||
} while (false);
|
||||
|
||||
window.Show();
|
||||
}
|
||||
|
||||
public static Task ShowDialogAsync(this Control control, object data)
|
||||
{
|
||||
var owner = TopLevel.GetTopLevel(control) as Window;
|
||||
if (owner == null)
|
||||
return null;
|
||||
|
||||
if (data is ChromelessWindow window)
|
||||
return window.ShowDialog(owner);
|
||||
|
||||
window = CreateFromViewModels(data) as ChromelessWindow;
|
||||
if (window != null)
|
||||
{
|
||||
window.DataContext = data;
|
||||
return window.ShowDialog(owner);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,11 +321,26 @@
|
||||
<ContentControl Content="{Binding New}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="m:RevisionSubmodule">
|
||||
<v:CommitBaseInfo Margin="0,4,8,6" Content="{Binding Commit}" FullMessage="{Binding FullMessage}"/>
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock Margin="0,8,0,4"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="OrangeRed"
|
||||
FontFamily="{DynamicResource Fonts.Monospace}"
|
||||
Text="{Binding UncommittedChanges, Converter={x:Static c:StringConverters.FormatByResourceKey}, ConverterParameter='Diff.Submodule.UncommittedChanges'}"
|
||||
IsVisible="{Binding UncommittedChanges, Converter={x:Static c:IntConverters.IsGreaterThanZero}}"/>
|
||||
<v:CommitBaseInfo Margin="0,4,8,6" Content="{Binding Commit}" FullMessage="{Binding FullMessage}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
</Border>
|
||||
|
||||
<Button Classes="flat"
|
||||
Margin="0,8"
|
||||
HorizontalAlignment="Center"
|
||||
Content="{DynamicResource Text.SubmoduleRevisionCompare.OpenDetails}"
|
||||
Click="OnOpenSubmoduleRevisionCompare"
|
||||
IsEnabled="{Binding CanOpenDetails, Mode=OneWay}"/>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
@@ -42,5 +42,14 @@ namespace SourceGit.Views
|
||||
this.FindDescendantOfType<ThemedTextDiffPresenter>()?.GotoChange(ViewModels.BlockNavigationDirection.Last);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnOpenSubmoduleRevisionCompare(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button { DataContext: Models.SubmoduleDiff diff } && diff.CanOpenDetails)
|
||||
{
|
||||
var vm = new ViewModels.SubmoduleRevisionCompare(diff);
|
||||
this.ShowWindow(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.ExecuteCustomAction"
|
||||
@@ -140,6 +141,28 @@
|
||||
IsVisible="{Binding Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="vm:CustomActionControlBranchSelector">
|
||||
<Grid RowDefinitions="32,Auto" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
Text="{Binding Label}"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"/>
|
||||
<v:BranchSelector Grid.Row="0" Grid.Column="1"
|
||||
Height="28" Padding="8,0"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Stretch"
|
||||
Branches="{Binding Branches, Mode=OneWay}"
|
||||
SelectedBranch="{Binding SelectedBranch, Mode=TwoWay}"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="1"
|
||||
Classes="small"
|
||||
Margin="0,2"
|
||||
TextWrapping="Wrap"
|
||||
Text="{Binding Description}"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
IsVisible="{Binding Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.DataTemplates>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace SourceGit.Views
|
||||
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
vm.Launch();
|
||||
this.ShowWindow(vm.Launch());
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == Key.Up)
|
||||
@@ -55,7 +55,7 @@ namespace SourceGit.Views
|
||||
{
|
||||
if (DataContext is ViewModels.FileHistoryCommandPalette vm)
|
||||
{
|
||||
vm.Launch();
|
||||
this.ShowWindow(vm.Launch());
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
IsVisible="{Binding Type, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:GitFlowBranchType.Hotfix}}"/>
|
||||
</StackPanel>
|
||||
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32,32" ColumnDefinitions="150,*">
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
@@ -43,11 +43,6 @@
|
||||
ToolTip.Tip="--squash"/>
|
||||
|
||||
<CheckBox Grid.Row="2" Grid.Column="1"
|
||||
Content="{DynamicResource Text.GitFlow.FinishWithPush}"
|
||||
IsChecked="{Binding AutoPush, Mode=TwoWay}"
|
||||
ToolTip.Tip="--push"/>
|
||||
|
||||
<CheckBox Grid.Row="3" Grid.Column="1"
|
||||
Content="{DynamicResource Text.GitFlow.KeepBranchAfterFinish}"
|
||||
IsChecked="{Binding KeepBranch, Mode=TwoWay}"
|
||||
ToolTip.Tip="-k"/>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Collections;
|
||||
@@ -832,7 +833,7 @@ namespace SourceGit.Views
|
||||
manually.Icon = this.CreateMenuIcon("Icons.InteractiveRebase");
|
||||
manually.Click += async (_, e) =>
|
||||
{
|
||||
await App.ShowDialog(new ViewModels.InteractiveRebase(repo, commit));
|
||||
await this.ShowDialogAsync(new ViewModels.InteractiveRebase(repo, commit));
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -841,7 +842,7 @@ namespace SourceGit.Views
|
||||
reword.Icon = this.CreateMenuIcon("Icons.Rename");
|
||||
reword.Click += async (_, e) =>
|
||||
{
|
||||
await vm.InteractiveRebaseAsync(commit, Models.InteractiveRebaseAction.Reword);
|
||||
await InteractiveRebaseWithPrefillActionAsync(repo, commit, Models.InteractiveRebaseAction.Reword);
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -850,7 +851,7 @@ namespace SourceGit.Views
|
||||
edit.Icon = this.CreateMenuIcon("Icons.Edit");
|
||||
edit.Click += async (_, e) =>
|
||||
{
|
||||
await vm.InteractiveRebaseAsync(commit, Models.InteractiveRebaseAction.Edit);
|
||||
await InteractiveRebaseWithPrefillActionAsync(repo, commit, Models.InteractiveRebaseAction.Edit);
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -859,7 +860,7 @@ namespace SourceGit.Views
|
||||
squash.Icon = this.CreateMenuIcon("Icons.SquashIntoParent");
|
||||
squash.Click += async (_, e) =>
|
||||
{
|
||||
await vm.InteractiveRebaseAsync(commit, Models.InteractiveRebaseAction.Squash);
|
||||
await InteractiveRebaseWithPrefillActionAsync(repo, commit, Models.InteractiveRebaseAction.Squash);
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -868,7 +869,7 @@ namespace SourceGit.Views
|
||||
fixup.Icon = this.CreateMenuIcon("Icons.Fix");
|
||||
fixup.Click += async (_, e) =>
|
||||
{
|
||||
await vm.InteractiveRebaseAsync(commit, Models.InteractiveRebaseAction.Fixup);
|
||||
await InteractiveRebaseWithPrefillActionAsync(repo, commit, Models.InteractiveRebaseAction.Fixup);
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -877,7 +878,7 @@ namespace SourceGit.Views
|
||||
drop.Icon = this.CreateMenuIcon("Icons.Clear");
|
||||
drop.Click += async (_, e) =>
|
||||
{
|
||||
await vm.InteractiveRebaseAsync(commit, Models.InteractiveRebaseAction.Drop);
|
||||
await InteractiveRebaseWithPrefillActionAsync(repo, commit, Models.InteractiveRebaseAction.Drop);
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -902,7 +903,7 @@ namespace SourceGit.Views
|
||||
interactiveRebase.Icon = this.CreateMenuIcon("Icons.InteractiveRebase");
|
||||
interactiveRebase.Click += async (_, e) =>
|
||||
{
|
||||
await App.ShowDialog(new ViewModels.InteractiveRebase(repo, commit));
|
||||
await this.ShowDialogAsync(new ViewModels.InteractiveRebase(repo, commit));
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -1417,6 +1418,22 @@ namespace SourceGit.Views
|
||||
menu.Items.Add(submenu);
|
||||
}
|
||||
|
||||
private async Task InteractiveRebaseWithPrefillActionAsync(ViewModels.Repository repo, Models.Commit target, Models.InteractiveRebaseAction action)
|
||||
{
|
||||
var prefill = new ViewModels.InteractiveRebasePrefill(target.SHA, action);
|
||||
var start = action switch
|
||||
{
|
||||
Models.InteractiveRebaseAction.Squash or Models.InteractiveRebaseAction.Fixup => $"{target.SHA}~~",
|
||||
_ => $"{target.SHA}~",
|
||||
};
|
||||
|
||||
var on = await new Commands.QuerySingleCommit(repo.FullPath, start).GetResultAsync();
|
||||
if (on == null)
|
||||
repo.SendNotification($"Commit '{start}' is not a valid revision for `git rebase -i`!", true);
|
||||
else
|
||||
await this.ShowDialogAsync(new ViewModels.InteractiveRebase(repo, on, prefill));
|
||||
}
|
||||
|
||||
private double _lastGraphStartY = 0;
|
||||
private double _lastGraphClipWidth = 0;
|
||||
private double _lastGraphRowHeight = 0;
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Increase}}"
|
||||
Margin="0,0,0,8"/>
|
||||
|
||||
<Grid RowDefinitions="20,20,20,20,20,20,20,20,20,20" ColumnDefinitions="150,*">
|
||||
<Grid RowDefinitions="20,20,20,20,20,20,20,20,20,20,20" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+\,, macOS=⌘+\,}"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.OpenPreferences}"/>
|
||||
|
||||
@@ -64,17 +64,20 @@
|
||||
<TextBlock Grid.Row="5" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+N, macOS=⌘+N}"/>
|
||||
<TextBlock Grid.Row="5" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.Clone}" />
|
||||
|
||||
<TextBlock Grid.Row="6" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+Alt+P, macOS=⌘+⌥+P}"/>
|
||||
<TextBlock Grid.Row="6" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.ShowWorkspaceDropdownMenu}" />
|
||||
<TextBlock Grid.Row="6" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+Shift+O, macOS=⌘+⇧+O}"/>
|
||||
<TextBlock Grid.Row="6" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.OpenLocalRepository}" />
|
||||
|
||||
<TextBlock Grid.Row="7" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+P, macOS=⌘+P}"/>
|
||||
<TextBlock Grid.Row="7" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.SwitchTab}" />
|
||||
<TextBlock Grid.Row="7" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+Alt+P, macOS=⌘+⌥+P}"/>
|
||||
<TextBlock Grid.Row="7" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.ShowWorkspaceDropdownMenu}" />
|
||||
|
||||
<TextBlock Grid.Row="8" Grid.Column="0" Classes="bold" Text="{OnPlatform 'Ctrl+-/=', macOS='⌘+-/='}"/>
|
||||
<TextBlock Grid.Row="8" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.Zoom}" />
|
||||
<TextBlock Grid.Row="8" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+P, macOS=⌘+P}"/>
|
||||
<TextBlock Grid.Row="8" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.SwitchTab}" />
|
||||
|
||||
<TextBlock Grid.Row="9" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+Q, macOS=⌘+Q}"/>
|
||||
<TextBlock Grid.Row="9" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Quit}" />
|
||||
<TextBlock Grid.Row="9" Grid.Column="0" Classes="bold" Text="{OnPlatform 'Ctrl+-/=', macOS='⌘+-/='}"/>
|
||||
<TextBlock Grid.Row="9" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Global.Zoom}" />
|
||||
|
||||
<TextBlock Grid.Row="10" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+Q, macOS=⌘+Q}"/>
|
||||
<TextBlock Grid.Row="10" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Quit}" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock Text="{DynamicResource Text.Hotkeys.Repo}"
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace SourceGit.Views
|
||||
Activate();
|
||||
}
|
||||
|
||||
protected override async void OnOpened(EventArgs e)
|
||||
protected override void OnOpened(EventArgs e)
|
||||
{
|
||||
base.OnOpened(e);
|
||||
|
||||
@@ -114,8 +114,6 @@ namespace SourceGit.Views
|
||||
var state = preferences.Layout.LauncherWindowState;
|
||||
if (state == WindowState.Maximized || state == WindowState.FullScreen)
|
||||
WindowState = WindowState.Maximized;
|
||||
|
||||
await preferences.UpdateAvailableAIModelsAsync();
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
@@ -174,14 +172,14 @@ namespace SourceGit.Views
|
||||
{
|
||||
if (e is { KeyModifiers: KeyModifiers.Control, Key: Key.OemComma })
|
||||
{
|
||||
await App.ShowDialog(new Preferences());
|
||||
await this.ShowDialogAsync(new Preferences());
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (e is { KeyModifiers: KeyModifiers.None, Key: Key.F1 })
|
||||
{
|
||||
await App.ShowDialog(new Hotkeys());
|
||||
await this.ShowDialogAsync(new Hotkeys());
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
@@ -233,6 +231,16 @@ namespace SourceGit.Views
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Key == Key.O && e.KeyModifiers.HasFlag(KeyModifiers.Shift))
|
||||
{
|
||||
if (vm.ActivePage.Data is not ViewModels.Welcome)
|
||||
vm.AddNewTab();
|
||||
|
||||
ViewModels.Welcome.Instance.OpenLocalRepository();
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Key == Key.T)
|
||||
{
|
||||
vm.AddNewTab();
|
||||
@@ -330,10 +338,17 @@ namespace SourceGit.Views
|
||||
base.OnClosing(e);
|
||||
|
||||
if (!Design.IsDesignMode && DataContext is ViewModels.Launcher launcher)
|
||||
{
|
||||
launcher.CloseAll();
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
base.OnClosed(e);
|
||||
|
||||
if (!Design.IsDesignMode)
|
||||
ViewModels.Preferences.Instance.Save();
|
||||
launcher.Quit();
|
||||
}
|
||||
|
||||
App.Quit(0);
|
||||
}
|
||||
|
||||
private void OnPositionChanged(object sender, PixelPointEventArgs e)
|
||||
@@ -396,7 +411,7 @@ namespace SourceGit.Views
|
||||
configure.Header = App.Text("Workspace.Configure");
|
||||
configure.Click += async (_, ev) =>
|
||||
{
|
||||
await App.ShowDialog(new ViewModels.ConfigureWorkspace());
|
||||
await this.ShowDialogAsync(new ViewModels.ConfigureWorkspace());
|
||||
ev.Handled = true;
|
||||
};
|
||||
menu.Items.Add(configure);
|
||||
|
||||
@@ -351,8 +351,6 @@ namespace SourceGit.Views
|
||||
Models.TextMateHelper.SetThemeByApp(_textMate);
|
||||
else if (change.Property == SelectedChunkProperty)
|
||||
TextArea.TextView.InvalidateVisual();
|
||||
else if (change.Property == MaxLineNumberProperty)
|
||||
TextArea.LeftMargins[0].InvalidateMeasure();
|
||||
}
|
||||
|
||||
private void UpdateContent()
|
||||
@@ -439,6 +437,9 @@ namespace SourceGit.Views
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var margin in TextArea.LeftMargins)
|
||||
margin.InvalidateMeasure();
|
||||
|
||||
var lines = Lines;
|
||||
var start = int.MaxValue;
|
||||
var count = 0;
|
||||
|
||||
77
src/Views/OpenLocalRepository.axaml
Normal file
77
src/Views/OpenLocalRepository.axaml
Normal file
@@ -0,0 +1,77 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.OpenLocalRepository"
|
||||
x:DataType="vm:OpenLocalRepository">
|
||||
<StackPanel Orientation="Vertical" Margin="8,0,0,0">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="16" Height="16"
|
||||
Margin="0,2,0,0"
|
||||
Data="{StaticResource Icons.Folder.Open}"/>
|
||||
|
||||
<TextBlock FontSize="18"
|
||||
Margin="8,0,0,0"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.OpenLocalRepository}"/>
|
||||
</StackPanel>
|
||||
|
||||
<Grid Margin="8,16,0,0" RowDefinitions="32,32,32" ColumnDefinitions="Auto,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.OpenLocalRepository.Path}"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Text="{Binding RepoPath, Mode=TwoWay}">
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button" Width="28" Height="28" Margin="4,0,0,0" Click="OnSelectRepositoryFolder">
|
||||
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.OpenLocalRepository.Group}"/>
|
||||
<ComboBox Grid.Row="1" Grid.Column="1"
|
||||
Height="28" Padding="8,0"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding Groups}"
|
||||
SelectedItem="{Binding Group, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate DataType="vm:RepositoryNode">
|
||||
<TextBlock Text="{Binding Name, Mode=OneWay}"/>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.OpenLocalRepository.Bookmark}"/>
|
||||
<ComboBox Grid.Row="2" Grid.Column="1"
|
||||
Height="28" Padding="8,0"
|
||||
VerticalAlignment="Center"
|
||||
ItemsSource="{Binding Bookmarks}"
|
||||
SelectedItem="{Binding Bookmark, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Height="20">
|
||||
<Path Width="12" Height="12"
|
||||
Fill="{Binding Converter={x:Static c:IntConverters.ToBookmarkBrush}}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Data="{StaticResource Icons.Bookmark}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
56
src/Views/OpenLocalRepository.axaml.cs
Normal file
56
src/Views/OpenLocalRepository.axaml.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Platform.Storage;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class OpenLocalRepository : UserControl
|
||||
{
|
||||
public OpenLocalRepository()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void OnSelectRepositoryFolder(object _1, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is not ViewModels.OpenLocalRepository vm)
|
||||
return;
|
||||
|
||||
var topLevel = TopLevel.GetTopLevel(this);
|
||||
if (topLevel == null)
|
||||
return;
|
||||
|
||||
var preference = ViewModels.Preferences.Instance;
|
||||
var workspace = preference.GetActiveWorkspace();
|
||||
var initDir = workspace.DefaultCloneDir;
|
||||
if (string.IsNullOrEmpty(initDir) || !Directory.Exists(initDir))
|
||||
initDir = preference.GitDefaultCloneDir;
|
||||
|
||||
var options = new FolderPickerOpenOptions() { AllowMultiple = false };
|
||||
if (Directory.Exists(initDir))
|
||||
{
|
||||
var folder = await topLevel.StorageProvider.TryGetFolderFromPathAsync(initDir);
|
||||
options.SuggestedStartLocation = folder;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var selected = await topLevel.StorageProvider.OpenFolderPickerAsync(options);
|
||||
if (selected.Count == 1)
|
||||
{
|
||||
var folder = selected[0];
|
||||
vm.RepoPath = folder is { Path: { IsAbsoluteUri: true } path } ? path.LocalPath : folder?.Path.ToString();
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Models.Notification.Send(null, $"Failed to open repository: {exception.Message}", true);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -206,7 +206,7 @@ namespace SourceGit.Views
|
||||
}
|
||||
|
||||
var preferences = ViewModels.Preferences.Instance;
|
||||
await preferences.UpdateAvailableAIModelsAsync();
|
||||
preferences.UpdateAvailableAIModels();
|
||||
preferences.Save();
|
||||
}
|
||||
|
||||
@@ -386,7 +386,7 @@ namespace SourceGit.Views
|
||||
if (sender is CheckBox box)
|
||||
{
|
||||
ViewModels.Preferences.Instance.UseSystemWindowFrame = box.IsChecked == true;
|
||||
await App.ShowDialog(new ConfirmRestart());
|
||||
await this.ShowDialogAsync(new ConfirmRestart());
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
@@ -486,12 +486,7 @@ namespace SourceGit.Views
|
||||
if (sender is not Button { DataContext: Models.CustomAction act })
|
||||
return;
|
||||
|
||||
var dialog = new ConfigureCustomActionControls()
|
||||
{
|
||||
DataContext = new ViewModels.ConfigureCustomActionControls(act.Controls)
|
||||
};
|
||||
|
||||
await dialog.ShowDialog(this);
|
||||
await this.ShowDialogAsync(new ViewModels.ConfigureCustomActionControls(act.Controls));
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,12 +56,7 @@ namespace SourceGit.Views
|
||||
if (sender is not Button { DataContext: Models.CustomAction act })
|
||||
return;
|
||||
|
||||
var dialog = new ConfigureCustomActionControls()
|
||||
{
|
||||
DataContext = new ViewModels.ConfigureCustomActionControls(act.Controls)
|
||||
};
|
||||
|
||||
await dialog.ShowDialog(this);
|
||||
await this.ShowDialogAsync(new ViewModels.ConfigureCustomActionControls(act.Controls));
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace SourceGit.Views
|
||||
{
|
||||
if (DataContext is ViewModels.Repository repo)
|
||||
{
|
||||
await App.ShowDialog(new ViewModels.Statistics(repo.FullPath));
|
||||
await this.ShowDialogAsync(new ViewModels.Statistics(repo.FullPath));
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
@@ -147,7 +147,7 @@ namespace SourceGit.Views
|
||||
{
|
||||
if (DataContext is ViewModels.Repository repo)
|
||||
{
|
||||
await App.ShowDialog(new ViewModels.RepositoryConfigure(repo));
|
||||
await this.ShowDialogAsync(new ViewModels.RepositoryConfigure(repo));
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
@@ -387,7 +387,7 @@ namespace SourceGit.Views
|
||||
{
|
||||
locks.Click += async (_, e) =>
|
||||
{
|
||||
await App.ShowDialog(new ViewModels.LFSLocks(repo, repo.Remotes[0].Name));
|
||||
await this.ShowDialogAsync(new ViewModels.LFSLocks(repo, repo.Remotes[0].Name));
|
||||
e.Handled = true;
|
||||
};
|
||||
}
|
||||
@@ -400,7 +400,7 @@ namespace SourceGit.Views
|
||||
lockRemote.Header = remoteName;
|
||||
lockRemote.Click += async (_, e) =>
|
||||
{
|
||||
await App.ShowDialog(new ViewModels.LFSLocks(repo, remoteName));
|
||||
await this.ShowDialogAsync(new ViewModels.LFSLocks(repo, remoteName));
|
||||
e.Handled = true;
|
||||
};
|
||||
locks.Items.Add(lockRemote);
|
||||
@@ -494,7 +494,7 @@ namespace SourceGit.Views
|
||||
{
|
||||
if (DataContext is ViewModels.Repository repo)
|
||||
{
|
||||
await App.ShowDialog(new ViewModels.ViewLogs(repo));
|
||||
await this.ShowDialogAsync(new ViewModels.ViewLogs(repo));
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,7 +472,7 @@ namespace SourceGit.Views
|
||||
history.Icon = this.CreateMenuIcon("Icons.Histories");
|
||||
history.Click += (_, ev) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.DirHistories(repo, path, commit.SHA));
|
||||
this.ShowWindow(new ViewModels.DirHistories(repo, path, commit.SHA));
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
@@ -601,7 +601,7 @@ namespace SourceGit.Views
|
||||
history.Icon = this.CreateMenuIcon("Icons.Histories");
|
||||
history.Click += (_, ev) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.FileHistories(repo.FullPath, file.Path, commit.SHA));
|
||||
this.ShowWindow(new ViewModels.FileHistories(repo.FullPath, file.Path, commit.SHA));
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
@@ -611,7 +611,7 @@ namespace SourceGit.Views
|
||||
blame.IsEnabled = file.Type == Models.ObjectType.Blob;
|
||||
blame.Click += (_, ev) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.Blame(repo.FullPath, file.Path, commit));
|
||||
this.ShowWindow(new ViewModels.Blame(repo.FullPath, file.Path, commit));
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
|
||||
193
src/Views/SubmoduleRevisionCompare.axaml
Normal file
193
src/Views/SubmoduleRevisionCompare.axaml
Normal file
@@ -0,0 +1,193 @@
|
||||
<v:ChromelessWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.SubmoduleRevisionCompare"
|
||||
x:DataType="vm:SubmoduleRevisionCompare"
|
||||
x:Name="ThisControl"
|
||||
Icon="/App.ico"
|
||||
Title="{DynamicResource Text.SubmoduleRevisionCompare}"
|
||||
MinWidth="1280" MinHeight="720">
|
||||
<Grid RowDefinitions="Auto,64,*">
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" Height="28" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
|
||||
<!-- Bottom border -->
|
||||
<Border Background="{DynamicResource Brush.TitleBar}"
|
||||
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border2}"
|
||||
DoubleTapped="MaximizeOrRestoreWindow"
|
||||
PointerPressed="BeginMoveWindow"/>
|
||||
|
||||
<Path Width="12" Height="12"
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
Data="{StaticResource Icons.Compare}"
|
||||
IsVisible="{OnPlatform True, macOS=False}"/>
|
||||
|
||||
<TextBlock Classes="bold"
|
||||
Text="{DynamicResource Text.SubmoduleRevisionCompare}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
IsHitTestVisible="False"/>
|
||||
|
||||
<!-- Caption Buttons (Windows/Linux) -->
|
||||
<v:CaptionButtons HorizontalAlignment="Right" IsVisible="{OnPlatform True, macOS=False}"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Compare Targets -->
|
||||
<Border Grid.Row="1">
|
||||
<Grid Margin="8" ColumnDefinitions="*,48,*">
|
||||
<Border Grid.Column="0" BorderBrush="{DynamicResource Brush.Diff.DeletedHighlight}" BorderThickness="1" Background="{DynamicResource Brush.Contents}" CornerRadius="4" Padding="4">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto,Auto">
|
||||
<v:Avatar Grid.Column="0"
|
||||
Width="16" Height="16"
|
||||
VerticalAlignment="Center"
|
||||
IsHitTestVisible="False"
|
||||
User="{Binding Base.Author}"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding Base.Author.Name}" Margin="8,0,0,0"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="{Binding Base.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}"
|
||||
Foreground="DarkOrange" Margin="8,0,0,0"
|
||||
TextDecorations="Underline"
|
||||
Cursor="Hand"/>
|
||||
<v:DateTimePresenter Grid.Column="3"
|
||||
Margin="8,0,0,0"
|
||||
Timestamp="{Binding Base.CommitterTime}"
|
||||
Foreground="{DynamicResource Brush.FG2}"/>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Row="1" Text="{Binding Base.Subject}" VerticalAlignment="Bottom"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Swap Button -->
|
||||
<Button Grid.Column="1" Classes="icon_button" Command="{Binding Swap}" HorizontalAlignment="Center" ToolTip.Tip="{DynamicResource Text.Diff.SwapCommits}">
|
||||
<Path Width="16" Height="16" Data="{DynamicResource Icons.Compare}"/>
|
||||
</Button>
|
||||
|
||||
<Border Grid.Column="2" BorderBrush="{DynamicResource Brush.Diff.AddedHighlight}" BorderThickness="1" Background="{DynamicResource Brush.Contents}" CornerRadius="4" Padding="4">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto,Auto">
|
||||
<v:Avatar Grid.Column="0"
|
||||
Width="16" Height="16"
|
||||
VerticalAlignment="Center"
|
||||
IsHitTestVisible="False"
|
||||
User="{Binding To.Author}"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding To.Author.Name}" Margin="8,0,0,0"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="{Binding To.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}"
|
||||
Foreground="DarkOrange"
|
||||
Margin="8,0,0,0"
|
||||
TextDecorations="Underline"
|
||||
Cursor="Hand"/>
|
||||
<v:DateTimePresenter Grid.Column="3"
|
||||
Margin="8,0,0,0"
|
||||
Timestamp="{Binding To.CommitterTime}"
|
||||
Foreground="{DynamicResource Brush.FG2}"/>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Row="1" Text="{Binding To.Subject}" VerticalAlignment="Bottom"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Changes -->
|
||||
<Border Grid.Row="2">
|
||||
<Grid Margin="8,0,8,8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="256" MinWidth="200" MaxWidth="480"/>
|
||||
<ColumnDefinition Width="4"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid Grid.Column="0" RowDefinitions="26,*,26">
|
||||
<!-- Search & Display Mode -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="*,18">
|
||||
<TextBox Grid.Column="0"
|
||||
x:Name="ChangeSearchBox"
|
||||
Height="26"
|
||||
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"
|
||||
Background="Transparent"
|
||||
CornerRadius="4"
|
||||
Watermark="{DynamicResource Text.CommitDetail.Changes.Search}"
|
||||
Text="{Binding SearchFilter, Mode=TwoWay}">
|
||||
<TextBox.InnerLeftContent>
|
||||
<Path Width="14" Height="14" Margin="4,0,0,0" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.Search}"/>
|
||||
</TextBox.InnerLeftContent>
|
||||
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button"
|
||||
IsVisible="{Binding SearchFilter, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||
Command="{Binding ClearSearchFilter}">
|
||||
<Path Width="14" Height="14" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.Clear}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
|
||||
<v:ChangeViewModeSwitcher Grid.Column="1"
|
||||
Width="14" Height="14"
|
||||
HorizontalAlignment="Right"
|
||||
ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=CommitChangeViewMode, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Changes -->
|
||||
<Border Grid.Row="1" Margin="0,4,0,0" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="1" Background="{DynamicResource Brush.Contents}">
|
||||
<v:ChangeCollectionView ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=CommitChangeViewMode}"
|
||||
EnableCompactFolders="{Binding Source={x:Static vm:Preferences.Instance}, Path=EnableCompactFoldersInChangesTree}"
|
||||
Changes="{Binding VisibleChanges}"
|
||||
SelectedChanges="{Binding SelectedChanges, Mode=TwoWay}"
|
||||
ContextRequested="OnChangeContextRequested"
|
||||
KeyDown="OnChangeCollectionViewKeyDown"/>
|
||||
</Border>
|
||||
|
||||
<!-- Loading Status Icon -->
|
||||
<v:LoadingIcon Grid.Row="1"
|
||||
Width="48" Height="48"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
IsVisible="{Binding IsLoading}"/>
|
||||
|
||||
<!-- Summary -->
|
||||
<Border Grid.Row="2" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="1,0,1,1" Background="Transparent">
|
||||
<TextBlock Margin="4,0,0,0"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Center">
|
||||
<Run Text="{Binding TotalChanges, Mode=OneWay}" FontWeight="Bold"/>
|
||||
<Run Text="{DynamicResource Text.CommitDetail.Changes.Count}"/>
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<GridSplitter Grid.Column="1"
|
||||
MinWidth="1"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
||||
Background="Transparent"
|
||||
Focusable="False"/>
|
||||
|
||||
<Grid Grid.Column="2">
|
||||
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}">
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
|
||||
<Path Width="64" Height="64" Data="{StaticResource Icons.Diff}" Fill="{DynamicResource Brush.FG2}"/>
|
||||
<TextBlock Margin="0,16,0,0"
|
||||
Text="{DynamicResource Text.Diff.Welcome}"
|
||||
FontSize="18" FontWeight="Bold"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<ContentControl Content="{Binding DiffContext}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="vm:DiffContext">
|
||||
<v:DiffView/>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</v:ChromelessWindow>
|
||||
190
src/Views/SubmoduleRevisionCompare.axaml.cs
Normal file
190
src/Views/SubmoduleRevisionCompare.axaml.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Platform.Storage;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class SubmoduleRevisionCompare : ChromelessWindow
|
||||
{
|
||||
public SubmoduleRevisionCompare()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void OnChangeContextRequested(object sender, ContextRequestedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.SubmoduleRevisionCompare { SelectedChanges: { Count: > 0 } selected } vm &&
|
||||
sender is ChangeCollectionView view)
|
||||
{
|
||||
var menu = new ContextMenu();
|
||||
|
||||
var patch = new MenuItem();
|
||||
patch.Header = App.Text("FileCM.SaveAsPatch");
|
||||
patch.Icon = this.CreateMenuIcon("Icons.Save");
|
||||
patch.Click += async (_, e) =>
|
||||
{
|
||||
var storageProvider = this.StorageProvider;
|
||||
if (storageProvider == null)
|
||||
return;
|
||||
|
||||
var options = new FilePickerSaveOptions();
|
||||
options.Title = App.Text("FileCM.SaveAsPatch");
|
||||
options.DefaultExtension = ".patch";
|
||||
options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }];
|
||||
|
||||
try
|
||||
{
|
||||
var storageFile = await storageProvider.SaveFilePickerAsync(options);
|
||||
if (storageFile != null)
|
||||
{
|
||||
var saveTo = storageFile.Path.LocalPath;
|
||||
var succ = await vm.SaveChangesAsPatchAsync(selected, saveTo);
|
||||
if (succ)
|
||||
await new Alert().ShowAsync(this, "Save patch successfully.", false);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
await new Alert().ShowAsync(this, $"Failed to save as patch: {exception.Message}", true);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
if (selected.Count == 1)
|
||||
{
|
||||
var change = selected[0];
|
||||
var openWithMerger = new MenuItem();
|
||||
openWithMerger.Header = App.Text("OpenInExternalMergeTool");
|
||||
openWithMerger.Icon = this.CreateMenuIcon("Icons.OpenWith");
|
||||
openWithMerger.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+D" : "Ctrl+Shift+D";
|
||||
openWithMerger.Click += (_, ev) =>
|
||||
{
|
||||
vm.OpenInExternalDiffTool(change);
|
||||
ev.Handled = true;
|
||||
};
|
||||
menu.Items.Add(openWithMerger);
|
||||
|
||||
if (change.Index != Models.ChangeState.Deleted)
|
||||
{
|
||||
var full = vm.GetAbsPath(change.Path);
|
||||
var explore = new MenuItem();
|
||||
explore.Header = App.Text("RevealFile");
|
||||
explore.Icon = this.CreateMenuIcon("Icons.Explore");
|
||||
explore.IsEnabled = File.Exists(full);
|
||||
explore.Click += (_, ev) =>
|
||||
{
|
||||
Native.OS.OpenInFileManager(full);
|
||||
ev.Handled = true;
|
||||
};
|
||||
menu.Items.Add(explore);
|
||||
}
|
||||
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
menu.Items.Add(patch);
|
||||
|
||||
var copyPath = new MenuItem();
|
||||
copyPath.Header = App.Text("CopyPath");
|
||||
copyPath.Icon = this.CreateMenuIcon("Icons.Copy");
|
||||
copyPath.Tag = OperatingSystem.IsMacOS() ? "⌘+C" : "Ctrl+C";
|
||||
copyPath.Click += async (_, ev) =>
|
||||
{
|
||||
await this.CopyTextAsync(change.Path);
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
var copyFullPath = new MenuItem();
|
||||
copyFullPath.Header = App.Text("CopyFullPath");
|
||||
copyFullPath.Icon = this.CreateMenuIcon("Icons.Copy");
|
||||
copyFullPath.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+C" : "Ctrl+Shift+C";
|
||||
copyFullPath.Click += async (_, ev) =>
|
||||
{
|
||||
await this.CopyTextAsync(vm.GetAbsPath(change.Path));
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
menu.Items.Add(copyPath);
|
||||
menu.Items.Add(copyFullPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu.Items.Add(patch);
|
||||
|
||||
var copyPath = new MenuItem();
|
||||
copyPath.Header = App.Text("CopyPath");
|
||||
copyPath.Icon = this.CreateMenuIcon("Icons.Copy");
|
||||
copyPath.Tag = OperatingSystem.IsMacOS() ? "⌘+C" : "Ctrl+C";
|
||||
copyPath.Click += async (_, ev) =>
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
foreach (var c in selected)
|
||||
builder.AppendLine(c.Path);
|
||||
|
||||
await this.CopyTextAsync(builder.ToString());
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
var copyFullPath = new MenuItem();
|
||||
copyFullPath.Header = App.Text("CopyFullPath");
|
||||
copyFullPath.Icon = this.CreateMenuIcon("Icons.Copy");
|
||||
copyFullPath.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+C" : "Ctrl+Shift+C";
|
||||
copyFullPath.Click += async (_, ev) =>
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
foreach (var c in selected)
|
||||
builder.AppendLine(vm.GetAbsPath(c.Path));
|
||||
|
||||
await this.CopyTextAsync(builder.ToString());
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
menu.Items.Add(copyPath);
|
||||
menu.Items.Add(copyFullPath);
|
||||
}
|
||||
|
||||
menu.Open(view);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private async void OnChangeCollectionViewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (DataContext is not ViewModels.SubmoduleRevisionCompare vm)
|
||||
return;
|
||||
|
||||
if (sender is not ChangeCollectionView { SelectedChanges: { Count: > 0 } selectedChanges })
|
||||
return;
|
||||
|
||||
var cmdKey = OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control;
|
||||
if (e.Key == Key.C && e.KeyModifiers.HasFlag(cmdKey))
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
var copyAbsPath = e.KeyModifiers.HasFlag(KeyModifiers.Shift);
|
||||
if (selectedChanges.Count == 1)
|
||||
{
|
||||
builder.Append(copyAbsPath ? vm.GetAbsPath(selectedChanges[0].Path) : selectedChanges[0].Path);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var c in selectedChanges)
|
||||
builder.AppendLine(copyAbsPath ? vm.GetAbsPath(c.Path) : c.Path);
|
||||
}
|
||||
|
||||
await this.CopyTextAsync(builder.ToString());
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == Key.F && e.KeyModifiers == cmdKey)
|
||||
{
|
||||
ChangeSearchBox.Focus();
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,7 +257,7 @@ namespace SourceGit.Views
|
||||
histories.Icon = this.CreateMenuIcon("Icons.Histories");
|
||||
histories.Click += (_, ev) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.FileHistories(repo.FullPath, submodule.Path));
|
||||
this.ShowWindow(new ViewModels.FileHistories(repo.FullPath, submodule.Path));
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -271,7 +271,7 @@ namespace SourceGit.Views
|
||||
compareWithHead.Icon = this.CreateMenuIcon("Icons.Compare");
|
||||
compareWithHead.Click += (_, _) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.Compare(repo, tag, repo.CurrentBranch));
|
||||
this.ShowWindow(new ViewModels.Compare(repo, tag, repo.CurrentBranch));
|
||||
};
|
||||
|
||||
var compareWith = new MenuItem();
|
||||
@@ -387,7 +387,7 @@ namespace SourceGit.Views
|
||||
if (based.CreatorDate > to.CreatorDate)
|
||||
(based, to) = (to, based);
|
||||
|
||||
App.ShowWindow(new ViewModels.Compare(repo, based, to));
|
||||
this.ShowWindow(new ViewModels.Compare(repo, based, to));
|
||||
ev.Handled = true;
|
||||
};
|
||||
menu.Items.Add(compare);
|
||||
|
||||
@@ -98,6 +98,23 @@ namespace SourceGit.Views
|
||||
}
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
if (DataContext is not ViewModels.TextDiffContext ctx)
|
||||
return new Size(0, 0);
|
||||
|
||||
var typeface = new Typeface(TextArea.FontFamily);
|
||||
var test = new FormattedText(
|
||||
$"{ctx.Data.MaxLineNumber}",
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
TextArea.FontSize,
|
||||
Brushes.White);
|
||||
|
||||
return new Size(test.Width, 0);
|
||||
}
|
||||
|
||||
private readonly bool _usePresenter;
|
||||
private readonly bool _isOld;
|
||||
}
|
||||
@@ -578,29 +595,6 @@ namespace SourceGit.Views
|
||||
protected override void OnDataContextChanged(EventArgs e)
|
||||
{
|
||||
base.OnDataContextChanged(e);
|
||||
|
||||
if (DataContext is ViewModels.TextDiffContext ctx)
|
||||
{
|
||||
var typeface = new Typeface(FontFamily);
|
||||
var test = new FormattedText(
|
||||
$"{ctx.Data.MaxLineNumber}",
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
FontSize,
|
||||
Brushes.White);
|
||||
|
||||
var width = test.WidthIncludingTrailingWhitespace;
|
||||
foreach (var margin in TextArea.LeftMargins)
|
||||
{
|
||||
if (margin is LineNumberMargin lineNumberMargin)
|
||||
margin.Width = width;
|
||||
}
|
||||
|
||||
var dock = TextArea.FindDescendantOfType<DockPanel>();
|
||||
dock?.InvalidateArrange();
|
||||
}
|
||||
|
||||
AutoScrollToFirstChange();
|
||||
}
|
||||
|
||||
@@ -721,6 +715,9 @@ namespace SourceGit.Views
|
||||
if (DataContext is not ViewModels.TextDiffContext ctx)
|
||||
return;
|
||||
|
||||
foreach (var margin in TextArea.LeftMargins)
|
||||
margin.InvalidateMeasure();
|
||||
|
||||
if (ctx.IsSideBySide() && !IsOld)
|
||||
return;
|
||||
|
||||
@@ -1495,17 +1492,17 @@ namespace SourceGit.Views
|
||||
var tmpFile = Path.GetTempFileName();
|
||||
if (change.WorkTree == Models.ChangeState.Untracked)
|
||||
{
|
||||
diff.GenerateNewPatchFromSelection(change, null, selection, false, tmpFile);
|
||||
diff.GenerateNewPatchFromSelection(change.Path, null, selection, false, tmpFile);
|
||||
}
|
||||
else if (chunk.Combined)
|
||||
{
|
||||
var treeGuid = await new Commands.QueryStagedFileBlobGuid(repo.FullPath, change.Path).GetResultAsync();
|
||||
diff.GeneratePatchFromSelection(change, treeGuid, selection, false, tmpFile);
|
||||
diff.GeneratePatchFromSelection(change.Path, treeGuid, selection, false, tmpFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
var treeGuid = await new Commands.QueryStagedFileBlobGuid(repo.FullPath, change.Path).GetResultAsync();
|
||||
diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, false, chunk.IsOldSide, tmpFile);
|
||||
diff.GeneratePatchFromSelectionSingleSide(change.Path, treeGuid, selection, false, chunk.IsOldSide, tmpFile);
|
||||
}
|
||||
|
||||
await new Commands.Apply(repo.FullPath, tmpFile, true, "nowarn", "--cache --index").ExecAsync();
|
||||
@@ -1533,11 +1530,11 @@ namespace SourceGit.Views
|
||||
var treeGuid = await new Commands.QueryStagedFileBlobGuid(repo.FullPath, change.Path).GetResultAsync();
|
||||
var tmpFile = Path.GetTempFileName();
|
||||
if (change.Index == Models.ChangeState.Added)
|
||||
diff.GenerateNewPatchFromSelection(change, treeGuid, selection, true, tmpFile);
|
||||
diff.GenerateNewPatchFromSelection(change.Path, treeGuid, selection, true, tmpFile);
|
||||
else if (chunk.Combined)
|
||||
diff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile);
|
||||
diff.GeneratePatchFromSelection(change.Path, treeGuid, selection, true, tmpFile);
|
||||
else
|
||||
diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, chunk.IsOldSide, tmpFile);
|
||||
diff.GeneratePatchFromSelectionSingleSide(change.Path, treeGuid, selection, true, chunk.IsOldSide, tmpFile);
|
||||
|
||||
await new Commands.Apply(repo.FullPath, tmpFile, true, "nowarn", "--cache --index --reverse").ExecAsync();
|
||||
File.Delete(tmpFile);
|
||||
@@ -1564,17 +1561,17 @@ namespace SourceGit.Views
|
||||
var tmpFile = Path.GetTempFileName();
|
||||
if (change.WorkTree == Models.ChangeState.Untracked)
|
||||
{
|
||||
diff.GenerateNewPatchFromSelection(change, null, selection, true, tmpFile);
|
||||
diff.GenerateNewPatchFromSelection(change.Path, null, selection, true, tmpFile);
|
||||
}
|
||||
else if (chunk.Combined)
|
||||
{
|
||||
var treeGuid = await new Commands.QueryStagedFileBlobGuid(repo.FullPath, change.Path).GetResultAsync();
|
||||
diff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile);
|
||||
diff.GeneratePatchFromSelection(change.Path, treeGuid, selection, true, tmpFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
var treeGuid = await new Commands.QueryStagedFileBlobGuid(repo.FullPath, change.Path).GetResultAsync();
|
||||
diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, chunk.IsOldSide, tmpFile);
|
||||
diff.GeneratePatchFromSelectionSingleSide(change.Path, treeGuid, selection, true, chunk.IsOldSide, tmpFile);
|
||||
}
|
||||
|
||||
await new Commands.Apply(repo.FullPath, tmpFile, true, "nowarn", "--reverse").ExecAsync();
|
||||
|
||||
@@ -19,7 +19,14 @@
|
||||
<Path Width="16" Height="16" Data="{StaticResource Icons.Clone}" Margin="0,4,0,0"/>
|
||||
</Button>
|
||||
|
||||
<Button Classes="icon_button" Width="32" Click="OpenLocalRepository" ToolTip.Tip="{DynamicResource Text.Welcome.OpenOrInit}">
|
||||
<Button Classes="icon_button" Width="32" Command="{Binding OpenLocalRepository}">
|
||||
<ToolTip.Tip>
|
||||
<TextBlock>
|
||||
<Run Text="{DynamicResource Text.Welcome.OpenOrInit}"/>
|
||||
<Run Text=" "/>
|
||||
<Run Text="{OnPlatform Ctrl+Shift+O, macOS=⌘+⇧+O}" FontSize="11" Foreground="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForeground}"/>
|
||||
</TextBlock>
|
||||
</ToolTip.Tip>
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Folder.Open}" Margin="0,2,0,0"/>
|
||||
</Button>
|
||||
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Platform.Storage;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
@@ -13,56 +8,5 @@ namespace SourceGit.Views
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void OpenLocalRepository(object _1, RoutedEventArgs e)
|
||||
{
|
||||
var activePage = App.GetLauncher().ActivePage;
|
||||
if (activePage == null || !activePage.CanCreatePopup())
|
||||
return;
|
||||
|
||||
var topLevel = TopLevel.GetTopLevel(this);
|
||||
if (topLevel == null)
|
||||
return;
|
||||
|
||||
var preference = ViewModels.Preferences.Instance;
|
||||
var workspace = preference.GetActiveWorkspace();
|
||||
var initDir = workspace.DefaultCloneDir;
|
||||
if (string.IsNullOrEmpty(initDir) || !Directory.Exists(initDir))
|
||||
initDir = preference.GitDefaultCloneDir;
|
||||
|
||||
var options = new FolderPickerOpenOptions() { AllowMultiple = false };
|
||||
if (Directory.Exists(initDir))
|
||||
{
|
||||
var folder = await topLevel.StorageProvider.TryGetFolderFromPathAsync(initDir);
|
||||
options.SuggestedStartLocation = folder;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var selected = await topLevel.StorageProvider.OpenFolderPickerAsync(options);
|
||||
if (selected.Count == 1)
|
||||
{
|
||||
var folder = selected[0];
|
||||
var folderPath = folder is { Path: { IsAbsoluteUri: true } path } ? path.LocalPath : folder?.Path.ToString();
|
||||
var repoPath = await ViewModels.Welcome.Instance.GetRepositoryRootAsync(folderPath);
|
||||
if (!string.IsNullOrEmpty(repoPath))
|
||||
{
|
||||
await ViewModels.Welcome.Instance.AddRepositoryAsync(repoPath, null, false, true);
|
||||
ViewModels.Welcome.Instance.Refresh();
|
||||
}
|
||||
else if (Directory.Exists(folderPath))
|
||||
{
|
||||
var test = await new Commands.QueryRepositoryRootPath(folderPath).GetResultAsync();
|
||||
ViewModels.Welcome.Instance.InitRepository(folderPath, null, test.StdErr);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Models.Notification.Send(null, $"Failed to open repository: {exception.Message}", true);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using Avalonia.Controls;
|
||||
@@ -33,7 +34,7 @@ namespace SourceGit.Views
|
||||
{
|
||||
var repoView = this.FindAncestorOfType<Repository>();
|
||||
if (repoView is { DataContext: ViewModels.Repository repo })
|
||||
await App.ShowDialog(new ViewModels.AssumeUnchangedManager(repo));
|
||||
await this.ShowDialogAsync(new ViewModels.AssumeUnchangedManager(repo));
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
@@ -359,7 +360,7 @@ namespace SourceGit.Views
|
||||
mergeBuiltin.Click += async (_, e) =>
|
||||
{
|
||||
var head = await new Commands.QuerySingleCommit(repo.FullPath, "HEAD").GetResultAsync();
|
||||
await App.ShowDialog(new ViewModels.MergeConflictEditor(repo, head, change.Path));
|
||||
await this.ShowDialogAsync(new ViewModels.MergeConflictEditor(repo, head, change.Path));
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -540,7 +541,7 @@ namespace SourceGit.Views
|
||||
hasExtra = true;
|
||||
}
|
||||
|
||||
if (repo.IsLFSEnabled())
|
||||
if (File.Exists(path) && repo.IsLFSEnabled())
|
||||
{
|
||||
var lfs = new MenuItem();
|
||||
lfs.Header = App.Text("GitLFS");
|
||||
@@ -647,7 +648,7 @@ namespace SourceGit.Views
|
||||
history.Icon = this.CreateMenuIcon("Icons.Histories");
|
||||
history.Click += (_, e) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.DirHistories(repo, selectedSingleFolder));
|
||||
this.ShowWindow(new ViewModels.DirHistories(repo, selectedSingleFolder));
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -661,7 +662,7 @@ namespace SourceGit.Views
|
||||
history.Icon = this.CreateMenuIcon("Icons.Histories");
|
||||
history.Click += (_, e) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.FileHistories(repo.FullPath, change.Path));
|
||||
this.ShowWindow(new ViewModels.FileHistories(repo.FullPath, change.Path));
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -671,7 +672,7 @@ namespace SourceGit.Views
|
||||
blame.Click += async (_, ev) =>
|
||||
{
|
||||
var commit = await new Commands.QuerySingleCommit(repo.FullPath, "HEAD").GetResultAsync();
|
||||
App.ShowWindow(new ViewModels.Blame(repo.FullPath, change.Path, commit));
|
||||
this.ShowWindow(new ViewModels.Blame(repo.FullPath, change.Path, commit));
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
@@ -871,7 +872,7 @@ namespace SourceGit.Views
|
||||
history.Icon = this.CreateMenuIcon("Icons.Histories");
|
||||
history.Click += (_, e) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.DirHistories(repo, selectedSingleFolder));
|
||||
this.ShowWindow(new ViewModels.DirHistories(repo, selectedSingleFolder));
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -927,9 +928,9 @@ namespace SourceGit.Views
|
||||
|
||||
if (services.Count == 1)
|
||||
{
|
||||
ai.Click += async (_, e) =>
|
||||
ai.Click += (_, e) =>
|
||||
{
|
||||
await App.ShowDialog(new ViewModels.AIAssistant(repo, services[0], selectedStaged));
|
||||
DoOpenAIAssistant(repo, services[0], selectedStaged);
|
||||
e.Handled = true;
|
||||
};
|
||||
}
|
||||
@@ -941,9 +942,9 @@ namespace SourceGit.Views
|
||||
|
||||
var item = new MenuItem();
|
||||
item.Header = service.Name;
|
||||
item.Click += async (_, e) =>
|
||||
item.Click += (_, e) =>
|
||||
{
|
||||
await App.ShowDialog(new ViewModels.AIAssistant(repo, dup, selectedStaged));
|
||||
DoOpenAIAssistant(repo, dup, selectedStaged);
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -1037,7 +1038,7 @@ namespace SourceGit.Views
|
||||
menu.Items.Add(patch);
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
|
||||
if (repo.IsLFSEnabled())
|
||||
if (File.Exists(path) && repo.IsLFSEnabled())
|
||||
{
|
||||
var lfs = new MenuItem();
|
||||
lfs.Header = App.Text("GitLFS");
|
||||
@@ -1118,7 +1119,7 @@ namespace SourceGit.Views
|
||||
history.Icon = this.CreateMenuIcon("Icons.Histories");
|
||||
history.Click += (_, e) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.DirHistories(repo, selectedSingleFolder));
|
||||
this.ShowWindow(new ViewModels.DirHistories(repo, selectedSingleFolder));
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -1132,7 +1133,7 @@ namespace SourceGit.Views
|
||||
history.Icon = this.CreateMenuIcon("Icons.Histories");
|
||||
history.Click += (_, e) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.FileHistories(repo.FullPath, change.Path));
|
||||
this.ShowWindow(new ViewModels.FileHistories(repo.FullPath, change.Path));
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -1142,7 +1143,7 @@ namespace SourceGit.Views
|
||||
blame.Click += async (_, e) =>
|
||||
{
|
||||
var commit = await new Commands.QuerySingleCommit(repo.FullPath, "HEAD").GetResultAsync();
|
||||
App.ShowWindow(new ViewModels.Blame(repo.FullPath, change.Path, commit));
|
||||
this.ShowWindow(new ViewModels.Blame(repo.FullPath, change.Path, commit));
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -1262,7 +1263,7 @@ namespace SourceGit.Views
|
||||
history.Icon = this.CreateMenuIcon("Icons.Histories");
|
||||
history.Click += (_, e) =>
|
||||
{
|
||||
App.ShowWindow(new ViewModels.DirHistories(repo, selectedSingleFolder));
|
||||
this.ShowWindow(new ViewModels.DirHistories(repo, selectedSingleFolder));
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
@@ -1369,5 +1370,16 @@ namespace SourceGit.Views
|
||||
menu.Items.Add(custom);
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
}
|
||||
|
||||
private void DoOpenAIAssistant(ViewModels.Repository repo, AI.Service serivce, List<Models.Change> changes)
|
||||
{
|
||||
var owner = TopLevel.GetTopLevel(this) as Window;
|
||||
if (owner == null)
|
||||
return;
|
||||
|
||||
var assistant = new ViewModels.AIAssistant(repo, serivce, changes);
|
||||
var view = new AIAssistant() { DataContext = assistant };
|
||||
view.Show(owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user