From 18aaa0a1439b195b227e4b1ed9a46dc8a646f5c2 Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 18 Mar 2024 09:37:06 +0800 Subject: [PATCH] style: add .editorconfig for code formatting. see issu #25 --- .editorconfig | 364 +++++++++++ src/App.axaml.cs | 104 ++- src/Commands/Add.cs | 21 +- src/Commands/Apply.cs | 11 +- src/Commands/Archive.cs | 16 +- src/Commands/AssumeUnchanged.cs | 47 +- src/Commands/Blame.cs | 46 +- src/Commands/Branch.cs | 27 +- src/Commands/Checkout.cs | 39 +- src/Commands/CherryPick.cs | 11 +- src/Commands/Clean.cs | 17 +- src/Commands/Clone.cs | 23 +- src/Commands/Command.cs | 72 +- src/Commands/Commit.cs | 11 +- src/Commands/CompareRevisions.cs | 32 +- src/Commands/Config.cs | 61 +- src/Commands/Diff.cs | 131 ++-- src/Commands/Discard.cs | 36 +- src/Commands/Fetch.cs | 103 ++- src/Commands/FormatPatch.cs | 11 +- src/Commands/GC.cs | 16 +- src/Commands/GitFlow.cs | 89 +-- src/Commands/Init.cs | 11 +- src/Commands/IsBinary.cs | 14 +- src/Commands/IsLFSFiltered.cs | 14 +- src/Commands/LFS.cs | 30 +- src/Commands/Merge.cs | 16 +- src/Commands/MergeTool.cs | 49 +- src/Commands/Pull.cs | 23 +- src/Commands/Push.cs | 43 +- src/Commands/QueryBranches.cs | 48 +- src/Commands/QueryCommitChanges.cs | 32 +- src/Commands/QueryCommits.cs | 126 ++-- src/Commands/QueryFileContent.cs | 19 +- src/Commands/QueryFileSize.cs | 24 +- src/Commands/QueryGitDir.cs | 14 +- src/Commands/QueryLocalChanges.cs | 82 +-- src/Commands/QueryRemotes.cs | 22 +- src/Commands/QueryRepositoryRootPath.cs | 14 +- src/Commands/QueryRevisionObjects.cs | 32 +- src/Commands/QueryStagedFileBlobGuid.cs | 17 +- src/Commands/QueryStashChanges.cs | 34 +- src/Commands/QueryStashes.cs | 37 +- src/Commands/QuerySubmodules.cs | 27 +- src/Commands/QueryTags.cs | 32 +- src/Commands/Rebase.cs | 11 +- src/Commands/Remote.cs | 26 +- src/Commands/Reset.cs | 22 +- src/Commands/Restore.cs | 13 +- src/Commands/Revert.cs | 11 +- src/Commands/SaveChangesAsPatch.cs | 37 +- src/Commands/SaveRevisionFile.cs | 57 +- src/Commands/Stash.cs | 41 +- src/Commands/Statistics.cs | 19 +- src/Commands/Submodule.cs | 30 +- src/Commands/Tag.cs | 27 +- src/Commands/Version.cs | 14 +- src/Converters/BookmarkConverters.cs | 8 +- src/Converters/BoolConverters.cs | 8 +- src/Converters/BranchConverters.cs | 8 +- src/Converters/ChangeViewModeConverters.cs | 26 +- src/Converters/DecoratorTypeConverters.cs | 39 +- src/Converters/IntConverters.cs | 8 +- src/Converters/LauncherPageConverters.cs | 25 +- src/Converters/ListConverters.cs | 13 +- src/Converters/PathConverters.cs | 16 +- src/Converters/StringConverters.cs | 53 +- src/Converters/WindowStateConverters.cs | 49 +- src/Models/ApplyWhiteSpaceMode.cs | 11 +- src/Models/AvatarManager.cs | 110 ++-- src/Models/Blame.cs | 11 +- src/Models/Bookmarks.cs | 11 +- src/Models/Branch.cs | 8 +- src/Models/BranchTreeNode.cs | 125 ++-- src/Models/CRLFMode.cs | 11 +- src/Models/Change.cs | 36 +- src/Models/Commit.cs | 22 +- src/Models/CommitGraph.cs | 107 ++- src/Models/Decorator.cs | 14 +- src/Models/DiffOption.cs | 65 +- src/Models/DiffResult.cs | 355 +++++++--- src/Models/ExternalMergeTools.cs | 29 +- src/Models/GitFlow.cs | 20 +- src/Models/LFSObject.cs | 8 +- src/Models/Locales.cs | 11 +- src/Models/Notification.cs | 11 +- src/Models/Object.cs | 11 +- src/Models/Remote.cs | 24 +- src/Models/RevisionFile.cs | 17 +- src/Models/Stash.cs | 8 +- src/Models/Statistics.cs | 75 ++- src/Models/Tag.cs | 8 +- src/Models/TextInlineChange.cs | 150 +++-- src/Models/User.cs | 24 +- src/Models/Watcher.cs | 93 ++- src/Native/Linux.cs | 75 ++- src/Native/MacOS.cs | 49 +- src/Native/OS.cs | 69 +- src/Native/Windows.cs | 74 ++- src/ViewModels/AddRemote.cs | 55 +- src/ViewModels/AddSubmodule.cs | 40 +- src/ViewModels/Apply.cs | 37 +- src/ViewModels/Archive.cs | 38 +- src/ViewModels/AssumeUnchangedManager.cs | 32 +- src/ViewModels/Blame.cs | 42 +- src/ViewModels/Checkout.cs | 22 +- src/ViewModels/CherryPick.cs | 25 +- src/ViewModels/Cleanup.cs | 22 +- src/ViewModels/ClearStashes.cs | 19 +- src/ViewModels/Clone.cs | 70 +- src/ViewModels/CommitDetail.cs | 323 +++++---- src/ViewModels/CreateBranch.cs | 74 ++- src/ViewModels/CreateGroup.cs | 22 +- src/ViewModels/CreateTag.cs | 39 +- src/ViewModels/DeleteBranch.cs | 29 +- src/ViewModels/DeleteRemote.cs | 25 +- src/ViewModels/DeleteRepositoryNode.cs | 17 +- src/ViewModels/DeleteSubmodule.cs | 22 +- src/ViewModels/DeleteTag.cs | 25 +- src/ViewModels/DiffContext.cs | 95 ++- src/ViewModels/Discard.cs | 51 +- src/ViewModels/DropStash.cs | 19 +- src/ViewModels/EditRemote.cs | 66 +- src/ViewModels/EditRepositoryNode.cs | 31 +- src/ViewModels/FastForwardWithoutCheckout.cs | 25 +- src/ViewModels/Fetch.cs | 41 +- src/ViewModels/FileHistories.cs | 60 +- src/ViewModels/FileTreeNode.cs | 124 ++-- src/ViewModels/GitFlowFinish.cs | 47 +- src/ViewModels/GitFlowStart.cs | 59 +- src/ViewModels/Histories.cs | 260 +++++--- src/ViewModels/Init.cs | 28 +- src/ViewModels/InitGitFlow.cs | 54 +- src/ViewModels/Launcher.cs | 129 ++-- src/ViewModels/LauncherPage.cs | 43 +- src/ViewModels/Merge.cs | 37 +- src/ViewModels/Popup.cs | 40 +- src/ViewModels/PopupHost.cs | 49 +- src/ViewModels/Preference.cs | 201 ++++-- src/ViewModels/PruneRemote.cs | 22 +- src/ViewModels/Pull.cs | 91 ++- src/ViewModels/Push.cs | 107 ++- src/ViewModels/PushTag.cs | 28 +- src/ViewModels/Rebase.cs | 33 +- src/ViewModels/RenameBranch.cs | 37 +- src/ViewModels/Repository.cs | 567 ++++++++++------ src/ViewModels/RepositoryConfigure.cs | 46 +- src/ViewModels/RepositoryNode.cs | 57 +- src/ViewModels/Reset.cs | 42 +- src/ViewModels/Revert.cs | 25 +- src/ViewModels/RevisionCompare.cs | 132 ++-- src/ViewModels/Reword.cs | 25 +- src/ViewModels/Squash.cs | 28 +- src/ViewModels/StashChanges.cs | 41 +- src/ViewModels/StashesPage.cs | 116 ++-- src/ViewModels/Statistics.cs | 53 +- src/ViewModels/TwoSideTextDiff.cs | 54 +- src/ViewModels/Welcome.cs | 103 ++- src/ViewModels/WorkingCopy.cs | 429 ++++++++---- src/Views/About.axaml.cs | 32 +- src/Views/AddRemote.axaml.cs | 17 +- src/Views/AddSubmodule.axaml.cs | 11 +- src/Views/Apply.axaml.cs | 19 +- src/Views/Archive.axaml.cs | 19 +- src/Views/AssumeUnchangedManager.axaml.cs | 17 +- src/Views/Avatar.cs | 71 +- src/Views/Blame.axaml.cs | 191 ++++-- src/Views/CaptionButtons.axaml.cs | 30 +- src/Views/CaptionButtonsMacOS.axaml.cs | 30 +- src/Views/ChangeStatusIcon.cs | 64 +- src/Views/ChangeViewModeSwitcher.axaml.cs | 17 +- src/Views/Checkout.axaml.cs | 11 +- src/Views/CherryPick.axaml.cs | 11 +- src/Views/Cleanup.axaml.cs | 11 +- src/Views/ClearStashes.axaml.cs | 11 +- src/Views/Clone.axaml.cs | 23 +- src/Views/CommitBaseInfo.axaml.cs | 17 +- src/Views/CommitChanges.axaml.cs | 32 +- src/Views/CommitDetail.axaml.cs | 26 +- src/Views/CreateBranch.axaml.cs | 11 +- src/Views/CreateGroup.axaml.cs | 11 +- src/Views/CreateTag.axaml.cs | 11 +- src/Views/DeleteBranch.axaml.cs | 11 +- src/Views/DeleteRemote.axaml.cs | 11 +- src/Views/DeleteRepositoryNode.axaml.cs | 11 +- src/Views/DeleteSubmodule.axaml.cs | 11 +- src/Views/DeleteTag.axaml.cs | 11 +- src/Views/DiffView.axaml.cs | 11 +- src/Views/Discard.axaml.cs | 11 +- src/Views/DropStash.axaml.cs | 11 +- src/Views/EditRemote.axaml.cs | 17 +- src/Views/EditRepositoryNode.axaml.cs | 12 +- src/Views/FastForwardWithoutCheckout.axaml.cs | 11 +- src/Views/Fetch.axaml.cs | 11 +- src/Views/FileHistories.axaml.cs | 39 +- src/Views/GitFlowFinish.axaml.cs | 11 +- src/Views/GitFlowStart.axaml.cs | 11 +- src/Views/Histories.axaml.cs | 138 ++-- src/Views/Hotkeys.axaml.cs | 17 +- src/Views/Init.axaml.cs | 12 +- src/Views/InitGitFlow.axaml.cs | 11 +- src/Views/Launcher.axaml.cs | 203 ++++-- src/Views/Merge.axaml.cs | 11 +- src/Views/NameHighlightedTextBlock.cs | 54 +- src/Views/Preference.axaml.cs | 85 ++- src/Views/PruneRemote.axaml.cs | 11 +- src/Views/Pull.axaml.cs | 11 +- src/Views/Push.axaml.cs | 11 +- src/Views/PushTag.axaml.cs | 11 +- src/Views/Rebase.axaml.cs | 11 +- src/Views/RenameBranch.axaml.cs | 11 +- src/Views/Repository.axaml.cs | 191 ++++-- src/Views/RepositoryConfigure.axaml.cs | 11 +- src/Views/Reset.axaml.cs | 11 +- src/Views/Revert.axaml.cs | 11 +- src/Views/RevisionCompare.axaml.cs | 38 +- src/Views/RevisionFiles.axaml.cs | 78 ++- src/Views/Reword.axaml.cs | 11 +- src/Views/Squash.axaml.cs | 11 +- src/Views/StashChanges.axaml.cs | 11 +- src/Views/StashesPage.axaml.cs | 11 +- src/Views/Statistics.axaml.cs | 124 ++-- src/Views/TextDiffView.axaml.cs | 618 ++++++++++++------ src/Views/Welcome.axaml.cs | 145 ++-- src/Views/WorkingCopy.axaml.cs | 207 +++--- 225 files changed, 7781 insertions(+), 3911 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..b5f39e6a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,364 @@ +root = true + +# All files +[*] +indent_style = space + +# Xml files +[*.xml] +indent_size = 2 + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = false + +#### .NET Coding Conventions #### +[*.{cs,vb}] + +# Organize usings +dotnet_separate_import_directive_groups = true +dotnet_sort_system_directives_first = true +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false:silent +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_property = false:silent + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent + +# Expression-level preferences +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_object_initializer = true:suggestion +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion + +# Field preferences +dotnet_style_readonly_field = true:warning + +# Parameter preferences +dotnet_code_quality_unused_parameters = all:suggestion + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +#### C# Coding Conventions #### +[*.cs] + +# var preferences +csharp_style_var_elsewhere = false:silent +csharp_style_var_for_built_in_types = false:silent +csharp_style_var_when_type_is_apparent = false:silent + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_lambdas = true:suggestion +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_prefer_not_pattern = true:suggestion +csharp_style_prefer_pattern_matching = true:silent +csharp_style_prefer_switch_expression = true:suggestion + +# Null-checking preferences +csharp_style_conditional_delegate_call = true:suggestion + +# Modifier preferences +csharp_prefer_static_local_function = true:warning +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent + +# Code-block preferences +csharp_prefer_braces = true:silent +csharp_prefer_simple_using_statement = true:suggestion + +# Expression-level preferences +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:silent + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace:silent + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### +[*.{cs,vb}] + +# Naming rules + +dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.symbols = types_and_namespaces +dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.interfaces_should_be_ipascalcase.severity = suggestion +dotnet_naming_rule.interfaces_should_be_ipascalcase.symbols = interfaces +dotnet_naming_rule.interfaces_should_be_ipascalcase.style = ipascalcase + +dotnet_naming_rule.type_parameters_should_be_tpascalcase.severity = suggestion +dotnet_naming_rule.type_parameters_should_be_tpascalcase.symbols = type_parameters +dotnet_naming_rule.type_parameters_should_be_tpascalcase.style = tpascalcase + +dotnet_naming_rule.methods_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.methods_should_be_pascalcase.symbols = methods +dotnet_naming_rule.methods_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.properties_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.properties_should_be_pascalcase.symbols = properties +dotnet_naming_rule.properties_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.events_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.events_should_be_pascalcase.symbols = events +dotnet_naming_rule.events_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.local_variables_should_be_camelcase.severity = suggestion +dotnet_naming_rule.local_variables_should_be_camelcase.symbols = local_variables +dotnet_naming_rule.local_variables_should_be_camelcase.style = camelcase + +dotnet_naming_rule.local_constants_should_be_camelcase.severity = suggestion +dotnet_naming_rule.local_constants_should_be_camelcase.symbols = local_constants +dotnet_naming_rule.local_constants_should_be_camelcase.style = camelcase + +dotnet_naming_rule.parameters_should_be_camelcase.severity = suggestion +dotnet_naming_rule.parameters_should_be_camelcase.symbols = parameters +dotnet_naming_rule.parameters_should_be_camelcase.style = camelcase + +dotnet_naming_rule.public_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.public_fields_should_be_pascalcase.symbols = public_fields +dotnet_naming_rule.public_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.private_fields_should_be__camelcase.severity = suggestion +dotnet_naming_rule.private_fields_should_be__camelcase.symbols = private_fields +dotnet_naming_rule.private_fields_should_be__camelcase.style = _camelcase + +dotnet_naming_rule.private_static_fields_should_be_s_camelcase.severity = suggestion +dotnet_naming_rule.private_static_fields_should_be_s_camelcase.symbols = private_static_fields +dotnet_naming_rule.private_static_fields_should_be_s_camelcase.style = s_camelcase + +dotnet_naming_rule.public_constant_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.public_constant_fields_should_be_pascalcase.symbols = public_constant_fields +dotnet_naming_rule.public_constant_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.private_constant_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.private_constant_fields_should_be_pascalcase.symbols = private_constant_fields +dotnet_naming_rule.private_constant_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.symbols = public_static_readonly_fields +dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.symbols = private_static_readonly_fields +dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.enums_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.enums_should_be_pascalcase.symbols = enums +dotnet_naming_rule.enums_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.local_functions_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.local_functions_should_be_pascalcase.symbols = local_functions +dotnet_naming_rule.local_functions_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.non_field_members_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascalcase.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascalcase.style = pascalcase + +# Symbol specifications + +dotnet_naming_symbols.interfaces.applicable_kinds = interface +dotnet_naming_symbols.interfaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interfaces.required_modifiers = + +dotnet_naming_symbols.enums.applicable_kinds = enum +dotnet_naming_symbols.enums.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.enums.required_modifiers = + +dotnet_naming_symbols.events.applicable_kinds = event +dotnet_naming_symbols.events.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.events.required_modifiers = + +dotnet_naming_symbols.methods.applicable_kinds = method +dotnet_naming_symbols.methods.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.methods.required_modifiers = + +dotnet_naming_symbols.properties.applicable_kinds = property +dotnet_naming_symbols.properties.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.properties.required_modifiers = + +dotnet_naming_symbols.public_fields.applicable_kinds = field +dotnet_naming_symbols.public_fields.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_fields.required_modifiers = + +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_fields.required_modifiers = + +dotnet_naming_symbols.private_static_fields.applicable_kinds = field +dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_static_fields.required_modifiers = static + +dotnet_naming_symbols.types_and_namespaces.applicable_kinds = namespace, class, struct, interface, enum +dotnet_naming_symbols.types_and_namespaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types_and_namespaces.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +dotnet_naming_symbols.type_parameters.applicable_kinds = namespace +dotnet_naming_symbols.type_parameters.applicable_accessibilities = * +dotnet_naming_symbols.type_parameters.required_modifiers = + +dotnet_naming_symbols.private_constant_fields.applicable_kinds = field +dotnet_naming_symbols.private_constant_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_constant_fields.required_modifiers = const + +dotnet_naming_symbols.local_variables.applicable_kinds = local +dotnet_naming_symbols.local_variables.applicable_accessibilities = local +dotnet_naming_symbols.local_variables.required_modifiers = + +dotnet_naming_symbols.local_constants.applicable_kinds = local +dotnet_naming_symbols.local_constants.applicable_accessibilities = local +dotnet_naming_symbols.local_constants.required_modifiers = const + +dotnet_naming_symbols.parameters.applicable_kinds = parameter +dotnet_naming_symbols.parameters.applicable_accessibilities = * +dotnet_naming_symbols.parameters.required_modifiers = + +dotnet_naming_symbols.public_constant_fields.applicable_kinds = field +dotnet_naming_symbols.public_constant_fields.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_constant_fields.required_modifiers = const + +dotnet_naming_symbols.public_static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.public_static_readonly_fields.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_static_readonly_fields.required_modifiers = readonly, static + +dotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_static_readonly_fields.required_modifiers = readonly, static + +dotnet_naming_symbols.local_functions.applicable_kinds = local_function +dotnet_naming_symbols.local_functions.applicable_accessibilities = * +dotnet_naming_symbols.local_functions.required_modifiers = + +# Naming styles + +dotnet_naming_style.pascalcase.required_prefix = +dotnet_naming_style.pascalcase.required_suffix = +dotnet_naming_style.pascalcase.word_separator = +dotnet_naming_style.pascalcase.capitalization = pascal_case + +dotnet_naming_style.ipascalcase.required_prefix = I +dotnet_naming_style.ipascalcase.required_suffix = +dotnet_naming_style.ipascalcase.word_separator = +dotnet_naming_style.ipascalcase.capitalization = pascal_case + +dotnet_naming_style.tpascalcase.required_prefix = T +dotnet_naming_style.tpascalcase.required_suffix = +dotnet_naming_style.tpascalcase.word_separator = +dotnet_naming_style.tpascalcase.capitalization = pascal_case + +dotnet_naming_style._camelcase.required_prefix = _ +dotnet_naming_style._camelcase.required_suffix = +dotnet_naming_style._camelcase.word_separator = +dotnet_naming_style._camelcase.capitalization = camel_case + +dotnet_naming_style.camelcase.required_prefix = +dotnet_naming_style.camelcase.required_suffix = +dotnet_naming_style.camelcase.word_separator = +dotnet_naming_style.camelcase.capitalization = camel_case + +dotnet_naming_style.s_camelcase.required_prefix = s_ +dotnet_naming_style.s_camelcase.required_suffix = +dotnet_naming_style.s_camelcase.word_separator = +dotnet_naming_style.s_camelcase.capitalization = camel_case + diff --git a/src/App.axaml.cs b/src/App.axaml.cs index 60e44d7b..552a54cc 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -1,3 +1,8 @@ +using System; +using System.IO; +using System.Reflection; +using System.Text; + using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; @@ -6,19 +11,21 @@ using Avalonia.Markup.Xaml; using Avalonia.Media; using Avalonia.Media.Fonts; using Avalonia.Styling; -using System; -using System.IO; -using System.Reflection; -using System.Text; -namespace SourceGit { - public partial class App : Application { +namespace SourceGit +{ + public partial class App : Application + { [STAThread] - public static void Main(string[] args) { - try { + public static void Main(string[] args) + { + try + { BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); - } catch (Exception ex) { + } + catch (Exception ex) + { var builder = new StringBuilder(); builder.Append("Crash: "); builder.Append(ex.Message); @@ -36,14 +43,16 @@ namespace SourceGit { "SourceGit", $"crash_{time}.log"); File.WriteAllText(file, builder.ToString()); - } + } } - public static AppBuilder BuildAvaloniaApp() { + public static AppBuilder BuildAvaloniaApp() + { var builder = AppBuilder.Configure(); builder.UsePlatformDetect(); builder.LogToTrace(); - builder.ConfigureFonts(manager => { + builder.ConfigureFonts(manager => + { var monospace = new EmbeddedFontCollection( new Uri("fonts:SourceGit", UriKind.Absolute), new Uri("avares://SourceGit/Resources/Fonts", UriKind.Absolute)); @@ -54,28 +63,35 @@ namespace SourceGit { return builder; } - public static void RaiseException(string context, string message) { - if (Current is App app && app._notificationReceiver != null) { + public static void RaiseException(string context, string message) + { + if (Current is App app && app._notificationReceiver != null) + { var notice = new Models.Notification() { IsError = true, Message = message }; app._notificationReceiver.OnReceiveNotification(context, notice); } } - public static void SendNotification(string context, string message) { - if (Current is App app && app._notificationReceiver != null) { + public static void SendNotification(string context, string message) + { + if (Current is App app && app._notificationReceiver != null) + { var notice = new Models.Notification() { IsError = false, Message = message }; app._notificationReceiver.OnReceiveNotification(context, notice); } } - public static void SetLocale(string localeKey) { + public static void SetLocale(string localeKey) + { var app = Current as App; var targetLocale = app.Resources[localeKey] as ResourceDictionary; - if (targetLocale == null || targetLocale == app._activeLocale) { + if (targetLocale == null || targetLocale == app._activeLocale) + { return; } - if (app._activeLocale != null) { + if (app._activeLocale != null) + { app.Resources.MergedDictionaries.Remove(app._activeLocale); } @@ -83,31 +99,42 @@ namespace SourceGit { app._activeLocale = targetLocale; } - public static void SetTheme(string theme) { - if (theme.Equals("Light", StringComparison.OrdinalIgnoreCase)) { + public static void SetTheme(string theme) + { + if (theme.Equals("Light", StringComparison.OrdinalIgnoreCase)) + { Current.RequestedThemeVariant = ThemeVariant.Light; - } else if (theme.Equals("Dark", StringComparison.OrdinalIgnoreCase)) { + } + else if (theme.Equals("Dark", StringComparison.OrdinalIgnoreCase)) + { Current.RequestedThemeVariant = ThemeVariant.Dark; - } else { + } + else + { Current.RequestedThemeVariant = ThemeVariant.Default; } } - public static async void CopyText(string data) { - if (Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - if (desktop.MainWindow.Clipboard is { } clipbord) { + public static async void CopyText(string data) + { + if (Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + if (desktop.MainWindow.Clipboard is { } clipbord) + { await clipbord.SetTextAsync(data); } } } - public static string Text(string key, params object[] args) { + public static string Text(string key, params object[] args) + { var fmt = Current.FindResource($"Text.{key}") as string; if (string.IsNullOrWhiteSpace(fmt)) return $"Text.{key}"; return string.Format(fmt, args); } - public static Avalonia.Controls.Shapes.Path CreateMenuIcon(string key) { + public static Avalonia.Controls.Shapes.Path CreateMenuIcon(string key) + { var icon = new Avalonia.Controls.Shapes.Path(); icon.Width = 12; icon.Height = 12; @@ -116,29 +143,36 @@ namespace SourceGit { return icon; } - public static TopLevel GetTopLevel() { - if (Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { + public static TopLevel GetTopLevel() + { + if (Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { return desktop.MainWindow; } return null; } - public static void Quit() { - if (Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { + public static void Quit() + { + if (Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { desktop.MainWindow.Close(); desktop.Shutdown(); } } - public override void Initialize() { + public override void Initialize() + { AvaloniaXamlLoader.Load(this); SetLocale(ViewModels.Preference.Instance.Locale); SetTheme(ViewModels.Preference.Instance.Theme); } - public override void OnFrameworkInitializationCompleted() { - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { BindingPlugins.DataValidators.RemoveAt(0); var launcher = new Views.Launcher(); diff --git a/src/Commands/Add.cs b/src/Commands/Add.cs index c83c330d..b5f02089 100644 --- a/src/Commands/Add.cs +++ b/src/Commands/Add.cs @@ -1,18 +1,25 @@ using System.Collections.Generic; using System.Text; -namespace SourceGit.Commands { - public class Add : Command { - public Add(string repo, List changes = null) { +namespace SourceGit.Commands +{ + public class Add : Command + { + public Add(string repo, List changes = null) + { WorkingDirectory = repo; Context = repo; - if (changes == null || changes.Count == 0) { + if (changes == null || changes.Count == 0) + { Args = "add ."; - } else { + } + else + { var builder = new StringBuilder(); builder.Append("add --"); - foreach (var c in changes) { + foreach (var c in changes) + { builder.Append(" \""); builder.Append(c.Path); builder.Append("\""); @@ -21,4 +28,4 @@ namespace SourceGit.Commands { } } } -} +} \ No newline at end of file diff --git a/src/Commands/Apply.cs b/src/Commands/Apply.cs index 1f550de4..e98ec601 100644 --- a/src/Commands/Apply.cs +++ b/src/Commands/Apply.cs @@ -1,6 +1,9 @@ -namespace SourceGit.Commands { - public class Apply : Command { - public Apply(string repo, string file, bool ignoreWhitespace, string whitespaceMode, string extra) { +namespace SourceGit.Commands +{ + public class Apply : Command + { + public Apply(string repo, string file, bool ignoreWhitespace, string whitespaceMode, string extra) + { WorkingDirectory = repo; Context = repo; Args = "apply "; @@ -10,4 +13,4 @@ Args += $"\"{file}\""; } } -} +} \ No newline at end of file diff --git a/src/Commands/Archive.cs b/src/Commands/Archive.cs index ac748653..065b9900 100644 --- a/src/Commands/Archive.cs +++ b/src/Commands/Archive.cs @@ -1,8 +1,11 @@ using System; -namespace SourceGit.Commands { - public class Archive : Command { - public Archive(string repo, string revision, string saveTo, Action outputHandler) { +namespace SourceGit.Commands +{ + public class Archive : Command + { + public Archive(string repo, string revision, string saveTo, Action outputHandler) + { WorkingDirectory = repo; Context = repo; Args = $"archive --format=zip --verbose --output=\"{saveTo}\" {revision}"; @@ -10,10 +13,11 @@ namespace SourceGit.Commands { _outputHandler = outputHandler; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { _outputHandler?.Invoke(line); } - private Action _outputHandler; + private readonly Action _outputHandler; } -} +} \ No newline at end of file diff --git a/src/Commands/AssumeUnchanged.cs b/src/Commands/AssumeUnchanged.cs index c1d7110e..936242b5 100644 --- a/src/Commands/AssumeUnchanged.cs +++ b/src/Commands/AssumeUnchanged.cs @@ -1,38 +1,47 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class AssumeUnchanged { - partial class ViewCommand : Command { - +namespace SourceGit.Commands +{ + public partial class AssumeUnchanged + { + partial class ViewCommand : Command + { + [GeneratedRegex(@"^(\w)\s+(.+)$")] private static partial Regex REG(); - public ViewCommand(string repo) { + public ViewCommand(string repo) + { WorkingDirectory = repo; Args = "ls-files -v"; RaiseError = false; } - public List Result() { + public List Result() + { Exec(); return _outs; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { var match = REG().Match(line); if (!match.Success) return; - if (match.Groups[1].Value == "h") { + if (match.Groups[1].Value == "h") + { _outs.Add(match.Groups[2].Value); } } - private List _outs = new List(); + private readonly List _outs = new List(); } - class ModCommand : Command { - public ModCommand(string repo, string file, bool bAdd) { + class ModCommand : Command + { + public ModCommand(string repo, string file, bool bAdd) + { var mode = bAdd ? "--assume-unchanged" : "--no-assume-unchanged"; WorkingDirectory = repo; @@ -41,22 +50,26 @@ namespace SourceGit.Commands { } } - public AssumeUnchanged(string repo) { + public AssumeUnchanged(string repo) + { _repo = repo; } - public List View() { + public List View() + { return new ViewCommand(_repo).Result(); } - public void Add(string file) { + public void Add(string file) + { new ModCommand(_repo, file, true).Exec(); } - public void Remove(string file) { + public void Remove(string file) + { new ModCommand(_repo, file, false).Exec(); } - private string _repo; + private readonly string _repo; } -} +} \ No newline at end of file diff --git a/src/Commands/Blame.cs b/src/Commands/Blame.cs index 99ff3923..ef3324e3 100644 --- a/src/Commands/Blame.cs +++ b/src/Commands/Blame.cs @@ -2,14 +2,17 @@ using System.Text; using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class Blame : Command { - +namespace SourceGit.Commands +{ + public partial class Blame : Command + { + [GeneratedRegex(@"^\^?([0-9a-f]+)\s+.*\((.*)\s+(\d+)\s+[\-\+]?\d+\s+\d+\) (.*)")] private static partial Regex REG_FORMAT(); private static readonly DateTime UTC_START = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime(); - public Blame(string repo, string file, string revision) { + public Blame(string repo, string file, string revision) + { WorkingDirectory = repo; Context = repo; Args = $"blame -t {revision} -- \"{file}\""; @@ -18,15 +21,20 @@ namespace SourceGit.Commands { _result.File = file; } - public Models.BlameData Result() { + public Models.BlameData Result() + { var succ = Exec(); - if (!succ) { + if (!succ) + { return new Models.BlameData(); } - if (_needUnifyCommitSHA) { - foreach (var line in _result.LineInfos) { - if (line.CommitSHA.Length > _minSHALen) { + if (_needUnifyCommitSHA) + { + foreach (var line in _result.LineInfos) + { + if (line.CommitSHA.Length > _minSHALen) + { line.CommitSHA = line.CommitSHA.Substring(0, _minSHALen); } } @@ -36,11 +44,13 @@ namespace SourceGit.Commands { return _result; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { if (_result.IsBinary) return; if (string.IsNullOrEmpty(line)) return; - if (line.IndexOf('\0', StringComparison.Ordinal) >= 0) { + if (line.IndexOf('\0', StringComparison.Ordinal) >= 0) + { _result.IsBinary = true; _result.LineInfos.Clear(); return; @@ -51,12 +61,13 @@ namespace SourceGit.Commands { _content.AppendLine(match.Groups[4].Value); - var commit = match.Groups[1].Value; + var commit = match.Groups[1].Value; var author = match.Groups[2].Value; var timestamp = int.Parse(match.Groups[3].Value); var when = UTC_START.AddSeconds(timestamp).ToString("yyyy/MM/dd"); - var info = new Models.BlameLineInfo() { + var info = new Models.BlameLineInfo() + { IsFirstInGroup = commit != _lastSHA, CommitSHA = commit, Author = author, @@ -66,16 +77,17 @@ namespace SourceGit.Commands { _result.LineInfos.Add(info); _lastSHA = commit; - if (line[0] == '^') { + if (line[0] == '^') + { _needUnifyCommitSHA = true; _minSHALen = Math.Min(_minSHALen, commit.Length); } } - private Models.BlameData _result = new Models.BlameData(); - private StringBuilder _content = new StringBuilder(); + private readonly Models.BlameData _result = new Models.BlameData(); + private readonly StringBuilder _content = new StringBuilder(); private string _lastSHA = string.Empty; private bool _needUnifyCommitSHA = false; private int _minSHALen = 64; } -} +} \ No newline at end of file diff --git a/src/Commands/Branch.cs b/src/Commands/Branch.cs index f109d1e4..aa3990c9 100644 --- a/src/Commands/Branch.cs +++ b/src/Commands/Branch.cs @@ -1,6 +1,9 @@ -namespace SourceGit.Commands { - public static class Branch { - public static bool Create(string repo, string name, string basedOn) { +namespace SourceGit.Commands +{ + public static class Branch + { + public static bool Create(string repo, string name, string basedOn) + { var cmd = new Command(); cmd.WorkingDirectory = repo; cmd.Context = repo; @@ -8,7 +11,8 @@ return cmd.Exec(); } - public static bool Rename(string repo, string name, string to) { + public static bool Rename(string repo, string name, string to) + { var cmd = new Command(); cmd.WorkingDirectory = repo; cmd.Context = repo; @@ -16,19 +20,24 @@ return cmd.Exec(); } - public static bool SetUpstream(string repo, string name, string upstream) { + public static bool SetUpstream(string repo, string name, string upstream) + { var cmd = new Command(); cmd.WorkingDirectory = repo; cmd.Context = repo; - if (string.IsNullOrEmpty(upstream)) { + if (string.IsNullOrEmpty(upstream)) + { cmd.Args = $"branch {name} --unset-upstream"; - } else { + } + else + { cmd.Args = $"branch {name} -u {upstream}"; } return cmd.Exec(); } - public static bool Delete(string repo, string name) { + public static bool Delete(string repo, string name) + { var cmd = new Command(); cmd.WorkingDirectory = repo; cmd.Context = repo; @@ -36,4 +45,4 @@ return cmd.Exec(); } } -} +} \ No newline at end of file diff --git a/src/Commands/Checkout.cs b/src/Commands/Checkout.cs index 14121fab..d6a9aba4 100644 --- a/src/Commands/Checkout.cs +++ b/src/Commands/Checkout.cs @@ -2,46 +2,58 @@ using System.Collections.Generic; using System.Text; -namespace SourceGit.Commands { - public class Checkout : Command { - public Checkout(string repo) { +namespace SourceGit.Commands +{ + public class Checkout : Command + { + public Checkout(string repo) + { WorkingDirectory = repo; Context = repo; } - public bool Branch(string branch, Action onProgress) { + public bool Branch(string branch, Action onProgress) + { Args = $"checkout --progress {branch}"; TraitErrorAsOutput = true; _outputHandler = onProgress; return Exec(); } - public bool Branch(string branch, string basedOn, Action onProgress) { + public bool Branch(string branch, string basedOn, Action onProgress) + { Args = $"checkout --progress -b {branch} {basedOn}"; TraitErrorAsOutput = true; _outputHandler = onProgress; return Exec(); } - public bool File(string file, bool useTheirs) { - if (useTheirs) { + public bool File(string file, bool useTheirs) + { + if (useTheirs) + { Args = $"checkout --theirs -- \"{file}\""; - } else { + } + else + { Args = $"checkout --ours -- \"{file}\""; } return Exec(); } - public bool FileWithRevision(string file, string revision) { + public bool FileWithRevision(string file, string revision) + { Args = $"checkout {revision} -- \"{file}\""; return Exec(); } - public bool Files(List files) { + public bool Files(List files) + { StringBuilder builder = new StringBuilder(); builder.Append("checkout -f -q --"); - foreach (var f in files) { + foreach (var f in files) + { builder.Append(" \""); builder.Append(f); builder.Append("\""); @@ -50,10 +62,11 @@ namespace SourceGit.Commands { return Exec(); } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { _outputHandler?.Invoke(line); } private Action _outputHandler; } -} +} \ No newline at end of file diff --git a/src/Commands/CherryPick.cs b/src/Commands/CherryPick.cs index 6160ebac..622202b4 100644 --- a/src/Commands/CherryPick.cs +++ b/src/Commands/CherryPick.cs @@ -1,10 +1,13 @@ -namespace SourceGit.Commands { - public class CherryPick : Command { - public CherryPick(string repo, string commit, bool noCommit) { +namespace SourceGit.Commands +{ + public class CherryPick : Command + { + public CherryPick(string repo, string commit, bool noCommit) + { var mode = noCommit ? "-n" : "--ff"; WorkingDirectory = repo; Context = repo; Args = $"cherry-pick {mode} {commit}"; } } -} +} \ No newline at end of file diff --git a/src/Commands/Clean.cs b/src/Commands/Clean.cs index 56a56a6c..5ef4570f 100644 --- a/src/Commands/Clean.cs +++ b/src/Commands/Clean.cs @@ -1,18 +1,23 @@ using System.Collections.Generic; using System.Text; -namespace SourceGit.Commands { - public class Clean : Command { - public Clean(string repo) { +namespace SourceGit.Commands +{ + public class Clean : Command + { + public Clean(string repo) + { WorkingDirectory = repo; Context = repo; Args = "clean -qfd"; } - public Clean(string repo, List files) { + public Clean(string repo, List files) + { StringBuilder builder = new StringBuilder(); builder.Append("clean -qfd --"); - foreach (var f in files) { + foreach (var f in files) + { builder.Append(" \""); builder.Append(f); builder.Append("\""); @@ -23,4 +28,4 @@ namespace SourceGit.Commands { Args = builder.ToString(); } } -} +} \ No newline at end of file diff --git a/src/Commands/Clone.cs b/src/Commands/Clone.cs index a6228e20..a8709138 100644 --- a/src/Commands/Clone.cs +++ b/src/Commands/Clone.cs @@ -1,17 +1,23 @@ using System; -namespace SourceGit.Commands { - public class Clone : Command { - private Action _notifyProgress; +namespace SourceGit.Commands +{ + public class Clone : Command + { + private readonly Action _notifyProgress; - public Clone(string ctx, string path, string url, string localName, string sshKey, string extraArgs, Action ouputHandler) { + public Clone(string ctx, string path, string url, string localName, string sshKey, string extraArgs, Action ouputHandler) + { Context = ctx; WorkingDirectory = path; TraitErrorAsOutput = true; - if (string.IsNullOrEmpty(sshKey)) { + if (string.IsNullOrEmpty(sshKey)) + { Args = "-c credential.helper=manager "; - } else { + } + else + { Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" "; } @@ -24,8 +30,9 @@ namespace SourceGit.Commands { _notifyProgress = ouputHandler; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { _notifyProgress?.Invoke(line); } } -} +} \ No newline at end of file diff --git a/src/Commands/Command.cs b/src/Commands/Command.cs index b0d630d0..2fa42b1a 100644 --- a/src/Commands/Command.cs +++ b/src/Commands/Command.cs @@ -1,17 +1,22 @@ -using Avalonia.Threading; using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class Command { - public class CancelToken { +using Avalonia.Threading; + +namespace SourceGit.Commands +{ + public partial class Command + { + public class CancelToken + { public bool Requested { get; set; } = false; } - public class ReadToEndResult { + public class ReadToEndResult + { public bool IsSuccess { get; set; } public string StdOut { get; set; } public string StdErr { get; set; } @@ -24,7 +29,8 @@ namespace SourceGit.Commands { public bool RaiseError { get; set; } = true; public bool TraitErrorAsOutput { get; set; } = false; - public bool Exec() { + public bool Exec() + { var start = new ProcessStartInfo(); start.FileName = Native.OS.GitInstallPath; start.Arguments = "--no-pager -c core.quotepath=off " + Args; @@ -41,8 +47,10 @@ namespace SourceGit.Commands { var proc = new Process() { StartInfo = start }; var isCancelled = false; - proc.OutputDataReceived += (_, e) => { - if (Cancel != null && Cancel.Requested) { + proc.OutputDataReceived += (_, e) => + { + if (Cancel != null && Cancel.Requested) + { isCancelled = true; proc.CancelErrorRead(); proc.CancelOutputRead(); @@ -53,8 +61,10 @@ namespace SourceGit.Commands { if (e.Data != null) OnReadline(e.Data); }; - proc.ErrorDataReceived += (_, e) => { - if (Cancel != null && Cancel.Requested) { + proc.ErrorDataReceived += (_, e) => + { + if (Cancel != null && Cancel.Requested) + { isCancelled = true; proc.CancelErrorRead(); proc.CancelOutputRead(); @@ -74,11 +84,16 @@ namespace SourceGit.Commands { errs.Add(e.Data); }; - try { + try + { proc.Start(); - } catch (Exception e) { - if (RaiseError) { - Dispatcher.UIThread.Invoke(() => { + } + catch (Exception e) + { + if (RaiseError) + { + Dispatcher.UIThread.Invoke(() => + { App.RaiseException(Context, e.Message); }); } @@ -92,19 +107,25 @@ namespace SourceGit.Commands { int exitCode = proc.ExitCode; proc.Close(); - if (!isCancelled && exitCode != 0 && errs.Count > 0) { - if (RaiseError) { - Dispatcher.UIThread.Invoke(() => { + if (!isCancelled && exitCode != 0 && errs.Count > 0) + { + if (RaiseError) + { + Dispatcher.UIThread.Invoke(() => + { App.RaiseException(Context, string.Join("\n", errs)); }); } return false; - } else { + } + else + { return true; } } - public ReadToEndResult ReadToEnd() { + public ReadToEndResult ReadToEnd() + { var start = new ProcessStartInfo(); start.FileName = Native.OS.GitInstallPath; start.Arguments = "--no-pager -c core.quotepath=off " + Args; @@ -118,17 +139,22 @@ namespace SourceGit.Commands { if (!string.IsNullOrEmpty(WorkingDirectory)) start.WorkingDirectory = WorkingDirectory; var proc = new Process() { StartInfo = start }; - try { + try + { proc.Start(); - } catch (Exception e) { - return new ReadToEndResult() { + } + catch (Exception e) + { + return new ReadToEndResult() + { IsSuccess = false, StdOut = string.Empty, StdErr = e.Message, }; } - var rs = new ReadToEndResult() { + var rs = new ReadToEndResult() + { StdOut = proc.StandardOutput.ReadToEnd(), StdErr = proc.StandardError.ReadToEnd(), }; diff --git a/src/Commands/Commit.cs b/src/Commands/Commit.cs index 2733590c..faa941c3 100644 --- a/src/Commands/Commit.cs +++ b/src/Commands/Commit.cs @@ -1,8 +1,11 @@ using System.IO; -namespace SourceGit.Commands { - public class Commit : Command { - public Commit(string repo, string message, bool amend, bool allowEmpty = false) { +namespace SourceGit.Commands +{ + public class Commit : Command + { + public Commit(string repo, string message, bool amend, bool allowEmpty = false) + { var file = Path.GetTempFileName(); File.WriteAllText(file, message); @@ -13,4 +16,4 @@ namespace SourceGit.Commands { if (allowEmpty) Args += " --allow-empty"; } } -} +} \ No newline at end of file diff --git a/src/Commands/CompareRevisions.cs b/src/Commands/CompareRevisions.cs index 66616ddb..7938df8e 100644 --- a/src/Commands/CompareRevisions.cs +++ b/src/Commands/CompareRevisions.cs @@ -1,39 +1,45 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class CompareRevisions : Command { +namespace SourceGit.Commands +{ + public partial class CompareRevisions : Command + { [GeneratedRegex(@"^(\s?[\w\?]{1,4})\s+(.+)$")] private static partial Regex REG_FORMAT(); - public CompareRevisions(string repo, string start, string end) { + public CompareRevisions(string repo, string start, string end) + { WorkingDirectory = repo; Context = repo; Args = $"diff --name-status {start} {end}"; } - public List Result() { + public List Result() + { Exec(); _changes.Sort((l, r) => l.Path.CompareTo(r.Path)); return _changes; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { var match = REG_FORMAT().Match(line); if (!match.Success) return; var change = new Models.Change() { Path = match.Groups[2].Value }; var status = match.Groups[1].Value; - switch (status[0]) { - case 'M': change.Set(Models.ChangeState.Modified); _changes.Add(change); break; - case 'A': change.Set(Models.ChangeState.Added); _changes.Add(change); break; - case 'D': change.Set(Models.ChangeState.Deleted); _changes.Add(change); break; - case 'R': change.Set(Models.ChangeState.Renamed); _changes.Add(change); break; - case 'C': change.Set(Models.ChangeState.Copied); _changes.Add(change); break; + switch (status[0]) + { + case 'M': change.Set(Models.ChangeState.Modified); _changes.Add(change); break; + case 'A': change.Set(Models.ChangeState.Added); _changes.Add(change); break; + case 'D': change.Set(Models.ChangeState.Deleted); _changes.Add(change); break; + case 'R': change.Set(Models.ChangeState.Renamed); _changes.Add(change); break; + case 'C': change.Set(Models.ChangeState.Copied); _changes.Add(change); break; } } - private List _changes = new List(); + private readonly List _changes = new List(); } -} +} \ No newline at end of file diff --git a/src/Commands/Config.cs b/src/Commands/Config.cs index dfd58e47..43723839 100644 --- a/src/Commands/Config.cs +++ b/src/Commands/Config.cs @@ -1,31 +1,41 @@ using System; using System.Collections.Generic; -namespace SourceGit.Commands { - public class Config : Command { - public Config(string repository) { +namespace SourceGit.Commands +{ + public class Config : Command + { + public Config(string repository) + { WorkingDirectory = repository; Context = repository; RaiseError = false; } - public Dictionary ListAll() { + public Dictionary ListAll() + { Args = "config -l"; var output = ReadToEnd(); var rs = new Dictionary(); - if (output.IsSuccess) { + if (output.IsSuccess) + { var lines = output.StdOut.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - foreach (var line in lines) { + foreach (var line in lines) + { var idx = line.IndexOf('=', StringComparison.Ordinal); - if (idx != -1) { + if (idx != -1) + { var key = line.Substring(0, idx).Trim(); - var val = line.Substring(idx+1).Trim(); - if (rs.ContainsKey(key)) { + var val = line.Substring(idx + 1).Trim(); + if (rs.ContainsKey(key)) + { rs[key] = val; - } else { + } + else + { rs.Add(key, val); - } + } } } } @@ -33,22 +43,33 @@ namespace SourceGit.Commands { return rs; } - public string Get(string key) { + public string Get(string key) + { Args = $"config {key}"; return ReadToEnd().StdOut.Trim(); } - public bool Set(string key, string value, bool allowEmpty = false) { - if (!allowEmpty && string.IsNullOrWhiteSpace(value)) { - if (string.IsNullOrEmpty(WorkingDirectory)) { + public bool Set(string key, string value, bool allowEmpty = false) + { + if (!allowEmpty && string.IsNullOrWhiteSpace(value)) + { + if (string.IsNullOrEmpty(WorkingDirectory)) + { Args = $"config --global --unset {key}"; - } else { + } + else + { Args = $"config --unset {key}"; } - } else { - if (string.IsNullOrWhiteSpace(WorkingDirectory)) { + } + else + { + if (string.IsNullOrWhiteSpace(WorkingDirectory)) + { Args = $"config --global {key} \"{value}\""; - } else { + } + else + { Args = $"config {key} \"{value}\""; } } @@ -56,4 +77,4 @@ namespace SourceGit.Commands { return Exec(); } } -} +} \ No newline at end of file diff --git a/src/Commands/Diff.cs b/src/Commands/Diff.cs index bcad4f4c..a35bd6e7 100644 --- a/src/Commands/Diff.cs +++ b/src/Commands/Diff.cs @@ -2,64 +2,89 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class Diff : Command { +namespace SourceGit.Commands +{ + public partial class Diff : Command + { [GeneratedRegex(@"^@@ \-(\d+),?\d* \+(\d+),?\d* @@")] private static partial Regex REG_INDICATOR(); private static readonly string PREFIX_LFS_NEW = "+version https://git-lfs.github.com/spec/"; private static readonly string PREFIX_LFS_DEL = "-version https://git-lfs.github.com/spec/"; private static readonly string PREFIX_LFS_MODIFY = " version https://git-lfs.github.com/spec/"; - public Diff(string repo, Models.DiffOption opt) { + public Diff(string repo, Models.DiffOption opt) + { WorkingDirectory = repo; Context = repo; Args = $"diff --ignore-cr-at-eol --unified=4 {opt}"; } - public Models.DiffResult Result() { + public Models.DiffResult Result() + { Exec(); - if (_result.IsBinary || _result.IsLFS) { + if (_result.IsBinary || _result.IsLFS) + { _result.TextDiff = null; - } else { + } + else + { ProcessInlineHighlights(); - if (_result.TextDiff.Lines.Count == 0) { + if (_result.TextDiff.Lines.Count == 0) + { _result.TextDiff = null; - } else { + } + else + { _result.TextDiff.MaxLineNumber = Math.Max(_newLine, _oldLine); - } + } } return _result; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { if (_result.IsBinary) return; - if (_result.IsLFS) { + if (_result.IsLFS) + { var ch = line[0]; - if (ch == '-') { - if (line.StartsWith("-oid sha256:", StringComparison.Ordinal)) { + if (ch == '-') + { + if (line.StartsWith("-oid sha256:", StringComparison.Ordinal)) + { _result.LFSDiff.Old.Oid = line.Substring(12); - } else if (line.StartsWith("-size ", StringComparison.Ordinal)) { + } + else if (line.StartsWith("-size ", StringComparison.Ordinal)) + { _result.LFSDiff.Old.Size = long.Parse(line.Substring(6)); } - } else if (ch == '+') { - if (line.StartsWith("+oid sha256:", StringComparison.Ordinal)) { + } + else if (ch == '+') + { + if (line.StartsWith("+oid sha256:", StringComparison.Ordinal)) + { _result.LFSDiff.New.Oid = line.Substring(12); - } else if (line.StartsWith("+size ", StringComparison.Ordinal)) { + } + else if (line.StartsWith("+size ", StringComparison.Ordinal)) + { _result.LFSDiff.New.Size = long.Parse(line.Substring(6)); } - } else if (line.StartsWith(" size ", StringComparison.Ordinal)) { + } + else if (line.StartsWith(" size ", StringComparison.Ordinal)) + { _result.LFSDiff.New.Size = _result.LFSDiff.Old.Size = long.Parse(line.Substring(6)); } return; } - if (_result.TextDiff.Lines.Count == 0) { + if (_result.TextDiff.Lines.Count == 0) + { var match = REG_INDICATOR().Match(line); - if (!match.Success) { + if (!match.Success) + { if (line.StartsWith("Binary", StringComparison.Ordinal)) _result.IsBinary = true; return; } @@ -67,8 +92,11 @@ namespace SourceGit.Commands { _oldLine = int.Parse(match.Groups[1].Value); _newLine = int.Parse(match.Groups[2].Value); _result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0)); - } else { - if (line.Length == 0) { + } + else + { + if (line.Length == 0) + { ProcessInlineHighlights(); _result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Normal, "", _oldLine, _newLine)); _oldLine++; @@ -77,8 +105,10 @@ namespace SourceGit.Commands { } var ch = line[0]; - if (ch == '-') { - if (_oldLine == 1 && _newLine == 0 && line.StartsWith(PREFIX_LFS_DEL, StringComparison.Ordinal)) { + if (ch == '-') + { + if (_oldLine == 1 && _newLine == 0 && line.StartsWith(PREFIX_LFS_DEL, StringComparison.Ordinal)) + { _result.IsLFS = true; _result.LFSDiff = new Models.LFSDiff(); return; @@ -86,8 +116,11 @@ namespace SourceGit.Commands { _deleted.Add(new Models.TextDiffLine(Models.TextDiffLineType.Deleted, line.Substring(1), _oldLine, 0)); _oldLine++; - } else if (ch == '+') { - if (_oldLine == 0 && _newLine == 1 && line.StartsWith(PREFIX_LFS_NEW, StringComparison.Ordinal)) { + } + else if (ch == '+') + { + if (_oldLine == 0 && _newLine == 1 && line.StartsWith(PREFIX_LFS_NEW, StringComparison.Ordinal)) + { _result.IsLFS = true; _result.LFSDiff = new Models.LFSDiff(); return; @@ -95,15 +128,21 @@ namespace SourceGit.Commands { _added.Add(new Models.TextDiffLine(Models.TextDiffLineType.Added, line.Substring(1), 0, _newLine)); _newLine++; - } else if (ch != '\\') { + } + else if (ch != '\\') + { ProcessInlineHighlights(); var match = REG_INDICATOR().Match(line); - if (match.Success) { + if (match.Success) + { _oldLine = int.Parse(match.Groups[1].Value); _newLine = int.Parse(match.Groups[2].Value); _result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0)); - } else { - if (_oldLine == 1 && _newLine == 1 && line.StartsWith(PREFIX_LFS_MODIFY, StringComparison.Ordinal)) { + } + else + { + if (_oldLine == 1 && _newLine == 1 && line.StartsWith(PREFIX_LFS_MODIFY, StringComparison.Ordinal)) + { _result.IsLFS = true; _result.LFSDiff = new Models.LFSDiff(); return; @@ -117,10 +156,14 @@ namespace SourceGit.Commands { } } - private void ProcessInlineHighlights() { - if (_deleted.Count > 0) { - if (_added.Count == _deleted.Count) { - for (int i = _added.Count - 1; i >= 0; i--) { + private void ProcessInlineHighlights() + { + if (_deleted.Count > 0) + { + if (_added.Count == _deleted.Count) + { + for (int i = _added.Count - 1; i >= 0; i--) + { var left = _deleted[i]; var right = _added[i]; @@ -129,12 +172,15 @@ namespace SourceGit.Commands { var chunks = Models.TextInlineChange.Compare(left.Content, right.Content); if (chunks.Count > 4) continue; - foreach (var chunk in chunks) { - if (chunk.DeletedCount > 0) { + foreach (var chunk in chunks) + { + if (chunk.DeletedCount > 0) + { left.Highlights.Add(new Models.TextInlineRange(chunk.DeletedStart, chunk.DeletedCount)); } - if (chunk.AddedCount > 0) { + if (chunk.AddedCount > 0) + { right.Highlights.Add(new Models.TextInlineRange(chunk.AddedStart, chunk.AddedCount)); } } @@ -145,16 +191,17 @@ namespace SourceGit.Commands { _deleted.Clear(); } - if (_added.Count > 0) { + if (_added.Count > 0) + { _result.TextDiff.Lines.AddRange(_added); _added.Clear(); } } - private Models.DiffResult _result = new Models.DiffResult() { TextDiff = new Models.TextDiff() }; - private List _deleted = new List(); - private List _added = new List(); + private readonly Models.DiffResult _result = new Models.DiffResult() { TextDiff = new Models.TextDiff() }; + private readonly List _deleted = new List(); + private readonly List _added = new List(); private int _oldLine = 0; private int _newLine = 0; } -} +} \ No newline at end of file diff --git a/src/Commands/Discard.cs b/src/Commands/Discard.cs index 95f118c9..11f174d6 100644 --- a/src/Commands/Discard.cs +++ b/src/Commands/Discard.cs @@ -1,38 +1,50 @@ using System; using System.Collections.Generic; -namespace SourceGit.Commands { - public static class Discard { - public static void All(string repo) { +namespace SourceGit.Commands +{ + public static class Discard + { + public static void All(string repo) + { new Reset(repo, "HEAD", "--hard").Exec(); new Clean(repo).Exec(); } - public static void ChangesInWorkTree(string repo, List changes) { + public static void ChangesInWorkTree(string repo, List changes) + { var needClean = new List(); var needCheckout = new List(); - foreach (var c in changes) { - if (c.WorkTree == Models.ChangeState.Untracked || c.WorkTree == Models.ChangeState.Added) { + foreach (var c in changes) + { + if (c.WorkTree == Models.ChangeState.Untracked || c.WorkTree == Models.ChangeState.Added) + { needClean.Add(c.Path); - } else { + } + else + { needCheckout.Add(c.Path); } } - for (int i = 0; i < needClean.Count; i += 10) { + for (int i = 0; i < needClean.Count; i += 10) + { var count = Math.Min(10, needClean.Count - i); new Clean(repo, needClean.GetRange(i, count)).Exec(); } - for (int i = 0; i < needCheckout.Count; i += 10) { + for (int i = 0; i < needCheckout.Count; i += 10) + { var count = Math.Min(10, needCheckout.Count - i); new Checkout(repo).Files(needCheckout.GetRange(i, count)); } } - public static void ChangesInStaged(string repo, List changes) { - for (int i = 0; i < changes.Count; i += 10) { + public static void ChangesInStaged(string repo, List changes) + { + for (int i = 0; i < changes.Count; i += 10) + { var count = Math.Min(10, changes.Count - i); var files = new List(); for (int j = 0; j < count; j++) files.Add(changes[i + j].Path); @@ -40,4 +52,4 @@ namespace SourceGit.Commands { } } } -} +} \ No newline at end of file diff --git a/src/Commands/Fetch.cs b/src/Commands/Fetch.cs index 1c5acebb..3b068d2d 100644 --- a/src/Commands/Fetch.cs +++ b/src/Commands/Fetch.cs @@ -3,18 +3,24 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -namespace SourceGit.Commands { - public class Fetch : Command { - public Fetch(string repo, string remote, bool prune, Action outputHandler) { +namespace SourceGit.Commands +{ + public class Fetch : Command + { + public Fetch(string repo, string remote, bool prune, Action outputHandler) + { _outputHandler = outputHandler; WorkingDirectory = repo; Context = repo; TraitErrorAsOutput = true; var sshKey = new Config(repo).Get($"remote.{remote}.sshkey"); - if (!string.IsNullOrEmpty(sshKey)) { + if (!string.IsNullOrEmpty(sshKey)) + { Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" "; - } else { + } + else + { Args = "-c credential.helper=manager "; } @@ -25,59 +31,75 @@ namespace SourceGit.Commands { AutoFetch.MarkFetched(repo); } - public Fetch(string repo, string remote, string localBranch, string remoteBranch, Action outputHandler) { + public Fetch(string repo, string remote, string localBranch, string remoteBranch, Action outputHandler) + { _outputHandler = outputHandler; WorkingDirectory = repo; Context = repo; TraitErrorAsOutput = true; var sshKey = new Config(repo).Get($"remote.{remote}.sshkey"); - if (!string.IsNullOrEmpty(sshKey)) { + if (!string.IsNullOrEmpty(sshKey)) + { Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" "; - } else { + } + else + { Args = "-c credential.helper=manager "; } Args += $"fetch --progress --verbose {remote} {remoteBranch}:{localBranch}"; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { _outputHandler?.Invoke(line); } - private Action _outputHandler; + private readonly Action _outputHandler; } - public class AutoFetch { - public static bool IsEnabled { + public class AutoFetch + { + public static bool IsEnabled + { get; set; } = false; - class Job { + class Job + { public Fetch Cmd = null; public DateTime NextRunTimepoint = DateTime.MinValue; } - static AutoFetch() { - Task.Run(() => { - while (true) { - if (!IsEnabled) { + static AutoFetch() + { + Task.Run(() => + { + while (true) + { + if (!IsEnabled) + { Thread.Sleep(10000); continue; } var now = DateTime.Now; var uptodate = new List(); - lock (_lock) { - foreach (var job in _jobs) { - if (job.Value.NextRunTimepoint.Subtract(now).TotalSeconds <= 0) { + lock (_lock) + { + foreach (var job in _jobs) + { + if (job.Value.NextRunTimepoint.Subtract(now).TotalSeconds <= 0) + { uptodate.Add(job.Value); } } } - foreach (var job in uptodate) { + foreach (var job in uptodate) + { job.Cmd.Exec(); job.NextRunTimepoint = DateTime.Now.AddSeconds(_fetchInterval); } @@ -87,37 +109,48 @@ namespace SourceGit.Commands { }); } - public static void AddRepository(string repo) { - var job = new Job { + public static void AddRepository(string repo) + { + var job = new Job + { Cmd = new Fetch(repo, "--all", true, null) { RaiseError = false }, NextRunTimepoint = DateTime.Now.AddSeconds(_fetchInterval), }; - lock (_lock) { - if (_jobs.ContainsKey(repo)) { + lock (_lock) + { + if (_jobs.ContainsKey(repo)) + { _jobs[repo] = job; - } else { + } + else + { _jobs.Add(repo, job); } } } - public static void RemoveRepository(string repo) { - lock (_lock) { + public static void RemoveRepository(string repo) + { + lock (_lock) + { _jobs.Remove(repo); } } - public static void MarkFetched(string repo) { - lock (_lock) { - if (_jobs.ContainsKey(repo)) { + public static void MarkFetched(string repo) + { + lock (_lock) + { + if (_jobs.ContainsKey(repo)) + { _jobs[repo].NextRunTimepoint = DateTime.Now.AddSeconds(_fetchInterval); } } } - private static Dictionary _jobs = new Dictionary(); - private static object _lock = new object(); - private static double _fetchInterval = 10 * 60; + private static readonly Dictionary _jobs = new Dictionary(); + private static readonly object _lock = new object(); + private static readonly double _fetchInterval = 10 * 60; } -} +} \ No newline at end of file diff --git a/src/Commands/FormatPatch.cs b/src/Commands/FormatPatch.cs index c139c477..5310115c 100644 --- a/src/Commands/FormatPatch.cs +++ b/src/Commands/FormatPatch.cs @@ -1,9 +1,12 @@ -namespace SourceGit.Commands { - public class FormatPatch : Command { - public FormatPatch(string repo, string commit, string saveTo) { +namespace SourceGit.Commands +{ + public class FormatPatch : Command + { + public FormatPatch(string repo, string commit, string saveTo) + { WorkingDirectory = repo; Context = repo; Args = $"format-patch {commit} -1 -o \"{saveTo}\""; } } -} +} \ No newline at end of file diff --git a/src/Commands/GC.cs b/src/Commands/GC.cs index 0c9d5761..a38f6147 100644 --- a/src/Commands/GC.cs +++ b/src/Commands/GC.cs @@ -1,8 +1,11 @@ using System; -namespace SourceGit.Commands { - public class GC : Command { - public GC(string repo, Action outputHandler) { +namespace SourceGit.Commands +{ + public class GC : Command + { + public GC(string repo, Action outputHandler) + { _outputHandler = outputHandler; WorkingDirectory = repo; Context = repo; @@ -10,10 +13,11 @@ namespace SourceGit.Commands { Args = "gc"; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { _outputHandler?.Invoke(line); } - private Action _outputHandler; + private readonly Action _outputHandler; } -} +} \ No newline at end of file diff --git a/src/Commands/GitFlow.cs b/src/Commands/GitFlow.cs index 0d277f58..3a52ed83 100644 --- a/src/Commands/GitFlow.cs +++ b/src/Commands/GitFlow.cs @@ -1,14 +1,19 @@ -using Avalonia.Threading; -using System.Collections.Generic; +using System.Collections.Generic; -namespace SourceGit.Commands { - public class GitFlow : Command { - public GitFlow(string repo) { +using Avalonia.Threading; + +namespace SourceGit.Commands +{ + public class GitFlow : Command + { + public GitFlow(string repo) + { WorkingDirectory = repo; Context = repo; } - public bool Init(List branches, string master, string develop, string feature, string release, string hotfix, string version) { + public bool Init(List branches, string master, string develop, string feature, string release, string hotfix, string version) + { var current = branches.Find(x => x.IsCurrent); var masterBranch = branches.Find(x => x.Name == master); @@ -31,47 +36,53 @@ namespace SourceGit.Commands { return Exec(); } - public bool Start(Models.GitFlowBranchType type, string name) { - switch (type) { - case Models.GitFlowBranchType.Feature: - Args = $"flow feature start {name}"; - break; - case Models.GitFlowBranchType.Release: - Args = $"flow release start {name}"; - break; - case Models.GitFlowBranchType.Hotfix: - Args = $"flow hotfix start {name}"; - break; - default: - Dispatcher.UIThread.Invoke(() => { - App.RaiseException(Context, "Bad branch type!!!"); - }); - return false; + public bool Start(Models.GitFlowBranchType type, string name) + { + switch (type) + { + case Models.GitFlowBranchType.Feature: + Args = $"flow feature start {name}"; + break; + case Models.GitFlowBranchType.Release: + Args = $"flow release start {name}"; + break; + case Models.GitFlowBranchType.Hotfix: + Args = $"flow hotfix start {name}"; + break; + default: + Dispatcher.UIThread.Invoke(() => + { + App.RaiseException(Context, "Bad branch type!!!"); + }); + return false; } return Exec(); } - public bool Finish(Models.GitFlowBranchType type, string name, bool keepBranch) { + public bool Finish(Models.GitFlowBranchType type, string name, bool keepBranch) + { var option = keepBranch ? "-k" : string.Empty; - switch (type) { - case Models.GitFlowBranchType.Feature: - Args = $"flow feature finish {option} {name}"; - break; - case Models.GitFlowBranchType.Release: - Args = $"flow release finish {option} {name} -m \"RELEASE_DONE\""; - break; - case Models.GitFlowBranchType.Hotfix: - Args = $"flow hotfix finish {option} {name} -m \"HOTFIX_DONE\""; - break; - default: - Dispatcher.UIThread.Invoke(() => { - App.RaiseException(Context, "Bad branch type!!!"); - }); - return false; + switch (type) + { + case Models.GitFlowBranchType.Feature: + Args = $"flow feature finish {option} {name}"; + break; + case Models.GitFlowBranchType.Release: + Args = $"flow release finish {option} {name} -m \"RELEASE_DONE\""; + break; + case Models.GitFlowBranchType.Hotfix: + Args = $"flow hotfix finish {option} {name} -m \"HOTFIX_DONE\""; + break; + default: + Dispatcher.UIThread.Invoke(() => + { + App.RaiseException(Context, "Bad branch type!!!"); + }); + return false; } return Exec(); } } -} +} \ No newline at end of file diff --git a/src/Commands/Init.cs b/src/Commands/Init.cs index f009ebe0..f0c03149 100644 --- a/src/Commands/Init.cs +++ b/src/Commands/Init.cs @@ -1,9 +1,12 @@ -namespace SourceGit.Commands { - public class Init : Command { - public Init(string ctx, string dir) { +namespace SourceGit.Commands +{ + public class Init : Command + { + public Init(string ctx, string dir) + { Context = ctx; WorkingDirectory = dir; Args = "init -q"; } } -} +} \ No newline at end of file diff --git a/src/Commands/IsBinary.cs b/src/Commands/IsBinary.cs index a3b92b4c..ef97eefc 100644 --- a/src/Commands/IsBinary.cs +++ b/src/Commands/IsBinary.cs @@ -1,19 +1,23 @@ using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class IsBinary : Command { +namespace SourceGit.Commands +{ + public partial class IsBinary : Command + { [GeneratedRegex(@"^\-\s+\-\s+.*$")] private static partial Regex REG_TEST(); - public IsBinary(string repo, string commit, string path) { + public IsBinary(string repo, string commit, string path) + { WorkingDirectory = repo; Context = repo; Args = $"diff 4b825dc642cb6eb9a060e54bf8d69288fbee4904 {commit} --numstat -- \"{path}\""; RaiseError = false; } - public bool Result() { + public bool Result() + { return REG_TEST().IsMatch(ReadToEnd().StdOut); } } -} +} \ No newline at end of file diff --git a/src/Commands/IsLFSFiltered.cs b/src/Commands/IsLFSFiltered.cs index 39e24654..33f9abfb 100644 --- a/src/Commands/IsLFSFiltered.cs +++ b/src/Commands/IsLFSFiltered.cs @@ -1,15 +1,19 @@ -namespace SourceGit.Commands { - public class IsLFSFiltered : Command { - public IsLFSFiltered(string repo, string path) { +namespace SourceGit.Commands +{ + public class IsLFSFiltered : Command + { + public IsLFSFiltered(string repo, string path) + { WorkingDirectory = repo; Context = repo; Args = $"check-attr -a -z \"{path}\""; RaiseError = false; } - public bool Result() { + public bool Result() + { var rs = ReadToEnd(); return rs.IsSuccess && rs.StdOut.Contains("filter\0lfs"); } } -} +} \ No newline at end of file diff --git a/src/Commands/LFS.cs b/src/Commands/LFS.cs index d632a25b..1b94ad75 100644 --- a/src/Commands/LFS.cs +++ b/src/Commands/LFS.cs @@ -1,10 +1,14 @@ using System; using System.IO; -namespace SourceGit.Commands { - public class LFS { - class PruneCmd : Command { - public PruneCmd(string repo, Action onProgress) { +namespace SourceGit.Commands +{ + public class LFS + { + class PruneCmd : Command + { + public PruneCmd(string repo, Action onProgress) + { WorkingDirectory = repo; Context = repo; Args = "lfs prune"; @@ -12,18 +16,21 @@ namespace SourceGit.Commands { _outputHandler = onProgress; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { _outputHandler?.Invoke(line); } - private Action _outputHandler; + private readonly Action _outputHandler; } - public LFS(string repo) { + public LFS(string repo) + { _repo = repo; } - public bool IsEnabled() { + public bool IsEnabled() + { var path = Path.Combine(_repo, ".git", "hooks", "pre-push"); if (!File.Exists(path)) return false; @@ -31,10 +38,11 @@ namespace SourceGit.Commands { return content.Contains("git lfs pre-push"); } - public void Prune(Action outputHandler) { + public void Prune(Action outputHandler) + { new PruneCmd(_repo, outputHandler).Exec(); } - private string _repo; + private readonly string _repo; } -} +} \ No newline at end of file diff --git a/src/Commands/Merge.cs b/src/Commands/Merge.cs index 9854e8c5..6c3eb934 100644 --- a/src/Commands/Merge.cs +++ b/src/Commands/Merge.cs @@ -1,8 +1,11 @@ using System; -namespace SourceGit.Commands { - public class Merge : Command { - public Merge(string repo, string source, string mode, Action outputHandler) { +namespace SourceGit.Commands +{ + public class Merge : Command + { + public Merge(string repo, string source, string mode, Action outputHandler) + { _outputHandler = outputHandler; WorkingDirectory = repo; Context = repo; @@ -10,10 +13,11 @@ namespace SourceGit.Commands { Args = $"merge --progress {source} {mode}"; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { _outputHandler?.Invoke(line); } - private Action _outputHandler = null; + private readonly Action _outputHandler = null; } -} +} \ No newline at end of file diff --git a/src/Commands/MergeTool.cs b/src/Commands/MergeTool.cs index d1857636..6701eb4b 100644 --- a/src/Commands/MergeTool.cs +++ b/src/Commands/MergeTool.cs @@ -1,20 +1,28 @@ -using Avalonia.Threading; -using System.IO; +using System.IO; -namespace SourceGit.Commands { - public static class MergeTool { - public static bool OpenForMerge(string repo, string tool, string mergeCmd, string file) { - if (string.IsNullOrWhiteSpace(tool) || string.IsNullOrWhiteSpace(mergeCmd)) { - Dispatcher.UIThread.Invoke(() => { +using Avalonia.Threading; + +namespace SourceGit.Commands +{ + public static class MergeTool + { + public static bool OpenForMerge(string repo, string tool, string mergeCmd, string file) + { + if (string.IsNullOrWhiteSpace(tool) || string.IsNullOrWhiteSpace(mergeCmd)) + { + Dispatcher.UIThread.Invoke(() => + { App.RaiseException(repo, "Invalid external merge tool settings!"); }); return false; } - if (!File.Exists(tool)) { - Dispatcher.UIThread.Invoke(() => { + if (!File.Exists(tool)) + { + Dispatcher.UIThread.Invoke(() => + { App.RaiseException(repo, $"Can NOT found external merge tool in '{tool}'!"); - }); + }); return false; } @@ -25,16 +33,21 @@ namespace SourceGit.Commands { return cmd.Exec(); } - public static bool OpenForDiff(string repo, string tool, string diffCmd, Models.DiffOption option) { - if (string.IsNullOrWhiteSpace(tool) || string.IsNullOrWhiteSpace(diffCmd)) { - Dispatcher.UIThread.Invoke(() => { + public static bool OpenForDiff(string repo, string tool, string diffCmd, Models.DiffOption option) + { + if (string.IsNullOrWhiteSpace(tool) || string.IsNullOrWhiteSpace(diffCmd)) + { + Dispatcher.UIThread.Invoke(() => + { App.RaiseException(repo, "Invalid external merge tool settings!"); - }); + }); return false; } - if (!File.Exists(tool)) { - Dispatcher.UIThread.Invoke(() => { + if (!File.Exists(tool)) + { + Dispatcher.UIThread.Invoke(() => + { App.RaiseException(repo, $"Can NOT found external merge tool in '{tool}'!"); }); return false; @@ -42,9 +55,9 @@ namespace SourceGit.Commands { var cmd = new Command(); cmd.WorkingDirectory = repo; - cmd.RaiseError = false; + cmd.RaiseError = false; cmd.Args = $"-c difftool.sourcegit.cmd=\"\\\"{tool}\\\" {diffCmd}\" difftool --tool=sourcegit --no-prompt {option}"; return cmd.Exec(); } } -} +} \ No newline at end of file diff --git a/src/Commands/Pull.cs b/src/Commands/Pull.cs index f9112206..1381e0fe 100644 --- a/src/Commands/Pull.cs +++ b/src/Commands/Pull.cs @@ -1,17 +1,23 @@ using System; -namespace SourceGit.Commands { - public class Pull : Command { - public Pull(string repo, string remote, string branch, bool useRebase, Action outputHandler) { +namespace SourceGit.Commands +{ + public class Pull : Command + { + public Pull(string repo, string remote, string branch, bool useRebase, Action outputHandler) + { _outputHandler = outputHandler; WorkingDirectory = repo; Context = repo; TraitErrorAsOutput = true; var sshKey = new Config(repo).Get($"remote.{remote}.sshkey"); - if (!string.IsNullOrEmpty(sshKey)) { + if (!string.IsNullOrEmpty(sshKey)) + { Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" "; - } else { + } + else + { Args = "-c credential.helper=manager "; } @@ -20,10 +26,11 @@ namespace SourceGit.Commands { Args += $"{remote} {branch}"; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { _outputHandler?.Invoke(line); } - private Action _outputHandler; + private readonly Action _outputHandler; } -} +} \ No newline at end of file diff --git a/src/Commands/Push.cs b/src/Commands/Push.cs index 8839666b..a15591f3 100644 --- a/src/Commands/Push.cs +++ b/src/Commands/Push.cs @@ -1,17 +1,23 @@ using System; -namespace SourceGit.Commands { - public class Push : Command { - public Push(string repo, string local, string remote, string remoteBranch, bool withTags, bool force, bool track, Action onProgress) { +namespace SourceGit.Commands +{ + public class Push : Command + { + public Push(string repo, string local, string remote, string remoteBranch, bool withTags, bool force, bool track, Action onProgress) + { WorkingDirectory = repo; Context = repo; TraitErrorAsOutput = true; _outputHandler = onProgress; var sshKey = new Config(repo).Get($"remote.{remote}.sshkey"); - if (!string.IsNullOrEmpty(sshKey)) { + if (!string.IsNullOrEmpty(sshKey)) + { Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" "; - } else { + } + else + { Args = "-c credential.helper=manager "; } @@ -30,29 +36,37 @@ namespace SourceGit.Commands { /// /// /// - public Push(string repo, string remote, string branch) { + public Push(string repo, string remote, string branch) + { WorkingDirectory = repo; Context = repo; TraitErrorAsOutput = true; var sshKey = new Config(repo).Get($"remote.{remote}.sshkey"); - if (!string.IsNullOrEmpty(sshKey)) { + if (!string.IsNullOrEmpty(sshKey)) + { Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" "; - } else { + } + else + { Args = "-c credential.helper=manager "; } Args += $"push {remote} --delete {branch}"; } - public Push(string repo, string remote, string tag, bool isDelete) { + public Push(string repo, string remote, string tag, bool isDelete) + { WorkingDirectory = repo; Context = repo; var sshKey = new Config(repo).Get($"remote.{remote}.sshkey"); - if (!string.IsNullOrEmpty(sshKey)) { + if (!string.IsNullOrEmpty(sshKey)) + { Args = $"-c core.sshCommand=\"ssh -i '{sshKey}'\" "; - } else { + } + else + { Args = "-c credential.helper=manager "; } @@ -61,10 +75,11 @@ namespace SourceGit.Commands { Args += $"{remote} refs/tags/{tag}"; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { _outputHandler?.Invoke(line); } - private Action _outputHandler = null; + private readonly Action _outputHandler = null; } -} +} \ No newline at end of file diff --git a/src/Commands/QueryBranches.cs b/src/Commands/QueryBranches.cs index 927d96c2..3b993831 100644 --- a/src/Commands/QueryBranches.cs +++ b/src/Commands/QueryBranches.cs @@ -2,28 +2,37 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class QueryBranches : Command { +namespace SourceGit.Commands +{ + public partial class QueryBranches : Command + { private static readonly string PREFIX_LOCAL = "refs/heads/"; private static readonly string PREFIX_REMOTE = "refs/remotes/"; - + [GeneratedRegex(@"^(\d+)\s(\d+)$")] private static partial Regex REG_AHEAD_BEHIND(); - public QueryBranches(string repo) { + public QueryBranches(string repo) + { WorkingDirectory = repo; Context = repo; Args = "branch -l --all -v --format=\"%(refname)$%(objectname)$%(HEAD)$%(upstream)$%(upstream:trackshort)\""; } - public List Result() { + public List Result() + { Exec(); - foreach (var b in _branches) { - if (b.IsLocal && !string.IsNullOrEmpty(b.UpstreamTrackStatus)) { - if (b.UpstreamTrackStatus == "=") { + foreach (var b in _branches) + { + if (b.IsLocal && !string.IsNullOrEmpty(b.UpstreamTrackStatus)) + { + if (b.UpstreamTrackStatus == "=") + { b.UpstreamTrackStatus = string.Empty; - } else { + } + else + { b.UpstreamTrackStatus = ParseTrackStatus(b.Name, b.Upstream); } } @@ -32,7 +41,8 @@ namespace SourceGit.Commands { return _branches; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { var parts = line.Split('$'); if (parts.Length != 5) return; @@ -40,10 +50,13 @@ namespace SourceGit.Commands { var refName = parts[0]; if (refName.EndsWith("/HEAD", StringComparison.Ordinal)) return; - if (refName.StartsWith(PREFIX_LOCAL, StringComparison.Ordinal)) { + if (refName.StartsWith(PREFIX_LOCAL, StringComparison.Ordinal)) + { branch.Name = refName.Substring(PREFIX_LOCAL.Length); branch.IsLocal = true; - } else if (refName.StartsWith(PREFIX_REMOTE, StringComparison.Ordinal)) { + } + else if (refName.StartsWith(PREFIX_REMOTE, StringComparison.Ordinal)) + { var name = refName.Substring(PREFIX_REMOTE.Length); var shortNameIdx = name.IndexOf('/', StringComparison.Ordinal); if (shortNameIdx < 0) return; @@ -51,7 +64,9 @@ namespace SourceGit.Commands { branch.Remote = name.Substring(0, shortNameIdx); branch.Name = name.Substring(branch.Remote.Length + 1); branch.IsLocal = false; - } else { + } + else + { branch.Name = refName; branch.IsLocal = true; } @@ -64,7 +79,8 @@ namespace SourceGit.Commands { _branches.Add(branch); } - private string ParseTrackStatus(string local, string upstream) { + private string ParseTrackStatus(string local, string upstream) + { var cmd = new Command(); cmd.WorkingDirectory = WorkingDirectory; cmd.Context = Context; @@ -84,6 +100,6 @@ namespace SourceGit.Commands { return track.Trim(); } - private List _branches = new List(); + private readonly List _branches = new List(); } -} +} \ No newline at end of file diff --git a/src/Commands/QueryCommitChanges.cs b/src/Commands/QueryCommitChanges.cs index 02fc7e48..b2edfdff 100644 --- a/src/Commands/QueryCommitChanges.cs +++ b/src/Commands/QueryCommitChanges.cs @@ -1,39 +1,45 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class QueryCommitChanges : Command { +namespace SourceGit.Commands +{ + public partial class QueryCommitChanges : Command + { [GeneratedRegex(@"^(\s?[\w\?]{1,4})\s+(.+)$")] private static partial Regex REG_FORMAT(); - public QueryCommitChanges(string repo, string commitSHA) { + public QueryCommitChanges(string repo, string commitSHA) + { WorkingDirectory = repo; Context = repo; Args = $"show --name-status {commitSHA}"; } - public List Result() { + public List Result() + { Exec(); _changes.Sort((l, r) => l.Path.CompareTo(r.Path)); return _changes; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { var match = REG_FORMAT().Match(line); if (!match.Success) return; var change = new Models.Change() { Path = match.Groups[2].Value }; var status = match.Groups[1].Value; - switch (status[0]) { - case 'M': change.Set(Models.ChangeState.Modified); _changes.Add(change); break; - case 'A': change.Set(Models.ChangeState.Added); _changes.Add(change); break; - case 'D': change.Set(Models.ChangeState.Deleted); _changes.Add(change); break; - case 'R': change.Set(Models.ChangeState.Renamed); _changes.Add(change); break; - case 'C': change.Set(Models.ChangeState.Copied); _changes.Add(change); break; + switch (status[0]) + { + case 'M': change.Set(Models.ChangeState.Modified); _changes.Add(change); break; + case 'A': change.Set(Models.ChangeState.Added); _changes.Add(change); break; + case 'D': change.Set(Models.ChangeState.Deleted); _changes.Add(change); break; + case 'R': change.Set(Models.ChangeState.Renamed); _changes.Add(change); break; + case 'C': change.Set(Models.ChangeState.Copied); _changes.Add(change); break; } } - private List _changes = new List(); + private readonly List _changes = new List(); } -} +} \ No newline at end of file diff --git a/src/Commands/QueryCommits.cs b/src/Commands/QueryCommits.cs index 81424409..e8c421f9 100644 --- a/src/Commands/QueryCommits.cs +++ b/src/Commands/QueryCommits.cs @@ -1,49 +1,61 @@ using System; using System.Collections.Generic; -namespace SourceGit.Commands { - public class QueryCommits : Command { +namespace SourceGit.Commands +{ + public class QueryCommits : Command + { private static readonly string GPGSIG_START = "gpgsig -----BEGIN PGP SIGNATURE-----"; private static readonly string GPGSIG_END = " -----END PGP SIGNATURE-----"; - private List commits = new List(); + private readonly List commits = new List(); private Models.Commit current = null; private bool isSkipingGpgsig = false; private bool isHeadFounded = false; - private bool findFirstMerged = true; + private readonly bool findFirstMerged = true; - public QueryCommits(string repo, string limits, bool needFindHead = true) { + public QueryCommits(string repo, string limits, bool needFindHead = true) + { WorkingDirectory = repo; Args = "log --date-order --decorate=full --pretty=raw " + limits; findFirstMerged = needFindHead; } - public List Result() { + public List Result() + { Exec(); - if (current != null) { + if (current != null) + { current.Message = current.Message.Trim(); commits.Add(current); } - if (findFirstMerged && !isHeadFounded && commits.Count > 0) { + if (findFirstMerged && !isHeadFounded && commits.Count > 0) + { MarkFirstMerged(); } return commits; } - protected override void OnReadline(string line) { - if (isSkipingGpgsig) { + protected override void OnReadline(string line) + { + if (isSkipingGpgsig) + { if (line.StartsWith(GPGSIG_END, StringComparison.Ordinal)) isSkipingGpgsig = false; return; - } else if (line.StartsWith(GPGSIG_START, StringComparison.Ordinal)) { + } + else if (line.StartsWith(GPGSIG_START, StringComparison.Ordinal)) + { isSkipingGpgsig = true; return; } - if (line.StartsWith("commit ", StringComparison.Ordinal)) { - if (current != null) { + if (line.StartsWith("commit ", StringComparison.Ordinal)) + { + if (current != null) + { current.Message = current.Message.Trim(); commits.Add(current); } @@ -52,9 +64,12 @@ namespace SourceGit.Commands { line = line.Substring(7); var decoratorStart = line.IndexOf('(', StringComparison.Ordinal); - if (decoratorStart < 0) { + if (decoratorStart < 0) + { current.SHA = line.Trim(); - } else { + } + else + { current.SHA = line.Substring(0, decoratorStart).Trim(); current.IsMerged = ParseDecorators(current.Decorators, line.Substring(decoratorStart + 1)); if (!isHeadFounded) isHeadFounded = current.IsMerged; @@ -65,65 +80,95 @@ namespace SourceGit.Commands { if (current == null) return; - if (line.StartsWith("tree ", StringComparison.Ordinal)) { + if (line.StartsWith("tree ", StringComparison.Ordinal)) + { return; - } else if (line.StartsWith("parent ", StringComparison.Ordinal)) { + } + else if (line.StartsWith("parent ", StringComparison.Ordinal)) + { current.Parents.Add(line.Substring("parent ".Length)); - } else if (line.StartsWith("author ", StringComparison.Ordinal)) { + } + else if (line.StartsWith("author ", StringComparison.Ordinal)) + { Models.User user = Models.User.Invalid; ulong time = 0; Models.Commit.ParseUserAndTime(line.Substring(7), ref user, ref time); current.Author = user; current.AuthorTime = time; - } else if (line.StartsWith("committer ", StringComparison.Ordinal)) { + } + else if (line.StartsWith("committer ", StringComparison.Ordinal)) + { Models.User user = Models.User.Invalid; ulong time = 0; Models.Commit.ParseUserAndTime(line.Substring(10), ref user, ref time); current.Committer = user; current.CommitterTime = time; - } else if (string.IsNullOrEmpty(current.Subject)) { + } + else if (string.IsNullOrEmpty(current.Subject)) + { current.Subject = line.Trim(); - } else { + } + else + { current.Message += (line.Trim() + "\n"); } } - private bool ParseDecorators(List decorators, string data) { + private bool ParseDecorators(List decorators, string data) + { bool isHeadOfCurrent = false; var subs = data.Split(new char[] { ',', ')', '(' }, StringSplitOptions.RemoveEmptyEntries); - foreach (var sub in subs) { + foreach (var sub in subs) + { var d = sub.Trim(); - if (d.StartsWith("tag: refs/tags/", StringComparison.Ordinal)) { - decorators.Add(new Models.Decorator() { + if (d.StartsWith("tag: refs/tags/", StringComparison.Ordinal)) + { + decorators.Add(new Models.Decorator() + { Type = Models.DecoratorType.Tag, Name = d.Substring(15).Trim(), }); - } else if (d.EndsWith("/HEAD", StringComparison.Ordinal)) { + } + else if (d.EndsWith("/HEAD", StringComparison.Ordinal)) + { continue; - } else if (d.StartsWith("HEAD -> refs/heads/", StringComparison.Ordinal)) { + } + else if (d.StartsWith("HEAD -> refs/heads/", StringComparison.Ordinal)) + { isHeadOfCurrent = true; - decorators.Add(new Models.Decorator() { + decorators.Add(new Models.Decorator() + { Type = Models.DecoratorType.CurrentBranchHead, Name = d.Substring(19).Trim(), }); - } else if (d.StartsWith("refs/heads/", StringComparison.Ordinal)) { - decorators.Add(new Models.Decorator() { + } + else if (d.StartsWith("refs/heads/", StringComparison.Ordinal)) + { + decorators.Add(new Models.Decorator() + { Type = Models.DecoratorType.LocalBranchHead, Name = d.Substring(11).Trim(), }); - } else if (d.StartsWith("refs/remotes/", StringComparison.Ordinal)) { - decorators.Add(new Models.Decorator() { + } + else if (d.StartsWith("refs/remotes/", StringComparison.Ordinal)) + { + decorators.Add(new Models.Decorator() + { Type = Models.DecoratorType.RemoteBranchHead, Name = d.Substring(13).Trim(), }); } } - decorators.Sort((l, r) => { - if (l.Type != r.Type) { + decorators.Sort((l, r) => + { + if (l.Type != r.Type) + { return (int)l.Type - (int)r.Type; - } else { + } + else + { return l.Name.CompareTo(r.Name); } }); @@ -131,7 +176,8 @@ namespace SourceGit.Commands { return isHeadOfCurrent; } - private void MarkFirstMerged() { + private void MarkFirstMerged() + { Args = $"log --since=\"{commits[commits.Count - 1].CommitterTimeStr}\" --format=\"%H\""; var rs = ReadToEnd(); @@ -141,12 +187,14 @@ namespace SourceGit.Commands { var set = new HashSet(); foreach (var sha in shas) set.Add(sha); - foreach (var c in commits) { - if (set.Contains(c.SHA)) { + foreach (var c in commits) + { + if (set.Contains(c.SHA)) + { c.IsMerged = true; break; } } } } -} +} \ No newline at end of file diff --git a/src/Commands/QueryFileContent.cs b/src/Commands/QueryFileContent.cs index 172134c5..e0898105 100644 --- a/src/Commands/QueryFileContent.cs +++ b/src/Commands/QueryFileContent.cs @@ -1,23 +1,28 @@ using System.Text; -namespace SourceGit.Commands { - public class QueryFileContent : Command { - public QueryFileContent(string repo, string revision, string file) { +namespace SourceGit.Commands +{ + public class QueryFileContent : Command + { + public QueryFileContent(string repo, string revision, string file) + { WorkingDirectory = repo; Context = repo; Args = $"show {revision}:\"{file}\""; } - public string Result() { + public string Result() + { Exec(); return _builder.ToString(); } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { _builder.Append(line); _builder.Append('\n'); } - private StringBuilder _builder = new StringBuilder(); + private readonly StringBuilder _builder = new StringBuilder(); } -} +} \ No newline at end of file diff --git a/src/Commands/QueryFileSize.cs b/src/Commands/QueryFileSize.cs index a75b1768..c2c031c6 100644 --- a/src/Commands/QueryFileSize.cs +++ b/src/Commands/QueryFileSize.cs @@ -1,24 +1,30 @@ using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class QueryFileSize : Command { - +namespace SourceGit.Commands +{ + public partial class QueryFileSize : Command + { + [GeneratedRegex(@"^\d+\s+\w+\s+[0-9a-f]+\s+(\d+)\s+.*$")] private static partial Regex REG_FORMAT(); - public QueryFileSize(string repo, string file, string revision) { + public QueryFileSize(string repo, string file, string revision) + { WorkingDirectory = repo; Context = repo; Args = $"ls-tree {revision} -l -- {file}"; } - public long Result() { + public long Result() + { if (_result != 0) return _result; var rs = ReadToEnd(); - if (rs.IsSuccess) { + if (rs.IsSuccess) + { var match = REG_FORMAT().Match(rs.StdOut); - if (match.Success) { + if (match.Success) + { return long.Parse(match.Groups[1].Value); } } @@ -26,6 +32,6 @@ namespace SourceGit.Commands { return 0; } - private long _result = 0; + private readonly long _result = 0; } -} +} \ No newline at end of file diff --git a/src/Commands/QueryGitDir.cs b/src/Commands/QueryGitDir.cs index dcdc216b..f7ed0cc0 100644 --- a/src/Commands/QueryGitDir.cs +++ b/src/Commands/QueryGitDir.cs @@ -1,14 +1,18 @@ using System.IO; -namespace SourceGit.Commands { - public class QueryGitDir : Command { - public QueryGitDir(string workDir) { +namespace SourceGit.Commands +{ + public class QueryGitDir : Command + { + public QueryGitDir(string workDir) + { WorkingDirectory = workDir; Args = "rev-parse --git-dir"; RaiseError = false; } - public string Result() { + public string Result() + { var rs = ReadToEnd().StdOut; if (string.IsNullOrEmpty(rs)) return null; @@ -17,4 +21,4 @@ namespace SourceGit.Commands { return Path.GetFullPath(Path.Combine(WorkingDirectory, rs)); } } -} +} \ No newline at end of file diff --git a/src/Commands/QueryLocalChanges.cs b/src/Commands/QueryLocalChanges.cs index 8b543b47..943f3a72 100644 --- a/src/Commands/QueryLocalChanges.cs +++ b/src/Commands/QueryLocalChanges.cs @@ -2,24 +2,29 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class QueryLocalChanges : Command { +namespace SourceGit.Commands +{ + public partial class QueryLocalChanges : Command + { [GeneratedRegex(@"^(\s?[\w\?]{1,4})\s+(.+)$")] private static partial Regex REG_FORMAT(); - private static readonly string[] UNTRACKED = [ "no", "all" ]; + private static readonly string[] UNTRACKED = ["no", "all"]; - public QueryLocalChanges(string repo, bool includeUntracked = true) { + public QueryLocalChanges(string repo, bool includeUntracked = true) + { WorkingDirectory = repo; Context = repo; Args = $"status -u{UNTRACKED[includeUntracked ? 1 : 0]} --ignore-submodules=dirty --porcelain"; } - public List Result() { + public List Result() + { Exec(); return _changes; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { var match = REG_FORMAT().Match(line); if (!match.Success) return; if (line.EndsWith("/", StringComparison.Ordinal)) return; // Ignore changes with git-worktree @@ -27,41 +32,42 @@ namespace SourceGit.Commands { var change = new Models.Change() { Path = match.Groups[2].Value }; var status = match.Groups[1].Value; - switch (status) { - case " M": change.Set(Models.ChangeState.None, Models.ChangeState.Modified); break; - case " A": change.Set(Models.ChangeState.None, Models.ChangeState.Added); break; - case " D": change.Set(Models.ChangeState.None, Models.ChangeState.Deleted); break; - case " R": change.Set(Models.ChangeState.None, Models.ChangeState.Renamed); break; - case " C": change.Set(Models.ChangeState.None, Models.ChangeState.Copied); break; - case "M": change.Set(Models.ChangeState.Modified, Models.ChangeState.None); break; - case "MM": change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified); break; - case "MD": change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted); break; - case "A": change.Set(Models.ChangeState.Added, Models.ChangeState.None); break; - case "AM": change.Set(Models.ChangeState.Added, Models.ChangeState.Modified); break; - case "AD": change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted); break; - case "D": change.Set(Models.ChangeState.Deleted, Models.ChangeState.None); break; - case "R": change.Set(Models.ChangeState.Renamed, Models.ChangeState.None); break; - case "RM": change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified); break; - case "RD": change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted); break; - case "C": change.Set(Models.ChangeState.Copied, Models.ChangeState.None); break; - case "CM": change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified); break; - case "CD": change.Set(Models.ChangeState.Copied, Models.ChangeState.Deleted); break; - case "DR": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Renamed); break; - case "DC": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Copied); break; - case "DD": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Deleted); break; - case "AU": change.Set(Models.ChangeState.Added, Models.ChangeState.Unmerged); break; - case "UD": change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Deleted); break; - case "UA": change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Added); break; - case "DU": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Unmerged); break; - case "AA": change.Set(Models.ChangeState.Added, Models.ChangeState.Added); break; - case "UU": change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Unmerged); break; - case "??": change.Set(Models.ChangeState.Untracked, Models.ChangeState.Untracked); break; - default: return; + switch (status) + { + case " M": change.Set(Models.ChangeState.None, Models.ChangeState.Modified); break; + case " A": change.Set(Models.ChangeState.None, Models.ChangeState.Added); break; + case " D": change.Set(Models.ChangeState.None, Models.ChangeState.Deleted); break; + case " R": change.Set(Models.ChangeState.None, Models.ChangeState.Renamed); break; + case " C": change.Set(Models.ChangeState.None, Models.ChangeState.Copied); break; + case "M": change.Set(Models.ChangeState.Modified, Models.ChangeState.None); break; + case "MM": change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified); break; + case "MD": change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted); break; + case "A": change.Set(Models.ChangeState.Added, Models.ChangeState.None); break; + case "AM": change.Set(Models.ChangeState.Added, Models.ChangeState.Modified); break; + case "AD": change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted); break; + case "D": change.Set(Models.ChangeState.Deleted, Models.ChangeState.None); break; + case "R": change.Set(Models.ChangeState.Renamed, Models.ChangeState.None); break; + case "RM": change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified); break; + case "RD": change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted); break; + case "C": change.Set(Models.ChangeState.Copied, Models.ChangeState.None); break; + case "CM": change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified); break; + case "CD": change.Set(Models.ChangeState.Copied, Models.ChangeState.Deleted); break; + case "DR": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Renamed); break; + case "DC": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Copied); break; + case "DD": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Deleted); break; + case "AU": change.Set(Models.ChangeState.Added, Models.ChangeState.Unmerged); break; + case "UD": change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Deleted); break; + case "UA": change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Added); break; + case "DU": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Unmerged); break; + case "AA": change.Set(Models.ChangeState.Added, Models.ChangeState.Added); break; + case "UU": change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Unmerged); break; + case "??": change.Set(Models.ChangeState.Untracked, Models.ChangeState.Untracked); break; + default: return; } _changes.Add(change); } - private List _changes = new List(); + private readonly List _changes = new List(); } -} +} \ No newline at end of file diff --git a/src/Commands/QueryRemotes.cs b/src/Commands/QueryRemotes.cs index f301339f..ed2a26e6 100644 --- a/src/Commands/QueryRemotes.cs +++ b/src/Commands/QueryRemotes.cs @@ -1,27 +1,33 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class QueryRemotes : Command { +namespace SourceGit.Commands +{ + public partial class QueryRemotes : Command + { [GeneratedRegex(@"^([\w\.\-]+)\s*(\S+).*$")] private static partial Regex REG_REMOTE(); - public QueryRemotes(string repo) { + public QueryRemotes(string repo) + { WorkingDirectory = repo; Context = repo; Args = "remote -v"; } - public List Result() { + public List Result() + { Exec(); return _loaded; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { var match = REG_REMOTE().Match(line); if (!match.Success) return; - var remote = new Models.Remote() { + var remote = new Models.Remote() + { Name = match.Groups[1].Value, URL = match.Groups[2].Value, }; @@ -30,6 +36,6 @@ namespace SourceGit.Commands { _loaded.Add(remote); } - private List _loaded = new List(); + private readonly List _loaded = new List(); } -} +} \ No newline at end of file diff --git a/src/Commands/QueryRepositoryRootPath.cs b/src/Commands/QueryRepositoryRootPath.cs index 51a1a15a..fad9fe34 100644 --- a/src/Commands/QueryRepositoryRootPath.cs +++ b/src/Commands/QueryRepositoryRootPath.cs @@ -1,15 +1,19 @@ -namespace SourceGit.Commands { - public class QueryRepositoryRootPath : Command { - public QueryRepositoryRootPath(string path) { +namespace SourceGit.Commands +{ + public class QueryRepositoryRootPath : Command + { + public QueryRepositoryRootPath(string path) + { WorkingDirectory = path; Args = "rev-parse --show-toplevel"; RaiseError = false; } - public string Result() { + public string Result() + { var rs = ReadToEnd().StdOut; if (string.IsNullOrEmpty(rs)) return null; return rs.Trim(); } } -} +} \ No newline at end of file diff --git a/src/Commands/QueryRevisionObjects.cs b/src/Commands/QueryRevisionObjects.cs index 4dc0dafe..5c97b5bf 100644 --- a/src/Commands/QueryRevisionObjects.cs +++ b/src/Commands/QueryRevisionObjects.cs @@ -1,25 +1,30 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class QueryRevisionObjects : Command { - +namespace SourceGit.Commands +{ + public partial class QueryRevisionObjects : Command + { + [GeneratedRegex(@"^\d+\s+(\w+)\s+([0-9a-f]+)\s+(.*)$")] private static partial Regex REG_FORMAT(); - private List objects = new List(); + private readonly List objects = new List(); - public QueryRevisionObjects(string repo, string sha) { + public QueryRevisionObjects(string repo, string sha) + { WorkingDirectory = repo; Context = repo; Args = $"ls-tree -r {sha}"; } - public List Result() { + public List Result() + { Exec(); return objects; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { var match = REG_FORMAT().Match(line); if (!match.Success) return; @@ -28,14 +33,15 @@ namespace SourceGit.Commands { obj.Type = Models.ObjectType.Blob; obj.Path = match.Groups[3].Value; - switch (match.Groups[1].Value) { - case "blob": obj.Type = Models.ObjectType.Blob; break; - case "tree": obj.Type = Models.ObjectType.Tree; break; - case "tag": obj.Type = Models.ObjectType.Tag; break; - case "commit": obj.Type = Models.ObjectType.Commit; break; + switch (match.Groups[1].Value) + { + case "blob": obj.Type = Models.ObjectType.Blob; break; + case "tree": obj.Type = Models.ObjectType.Tree; break; + case "tag": obj.Type = Models.ObjectType.Tag; break; + case "commit": obj.Type = Models.ObjectType.Commit; break; } objects.Add(obj); } } -} +} \ No newline at end of file diff --git a/src/Commands/QueryStagedFileBlobGuid.cs b/src/Commands/QueryStagedFileBlobGuid.cs index b2b21c6b..5fa56dd6 100644 --- a/src/Commands/QueryStagedFileBlobGuid.cs +++ b/src/Commands/QueryStagedFileBlobGuid.cs @@ -1,24 +1,29 @@ using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class QueryStagedFileBlobGuid : Command { +namespace SourceGit.Commands +{ + public partial class QueryStagedFileBlobGuid : Command + { [GeneratedRegex(@"^\d+\s+([0-9a-f]+)\s+.*$")] private static partial Regex REG_FORMAT(); - public QueryStagedFileBlobGuid(string repo, string file) { + public QueryStagedFileBlobGuid(string repo, string file) + { WorkingDirectory = repo; Context = repo; Args = $"ls-files -s -- \"{file}\""; } - public string Result() { + public string Result() + { var rs = ReadToEnd(); var match = REG_FORMAT().Match(rs.StdOut.Trim()); - if (match.Success) { + if (match.Success) + { return match.Groups[1].Value; } return string.Empty; } } -} +} \ No newline at end of file diff --git a/src/Commands/QueryStashChanges.cs b/src/Commands/QueryStashChanges.cs index 2f9d7312..ad02ef00 100644 --- a/src/Commands/QueryStashChanges.cs +++ b/src/Commands/QueryStashChanges.cs @@ -1,39 +1,45 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class QueryStashChanges : Command { - +namespace SourceGit.Commands +{ + public partial class QueryStashChanges : Command + { + [GeneratedRegex(@"^(\s?[\w\?]{1,4})\s+(.+)$")] private static partial Regex REG_FORMAT(); - public QueryStashChanges(string repo, string sha) { + public QueryStashChanges(string repo, string sha) + { WorkingDirectory = repo; Context = repo; Args = $"diff --name-status --pretty=format: {sha}^ {sha}"; } - public List Result() { + public List Result() + { Exec(); return _changes; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { var match = REG_FORMAT().Match(line); if (!match.Success) return; var change = new Models.Change() { Path = match.Groups[2].Value }; var status = match.Groups[1].Value; - switch (status[0]) { - case 'M': change.Set(Models.ChangeState.Modified); _changes.Add(change); break; - case 'A': change.Set(Models.ChangeState.Added); _changes.Add(change); break; - case 'D': change.Set(Models.ChangeState.Deleted); _changes.Add(change); break; - case 'R': change.Set(Models.ChangeState.Renamed); _changes.Add(change); break; - case 'C': change.Set(Models.ChangeState.Copied); _changes.Add(change); break; + switch (status[0]) + { + case 'M': change.Set(Models.ChangeState.Modified); _changes.Add(change); break; + case 'A': change.Set(Models.ChangeState.Added); _changes.Add(change); break; + case 'D': change.Set(Models.ChangeState.Deleted); _changes.Add(change); break; + case 'R': change.Set(Models.ChangeState.Renamed); _changes.Add(change); break; + case 'C': change.Set(Models.ChangeState.Copied); _changes.Add(change); break; } } - private List _changes = new List(); + private readonly List _changes = new List(); } -} +} \ No newline at end of file diff --git a/src/Commands/QueryStashes.cs b/src/Commands/QueryStashes.cs index be51849b..e9023574 100644 --- a/src/Commands/QueryStashes.cs +++ b/src/Commands/QueryStashes.cs @@ -2,26 +2,32 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class QueryStashes : Command { - +namespace SourceGit.Commands +{ + public partial class QueryStashes : Command + { + [GeneratedRegex(@"^Reflog: refs/(stash@\{\d+\}).*$")] private static partial Regex REG_STASH(); - - public QueryStashes(string repo) { + + public QueryStashes(string repo) + { WorkingDirectory = repo; Context = repo; Args = "stash list --pretty=raw"; } - public List Result() { + public List Result() + { Exec(); if (_current != null) _stashes.Add(_current); return _stashes; } - protected override void OnReadline(string line) { - if (line.StartsWith("commit ", StringComparison.Ordinal)) { + protected override void OnReadline(string line) + { + if (line.StartsWith("commit ", StringComparison.Ordinal)) + { if (_current != null && !string.IsNullOrEmpty(_current.Name)) _stashes.Add(_current); _current = new Models.Stash() { SHA = line.Substring(7, 8) }; return; @@ -29,12 +35,17 @@ namespace SourceGit.Commands { if (_current == null) return; - if (line.StartsWith("Reflog: refs/stash@", StringComparison.Ordinal)) { + if (line.StartsWith("Reflog: refs/stash@", StringComparison.Ordinal)) + { var match = REG_STASH().Match(line); if (match.Success) _current.Name = match.Groups[1].Value; - } else if (line.StartsWith("Reflog message: ", StringComparison.Ordinal)) { + } + else if (line.StartsWith("Reflog message: ", StringComparison.Ordinal)) + { _current.Message = line.Substring(16); - } else if (line.StartsWith("author ", StringComparison.Ordinal)) { + } + else if (line.StartsWith("author ", StringComparison.Ordinal)) + { Models.User user = Models.User.Invalid; ulong time = 0; Models.Commit.ParseUserAndTime(line.Substring(7), ref user, ref time); @@ -43,7 +54,7 @@ namespace SourceGit.Commands { } } - private List _stashes = new List(); + private readonly List _stashes = new List(); private Models.Stash _current = null; } -} +} \ No newline at end of file diff --git a/src/Commands/QuerySubmodules.cs b/src/Commands/QuerySubmodules.cs index fc2a522f..58c858d4 100644 --- a/src/Commands/QuerySubmodules.cs +++ b/src/Commands/QuerySubmodules.cs @@ -1,37 +1,44 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -namespace SourceGit.Commands { - public partial class QuerySubmodules : Command { +namespace SourceGit.Commands +{ + public partial class QuerySubmodules : Command + { [GeneratedRegex(@"^[\-\+ ][0-9a-f]+\s(.*)\s\(.*\)$")] private static partial Regex REG_FORMAT1(); [GeneratedRegex(@"^[\-\+ ][0-9a-f]+\s(.*)$")] private static partial Regex REG_FORMAT2(); - public QuerySubmodules(string repo) { + public QuerySubmodules(string repo) + { WorkingDirectory = repo; Context = repo; Args = "submodule status"; } - public List Result() { + public List Result() + { Exec(); return _submodules; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { var match = REG_FORMAT1().Match(line); - if (match.Success) { + if (match.Success) + { _submodules.Add(match.Groups[1].Value); return; } - + match = REG_FORMAT2().Match(line); - if (match.Success) { + if (match.Success) + { _submodules.Add(match.Groups[1].Value); } } - private List _submodules = new List(); + private readonly List _submodules = new List(); } -} +} \ No newline at end of file diff --git a/src/Commands/QueryTags.cs b/src/Commands/QueryTags.cs index 470301a3..a4d5a65d 100644 --- a/src/Commands/QueryTags.cs +++ b/src/Commands/QueryTags.cs @@ -1,34 +1,44 @@ using System; using System.Collections.Generic; -namespace SourceGit.Commands { - public class QueryTags : Command { - public QueryTags(string repo) { +namespace SourceGit.Commands +{ + public class QueryTags : Command + { + public QueryTags(string repo) + { Context = repo; WorkingDirectory = repo; Args = "for-each-ref --sort=-creatordate --format=\"$%(refname:short)$%(objectname)$%(*objectname)\" refs/tags"; } - public List Result() { + public List Result() + { Exec(); return _loaded; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { var subs = line.Split(new char[] { '$' }, StringSplitOptions.RemoveEmptyEntries); - if (subs.Length == 2) { - _loaded.Add(new Models.Tag() { + if (subs.Length == 2) + { + _loaded.Add(new Models.Tag() + { Name = subs[0], SHA = subs[1], }); - } else if (subs.Length == 3) { - _loaded.Add(new Models.Tag() { + } + else if (subs.Length == 3) + { + _loaded.Add(new Models.Tag() + { Name = subs[0], SHA = subs[2], }); } } - private List _loaded = new List(); + private readonly List _loaded = new List(); } -} +} \ No newline at end of file diff --git a/src/Commands/Rebase.cs b/src/Commands/Rebase.cs index 88d304aa..faa4f5c5 100644 --- a/src/Commands/Rebase.cs +++ b/src/Commands/Rebase.cs @@ -1,6 +1,9 @@ -namespace SourceGit.Commands { - public class Rebase : Command { - public Rebase(string repo, string basedOn, bool autoStash) { +namespace SourceGit.Commands +{ + public class Rebase : Command + { + public Rebase(string repo, string basedOn, bool autoStash) + { WorkingDirectory = repo; Context = repo; Args = "rebase "; @@ -8,4 +11,4 @@ Args += basedOn; } } -} +} \ No newline at end of file diff --git a/src/Commands/Remote.cs b/src/Commands/Remote.cs index 1a526045..d669b0a3 100644 --- a/src/Commands/Remote.cs +++ b/src/Commands/Remote.cs @@ -1,33 +1,41 @@ -namespace SourceGit.Commands { - public class Remote : Command { - public Remote(string repo) { +namespace SourceGit.Commands +{ + public class Remote : Command + { + public Remote(string repo) + { WorkingDirectory = repo; Context = repo; } - public bool Add(string name, string url) { + public bool Add(string name, string url) + { Args = $"remote add {name} {url}"; return Exec(); } - public bool Delete(string name) { + public bool Delete(string name) + { Args = $"remote remove {name}"; return Exec(); } - public bool Rename(string name, string to) { + public bool Rename(string name, string to) + { Args = $"remote rename {name} {to}"; return Exec(); } - public bool Prune(string name) { + public bool Prune(string name) + { Args = $"remote prune {name}"; return Exec(); } - public bool SetURL(string name, string url) { + public bool SetURL(string name, string url) + { Args = $"remote set-url {name} {url}"; return Exec(); } } -} +} \ No newline at end of file diff --git a/src/Commands/Reset.cs b/src/Commands/Reset.cs index 445890bd..c44eae12 100644 --- a/src/Commands/Reset.cs +++ b/src/Commands/Reset.cs @@ -1,21 +1,26 @@ using System.Collections.Generic; using System.Text; -namespace SourceGit.Commands { - public class Reset : Command { - public Reset(string repo) { +namespace SourceGit.Commands +{ + public class Reset : Command + { + public Reset(string repo) + { WorkingDirectory = repo; Context = repo; Args = "reset"; } - public Reset(string repo, List changes) { + public Reset(string repo, List changes) + { WorkingDirectory = repo; Context = repo; var builder = new StringBuilder(); builder.Append("reset --"); - foreach (var c in changes) { + foreach (var c in changes) + { builder.Append(" \""); builder.Append(c.Path); builder.Append("\""); @@ -23,10 +28,11 @@ namespace SourceGit.Commands { Args = builder.ToString(); } - public Reset(string repo, string revision, string mode) { + public Reset(string repo, string revision, string mode) + { WorkingDirectory = repo; Context = repo; Args = $"reset {mode} {revision}"; - } + } } -} +} \ No newline at end of file diff --git a/src/Commands/Restore.cs b/src/Commands/Restore.cs index c0aeafd5..f55f6b70 100644 --- a/src/Commands/Restore.cs +++ b/src/Commands/Restore.cs @@ -1,9 +1,12 @@ using System.Collections.Generic; using System.Text; -namespace SourceGit.Commands { - public class Restore : Command { - public Restore(string repo, List files, string extra) { +namespace SourceGit.Commands +{ + public class Restore : Command + { + public Restore(string repo, List files, string extra) + { WorkingDirectory = repo; Context = repo; @@ -13,6 +16,6 @@ namespace SourceGit.Commands { builder.Append("--"); foreach (var f in files) builder.Append(' ').Append('"').Append(f).Append('"'); Args = builder.ToString(); - } + } } -} +} \ No newline at end of file diff --git a/src/Commands/Revert.cs b/src/Commands/Revert.cs index 6b9549f5..12149c97 100644 --- a/src/Commands/Revert.cs +++ b/src/Commands/Revert.cs @@ -1,10 +1,13 @@ -namespace SourceGit.Commands { - public class Revert : Command { - public Revert(string repo, string commit, bool autoCommit) { +namespace SourceGit.Commands +{ + public class Revert : Command + { + public Revert(string repo, string commit, bool autoCommit) + { WorkingDirectory = repo; Context = repo; Args = $"revert {commit} --no-edit"; if (!autoCommit) Args += " --no-commit"; } } -} +} \ No newline at end of file diff --git a/src/Commands/SaveChangesAsPatch.cs b/src/Commands/SaveChangesAsPatch.cs index 8a2a7bc6..25003059 100644 --- a/src/Commands/SaveChangesAsPatch.cs +++ b/src/Commands/SaveChangesAsPatch.cs @@ -1,14 +1,20 @@ -using Avalonia.Threading; -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; -namespace SourceGit.Commands { - public static class SaveChangesAsPatch { - public static bool Exec(string repo, List changes, bool isUnstaged, string saveTo) { - using (var sw = File.Create(saveTo)) { - foreach (var change in changes) { +using Avalonia.Threading; + +namespace SourceGit.Commands +{ + public static class SaveChangesAsPatch + { + public static bool Exec(string repo, List changes, bool isUnstaged, string saveTo) + { + using (var sw = File.Create(saveTo)) + { + foreach (var change in changes) + { if (!ProcessSingleChange(repo, new Models.DiffOption(change, isUnstaged), sw)) return false; } } @@ -16,7 +22,8 @@ namespace SourceGit.Commands { return true; } - private static bool ProcessSingleChange(string repo, Models.DiffOption opt, FileStream writer) { + private static bool ProcessSingleChange(string repo, Models.DiffOption opt, FileStream writer) + { var starter = new ProcessStartInfo(); starter.WorkingDirectory = repo; starter.FileName = Native.OS.GitInstallPath; @@ -26,7 +33,8 @@ namespace SourceGit.Commands { starter.WindowStyle = ProcessWindowStyle.Hidden; starter.RedirectStandardOutput = true; - try { + try + { var proc = new Process() { StartInfo = starter }; proc.Start(); proc.StandardOutput.BaseStream.CopyTo(writer); @@ -35,12 +43,15 @@ namespace SourceGit.Commands { proc.Close(); return rs; - } catch (Exception e) { - Dispatcher.UIThread.Invoke(() => { + } + catch (Exception e) + { + Dispatcher.UIThread.Invoke(() => + { App.RaiseException(repo, "Save change to patch failed: " + e.Message); - }); + }); return false; } } } -} +} \ No newline at end of file diff --git a/src/Commands/SaveRevisionFile.cs b/src/Commands/SaveRevisionFile.cs index bd38b617..a19a4397 100644 --- a/src/Commands/SaveRevisionFile.cs +++ b/src/Commands/SaveRevisionFile.cs @@ -1,24 +1,33 @@ -using Avalonia.Threading; -using System; +using System; using System.Diagnostics; using System.IO; -namespace SourceGit.Commands { - public static class SaveRevisionFile { - public static void Run(string repo, string revision, string file, string saveTo) { +using Avalonia.Threading; + +namespace SourceGit.Commands +{ + public static class SaveRevisionFile + { + public static void Run(string repo, string revision, string file, string saveTo) + { var isLFSFiltered = new IsLFSFiltered(repo, file).Result(); - if (isLFSFiltered) { + if (isLFSFiltered) + { var tmpFile = saveTo + ".tmp"; - if (ExecCmd(repo, $"show {revision}:\"{file}\"", tmpFile)) { + if (ExecCmd(repo, $"show {revision}:\"{file}\"", tmpFile)) + { ExecCmd(repo, $"lfs smudge", saveTo, tmpFile); - } + } File.Delete(tmpFile); - } else { + } + else + { ExecCmd(repo, $"show {revision}:\"{file}\"", saveTo); } } - - private static bool ExecCmd(string repo, string args, string outputFile, string inputFile = null) { + + private static bool ExecCmd(string repo, string args, string outputFile, string inputFile = null) + { var starter = new ProcessStartInfo(); starter.WorkingDirectory = repo; starter.FileName = Native.OS.GitInstallPath; @@ -30,14 +39,19 @@ namespace SourceGit.Commands { starter.RedirectStandardOutput = true; starter.RedirectStandardError = true; - using (var sw = File.OpenWrite(outputFile)) { - try { + using (var sw = File.OpenWrite(outputFile)) + { + try + { var proc = new Process() { StartInfo = starter }; proc.Start(); - if (inputFile != null) { - using (StreamReader sr = new StreamReader(inputFile)) { - while (true) { + if (inputFile != null) + { + using (StreamReader sr = new StreamReader(inputFile)) + { + while (true) + { var line = sr.ReadLine(); if (line == null) break; proc.StandardInput.WriteLine(line); @@ -51,13 +65,16 @@ namespace SourceGit.Commands { proc.Close(); return rs; - } catch (Exception e) { - Dispatcher.UIThread.Invoke(() => { + } + catch (Exception e) + { + Dispatcher.UIThread.Invoke(() => + { App.RaiseException(repo, "Save file failed: " + e.Message); - }); + }); return false; } } } } -} +} \ No newline at end of file diff --git a/src/Commands/Stash.cs b/src/Commands/Stash.cs index 720129a7..cb0c18e7 100644 --- a/src/Commands/Stash.cs +++ b/src/Commands/Stash.cs @@ -1,36 +1,45 @@ using System.Collections.Generic; using System.IO; -namespace SourceGit.Commands { - public class Stash : Command { - public Stash(string repo) { +namespace SourceGit.Commands +{ + public class Stash : Command + { + public Stash(string repo) + { WorkingDirectory = repo; Context = repo; } - public bool Push(string message) { + public bool Push(string message) + { Args = $"stash push -m \"{message}\""; return Exec(); } - public bool Push(List changes, string message) { + public bool Push(List changes, string message) + { var temp = Path.GetTempFileName(); var stream = new FileStream(temp, FileMode.Create); var writer = new StreamWriter(stream); var needAdd = new List(); - foreach (var c in changes) { + foreach (var c in changes) + { writer.WriteLine(c.Path); - if (c.WorkTree == Models.ChangeState.Added || c.WorkTree == Models.ChangeState.Untracked) { + if (c.WorkTree == Models.ChangeState.Added || c.WorkTree == Models.ChangeState.Untracked) + { needAdd.Add(c); - if (needAdd.Count > 10) { + if (needAdd.Count > 10) + { new Add(WorkingDirectory, needAdd).Exec(); needAdd.Clear(); } } } - if (needAdd.Count > 0) { + if (needAdd.Count > 0) + { new Add(WorkingDirectory, needAdd).Exec(); needAdd.Clear(); } @@ -46,24 +55,28 @@ namespace SourceGit.Commands { return succ; } - public bool Apply(string name) { + public bool Apply(string name) + { Args = $"stash apply -q {name}"; return Exec(); } - public bool Pop(string name) { + public bool Pop(string name) + { Args = $"stash pop -q {name}"; return Exec(); } - public bool Drop(string name) { + public bool Drop(string name) + { Args = $"stash drop -q {name}"; return Exec(); } - public bool Clear() { + public bool Clear() + { Args = "stash clear"; return Exec(); } } -} +} \ No newline at end of file diff --git a/src/Commands/Statistics.cs b/src/Commands/Statistics.cs index fb0e7ee0..36a048a7 100644 --- a/src/Commands/Statistics.cs +++ b/src/Commands/Statistics.cs @@ -1,8 +1,11 @@ using System; -namespace SourceGit.Commands { - public class Statistics : Command { - public Statistics(string repo) { +namespace SourceGit.Commands +{ + public class Statistics : Command + { + public Statistics(string repo) + { _statistics = new Models.Statistics(); WorkingDirectory = repo; @@ -10,13 +13,15 @@ namespace SourceGit.Commands { Args = $"log --date-order --branches --remotes --since=\"{_statistics.Since()}\" --pretty=format:\"%ct$%cn\""; } - public Models.Statistics Result() { + public Models.Statistics Result() + { Exec(); _statistics.Complete(); return _statistics; } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { var dateEndIdx = line.IndexOf('$', StringComparison.Ordinal); if (dateEndIdx == -1) return; @@ -27,6 +32,6 @@ namespace SourceGit.Commands { _statistics.AddCommit(line.Substring(dateEndIdx + 1), date); } - private Models.Statistics _statistics = null; + private readonly Models.Statistics _statistics = null; } -} +} \ No newline at end of file diff --git a/src/Commands/Submodule.cs b/src/Commands/Submodule.cs index a6aeee83..e5c385c3 100644 --- a/src/Commands/Submodule.cs +++ b/src/Commands/Submodule.cs @@ -1,32 +1,41 @@ using System; -namespace SourceGit.Commands { - public class Submodule : Command { - public Submodule(string repo) { +namespace SourceGit.Commands +{ + public class Submodule : Command + { + public Submodule(string repo) + { WorkingDirectory = repo; Context = repo; } - public bool Add(string url, string relativePath, bool recursive, Action outputHandler) { + public bool Add(string url, string relativePath, bool recursive, Action outputHandler) + { _outputHandler = outputHandler; Args = $"submodule add {url} {relativePath}"; if (!Exec()) return false; - if (recursive) { + if (recursive) + { Args = $"submodule update --init --recursive -- {relativePath}"; return Exec(); - } else { + } + else + { Args = $"submodule update --init -- {relativePath}"; return true; } } - public bool Update() { + public bool Update() + { Args = $"submodule update --rebase --remote"; return Exec(); } - public bool Delete(string relativePath) { + public bool Delete(string relativePath) + { Args = $"submodule deinit -f {relativePath}"; if (!Exec()) return false; @@ -34,10 +43,11 @@ namespace SourceGit.Commands { return Exec(); } - protected override void OnReadline(string line) { + protected override void OnReadline(string line) + { _outputHandler?.Invoke(line); } private Action _outputHandler; } -} +} \ No newline at end of file diff --git a/src/Commands/Tag.cs b/src/Commands/Tag.cs index d0ab3bcb..3b49deba 100644 --- a/src/Commands/Tag.cs +++ b/src/Commands/Tag.cs @@ -1,34 +1,43 @@ using System.Collections.Generic; using System.IO; -namespace SourceGit.Commands { - public static class Tag { - public static bool Add(string repo, string name, string basedOn, string message) { +namespace SourceGit.Commands +{ + public static class Tag + { + public static bool Add(string repo, string name, string basedOn, string message) + { var cmd = new Command(); cmd.WorkingDirectory = repo; cmd.Context = repo; cmd.Args = $"tag -a {name} {basedOn} "; - if (!string.IsNullOrEmpty(message)) { + if (!string.IsNullOrEmpty(message)) + { string tmp = Path.GetTempFileName(); File.WriteAllText(tmp, message); cmd.Args += $"-F \"{tmp}\""; - } else { + } + else + { cmd.Args += $"-m {name}"; } return cmd.Exec(); } - public static bool Delete(string repo, string name, List remotes) { + public static bool Delete(string repo, string name, List remotes) + { var cmd = new Command(); cmd.WorkingDirectory = repo; cmd.Context = repo; cmd.Args = $"tag --delete {name}"; if (!cmd.Exec()) return false; - if (remotes != null) { - foreach (var r in remotes) { + if (remotes != null) + { + foreach (var r in remotes) + { new Push(repo, r.Name, name, true).Exec(); } } @@ -36,4 +45,4 @@ namespace SourceGit.Commands { return true; } } -} +} \ No newline at end of file diff --git a/src/Commands/Version.cs b/src/Commands/Version.cs index 54a937f7..7b368b04 100644 --- a/src/Commands/Version.cs +++ b/src/Commands/Version.cs @@ -1,14 +1,18 @@ -namespace SourceGit.Commands { - public class Version : Command { - public Version() { +namespace SourceGit.Commands +{ + public class Version : Command + { + public Version() + { Args = "--version"; RaiseError = false; } - public string Query() { + public string Query() + { var rs = ReadToEnd(); if (!rs.IsSuccess || string.IsNullOrWhiteSpace(rs.StdOut)) return string.Empty; return rs.StdOut.Trim().Substring("git version ".Length); } } -} +} \ No newline at end of file diff --git a/src/Converters/BookmarkConverters.cs b/src/Converters/BookmarkConverters.cs index 1eca567b..01da5475 100644 --- a/src/Converters/BookmarkConverters.cs +++ b/src/Converters/BookmarkConverters.cs @@ -1,12 +1,14 @@ using Avalonia.Data.Converters; using Avalonia.Media; -namespace SourceGit.Converters { - public static class BookmarkConverters { +namespace SourceGit.Converters +{ + public static class BookmarkConverters + { public static FuncValueConverter ToBrush = new FuncValueConverter(bookmark => Models.Bookmarks.Brushes[bookmark]); public static FuncValueConverter ToStrokeThickness = new FuncValueConverter(bookmark => bookmark == 0 ? 1.0 : 0); } -} +} \ No newline at end of file diff --git a/src/Converters/BoolConverters.cs b/src/Converters/BoolConverters.cs index 65593f8f..31f56499 100644 --- a/src/Converters/BoolConverters.cs +++ b/src/Converters/BoolConverters.cs @@ -1,8 +1,10 @@ using Avalonia.Data.Converters; -namespace SourceGit.Converters { - public static class BoolConverters { +namespace SourceGit.Converters +{ + public static class BoolConverters + { public static FuncValueConverter ToCommitOpacity = new FuncValueConverter(x => x ? 1 : 0.5); } -} +} \ No newline at end of file diff --git a/src/Converters/BranchConverters.cs b/src/Converters/BranchConverters.cs index c067a481..66675eca 100644 --- a/src/Converters/BranchConverters.cs +++ b/src/Converters/BranchConverters.cs @@ -1,8 +1,10 @@ using Avalonia.Data.Converters; -namespace SourceGit.Converters { - public static class BranchConverters { +namespace SourceGit.Converters +{ + public static class BranchConverters + { public static FuncValueConverter ToName = new FuncValueConverter(v => v.IsLocal ? v.Name : $"{v.Remote}/{v.Name}"); } -} +} \ No newline at end of file diff --git a/src/Converters/ChangeViewModeConverters.cs b/src/Converters/ChangeViewModeConverters.cs index 8bfb0898..90a0828f 100644 --- a/src/Converters/ChangeViewModeConverters.cs +++ b/src/Converters/ChangeViewModeConverters.cs @@ -2,17 +2,21 @@ using Avalonia.Data.Converters; using Avalonia.Media; -namespace SourceGit.Converters { - public static class ChangeViewModeConverters { +namespace SourceGit.Converters +{ + public static class ChangeViewModeConverters + { public static FuncValueConverter ToIcon = - new FuncValueConverter(v => { - switch (v) { - case Models.ChangeViewMode.List: - return App.Current?.FindResource("Icons.List") as StreamGeometry; - case Models.ChangeViewMode.Grid: - return App.Current?.FindResource("Icons.Grid") as StreamGeometry; - default: - return App.Current?.FindResource("Icons.Tree") as StreamGeometry; + new FuncValueConverter(v => + { + switch (v) + { + case Models.ChangeViewMode.List: + return App.Current?.FindResource("Icons.List") as StreamGeometry; + case Models.ChangeViewMode.Grid: + return App.Current?.FindResource("Icons.Grid") as StreamGeometry; + default: + return App.Current?.FindResource("Icons.Tree") as StreamGeometry; } }); @@ -25,4 +29,4 @@ namespace SourceGit.Converters { public static FuncValueConverter IsTree = new FuncValueConverter(v => v == Models.ChangeViewMode.Tree); } -} +} \ No newline at end of file diff --git a/src/Converters/DecoratorTypeConverters.cs b/src/Converters/DecoratorTypeConverters.cs index 2e9460c9..10d6f0a7 100644 --- a/src/Converters/DecoratorTypeConverters.cs +++ b/src/Converters/DecoratorTypeConverters.cs @@ -3,32 +3,37 @@ using Avalonia.Controls; using Avalonia.Data.Converters; using Avalonia.Media; -namespace SourceGit.Converters { - public static class DecoratorTypeConverters { +namespace SourceGit.Converters +{ + public static class DecoratorTypeConverters + { public static FuncValueConverter ToBackground = - new FuncValueConverter(v => { + new FuncValueConverter(v => + { if (v == Models.DecoratorType.Tag) return Models.DecoratorResources.Backgrounds[0]; return Models.DecoratorResources.Backgrounds[1]; }); public static FuncValueConverter ToIcon = - new FuncValueConverter(v => { + new FuncValueConverter(v => + { var key = "Icons.Tag"; - switch (v) { - case Models.DecoratorType.CurrentBranchHead: - key = "Icons.Check"; - break; - case Models.DecoratorType.RemoteBranchHead: - key = "Icons.Remote"; - break; - case Models.DecoratorType.LocalBranchHead: - key = "Icons.Branch"; - break; - default: - break; + switch (v) + { + case Models.DecoratorType.CurrentBranchHead: + key = "Icons.Check"; + break; + case Models.DecoratorType.RemoteBranchHead: + key = "Icons.Remote"; + break; + case Models.DecoratorType.LocalBranchHead: + key = "Icons.Branch"; + break; + default: + break; } return Application.Current?.FindResource(key) as StreamGeometry; }); } -} +} \ No newline at end of file diff --git a/src/Converters/IntConverters.cs b/src/Converters/IntConverters.cs index 4a97a90d..f595505e 100644 --- a/src/Converters/IntConverters.cs +++ b/src/Converters/IntConverters.cs @@ -1,7 +1,9 @@ using Avalonia.Data.Converters; -namespace SourceGit.Converters { - public static class IntConverters { +namespace SourceGit.Converters +{ + public static class IntConverters + { public static FuncValueConverter IsGreaterThanZero = new FuncValueConverter(v => v > 0); @@ -11,4 +13,4 @@ namespace SourceGit.Converters { public static FuncValueConverter IsOne = new FuncValueConverter(v => v == 1); } -} +} \ No newline at end of file diff --git a/src/Converters/LauncherPageConverters.cs b/src/Converters/LauncherPageConverters.cs index 6ba2a0a4..88d21d51 100644 --- a/src/Converters/LauncherPageConverters.cs +++ b/src/Converters/LauncherPageConverters.cs @@ -1,11 +1,15 @@ -using Avalonia.Collections; -using Avalonia.Data.Converters; -using System.Collections.Generic; +using System.Collections.Generic; -namespace SourceGit.Converters { - public static class LauncherPageConverters { +using Avalonia.Collections; +using Avalonia.Data.Converters; + +namespace SourceGit.Converters +{ + public static class LauncherPageConverters + { public static FuncMultiValueConverter ToTabSeperatorVisible = - new FuncMultiValueConverter(v => { + new FuncMultiValueConverter(v => + { if (v == null) return false; var array = new List(); @@ -18,11 +22,14 @@ namespace SourceGit.Converters { var selected = array[1] as ViewModels.LauncherPage; var collections = array[2] as AvaloniaList; - if (selected != null && collections != null && (self == selected || collections.IndexOf(self) + 1 == collections.IndexOf(selected))) { + if (selected != null && collections != null && (self == selected || collections.IndexOf(self) + 1 == collections.IndexOf(selected))) + { return false; - } else { + } + else + { return true; } }); } -} +} \ No newline at end of file diff --git a/src/Converters/ListConverters.cs b/src/Converters/ListConverters.cs index bf52a281..039cf2ad 100644 --- a/src/Converters/ListConverters.cs +++ b/src/Converters/ListConverters.cs @@ -1,12 +1,15 @@ -using Avalonia.Data.Converters; -using System.Collections; +using System.Collections; -namespace SourceGit.Converters { - public static class ListConverters { +using Avalonia.Data.Converters; + +namespace SourceGit.Converters +{ + public static class ListConverters + { public static FuncValueConverter ToCount = new FuncValueConverter(v => $" ({v.Count})"); public static FuncValueConverter IsNotNullOrEmpty = new FuncValueConverter(v => v != null && v.Count > 0); } -} +} \ No newline at end of file diff --git a/src/Converters/PathConverters.cs b/src/Converters/PathConverters.cs index e1de3795..36f0f588 100644 --- a/src/Converters/PathConverters.cs +++ b/src/Converters/PathConverters.cs @@ -1,8 +1,11 @@ -using Avalonia.Data.Converters; -using System.IO; +using System.IO; -namespace SourceGit.Converters { - public static class PathConverters { +using Avalonia.Data.Converters; + +namespace SourceGit.Converters +{ + public static class PathConverters + { public static FuncValueConverter PureFileName = new FuncValueConverter(fullpath => Path.GetFileName(fullpath) ?? ""); @@ -10,9 +13,10 @@ namespace SourceGit.Converters { new FuncValueConverter(fullpath => Path.GetDirectoryName(fullpath) ?? ""); public static FuncValueConverter TruncateIfTooLong = - new FuncValueConverter(fullpath => { + new FuncValueConverter(fullpath => + { if (fullpath.Length <= 50) return fullpath; return fullpath.Substring(0, 20) + ".../" + Path.GetFileName(fullpath); }); } -} +} \ No newline at end of file diff --git a/src/Converters/StringConverters.cs b/src/Converters/StringConverters.cs index 0f305700..3b227316 100644 --- a/src/Converters/StringConverters.cs +++ b/src/Converters/StringConverters.cs @@ -1,35 +1,49 @@ -using Avalonia.Data.Converters; -using Avalonia.Styling; -using System; +using System; using System.Globalization; -namespace SourceGit.Converters { - public static class StringConverters { - public class ToLocaleConverter : IValueConverter { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { +using Avalonia.Data.Converters; +using Avalonia.Styling; + +namespace SourceGit.Converters +{ + public static class StringConverters + { + public class ToLocaleConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { return Models.Locale.Supported.Find(x => x.Key == value as string); } - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { return (value as Models.Locale).Key; } } public static ToLocaleConverter ToLocale = new ToLocaleConverter(); - public class ToThemeConverter : IValueConverter { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { + public class ToThemeConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { var theme = (string)value; - if (theme.Equals("Light", StringComparison.OrdinalIgnoreCase)) { + if (theme.Equals("Light", StringComparison.OrdinalIgnoreCase)) + { return ThemeVariant.Light; - } else if (theme.Equals("Dark", StringComparison.OrdinalIgnoreCase)) { + } + else if (theme.Equals("Dark", StringComparison.OrdinalIgnoreCase)) + { return ThemeVariant.Dark; - } else { + } + else + { return ThemeVariant.Default; } } - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { var theme = (ThemeVariant)value; return theme.Key; } @@ -37,13 +51,16 @@ namespace SourceGit.Converters { public static ToThemeConverter ToTheme = new ToThemeConverter(); - public class FormatByResourceKeyConverter : IValueConverter { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { + public class FormatByResourceKeyConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { var key = parameter as string; return App.Text(key, value); } - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { throw new NotImplementedException(); } } @@ -53,4 +70,4 @@ namespace SourceGit.Converters { public static FuncValueConverter ToShortSHA = new FuncValueConverter(v => v.Length > 10 ? v.Substring(0, 10) : v); } -} +} \ No newline at end of file diff --git a/src/Converters/WindowStateConverters.cs b/src/Converters/WindowStateConverters.cs index fc7c0bd4..050f5457 100644 --- a/src/Converters/WindowStateConverters.cs +++ b/src/Converters/WindowStateConverters.cs @@ -1,38 +1,55 @@ -using Avalonia.Controls; +using System; + +using Avalonia; +using Avalonia.Controls; using Avalonia.Data.Converters; using Avalonia.Media; -using Avalonia; -using System; -namespace SourceGit.Converters { - public static class WindowStateConverters { +namespace SourceGit.Converters +{ + public static class WindowStateConverters + { public static FuncValueConverter ToContentMargin = - new FuncValueConverter(state => { - if (OperatingSystem.IsWindows() && state == WindowState.Maximized) { + new FuncValueConverter(state => + { + if (OperatingSystem.IsWindows() && state == WindowState.Maximized) + { return new Thickness(6); - } else if (OperatingSystem.IsLinux() && state != WindowState.Maximized) { + } + else if (OperatingSystem.IsLinux() && state != WindowState.Maximized) + { return new Thickness(6); - } else { + } + else + { return new Thickness(0); } }); public static FuncValueConverter ToTitleBarHeight = - new FuncValueConverter(state => { - if (state == WindowState.Maximized) { + new FuncValueConverter(state => + { + if (state == WindowState.Maximized) + { return new GridLength(30); - } else { + } + else + { return new GridLength(38); } }); public static FuncValueConverter ToMaxOrRestoreIcon = - new FuncValueConverter(state => { - if (state == WindowState.Maximized) { + new FuncValueConverter(state => + { + if (state == WindowState.Maximized) + { return Application.Current?.FindResource("Icons.Window.Restore") as StreamGeometry; - } else { + } + else + { return Application.Current?.FindResource("Icons.Window.Maximize") as StreamGeometry; } }); } -} +} \ No newline at end of file diff --git a/src/Models/ApplyWhiteSpaceMode.cs b/src/Models/ApplyWhiteSpaceMode.cs index b35fa5f2..b430983b 100644 --- a/src/Models/ApplyWhiteSpaceMode.cs +++ b/src/Models/ApplyWhiteSpaceMode.cs @@ -1,13 +1,16 @@ -namespace SourceGit.Models { - public class ApplyWhiteSpaceMode { +namespace SourceGit.Models +{ + public class ApplyWhiteSpaceMode + { public string Name { get; set; } public string Desc { get; set; } public string Arg { get; set; } - public ApplyWhiteSpaceMode(string n, string d, string a) { + public ApplyWhiteSpaceMode(string n, string d, string a) + { Name = App.Text(n); Desc = App.Text(d); Arg = a; } } -} +} \ No newline at end of file diff --git a/src/Models/AvatarManager.cs b/src/Models/AvatarManager.cs index 4d81e112..cd989bdd 100644 --- a/src/Models/AvatarManager.cs +++ b/src/Models/AvatarManager.cs @@ -1,69 +1,88 @@ -using Avalonia.Media.Imaging; -using Avalonia.Threading; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks; -namespace SourceGit.Models { - public interface IAvatarHost { +using Avalonia.Media.Imaging; +using Avalonia.Threading; + +namespace SourceGit.Models +{ + public interface IAvatarHost + { void OnAvatarResourceChanged(string md5); } - public static class AvatarManager { - public static string SelectedServer { + public static class AvatarManager + { + public static string SelectedServer + { get; set; } = "https://www.gravatar.com/avatar/"; - static AvatarManager() { + static AvatarManager() + { _storePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "SourceGit", "avatars"); if (!Directory.Exists(_storePath)) Directory.CreateDirectory(_storePath); - Task.Run(() => { - while (true) { + Task.Run(() => + { + while (true) + { var md5 = null as string; - lock (_synclock) { - foreach (var one in _requesting) { + lock (_synclock) + { + foreach (var one in _requesting) + { md5 = one; break; } } - if (md5 == null) { + if (md5 == null) + { Thread.Sleep(100); continue; } var localFile = Path.Combine(_storePath, md5); var img = null as Bitmap; - try { + try + { var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(2) }; var task = client.GetAsync($"{SelectedServer}{md5}?d=404"); task.Wait(); var rsp = task.Result; - if (rsp.IsSuccessStatusCode) { - using (var stream = rsp.Content.ReadAsStream()) { - using (var writer = File.OpenWrite(localFile)) { + if (rsp.IsSuccessStatusCode) + { + using (var stream = rsp.Content.ReadAsStream()) + { + using (var writer = File.OpenWrite(localFile)) + { stream.CopyTo(writer); } } - using (var reader = File.OpenRead(localFile)) { + using (var reader = File.OpenRead(localFile)) + { img = Bitmap.DecodeToWidth(reader, 128); } } - } catch { } + } + catch { } - lock (_synclock) { + lock (_synclock) + { _requesting.Remove(md5); } - Dispatcher.UIThread.InvokeAsync(() => { + Dispatcher.UIThread.InvokeAsync(() => + { if (_resources.ContainsKey(md5)) _resources[md5] = img; else _resources.Add(md5, img); NotifyResourceChanged(md5); @@ -72,54 +91,67 @@ namespace SourceGit.Models { }); } - public static void Subscribe(IAvatarHost host) { + public static void Subscribe(IAvatarHost host) + { _avatars.Add(host); } - public static void Unsubscribe(IAvatarHost host) { + public static void Unsubscribe(IAvatarHost host) + { _avatars.Remove(host); } - public static Bitmap Request(string md5, bool forceRefetch = false) { - if (forceRefetch) { + public static Bitmap Request(string md5, bool forceRefetch = false) + { + if (forceRefetch) + { if (_resources.ContainsKey(md5)) _resources.Remove(md5); var localFile = Path.Combine(_storePath, md5); if (File.Exists(localFile)) File.Delete(localFile); NotifyResourceChanged(md5); - } else { + } + else + { if (_resources.ContainsKey(md5)) return _resources[md5]; var localFile = Path.Combine(_storePath, md5); - if (File.Exists(localFile)) { - try { - using (var stream = File.OpenRead(localFile)) { + if (File.Exists(localFile)) + { + try + { + using (var stream = File.OpenRead(localFile)) + { var img = Bitmap.DecodeToWidth(stream, 128); _resources.Add(md5, img); return img; } - } catch { } + } + catch { } } } - lock (_synclock) { + lock (_synclock) + { if (!_requesting.Contains(md5)) _requesting.Add(md5); } return null; } - private static void NotifyResourceChanged(string md5) { - foreach (var avatar in _avatars) { + private static void NotifyResourceChanged(string md5) + { + foreach (var avatar in _avatars) + { avatar.OnAvatarResourceChanged(md5); } } - private static object _synclock = new object(); - private static string _storePath = string.Empty; - private static List _avatars = new List(); - private static Dictionary _resources = new Dictionary(); - private static HashSet _requesting = new HashSet(); + private static readonly object _synclock = new object(); + private static readonly string _storePath = string.Empty; + private static readonly List _avatars = new List(); + private static readonly Dictionary _resources = new Dictionary(); + private static readonly HashSet _requesting = new HashSet(); } -} +} \ No newline at end of file diff --git a/src/Models/Blame.cs b/src/Models/Blame.cs index d9d3c9a4..9f5db81b 100644 --- a/src/Models/Blame.cs +++ b/src/Models/Blame.cs @@ -1,17 +1,20 @@ using System.Collections.Generic; -namespace SourceGit.Models { - public class BlameLineInfo { +namespace SourceGit.Models +{ + public class BlameLineInfo + { public bool IsFirstInGroup { get; set; } = false; public string CommitSHA { get; set; } = string.Empty; public string Author { get; set; } = string.Empty; public string Time { get; set; } = string.Empty; } - public class BlameData { + public class BlameData + { public string File { get; set; } = string.Empty; public List LineInfos { get; set; } = new List(); public string Content { get; set; } = string.Empty; public bool IsBinary { get; set; } = false; } -} +} \ No newline at end of file diff --git a/src/Models/Bookmarks.cs b/src/Models/Bookmarks.cs index 5c5e522c..faeb4c49 100644 --- a/src/Models/Bookmarks.cs +++ b/src/Models/Bookmarks.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; -namespace SourceGit.Models { - public static class Bookmarks { +namespace SourceGit.Models +{ + public static class Bookmarks + { public static readonly Avalonia.Media.IBrush[] Brushes = [ Avalonia.Media.Brushes.Transparent, Avalonia.Media.Brushes.Red, @@ -15,8 +17,9 @@ namespace SourceGit.Models { public static readonly List Supported = new List(); - static Bookmarks() { + static Bookmarks() + { for (int i = 0; i < Brushes.Length; i++) Supported.Add(i); } } -} +} \ No newline at end of file diff --git a/src/Models/Branch.cs b/src/Models/Branch.cs index f1041839..a603c5e5 100644 --- a/src/Models/Branch.cs +++ b/src/Models/Branch.cs @@ -1,5 +1,7 @@ -namespace SourceGit.Models { - public class Branch { +namespace SourceGit.Models +{ + public class Branch + { public string Name { get; set; } public string FullName { get; set; } public string Head { get; set; } @@ -9,4 +11,4 @@ public string UpstreamTrackStatus { get; set; } public string Remote { get; set; } } -} +} \ No newline at end of file diff --git a/src/Models/BranchTreeNode.cs b/src/Models/BranchTreeNode.cs index 77236e4c..dda92e68 100644 --- a/src/Models/BranchTreeNode.cs +++ b/src/Models/BranchTreeNode.cs @@ -1,15 +1,19 @@ -using Avalonia.Collections; -using System; +using System; using System.Collections.Generic; -namespace SourceGit.Models { - public enum BranchTreeNodeType { +using Avalonia.Collections; + +namespace SourceGit.Models +{ + public enum BranchTreeNodeType + { Remote, Folder, Branch, } - public class BranchTreeNode { + public class BranchTreeNode + { public string Name { get; set; } public BranchTreeNodeType Type { get; set; } public object Backend { get; set; } @@ -17,38 +21,48 @@ namespace SourceGit.Models { public bool IsFiltered { get; set; } public List Children { get; set; } = new List(); - public bool IsUpstreamTrackStatusVisible { + public bool IsUpstreamTrackStatusVisible + { get => IsBranch && !string.IsNullOrEmpty((Backend as Branch).UpstreamTrackStatus); } - public string UpstreamTrackStatus { + public string UpstreamTrackStatus + { get => Type == BranchTreeNodeType.Branch ? (Backend as Branch).UpstreamTrackStatus : ""; } - public bool IsRemote { + public bool IsRemote + { get => Type == BranchTreeNodeType.Remote; } - public bool IsFolder { + public bool IsFolder + { get => Type == BranchTreeNodeType.Folder; } - public bool IsBranch { + public bool IsBranch + { get => Type == BranchTreeNodeType.Branch; } - public bool IsCurrent { + public bool IsCurrent + { get => IsBranch && (Backend as Branch).IsCurrent; - } + } - public class Builder { + public class Builder + { public List Locals => _locals; public List Remotes => _remotes; - public void Run(List branches, List remotes) { - foreach (var remote in remotes) { + public void Run(List branches, List remotes) + { + foreach (var remote in remotes) + { var path = $"remote/{remote.Name}"; - var node = new BranchTreeNode() { + var node = new BranchTreeNode() + { Name = remote.Name, Type = BranchTreeNodeType.Remote, Backend = remote, @@ -59,11 +73,15 @@ namespace SourceGit.Models { _remotes.Add(node); } - foreach (var branch in branches) { + foreach (var branch in branches) + { var isFiltered = _filters.Contains(branch.FullName); - if (branch.IsLocal) { + if (branch.IsLocal) + { MakeBranchNode(branch, _locals, "local", isFiltered); - } else { + } + else + { var remote = _remotes.Find(x => x.Name == branch.Remote); if (remote != null) MakeBranchNode(branch, remote.Children, $"remote/{remote.Name}", isFiltered); } @@ -73,27 +91,34 @@ namespace SourceGit.Models { SortNodes(_remotes); } - public void SetFilters(AvaloniaList filters) { + public void SetFilters(AvaloniaList filters) + { _filters.AddRange(filters); } - public void CollectExpandedNodes(List nodes, bool isLocal) { + public void CollectExpandedNodes(List nodes, bool isLocal) + { CollectExpandedNodes(nodes, isLocal ? "local" : "remote"); } - private void CollectExpandedNodes(List nodes, string prefix) { - foreach (var node in nodes) { + private void CollectExpandedNodes(List nodes, string prefix) + { + foreach (var node in nodes) + { var path = prefix + "/" + node.Name; if (node.Type != BranchTreeNodeType.Branch && node.IsExpanded) _expanded.Add(path); CollectExpandedNodes(node.Children, path); } } - private void MakeBranchNode(Branch branch, List roots, string prefix, bool isFiltered) { + private void MakeBranchNode(Branch branch, List roots, string prefix, bool isFiltered) + { var subs = branch.Name.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - if (subs.Length == 1) { - var node = new BranchTreeNode() { + if (subs.Length == 1) + { + var node = new BranchTreeNode() + { Name = subs[0], Type = BranchTreeNodeType.Branch, Backend = branch, @@ -106,20 +131,28 @@ namespace SourceGit.Models { BranchTreeNode lastFolder = null; string path = prefix; - for (int i = 0; i < subs.Length - 1; i++) { + for (int i = 0; i < subs.Length - 1; i++) + { path = string.Concat(path, "/", subs[i]); - if (_maps.ContainsKey(path)) { + if (_maps.ContainsKey(path)) + { lastFolder = _maps[path]; - } else if (lastFolder == null) { - lastFolder = new BranchTreeNode() { + } + else if (lastFolder == null) + { + lastFolder = new BranchTreeNode() + { Name = subs[i], Type = BranchTreeNodeType.Folder, IsExpanded = branch.IsCurrent || _expanded.Contains(path), }; roots.Add(lastFolder); _maps.Add(path, lastFolder); - } else { - var folder = new BranchTreeNode() { + } + else + { + var folder = new BranchTreeNode() + { Name = subs[i], Type = BranchTreeNodeType.Folder, IsExpanded = branch.IsCurrent || _expanded.Contains(path), @@ -130,7 +163,8 @@ namespace SourceGit.Models { } } - var last = new BranchTreeNode() { + var last = new BranchTreeNode() + { Name = subs[subs.Length - 1], Type = BranchTreeNodeType.Branch, Backend = branch, @@ -140,11 +174,16 @@ namespace SourceGit.Models { lastFolder.Children.Add(last); } - private void SortNodes(List nodes) { - nodes.Sort((l, r) => { - if (l.Type == r.Type) { + private void SortNodes(List nodes) + { + nodes.Sort((l, r) => + { + if (l.Type == r.Type) + { return l.Name.CompareTo(r.Name); - } else { + } + else + { return (int)(l.Type) - (int)(r.Type); } }); @@ -152,11 +191,11 @@ namespace SourceGit.Models { foreach (var node in nodes) SortNodes(node.Children); } - private List _locals = new List(); - private List _remotes = new List(); - private HashSet _expanded = new HashSet(); - private List _filters = new List(); - private Dictionary _maps = new Dictionary(); + private readonly List _locals = new List(); + private readonly List _remotes = new List(); + private readonly HashSet _expanded = new HashSet(); + private readonly List _filters = new List(); + private readonly Dictionary _maps = new Dictionary(); } } -} +} \ No newline at end of file diff --git a/src/Models/CRLFMode.cs b/src/Models/CRLFMode.cs index a75c247c..1c492729 100644 --- a/src/Models/CRLFMode.cs +++ b/src/Models/CRLFMode.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; -namespace SourceGit.Models { - public class CRLFMode { +namespace SourceGit.Models +{ + public class CRLFMode + { public string Name { get; set; } public string Value { get; set; } public string Desc { get; set; } @@ -12,10 +14,11 @@ namespace SourceGit.Models { new CRLFMode("FALSE", "false", "Do NOT convert"), }; - public CRLFMode(string name, string value, string desc) { + public CRLFMode(string name, string value, string desc) + { Name = name; Value = value; Desc = desc; } } -} +} \ No newline at end of file diff --git a/src/Models/Change.cs b/src/Models/Change.cs index 7b6b5958..21ba7e6f 100644 --- a/src/Models/Change.cs +++ b/src/Models/Change.cs @@ -1,13 +1,16 @@ using System; -namespace SourceGit.Models { - public enum ChangeViewMode { +namespace SourceGit.Models +{ + public enum ChangeViewMode + { List, Grid, Tree, } - public enum ChangeState { + public enum ChangeState + { None, Modified, Added, @@ -18,14 +21,17 @@ namespace SourceGit.Models { Untracked } - public class Change { + public class Change + { public ChangeState Index { get; set; } public ChangeState WorkTree { get; set; } = ChangeState.None; public string Path { get; set; } = ""; public string OriginalPath { get; set; } = ""; - public bool IsConflit { - get { + public bool IsConflit + { + get + { if (Index == ChangeState.Unmerged || WorkTree == ChangeState.Unmerged) return true; if (Index == ChangeState.Added && WorkTree == ChangeState.Added) return true; if (Index == ChangeState.Deleted && WorkTree == ChangeState.Deleted) return true; @@ -33,18 +39,24 @@ namespace SourceGit.Models { } } - public void Set(ChangeState index, ChangeState workTree = ChangeState.None) { + public void Set(ChangeState index, ChangeState workTree = ChangeState.None) + { Index = index; WorkTree = workTree; - if (index == ChangeState.Renamed || workTree == ChangeState.Renamed) { + if (index == ChangeState.Renamed || workTree == ChangeState.Renamed) + { var idx = Path.IndexOf('\t', StringComparison.Ordinal); - if (idx >= 0) { + if (idx >= 0) + { OriginalPath = Path.Substring(0, idx); Path = Path.Substring(idx + 1); - } else { + } + else + { idx = Path.IndexOf(" -> ", StringComparison.Ordinal); - if (idx > 0) { + if (idx > 0) + { OriginalPath = Path.Substring(0, idx); Path = Path.Substring(idx + 4); } @@ -55,4 +67,4 @@ namespace SourceGit.Models { if (!string.IsNullOrEmpty(OriginalPath) && OriginalPath[0] == '"') OriginalPath = OriginalPath.Substring(1, OriginalPath.Length - 2); } } -} +} \ No newline at end of file diff --git a/src/Models/Commit.cs b/src/Models/Commit.cs index 5b4f1ff6..67e9f72d 100644 --- a/src/Models/Commit.cs +++ b/src/Models/Commit.cs @@ -1,9 +1,12 @@ -using Avalonia; -using System; +using System; using System.Collections.Generic; -namespace SourceGit.Models { - public class Commit { +using Avalonia; + +namespace SourceGit.Models +{ + public class Commit + { public string SHA { get; set; } = string.Empty; public User Author { get; set; } = User.Invalid; public ulong AuthorTime { get; set; } = 0; @@ -22,15 +25,18 @@ namespace SourceGit.Models { public string AuthorTimeShortStr => _utcStart.AddSeconds(AuthorTime).ToString("yyyy/MM/dd"); public string CommitterTimeShortStr => _utcStart.AddSeconds(CommitterTime).ToString("yyyy/MM/dd"); - public bool IsCommitterVisible { + public bool IsCommitterVisible + { get => Author != Committer || AuthorTime != CommitterTime; } - public string FullMessage { + public string FullMessage + { get => string.IsNullOrWhiteSpace(Message) ? Subject : $"{Subject}\n\n{Message}"; } - public static void ParseUserAndTime(string data, ref User user, ref ulong time) { + public static void ParseUserAndTime(string data, ref User user, ref ulong time) + { var userEndIdx = data.IndexOf('>', StringComparison.Ordinal); if (userEndIdx < 0) return; @@ -41,4 +47,4 @@ namespace SourceGit.Models { private static readonly DateTime _utcStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime(); } -} +} \ No newline at end of file diff --git a/src/Models/CommitGraph.cs b/src/Models/CommitGraph.cs index cabaff14..805f2863 100644 --- a/src/Models/CommitGraph.cs +++ b/src/Models/CommitGraph.cs @@ -1,15 +1,20 @@ -using Avalonia; -using System; +using System; using System.Collections.Generic; -namespace SourceGit.Models { - public class CommitGraph { - public class Path { +using Avalonia; + +namespace SourceGit.Models +{ + public class CommitGraph + { + public class Path + { public List Points = new List(); public int Color = 0; } - public class PathHelper { + public class PathHelper + { public string Next; public bool IsMerged; public double LastX; @@ -17,7 +22,8 @@ namespace SourceGit.Models { public double EndY; public Path Path; - public PathHelper(string next, bool isMerged, int color, Point start) { + public PathHelper(string next, bool isMerged, int color, Point start) + { Next = next; IsMerged = isMerged; LastX = start.X; @@ -29,7 +35,8 @@ namespace SourceGit.Models { Path.Points.Add(start); } - public PathHelper(string next, bool isMerged, int color, Point start, Point to) { + public PathHelper(string next, bool isMerged, int color, Point start, Point to) + { Next = next; IsMerged = isMerged; LastX = to.X; @@ -42,15 +49,21 @@ namespace SourceGit.Models { Path.Points.Add(to); } - public void Add(double x, double y, double halfHeight, bool isEnd = false) { - if (x > LastX) { + public void Add(double x, double y, double halfHeight, bool isEnd = false) + { + if (x > LastX) + { Add(new Point(LastX, LastY)); Add(new Point(x, y - halfHeight)); if (isEnd) Add(new Point(x, y)); - } else if (x < LastX) { + } + else if (x < LastX) + { if (y > LastY + halfHeight) Add(new Point(LastX, LastY + halfHeight)); Add(new Point(x, y)); - } else if (isEnd) { + } + else if (isEnd) + { Add(new Point(x, y)); } @@ -58,22 +71,26 @@ namespace SourceGit.Models { LastY = y; } - private void Add(Point p) { - if (EndY < p.Y) { + private void Add(Point p) + { + if (EndY < p.Y) + { Path.Points.Add(p); EndY = p.Y; } } } - public class Link { + public class Link + { public Point Start; public Point Control; public Point End; public int Color; } - public class Dot { + public class Dot + { public Point Center; public int Color; } @@ -82,7 +99,8 @@ namespace SourceGit.Models { public List Links { get; set; } = new List(); public List Dots { get; set; } = new List(); - public static CommitGraph Parse(List commits, double rowHeight, int colorCount) { + public static CommitGraph Parse(List commits, double rowHeight, int colorCount) + { double UNIT_WIDTH = 12; double HALF_WIDTH = 6; double UNIT_HEIGHT = rowHeight; @@ -95,7 +113,8 @@ namespace SourceGit.Models { var offsetY = -HALF_HEIGHT; var colorIdx = 0; - foreach (var commit in commits) { + foreach (var commit in commits) + { var major = null as PathHelper; var isMerged = commit.IsMerged; var oldCount = unsolved.Count; @@ -105,27 +124,37 @@ namespace SourceGit.Models { // Find first curves that links to this commit and marks others that links to this commit ended. double offsetX = -HALF_WIDTH; - foreach (var l in unsolved) { - if (l.Next == commit.SHA) { - if (major == null) { + foreach (var l in unsolved) + { + if (l.Next == commit.SHA) + { + if (major == null) + { offsetX += UNIT_WIDTH; major = l; - if (commit.Parents.Count > 0) { + if (commit.Parents.Count > 0) + { major.Next = commit.Parents[0]; if (!mapUnsolved.ContainsKey(major.Next)) mapUnsolved.Add(major.Next, major); - } else { + } + else + { major.Next = "ENDED"; ended.Add(l); } major.Add(offsetX, offsetY, HALF_HEIGHT); - } else { + } + else + { ended.Add(l); } isMerged = isMerged || l.IsMerged; - } else { + } + else + { if (!mapUnsolved.ContainsKey(l.Next)) mapUnsolved.Add(l.Next, l); offsetX += UNIT_WIDTH; l.Add(offsetX, offsetY, HALF_HEIGHT); @@ -133,7 +162,8 @@ namespace SourceGit.Models { } // Create new curve for branch head - if (major == null && commit.Parents.Count > 0) { + if (major == null && commit.Parents.Count > 0) + { offsetX += UNIT_WIDTH; major = new PathHelper(commit.Parents[0], isMerged, colorIdx, new Point(offsetX, offsetY)); unsolved.Add(major); @@ -143,18 +173,23 @@ namespace SourceGit.Models { // Calculate link position of this commit. Point position = new Point(offsetX, offsetY); - if (major != null) { + if (major != null) + { major.IsMerged = isMerged; position = new Point(major.LastX, offsetY); temp.Dots.Add(new Dot() { Center = position, Color = major.Path.Color }); - } else { + } + else + { temp.Dots.Add(new Dot() { Center = position, Color = 0 }); } // Deal with parents - for (int j = 1; j < commit.Parents.Count; j++) { + for (int j = 1; j < commit.Parents.Count; j++) + { var parent = commit.Parents[j]; - if (mapUnsolved.ContainsKey(parent)) { + if (mapUnsolved.ContainsKey(parent)) + { var l = mapUnsolved[parent]; var link = new Link(); @@ -163,7 +198,9 @@ namespace SourceGit.Models { link.Control = new Point(link.End.X, link.Start.Y); link.Color = l.Path.Color; temp.Links.Add(link); - } else { + } + else + { offsetX += UNIT_WIDTH; // Create new curve for parent commit that not includes before @@ -175,7 +212,8 @@ namespace SourceGit.Models { } // Remove ended curves from unsolved - foreach (var l in ended) { + foreach (var l in ended) + { l.Add(position.X, position.Y, HALF_HEIGHT, true); unsolved.Remove(l); } @@ -190,7 +228,8 @@ namespace SourceGit.Models { } // Deal with curves haven't ended yet. - for (int i = 0; i < unsolved.Count; i++) { + for (int i = 0; i < unsolved.Count; i++) + { var path = unsolved[i]; var endY = (commits.Count - 0.5) * UNIT_HEIGHT; @@ -202,4 +241,4 @@ namespace SourceGit.Models { return temp; } } -} +} \ No newline at end of file diff --git a/src/Models/Decorator.cs b/src/Models/Decorator.cs index 5c306b7f..696bcf0c 100644 --- a/src/Models/Decorator.cs +++ b/src/Models/Decorator.cs @@ -1,7 +1,9 @@ using Avalonia.Media; -namespace SourceGit.Models { - public enum DecoratorType { +namespace SourceGit.Models +{ + public enum DecoratorType + { None, CurrentBranchHead, LocalBranchHead, @@ -9,15 +11,17 @@ namespace SourceGit.Models { Tag, } - public class Decorator { + public class Decorator + { public DecoratorType Type { get; set; } = DecoratorType.None; public string Name { get; set; } = ""; } - public static class DecoratorResources { + public static class DecoratorResources + { public static readonly IBrush[] Backgrounds = [ new SolidColorBrush(0xFF02C302), new SolidColorBrush(0xFFFFB835), ]; } -} +} \ No newline at end of file diff --git a/src/Models/DiffOption.cs b/src/Models/DiffOption.cs index caf25b5f..4187c739 100644 --- a/src/Models/DiffOption.cs +++ b/src/Models/DiffOption.cs @@ -1,8 +1,10 @@ using System.Collections.Generic; using System.Text; -namespace SourceGit.Models { - public class DiffOption { +namespace SourceGit.Models +{ + public class DiffOption + { public Change WorkingCopyChange => _workingCopyChange; public bool IsUnstaged => _isUnstaged; public List Revisions => _revisions; @@ -14,24 +16,29 @@ namespace SourceGit.Models { /// /// /// - public DiffOption(Change change, bool isUnstaged) { + public DiffOption(Change change, bool isUnstaged) + { _workingCopyChange = change; _isUnstaged = isUnstaged; - if (isUnstaged) { - switch (change.WorkTree) { - case ChangeState.Added: - case ChangeState.Untracked: - _extra = "--no-index"; - _path = change.Path; - _orgPath = "/dev/null"; - break; - default: - _path = change.Path; - _orgPath = change.OriginalPath; - break; + if (isUnstaged) + { + switch (change.WorkTree) + { + case ChangeState.Added: + case ChangeState.Untracked: + _extra = "--no-index"; + _path = change.Path; + _orgPath = "/dev/null"; + break; + default: + _path = change.Path; + _orgPath = change.OriginalPath; + break; } - } else { + } + else + { _extra = "--cached"; _path = change.Path; _orgPath = change.OriginalPath; @@ -43,7 +50,8 @@ namespace SourceGit.Models { /// /// /// - public DiffOption(Commit commit, Change change) { + public DiffOption(Commit commit, Change change) + { var baseRevision = commit.Parents.Count == 0 ? "4b825dc642cb6eb9a060e54bf8d69288fbee4904" : $"{commit.SHA}^"; _revisions.Add(baseRevision); _revisions.Add(commit.SHA); @@ -56,7 +64,8 @@ namespace SourceGit.Models { /// /// /// - public DiffOption(Commit commit, string file) { + public DiffOption(Commit commit, string file) + { var baseRevision = commit.Parents.Count == 0 ? "4b825dc642cb6eb9a060e54bf8d69288fbee4904" : $"{commit.SHA}^"; _revisions.Add(baseRevision); _revisions.Add(commit.SHA); @@ -69,7 +78,8 @@ namespace SourceGit.Models { /// /// /// - public DiffOption(string baseRevision, string targetRevision, Change change) { + public DiffOption(string baseRevision, string targetRevision, Change change) + { _revisions.Add(baseRevision); _revisions.Add(targetRevision); _path = change.Path; @@ -80,7 +90,8 @@ namespace SourceGit.Models { /// Converts to diff command arguments. /// /// - public override string ToString() { + public override string ToString() + { var builder = new StringBuilder(); if (!string.IsNullOrEmpty(_extra)) builder.Append($"{_extra} "); foreach (var r in _revisions) builder.Append($"{r} "); @@ -92,11 +103,11 @@ namespace SourceGit.Models { return builder.ToString(); } - private Change _workingCopyChange = null; - private bool _isUnstaged = false; - private string _orgPath = string.Empty; - private string _path = string.Empty; - private string _extra = string.Empty; - private List _revisions = new List(); + private readonly Change _workingCopyChange = null; + private readonly bool _isUnstaged = false; + private readonly string _orgPath = string.Empty; + private readonly string _path = string.Empty; + private readonly string _extra = string.Empty; + private readonly List _revisions = new List(); } -} +} \ No newline at end of file diff --git a/src/Models/DiffResult.cs b/src/Models/DiffResult.cs index 204f509e..1c73aa5b 100644 --- a/src/Models/DiffResult.cs +++ b/src/Models/DiffResult.cs @@ -2,8 +2,10 @@ using System.Text; using System.Text.RegularExpressions; -namespace SourceGit.Models { - public enum TextDiffLineType { +namespace SourceGit.Models +{ + public enum TextDiffLineType + { None, Normal, Indicator, @@ -11,13 +13,15 @@ namespace SourceGit.Models { Deleted, } - public class TextInlineRange { + public class TextInlineRange + { public int Start { get; set; } public int Count { get; set; } public TextInlineRange(int p, int n) { Start = p; Count = n; } } - public class TextDiffLine { + public class TextDiffLine + { public TextDiffLineType Type { get; set; } = TextDiffLineType.None; public string Content { get; set; } = ""; public int OldLineNumber { get; set; } = 0; @@ -28,7 +32,8 @@ 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 content, int oldLine, int newLine) + { Type = type; Content = content; OldLineNumber = oldLine; @@ -36,7 +41,8 @@ namespace SourceGit.Models { } } - public class TextDiffSelection { + public class TextDiffSelection + { public int StartLine { get; set; } = 0; public int EndLine { get; set; } = 0; public bool HasChanges { get; set; } = false; @@ -44,17 +50,20 @@ namespace SourceGit.Models { public int IgnoredAdds { get; set; } = 0; public int IgnoredDeletes { get; set; } = 0; - public bool IsInRange(int idx) { + public bool IsInRange(int idx) + { return idx >= StartLine - 1 && idx < EndLine; } } - public partial class TextDiff { + public partial class TextDiff + { public string File { get; set; } = string.Empty; public List Lines { get; set; } = new List(); public int MaxLineNumber = 0; - public void GenerateNewPatchFromSelection(Change change, string fileBlobGuid, TextDiffSelection selection, bool revert, string output) { + public void GenerateNewPatchFromSelection(Change change, string fileBlobGuid, TextDiffSelection selection, bool revert, string output) + { var isTracked = !string.IsNullOrEmpty(fileBlobGuid); var fileGuid = isTracked ? fileBlobGuid.Substring(0, 8) : "00000000"; @@ -68,17 +77,22 @@ namespace SourceGit.Models { var additions = selection.EndLine - selection.StartLine; if (selection.StartLine != 1) additions++; - if (revert) { + if (revert) + { var totalLines = Lines.Count - 1; builder.Append($"@@ -0,").Append(totalLines - additions).Append(" +0,").Append(totalLines).Append(" @@"); - for (int i = 1; i <= totalLines; i++) { + for (int i = 1; i <= totalLines; i++) + { var line = Lines[i]; if (line.Type != TextDiffLineType.Added) continue; builder.Append(selection.IsInRange(i) ? "\n+" : "\n ").Append(line.Content); } - } else { + } + else + { builder.Append("@@ -0,0 +0,").Append(additions).Append(" @@"); - for (int i = selection.StartLine - 1; i < selection.EndLine; i++) { + for (int i = selection.StartLine - 1; i < selection.EndLine; i++) + { var line = Lines[i]; if (line.Type != TextDiffLineType.Added) continue; builder.Append("\n+").Append(line.Content); @@ -89,7 +103,8 @@ namespace SourceGit.Models { System.IO.File.WriteAllText(output, builder.ToString()); } - public void GeneratePatchFromSelection(Change change, string fileTreeGuid, TextDiffSelection selection, bool revert, string output) { + public void GeneratePatchFromSelection(Change change, string fileTreeGuid, TextDiffSelection selection, bool revert, string output) + { var orgFile = !string.IsNullOrEmpty(change.OriginalPath) ? change.OriginalPath : change.Path; var builder = new StringBuilder(); @@ -100,19 +115,27 @@ namespace SourceGit.Models { // If last line of selection is a change. Find one more line. var tail = null as string; - if (selection.EndLine < Lines.Count) { + if (selection.EndLine < Lines.Count) + { var lastLine = Lines[selection.EndLine - 1]; - if (lastLine.Type == TextDiffLineType.Added || lastLine.Type == TextDiffLineType.Deleted) { - for (int i = selection.EndLine; i < Lines.Count; i++) { + if (lastLine.Type == TextDiffLineType.Added || lastLine.Type == TextDiffLineType.Deleted) + { + for (int i = selection.EndLine; i < Lines.Count; i++) + { var line = Lines[i]; if (line.Type == TextDiffLineType.Indicator) break; - if (revert) { - if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Added) { + if (revert) + { + if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Added) + { tail = line.Content; break; } - } else { - if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Deleted) { + } + else + { + if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Deleted) + { tail = line.Content; break; } @@ -122,11 +145,14 @@ namespace SourceGit.Models { } // If the first line is not indicator. - if (Lines[selection.StartLine - 1].Type != TextDiffLineType.Indicator) { + if (Lines[selection.StartLine - 1].Type != TextDiffLineType.Indicator) + { var indicator = selection.StartLine - 1; - for (int i = selection.StartLine - 2; i >= 0; i--) { + for (int i = selection.StartLine - 2; i >= 0; i--) + { var line = Lines[i]; - if (line.Type == TextDiffLineType.Indicator) { + if (line.Type == TextDiffLineType.Indicator) + { indicator = i; break; } @@ -134,41 +160,62 @@ namespace SourceGit.Models { var ignoreAdds = 0; var ignoreRemoves = 0; - for (int i = 0; i < indicator; i++) { + for (int i = 0; i < indicator; i++) + { var line = Lines[i]; - if (line.Type == TextDiffLineType.Added) { + if (line.Type == TextDiffLineType.Added) + { ignoreAdds++; - } else if (line.Type == TextDiffLineType.Deleted) { + } + else if (line.Type == TextDiffLineType.Deleted) + { ignoreRemoves++; } } - for (int i = indicator; i < selection.StartLine - 1; i++) { + for (int i = indicator; i < selection.StartLine - 1; i++) + { var line = Lines[i]; - if (line.Type == TextDiffLineType.Indicator) { + if (line.Type == TextDiffLineType.Indicator) + { ProcessIndicatorForPatch(builder, line, i, selection.StartLine, selection.EndLine, ignoreRemoves, ignoreAdds, revert, tail != null); - } else if (line.Type == TextDiffLineType.Added) { + } + else if (line.Type == TextDiffLineType.Added) + { if (revert) builder.Append("\n ").Append(line.Content); - } else if (line.Type == TextDiffLineType.Deleted) { + } + else if (line.Type == TextDiffLineType.Deleted) + { if (!revert) builder.Append("\n ").Append(line.Content); - } else if (line.Type == TextDiffLineType.Normal) { + } + else if (line.Type == TextDiffLineType.Normal) + { builder.Append("\n ").Append(line.Content); } } } // Outputs the selected lines. - for (int i = selection.StartLine - 1; i < selection.EndLine; i++) { + for (int i = selection.StartLine - 1; i < selection.EndLine; i++) + { var line = Lines[i]; - if (line.Type == TextDiffLineType.Indicator) { - if (!ProcessIndicatorForPatch(builder, line, i, selection.StartLine, selection.EndLine, selection.IgnoredDeletes, selection.IgnoredAdds, revert, tail != null)) { + if (line.Type == TextDiffLineType.Indicator) + { + if (!ProcessIndicatorForPatch(builder, line, i, selection.StartLine, selection.EndLine, selection.IgnoredDeletes, selection.IgnoredAdds, revert, tail != null)) + { break; } - } else if (line.Type == TextDiffLineType.Normal) { + } + else if (line.Type == TextDiffLineType.Normal) + { builder.Append("\n ").Append(line.Content); - } else if (line.Type == TextDiffLineType.Added) { + } + else if (line.Type == TextDiffLineType.Added) + { builder.Append("\n+").Append(line.Content); - } else if (line.Type == TextDiffLineType.Deleted) { + } + else if (line.Type == TextDiffLineType.Deleted) + { builder.Append("\n-").Append(line.Content); } } @@ -178,7 +225,8 @@ namespace SourceGit.Models { System.IO.File.WriteAllText(output, builder.ToString()); } - public void GeneratePatchFromSelectionSingleSide(Change change, string fileTreeGuid, TextDiffSelection selection, bool revert, bool isOldSide, string output) { + public void GeneratePatchFromSelectionSingleSide(Change change, string fileTreeGuid, TextDiffSelection selection, bool revert, bool isOldSide, string output) + { var orgFile = !string.IsNullOrEmpty(change.OriginalPath) ? change.OriginalPath : change.Path; var builder = new StringBuilder(); @@ -189,19 +237,27 @@ namespace SourceGit.Models { // If last line of selection is a change. Find one more line. var tail = null as string; - if (selection.EndLine < Lines.Count) { + if (selection.EndLine < Lines.Count) + { var lastLine = Lines[selection.EndLine - 1]; - if (lastLine.Type == TextDiffLineType.Added || lastLine.Type == TextDiffLineType.Deleted) { - for (int i = selection.EndLine; i < Lines.Count; i++) { + if (lastLine.Type == TextDiffLineType.Added || lastLine.Type == TextDiffLineType.Deleted) + { + for (int i = selection.EndLine; i < Lines.Count; i++) + { var line = Lines[i]; if (line.Type == TextDiffLineType.Indicator) break; - if (revert) { - if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Added) { + if (revert) + { + if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Added) + { tail = line.Content; break; } - } else { - if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Deleted) { + } + else + { + if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Deleted) + { tail = line.Content; break; } @@ -211,11 +267,14 @@ namespace SourceGit.Models { } // If the first line is not indicator. - if (Lines[selection.StartLine - 1].Type != TextDiffLineType.Indicator) { + if (Lines[selection.StartLine - 1].Type != TextDiffLineType.Indicator) + { var indicator = selection.StartLine - 1; - for (int i = selection.StartLine - 2; i >= 0; i--) { + for (int i = selection.StartLine - 2; i >= 0; i--) + { var line = Lines[i]; - if (line.Type == TextDiffLineType.Indicator) { + if (line.Type == TextDiffLineType.Indicator) + { indicator = i; break; } @@ -223,55 +282,88 @@ namespace SourceGit.Models { var ignoreAdds = 0; var ignoreRemoves = 0; - for (int i = 0; i < indicator; i++) { + for (int i = 0; i < indicator; i++) + { var line = Lines[i]; - if (line.Type == TextDiffLineType.Added) { + if (line.Type == TextDiffLineType.Added) + { ignoreAdds++; - } else if (line.Type == TextDiffLineType.Deleted) { + } + else if (line.Type == TextDiffLineType.Deleted) + { ignoreRemoves++; } } - for (int i = indicator; i < selection.StartLine - 1; i++) { + for (int i = indicator; i < selection.StartLine - 1; i++) + { var line = Lines[i]; - if (line.Type == TextDiffLineType.Indicator) { + if (line.Type == TextDiffLineType.Indicator) + { ProcessIndicatorForPatchSingleSide(builder, line, i, selection.StartLine, selection.EndLine, ignoreRemoves, ignoreAdds, revert, isOldSide, tail != null); - } else if (line.Type == TextDiffLineType.Added) { + } + else if (line.Type == TextDiffLineType.Added) + { if (revert) builder.Append("\n ").Append(line.Content); - } else if (line.Type == TextDiffLineType.Deleted) { + } + else if (line.Type == TextDiffLineType.Deleted) + { if (!revert) builder.Append("\n ").Append(line.Content); - } else if (line.Type == TextDiffLineType.Normal) { + } + else if (line.Type == TextDiffLineType.Normal) + { builder.Append("\n ").Append(line.Content); } } } // Outputs the selected lines. - for (int i = selection.StartLine - 1; i < selection.EndLine; i++) { + for (int i = selection.StartLine - 1; i < selection.EndLine; i++) + { var line = Lines[i]; - if (line.Type == TextDiffLineType.Indicator) { - if (!ProcessIndicatorForPatchSingleSide(builder, line, i, selection.StartLine, selection.EndLine, selection.IgnoredDeletes, selection.IgnoredAdds, revert, isOldSide, tail != null)) { + if (line.Type == TextDiffLineType.Indicator) + { + if (!ProcessIndicatorForPatchSingleSide(builder, line, i, selection.StartLine, selection.EndLine, selection.IgnoredDeletes, selection.IgnoredAdds, revert, isOldSide, tail != null)) + { break; } - } else if (line.Type == TextDiffLineType.Normal) { + } + else if (line.Type == TextDiffLineType.Normal) + { builder.Append("\n ").Append(line.Content); - } else if (line.Type == TextDiffLineType.Added) { - if (isOldSide) { - if (revert) { + } + else if (line.Type == TextDiffLineType.Added) + { + if (isOldSide) + { + if (revert) + { builder.Append("\n ").Append(line.Content); - } else { + } + else + { selection.IgnoredAdds++; } - } else { + } + else + { builder.Append("\n+").Append(line.Content); } - } else if (line.Type == TextDiffLineType.Deleted) { - if (isOldSide) { + } + else if (line.Type == TextDiffLineType.Deleted) + { + if (isOldSide) + { builder.Append("\n-").Append(line.Content); - } else { - if (!revert) { + } + else + { + if (!revert) + { builder.Append("\n ").Append(line.Content); - } else { + } + else + { selection.IgnoredDeletes++; } } @@ -282,50 +374,67 @@ namespace SourceGit.Models { builder.Append("\n"); System.IO.File.WriteAllText(output, builder.ToString()); } - + [GeneratedRegex(@"^@@ \-(\d+),?\d* \+(\d+),?\d* @@")] private static partial Regex indicatorRegex(); - private bool ProcessIndicatorForPatch(StringBuilder builder, TextDiffLine indicator, int idx, int start, int end, int ignoreRemoves, int ignoreAdds, bool revert, bool tailed) { - + private bool ProcessIndicatorForPatch(StringBuilder builder, TextDiffLine indicator, int idx, int start, int end, int ignoreRemoves, int ignoreAdds, bool revert, bool tailed) + { + var match = indicatorRegex().Match(indicator.Content); var oldStart = int.Parse(match.Groups[1].Value); var newStart = int.Parse(match.Groups[2].Value) + ignoreRemoves - ignoreAdds; var oldCount = 0; var newCount = 0; - for (int i = idx + 1; i < end; i++) { + for (int i = idx + 1; i < end; i++) + { var test = Lines[i]; if (test.Type == TextDiffLineType.Indicator) break; - if (test.Type == TextDiffLineType.Normal) { + if (test.Type == TextDiffLineType.Normal) + { oldCount++; newCount++; - } else if (test.Type == TextDiffLineType.Added) { - if (i < start - 1) { - if (revert) { + } + else if (test.Type == TextDiffLineType.Added) + { + if (i < start - 1) + { + if (revert) + { newCount++; oldCount++; } - } else { + } + else + { newCount++; } - if (i == end - 1 && tailed) { + if (i == end - 1 && tailed) + { newCount++; oldCount++; } - } else if (test.Type == TextDiffLineType.Deleted) { - if (i < start - 1) { - if (!revert) { + } + else if (test.Type == TextDiffLineType.Deleted) + { + if (i < start - 1) + { + if (!revert) + { newCount++; oldCount++; } - } else { + } + else + { oldCount++; } - if (i == end - 1 && tailed) { + if (i == end - 1 && tailed) + { newCount++; oldCount++; } @@ -338,59 +447,84 @@ namespace SourceGit.Models { return true; } - private bool ProcessIndicatorForPatchSingleSide(StringBuilder builder, TextDiffLine indicator, int idx, int start, int end, int ignoreRemoves, int ignoreAdds, bool revert, bool isOldSide, bool tailed) { + private bool ProcessIndicatorForPatchSingleSide(StringBuilder builder, TextDiffLine indicator, int idx, int start, int end, int ignoreRemoves, int ignoreAdds, bool revert, bool isOldSide, bool tailed) + { var match = indicatorRegex().Match(indicator.Content); var oldStart = int.Parse(match.Groups[1].Value); var newStart = int.Parse(match.Groups[2].Value) + ignoreRemoves - ignoreAdds; var oldCount = 0; var newCount = 0; - for (int i = idx + 1; i < end; i++) { + for (int i = idx + 1; i < end; i++) + { var test = Lines[i]; if (test.Type == TextDiffLineType.Indicator) break; - if (test.Type == TextDiffLineType.Normal) { + if (test.Type == TextDiffLineType.Normal) + { oldCount++; newCount++; - } else if (test.Type == TextDiffLineType.Added) { - if (i < start - 1) { - if (revert) { + } + else if (test.Type == TextDiffLineType.Added) + { + if (i < start - 1) + { + if (revert) + { newCount++; oldCount++; } - } else { - if (isOldSide) { - if (revert) { + } + else + { + if (isOldSide) + { + if (revert) + { newCount++; oldCount++; } - } else { + } + else + { newCount++; } } - if (i == end - 1 && tailed) { + if (i == end - 1 && tailed) + { newCount++; oldCount++; } - } else if (test.Type == TextDiffLineType.Deleted) { - if (i < start - 1) { - if (!revert) { + } + else if (test.Type == TextDiffLineType.Deleted) + { + if (i < start - 1) + { + if (!revert) + { newCount++; oldCount++; } - } else { - if (isOldSide) { + } + else + { + if (isOldSide) + { oldCount++; - } else { - if (!revert) { + } + else + { + if (!revert) + { newCount++; oldCount++; } } } - if (i == end - 1 && tailed) { + if (i == end - 1 && tailed) + { newCount++; oldCount++; } @@ -404,20 +538,23 @@ namespace SourceGit.Models { } } - public class LFSDiff { + public class LFSDiff + { public LFSObject Old { get; set; } = new LFSObject(); public LFSObject New { get; set; } = new LFSObject(); } - public class BinaryDiff { + public class BinaryDiff + { public long OldSize { get; set; } = 0; public long NewSize { get; set; } = 0; } - public class DiffResult { + public class DiffResult + { public bool IsBinary { get; set; } = false; public bool IsLFS { get; set; } = false; public TextDiff TextDiff { get; set; } = null; public LFSDiff LFSDiff { get; set; } = null; } -} +} \ No newline at end of file diff --git a/src/Models/ExternalMergeTools.cs b/src/Models/ExternalMergeTools.cs index 6efd6471..4fa2fcb1 100644 --- a/src/Models/ExternalMergeTools.cs +++ b/src/Models/ExternalMergeTools.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; -namespace SourceGit.Models { - public class ExternalMergeTools { +namespace SourceGit.Models +{ + public class ExternalMergeTools + { public int Type { get; set; } public string Name { get; set; } public string Exec { get; set; } @@ -11,8 +13,10 @@ namespace SourceGit.Models { public static List Supported; - static ExternalMergeTools() { - if (OperatingSystem.IsWindows()) { + static ExternalMergeTools() + { + if (OperatingSystem.IsWindows()) + { Supported = new List() { new ExternalMergeTools(0, "Custom", "", "", ""), new ExternalMergeTools(1, "Visual Studio Code", "Code.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""), @@ -22,7 +26,9 @@ namespace SourceGit.Models { new ExternalMergeTools(5, "Beyond Compare 4", "BComp.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), new ExternalMergeTools(6, "WinMerge", "WinMergeU.exe", "-u -e \"$REMOTE\" \"$LOCAL\" \"$MERGED\"", "-u -e \"$LOCAL\" \"$REMOTE\""), }; - } else if (OperatingSystem.IsMacOS()) { + } + else if (OperatingSystem.IsMacOS()) + { Supported = new List() { new ExternalMergeTools(0, "Custom", "", "", ""), new ExternalMergeTools(1, "FileMerge", "/usr/bin/opendiff", "\"$BASE\" \"$LOCAL\" \"$REMOTE\" -ancestor \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), @@ -30,21 +36,26 @@ namespace SourceGit.Models { new ExternalMergeTools(3, "KDiff3", "/Applications/kdiff3.app/Contents/MacOS/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), new ExternalMergeTools(4, "Beyond Compare 4", "/Applications/Beyond Compare.app/Contents/MacOS/bcomp", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), }; - } else if (OperatingSystem.IsLinux()) { + } + else if (OperatingSystem.IsLinux()) + { Supported = new List() { new ExternalMergeTools(0, "Custom", "", "", ""), new ExternalMergeTools(1, "Visual Studio Code", "/usr/share/code/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""), new ExternalMergeTools(2, "KDiff3", "/usr/bin/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), new ExternalMergeTools(3, "Beyond Compare 4", "/usr/bin/bcomp", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), }; - } else { + } + else + { Supported = new List() { new ExternalMergeTools(0, "Custom", "", "", ""), }; } } - public ExternalMergeTools(int type, string name, string exec, string cmd, string diffCmd) { + public ExternalMergeTools(int type, string name, string exec, string cmd, string diffCmd) + { Type = type; Name = name; Exec = exec; @@ -52,4 +63,4 @@ namespace SourceGit.Models { DiffCmd = diffCmd; } } -} +} \ No newline at end of file diff --git a/src/Models/GitFlow.cs b/src/Models/GitFlow.cs index dca2aa91..a8e28adb 100644 --- a/src/Models/GitFlow.cs +++ b/src/Models/GitFlow.cs @@ -1,25 +1,31 @@ -namespace SourceGit.Models { - public enum GitFlowBranchType { +namespace SourceGit.Models +{ + public enum GitFlowBranchType + { None, Feature, Release, Hotfix, } - public class GitFlow { + public class GitFlow + { public string Feature { get; set; } public string Release { get; set; } public string Hotfix { get; set; } - public bool IsEnabled { - get { + public bool IsEnabled + { + get + { return !string.IsNullOrEmpty(Feature) && !string.IsNullOrEmpty(Release) && !string.IsNullOrEmpty(Hotfix); } } - public GitFlowBranchType GetBranchType(string name) { + public GitFlowBranchType GetBranchType(string name) + { if (!IsEnabled) return GitFlowBranchType.None; if (name.StartsWith(Feature)) return GitFlowBranchType.Feature; if (name.StartsWith(Release)) return GitFlowBranchType.Release; @@ -27,4 +33,4 @@ return GitFlowBranchType.None; } } -} +} \ No newline at end of file diff --git a/src/Models/LFSObject.cs b/src/Models/LFSObject.cs index 13bf0b32..e92d4a10 100644 --- a/src/Models/LFSObject.cs +++ b/src/Models/LFSObject.cs @@ -1,6 +1,8 @@ -namespace SourceGit.Models { - public class LFSObject { +namespace SourceGit.Models +{ + public class LFSObject + { public string Oid { get; set; } = string.Empty; public long Size { get; set; } = 0; } -} +} \ No newline at end of file diff --git a/src/Models/Locales.cs b/src/Models/Locales.cs index 35bb7a29..1ef72ea1 100644 --- a/src/Models/Locales.cs +++ b/src/Models/Locales.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; -namespace SourceGit.Models { - public class Locale { +namespace SourceGit.Models +{ + public class Locale + { public string Name { get; set; } public string Key { get; set; } @@ -10,9 +12,10 @@ namespace SourceGit.Models { new Locale("简体中文", "zh_CN"), }; - public Locale(string name, string key) { + public Locale(string name, string key) + { Name = name; Key = key; } } -} +} \ No newline at end of file diff --git a/src/Models/Notification.cs b/src/Models/Notification.cs index 08c888b9..0eae0890 100644 --- a/src/Models/Notification.cs +++ b/src/Models/Notification.cs @@ -1,10 +1,13 @@ -namespace SourceGit.Models { - public class Notification { +namespace SourceGit.Models +{ + public class Notification + { public bool IsError { get; set; } = false; public string Message { get; set; } = string.Empty; } - public interface INotificationReceiver { + public interface INotificationReceiver + { void OnReceiveNotification(string ctx, Notification notice); } -} +} \ No newline at end of file diff --git a/src/Models/Object.cs b/src/Models/Object.cs index c2f27a31..5829a0ba 100644 --- a/src/Models/Object.cs +++ b/src/Models/Object.cs @@ -1,5 +1,7 @@ -namespace SourceGit.Models { - public enum ObjectType { +namespace SourceGit.Models +{ + public enum ObjectType + { None, Blob, Tree, @@ -7,9 +9,10 @@ Commit, } - public class Object { + public class Object + { public string SHA { get; set; } public ObjectType Type { get; set; } public string Path { get; set; } } -} +} \ No newline at end of file diff --git a/src/Models/Remote.cs b/src/Models/Remote.cs index fb3ae399..5539c4d9 100644 --- a/src/Models/Remote.cs +++ b/src/Models/Remote.cs @@ -1,8 +1,10 @@ using System.Text.RegularExpressions; -namespace SourceGit.Models { - public partial class Remote { - +namespace SourceGit.Models +{ + public partial class Remote + { + [GeneratedRegex(@"^http[s]?://([\w\-]+@)?[\w\.\-]+(\:[0-9]+)?/[\w\-]+/[\w\-\.]+\.git$")] private static partial Regex regex1(); @@ -10,7 +12,7 @@ namespace SourceGit.Models { private static partial Regex regex2(); [GeneratedRegex(@"^ssh://([\w\-]+@)?[\w\.\-]+(\:[0-9]+)?/[\w\-]+/[\w\-\.]+\.git$")] private static partial Regex regex3(); - + private static readonly Regex[] URL_FORMATS = [ regex1(), regex2(), @@ -20,21 +22,25 @@ namespace SourceGit.Models { public string Name { get; set; } public string URL { get; set; } - public static bool IsSSH(string url) { + public static bool IsSSH(string url) + { if (string.IsNullOrWhiteSpace(url)) return false; - for (int i = 1; i < URL_FORMATS.Length; i++) { + for (int i = 1; i < URL_FORMATS.Length; i++) + { if (URL_FORMATS[i].IsMatch(url)) return true; } return false; } - public static bool IsValidURL(string url) { - foreach (var fmt in URL_FORMATS) { + public static bool IsValidURL(string url) + { + foreach (var fmt in URL_FORMATS) + { if (fmt.IsMatch(url)) return true; } return false; } } -} +} \ No newline at end of file diff --git a/src/Models/RevisionFile.cs b/src/Models/RevisionFile.cs index f1effc4d..71ba4fd0 100644 --- a/src/Models/RevisionFile.cs +++ b/src/Models/RevisionFile.cs @@ -1,18 +1,23 @@ -namespace SourceGit.Models { - public class RevisionBinaryFile { +namespace SourceGit.Models +{ + public class RevisionBinaryFile + { public long Size { get; set; } = 0; } - public class RevisionTextFile { + public class RevisionTextFile + { public string FileName { get; set; } public string Content { get; set; } } - public class RevisionLFSObject { + public class RevisionLFSObject + { public LFSObject Object { get; set; } } - public class RevisionSubmodule { + public class RevisionSubmodule + { public string SHA { get; set; } } -} +} \ No newline at end of file diff --git a/src/Models/Stash.cs b/src/Models/Stash.cs index 8b2973b9..550f6100 100644 --- a/src/Models/Stash.cs +++ b/src/Models/Stash.cs @@ -1,7 +1,9 @@ using System; -namespace SourceGit.Models { - public class Stash { +namespace SourceGit.Models +{ + public class Stash + { private static readonly DateTime UTC_START = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime(); public string Name { get; set; } = ""; @@ -12,4 +14,4 @@ namespace SourceGit.Models { public string TimeStr => UTC_START.AddSeconds(Time).ToString("yyyy/MM/dd HH:mm:ss"); } -} +} \ No newline at end of file diff --git a/src/Models/Statistics.cs b/src/Models/Statistics.cs index 7f4e4809..ebebb46c 100644 --- a/src/Models/Statistics.cs +++ b/src/Models/Statistics.cs @@ -1,44 +1,54 @@ using System; using System.Collections.Generic; -namespace SourceGit.Models { - public class StatisticsSample { +namespace SourceGit.Models +{ + public class StatisticsSample + { public string Name { get; set; } public int Count { get; set; } } - public class StatisticsReport { + public class StatisticsReport + { public int Total { get; set; } = 0; public List Samples { get; set; } = new List(); public List ByCommitter { get; set; } = new List(); - public void AddCommit(int index, string committer) { + public void AddCommit(int index, string committer) + { Total++; Samples[index].Count++; - if (_mapByCommitter.ContainsKey(committer)) { + if (_mapByCommitter.ContainsKey(committer)) + { _mapByCommitter[committer].Count++; - } else { + } + else + { var sample = new StatisticsSample() { Name = committer, Count = 1 }; _mapByCommitter.Add(committer, sample); ByCommitter.Add(sample); } } - public void Complete() { + public void Complete() + { ByCommitter.Sort((l, r) => r.Count - l.Count); _mapByCommitter.Clear(); } - private Dictionary _mapByCommitter = new Dictionary(); + private readonly Dictionary _mapByCommitter = new Dictionary(); } - public class Statistics { + public class Statistics + { public StatisticsReport Year { get; set; } = new StatisticsReport(); public StatisticsReport Month { get; set; } = new StatisticsReport(); public StatisticsReport Week { get; set; } = new StatisticsReport(); - public Statistics() { + public Statistics() + { _utcStart = DateTime.UnixEpoch; _today = DateTime.Today; _thisWeekStart = _today.AddSeconds(-(int)_today.DayOfWeek * 3600 * 24 - _today.Hour * 3600 - _today.Minute * 60 - _today.Second); @@ -59,16 +69,20 @@ namespace SourceGit.Models { "Dec", ]; - for (int i = 0; i < monthNames.Length; i++) { - Year.Samples.Add(new StatisticsSample { + for (int i = 0; i < monthNames.Length; i++) + { + Year.Samples.Add(new StatisticsSample + { Name = monthNames[i], Count = 0, }); } var monthDays = DateTime.DaysInMonth(_today.Year, _today.Month); - for (int i = 0; i < monthDays; i++) { - Month.Samples.Add(new StatisticsSample { + for (int i = 0; i < monthDays; i++) + { + Month.Samples.Add(new StatisticsSample + { Name = $"{i + 1}", Count = 0, }); @@ -84,40 +98,47 @@ namespace SourceGit.Models { "SAT", ]; - for (int i = 0; i < weekDayNames.Length; i++) { - Week.Samples.Add(new StatisticsSample { + for (int i = 0; i < weekDayNames.Length; i++) + { + Week.Samples.Add(new StatisticsSample + { Name = weekDayNames[i], Count = 0, }); } } - public string Since() { + public string Since() + { return _today.ToString("yyyy-01-01 00:00:00"); } - public void AddCommit(string committer, double timestamp) { + public void AddCommit(string committer, double timestamp) + { var time = _utcStart.AddSeconds(timestamp).ToLocalTime(); - if (time.CompareTo(_thisWeekStart) >= 0 && time.CompareTo(_thisWeekEnd) < 0) { + if (time.CompareTo(_thisWeekStart) >= 0 && time.CompareTo(_thisWeekEnd) < 0) + { Week.AddCommit((int)time.DayOfWeek, committer); } - if (time.Month == _today.Month) { + if (time.Month == _today.Month) + { Month.AddCommit(time.Day - 1, committer); } - Year.AddCommit(time.Month - 1, committer); + Year.AddCommit(time.Month - 1, committer); } - public void Complete() { + public void Complete() + { Year.Complete(); Month.Complete(); Week.Complete(); } - private DateTime _utcStart; - private DateTime _today; - private DateTime _thisWeekStart; - private DateTime _thisWeekEnd; + private readonly DateTime _utcStart; + private readonly DateTime _today; + private readonly DateTime _thisWeekStart; + private readonly DateTime _thisWeekEnd; } -} +} \ No newline at end of file diff --git a/src/Models/Tag.cs b/src/Models/Tag.cs index 6f51a06e..e87aec4e 100644 --- a/src/Models/Tag.cs +++ b/src/Models/Tag.cs @@ -1,7 +1,9 @@ -namespace SourceGit.Models { - public class Tag { +namespace SourceGit.Models +{ + public class Tag + { public string Name { get; set; } public string SHA { get; set; } public bool IsFiltered { get; set; } } -} +} \ No newline at end of file diff --git a/src/Models/TextInlineChange.cs b/src/Models/TextInlineChange.cs index 6ce4c374..0a4345d1 100644 --- a/src/Models/TextInlineChange.cs +++ b/src/Models/TextInlineChange.cs @@ -1,19 +1,23 @@ using System.Collections.Generic; -namespace SourceGit.Models { - public class TextInlineChange { +namespace SourceGit.Models +{ + public class TextInlineChange + { public int DeletedStart { get; set; } public int DeletedCount { get; set; } public int AddedStart { get; set; } public int AddedCount { get; set; } - class Chunk { + class Chunk + { public int Hash; public bool Modified; public int Start; public int Size; - public Chunk(int hash, int start, int size) { + public Chunk(int hash, int start, int size) + { Hash = hash; Modified = false; Start = start; @@ -21,7 +25,8 @@ namespace SourceGit.Models { } } - enum Edit { + enum Edit + { None, DeletedRight, DeletedLeft, @@ -29,7 +34,8 @@ namespace SourceGit.Models { AddedLeft, } - class EditResult { + class EditResult + { public Edit State; public int DeleteStart; public int DeleteEnd; @@ -37,14 +43,16 @@ namespace SourceGit.Models { public int AddEnd; } - public TextInlineChange(int dp, int dc, int ap, int ac) { + public TextInlineChange(int dp, int dc, int ap, int ac) + { DeletedStart = dp; DeletedCount = dc; AddedStart = ap; AddedCount = ac; } - public static List Compare(string oldValue, string newValue) { + public static List Compare(string oldValue, string newValue) + { var hashes = new Dictionary(); var chunksOld = MakeChunks(hashes, oldValue); var chunksNew = MakeChunks(hashes, newValue); @@ -59,8 +67,10 @@ namespace SourceGit.Models { var posOld = 0; var posNew = 0; var last = null as TextInlineChange; - do { - while (posOld < sizeOld && posNew < sizeNew && !chunksOld[posOld].Modified && !chunksNew[posNew].Modified) { + do + { + while (posOld < sizeOld && posNew < sizeNew && !chunksOld[posOld].Modified && !chunksNew[posNew].Modified) + { posOld++; posNew++; } @@ -79,10 +89,12 @@ namespace SourceGit.Models { countOld, countNew > 0 ? chunksNew[beginNew].Start : 0, countNew); - if (last != null) { + if (last != null) + { var midSizeOld = diff.DeletedStart - last.DeletedStart - last.DeletedCount; var midSizeNew = diff.AddedStart - last.AddedStart - last.AddedCount; - if (midSizeOld == 1 && midSizeNew == 1) { + if (midSizeOld == 1 && midSizeNew == 1) + { last.DeletedCount += (1 + countOld); last.AddedCount += (1 + countNew); continue; @@ -96,15 +108,18 @@ namespace SourceGit.Models { return ret; } - private static List MakeChunks(Dictionary hashes, string text) { + private static List MakeChunks(Dictionary hashes, string text) + { var start = 0; var size = text.Length; var chunks = new List(); var delims = new HashSet(" \t+-*/=!,:;.'\"/?|&#@%`<>()[]{}\\".ToCharArray()); - for (int i = 0; i < size; i++) { + for (int i = 0; i < size; i++) + { var ch = text[i]; - if (delims.Contains(ch)) { + if (delims.Contains(ch)) + { if (start != i) AddChunk(chunks, hashes, text.Substring(start, i - start), start); AddChunk(chunks, hashes, text.Substring(i, 1), i); start = i + 1; @@ -115,43 +130,59 @@ namespace SourceGit.Models { return chunks; } - private static void CheckModified(List chunksOld, int startOld, int endOld, List chunksNew, int startNew, int endNew, int[] forward, int[] reverse) { - while (startOld < endOld && startNew < endNew && chunksOld[startOld].Hash == chunksNew[startNew].Hash) { + private static void CheckModified(List chunksOld, int startOld, int endOld, List chunksNew, int startNew, int endNew, int[] forward, int[] reverse) + { + while (startOld < endOld && startNew < endNew && chunksOld[startOld].Hash == chunksNew[startNew].Hash) + { startOld++; startNew++; } - while (startOld < endOld && startNew < endNew && chunksOld[endOld - 1].Hash == chunksNew[endNew - 1].Hash) { + while (startOld < endOld && startNew < endNew && chunksOld[endOld - 1].Hash == chunksNew[endNew - 1].Hash) + { endOld--; endNew--; } var lenOld = endOld - startOld; var lenNew = endNew - startNew; - if (lenOld > 0 && lenNew > 0) { + if (lenOld > 0 && lenNew > 0) + { var rs = CheckModifiedEdit(chunksOld, startOld, endOld, chunksNew, startNew, endNew, forward, reverse); if (rs.State == Edit.None) return; - if (rs.State == Edit.DeletedRight && rs.DeleteStart - 1 > startOld) { + if (rs.State == Edit.DeletedRight && rs.DeleteStart - 1 > startOld) + { chunksOld[--rs.DeleteStart].Modified = true; - } else if (rs.State == Edit.DeletedLeft && rs.DeleteEnd < endOld) { + } + else if (rs.State == Edit.DeletedLeft && rs.DeleteEnd < endOld) + { chunksOld[rs.DeleteEnd++].Modified = true; - } else if (rs.State == Edit.AddedRight && rs.AddStart - 1 > startNew) { + } + else if (rs.State == Edit.AddedRight && rs.AddStart - 1 > startNew) + { chunksNew[--rs.AddStart].Modified = true; - } else if (rs.State == Edit.AddedLeft && rs.AddEnd < endNew) { + } + else if (rs.State == Edit.AddedLeft && rs.AddEnd < endNew) + { chunksNew[rs.AddEnd++].Modified = true; } CheckModified(chunksOld, startOld, rs.DeleteStart, chunksNew, startNew, rs.AddStart, forward, reverse); CheckModified(chunksOld, rs.DeleteEnd, endOld, chunksNew, rs.AddEnd, endNew, forward, reverse); - } else if (lenOld > 0) { + } + else if (lenOld > 0) + { for (int i = startOld; i < endOld; i++) chunksOld[i].Modified = true; - } else if (lenNew > 0) { + } + else if (lenNew > 0) + { for (int i = startNew; i < endNew; i++) chunksNew[i].Modified = true; } } - private static EditResult CheckModifiedEdit(List chunksOld, int startOld, int endOld, List chunksNew, int startNew, int endNew, int[] forward, int[] reverse) { + private static EditResult CheckModifiedEdit(List chunksOld, int startOld, int endOld, List chunksNew, int startNew, int endNew, int[] forward, int[] reverse) + { var lenOld = endOld - startOld; var lenNew = endNew - startNew; var max = lenOld + lenNew + 1; @@ -163,15 +194,20 @@ namespace SourceGit.Models { forward[1 + half] = 0; reverse[1 + half] = lenOld + 1; - for (int i = 0; i <= half; i++) { + for (int i = 0; i <= half; i++) + { - for (int j = -i; j <= i; j += 2) { + for (int j = -i; j <= i; j += 2) + { var idx = j + half; int o, n; - if (j == -i || (j != i && forward[idx - 1] < forward[idx + 1])) { + if (j == -i || (j != i && forward[idx - 1] < forward[idx + 1])) + { o = forward[idx + 1]; rs.State = Edit.AddedRight; - } else { + } + else + { o = forward[idx - 1] + 1; rs.State = Edit.DeletedRight; } @@ -180,21 +216,27 @@ namespace SourceGit.Models { var startX = o; var startY = n; - while (o < lenOld && n < lenNew && chunksOld[o + startOld].Hash == chunksNew[n + startNew].Hash) { + while (o < lenOld && n < lenNew && chunksOld[o + startOld].Hash == chunksNew[n + startNew].Hash) + { o++; n++; } forward[idx] = o; - if (!deltaEven && j - delta >= -i + 1 && j - delta <= i - 1) { + if (!deltaEven && j - delta >= -i + 1 && j - delta <= i - 1) + { var revIdx = (j - delta) + half; var revOld = reverse[revIdx]; int revNew = revOld - j; - if (revOld <= o && revNew <= n) { - if (i == 0) { + if (revOld <= o && revNew <= n) + { + if (i == 0) + { rs.State = Edit.None; - } else { + } + else + { rs.DeleteStart = startX + startOld; rs.DeleteEnd = o + startOld; rs.AddStart = startY + startNew; @@ -205,13 +247,17 @@ namespace SourceGit.Models { } } - for (int j = -i; j <= i; j += 2) { + for (int j = -i; j <= i; j += 2) + { var idx = j + half; int o, n; - if (j == -i || (j != i && reverse[idx + 1] <= reverse[idx - 1])) { + if (j == -i || (j != i && reverse[idx + 1] <= reverse[idx - 1])) + { o = reverse[idx + 1] - 1; rs.State = Edit.DeletedLeft; - } else { + } + else + { o = reverse[idx - 1]; rs.State = Edit.AddedLeft; } @@ -220,21 +266,27 @@ namespace SourceGit.Models { var endX = o; var endY = n; - while (o > 0 && n > 0 && chunksOld[startOld + o - 1].Hash == chunksNew[startNew + n - 1].Hash) { + while (o > 0 && n > 0 && chunksOld[startOld + o - 1].Hash == chunksNew[startNew + n - 1].Hash) + { o--; n--; } reverse[idx] = o; - if (deltaEven && j + delta >= -i && j + delta <= i) { + if (deltaEven && j + delta >= -i && j + delta <= i) + { var forIdx = (j + delta) + half; var forOld = forward[forIdx]; int forNew = forOld - (j + delta); - if (forOld >= o && forNew >= n) { - if (i == 0) { + if (forOld >= o && forNew >= n) + { + if (i == 0) + { rs.State = Edit.None; - } else { + } + else + { rs.DeleteStart = o + startOld; rs.DeleteEnd = endX + startOld; rs.AddStart = n + startNew; @@ -250,15 +302,19 @@ namespace SourceGit.Models { return rs; } - private static void AddChunk(List chunks, Dictionary hashes, string data, int start) { + private static void AddChunk(List chunks, Dictionary hashes, string data, int start) + { int hash; - if (hashes.TryGetValue(data, out hash)) { + if (hashes.TryGetValue(data, out hash)) + { chunks.Add(new Chunk(hash, start, data.Length)); - } else { + } + else + { hash = hashes.Count; hashes.Add(data, hash); chunks.Add(new Chunk(hash, start, data.Length)); } } } -} +} \ No newline at end of file diff --git a/src/Models/User.cs b/src/Models/User.cs index 7f7a85ef..26c3c35d 100644 --- a/src/Models/User.cs +++ b/src/Models/User.cs @@ -1,28 +1,36 @@ using System.Collections.Generic; -namespace SourceGit.Models { - public class User { +namespace SourceGit.Models +{ + public class User + { public static User Invalid = new User(); public static Dictionary Caches = new Dictionary(); public string Name { get; set; } = string.Empty; public string Email { get; set; } = string.Empty; - public override bool Equals(object obj) { + public override bool Equals(object obj) + { if (obj == null || !(obj is User)) return false; var other = obj as User; return Name == other.Name && Email == other.Email; } - public override int GetHashCode() { + public override int GetHashCode() + { return base.GetHashCode(); } - public static User FindOrAdd(string data) { - if (Caches.ContainsKey(data)) { + public static User FindOrAdd(string data) + { + if (Caches.ContainsKey(data)) + { return Caches[data]; - } else { + } + else + { var nameEndIdx = data.IndexOf('<', System.StringComparison.Ordinal); var name = nameEndIdx >= 2 ? data.Substring(0, nameEndIdx - 1) : string.Empty; var email = data.Substring(nameEndIdx + 1); @@ -33,4 +41,4 @@ namespace SourceGit.Models { } } } -} +} \ No newline at end of file diff --git a/src/Models/Watcher.cs b/src/Models/Watcher.cs index 9ecbaa1d..c6de1882 100644 --- a/src/Models/Watcher.cs +++ b/src/Models/Watcher.cs @@ -3,8 +3,10 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -namespace SourceGit.Models { - public interface IRepository { +namespace SourceGit.Models +{ + public interface IRepository + { string FullPath { get; set; } string GitDir { get; set; } @@ -16,8 +18,10 @@ namespace SourceGit.Models { void RefreshStashes(); } - public class Watcher : IDisposable { - public Watcher(IRepository repo) { + public class Watcher : IDisposable + { + public Watcher(IRepository repo) + { _repo = repo; _wcWatcher = new FileSystemWatcher(); @@ -45,23 +49,30 @@ namespace SourceGit.Models { _timer = new Timer(Tick, null, 100, 100); } - public void SetEnabled(bool enabled) { - if (enabled) { + public void SetEnabled(bool enabled) + { + if (enabled) + { if (_lockCount > 0) _lockCount--; - } else { + } + else + { _lockCount++; } } - public void MarkBranchDirtyManually() { + public void MarkBranchDirtyManually() + { _updateBranch = DateTime.Now.ToFileTime() - 1; } - public void MarkWorkingCopyDirtyManually() { + public void MarkWorkingCopyDirtyManually() + { _updateWC = DateTime.Now.ToFileTime() - 1; } - public void Dispose() { + public void Dispose() + { _repoWatcher.EnableRaisingEvents = false; _repoWatcher.Created -= OnRepositoryChanged; _repoWatcher.Renamed -= OnRepositoryChanged; @@ -82,23 +93,30 @@ namespace SourceGit.Models { _timer = null; } - private void Tick(object sender) { + private void Tick(object sender) + { if (_lockCount > 0) return; var now = DateTime.Now.ToFileTime(); - if (_updateBranch > 0 && now > _updateBranch) { + if (_updateBranch > 0 && now > _updateBranch) + { _updateBranch = 0; _updateWC = 0; - if (_updateTags > 0) { + if (_updateTags > 0) + { _updateTags = 0; - Task.Run(() => { + Task.Run(() => + { _repo.RefreshTags(); _repo.RefreshBranches(); _repo.RefreshCommits(); }); - } else { - Task.Run(() => { + } + else + { + Task.Run(() => + { _repo.RefreshBranches(); _repo.RefreshCommits(); }); @@ -107,49 +125,64 @@ namespace SourceGit.Models { Task.Run(_repo.RefreshWorkingCopyChanges); } - if (_updateWC > 0 && now > _updateWC) { + if (_updateWC > 0 && now > _updateWC) + { _updateWC = 0; Task.Run(_repo.RefreshWorkingCopyChanges); } - if (_updateSubmodules > 0 && now > _updateSubmodules) { + if (_updateSubmodules > 0 && now > _updateSubmodules) + { _updateSubmodules = 0; _repo.RefreshSubmodules(); } - if (_updateStashes > 0 && now > _updateStashes) { + if (_updateStashes > 0 && now > _updateStashes) + { _updateStashes = 0; _repo.RefreshStashes(); } - if (_updateTags > 0 && now > _updateTags) { + if (_updateTags > 0 && now > _updateTags) + { _updateTags = 0; _repo.RefreshTags(); _repo.RefreshCommits(); } } - private void OnRepositoryChanged(object o, FileSystemEventArgs e) { + private void OnRepositoryChanged(object o, FileSystemEventArgs e) + { if (string.IsNullOrEmpty(e.Name)) return; var name = e.Name.Replace("\\", "/"); - if (name.StartsWith("modules", StringComparison.Ordinal)) { + if (name.StartsWith("modules", StringComparison.Ordinal)) + { _updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime(); - } else if (name.StartsWith("refs/tags", StringComparison.Ordinal)) { + } + else if (name.StartsWith("refs/tags", StringComparison.Ordinal)) + { _updateTags = DateTime.Now.AddSeconds(.5).ToFileTime(); - } else if (name.StartsWith("refs/stash", StringComparison.Ordinal)) { + } + else if (name.StartsWith("refs/stash", StringComparison.Ordinal)) + { _updateStashes = DateTime.Now.AddSeconds(.5).ToFileTime(); - } else if (name.Equals("HEAD", StringComparison.Ordinal) || + } + else if (name.Equals("HEAD", StringComparison.Ordinal) || name.StartsWith("refs/heads/", StringComparison.Ordinal) || name.StartsWith("refs/remotes/", StringComparison.Ordinal) || - name.StartsWith("worktrees/", StringComparison.Ordinal)) { + name.StartsWith("worktrees/", StringComparison.Ordinal)) + { _updateBranch = DateTime.Now.AddSeconds(.5).ToFileTime(); - } else if (name.StartsWith("objects/", StringComparison.Ordinal) || name.Equals("index", StringComparison.Ordinal)) { + } + else if (name.StartsWith("objects/", StringComparison.Ordinal) || name.Equals("index", StringComparison.Ordinal)) + { _updateWC = DateTime.Now.AddSeconds(1).ToFileTime(); } } - private void OnWorkingCopyChanged(object o, FileSystemEventArgs e) { + private void OnWorkingCopyChanged(object o, FileSystemEventArgs e) + { if (string.IsNullOrEmpty(e.Name)) return; var name = e.Name.Replace("\\", "/"); @@ -157,7 +190,7 @@ namespace SourceGit.Models { _updateWC = DateTime.Now.AddSeconds(1).ToFileTime(); } - private IRepository _repo = null; + private readonly IRepository _repo = null; private FileSystemWatcher _repoWatcher = null; private FileSystemWatcher _wcWatcher = null; private Timer _timer = null; @@ -168,4 +201,4 @@ namespace SourceGit.Models { private long _updateStashes = 0; private long _updateTags = 0; } -} +} \ No newline at end of file diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs index 262a7f3c..4b0cbb93 100644 --- a/src/Native/Linux.cs +++ b/src/Native/Linux.cs @@ -1,29 +1,37 @@ -using Avalonia; -using System.Diagnostics; +using System.Diagnostics; using System.IO; using System.Runtime.Versioning; -namespace SourceGit.Native { +using Avalonia; + +namespace SourceGit.Native +{ [SupportedOSPlatform("linux")] - internal class Linux : OS.IBackend { - public void SetupApp(AppBuilder builder) { - #if USE_FONT_INTER + internal class Linux : OS.IBackend + { + public void SetupApp(AppBuilder builder) + { +#if USE_FONT_INTER builder.WithInterFont(); - #endif +#endif } - public string FindGitExecutable() { + public string FindGitExecutable() + { if (File.Exists("/usr/bin/git")) return "/usr/bin/git"; return string.Empty; } - public string FindVSCode() { + public string FindVSCode() + { if (File.Exists("/usr/share/code/code")) return "/usr/share/code/code"; return string.Empty; } - public void OpenBrowser(string url) { - if (!File.Exists("/usr/bin/xdg-open")) { + public void OpenBrowser(string url) + { + if (!File.Exists("/usr/bin/xdg-open")) + { App.RaiseException("", $"You should install xdg-open first!"); return; } @@ -31,38 +39,54 @@ namespace SourceGit.Native { Process.Start("xdg-open", $"\"{url}\""); } - public void OpenInFileManager(string path, bool select) { - if (!File.Exists("/usr/bin/xdg-open")) { + public void OpenInFileManager(string path, bool select) + { + if (!File.Exists("/usr/bin/xdg-open")) + { App.RaiseException("", $"You should install xdg-open first!"); return; } - if (Directory.Exists(path)) { + if (Directory.Exists(path)) + { Process.Start("xdg-open", $"\"{path}\""); - } else { + } + else + { var dir = Path.GetDirectoryName(path); - if (Directory.Exists(dir)) { + if (Directory.Exists(dir)) + { Process.Start("xdg-open", $"\"{dir}\""); } } } - public void OpenTerminal(string workdir) { + public void OpenTerminal(string workdir) + { var dir = string.IsNullOrEmpty(workdir) ? "~" : workdir; - if (File.Exists("/usr/bin/gnome-terminal")) { + if (File.Exists("/usr/bin/gnome-terminal")) + { Process.Start("/usr/bin/gnome-terminal", $"--working-directory=\"{dir}\""); - } else if (File.Exists("/usr/bin/konsole")) { + } + else if (File.Exists("/usr/bin/konsole")) + { Process.Start("/usr/bin/konsole", $"--workdir \"{dir}\""); - } else if (File.Exists("/usr/bin/xfce4-terminal")) { + } + else if (File.Exists("/usr/bin/xfce4-terminal")) + { Process.Start("/usr/bin/xfce4-terminal", $"--working-directory=\"{dir}\""); - } else { + } + else + { App.RaiseException("", $"Only supports gnome-terminal/konsole/xfce4-terminal!"); return; } } - public void OpenWithDefaultEditor(string file) { - if (!File.Exists("/usr/bin/xdg-open")) { + public void OpenWithDefaultEditor(string file) + { + if (!File.Exists("/usr/bin/xdg-open")) + { App.RaiseException("", $"You should install xdg-open first!"); return; } @@ -70,11 +94,12 @@ namespace SourceGit.Native { var proc = Process.Start("xdg-open", $"\"{file}\""); proc.WaitForExit(); - if (proc.ExitCode != 0) { + if (proc.ExitCode != 0) + { App.RaiseException("", $"Failed to open \"{file}\""); } proc.Close(); } } -} +} \ No newline at end of file diff --git a/src/Native/MacOS.cs b/src/Native/MacOS.cs index 495fdc2b..6b75e50f 100644 --- a/src/Native/MacOS.cs +++ b/src/Native/MacOS.cs @@ -1,15 +1,20 @@ -using Avalonia; -using Avalonia.Media; -using System.Diagnostics; +using System.Diagnostics; using System.IO; using System.Runtime.Versioning; using System.Text; -namespace SourceGit.Native { +using Avalonia; +using Avalonia.Media; + +namespace SourceGit.Native +{ [SupportedOSPlatform("macOS")] - internal class MacOS : OS.IBackend { - public void SetupApp(AppBuilder builder) { - builder.With(new FontManagerOptions() { + internal class MacOS : OS.IBackend + { + public void SetupApp(AppBuilder builder) + { + builder.With(new FontManagerOptions() + { DefaultFamilyName = "PingFang SC", FontFallbacks = [ new FontFallback { FontFamily = new FontFamily("PingFang SC") } @@ -17,32 +22,41 @@ namespace SourceGit.Native { }); } - public string FindGitExecutable() { + public string FindGitExecutable() + { if (File.Exists("/usr/bin/git")) return "/usr/bin/git"; return string.Empty; } - public string FindVSCode() { - if (File.Exists("/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code")) { + public string FindVSCode() + { + if (File.Exists("/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code")) + { return "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code"; } return string.Empty; } - public void OpenBrowser(string url) { + public void OpenBrowser(string url) + { Process.Start("open", url); } - public void OpenInFileManager(string path, bool select) { - if (Directory.Exists(path)) { + public void OpenInFileManager(string path, bool select) + { + if (Directory.Exists(path)) + { Process.Start("open", path); - } else if (File.Exists(path)) { + } + else if (File.Exists(path)) + { Process.Start("open", $"\"{path}\" -R"); } } - public void OpenTerminal(string workdir) { + public void OpenTerminal(string workdir) + { var dir = string.IsNullOrEmpty(workdir) ? "~" : workdir; var builder = new StringBuilder(); builder.AppendLine("on run argv"); @@ -59,8 +73,9 @@ namespace SourceGit.Native { proc.Exited += (o, e) => File.Delete(tmp); } - public void OpenWithDefaultEditor(string file) { + public void OpenWithDefaultEditor(string file) + { Process.Start("open", file); } } -} +} \ No newline at end of file diff --git a/src/Native/OS.cs b/src/Native/OS.cs index 2c9d41b7..78f12972 100644 --- a/src/Native/OS.cs +++ b/src/Native/OS.cs @@ -1,10 +1,14 @@ -using Avalonia; -using System; +using System; using System.Diagnostics; -namespace SourceGit.Native { - public static class OS { - public interface IBackend { +using Avalonia; + +namespace SourceGit.Native +{ + public static class OS + { + public interface IBackend + { void SetupApp(AppBuilder builder); string FindGitExecutable(); @@ -16,62 +20,81 @@ namespace SourceGit.Native { void OpenWithDefaultEditor(string file); } - public static string GitInstallPath { + public static string GitInstallPath + { get; set; } - public static string VSCodeExecutableFile { + public static string VSCodeExecutableFile + { get; set; } - static OS() { - if (OperatingSystem.IsMacOS()) { + static OS() + { + if (OperatingSystem.IsMacOS()) + { _backend = new MacOS(); VSCodeExecutableFile = _backend.FindVSCode(); - } else if (OperatingSystem.IsWindows()) { + } + else if (OperatingSystem.IsWindows()) + { _backend = new Windows(); VSCodeExecutableFile = _backend.FindVSCode(); - } else if (OperatingSystem.IsLinux()) { + } + else if (OperatingSystem.IsLinux()) + { _backend = new Linux(); VSCodeExecutableFile = _backend.FindVSCode(); - } else { + } + else + { throw new Exception("Platform unsupported!!!"); } } - public static void SetupApp(AppBuilder builder) { + public static void SetupApp(AppBuilder builder) + { _backend?.SetupApp(builder); } - public static string FindGitExecutable() { + public static string FindGitExecutable() + { return _backend?.FindGitExecutable(); } - public static void OpenInFileManager(string path, bool select = false) { + public static void OpenInFileManager(string path, bool select = false) + { _backend?.OpenInFileManager(path, select); } - public static void OpenBrowser(string url) { + public static void OpenBrowser(string url) + { _backend?.OpenBrowser(url); } - public static void OpenTerminal(string workdir) { + public static void OpenTerminal(string workdir) + { _backend?.OpenTerminal(workdir); } - public static void OpenWithDefaultEditor(string file) { + public static void OpenWithDefaultEditor(string file) + { _backend?.OpenWithDefaultEditor(file); } - public static void OpenInVSCode(string repo) { - if (string.IsNullOrEmpty(VSCodeExecutableFile)) { + public static void OpenInVSCode(string repo) + { + if (string.IsNullOrEmpty(VSCodeExecutableFile)) + { App.RaiseException(repo, "Visual Studio Code can NOT be found in your system!!!"); return; } - Process.Start(new ProcessStartInfo() { + Process.Start(new ProcessStartInfo() + { WorkingDirectory = repo, FileName = VSCodeExecutableFile, Arguments = $"\"{repo}\"", @@ -79,6 +102,6 @@ namespace SourceGit.Native { }); } - private static IBackend _backend = null; + private static readonly IBackend _backend = null; } -} +} \ No newline at end of file diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index 7bce6ede..06c0b1dd 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -1,20 +1,25 @@ -using Avalonia; -using Avalonia.Media; -using System; +using System; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; -namespace SourceGit.Native { +using Avalonia; +using Avalonia.Media; + +namespace SourceGit.Native +{ [SupportedOSPlatform("windows")] - internal class Windows : OS.IBackend { + internal class Windows : OS.IBackend + { [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, SetLastError = false)] private static extern bool PathFindOnPath([In, Out] StringBuilder pszFile, [In] string[] ppszOtherDirs); - public void SetupApp(AppBuilder builder) { - builder.With(new FontManagerOptions() { + public void SetupApp(AppBuilder builder) + { + builder.With(new FontManagerOptions() + { DefaultFamilyName = "Microsoft YaHei UI", FontFallbacks = [ new FontFallback { FontFamily = new FontFamily("Microsoft YaHei UI") } @@ -22,18 +27,21 @@ namespace SourceGit.Native { }); } - public string FindGitExecutable() { + public string FindGitExecutable() + { var reg = Microsoft.Win32.RegistryKey.OpenBaseKey( Microsoft.Win32.RegistryHive.LocalMachine, Microsoft.Win32.RegistryView.Registry64); var git = reg.OpenSubKey("SOFTWARE\\GitForWindows"); - if (git != null) { + if (git != null) + { return Path.Combine(git.GetValue("InstallPath") as string, "bin", "git.exe"); } var builder = new StringBuilder("git.exe", 259); - if (!PathFindOnPath(builder, null)) { + if (!PathFindOnPath(builder, null)) + { return null; } @@ -43,43 +51,51 @@ namespace SourceGit.Native { return exePath; } - public string FindVSCode() { + public string FindVSCode() + { var root = Microsoft.Win32.RegistryKey.OpenBaseKey( Microsoft.Win32.RegistryHive.LocalMachine, Environment.Is64BitOperatingSystem ? Microsoft.Win32.RegistryView.Registry64 : Microsoft.Win32.RegistryView.Registry32); var vscode = root.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C26E74D1-022E-4238-8B9D-1E7564A36CC9}_is1"); - if (vscode != null) { + if (vscode != null) + { return vscode.GetValue("DisplayIcon") as string; } vscode = root.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{1287CAD5-7C8D-410D-88B9-0D1EE4A83FF2}_is1"); - if (vscode != null) { + if (vscode != null) + { return vscode.GetValue("DisplayIcon") as string; } vscode = root.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F8A2A208-72B3-4D61-95FC-8A65D340689B}_is1"); - if (vscode != null) { + if (vscode != null) + { return vscode.GetValue("DisplayIcon") as string; } vscode = root.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{EA457B21-F73E-494C-ACAB-524FDE069978}_is1"); - if (vscode != null) { + if (vscode != null) + { return vscode.GetValue("DisplayIcon") as string; } return string.Empty; } - public void OpenBrowser(string url) { + public void OpenBrowser(string url) + { var info = new ProcessStartInfo("cmd", $"/c start {url}"); info.CreateNoWindow = true; Process.Start(info); } - public void OpenTerminal(string workdir) { + public void OpenTerminal(string workdir) + { var bash = Path.Combine(Path.GetDirectoryName(OS.GitInstallPath), "bash.exe"); - if (!File.Exists(bash)) { + if (!File.Exists(bash)) + { App.RaiseException(string.IsNullOrEmpty(workdir) ? "" : workdir, $"Can NOT found bash.exe under '{Path.GetDirectoryName(OS.GitInstallPath)}'"); return; } @@ -91,26 +107,34 @@ namespace SourceGit.Native { Process.Start(startInfo); } - public void OpenInFileManager(string path, bool select) { + public void OpenInFileManager(string path, bool select) + { var fullpath = string.Empty; - if (File.Exists(path)) { + if (File.Exists(path)) + { fullpath = new FileInfo(path).FullName; - } else { + } + else + { fullpath = new DirectoryInfo(path).FullName; } - if (select) { + if (select) + { Process.Start("explorer", $"/select,\"{fullpath}\""); - } else { + } + else + { Process.Start("explorer", fullpath); } } - public void OpenWithDefaultEditor(string file) { + public void OpenWithDefaultEditor(string file) + { var info = new FileInfo(file); var start = new ProcessStartInfo("cmd", $"/c start {info.FullName}"); start.CreateNoWindow = true; Process.Start(start); } } -} +} \ No newline at end of file diff --git a/src/ViewModels/AddRemote.cs b/src/ViewModels/AddRemote.cs index 8d80046d..63ada2e6 100644 --- a/src/ViewModels/AddRemote.cs +++ b/src/ViewModels/AddRemote.cs @@ -1,42 +1,52 @@ using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class AddRemote : Popup { +namespace SourceGit.ViewModels +{ + public class AddRemote : Popup + { [Required(ErrorMessage = "Remote name is required!!!")] [RegularExpression(@"^[\w\-\.]+$", ErrorMessage = "Bad remote name format!!!")] [CustomValidation(typeof(AddRemote), nameof(ValidateRemoteName))] - public string Name { + public string Name + { get => _name; set => SetProperty(ref _name, value, true); } [Required(ErrorMessage = "Remote URL is required!!!")] [CustomValidation(typeof(AddRemote), nameof(ValidateRemoteURL))] - public string Url { + public string Url + { get => _url; - set { + set + { if (SetProperty(ref _url, value, true)) UseSSH = Models.Remote.IsSSH(value); } } - public bool UseSSH { + public bool UseSSH + { get => _useSSH; set => SetProperty(ref _useSSH, value); } - public string SSHKey { + public string SSHKey + { get; set; } - public AddRemote(Repository repo) { + public AddRemote(Repository repo) + { _repo = repo; View = new Views.AddRemote() { DataContext = this }; } - public static ValidationResult ValidateRemoteName(string name, ValidationContext ctx) { - if (ctx.ObjectInstance is AddRemote add) { + public static ValidationResult ValidateRemoteName(string name, ValidationContext ctx) + { + if (ctx.ObjectInstance is AddRemote add) + { var exists = add._repo.Remotes.Find(x => x.Name == name); if (exists != null) return new ValidationResult("A remote with given name already exists!!!"); } @@ -44,8 +54,10 @@ namespace SourceGit.ViewModels { return ValidationResult.Success; } - public static ValidationResult ValidateRemoteURL(string url, ValidationContext ctx) { - if (ctx.ObjectInstance is AddRemote add) { + public static ValidationResult ValidateRemoteURL(string url, ValidationContext ctx) + { + if (ctx.ObjectInstance is AddRemote add) + { if (!Models.Remote.IsValidURL(url)) return new ValidationResult("Bad remote URL format!!!"); var exists = add._repo.Remotes.Find(x => x.URL == url); @@ -55,22 +67,27 @@ namespace SourceGit.ViewModels { return ValidationResult.Success; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = "Adding remote ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Remote(_repo.FullPath).Add(_name, _url); - if (succ) { + if (succ) + { SetProgressDescription("Fetching from added remote ..."); new Commands.Fetch(_repo.FullPath, _name, true, SetProgressDescription).Exec(); - if (_useSSH) { + if (_useSSH) + { SetProgressDescription("Post processing ..."); new Commands.Config(_repo.FullPath).Set($"remote.{_name}.sshkey", SSHKey); } } - CallUIThread(() => { + CallUIThread(() => + { _repo.MarkBranchesDirtyManually(); _repo.SetWatcherEnabled(true); }); @@ -78,9 +95,9 @@ namespace SourceGit.ViewModels { }); } - private Repository _repo = null; + private readonly Repository _repo = null; private string _name = string.Empty; private string _url = string.Empty; private bool _useSSH = false; } -} +} \ No newline at end of file diff --git a/src/ViewModels/AddSubmodule.cs b/src/ViewModels/AddSubmodule.cs index 2bfdde3c..c12f09ca 100644 --- a/src/ViewModels/AddSubmodule.cs +++ b/src/ViewModels/AddSubmodule.cs @@ -2,62 +2,74 @@ using System.IO; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class AddSubmodule : Popup { +namespace SourceGit.ViewModels +{ + public class AddSubmodule : Popup + { [Required(ErrorMessage = "Url is required!!!")] [CustomValidation(typeof(AddSubmodule), nameof(ValidateURL))] - public string Url { + public string Url + { get => _url; set => SetProperty(ref _url, value, true); } [Required(ErrorMessage = "Reletive path is required!!!")] [CustomValidation(typeof(AddSubmodule), nameof(ValidateRelativePath))] - public string RelativePath { + public string RelativePath + { get => _relativePath; set => SetProperty(ref _relativePath, value, true); } - public bool Recursive { + public bool Recursive + { get; set; } - public AddSubmodule(Repository repo) { + public AddSubmodule(Repository repo) + { _repo = repo; View = new Views.AddSubmodule() { DataContext = this }; } - public static ValidationResult ValidateURL(string url, ValidationContext ctx) { + public static ValidationResult ValidateURL(string url, ValidationContext ctx) + { if (!Models.Remote.IsValidURL(url)) return new ValidationResult("Invalid repository URL format"); return ValidationResult.Success; } - public static ValidationResult ValidateRelativePath(string path, ValidationContext ctx) { - if (Path.Exists(path)) { + public static ValidationResult ValidateRelativePath(string path, ValidationContext ctx) + { + if (Path.Exists(path)) + { return new ValidationResult("Give path is exists already!"); } - if (Path.IsPathRooted(path)) { + if (Path.IsPathRooted(path)) + { return new ValidationResult("Path must be relative to this repository!"); } return ValidationResult.Success; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = "Adding submodule..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Submodule(_repo.FullPath).Add(_url, _relativePath, Recursive, SetProgressDescription); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } - private Repository _repo = null; + private readonly Repository _repo = null; private string _url = string.Empty; private string _relativePath = string.Empty; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Apply.cs b/src/ViewModels/Apply.cs index 937ebe70..2c57ee5e 100644 --- a/src/ViewModels/Apply.cs +++ b/src/ViewModels/Apply.cs @@ -3,31 +3,38 @@ using System.ComponentModel.DataAnnotations; using System.IO; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Apply : Popup { +namespace SourceGit.ViewModels +{ + public class Apply : Popup + { [Required(ErrorMessage = "Patch file is required!!!")] [CustomValidation(typeof(Apply), nameof(ValidatePatchFile))] - public string PatchFile { + public string PatchFile + { get => _patchFile; set => SetProperty(ref _patchFile, value, true); } - public bool IgnoreWhiteSpace { + public bool IgnoreWhiteSpace + { get => _ignoreWhiteSpace; set => SetProperty(ref _ignoreWhiteSpace, value); } - public List WhiteSpaceModes { + public List WhiteSpaceModes + { get; private set; } - public Models.ApplyWhiteSpaceMode SelectedWhiteSpaceMode { + public Models.ApplyWhiteSpaceMode SelectedWhiteSpaceMode + { get; set; } - public Apply(Repository repo) { + public Apply(Repository repo) + { _repo = repo; WhiteSpaceModes = new List { @@ -41,27 +48,31 @@ namespace SourceGit.ViewModels { View = new Views.Apply() { DataContext = this }; } - public static ValidationResult ValidatePatchFile(string file, ValidationContext _) { - if (File.Exists(file)) { + public static ValidationResult ValidatePatchFile(string file, ValidationContext _) + { + if (File.Exists(file)) + { return ValidationResult.Success; } return new ValidationResult($"File '{file}' can NOT be found!!!"); } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = "Apply patch..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Apply(_repo.FullPath, _patchFile, _ignoreWhiteSpace, SelectedWhiteSpaceMode.Arg, null).Exec(); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } - private Repository _repo = null; + private readonly Repository _repo = null; private string _patchFile = string.Empty; private bool _ignoreWhiteSpace = true; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Archive.cs b/src/ViewModels/Archive.cs index b9c172f6..024548e2 100644 --- a/src/ViewModels/Archive.cs +++ b/src/ViewModels/Archive.cs @@ -2,21 +2,26 @@ using System.IO; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Archive : Popup { +namespace SourceGit.ViewModels +{ + public class Archive : Popup + { [Required(ErrorMessage = "Output file name is required")] - public string SaveFile { + public string SaveFile + { get => _saveFile; set => SetProperty(ref _saveFile, value, true); } - public object BasedOn { + public object BasedOn + { get; private set; } - public Archive(Repository repo, Models.Branch branch) { + public Archive(Repository repo, Models.Branch branch) + { _repo = repo; _revision = branch.Head; _saveFile = $"archive-{Path.GetFileNameWithoutExtension(branch.Name)}.zip"; @@ -24,15 +29,17 @@ namespace SourceGit.ViewModels { View = new Views.Archive() { DataContext = this }; } - public Archive(Repository repo, Models.Commit commit) { + public Archive(Repository repo, Models.Commit commit) + { _repo = repo; _revision = commit.SHA; - _saveFile = $"archive-{commit.SHA.Substring(0,10)}.zip"; + _saveFile = $"archive-{commit.SHA.Substring(0, 10)}.zip"; BasedOn = commit; View = new Views.Archive() { DataContext = this }; } - public Archive(Repository repo, Models.Tag tag) { + public Archive(Repository repo, Models.Tag tag) + { _repo = repo; _revision = tag.SHA; _saveFile = $"archive-{tag.Name}.zip"; @@ -40,13 +47,16 @@ namespace SourceGit.ViewModels { View = new Views.Archive() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = "Archiving ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Archive(_repo.FullPath, _revision, _saveFile, SetProgressDescription).Exec(); - CallUIThread(() => { + CallUIThread(() => + { _repo.SetWatcherEnabled(true); if (succ) App.SendNotification(_repo.FullPath, $"Save archive to : {_saveFile}"); }); @@ -55,8 +65,8 @@ namespace SourceGit.ViewModels { }); } - private Repository _repo = null; + private readonly Repository _repo = null; private string _saveFile = string.Empty; - private string _revision = string.Empty; + private readonly string _revision = string.Empty; } -} +} \ No newline at end of file diff --git a/src/ViewModels/AssumeUnchangedManager.cs b/src/ViewModels/AssumeUnchangedManager.cs index f633de75..0566dabc 100644 --- a/src/ViewModels/AssumeUnchangedManager.cs +++ b/src/ViewModels/AssumeUnchangedManager.cs @@ -1,30 +1,38 @@ -using Avalonia.Collections; -using Avalonia.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class AssumeUnchangedManager { +using Avalonia.Collections; +using Avalonia.Threading; + +namespace SourceGit.ViewModels +{ + public class AssumeUnchangedManager + { public AvaloniaList Files { get; private set; } - public AssumeUnchangedManager(string repo) { + public AssumeUnchangedManager(string repo) + { _repo = repo; Files = new AvaloniaList(); - Task.Run(() => { + Task.Run(() => + { var collect = new Commands.AssumeUnchanged(_repo).View(); - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { Files.AddRange(collect); }); }); } - public void Remove(object param) { - if (param is string file) { + public void Remove(object param) + { + if (param is string file) + { new Commands.AssumeUnchanged(_repo).Remove(file); Files.Remove(file); } } - private string _repo; + private readonly string _repo; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Blame.cs b/src/ViewModels/Blame.cs index a5a2f961..b20bdfc9 100644 --- a/src/ViewModels/Blame.cs +++ b/src/ViewModels/Blame.cs @@ -1,48 +1,60 @@ -using Avalonia.Threading; -using CommunityToolkit.Mvvm.ComponentModel; -using System.Threading.Tasks; +using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Blame : ObservableObject { - public string Title { +using Avalonia.Threading; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class Blame : ObservableObject + { + public string Title + { get; private set; } - public string SelectedSHA { + public string SelectedSHA + { get => _selectedSHA; private set => SetProperty(ref _selectedSHA, value); } - public bool IsBinary { + public bool IsBinary + { get => _data != null && _data.IsBinary; } - public Models.BlameData Data { + public Models.BlameData Data + { get => _data; private set => SetProperty(ref _data, value); } - public Blame(string repo, string file, string revision) { + public Blame(string repo, string file, string revision) + { _repo = repo; Title = $"{file} @ {revision.Substring(0, 10)}"; - Task.Run(() => { + Task.Run(() => + { var result = new Commands.Blame(repo, file, revision).Result(); - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { Data = result; OnPropertyChanged(nameof(IsBinary)); }); }); } - public void NavigateToCommit(string commitSHA) { + public void NavigateToCommit(string commitSHA) + { var repo = Preference.FindRepository(_repo); if (repo != null) repo.NavigateToCommit(commitSHA); } - private string _repo = string.Empty; + private readonly string _repo = string.Empty; private string _selectedSHA = string.Empty; private Models.BlameData _data = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Checkout.cs b/src/ViewModels/Checkout.cs index 9570b265..ac2d9c1c 100644 --- a/src/ViewModels/Checkout.cs +++ b/src/ViewModels/Checkout.cs @@ -1,29 +1,35 @@ using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Checkout : Popup { - public string Branch { +namespace SourceGit.ViewModels +{ + public class Checkout : Popup + { + public string Branch + { get; private set; } - public Checkout(Repository repo, string branch) { + public Checkout(Repository repo, string branch) + { _repo = repo; Branch = branch; View = new Views.Checkout() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = $"Checkout '{Branch}' ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Checkout(_repo.FullPath).Branch(Branch, SetProgressDescription); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } - private Repository _repo; + private readonly Repository _repo; } -} +} \ No newline at end of file diff --git a/src/ViewModels/CherryPick.cs b/src/ViewModels/CherryPick.cs index 2844effb..6b945606 100644 --- a/src/ViewModels/CherryPick.cs +++ b/src/ViewModels/CherryPick.cs @@ -1,35 +1,42 @@ using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class CherryPick : Popup { - public Models.Commit Target { +namespace SourceGit.ViewModels +{ + public class CherryPick : Popup + { + public Models.Commit Target + { get; private set; } - public bool AutoCommit { + public bool AutoCommit + { get; set; } - public CherryPick(Repository repo, Models.Commit target) { + public CherryPick(Repository repo, Models.Commit target) + { _repo = repo; Target = target; AutoCommit = true; View = new Views.CherryPick() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = $"Cherry-Pick commit '{Target.SHA}' ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.CherryPick(_repo.FullPath, Target.SHA, !AutoCommit).Exec(); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } - private Repository _repo = null; + private readonly Repository _repo = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Cleanup.cs b/src/ViewModels/Cleanup.cs index a90b08f1..81c73373 100644 --- a/src/ViewModels/Cleanup.cs +++ b/src/ViewModels/Cleanup.cs @@ -1,21 +1,27 @@ using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Cleanup : Popup { - public Cleanup(Repository repo) { +namespace SourceGit.ViewModels +{ + public class Cleanup : Popup + { + public Cleanup(Repository repo) + { _repo = repo; View = new Views.Cleanup() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = "Cleanup (GC & prune) ..."; - return Task.Run(() => { + return Task.Run(() => + { new Commands.GC(_repo.FullPath, SetProgressDescription).Exec(); var lfs = new Commands.LFS(_repo.FullPath); - if (lfs.IsEnabled()) { + if (lfs.IsEnabled()) + { SetProgressDescription("Run LFS prune ..."); lfs.Prune(SetProgressDescription); } @@ -25,6 +31,6 @@ namespace SourceGit.ViewModels { }); } - private Repository _repo = null; + private readonly Repository _repo = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/ClearStashes.cs b/src/ViewModels/ClearStashes.cs index 40a36084..eab77b3f 100644 --- a/src/ViewModels/ClearStashes.cs +++ b/src/ViewModels/ClearStashes.cs @@ -1,23 +1,28 @@ using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class ClearStashes : Popup { - public ClearStashes(Repository repo) { +namespace SourceGit.ViewModels +{ + public class ClearStashes : Popup + { + public ClearStashes(Repository repo) + { _repo = repo; View = new Views.ClearStashes() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = "Clear all stashes..."; - return Task.Run(() => { + return Task.Run(() => + { new Commands.Stash(_repo.FullPath).Clear(); CallUIThread(() => _repo.SetWatcherEnabled(true)); return true; }); } - private Repository _repo = null; + private readonly Repository _repo = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Clone.cs b/src/ViewModels/Clone.cs index 7c06f7fe..bb4d7017 100644 --- a/src/ViewModels/Clone.cs +++ b/src/ViewModels/Clone.cs @@ -3,92 +3,114 @@ using System.ComponentModel.DataAnnotations; using System.IO; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Clone : Popup { +namespace SourceGit.ViewModels +{ + public class Clone : Popup + { [Required(ErrorMessage = "Remote URL is required")] [CustomValidation(typeof(Clone), nameof(ValidateRemote))] - public string Remote { + public string Remote + { get => _remote; - set { + set + { if (SetProperty(ref _remote, value, true)) UseSSH = Models.Remote.IsSSH(value); } } - public bool UseSSH { + public bool UseSSH + { get => _useSSH; set => SetProperty(ref _useSSH, value); } - public string SSHKey { + public string SSHKey + { get => _sshKey; set => SetProperty(ref _sshKey, value); } [Required(ErrorMessage = "Parent folder is required")] [CustomValidation(typeof(Clone), nameof(ValidateParentFolder))] - public string ParentFolder { + public string ParentFolder + { get => _parentFolder; set => SetProperty(ref _parentFolder, value, true); } - public string Local { + public string Local + { get => _local; set => SetProperty(ref _local, value); } - public string ExtraArgs { + public string ExtraArgs + { get => _extraArgs; set => SetProperty(ref _extraArgs, value); } - public Clone(Launcher launcher, LauncherPage page) { + public Clone(Launcher launcher, LauncherPage page) + { _launcher = launcher; _page = page; View = new Views.Clone() { DataContext = this }; } - public static ValidationResult ValidateRemote(string remote, ValidationContext _) { + public static ValidationResult ValidateRemote(string remote, ValidationContext _) + { if (!Models.Remote.IsValidURL(remote)) return new ValidationResult("Invalid remote repository URL format"); return ValidationResult.Success; } - public static ValidationResult ValidateParentFolder(string folder, ValidationContext _) { + public static ValidationResult ValidateParentFolder(string folder, ValidationContext _) + { if (!Directory.Exists(folder)) return new ValidationResult("Given path can NOT be found"); return ValidationResult.Success; } - public override Task Sure() { + public override Task Sure() + { ProgressDescription = "Clone ..."; - return Task.Run(() => { + return Task.Run(() => + { var cmd = new Commands.Clone(HostPageId, _parentFolder, _remote, _local, _useSSH ? _sshKey : "", _extraArgs, SetProgressDescription); if (!cmd.Exec()) return false; var path = _parentFolder; - if (!string.IsNullOrEmpty(_local)) { + if (!string.IsNullOrEmpty(_local)) + { path = Path.GetFullPath(Path.Combine(path, _local)); - } else { + } + else + { var name = Path.GetFileName(_remote); if (name.EndsWith(".git")) name = name.Substring(0, name.Length - 4); path = Path.GetFullPath(Path.Combine(path, name)); } - if (!Directory.Exists(path)) { - CallUIThread(() => { + if (!Directory.Exists(path)) + { + CallUIThread(() => + { App.RaiseException(HostPageId, $"Folder '{path}' can NOT be found"); }); return false; } - if (_useSSH && !string.IsNullOrEmpty(_sshKey)) { + if (_useSSH && !string.IsNullOrEmpty(_sshKey)) + { var config = new Commands.Config(path); config.Set("remote.origin.sshkey", _sshKey); } - CallUIThread(() => { + CallUIThread(() => + { var repo = Preference.AddRepository(path, Path.Combine(path, ".git")); - var node = new RepositoryNode() { + var node = new RepositoryNode() + { Id = repo.FullPath, Name = Path.GetFileName(repo.FullPath), Bookmark = 0, @@ -103,8 +125,8 @@ namespace SourceGit.ViewModels { }); } - private Launcher _launcher = null; - private LauncherPage _page = null; + private readonly Launcher _launcher = null; + private readonly LauncherPage _page = null; private string _remote = string.Empty; private bool _useSSH = false; private string _sshKey = string.Empty; @@ -112,4 +134,4 @@ namespace SourceGit.ViewModels { private string _local = string.Empty; private string _extraArgs = string.Empty; } -} +} \ No newline at end of file diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs index 1e189191..38c63574 100644 --- a/src/ViewModels/CommitDetail.cs +++ b/src/ViewModels/CommitDetail.cs @@ -1,54 +1,71 @@ -using Avalonia.Controls; -using Avalonia.Platform.Storage; -using Avalonia.Threading; -using CommunityToolkit.Mvvm.ComponentModel; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class CommitDetail : ObservableObject { - public DiffContext DiffContext { +using Avalonia.Controls; +using Avalonia.Platform.Storage; +using Avalonia.Threading; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class CommitDetail : ObservableObject + { + public DiffContext DiffContext + { get => _diffContext; private set => SetProperty(ref _diffContext, value); } - public int ActivePageIndex { + public int ActivePageIndex + { get => _activePageIndex; set => SetProperty(ref _activePageIndex, value); } - public Models.Commit Commit { + public Models.Commit Commit + { get => _commit; - set { + set + { if (SetProperty(ref _commit, value)) Refresh(); } } - public List Changes { + public List Changes + { get => _changes; set => SetProperty(ref _changes, value); } - public List VisibleChanges { + public List VisibleChanges + { get => _visibleChanges; set => SetProperty(ref _visibleChanges, value); } - public List ChangeTree { + public List ChangeTree + { get => _changeTree; set => SetProperty(ref _changeTree, value); } - public Models.Change SelectedChange { + public Models.Change SelectedChange + { get => _selectedChange; - set { - if (SetProperty(ref _selectedChange, value)) { - if (value == null) { + set + { + if (SetProperty(ref _selectedChange, value)) + { + if (value == null) + { SelectedChangeNode = null; DiffContext = null; - } else { + } + else + { SelectedChangeNode = FileTreeNode.SelectByPath(_changeTree, value.Path); DiffContext = new DiffContext(_repo, new Models.DiffOption(_commit, value)); } @@ -56,63 +73,84 @@ namespace SourceGit.ViewModels { } } - public FileTreeNode SelectedChangeNode { + public FileTreeNode SelectedChangeNode + { get => _selectedChangeNode; - set { - if (SetProperty(ref _selectedChangeNode, value)) { - if (value == null) { + set + { + if (SetProperty(ref _selectedChangeNode, value)) + { + if (value == null) + { SelectedChange = null; - } else { + } + else + { SelectedChange = value.Backend as Models.Change; } } } } - public string SearchChangeFilter { + public string SearchChangeFilter + { get => _searchChangeFilter; - set { - if (SetProperty(ref _searchChangeFilter, value)) { + set + { + if (SetProperty(ref _searchChangeFilter, value)) + { RefreshVisibleChanges(); } } } - public List RevisionFilesTree { + public List RevisionFilesTree + { get => _revisionFilesTree; set => SetProperty(ref _revisionFilesTree, value); } - public FileTreeNode SelectedRevisionFileNode { + public FileTreeNode SelectedRevisionFileNode + { get => _selectedRevisionFileNode; - set { - if (SetProperty(ref _selectedRevisionFileNode, value) && value != null && !value.IsFolder) { + set + { + if (SetProperty(ref _selectedRevisionFileNode, value) && value != null && !value.IsFolder) + { RefreshViewRevisionFile(value.Backend as Models.Object); - } else { + } + else + { ViewRevisionFileContent = null; } } } - public string SearchFileFilter { + public string SearchFileFilter + { get => _searchFileFilter; - set { - if (SetProperty(ref _searchFileFilter, value)) { + set + { + if (SetProperty(ref _searchFileFilter, value)) + { RefreshVisibleFiles(); } } } - public object ViewRevisionFileContent { + public object ViewRevisionFileContent + { get => _viewRevisionFileContent; set => SetProperty(ref _viewRevisionFileContent, value); } - public CommitDetail(string repo) { + public CommitDetail(string repo) + { _repo = repo; } - public void Cleanup() { + public void Cleanup() + { _repo = null; _commit = null; if (_changes != null) _changes.Clear(); @@ -130,27 +168,33 @@ namespace SourceGit.ViewModels { _cancelToken = null; } - public void NavigateTo(string commitSHA) { + public void NavigateTo(string commitSHA) + { var repo = Preference.FindRepository(_repo); if (repo != null) repo.NavigateToCommit(commitSHA); } - public void ClearSearchChangeFilter() { + public void ClearSearchChangeFilter() + { SearchChangeFilter = string.Empty; } - public void ClearSearchFileFilter() { + public void ClearSearchFileFilter() + { SearchFileFilter = string.Empty; } - public ContextMenu CreateChangeContextMenu(Models.Change change) { + public ContextMenu CreateChangeContextMenu(Models.Change change) + { var menu = new ContextMenu(); - if (change.Index != Models.ChangeState.Deleted) { + if (change.Index != Models.ChangeState.Deleted) + { var history = new MenuItem(); history.Header = App.Text("FileHistory"); history.Icon = App.CreateMenuIcon("Icons.Histories"); - history.Click += (_, ev) => { + history.Click += (_, ev) => + { var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path) }; window.Show(); ev.Handled = true; @@ -159,7 +203,8 @@ namespace SourceGit.ViewModels { var blame = new MenuItem(); blame.Header = App.Text("Blame"); blame.Icon = App.CreateMenuIcon("Icons.Blame"); - blame.Click += (o, ev) => { + blame.Click += (o, ev) => + { var window = new Views.Blame() { DataContext = new Blame(_repo, change.Path, _commit.SHA) }; window.Show(); ev.Handled = true; @@ -170,7 +215,8 @@ namespace SourceGit.ViewModels { explore.Header = App.Text("RevealFile"); explore.Icon = App.CreateMenuIcon("Icons.Folder.Open"); explore.IsEnabled = File.Exists(full); - explore.Click += (_, ev) => { + explore.Click += (_, ev) => + { Native.OS.OpenInFileManager(full, true); ev.Handled = true; }; @@ -183,7 +229,8 @@ namespace SourceGit.ViewModels { var copyPath = new MenuItem(); copyPath.Header = App.Text("CopyPath"); copyPath.Icon = App.CreateMenuIcon("Icons.Copy"); - copyPath.Click += (_, ev) => { + copyPath.Click += (_, ev) => + { App.CopyText(change.Path); ev.Handled = true; }; @@ -192,11 +239,13 @@ namespace SourceGit.ViewModels { return menu; } - public ContextMenu CreateRevisionFileContextMenu(Models.Object file) { + public ContextMenu CreateRevisionFileContextMenu(Models.Object file) + { var history = new MenuItem(); history.Header = App.Text("FileHistory"); history.Icon = App.CreateMenuIcon("Icons.Histories"); - history.Click += (_, ev) => { + history.Click += (_, ev) => + { var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, file.Path) }; window.Show(); ev.Handled = true; @@ -205,7 +254,8 @@ namespace SourceGit.ViewModels { var blame = new MenuItem(); blame.Header = App.Text("Blame"); blame.Icon = App.CreateMenuIcon("Icons.Blame"); - blame.Click += (o, ev) => { + blame.Click += (o, ev) => + { var window = new Views.Blame() { DataContext = new Blame(_repo, file.Path, _commit.SHA) }; window.Show(); ev.Handled = true; @@ -215,7 +265,8 @@ namespace SourceGit.ViewModels { var explore = new MenuItem(); explore.Header = App.Text("RevealFile"); explore.Icon = App.CreateMenuIcon("Icons.Folder.Open"); - explore.Click += (_, ev) => { + explore.Click += (_, ev) => + { Native.OS.OpenInFileManager(full, file.Type == Models.ObjectType.Blob); ev.Handled = true; }; @@ -224,13 +275,15 @@ namespace SourceGit.ViewModels { saveAs.Header = App.Text("SaveAs"); saveAs.Icon = App.CreateMenuIcon("Icons.Save"); saveAs.IsEnabled = file.Type == Models.ObjectType.Blob; - saveAs.Click += async (_, ev) => { + saveAs.Click += async (_, ev) => + { var topLevel = App.GetTopLevel(); if (topLevel == null) return; var options = new FolderPickerOpenOptions() { AllowMultiple = false }; var selected = await topLevel.StorageProvider.OpenFolderPickerAsync(options); - if (selected.Count == 1) { + if (selected.Count == 1) + { var saveTo = Path.Combine(selected[0].Path.LocalPath, Path.GetFileName(file.Path)); Commands.SaveRevisionFile.Run(_repo, _commit.SHA, file.Path, saveTo); } @@ -241,7 +294,8 @@ namespace SourceGit.ViewModels { var copyPath = new MenuItem(); copyPath.Header = App.Text("CopyPath"); copyPath.Icon = App.CreateMenuIcon("Icons.Copy"); - copyPath.Click += (_, ev) => { + copyPath.Click += (_, ev) => + { App.CopyText(file.Path); ev.Handled = true; }; @@ -255,7 +309,8 @@ namespace SourceGit.ViewModels { return menu; } - private void Refresh() { + private void Refresh() + { _changes = null; VisibleChanges = null; SelectedChange = null; @@ -268,59 +323,75 @@ namespace SourceGit.ViewModels { var cmdChanges = new Commands.QueryCommitChanges(_repo, _commit.SHA) { Cancel = _cancelToken }; var cmdRevisionFiles = new Commands.QueryRevisionObjects(_repo, _commit.SHA) { Cancel = _cancelToken }; - Task.Run(() => { + Task.Run(() => + { var changes = cmdChanges.Result(); if (cmdChanges.Cancel.Requested) return; var visible = changes; - if (!string.IsNullOrWhiteSpace(_searchChangeFilter)) { + if (!string.IsNullOrWhiteSpace(_searchChangeFilter)) + { visible = new List(); - foreach (var c in changes) { - if (c.Path.Contains(_searchChangeFilter, StringComparison.OrdinalIgnoreCase)) { + foreach (var c in changes) + { + if (c.Path.Contains(_searchChangeFilter, StringComparison.OrdinalIgnoreCase)) + { visible.Add(c); } } } var tree = FileTreeNode.Build(visible); - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { Changes = changes; VisibleChanges = visible; ChangeTree = tree; }); }); - Task.Run(() => { + Task.Run(() => + { var files = cmdRevisionFiles.Result(); if (cmdRevisionFiles.Cancel.Requested) return; var visible = files; - if (!string.IsNullOrWhiteSpace(_searchFileFilter)) { + if (!string.IsNullOrWhiteSpace(_searchFileFilter)) + { visible = new List(); - foreach (var f in files) { - if (f.Path.Contains(_searchFileFilter, StringComparison.OrdinalIgnoreCase)) { + foreach (var f in files) + { + if (f.Path.Contains(_searchFileFilter, StringComparison.OrdinalIgnoreCase)) + { visible.Add(f); } } } var tree = FileTreeNode.Build(visible); - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { _revisionFiles = files; RevisionFilesTree = tree; }); }); } - private void RefreshVisibleChanges() { + private void RefreshVisibleChanges() + { if (_changes == null) return; - if (string.IsNullOrEmpty(_searchChangeFilter)) { + if (string.IsNullOrEmpty(_searchChangeFilter)) + { VisibleChanges = _changes; - } else { + } + else + { var visible = new List(); - foreach (var c in _changes) { - if (c.Path.Contains(_searchChangeFilter, StringComparison.OrdinalIgnoreCase)) { + foreach (var c in _changes) + { + if (c.Path.Contains(_searchChangeFilter, StringComparison.OrdinalIgnoreCase)) + { visible.Add(c); } } @@ -331,14 +402,18 @@ namespace SourceGit.ViewModels { ChangeTree = FileTreeNode.Build(_visibleChanges); } - private void RefreshVisibleFiles() { + private void RefreshVisibleFiles() + { if (_revisionFiles == null) return; var visible = _revisionFiles; - if (!string.IsNullOrWhiteSpace(_searchFileFilter)) { + if (!string.IsNullOrWhiteSpace(_searchFileFilter)) + { visible = new List(); - foreach (var f in _revisionFiles) { - if (f.Path.Contains(_searchFileFilter, StringComparison.OrdinalIgnoreCase)) { + foreach (var f in _revisionFiles) + { + if (f.Path.Contains(_searchFileFilter, StringComparison.OrdinalIgnoreCase)) + { visible.Add(f); } } @@ -347,52 +422,66 @@ namespace SourceGit.ViewModels { RevisionFilesTree = FileTreeNode.Build(visible); } - private void RefreshViewRevisionFile(Models.Object file) { - switch (file.Type) { - case Models.ObjectType.Blob: - Task.Run(() => { - var isBinary = new Commands.IsBinary(_repo, _commit.SHA, file.Path).Result(); - if (isBinary) { - var size = new Commands.QueryFileSize(_repo, file.Path, _commit.SHA).Result(); - Dispatcher.UIThread.Invoke(() => { - ViewRevisionFileContent = new Models.RevisionBinaryFile() { Size = size }; - }); - return; - } - - var content = new Commands.QueryFileContent(_repo, _commit.SHA, file.Path).Result(); - if (content.StartsWith("version https://git-lfs.github.com/spec/", StringComparison.Ordinal)) { - var obj = new Models.RevisionLFSObject() { Object = new Models.LFSObject() }; - var lines = content.Split('\n', StringSplitOptions.RemoveEmptyEntries); - if (lines.Length == 3) { - foreach (var line in lines) { - if (line.StartsWith("oid sha256:", StringComparison.Ordinal)) { - obj.Object.Oid = line.Substring(11); - } else if (line.StartsWith("size ", StringComparison.Ordinal)) { - obj.Object.Size = long.Parse(line.Substring(5)); - } - } - Dispatcher.UIThread.Invoke(() => { - ViewRevisionFileContent = obj; + private void RefreshViewRevisionFile(Models.Object file) + { + switch (file.Type) + { + case Models.ObjectType.Blob: + Task.Run(() => + { + var isBinary = new Commands.IsBinary(_repo, _commit.SHA, file.Path).Result(); + if (isBinary) + { + var size = new Commands.QueryFileSize(_repo, file.Path, _commit.SHA).Result(); + Dispatcher.UIThread.Invoke(() => + { + ViewRevisionFileContent = new Models.RevisionBinaryFile() { Size = size }; }); return; - } - } + } - Dispatcher.UIThread.Invoke(() => { - ViewRevisionFileContent = new Models.RevisionTextFile() { - FileName = file.Path, - Content = content - }; + var content = new Commands.QueryFileContent(_repo, _commit.SHA, file.Path).Result(); + if (content.StartsWith("version https://git-lfs.github.com/spec/", StringComparison.Ordinal)) + { + var obj = new Models.RevisionLFSObject() { Object = new Models.LFSObject() }; + var lines = content.Split('\n', StringSplitOptions.RemoveEmptyEntries); + if (lines.Length == 3) + { + foreach (var line in lines) + { + if (line.StartsWith("oid sha256:", StringComparison.Ordinal)) + { + obj.Object.Oid = line.Substring(11); + } + else if (line.StartsWith("size ", StringComparison.Ordinal)) + { + obj.Object.Size = long.Parse(line.Substring(5)); + } + } + Dispatcher.UIThread.Invoke(() => + { + ViewRevisionFileContent = obj; + }); + return; + } + } + + Dispatcher.UIThread.Invoke(() => + { + ViewRevisionFileContent = new Models.RevisionTextFile() + { + FileName = file.Path, + Content = content + }; + }); }); - }); - break; - case Models.ObjectType.Commit: - ViewRevisionFileContent = new Models.RevisionSubmodule() { SHA = file.SHA }; - break; - default: - ViewRevisionFileContent = null; - break; + break; + case Models.ObjectType.Commit: + ViewRevisionFileContent = new Models.RevisionSubmodule() { SHA = file.SHA }; + break; + default: + ViewRevisionFileContent = null; + break; } } @@ -413,4 +502,4 @@ namespace SourceGit.ViewModels { private object _viewRevisionFileContent = null; private Commands.Command.CancelToken _cancelToken = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/CreateBranch.cs b/src/ViewModels/CreateBranch.cs index 291063ac..e3f2f728 100644 --- a/src/ViewModels/CreateBranch.cs +++ b/src/ViewModels/CreateBranch.cs @@ -1,36 +1,44 @@ using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class CreateBranch : Popup { +namespace SourceGit.ViewModels +{ + public class CreateBranch : Popup + { [Required(ErrorMessage = "Branch name is required!")] [RegularExpression(@"^[\w\-/\.]+$", ErrorMessage = "Bad branch name format!")] [CustomValidation(typeof(CreateBranch), nameof(ValidateBranchName))] - public string Name { + public string Name + { get => _name; set => SetProperty(ref _name, value, true); } - public object BasedOn { + public object BasedOn + { get; private set; } - public bool CheckoutAfterCreated { + public bool CheckoutAfterCreated + { get; set; } = true; - public bool AutoStash { + public bool AutoStash + { get; set; } = true; - public CreateBranch(Repository repo, Models.Branch branch) { + public CreateBranch(Repository repo, Models.Branch branch) + { _repo = repo; _baseOnRevision = branch.FullName; - if (!branch.IsLocal && repo.Branches.Find(x => x.IsLocal && x.Name == branch.Name) == null) { + if (!branch.IsLocal && repo.Branches.Find(x => x.IsLocal && x.Name == branch.Name) == null) + { Name = branch.Name; } @@ -38,7 +46,8 @@ namespace SourceGit.ViewModels { View = new Views.CreateBranch() { DataContext = this }; } - public CreateBranch(Repository repo, Models.Commit commit) { + public CreateBranch(Repository repo, Models.Commit commit) + { _repo = repo; _baseOnRevision = commit.SHA; @@ -46,7 +55,8 @@ namespace SourceGit.ViewModels { View = new Views.CreateBranch() { DataContext = this }; } - public CreateBranch(Repository repo, Models.Tag tag) { + public CreateBranch(Repository repo, Models.Tag tag) + { _repo = repo; _baseOnRevision = tag.SHA; @@ -54,11 +64,13 @@ namespace SourceGit.ViewModels { View = new Views.CreateBranch() { DataContext = this }; } - public static ValidationResult ValidateBranchName(string name, ValidationContext ctx) { + public static ValidationResult ValidateBranchName(string name, ValidationContext ctx) + { var creator = ctx.ObjectInstance as CreateBranch; if (creator == null) return new ValidationResult("Missing runtime context to create branch!"); - foreach (var b in creator._repo.Branches) { + foreach (var b in creator._repo.Branches) + { var test = b.IsLocal ? b.Name : $"{b.Remote}/{b.Name}"; if (test == name) return new ValidationResult("A branch with same name already exists!"); } @@ -66,27 +78,36 @@ namespace SourceGit.ViewModels { return ValidationResult.Success; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); - return Task.Run(() => { - if (CheckoutAfterCreated) { + return Task.Run(() => + { + if (CheckoutAfterCreated) + { bool needPopStash = false; - if (_repo.WorkingCopyChangesCount > 0) { - if (AutoStash) { + if (_repo.WorkingCopyChangesCount > 0) + { + if (AutoStash) + { SetProgressDescription("Adding untracked changes..."); var succ = new Commands.Add(_repo.FullPath).Exec(); - if (succ) { + if (succ) + { SetProgressDescription("Stash local changes"); succ = new Commands.Stash(_repo.FullPath).Push("CREATE_BRANCH_AUTO_STASH"); } - if (!succ) { + if (!succ) + { CallUIThread(() => _repo.SetWatcherEnabled(true)); return false; } needPopStash = true; - } else { + } + else + { SetProgressDescription("Discard local changes..."); Commands.Discard.All(_repo.FullPath); } @@ -95,11 +116,14 @@ namespace SourceGit.ViewModels { SetProgressDescription($"Create new branch '{_name}'"); new Commands.Checkout(_repo.FullPath).Branch(_name, _baseOnRevision, SetProgressDescription); - if (needPopStash) { + if (needPopStash) + { SetProgressDescription("Re-apply local changes..."); new Commands.Stash(_repo.FullPath).Pop("stash@{0}"); } - } else { + } + else + { Commands.Branch.Create(_repo.FullPath, _name, _baseOnRevision); } @@ -108,8 +132,8 @@ namespace SourceGit.ViewModels { }); } - private Repository _repo = null; + private readonly Repository _repo = null; private string _name = null; - private string _baseOnRevision = null; + private readonly string _baseOnRevision = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/CreateGroup.cs b/src/ViewModels/CreateGroup.cs index a398f610..af16d801 100644 --- a/src/ViewModels/CreateGroup.cs +++ b/src/ViewModels/CreateGroup.cs @@ -2,21 +2,27 @@ using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class CreateGroup : Popup { +namespace SourceGit.ViewModels +{ + public class CreateGroup : Popup + { [Required(ErrorMessage = "Group name is required!")] - public string Name { + public string Name + { get => _name; set => SetProperty(ref _name, value, true); } - public CreateGroup(RepositoryNode parent) { + public CreateGroup(RepositoryNode parent) + { _parent = parent; View = new Views.CreateGroup() { DataContext = this }; } - public override Task Sure() { - Preference.AddNode(new RepositoryNode() { + public override Task Sure() + { + Preference.AddNode(new RepositoryNode() + { Id = Guid.NewGuid().ToString(), Name = _name, IsRepository = false, @@ -26,7 +32,7 @@ namespace SourceGit.ViewModels { return null; } - private RepositoryNode _parent = null; + private readonly RepositoryNode _parent = null; private string _name = string.Empty; } -} +} \ No newline at end of file diff --git a/src/ViewModels/CreateTag.cs b/src/ViewModels/CreateTag.cs index 494fc3fc..f5ac562d 100644 --- a/src/ViewModels/CreateTag.cs +++ b/src/ViewModels/CreateTag.cs @@ -3,27 +3,33 @@ using System.ComponentModel.DataAnnotations; using System.Text.RegularExpressions; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class CreateTag : Popup { +namespace SourceGit.ViewModels +{ + public class CreateTag : Popup + { [Required(ErrorMessage = "Tag name is required!")] [RegularExpression(@"^[\w\-\.]+$", ErrorMessage = "Bad tag name format!")] [CustomValidation(typeof(CreateTag), nameof(ValidateTagName))] - public string TagName { + public string TagName + { get => _tagName; set => SetProperty(ref _tagName, value, true); } - public string Message { + public string Message + { get; set; } - public object BasedOn { + public object BasedOn + { get; private set; } - public CreateTag(Repository repo, Models.Branch branch) { + public CreateTag(Repository repo, Models.Branch branch) + { _repo = repo; _basedOn = branch.Head; @@ -31,7 +37,8 @@ namespace SourceGit.ViewModels { View = new Views.CreateTag() { DataContext = this }; } - public CreateTag(Repository repo, Models.Commit commit) { + public CreateTag(Repository repo, Models.Commit commit) + { _repo = repo; _basedOn = commit.SHA; @@ -39,28 +46,32 @@ namespace SourceGit.ViewModels { View = new Views.CreateTag() { DataContext = this }; } - public static ValidationResult ValidateTagName(string name, ValidationContext ctx) { + public static ValidationResult ValidateTagName(string name, ValidationContext ctx) + { var creator = ctx.ObjectInstance as CreateTag; - if (creator != null) { + if (creator != null) + { var found = creator._repo.Tags.Find(x => x.Name == name); if (found != null) return new ValidationResult("A tag with same name already exists!"); } return ValidationResult.Success; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = "Create tag..."; - return Task.Run(() => { + return Task.Run(() => + { Commands.Tag.Add(_repo.FullPath, TagName, _basedOn, Message); CallUIThread(() => _repo.SetWatcherEnabled(true)); return true; }); } - private Repository _repo = null; + private readonly Repository _repo = null; private string _tagName = string.Empty; - private string _basedOn = string.Empty; + private readonly string _basedOn = string.Empty; } -} +} \ No newline at end of file diff --git a/src/ViewModels/DeleteBranch.cs b/src/ViewModels/DeleteBranch.cs index 924ee12b..aa9788bf 100644 --- a/src/ViewModels/DeleteBranch.cs +++ b/src/ViewModels/DeleteBranch.cs @@ -1,26 +1,35 @@ using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class DeleteBranch : Popup { - public Models.Branch Target { +namespace SourceGit.ViewModels +{ + public class DeleteBranch : Popup + { + public Models.Branch Target + { get; private set; } - public DeleteBranch(Repository repo, Models.Branch branch) { + public DeleteBranch(Repository repo, Models.Branch branch) + { _repo = repo; Target = branch; View = new Views.DeleteBranch() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = "Deleting branch..."; - return Task.Run(() => { - if (Target.IsLocal) { + return Task.Run(() => + { + if (Target.IsLocal) + { Commands.Branch.Delete(_repo.FullPath, Target.Name); - } else { + } + else + { new Commands.Push(_repo.FullPath, Target.Remote, Target.Name).Exec(); } @@ -29,6 +38,6 @@ namespace SourceGit.ViewModels { }); } - private Repository _repo = null; + private readonly Repository _repo = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/DeleteRemote.cs b/src/ViewModels/DeleteRemote.cs index 83cea173..b00c1aea 100644 --- a/src/ViewModels/DeleteRemote.cs +++ b/src/ViewModels/DeleteRemote.cs @@ -1,25 +1,32 @@ using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class DeleteRemote : Popup { - public Models.Remote Remote { +namespace SourceGit.ViewModels +{ + public class DeleteRemote : Popup + { + public Models.Remote Remote + { get; private set; } - public DeleteRemote(Repository repo, Models.Remote remote) { + public DeleteRemote(Repository repo, Models.Remote remote) + { _repo = repo; Remote = remote; View = new Views.DeleteRemote() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = "Deleting remote ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Remote(_repo.FullPath).Delete(Remote.Name); - CallUIThread(() => { + CallUIThread(() => + { _repo.MarkBranchesDirtyManually(); _repo.SetWatcherEnabled(true); }); @@ -27,6 +34,6 @@ namespace SourceGit.ViewModels { }); } - private Repository _repo = null; + private readonly Repository _repo = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/DeleteRepositoryNode.cs b/src/ViewModels/DeleteRepositoryNode.cs index 03e4e9ef..9cc201f0 100644 --- a/src/ViewModels/DeleteRepositoryNode.cs +++ b/src/ViewModels/DeleteRepositoryNode.cs @@ -1,22 +1,27 @@ using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class DeleteRepositoryNode : Popup { - public RepositoryNode Node { +namespace SourceGit.ViewModels +{ + public class DeleteRepositoryNode : Popup + { + public RepositoryNode Node + { get => _node; set => SetProperty(ref _node, value); } - public DeleteRepositoryNode(RepositoryNode node) { + public DeleteRepositoryNode(RepositoryNode node) + { _node = node; View = new Views.DeleteRepositoryNode() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { Preference.RemoveNode(_node); return null; } private RepositoryNode _node = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/DeleteSubmodule.cs b/src/ViewModels/DeleteSubmodule.cs index 41b0fbca..33c7c3ac 100644 --- a/src/ViewModels/DeleteSubmodule.cs +++ b/src/ViewModels/DeleteSubmodule.cs @@ -1,30 +1,36 @@ using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class DeleteSubmodule : Popup { +namespace SourceGit.ViewModels +{ + public class DeleteSubmodule : Popup + { - public string Submodule { + public string Submodule + { get; private set; } - public DeleteSubmodule(Repository repo, string submodule) { + public DeleteSubmodule(Repository repo, string submodule) + { _repo = repo; Submodule = submodule; View = new Views.DeleteSubmodule() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = "Deleting submodule ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Submodule(_repo.FullPath).Delete(Submodule); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } - private Repository _repo = null; + private readonly Repository _repo = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/DeleteTag.cs b/src/ViewModels/DeleteTag.cs index 9890a535..70648462 100644 --- a/src/ViewModels/DeleteTag.cs +++ b/src/ViewModels/DeleteTag.cs @@ -1,29 +1,36 @@ using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class DeleteTag : Popup { - public Models.Tag Target { +namespace SourceGit.ViewModels +{ + public class DeleteTag : Popup + { + public Models.Tag Target + { get; private set; } - public bool ShouldPushToRemote { + public bool ShouldPushToRemote + { get; set; } - public DeleteTag(Repository repo, Models.Tag tag) { + public DeleteTag(Repository repo, Models.Tag tag) + { _repo = repo; Target = tag; ShouldPushToRemote = true; View = new Views.DeleteTag() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = $"Deleting tag '{Target.Name}' ..."; - return Task.Run(() => { + return Task.Run(() => + { var remotes = ShouldPushToRemote ? _repo.Remotes : null; var succ = Commands.Tag.Delete(_repo.FullPath, Target.Name, remotes); CallUIThread(() => _repo.SetWatcherEnabled(true)); @@ -31,6 +38,6 @@ namespace SourceGit.ViewModels { }); } - private Repository _repo = null; + private readonly Repository _repo = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/DiffContext.cs b/src/ViewModels/DiffContext.cs index 470125aa..d3cf3a6b 100644 --- a/src/ViewModels/DiffContext.cs +++ b/src/ViewModels/DiffContext.cs @@ -1,61 +1,77 @@ -using Avalonia; -using Avalonia.Threading; -using CommunityToolkit.Mvvm.ComponentModel; -using System.IO; +using System.IO; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class DiffContext : ObservableObject { - public string RepositoryPath { +using Avalonia; +using Avalonia.Threading; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class DiffContext : ObservableObject + { + public string RepositoryPath + { get => _repo; } - public Models.Change WorkingCopyChange { + public Models.Change WorkingCopyChange + { get => _option.WorkingCopyChange; } - public bool IsUnstaged { + public bool IsUnstaged + { get => _option.IsUnstaged; } - public string FilePath { + public string FilePath + { get => _option.Path; } - public bool IsOrgFilePathVisible { + public bool IsOrgFilePathVisible + { get => !string.IsNullOrWhiteSpace(_option.OrgPath) && _option.OrgPath != "/dev/null"; } - public string OrgFilePath { + public string OrgFilePath + { get => _option.OrgPath; } - public bool IsLoading { + public bool IsLoading + { get => _isLoading; private set => SetProperty(ref _isLoading, value); } - public bool IsNoChange { + public bool IsNoChange + { get => _isNoChange; private set => SetProperty(ref _isNoChange, value); } - public bool IsTextDiff { + public bool IsTextDiff + { get => _isTextDiff; private set => SetProperty(ref _isTextDiff, value); } - public object Content { + public object Content + { get => _content; private set => SetProperty(ref _content, value); } - public Vector SyncScrollOffset { + public Vector SyncScrollOffset + { get => _syncScrollOffset; set => SetProperty(ref _syncScrollOffset, value); } - public DiffContext(string repo, Models.DiffOption option) { + public DiffContext(string repo, Models.DiffOption option) + { _repo = repo; _option = option; @@ -63,33 +79,46 @@ namespace SourceGit.ViewModels { OnPropertyChanged(nameof(IsOrgFilePathVisible)); OnPropertyChanged(nameof(OrgFilePath)); - Task.Run(() => { + Task.Run(() => + { var latest = new Commands.Diff(repo, option).Result(); var binaryDiff = null as Models.BinaryDiff; - if (latest.IsBinary) { + if (latest.IsBinary) + { binaryDiff = new Models.BinaryDiff(); var oldPath = string.IsNullOrEmpty(_option.OrgPath) ? _option.Path : _option.OrgPath; - if (option.Revisions.Count == 2) { + if (option.Revisions.Count == 2) + { binaryDiff.OldSize = new Commands.QueryFileSize(repo, oldPath, option.Revisions[0]).Result(); binaryDiff.NewSize = new Commands.QueryFileSize(repo, _option.Path, option.Revisions[1]).Result(); - } else { + } + else + { binaryDiff.OldSize = new Commands.QueryFileSize(repo, oldPath, "HEAD").Result(); binaryDiff.NewSize = new FileInfo(Path.Combine(repo, _option.Path)).Length; } } - Dispatcher.UIThread.InvokeAsync(() => { - if (latest.IsBinary) { + Dispatcher.UIThread.InvokeAsync(() => + { + if (latest.IsBinary) + { Content = binaryDiff; - } else if (latest.IsLFS) { + } + else if (latest.IsLFS) + { Content = latest.LFSDiff; - } else if (latest.TextDiff != null) { + } + else if (latest.TextDiff != null) + { latest.TextDiff.File = _option.Path; Content = latest.TextDiff; IsTextDiff = true; - } else { + } + else + { IsTextDiff = false; IsNoChange = true; } @@ -99,12 +128,14 @@ namespace SourceGit.ViewModels { }); } - public async void OpenExternalMergeTool() { + public async void OpenExternalMergeTool() + { var type = Preference.Instance.ExternalMergeToolType; var exec = Preference.Instance.ExternalMergeToolPath; var tool = Models.ExternalMergeTools.Supported.Find(x => x.Type == type); - if (tool == null || !File.Exists(exec)) { + if (tool == null || !File.Exists(exec)) + { App.RaiseException(_repo, "Invalid merge tool in preference setting!"); return; } @@ -113,12 +144,12 @@ namespace SourceGit.ViewModels { await Task.Run(() => Commands.MergeTool.OpenForDiff(_repo, exec, args, _option)); } - private string _repo = string.Empty; - private Models.DiffOption _option = null; + private readonly string _repo = string.Empty; + private readonly Models.DiffOption _option = null; private bool _isLoading = true; private bool _isNoChange = false; private bool _isTextDiff = false; private object _content = null; private Vector _syncScrollOffset = Vector.Zero; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Discard.cs b/src/ViewModels/Discard.cs index be2dedc0..5960c5b2 100644 --- a/src/ViewModels/Discard.cs +++ b/src/ViewModels/Discard.cs @@ -1,51 +1,68 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace SourceGit.ViewModels { +namespace SourceGit.ViewModels +{ public class DiscardModeAll { } public class DiscardModeSingle { public string File { get; set; } } public class DiscardModeMulti { public int Count { get; set; } } - public class Discard : Popup { + public class Discard : Popup + { - public object Mode { + public object Mode + { get; private set; } - public Discard(Repository repo) { + public Discard(Repository repo) + { _repo = repo; Mode = new DiscardModeAll(); View = new Views.Discard { DataContext = this }; } - public Discard(Repository repo, List changes, bool isUnstaged) { + public Discard(Repository repo, List changes, bool isUnstaged) + { _repo = repo; _changes = changes; _isUnstaged = isUnstaged; - if (_changes == null) { + if (_changes == null) + { Mode = new DiscardModeAll(); - } else if (_changes.Count == 1) { + } + else if (_changes.Count == 1) + { Mode = new DiscardModeSingle() { File = _changes[0].Path }; - } else { + } + else + { Mode = new DiscardModeMulti() { Count = _changes.Count }; } View = new Views.Discard() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = _changes == null ? "Discard all local changes ..." : $"Discard total {_changes.Count} changes ..."; - return Task.Run(() => { - if (_changes == null) { + return Task.Run(() => + { + if (_changes == null) + { Commands.Discard.All(_repo.FullPath); - } else if (_isUnstaged) { + } + else if (_isUnstaged) + { Commands.Discard.ChangesInWorkTree(_repo.FullPath, _changes); - } else { + } + else + { Commands.Discard.ChangesInStaged(_repo.FullPath, _changes); } @@ -54,8 +71,8 @@ namespace SourceGit.ViewModels { }); } - private Repository _repo = null; - private List _changes = null; - private bool _isUnstaged = true; + private readonly Repository _repo = null; + private readonly List _changes = null; + private readonly bool _isUnstaged = true; } -} +} \ No newline at end of file diff --git a/src/ViewModels/DropStash.cs b/src/ViewModels/DropStash.cs index 87926503..9b71a724 100644 --- a/src/ViewModels/DropStash.cs +++ b/src/ViewModels/DropStash.cs @@ -1,24 +1,29 @@ using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class DropStash : Popup { +namespace SourceGit.ViewModels +{ + public class DropStash : Popup + { public Models.Stash Stash { get; private set; } - public DropStash(string repo, Models.Stash stash) { + public DropStash(string repo, Models.Stash stash) + { _repo = repo; Stash = stash; View = new Views.DropStash() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { ProgressDescription = $"Dropping stash: {Stash.Name}"; - return Task.Run(() => { + return Task.Run(() => + { new Commands.Stash(_repo).Drop(Stash.Name); return true; }); } - private string _repo; + private readonly string _repo; } -} +} \ No newline at end of file diff --git a/src/ViewModels/EditRemote.cs b/src/ViewModels/EditRemote.cs index ae735a80..67687cf6 100644 --- a/src/ViewModels/EditRemote.cs +++ b/src/ViewModels/EditRemote.cs @@ -1,52 +1,64 @@ using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class EditRemote : Popup { +namespace SourceGit.ViewModels +{ + public class EditRemote : Popup + { [Required(ErrorMessage = "Remote name is required!!!")] [RegularExpression(@"^[\w\-\.]+$", ErrorMessage = "Bad remote name format!!!")] [CustomValidation(typeof(EditRemote), nameof(ValidateRemoteName))] - public string Name { + public string Name + { get => _name; set => SetProperty(ref _name, value, true); } [Required(ErrorMessage = "Remote URL is required!!!")] [CustomValidation(typeof(EditRemote), nameof(ValidateRemoteURL))] - public string Url { + public string Url + { get => _url; - set { + set + { if (SetProperty(ref _url, value, true)) UseSSH = Models.Remote.IsSSH(value); } } - public bool UseSSH { + public bool UseSSH + { get => _useSSH; set => SetProperty(ref _useSSH, value); } - public string SSHKey { + public string SSHKey + { get; set; } - public EditRemote(Repository repo, Models.Remote remote) { + public EditRemote(Repository repo, Models.Remote remote) + { _repo = repo; _remote = remote; _name = remote.Name; _url = remote.URL; _useSSH = Models.Remote.IsSSH(remote.URL); - if (_useSSH) { + if (_useSSH) + { SSHKey = new Commands.Config(repo.FullPath).Get($"remote.{remote.Name}.sshkey"); } View = new Views.EditRemote() { DataContext = this }; } - public static ValidationResult ValidateRemoteName(string name, ValidationContext ctx) { - if (ctx.ObjectInstance is EditRemote edit) { - foreach (var remote in edit._repo.Remotes) { + public static ValidationResult ValidateRemoteName(string name, ValidationContext ctx) + { + if (ctx.ObjectInstance is EditRemote edit) + { + foreach (var remote in edit._repo.Remotes) + { if (remote != edit._remote && name == remote.Name) new ValidationResult("A remote with given name already exists!!!"); } } @@ -54,11 +66,14 @@ namespace SourceGit.ViewModels { return ValidationResult.Success; } - public static ValidationResult ValidateRemoteURL(string url, ValidationContext ctx) { - if (ctx.ObjectInstance is EditRemote edit) { + public static ValidationResult ValidateRemoteURL(string url, ValidationContext ctx) + { + if (ctx.ObjectInstance is EditRemote edit) + { if (!Models.Remote.IsValidURL(url)) return new ValidationResult("Bad remote URL format!!!"); - foreach (var remote in edit._repo.Remotes) { + foreach (var remote in edit._repo.Remotes) + { if (remote != edit._remote && url == remote.URL) new ValidationResult("A remote with the same url already exists!!!"); } } @@ -66,22 +81,27 @@ namespace SourceGit.ViewModels { return ValidationResult.Success; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = $"Editing remote '{_remote.Name}' ..."; - return Task.Run(() => { - if (_remote.Name != _name) { + return Task.Run(() => + { + if (_remote.Name != _name) + { var succ = new Commands.Remote(_repo.FullPath).Rename(_remote.Name, _name); if (succ) _remote.Name = _name; } - if (_remote.URL != _url) { + if (_remote.URL != _url) + { var succ = new Commands.Remote(_repo.FullPath).SetURL(_name, _url); if (succ) _remote.URL = _url; } - if (_useSSH) { + if (_useSSH) + { SetProgressDescription("Post processing ..."); new Commands.Config(_repo.FullPath).Set($"remote.{_name}.sshkey", SSHKey); } @@ -91,10 +111,10 @@ namespace SourceGit.ViewModels { }); } - private Repository _repo = null; - private Models.Remote _remote = null; + private readonly Repository _repo = null; + private readonly Models.Remote _remote = null; private string _name = string.Empty; private string _url = string.Empty; private bool _useSSH = false; } -} +} \ No newline at end of file diff --git a/src/ViewModels/EditRepositoryNode.cs b/src/ViewModels/EditRepositoryNode.cs index 6111b72e..c2e53085 100644 --- a/src/ViewModels/EditRepositoryNode.cs +++ b/src/ViewModels/EditRepositoryNode.cs @@ -2,35 +2,43 @@ using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class EditRepositoryNode : Popup { - public RepositoryNode Node { +namespace SourceGit.ViewModels +{ + public class EditRepositoryNode : Popup + { + public RepositoryNode Node + { get => _node; set => SetProperty(ref _node, value); } - public string Id { + public string Id + { get => _id; set => SetProperty(ref _id, value); } [Required(ErrorMessage = "Name is required!")] - public string Name { + public string Name + { get => _name; set => SetProperty(ref _name, value, true); } - public int Bookmark { + public int Bookmark + { get => _bookmark; set => SetProperty(ref _bookmark, value); } - public bool IsRepository { + public bool IsRepository + { get => _isRepository; set => SetProperty(ref _isRepository, value); } - public EditRepositoryNode(RepositoryNode node) { + public EditRepositoryNode(RepositoryNode node) + { _node = node; _id = node.Id; _name = node.Name; @@ -40,16 +48,17 @@ namespace SourceGit.ViewModels { View = new Views.EditRepositoryNode() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _node.Name = _name; _node.Bookmark = _bookmark; return null; } - private RepositoryNode _node = null; + private RepositoryNode _node = null; private string _id = string.Empty; private string _name = string.Empty; private bool _isRepository = false; private int _bookmark = 0; } -} +} \ No newline at end of file diff --git a/src/ViewModels/FastForwardWithoutCheckout.cs b/src/ViewModels/FastForwardWithoutCheckout.cs index 5d2da837..6e7ab18f 100644 --- a/src/ViewModels/FastForwardWithoutCheckout.cs +++ b/src/ViewModels/FastForwardWithoutCheckout.cs @@ -1,35 +1,42 @@ using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class FastForwardWithoutCheckout : Popup { - public Models.Branch Local { +namespace SourceGit.ViewModels +{ + public class FastForwardWithoutCheckout : Popup + { + public Models.Branch Local + { get; private set; } - public Models.Branch To { + public Models.Branch To + { get; private set; } - public FastForwardWithoutCheckout(Repository repo, Models.Branch local, Models.Branch upstream) { + public FastForwardWithoutCheckout(Repository repo, Models.Branch local, Models.Branch upstream) + { _repo = repo; Local = local; To = upstream; View = new Views.FastForwardWithoutCheckout() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = "Fast-Forward ..."; - return Task.Run(() => { + return Task.Run(() => + { new Commands.Fetch(_repo.FullPath, To.Remote, Local.Name, To.Name, SetProgressDescription).Exec(); CallUIThread(() => _repo.SetWatcherEnabled(true)); return true; }); } - private Repository _repo = null; + private readonly Repository _repo = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Fetch.cs b/src/ViewModels/Fetch.cs index dc85c94d..a2db7e72 100644 --- a/src/ViewModels/Fetch.cs +++ b/src/ViewModels/Fetch.cs @@ -1,28 +1,35 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Fetch : Popup { - public List Remotes { +namespace SourceGit.ViewModels +{ + public class Fetch : Popup + { + public List Remotes + { get => _repo.Remotes; } - public bool FetchAllRemotes { + public bool FetchAllRemotes + { get => _fetchAllRemotes; set => SetProperty(ref _fetchAllRemotes, value); } - public Models.Remote SelectedRemote { + public Models.Remote SelectedRemote + { get; set; } - public bool Prune { + public bool Prune + { get; set; } - public Fetch(Repository repo, Models.Remote preferedRemote = null) { + public Fetch(Repository repo, Models.Remote preferedRemote = null) + { _repo = repo; _fetchAllRemotes = preferedRemote == null; SelectedRemote = preferedRemote != null ? preferedRemote : _repo.Remotes[0]; @@ -30,15 +37,21 @@ namespace SourceGit.ViewModels { View = new Views.Fetch() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); - return Task.Run(() => { - if (FetchAllRemotes) { - foreach (var remote in _repo.Remotes) { + return Task.Run(() => + { + if (FetchAllRemotes) + { + foreach (var remote in _repo.Remotes) + { SetProgressDescription($"Fetching remote: {remote.Name}"); new Commands.Fetch(_repo.FullPath, remote.Name, Prune, SetProgressDescription).Exec(); } - } else { + } + else + { SetProgressDescription($"Fetching remote: {SelectedRemote.Name}"); new Commands.Fetch(_repo.FullPath, SelectedRemote.Name, Prune, SetProgressDescription).Exec(); } @@ -48,7 +61,7 @@ namespace SourceGit.ViewModels { }); } - private Repository _repo = null; + private readonly Repository _repo = null; private bool _fetchAllRemotes = true; } -} +} \ No newline at end of file diff --git a/src/ViewModels/FileHistories.cs b/src/ViewModels/FileHistories.cs index 90356484..f2e84c7e 100644 --- a/src/ViewModels/FileHistories.cs +++ b/src/ViewModels/FileHistories.cs @@ -1,49 +1,66 @@ -using Avalonia.Threading; -using CommunityToolkit.Mvvm.ComponentModel; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class FileHistories : ObservableObject { - public string File { +using Avalonia.Threading; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class FileHistories : ObservableObject + { + public string File + { get => _file; } - public bool IsLoading { + public bool IsLoading + { get => _isLoading; private set => SetProperty(ref _isLoading, value); } - public List Commits { + public List Commits + { get => _commits; set => SetProperty(ref _commits, value); } - public Models.Commit SelectedCommit { + public Models.Commit SelectedCommit + { get => _selectedCommit; - set { - if (SetProperty(ref _selectedCommit, value)) { - if (value == null) { + set + { + if (SetProperty(ref _selectedCommit, value)) + { + if (value == null) + { DiffContext = null; - } else { + } + else + { DiffContext = new DiffContext(_repo, new Models.DiffOption(value, _file)); } } } } - public DiffContext DiffContext { + public DiffContext DiffContext + { get => _diffContext; set => SetProperty(ref _diffContext, value); } - public FileHistories(string repo, string file) { + public FileHistories(string repo, string file) + { _repo = repo; _file = file; - Task.Run(() => { + Task.Run(() => + { var commits = new Commands.QueryCommits(_repo, $"-n 10000 -- \"{file}\"").Result(); - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { IsLoading = false; Commits = commits; if (commits.Count > 0) SelectedCommit = commits[0]; @@ -51,16 +68,17 @@ namespace SourceGit.ViewModels { }); } - public void NavigateToCommit(string commitSHA) { + public void NavigateToCommit(string commitSHA) + { var repo = Preference.FindRepository(_repo); if (repo != null) repo.NavigateToCommit(commitSHA); } - private string _repo = string.Empty; - private string _file = string.Empty; + private readonly string _repo = string.Empty; + private readonly string _file = string.Empty; private bool _isLoading = true; private List _commits = null; private Models.Commit _selectedCommit = null; private DiffContext _diffContext = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/FileTreeNode.cs b/src/ViewModels/FileTreeNode.cs index cec0620e..cba11d03 100644 --- a/src/ViewModels/FileTreeNode.cs +++ b/src/ViewModels/FileTreeNode.cs @@ -1,43 +1,58 @@ -using CommunityToolkit.Mvvm.ComponentModel; -using System; +using System; using System.Collections.Generic; -namespace SourceGit.ViewModels { - public class FileTreeNode : ObservableObject { +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class FileTreeNode : ObservableObject + { public string FullPath { get; set; } = string.Empty; public bool IsFolder { get; set; } = false; public object Backend { get; set; } = null; public List Children { get; set; } = new List(); - public bool IsExpanded { + public bool IsExpanded + { get => _isExpanded; set => SetProperty(ref _isExpanded, value); } - public static List Build(List changes) { + public static List Build(List changes) + { var nodes = new List(); var folders = new Dictionary(); var expanded = changes.Count <= 50; - foreach (var c in changes) { + foreach (var c in changes) + { var sepIdx = c.Path.IndexOf('/', StringComparison.Ordinal); - if (sepIdx == -1) { - nodes.Add(new FileTreeNode() { + if (sepIdx == -1) + { + nodes.Add(new FileTreeNode() + { FullPath = c.Path, Backend = c, IsFolder = false, IsExpanded = false }); - } else { + } + else + { FileTreeNode lastFolder = null; var start = 0; - while (sepIdx != -1) { + while (sepIdx != -1) + { var folder = c.Path.Substring(0, sepIdx); - if (folders.ContainsKey(folder)) { + if (folders.ContainsKey(folder)) + { lastFolder = folders[folder]; - } else if (lastFolder == null) { - lastFolder = new FileTreeNode() { + } + else if (lastFolder == null) + { + lastFolder = new FileTreeNode() + { FullPath = folder, Backend = null, IsFolder = true, @@ -45,8 +60,11 @@ namespace SourceGit.ViewModels { }; nodes.Add(lastFolder); folders.Add(folder, lastFolder); - } else { - var cur = new FileTreeNode() { + } + else + { + var cur = new FileTreeNode() + { FullPath = folder, Backend = null, IsFolder = true, @@ -61,7 +79,8 @@ namespace SourceGit.ViewModels { sepIdx = c.Path.IndexOf('/', start); } - lastFolder.Children.Add(new FileTreeNode() { + lastFolder.Children.Add(new FileTreeNode() + { FullPath = c.Path, Backend = c, IsFolder = false, @@ -75,30 +94,41 @@ namespace SourceGit.ViewModels { return nodes; } - public static List Build(List files) { + public static List Build(List files) + { var nodes = new List(); var folders = new Dictionary(); var expanded = files.Count <= 50; - foreach (var f in files) { + foreach (var f in files) + { var sepIdx = f.Path.IndexOf('/', StringComparison.Ordinal); - if (sepIdx == -1) { - nodes.Add(new FileTreeNode() { + if (sepIdx == -1) + { + nodes.Add(new FileTreeNode() + { FullPath = f.Path, Backend = f, IsFolder = false, IsExpanded = false }); - } else { + } + else + { FileTreeNode lastFolder = null; var start = 0; - while (sepIdx != -1) { + while (sepIdx != -1) + { var folder = f.Path.Substring(0, sepIdx); - if (folders.ContainsKey(folder)) { + if (folders.ContainsKey(folder)) + { lastFolder = folders[folder]; - } else if (lastFolder == null) { - lastFolder = new FileTreeNode() { + } + else if (lastFolder == null) + { + lastFolder = new FileTreeNode() + { FullPath = folder, Backend = null, IsFolder = true, @@ -106,8 +136,11 @@ namespace SourceGit.ViewModels { }; nodes.Add(lastFolder); folders.Add(folder, lastFolder); - } else { - var cur = new FileTreeNode() { + } + else + { + var cur = new FileTreeNode() + { FullPath = folder, Backend = null, IsFolder = true, @@ -122,7 +155,8 @@ namespace SourceGit.ViewModels { sepIdx = f.Path.IndexOf('/', start); } - lastFolder.Children.Add(new FileTreeNode() { + lastFolder.Children.Add(new FileTreeNode() + { FullPath = f.Path, Backend = f, IsFolder = false, @@ -136,13 +170,17 @@ namespace SourceGit.ViewModels { return nodes; } - public static FileTreeNode SelectByPath(List nodes, string path) { - foreach (var node in nodes) { + public static FileTreeNode SelectByPath(List nodes, string path) + { + foreach (var node in nodes) + { if (node.FullPath == path) return node; - - if (node.IsFolder && path.StartsWith(node.FullPath + "/", StringComparison.Ordinal)) { + + if (node.IsFolder && path.StartsWith(node.FullPath + "/", StringComparison.Ordinal)) + { var foundInChildren = SelectByPath(node.Children, path); - if (foundInChildren != null) { + if (foundInChildren != null) + { node.IsExpanded = true; } return foundInChildren; @@ -152,20 +190,26 @@ namespace SourceGit.ViewModels { return null; } - private static void Sort(List nodes) { - nodes.Sort((l, r) => { - if (l.IsFolder == r.IsFolder) { + private static void Sort(List nodes) + { + nodes.Sort((l, r) => + { + if (l.IsFolder == r.IsFolder) + { return l.FullPath.CompareTo(r.FullPath); - } else { + } + else + { return l.IsFolder ? -1 : 1; } }); - foreach (var node in nodes) { + foreach (var node in nodes) + { if (node.Children.Count > 1) Sort(node.Children); } } private bool _isExpanded = true; } -} +} \ No newline at end of file diff --git a/src/ViewModels/GitFlowFinish.cs b/src/ViewModels/GitFlowFinish.cs index a50251ce..e203b2e6 100644 --- a/src/ViewModels/GitFlowFinish.cs +++ b/src/ViewModels/GitFlowFinish.cs @@ -1,38 +1,45 @@ using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class GitFlowFinish : Popup { +namespace SourceGit.ViewModels +{ + public class GitFlowFinish : Popup + { public Models.Branch Branch => _branch; public bool IsFeature => _type == Models.GitFlowBranchType.Feature; public bool IsRelease => _type == Models.GitFlowBranchType.Release; public bool IsHotfix => _type == Models.GitFlowBranchType.Hotfix; - public bool KeepBranch { + public bool KeepBranch + { get; set; } = false; - public GitFlowFinish(Repository repo, Models.Branch branch, Models.GitFlowBranchType type) { + public GitFlowFinish(Repository repo, Models.Branch branch, Models.GitFlowBranchType type) + { _repo = repo; _branch = branch; _type = type; View = new Views.GitFlowFinish() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); - return Task.Run(() => { + return Task.Run(() => + { var branch = _branch.Name; - switch (_type) { - case Models.GitFlowBranchType.Feature: - branch = branch.Substring(_repo.GitFlow.Feature.Length); - break; - case Models.GitFlowBranchType.Release: - branch = branch.Substring(_repo.GitFlow.Release.Length); - break; - default: - branch = branch.Substring(_repo.GitFlow.Hotfix.Length); - break; + switch (_type) + { + case Models.GitFlowBranchType.Feature: + branch = branch.Substring(_repo.GitFlow.Feature.Length); + break; + case Models.GitFlowBranchType.Release: + branch = branch.Substring(_repo.GitFlow.Release.Length); + break; + default: + branch = branch.Substring(_repo.GitFlow.Hotfix.Length); + break; } var succ = new Commands.GitFlow(_repo.FullPath).Finish(_type, branch, KeepBranch); @@ -41,8 +48,8 @@ namespace SourceGit.ViewModels { }); } - private Repository _repo = null; - private Models.Branch _branch = null; - private Models.GitFlowBranchType _type = Models.GitFlowBranchType.None; + private readonly Repository _repo = null; + private readonly Models.Branch _branch = null; + private readonly Models.GitFlowBranchType _type = Models.GitFlowBranchType.None; } -} +} \ No newline at end of file diff --git a/src/ViewModels/GitFlowStart.cs b/src/ViewModels/GitFlowStart.cs index d1e4cf5c..c5b2ac06 100644 --- a/src/ViewModels/GitFlowStart.cs +++ b/src/ViewModels/GitFlowStart.cs @@ -1,17 +1,21 @@ using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class GitFlowStart : Popup { +namespace SourceGit.ViewModels +{ + public class GitFlowStart : Popup + { [Required(ErrorMessage = "Name is required!!!")] [RegularExpression(@"^[\w\-/\.]+$", ErrorMessage = "Bad branch name format!")] [CustomValidation(typeof(GitFlowStart), nameof(ValidateBranchName))] - public string Name { + public string Name + { get => _name; set => SetProperty(ref _name, value, true); } - public string Prefix { + public string Prefix + { get => _prefix; } @@ -19,29 +23,34 @@ namespace SourceGit.ViewModels { public bool IsRelease => _type == Models.GitFlowBranchType.Release; public bool IsHotfix => _type == Models.GitFlowBranchType.Hotfix; - public GitFlowStart(Repository repo, Models.GitFlowBranchType type) { + public GitFlowStart(Repository repo, Models.GitFlowBranchType type) + { _repo = repo; _type = type; - switch (type) { - case Models.GitFlowBranchType.Feature: - _prefix = repo.GitFlow.Feature; - break; - case Models.GitFlowBranchType.Release: - _prefix = repo.GitFlow.Release; - break; - default: - _prefix = repo.GitFlow.Hotfix; - break; + switch (type) + { + case Models.GitFlowBranchType.Feature: + _prefix = repo.GitFlow.Feature; + break; + case Models.GitFlowBranchType.Release: + _prefix = repo.GitFlow.Release; + break; + default: + _prefix = repo.GitFlow.Hotfix; + break; } View = new Views.GitFlowStart() { DataContext = this }; } - public static ValidationResult ValidateBranchName(string name, ValidationContext ctx) { - if (ctx.ObjectInstance is GitFlowStart starter) { + public static ValidationResult ValidateBranchName(string name, ValidationContext ctx) + { + if (ctx.ObjectInstance is GitFlowStart starter) + { var check = $"{starter._prefix}{name}"; - foreach (var b in starter._repo.Branches) { + foreach (var b in starter._repo.Branches) + { var test = b.IsLocal ? b.Name : $"{b.Remote}/{b.Name}"; if (test == check) return new ValidationResult("A branch with same name already exists!"); } @@ -50,18 +59,20 @@ namespace SourceGit.ViewModels { return ValidationResult.Success; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.GitFlow(_repo.FullPath).Start(_type, _name); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } - private Repository _repo = null; - private Models.GitFlowBranchType _type = Models.GitFlowBranchType.Feature; - private string _prefix = string.Empty; + private readonly Repository _repo = null; + private readonly Models.GitFlowBranchType _type = Models.GitFlowBranchType.Feature; + private readonly string _prefix = string.Empty; private string _name = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index 99642050..d69ef71a 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -1,35 +1,47 @@ -using Avalonia.Controls; -using Avalonia.Platform.Storage; -using Avalonia.Threading; -using CommunityToolkit.Mvvm.ComponentModel; -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class CountSelectedCommits { +using Avalonia.Controls; +using Avalonia.Platform.Storage; +using Avalonia.Threading; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class CountSelectedCommits + { public int Count { get; set; } } - public class Histories : ObservableObject { - public bool IsLoading { + public class Histories : ObservableObject + { + public bool IsLoading + { get => _isLoading; set => SetProperty(ref _isLoading, value); } - public double DataGridRowHeight { + public double DataGridRowHeight + { get => _dataGridRowHeight; } - public List Commits { + public List Commits + { get => _commits; - set { - if (SetProperty(ref _commits, value)) { + set + { + if (SetProperty(ref _commits, value)) + { Graph = null; - Task.Run(() => { + Task.Run(() => + { var graph = Models.CommitGraph.Parse(value, DataGridRowHeight, 8); - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { Graph = graph; }); }); @@ -37,49 +49,62 @@ namespace SourceGit.ViewModels { } } - public Models.CommitGraph Graph { + public Models.CommitGraph Graph + { get => _graph; set => SetProperty(ref _graph, value); } - public Models.Commit AutoSelectedCommit { + public Models.Commit AutoSelectedCommit + { get => _autoSelectedCommit; private set => SetProperty(ref _autoSelectedCommit, value); } - public object DetailContext { + public object DetailContext + { get => _detailContext; private set => SetProperty(ref _detailContext, value); } - public Histories(Repository repo) { + public Histories(Repository repo) + { _repo = repo; } - public void Cleanup() { + public void Cleanup() + { Commits = new List(); _repo = null; _graph = null; _autoSelectedCommit = null; - if (_detailContext is CommitDetail cd) { + if (_detailContext is CommitDetail cd) + { cd.Cleanup(); - } else if (_detailContext is RevisionCompare rc) { + } + else if (_detailContext is RevisionCompare rc) + { rc.Cleanup(); } _detailContext = null; } - public void NavigateTo(string commitSHA) { + public void NavigateTo(string commitSHA) + { var commit = _commits.Find(x => x.SHA.StartsWith(commitSHA, StringComparison.Ordinal)); - if (commit != null) { + if (commit != null) + { AutoSelectedCommit = commit; - if (_detailContext is CommitDetail detail) { + if (_detailContext is CommitDetail detail) + { detail.Commit = commit; - } else { + } + else + { var commitDetail = new CommitDetail(_repo.FullPath); commitDetail.Commit = commit; DetailContext = commitDetail; @@ -87,30 +112,42 @@ namespace SourceGit.ViewModels { } } - public void Select(IList commits) { - if (commits.Count == 0) { + public void Select(IList commits) + { + if (commits.Count == 0) + { DetailContext = null; - } else if (commits.Count == 1) { + } + else if (commits.Count == 1) + { var commit = commits[0] as Models.Commit; AutoSelectedCommit = commit; - if (_detailContext is CommitDetail detail) { + if (_detailContext is CommitDetail detail) + { detail.Commit = commit; - } else { + } + else + { var commitDetail = new CommitDetail(_repo.FullPath); commitDetail.Commit = commit; DetailContext = commitDetail; } - } else if (commits.Count == 2) { + } + else if (commits.Count == 2) + { var end = commits[0] as Models.Commit; var start = commits[1] as Models.Commit; DetailContext = new RevisionCompare(_repo.FullPath, start, end); - } else { + } + else + { DetailContext = new CountSelectedCommits() { Count = commits.Count }; } } - public ContextMenu MakeContextMenu() { + public ContextMenu MakeContextMenu() + { var detail = _detailContext as CommitDetail; if (detail == null) return null; @@ -121,17 +158,26 @@ namespace SourceGit.ViewModels { var menu = new ContextMenu(); var tags = new List(); - if (commit.HasDecorators) { - foreach (var d in commit.Decorators) { - if (d.Type == Models.DecoratorType.CurrentBranchHead) { + if (commit.HasDecorators) + { + foreach (var d in commit.Decorators) + { + if (d.Type == Models.DecoratorType.CurrentBranchHead) + { FillCurrentBranchMenu(menu, current); - } else if (d.Type == Models.DecoratorType.LocalBranchHead) { + } + else if (d.Type == Models.DecoratorType.LocalBranchHead) + { var b = _repo.Branches.Find(x => x.IsLocal && d.Name == x.Name); FillOtherLocalBranchMenu(menu, b, current, commit.IsMerged); - } else if (d.Type == Models.DecoratorType.RemoteBranchHead) { + } + else if (d.Type == Models.DecoratorType.RemoteBranchHead) + { var b = _repo.Branches.Find(x => !x.IsLocal && d.Name == $"{x.Remote}/{x.Name}"); FillRemoteBranchMenu(menu, b, current, commit.IsMerged); - } else if (d.Type == Models.DecoratorType.Tag) { + } + else if (d.Type == Models.DecoratorType.Tag) + { var t = _repo.Tags.Find(x => x.Name == d.Name); if (t != null) tags.Add(t); } @@ -140,25 +186,31 @@ namespace SourceGit.ViewModels { if (menu.Items.Count > 0) menu.Items.Add(new MenuItem() { Header = "-" }); } - if (tags.Count > 0) { + if (tags.Count > 0) + { foreach (var tag in tags) FillTagMenu(menu, tag); menu.Items.Add(new MenuItem() { Header = "-" }); } - if (current.Head != commit.SHA) { + if (current.Head != commit.SHA) + { var reset = new MenuItem(); reset.Header = new Views.NameHighlightedTextBlock("CommitCM.Reset", current.Name); reset.Icon = App.CreateMenuIcon("Icons.Reset"); - reset.Click += (o, e) => { + reset.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Reset(_repo, current, commit)); e.Handled = true; }; menu.Items.Add(reset); - } else { + } + else + { var reword = new MenuItem(); reword.Header = App.Text("CommitCM.Reword"); reword.Icon = App.CreateMenuIcon("Icons.Edit"); - reword.Click += (o, e) => { + reword.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Reword(_repo, commit)); e.Handled = true; }; @@ -168,22 +220,26 @@ namespace SourceGit.ViewModels { squash.Header = App.Text("CommitCM.Squash"); squash.Icon = App.CreateMenuIcon("Icons.SquashIntoParent"); squash.IsEnabled = commit.Parents.Count == 1; - squash.Click += (o, e) => { - if (commit.Parents.Count == 1) { + squash.Click += (o, e) => + { + if (commit.Parents.Count == 1) + { var parent = _commits.Find(x => x.SHA == commit.Parents[0]); if (parent != null && PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Squash(_repo, commit, parent)); } - + e.Handled = true; }; menu.Items.Add(squash); } - if (!commit.IsMerged) { + if (!commit.IsMerged) + { var rebase = new MenuItem(); rebase.Header = new Views.NameHighlightedTextBlock("CommitCM.Rebase", current.Name); rebase.Icon = App.CreateMenuIcon("Icons.Rebase"); - rebase.Click += (o, e) => { + rebase.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Rebase(_repo, current, commit)); e.Handled = true; }; @@ -192,16 +248,20 @@ namespace SourceGit.ViewModels { var cherryPick = new MenuItem(); cherryPick.Header = App.Text("CommitCM.CherryPick"); cherryPick.Icon = App.CreateMenuIcon("Icons.CherryPick"); - cherryPick.Click += (o, e) => { + cherryPick.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CherryPick(_repo, commit)); e.Handled = true; }; menu.Items.Add(cherryPick); - } else { + } + else + { var revert = new MenuItem(); revert.Header = App.Text("CommitCM.Revert"); revert.Icon = App.CreateMenuIcon("Icons.Undo"); - revert.Click += (o, e) => { + revert.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Revert(_repo, commit)); e.Handled = true; }; @@ -213,7 +273,8 @@ namespace SourceGit.ViewModels { var createBranch = new MenuItem(); createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add"); createBranch.Header = App.Text("CreateBranch"); - createBranch.Click += (o, e) => { + createBranch.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateBranch(_repo, commit)); e.Handled = true; }; @@ -222,7 +283,8 @@ namespace SourceGit.ViewModels { var createTag = new MenuItem(); createTag.Icon = App.CreateMenuIcon("Icons.Tag.Add"); createTag.Header = App.Text("CreateTag"); - createTag.Click += (o, e) => { + createTag.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateTag(_repo, commit)); e.Handled = true; }; @@ -232,13 +294,15 @@ namespace SourceGit.ViewModels { var saveToPatch = new MenuItem(); saveToPatch.Icon = App.CreateMenuIcon("Icons.Diff"); saveToPatch.Header = App.Text("CommitCM.SaveAsPatch"); - saveToPatch.Click += async (_, e) => { + saveToPatch.Click += async (_, e) => + { var topLevel = App.GetTopLevel(); if (topLevel == null) return; var options = new FolderPickerOpenOptions() { AllowMultiple = false }; var selected = await topLevel.StorageProvider.OpenFolderPickerAsync(options); - if (selected.Count == 1) { + if (selected.Count == 1) + { var succ = new Commands.FormatPatch(_repo.FullPath, commit.SHA, selected[0].Path.LocalPath).Exec(); if (succ) App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess")); } @@ -250,7 +314,8 @@ namespace SourceGit.ViewModels { var archive = new MenuItem(); archive.Icon = App.CreateMenuIcon("Icons.Archive"); archive.Header = App.Text("Archive"); - archive.Click += (o, e) => { + archive.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Archive(_repo, commit)); e.Handled = true; }; @@ -260,7 +325,8 @@ namespace SourceGit.ViewModels { var copySHA = new MenuItem(); copySHA.Header = App.Text("CommitCM.CopySHA"); copySHA.Icon = App.CreateMenuIcon("Icons.Copy"); - copySHA.Click += (o, e) => { + copySHA.Click += (o, e) => + { App.CopyText(commit.SHA); e.Handled = true; }; @@ -268,19 +334,22 @@ namespace SourceGit.ViewModels { return menu; } - private void FillCurrentBranchMenu(ContextMenu menu, Models.Branch current) { + private void FillCurrentBranchMenu(ContextMenu menu, Models.Branch current) + { var submenu = new MenuItem(); submenu.Icon = App.CreateMenuIcon("Icons.Branch"); submenu.Header = current.Name; - if (!string.IsNullOrEmpty(current.Upstream)) { + if (!string.IsNullOrEmpty(current.Upstream)) + { var upstream = current.Upstream.Substring(13); var fastForward = new MenuItem(); fastForward.Header = new Views.NameHighlightedTextBlock("BranchCM.FastForward", upstream); fastForward.Icon = App.CreateMenuIcon("Icons.FastForward"); fastForward.IsEnabled = !string.IsNullOrEmpty(current.UpstreamTrackStatus) && current.UpstreamTrackStatus.IndexOf('↑') < 0; ; - fastForward.Click += (o, e) => { + fastForward.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new Merge(_repo, upstream, current.Name)); e.Handled = true; }; @@ -289,7 +358,8 @@ namespace SourceGit.ViewModels { var pull = new MenuItem(); pull.Header = new Views.NameHighlightedTextBlock("BranchCM.Pull", upstream); pull.Icon = App.CreateMenuIcon("Icons.Pull"); - pull.Click += (o, e) => { + pull.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Pull(_repo, null)); e.Handled = true; }; @@ -300,7 +370,8 @@ namespace SourceGit.ViewModels { push.Header = new Views.NameHighlightedTextBlock("BranchCM.Push", current.Name); push.Icon = App.CreateMenuIcon("Icons.Push"); push.IsEnabled = _repo.Remotes.Count > 0; - push.Click += (o, e) => { + push.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Push(_repo, current)); e.Handled = true; }; @@ -308,11 +379,13 @@ namespace SourceGit.ViewModels { submenu.Items.Add(new MenuItem() { Header = "-" }); var type = _repo.GitFlow.GetBranchType(current.Name); - if (type != Models.GitFlowBranchType.None) { + if (type != Models.GitFlowBranchType.None) + { var finish = new MenuItem(); finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", current.Name); finish.Icon = App.CreateMenuIcon("Icons.Flow"); - finish.Click += (o, e) => { + finish.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new GitFlowFinish(_repo, current, type)); e.Handled = true; }; @@ -323,7 +396,8 @@ namespace SourceGit.ViewModels { var rename = new MenuItem(); rename.Header = new Views.NameHighlightedTextBlock("BranchCM.Rename", current.Name); rename.Icon = App.CreateMenuIcon("Icons.Rename"); - rename.Click += (o, e) => { + rename.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new RenameBranch(_repo, current)); e.Handled = true; }; @@ -332,7 +406,8 @@ namespace SourceGit.ViewModels { menu.Items.Add(submenu); } - private void FillOtherLocalBranchMenu(ContextMenu menu, Models.Branch branch, Models.Branch current, bool merged) { + private void FillOtherLocalBranchMenu(ContextMenu menu, Models.Branch branch, Models.Branch current, bool merged) + { var submenu = new MenuItem(); submenu.Icon = App.CreateMenuIcon("Icons.Branch"); submenu.Header = branch.Name; @@ -340,7 +415,8 @@ namespace SourceGit.ViewModels { var checkout = new MenuItem(); checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", branch.Name); checkout.Icon = App.CreateMenuIcon("Icons.Check"); - checkout.Click += (o, e) => { + checkout.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new Checkout(_repo, branch.Name)); e.Handled = true; }; @@ -350,7 +426,8 @@ namespace SourceGit.ViewModels { merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", branch.Name, current.Name); merge.Icon = App.CreateMenuIcon("Icons.Merge"); merge.IsEnabled = !merged; - merge.Click += (o, e) => { + merge.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Merge(_repo, branch.Name, current.Name)); e.Handled = true; }; @@ -358,11 +435,13 @@ namespace SourceGit.ViewModels { submenu.Items.Add(new MenuItem() { Header = "-" }); var type = _repo.GitFlow.GetBranchType(branch.Name); - if (type != Models.GitFlowBranchType.None) { + if (type != Models.GitFlowBranchType.None) + { var finish = new MenuItem(); finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name); finish.Icon = App.CreateMenuIcon("Icons.Flow"); - finish.Click += (o, e) => { + finish.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new GitFlowFinish(_repo, branch, type)); e.Handled = true; }; @@ -373,7 +452,8 @@ namespace SourceGit.ViewModels { var rename = new MenuItem(); rename.Header = new Views.NameHighlightedTextBlock("BranchCM.Rename", branch.Name); rename.Icon = App.CreateMenuIcon("Icons.Rename"); - rename.Click += (o, e) => { + rename.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new RenameBranch(_repo, branch)); e.Handled = true; }; @@ -382,7 +462,8 @@ namespace SourceGit.ViewModels { var delete = new MenuItem(); delete.Header = new Views.NameHighlightedTextBlock("BranchCM.Delete", branch.Name); delete.Icon = App.CreateMenuIcon("Icons.Clear"); - delete.Click += (o, e) => { + delete.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteBranch(_repo, branch)); e.Handled = true; }; @@ -391,7 +472,8 @@ namespace SourceGit.ViewModels { menu.Items.Add(submenu); } - private void FillRemoteBranchMenu(ContextMenu menu, Models.Branch branch, Models.Branch current, bool merged) { + private void FillRemoteBranchMenu(ContextMenu menu, Models.Branch branch, Models.Branch current, bool merged) + { var name = $"{branch.Remote}/{branch.Name}"; var submenu = new MenuItem(); @@ -401,9 +483,12 @@ namespace SourceGit.ViewModels { var checkout = new MenuItem(); checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", name); checkout.Icon = App.CreateMenuIcon("Icons.Check"); - checkout.Click += (o, e) => { - foreach (var b in _repo.Branches) { - if (b.IsLocal && b.Upstream == branch.FullName) { + checkout.Click += (o, e) => + { + foreach (var b in _repo.Branches) + { + if (b.IsLocal && b.Upstream == branch.FullName) + { if (b.IsCurrent) return; if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new Checkout(_repo, b.Name)); return; @@ -419,7 +504,8 @@ namespace SourceGit.ViewModels { merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", name, current.Name); merge.Icon = App.CreateMenuIcon("Icons.Merge"); merge.IsEnabled = !merged; - merge.Click += (o, e) => { + merge.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Merge(_repo, name, current.Name)); e.Handled = true; }; @@ -430,7 +516,8 @@ namespace SourceGit.ViewModels { var delete = new MenuItem(); delete.Header = new Views.NameHighlightedTextBlock("BranchCM.Delete", name); delete.Icon = App.CreateMenuIcon("Icons.Clear"); - delete.Click += (o, e) => { + delete.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteBranch(_repo, branch)); e.Handled = true; }; @@ -439,7 +526,8 @@ namespace SourceGit.ViewModels { menu.Items.Add(submenu); } - private void FillTagMenu(ContextMenu menu, Models.Tag tag) { + private void FillTagMenu(ContextMenu menu, Models.Tag tag) + { var submenu = new MenuItem(); submenu.Header = tag.Name; submenu.Icon = App.CreateMenuIcon("Icons.Tag"); @@ -449,7 +537,8 @@ namespace SourceGit.ViewModels { push.Header = new Views.NameHighlightedTextBlock("TagCM.Push", tag.Name); push.Icon = App.CreateMenuIcon("Icons.Push"); push.IsEnabled = _repo.Remotes.Count > 0; - push.Click += (o, e) => { + push.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new PushTag(_repo, tag)); e.Handled = true; }; @@ -458,7 +547,8 @@ namespace SourceGit.ViewModels { var delete = new MenuItem(); delete.Header = new Views.NameHighlightedTextBlock("TagCM.Delete", tag.Name); delete.Icon = App.CreateMenuIcon("Icons.Clear"); - delete.Click += (o, e) => { + delete.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteTag(_repo, tag)); e.Handled = true; }; @@ -468,11 +558,11 @@ namespace SourceGit.ViewModels { } private Repository _repo = null; - private double _dataGridRowHeight = 28; + private readonly double _dataGridRowHeight = 28; private bool _isLoading = true; private List _commits = new List(); private Models.CommitGraph _graph = null; private Models.Commit _autoSelectedCommit = null; private object _detailContext = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Init.cs b/src/ViewModels/Init.cs index 985453a0..6aaf6cd0 100644 --- a/src/ViewModels/Init.cs +++ b/src/ViewModels/Init.cs @@ -1,30 +1,38 @@ using System.IO; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Init : Popup { - public string TargetPath { +namespace SourceGit.ViewModels +{ + public class Init : Popup + { + public string TargetPath + { get => _targetPath; set => SetProperty(ref _targetPath, value); } - public Init(string path) { + public Init(string path) + { TargetPath = path; View = new Views.Init() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { ProgressDescription = $"Initialize git repository at: '{_targetPath}'"; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Init(HostPageId, _targetPath).Exec(); if (!succ) return false; var gitDir = Path.GetFullPath(Path.Combine(_targetPath, ".git")); - - CallUIThread(() => { + + CallUIThread(() => + { var repo = Preference.AddRepository(_targetPath, gitDir); - var node = new RepositoryNode() { + var node = new RepositoryNode() + { Id = repo.FullPath, Name = Path.GetFileName(repo.FullPath), Bookmark = 0, @@ -39,4 +47,4 @@ namespace SourceGit.ViewModels { private string _targetPath; } -} +} \ No newline at end of file diff --git a/src/ViewModels/InitGitFlow.cs b/src/ViewModels/InitGitFlow.cs index 7a499448..18293262 100644 --- a/src/ViewModels/InitGitFlow.cs +++ b/src/ViewModels/InitGitFlow.cs @@ -2,16 +2,19 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public partial class InitGitFlow : Popup { - +namespace SourceGit.ViewModels +{ + public partial class InitGitFlow : Popup + { + [GeneratedRegex(@"^[\w\-/\.]+$")] private static partial Regex TAG_PREFIX(); [Required(ErrorMessage = "Master branch name is required!!!")] [RegularExpression(@"^[\w\-/\.]+$", ErrorMessage = "Bad branch name format!")] [CustomValidation(typeof(InitGitFlow), nameof(ValidateBaseBranch))] - public string Master { + public string Master + { get => _master; set => SetProperty(ref _master, value, true); } @@ -19,66 +22,79 @@ namespace SourceGit.ViewModels { [Required(ErrorMessage = "Develop branch name is required!!!")] [RegularExpression(@"^[\w\-/\.]+$", ErrorMessage = "Bad branch name format!")] [CustomValidation(typeof(InitGitFlow), nameof(ValidateBaseBranch))] - public string Develop { + public string Develop + { get => _develop; set => SetProperty(ref _develop, value, true); } [Required(ErrorMessage = "Feature prefix is required!!!")] [RegularExpression(@"^[\w\-\.]+/$", ErrorMessage = "Bad feature prefix format!")] - public string FeturePrefix { + public string FeturePrefix + { get => _featurePrefix; set => SetProperty(ref _featurePrefix, value, true); } [Required(ErrorMessage = "Release prefix is required!!!")] [RegularExpression(@"^[\w\-\.]+/$", ErrorMessage = "Bad release prefix format!")] - public string ReleasePrefix { + public string ReleasePrefix + { get => _releasePrefix; set => SetProperty(ref _releasePrefix, value, true); } [Required(ErrorMessage = "Hotfix prefix is required!!!")] [RegularExpression(@"^[\w\-\.]+/$", ErrorMessage = "Bad hotfix prefix format!")] - public string HotfixPrefix { + public string HotfixPrefix + { get => _hotfixPrefix; set => SetProperty(ref _hotfixPrefix, value, true); } [CustomValidation(typeof(InitGitFlow), nameof(ValidateTagPrefix))] - public string TagPrefix { + public string TagPrefix + { get => _tagPrefix; set => SetProperty(ref _tagPrefix, value, true); } - public InitGitFlow(Repository repo) { + public InitGitFlow(Repository repo) + { _repo = repo; View = new Views.InitGitFlow() { DataContext = this }; } - public static ValidationResult ValidateBaseBranch(string _, ValidationContext ctx) { - if (ctx.ObjectInstance is InitGitFlow initializer) { + public static ValidationResult ValidateBaseBranch(string _, ValidationContext ctx) + { + if (ctx.ObjectInstance is InitGitFlow initializer) + { if (initializer._master == initializer._develop) return new ValidationResult("Develop branch has the same name with master branch!"); } return ValidationResult.Success; } - public static ValidationResult ValidateTagPrefix(string tagPrefix, ValidationContext ctx) { - if (!string.IsNullOrWhiteSpace(tagPrefix) && !TAG_PREFIX().IsMatch(tagPrefix)) { + public static ValidationResult ValidateTagPrefix(string tagPrefix, ValidationContext ctx) + { + if (!string.IsNullOrWhiteSpace(tagPrefix) && !TAG_PREFIX().IsMatch(tagPrefix)) + { return new ValidationResult("Bad tag prefix format!"); } return ValidationResult.Success; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = "Init git-flow ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.GitFlow(_repo.FullPath).Init(_repo.Branches, _master, _develop, _featurePrefix, _releasePrefix, _hotfixPrefix, _tagPrefix); - if (succ) { + if (succ) + { _repo.GitFlow.Feature = _featurePrefix; _repo.GitFlow.Release = _releasePrefix; _repo.GitFlow.Hotfix = _hotfixPrefix; @@ -89,7 +105,7 @@ namespace SourceGit.ViewModels { }); } - private Repository _repo = null; + private readonly Repository _repo = null; private string _master = "master"; private string _develop = "develop"; private string _featurePrefix = "feature/"; @@ -97,4 +113,4 @@ namespace SourceGit.ViewModels { private string _hotfixPrefix = "hotfix/"; private string _tagPrefix = string.Empty; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Launcher.cs b/src/ViewModels/Launcher.cs index c2dedc50..ebd4725c 100644 --- a/src/ViewModels/Launcher.cs +++ b/src/ViewModels/Launcher.cs @@ -1,30 +1,41 @@ -using Avalonia.Collections; -using CommunityToolkit.Mvvm.ComponentModel; -using System; +using System; using System.IO; -namespace SourceGit.ViewModels { - public class Launcher : ObservableObject { - public AvaloniaList Pages { +using Avalonia.Collections; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class Launcher : ObservableObject + { + public AvaloniaList Pages + { get; private set; } - public LauncherPage ActivePage { + public LauncherPage ActivePage + { get => _activePage; - set { - if (SetProperty(ref _activePage, value)) { + set + { + if (SetProperty(ref _activePage, value)) + { PopupHost.Active = value; } } } - public Launcher() { + public Launcher() + { Pages = new AvaloniaList(); AddNewTab(); - if (Preference.Instance.RestoreTabs) { - foreach (var id in Preference.Instance.OpenedTabs) { + if (Preference.Instance.RestoreTabs) + { + foreach (var id in Preference.Instance.OpenedTabs) + { var node = Preference.FindNode(id); if (node == null) continue; @@ -32,17 +43,21 @@ namespace SourceGit.ViewModels { } var lastActiveIdx = Preference.Instance.LastActiveTabIdx; - if (lastActiveIdx >= 0 && lastActiveIdx < Pages.Count) { + if (lastActiveIdx >= 0 && lastActiveIdx < Pages.Count) + { ActivePage = Pages[lastActiveIdx]; } } } - public void Quit() { + public void Quit() + { Preference.Instance.OpenedTabs.Clear(); - if (Preference.Instance.RestoreTabs) { - foreach (var page in Pages) { + if (Preference.Instance.RestoreTabs) + { + foreach (var page in Pages) + { if (page.Node.IsRepository) Preference.Instance.OpenedTabs.Add(page.Node.Id); } } @@ -51,20 +66,23 @@ namespace SourceGit.ViewModels { Preference.Save(); } - public void AddNewTab() { + public void AddNewTab() + { var page = new LauncherPage(); Pages.Add(page); ActivePage = page; } - public void MoveTab(LauncherPage from, LauncherPage to) { + public void MoveTab(LauncherPage from, LauncherPage to) + { var fromIdx = Pages.IndexOf(from); var toIdx = Pages.IndexOf(to); Pages.Move(fromIdx, toIdx); ActivePage = from; } - public void GotoNextTab() { + public void GotoNextTab() + { if (Pages.Count == 1) return; var activeIdx = Pages.IndexOf(_activePage); @@ -72,8 +90,10 @@ namespace SourceGit.ViewModels { ActivePage = Pages[nextIdx]; } - public void CloseTab(object param) { - if (Pages.Count == 1) { + public void CloseTab(object param) + { + if (Pages.Count == 1) + { App.Quit(); return; } @@ -83,21 +103,29 @@ namespace SourceGit.ViewModels { var removeIdx = Pages.IndexOf(page); var activeIdx = Pages.IndexOf(_activePage); - if (removeIdx == activeIdx) { - if (removeIdx == Pages.Count - 1) { + if (removeIdx == activeIdx) + { + if (removeIdx == Pages.Count - 1) + { ActivePage = Pages[removeIdx - 1]; - } else { + } + else + { ActivePage = Pages[removeIdx + 1]; } CloseRepositoryInTab(page); Pages.RemoveAt(removeIdx); OnPropertyChanged(nameof(Pages)); - } else if (removeIdx + 1 == activeIdx) { + } + else if (removeIdx + 1 == activeIdx) + { CloseRepositoryInTab(page); Pages.RemoveAt(removeIdx); OnPropertyChanged(nameof(Pages)); - } else { + } + else + { CloseRepositoryInTab(page); Pages.RemoveAt(removeIdx); } @@ -105,7 +133,8 @@ namespace SourceGit.ViewModels { GC.Collect(); } - public void CloseOtherTabs(object param) { + public void CloseOtherTabs(object param) + { if (Pages.Count == 1) return; var page = param as LauncherPage; @@ -113,7 +142,8 @@ namespace SourceGit.ViewModels { ActivePage = page; - foreach (var one in Pages) { + foreach (var one in Pages) + { if (one.Node.Id != page.Node.Id) CloseRepositoryInTab(one); } @@ -123,17 +153,20 @@ namespace SourceGit.ViewModels { GC.Collect(); } - public void CloseRightTabs(object param) { + public void CloseRightTabs(object param) + { LauncherPage page = param as LauncherPage; if (page == null) page = _activePage; var endIdx = Pages.IndexOf(page); var activeIdx = Pages.IndexOf(_activePage); - if (endIdx < activeIdx) { + if (endIdx < activeIdx) + { ActivePage = page; } - for (var i = Pages.Count - 1; i > endIdx; i--) { + for (var i = Pages.Count - 1; i > endIdx; i--) + { CloseRepositoryInTab(Pages[i]); Pages.Remove(Pages[i]); } @@ -141,16 +174,20 @@ namespace SourceGit.ViewModels { GC.Collect(); } - public void OpenRepositoryInTab(RepositoryNode node, LauncherPage page) { - foreach (var one in Pages) { - if (one.Node.Id == node.Id) { + public void OpenRepositoryInTab(RepositoryNode node, LauncherPage page) + { + foreach (var one in Pages) + { + if (one.Node.Id == node.Id) + { ActivePage = one; return; } } var repo = Preference.FindRepository(node.Id); - if (repo == null || !Path.Exists(repo.FullPath)) { + if (repo == null || !Path.Exists(repo.FullPath)) + { var ctx = page == null ? ActivePage.Node.Id : page.Node.Id; App.RaiseException(ctx, "Repository does NOT exists any more. Please remove it."); return; @@ -159,16 +196,22 @@ namespace SourceGit.ViewModels { repo.Open(); Commands.AutoFetch.AddRepository(repo.FullPath); - if (page == null) { - if (ActivePage == null || ActivePage.Node.IsRepository) { + if (page == null) + { + if (ActivePage == null || ActivePage.Node.IsRepository) + { page = new LauncherPage(node, repo); Pages.Add(page); - } else { + } + else + { page = ActivePage; page.Node = node; page.Data = repo; } - } else { + } + else + { page.Node = node; page.Data = repo; } @@ -176,8 +219,10 @@ namespace SourceGit.ViewModels { ActivePage = page; } - private void CloseRepositoryInTab(LauncherPage page) { - if (page.Data is Repository repo) { + private void CloseRepositoryInTab(LauncherPage page) + { + if (page.Data is Repository repo) + { Commands.AutoFetch.RemoveRepository(repo.FullPath); repo.Close(); } @@ -187,4 +232,4 @@ namespace SourceGit.ViewModels { private LauncherPage _activePage = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/LauncherPage.cs b/src/ViewModels/LauncherPage.cs index 4be607f5..5ba70d69 100644 --- a/src/ViewModels/LauncherPage.cs +++ b/src/ViewModels/LauncherPage.cs @@ -1,25 +1,33 @@ -using Avalonia.Collections; -using System; +using System; -namespace SourceGit.ViewModels { - public class LauncherPage : PopupHost { - public RepositoryNode Node { +using Avalonia.Collections; + +namespace SourceGit.ViewModels +{ + public class LauncherPage : PopupHost + { + public RepositoryNode Node + { get => _node; set => SetProperty(ref _node, value); } - public object Data { + public object Data + { get => _data; set => SetProperty(ref _data, value); } - public AvaloniaList Notifications { + public AvaloniaList Notifications + { get; set; } = new AvaloniaList(); - public LauncherPage() { - _node = new RepositoryNode() { + public LauncherPage() + { + _node = new RepositoryNode() + { Id = Guid.NewGuid().ToString(), Name = "WelcomePage", Bookmark = 0, @@ -28,21 +36,26 @@ namespace SourceGit.ViewModels { _data = new Welcome(); } - public LauncherPage(RepositoryNode node, Repository repo) { + public LauncherPage(RepositoryNode node, Repository repo) + { _node = node; _data = repo; } - public override string GetId() { + public override string GetId() + { return _node.Id; } - public void CopyPath() { + public void CopyPath() + { if (_node.IsRepository) App.CopyText(_node.Id); } - public void DismissNotification(object param) { - if (param is Models.Notification notice) { + public void DismissNotification(object param) + { + if (param is Models.Notification notice) + { Notifications.Remove(notice); } } @@ -50,4 +63,4 @@ namespace SourceGit.ViewModels { private RepositoryNode _node = null; private object _data = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Merge.cs b/src/ViewModels/Merge.cs index 3f68796a..935fa1cb 100644 --- a/src/ViewModels/Merge.cs +++ b/src/ViewModels/Merge.cs @@ -1,41 +1,50 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class MergeMode { +namespace SourceGit.ViewModels +{ + public class MergeMode + { public string Name { get; set; } public string Desc { get; set; } public string Arg { get; set; } - public MergeMode(string n, string d, string a) { + public MergeMode(string n, string d, string a) + { Name = n; Desc = d; Arg = a; } } - public class Merge : Popup { - public string Source { + public class Merge : Popup + { + public string Source + { get; private set; } - public string Into { + public string Into + { get; private set; } - public List Modes { + public List Modes + { get; private set; } - public MergeMode SelectedMode { + public MergeMode SelectedMode + { get; set; } - public Merge(Repository repo, string source, string into) { + public Merge(Repository repo, string source, string into) + { _repo = repo; Source = source; Into = into; @@ -49,17 +58,19 @@ namespace SourceGit.ViewModels { View = new Views.Merge() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = $"Merging '{Source}' into '{Into}' ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Merge(_repo.FullPath, Source, SelectedMode.Arg, SetProgressDescription).Exec(); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } - private Repository _repo = null; + private readonly Repository _repo = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Popup.cs b/src/ViewModels/Popup.cs index 52e99c84..f61cef33 100644 --- a/src/ViewModels/Popup.cs +++ b/src/ViewModels/Popup.cs @@ -1,51 +1,63 @@ -using Avalonia.Threading; -using CommunityToolkit.Mvvm.ComponentModel; -using System; +using System; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Popup : ObservableValidator { - public string HostPageId { +using Avalonia.Threading; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class Popup : ObservableValidator + { + public string HostPageId + { get; set; } - public object View { + public object View + { get; set; } - public bool InProgress { + public bool InProgress + { get => _inProgress; set => SetProperty(ref _inProgress, value); } - public string ProgressDescription { + public string ProgressDescription + { get => _progressDescription; set => SetProperty(ref _progressDescription, value); } [UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode")] - public bool Check() { + public bool Check() + { if (HasErrors) return false; ValidateAllProperties(); return !HasErrors; } - public virtual Task Sure() { + public virtual Task Sure() + { return null; } - protected void CallUIThread(Action action) { + protected void CallUIThread(Action action) + { Dispatcher.UIThread.Invoke(action); } - protected void SetProgressDescription(string description) { + protected void SetProgressDescription(string description) + { CallUIThread(() => ProgressDescription = description); } private bool _inProgress = false; private string _progressDescription = string.Empty; } -} +} \ No newline at end of file diff --git a/src/ViewModels/PopupHost.cs b/src/ViewModels/PopupHost.cs index 88f4c0c8..18be596b 100644 --- a/src/ViewModels/PopupHost.cs +++ b/src/ViewModels/PopupHost.cs @@ -1,57 +1,74 @@ using CommunityToolkit.Mvvm.ComponentModel; -namespace SourceGit.ViewModels { - public class PopupHost : ObservableObject { - public static PopupHost Active { +namespace SourceGit.ViewModels +{ + public class PopupHost : ObservableObject + { + public static PopupHost Active + { get; set; } = null; - public Popup Popup { + public Popup Popup + { get => _popup; set => SetProperty(ref _popup, value); } - public static bool CanCreatePopup() { + public static bool CanCreatePopup() + { return Active != null && (Active._popup == null || !Active._popup.InProgress); } - public static void ShowPopup(Popup popup) { + public static void ShowPopup(Popup popup) + { popup.HostPageId = Active.GetId(); Active.Popup = popup; } - public static void ShowAndStartPopup(Popup popup) { + public static void ShowAndStartPopup(Popup popup) + { var dumpPage = Active; popup.HostPageId = dumpPage.GetId(); dumpPage.Popup = popup; dumpPage.ProcessPopup(); } - public virtual string GetId() { + public virtual string GetId() + { return string.Empty; } - public async void ProcessPopup() { - if (_popup != null) { + public async void ProcessPopup() + { + if (_popup != null) + { if (!_popup.Check()) return; _popup.InProgress = true; var task = _popup.Sure(); - if (task != null) { + if (task != null) + { var finished = await task; - if (finished) { + if (finished) + { Popup = null; - } else { + } + else + { _popup.InProgress = false; } - } else { + } + else + { Popup = null; } } } - public void CancelPopup() { + public void CancelPopup() + { if (_popup == null) return; if (_popup.InProgress) return; Popup = null; @@ -59,4 +76,4 @@ namespace SourceGit.ViewModels { private Popup _popup = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Preference.cs b/src/ViewModels/Preference.cs index e9361e73..3d7d94e6 100644 --- a/src/ViewModels/Preference.cs +++ b/src/ViewModels/Preference.cs @@ -1,23 +1,36 @@ -using Avalonia.Collections; -using CommunityToolkit.Mvvm.ComponentModel; using System; using System.Collections.Generic; using System.IO; using System.Text.Json; using System.Text.Json.Serialization; -namespace SourceGit.ViewModels { - public class Preference : ObservableObject { +using Avalonia.Collections; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class Preference : ObservableObject + { [JsonIgnore] - public static Preference Instance { - get { - if (_instance == null) { - if (!File.Exists(_savePath)) { + public static Preference Instance + { + get + { + if (_instance == null) + { + if (!File.Exists(_savePath)) + { _instance = new Preference(); - } else { - try { + } + else + { + try + { _instance = JsonSerializer.Deserialize(File.ReadAllText(_savePath), JsonSerializationCodeGen.Default.Preference); - } catch { + } + catch + { _instance = new Preference(); } } @@ -25,7 +38,8 @@ namespace SourceGit.ViewModels { _instance.Repositories.RemoveAll(x => !Directory.Exists(x.FullPath)); - if (!_instance.IsGitConfigured) { + if (!_instance.IsGitConfigured) + { _instance.GitInstallPath = Native.OS.FindGitExecutable(); } @@ -33,109 +47,137 @@ namespace SourceGit.ViewModels { } } - public string Locale { + public string Locale + { get => _locale; - set { - if (SetProperty(ref _locale, value)) { + set + { + if (SetProperty(ref _locale, value)) + { App.SetLocale(value); } } } - public string Theme { + public string Theme + { get => _theme; - set { - if (SetProperty(ref _theme, value)) { + set + { + if (SetProperty(ref _theme, value)) + { App.SetTheme(value); } } } - public string AvatarServer { + public string AvatarServer + { get => Models.AvatarManager.SelectedServer; - set { - if (Models.AvatarManager.SelectedServer != value) { + set + { + if (Models.AvatarManager.SelectedServer != value) + { Models.AvatarManager.SelectedServer = value; OnPropertyChanged(nameof(AvatarServer)); } } } - public int MaxHistoryCommits { + public int MaxHistoryCommits + { get => _maxHistoryCommits; set => SetProperty(ref _maxHistoryCommits, value); } - public bool RestoreTabs { + public bool RestoreTabs + { get => _restoreTabs; set => SetProperty(ref _restoreTabs, value); } - public bool UseFixedTabWidth { + public bool UseFixedTabWidth + { get => _useFixedTabWidth; set => SetProperty(ref _useFixedTabWidth, value); } - public bool UseTwoColumnsLayoutInHistories { + public bool UseTwoColumnsLayoutInHistories + { get => _useTwoColumnsLayoutInHistories; set => SetProperty(ref _useTwoColumnsLayoutInHistories, value); } - public bool UseCombinedTextDiff { + public bool UseCombinedTextDiff + { get => _useCombinedTextDiff; set => SetProperty(ref _useCombinedTextDiff, value); } - public Models.ChangeViewMode UnstagedChangeViewMode { + public Models.ChangeViewMode UnstagedChangeViewMode + { get => _unstagedChangeViewMode; set => SetProperty(ref _unstagedChangeViewMode, value); } - public Models.ChangeViewMode StagedChangeViewMode { + public Models.ChangeViewMode StagedChangeViewMode + { get => _stagedChangeViewMode; set => SetProperty(ref _stagedChangeViewMode, value); } - public Models.ChangeViewMode CommitChangeViewMode { + public Models.ChangeViewMode CommitChangeViewMode + { get => _commitChangeViewMode; set => SetProperty(ref _commitChangeViewMode, value); } [JsonIgnore] - public bool IsGitConfigured { + public bool IsGitConfigured + { get => !string.IsNullOrEmpty(GitInstallPath) && File.Exists(GitInstallPath); } - public string GitInstallPath { + public string GitInstallPath + { get => Native.OS.GitInstallPath; - set { - if (Native.OS.GitInstallPath != value) { + set + { + if (Native.OS.GitInstallPath != value) + { Native.OS.GitInstallPath = value; OnPropertyChanged(nameof(GitInstallPath)); } } } - public string GitDefaultCloneDir { + public string GitDefaultCloneDir + { get => _gitDefaultCloneDir; set => SetProperty(ref _gitDefaultCloneDir, value); } - public bool GitAutoFetch { + public bool GitAutoFetch + { get => Commands.AutoFetch.IsEnabled; - set { - if (Commands.AutoFetch.IsEnabled != value) { + set + { + if (Commands.AutoFetch.IsEnabled != value) + { Commands.AutoFetch.IsEnabled = value; OnPropertyChanged(nameof(GitAutoFetch)); } } } - public int ExternalMergeToolType { + public int ExternalMergeToolType + { get => _externalMergeToolType; - set { + set + { var changed = SetProperty(ref _externalMergeToolType, value); - if (changed && !OperatingSystem.IsWindows() && value > 0 && value < Models.ExternalMergeTools.Supported.Count) { + if (changed && !OperatingSystem.IsWindows() && value > 0 && value < Models.ExternalMergeTools.Supported.Count) + { var tool = Models.ExternalMergeTools.Supported[value]; if (File.Exists(tool.Exec)) ExternalMergeToolPath = tool.Exec; else ExternalMergeToolPath = string.Empty; @@ -143,65 +185,80 @@ namespace SourceGit.ViewModels { } } - public string ExternalMergeToolPath { + public string ExternalMergeToolPath + { get => _externalMergeToolPath; set => SetProperty(ref _externalMergeToolPath, value); } - public string ExternalMergeToolCmd { + public string ExternalMergeToolCmd + { get => _externalMergeToolCmd; set => SetProperty(ref _externalMergeToolCmd, value); } - public string ExternalMergeToolDiffCmd { + public string ExternalMergeToolDiffCmd + { get => _externalMergeToolDiffCmd; set => SetProperty(ref _externalMergeToolDiffCmd, value); } - public List Repositories { + public List Repositories + { get; set; } = new List(); - public AvaloniaList RepositoryNodes { + public AvaloniaList RepositoryNodes + { get => _repositoryNodes; set => SetProperty(ref _repositoryNodes, value); } - public List OpenedTabs { + public List OpenedTabs + { get; set; } = new List(); - public int LastActiveTabIdx { + public int LastActiveTabIdx + { get; set; } = 0; - public static void AddNode(RepositoryNode node, RepositoryNode to = null) { + public static void AddNode(RepositoryNode node, RepositoryNode to = null) + { var collection = to == null ? _instance._repositoryNodes : to.SubNodes; var list = new List(); list.AddRange(collection); list.Add(node); - list.Sort((l, r) => { - if (l.IsRepository != r.IsRepository) { + list.Sort((l, r) => + { + if (l.IsRepository != r.IsRepository) + { return l.IsRepository ? 1 : -1; - } else { + } + else + { return l.Name.CompareTo(r.Name); } }); collection.Clear(); - foreach (var one in list) { + foreach (var one in list) + { collection.Add(one); } } - public static RepositoryNode FindNode(string id) { + public static RepositoryNode FindNode(string id) + { return FindNodeRecursive(id, _instance.RepositoryNodes); } - public static void MoveNode(RepositoryNode node, RepositoryNode to = null) { + public static void MoveNode(RepositoryNode node, RepositoryNode to = null) + { if (to == null && _instance._repositoryNodes.Contains(node)) return; if (to != null && to.SubNodes.Contains(node)) return; @@ -209,26 +266,32 @@ namespace SourceGit.ViewModels { AddNode(node, to); } - public static void RemoveNode(RepositoryNode node) { + public static void RemoveNode(RepositoryNode node) + { RemoveNodeRecursive(node, _instance._repositoryNodes); } - public static Repository FindRepository(string path) { - foreach (var repo in _instance.Repositories) { + public static Repository FindRepository(string path) + { + foreach (var repo in _instance.Repositories) + { if (repo.FullPath == path) return repo; } return null; } - public static Repository AddRepository(string rootDir, string gitDir) { + public static Repository AddRepository(string rootDir, string gitDir) + { var normalized = rootDir.Replace('\\', '/'); var repo = FindRepository(normalized); - if (repo != null) { + if (repo != null) + { repo.GitDir = gitDir; return repo; } - repo = new Repository() { + repo = new Repository() + { FullPath = normalized, GitDir = gitDir }; @@ -237,7 +300,8 @@ namespace SourceGit.ViewModels { return repo; } - public static void Save() { + public static void Save() + { var dir = Path.GetDirectoryName(_savePath); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); @@ -245,8 +309,10 @@ namespace SourceGit.ViewModels { File.WriteAllText(_savePath, data); } - private static RepositoryNode FindNodeRecursive(string id, AvaloniaList collection) { - foreach (var node in collection) { + private static RepositoryNode FindNodeRecursive(string id, AvaloniaList collection) + { + foreach (var node in collection) + { if (node.Id == id) return node; var sub = FindNodeRecursive(id, node.SubNodes); @@ -256,13 +322,16 @@ namespace SourceGit.ViewModels { return null; } - private static bool RemoveNodeRecursive(RepositoryNode node, AvaloniaList collection) { - if (collection.Contains(node)) { + private static bool RemoveNodeRecursive(RepositoryNode node, AvaloniaList collection) + { + if (collection.Contains(node)) + { collection.Remove(node); return true; } - foreach (RepositoryNode one in collection) { + foreach (RepositoryNode one in collection) + { if (RemoveNodeRecursive(node, one.SubNodes)) return true; } diff --git a/src/ViewModels/PruneRemote.cs b/src/ViewModels/PruneRemote.cs index c256281b..9b950b9f 100644 --- a/src/ViewModels/PruneRemote.cs +++ b/src/ViewModels/PruneRemote.cs @@ -1,29 +1,35 @@ using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class PruneRemote : Popup { - public Models.Remote Remote { +namespace SourceGit.ViewModels +{ + public class PruneRemote : Popup + { + public Models.Remote Remote + { get; private set; } - public PruneRemote(Repository repo, Models.Remote remote) { + public PruneRemote(Repository repo, Models.Remote remote) + { _repo = repo; Remote = remote; View = new Views.PruneRemote() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = "Run `prune` on remote ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Remote(_repo.FullPath).Prune(Remote.Name); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } - private Repository _repo = null; + private readonly Repository _repo = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Pull.cs b/src/ViewModels/Pull.cs index 881b779a..df0153cd 100644 --- a/src/ViewModels/Pull.cs +++ b/src/ViewModels/Pull.cs @@ -2,22 +2,29 @@ using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Pull : Popup { +namespace SourceGit.ViewModels +{ + public class Pull : Popup + { public List Remotes => _repo.Remotes; public Models.Branch Current => _current; - public bool HasSpecifiedRemoteBranch { + public bool HasSpecifiedRemoteBranch + { get; private set; } - public Models.Remote SelectedRemote { + public Models.Remote SelectedRemote + { get => _selectedRemote; - set { - if (SetProperty(ref _selectedRemote, value)) { + set + { + if (SetProperty(ref _selectedRemote, value)) + { var branches = new List(); - foreach (var branch in _repo.Branches) { + foreach (var branch in _repo.Branches) + { if (branch.Remote == value.Name) branches.Add(branch); } RemoteBranches = branches; @@ -26,81 +33,100 @@ namespace SourceGit.ViewModels { } } - public List RemoteBranches { + public List RemoteBranches + { get => _remoteBranches; private set => SetProperty(ref _remoteBranches, value); } [Required(ErrorMessage = "Remote branch to pull is required!!!")] - public Models.Branch SelectedBranch { + public Models.Branch SelectedBranch + { get => _selectedBranch; set => SetProperty(ref _selectedBranch, value); } - public bool UseRebase { + public bool UseRebase + { get; set; } = true; - public bool AutoStash { + public bool AutoStash + { get; set; } = true; - public Pull(Repository repo, Models.Branch specifiedRemoteBranch) { + public Pull(Repository repo, Models.Branch specifiedRemoteBranch) + { _repo = repo; _current = repo.Branches.Find(x => x.IsCurrent); - - if (specifiedRemoteBranch != null) { + + if (specifiedRemoteBranch != null) + { _selectedRemote = repo.Remotes.Find(x => x.Name == specifiedRemoteBranch.Remote); _selectedBranch = specifiedRemoteBranch; HasSpecifiedRemoteBranch = true; - } else { - if (!string.IsNullOrEmpty(_current.Upstream)) { - foreach (var branch in repo.Branches) { - if (!branch.IsLocal && _current.Upstream == branch.FullName) { + } + else + { + if (!string.IsNullOrEmpty(_current.Upstream)) + { + foreach (var branch in repo.Branches) + { + if (!branch.IsLocal && _current.Upstream == branch.FullName) + { _selectedRemote = repo.Remotes.Find(x => x.Name == branch.Remote); _selectedBranch = branch; break; } } - } + } HasSpecifiedRemoteBranch = false; } // Make sure remote is exists. - if (_selectedRemote == null) { + if (_selectedRemote == null) + { _selectedRemote = repo.Remotes[0]; _selectedBranch = null; HasSpecifiedRemoteBranch = false; } _remoteBranches = new List(); - foreach (var branch in _repo.Branches) { + foreach (var branch in _repo.Branches) + { if (branch.Remote == _selectedRemote.Name) _remoteBranches.Add(branch); } - if (_selectedBranch == null && _remoteBranches.Count > 0) { + if (_selectedBranch == null && _remoteBranches.Count > 0) + { _selectedBranch = _remoteBranches[0]; } View = new Views.Pull() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); - return Task.Run(() => { + return Task.Run(() => + { var needPopStash = false; - if (AutoStash && _repo.WorkingCopyChangesCount > 0) { + if (AutoStash && _repo.WorkingCopyChangesCount > 0) + { SetProgressDescription("Adding untracked changes..."); var succ = new Commands.Add(_repo.FullPath).Exec(); - if (succ) { + if (succ) + { SetProgressDescription("Stash local changes..."); succ = new Commands.Stash(_repo.FullPath).Push("PULL_AUTO_STASH"); } - - if (!succ) { + + if (!succ) + { CallUIThread(() => _repo.SetWatcherEnabled(true)); return false; } @@ -110,7 +136,8 @@ namespace SourceGit.ViewModels { SetProgressDescription($"Pull {_selectedRemote.Name}/{_selectedBranch.Name}..."); var rs = new Commands.Pull(_repo.FullPath, _selectedRemote.Name, _selectedBranch.Name, UseRebase, SetProgressDescription).Exec(); - if (rs && needPopStash) { + if (rs && needPopStash) + { SetProgressDescription("Re-apply local changes..."); rs = new Commands.Stash(_repo.FullPath).Pop("stash@{0}"); } @@ -120,10 +147,10 @@ namespace SourceGit.ViewModels { }); } - private Repository _repo = null; - private Models.Branch _current = null; + private readonly Repository _repo = null; + private readonly Models.Branch _current = null; private Models.Remote _selectedRemote = null; private List _remoteBranches = null; private Models.Branch _selectedBranch = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Push.cs b/src/ViewModels/Push.cs index 73f8c42a..315f0d2e 100644 --- a/src/ViewModels/Push.cs +++ b/src/ViewModels/Push.cs @@ -2,24 +2,33 @@ using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Push : Popup { - public bool HasSpecifiedLocalBranch { +namespace SourceGit.ViewModels +{ + public class Push : Popup + { + public bool HasSpecifiedLocalBranch + { get; private set; } [Required(ErrorMessage = "Local branch is required!!!")] - public Models.Branch SelectedLocalBranch { + public Models.Branch SelectedLocalBranch + { get => _selectedLocalBranch; - set { - if (SetProperty(ref _selectedLocalBranch, value)) { + set + { + if (SetProperty(ref _selectedLocalBranch, value)) + { // If selected local branch has upstream branch. Try to find it's remote. - if (!string.IsNullOrEmpty(value.Upstream)) { + if (!string.IsNullOrEmpty(value.Upstream)) + { var branch = _repo.Branches.Find(x => x.FullName == value.Upstream); - if (branch != null) { + if (branch != null) + { var remote = _repo.Remotes.Find(x => x.Name == branch.Remote); - if (remote != null && remote != _selectedRemote) { + if (remote != null && remote != _selectedRemote) + { SelectedRemote = remote; return; } @@ -32,68 +41,84 @@ namespace SourceGit.ViewModels { } } - public List LocalBranches { + public List LocalBranches + { get; private set; } - public List Remotes { + public List Remotes + { get => _repo.Remotes; } [Required(ErrorMessage = "Remote is required!!!")] - public Models.Remote SelectedRemote { + public Models.Remote SelectedRemote + { get => _selectedRemote; - set { + set + { if (SetProperty(ref _selectedRemote, value)) AutoSelectBranchByRemote(); } } - public List RemoteBranches { + public List RemoteBranches + { get => _remoteBranches; private set => SetProperty(ref _remoteBranches, value); } [Required(ErrorMessage = "Remote branch is required!!!")] - public Models.Branch SelectedRemoteBranch { + public Models.Branch SelectedRemoteBranch + { get => _selectedRemoteBranch; set => SetProperty(ref _selectedRemoteBranch, value); } - public bool PushAllTags { + public bool PushAllTags + { get; set; } - public bool ForcePush { + public bool ForcePush + { get; set; } - public Push(Repository repo, Models.Branch localBranch) { + public Push(Repository repo, Models.Branch localBranch) + { _repo = repo; // Gather all local branches and find current branch. LocalBranches = new List(); var current = null as Models.Branch; - foreach (var branch in _repo.Branches) { + foreach (var branch in _repo.Branches) + { if (branch.IsLocal) LocalBranches.Add(branch); if (branch.IsCurrent) current = branch; } // Set default selected local branch. - if (localBranch != null) { + if (localBranch != null) + { _selectedLocalBranch = localBranch; HasSpecifiedLocalBranch = true; - } else { + } + else + { _selectedLocalBranch = current; HasSpecifiedLocalBranch = false; } // Find preferred remote if selected local branch has upstream. - if (!string.IsNullOrEmpty(_selectedLocalBranch.Upstream)) { - foreach (var branch in repo.Branches) { - if (!branch.IsLocal && _selectedLocalBranch.Upstream == branch.FullName) { + if (!string.IsNullOrEmpty(_selectedLocalBranch.Upstream)) + { + foreach (var branch in repo.Branches) + { + if (!branch.IsLocal && _selectedLocalBranch.Upstream == branch.FullName) + { _selectedRemote = repo.Remotes.Find(x => x.Name == branch.Remote); break; } @@ -109,13 +134,15 @@ namespace SourceGit.ViewModels { View = new Views.Push() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); var remoteBranchName = _selectedRemoteBranch.Name.Replace(" (new)", ""); ProgressDescription = $"Push {_selectedLocalBranch.Name} -> {_selectedRemote.Name}/{remoteBranchName} ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Push( _repo.FullPath, _selectedLocalBranch.Name, @@ -130,17 +157,22 @@ namespace SourceGit.ViewModels { }); } - private void AutoSelectBranchByRemote() { + private void AutoSelectBranchByRemote() + { // Gather branches. var branches = new List(); - foreach (var branch in _repo.Branches) { + foreach (var branch in _repo.Branches) + { if (branch.Remote == _selectedRemote.Name) branches.Add(branch); } // If selected local branch has upstream branch. Try to find it in current remote branches. - if (!string.IsNullOrEmpty(_selectedLocalBranch.Upstream)) { - foreach (var branch in branches) { - if (_selectedLocalBranch.Upstream == branch.FullName) { + if (!string.IsNullOrEmpty(_selectedLocalBranch.Upstream)) + { + foreach (var branch in branches) + { + if (_selectedLocalBranch.Upstream == branch.FullName) + { RemoteBranches = branches; SelectedRemoteBranch = branch; return; @@ -149,8 +181,10 @@ namespace SourceGit.ViewModels { } // Find best remote branch by name. - foreach (var branch in branches) { - if (_selectedLocalBranch.Name == branch.Name) { + foreach (var branch in branches) + { + if (_selectedLocalBranch.Name == branch.Name) + { RemoteBranches = branches; SelectedRemoteBranch = branch; return; @@ -158,7 +192,8 @@ namespace SourceGit.ViewModels { } // Add a fake new branch. - var fake = new Models.Branch() { + var fake = new Models.Branch() + { Name = $"{_selectedLocalBranch.Name} (new)", Remote = _selectedRemote.Name, }; @@ -167,10 +202,10 @@ namespace SourceGit.ViewModels { SelectedRemoteBranch = fake; } - private Repository _repo = null; + private readonly Repository _repo = null; private Models.Branch _selectedLocalBranch = null; private Models.Remote _selectedRemote = null; private List _remoteBranches = new List(); private Models.Branch _selectedRemoteBranch = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/PushTag.cs b/src/ViewModels/PushTag.cs index c3a8172e..b59f0d7d 100644 --- a/src/ViewModels/PushTag.cs +++ b/src/ViewModels/PushTag.cs @@ -1,40 +1,48 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class PushTag : Popup { - public Models.Tag Target { +namespace SourceGit.ViewModels +{ + public class PushTag : Popup + { + public Models.Tag Target + { get; private set; } - public List Remotes { + public List Remotes + { get => _repo.Remotes; } - public Models.Remote SelectedRemote { + public Models.Remote SelectedRemote + { get; set; } - public PushTag(Repository repo, Models.Tag target) { + public PushTag(Repository repo, Models.Tag target) + { _repo = repo; Target = target; SelectedRemote = _repo.Remotes[0]; View = new Views.PushTag() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = $"Pushing tag '{Target.Name}' to remote '{SelectedRemote.Name}' ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Push(_repo.FullPath, SelectedRemote.Name, Target.Name, false).Exec(); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } - private Repository _repo = null; + private readonly Repository _repo = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Rebase.cs b/src/ViewModels/Rebase.cs index 07c579c9..13bc2638 100644 --- a/src/ViewModels/Rebase.cs +++ b/src/ViewModels/Rebase.cs @@ -1,23 +1,29 @@ using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Rebase : Popup { - public Models.Branch Current { +namespace SourceGit.ViewModels +{ + public class Rebase : Popup + { + public Models.Branch Current + { get; private set; } - public object On { + public object On + { get; private set; } - public bool AutoStash { + public bool AutoStash + { get; set; } - public Rebase(Repository repo, Models.Branch current, Models.Branch on) { + public Rebase(Repository repo, Models.Branch current, Models.Branch on) + { _repo = repo; _revision = on.Head; Current = current; @@ -26,7 +32,8 @@ namespace SourceGit.ViewModels { View = new Views.Rebase() { DataContext = this }; } - public Rebase(Repository repo, Models.Branch current, Models.Commit on) { + public Rebase(Repository repo, Models.Branch current, Models.Commit on) + { _repo = repo; _revision = on.SHA; Current = current; @@ -35,18 +42,20 @@ namespace SourceGit.ViewModels { View = new Views.Rebase() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = "Rebasing ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Rebase(_repo.FullPath, _revision, AutoStash).Exec(); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } - private Repository _repo = null; - private string _revision = string.Empty; + private readonly Repository _repo = null; + private readonly string _revision = string.Empty; } -} +} \ No newline at end of file diff --git a/src/ViewModels/RenameBranch.cs b/src/ViewModels/RenameBranch.cs index b3056853..908f5fe1 100644 --- a/src/ViewModels/RenameBranch.cs +++ b/src/ViewModels/RenameBranch.cs @@ -1,9 +1,12 @@ using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class RenameBranch : Popup { - public Models.Branch Target { +namespace SourceGit.ViewModels +{ + public class RenameBranch : Popup + { + public Models.Branch Target + { get; private set; } @@ -11,22 +14,28 @@ namespace SourceGit.ViewModels { [Required(ErrorMessage = "Branch name is required!!!")] [RegularExpression(@"^[\w\-/\.]+$", ErrorMessage = "Bad branch name format!")] [CustomValidation(typeof(RenameBranch), nameof(ValidateBranchName))] - public string Name { + public string Name + { get => _name; set => SetProperty(ref _name, value, true); } - public RenameBranch(Repository repo, Models.Branch target) { + public RenameBranch(Repository repo, Models.Branch target) + { _repo = repo; _name = target.Name; Target = target; View = new Views.RenameBranch() { DataContext = this }; } - public static ValidationResult ValidateBranchName(string name, ValidationContext ctx) { - if (ctx.ObjectInstance is RenameBranch rename) { - foreach (var b in rename._repo.Branches) { - if (b != rename.Target && b.Name == name) { + public static ValidationResult ValidateBranchName(string name, ValidationContext ctx) + { + if (ctx.ObjectInstance is RenameBranch rename) + { + foreach (var b in rename._repo.Branches) + { + if (b != rename.Target && b.Name == name) + { return new ValidationResult("A branch with same name already exists!!!"); } } @@ -35,20 +44,22 @@ namespace SourceGit.ViewModels { return ValidationResult.Success; } - public override Task Sure() { + public override Task Sure() + { if (_name == Target.Name) return null; _repo.SetWatcherEnabled(false); ProgressDescription = $"Rename '{Target.Name}'"; - return Task.Run(() => { + return Task.Run(() => + { var succ = Commands.Branch.Rename(_repo.FullPath, Target.Name, _name); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } - private Repository _repo = null; + private readonly Repository _repo = null; private string _name = string.Empty; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index dcf4ce49..3c7e5af7 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -1,158 +1,194 @@ -using Avalonia.Collections; -using Avalonia.Controls; -using Avalonia.Threading; -using CommunityToolkit.Mvvm.ComponentModel; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Text.Json.Serialization; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Repository : ObservableObject, Models.IRepository { - public string FullPath { +using Avalonia.Collections; +using Avalonia.Controls; +using Avalonia.Threading; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class Repository : ObservableObject, Models.IRepository + { + public string FullPath + { get => _fullpath; - set { - if (value != null) { + set + { + if (value != null) + { var normalized = value.Replace('\\', '/'); SetProperty(ref _fullpath, normalized); - } else { + } + else + { SetProperty(ref _fullpath, null); } } } - public string GitDir { + public string GitDir + { get => _gitDir; set => SetProperty(ref _gitDir, value); } - public AvaloniaList Filters { + public AvaloniaList Filters + { get; set; } = new AvaloniaList(); - public AvaloniaList CommitMessages { + public AvaloniaList CommitMessages + { get; set; } = new AvaloniaList(); [JsonIgnore] - public bool IsVSCodeFound { + public bool IsVSCodeFound + { get => !string.IsNullOrEmpty(Native.OS.VSCodeExecutableFile); } [JsonIgnore] - public Models.GitFlow GitFlow { + public Models.GitFlow GitFlow + { get => _gitflow; set => SetProperty(ref _gitflow, value); } [JsonIgnore] - public int SelectedViewIndex { + public int SelectedViewIndex + { get => _selectedViewIndex; - set { - if (SetProperty(ref _selectedViewIndex, value)) { - switch (value) { - case 1: - SelectedView = _workingCopy; - break; - case 2: - SelectedView = _stashesPage; - break; - default: - SelectedView = _histories; - break; + set + { + if (SetProperty(ref _selectedViewIndex, value)) + { + switch (value) + { + case 1: + SelectedView = _workingCopy; + break; + case 2: + SelectedView = _stashesPage; + break; + default: + SelectedView = _histories; + break; } } } } [JsonIgnore] - public object SelectedView { + public object SelectedView + { get => _selectedView; set => SetProperty(ref _selectedView, value); } [JsonIgnore] - public List Remotes { + public List Remotes + { get => _remotes; private set => SetProperty(ref _remotes, value); } [JsonIgnore] - public List Branches { + public List Branches + { get => _branches; private set => SetProperty(ref _branches, value); } [JsonIgnore] - public List LocalBranchTrees { + public List LocalBranchTrees + { get => _localBranchTrees; private set => SetProperty(ref _localBranchTrees, value); } [JsonIgnore] - public List RemoteBranchTrees { + public List RemoteBranchTrees + { get => _remoteBranchTrees; private set => SetProperty(ref _remoteBranchTrees, value); } [JsonIgnore] - public List Tags { + public List Tags + { get => _tags; private set => SetProperty(ref _tags, value); } [JsonIgnore] - public List Submodules { + public List Submodules + { get => _submodules; private set => SetProperty(ref _submodules, value); } [JsonIgnore] - public int WorkingCopyChangesCount { + public int WorkingCopyChangesCount + { get => _workingCopy == null ? 0 : _workingCopy.Count; } [JsonIgnore] - public int StashesCount { + public int StashesCount + { get => _stashesPage == null ? 0 : _stashesPage.Count; } [JsonIgnore] - public bool IsConflictBarVisible { + public bool IsConflictBarVisible + { get => _isConflictBarVisible; private set => SetProperty(ref _isConflictBarVisible, value); } [JsonIgnore] - public bool HasUnsolvedConflict { + public bool HasUnsolvedConflict + { get => _hasUnsolvedConflict; private set => SetProperty(ref _hasUnsolvedConflict, value); } [JsonIgnore] - public bool CanCommitWithPush { + public bool CanCommitWithPush + { get => _canCommitWithPush; private set => SetProperty(ref _canCommitWithPush, value); } [JsonIgnore] - public bool IncludeUntracked { + public bool IncludeUntracked + { get => _includeUntracked; - set { - if (SetProperty(ref _includeUntracked, value)) { + set + { + if (SetProperty(ref _includeUntracked, value)) + { Task.Run(RefreshWorkingCopyChanges); } } } [JsonIgnore] - public bool IsSearching { + public bool IsSearching + { get => _isSearching; - set { - if (SetProperty(ref _isSearching, value)) { + set + { + if (SetProperty(ref _isSearching, value)) + { SearchedCommits = new List(); SearchCommitFilter = string.Empty; if (value) SelectedViewIndex = 0; @@ -161,18 +197,21 @@ namespace SourceGit.ViewModels { } [JsonIgnore] - public string SearchCommitFilter { + public string SearchCommitFilter + { get => _searchCommitFilter; set => SetProperty(ref _searchCommitFilter, value); } [JsonIgnore] - public List SearchedCommits { + public List SearchedCommits + { get => _searchedCommits; set => SetProperty(ref _searchedCommits, value); } - public void Open() { + public void Open() + { _watcher = new Models.Watcher(this); _histories = new Histories(this); _workingCopy = new WorkingCopy(this); @@ -182,7 +221,8 @@ namespace SourceGit.ViewModels { _isConflictBarVisible = false; _hasUnsolvedConflict = false; - Task.Run(() => { + Task.Run(() => + { RefreshBranches(); RefreshTags(); RefreshCommits(); @@ -194,7 +234,8 @@ namespace SourceGit.ViewModels { Task.Run(RefreshGitFlow); } - public void Close() { + public void Close() + { SelectedView = 0.0; // Do NOT modify. Used to remove exists widgets for GC.Collect _watcher.Dispose(); @@ -218,22 +259,27 @@ namespace SourceGit.ViewModels { _searchedCommits.Clear(); } - public void OpenInFileManager() { + public void OpenInFileManager() + { Native.OS.OpenInFileManager(_fullpath); } - public void OpenInVSCode() { + public void OpenInVSCode() + { Native.OS.OpenInVSCode(_fullpath); } - public void OpenInTerminal() { + public void OpenInTerminal() + { Native.OS.OpenTerminal(_fullpath); } - public void Fetch() { + public void Fetch() + { if (!PopupHost.CanCreatePopup()) return; - if (Remotes.Count == 0) { + if (Remotes.Count == 0) + { App.RaiseException(_fullpath, "No remotes added to this repository!!!"); return; } @@ -241,10 +287,12 @@ namespace SourceGit.ViewModels { PopupHost.ShowPopup(new Fetch(this)); } - public void Pull() { + public void Pull() + { if (!PopupHost.CanCreatePopup()) return; - if (Remotes.Count == 0) { + if (Remotes.Count == 0) + { App.RaiseException(_fullpath, "No remotes added to this repository!!!"); return; } @@ -252,10 +300,12 @@ namespace SourceGit.ViewModels { PopupHost.ShowPopup(new Pull(this, null)); } - public void Push() { + public void Push() + { if (!PopupHost.CanCreatePopup()) return; - if (Remotes.Count == 0) { + if (Remotes.Count == 0) + { App.RaiseException(_fullpath, "No remotes added to this repository!!!"); return; } @@ -264,37 +314,44 @@ namespace SourceGit.ViewModels { PopupHost.ShowPopup(new Push(this, null)); } - public void ApplyPatch() { + public void ApplyPatch() + { if (!PopupHost.CanCreatePopup()) return; PopupHost.ShowPopup(new Apply(this)); } - public void Cleanup() { + public void Cleanup() + { if (!PopupHost.CanCreatePopup()) return; PopupHost.ShowAndStartPopup(new Cleanup(this)); } - public void OpenConfigure() { + public void OpenConfigure() + { if (!PopupHost.CanCreatePopup()) return; PopupHost.ShowPopup(new RepositoryConfigure(this)); } - public void ClearSearchCommitFilter() { + public void ClearSearchCommitFilter() + { SearchCommitFilter = string.Empty; } - public void StartSearchCommits() { + public void StartSearchCommits() + { if (_histories == null) return; var visible = new List(); - foreach (var c in _histories.Commits) { + foreach (var c in _histories.Commits) + { if (c.SHA.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase) || c.Subject.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase) || c.Message.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase) || c.Author.Name.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase) || c.Committer.Name.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase) || c.Author.Email.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase) - || c.Committer.Email.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase)) { + || c.Committer.Email.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase)) + { visible.Add(c); } } @@ -302,41 +359,53 @@ namespace SourceGit.ViewModels { SearchedCommits = visible; } - public void SetWatcherEnabled(bool enabled) { + public void SetWatcherEnabled(bool enabled) + { if (_watcher != null) _watcher.SetEnabled(enabled); } - public void MarkBranchesDirtyManually() { + public void MarkBranchesDirtyManually() + { if (_watcher != null) _watcher.MarkBranchDirtyManually(); } - public void MarkWorkingCopyDirtyManually() { + public void MarkWorkingCopyDirtyManually() + { if (_watcher != null) _watcher.MarkWorkingCopyDirtyManually(); } - public void NavigateToCommit(string sha) { - if (_histories != null) { + public void NavigateToCommit(string sha) + { + if (_histories != null) + { SelectedViewIndex = 0; _histories.NavigateTo(sha); } } - public void UpdateFilter(string filter, bool toggle) { + public void UpdateFilter(string filter, bool toggle) + { var changed = false; - if (toggle) { - if (!Filters.Contains(filter)) { + if (toggle) + { + if (!Filters.Contains(filter)) + { Filters.Add(filter); changed = true; } - } else { + } + else + { changed = Filters.Remove(filter); } if (changed) Task.Run(RefreshCommits); } - public void StashAll() { - if (PopupHost.CanCreatePopup()) { + public void StashAll() + { + if (PopupHost.CanCreatePopup()) + { var changes = new List(); changes.AddRange(_workingCopy.Unstaged); changes.AddRange(_workingCopy.Staged); @@ -344,11 +413,13 @@ namespace SourceGit.ViewModels { } } - public void GotoResolve() { + public void GotoResolve() + { if (_workingCopy != null) SelectedViewIndex = 1; } - public async void ContinueMerge() { + public async void ContinueMerge() + { var cherryPickMerge = Path.Combine(_gitDir, "CHERRY_PICK_HEAD"); var rebaseMerge = Path.Combine(_gitDir, "REBASE_HEAD"); var rebaseMergeFolder = Path.Combine(_gitDir, "rebase-merge"); @@ -356,15 +427,24 @@ namespace SourceGit.ViewModels { var otherMerge = Path.Combine(_gitDir, "MERGE_HEAD"); var mode = ""; - if (File.Exists(cherryPickMerge)) { + if (File.Exists(cherryPickMerge)) + { mode = "cherry-pick"; - } else if (File.Exists(rebaseMerge) && Directory.Exists(rebaseMergeFolder)) { + } + else if (File.Exists(rebaseMerge) && Directory.Exists(rebaseMergeFolder)) + { mode = "rebase"; - } else if (File.Exists(revertMerge)) { + } + else if (File.Exists(revertMerge)) + { mode = "revert"; - } else if (File.Exists(otherMerge)) { + } + else if (File.Exists(otherMerge)) + { mode = "merge"; - } else { + } + else + { MarkWorkingCopyDirtyManually(); return; } @@ -378,30 +458,42 @@ namespace SourceGit.ViewModels { var succ = await Task.Run(cmd.Exec); SetWatcherEnabled(true); - if (succ) { + if (succ) + { if (_workingCopy != null) _workingCopy.CommitMessage = string.Empty; - if (mode == "rebase") { + if (mode == "rebase") + { if (File.Exists(rebaseMerge)) File.Delete(rebaseMerge); if (Directory.Exists(rebaseMergeFolder)) Directory.Delete(rebaseMergeFolder); } } } - public async void AbortMerge() { + public async void AbortMerge() + { var cmd = new Commands.Command(); cmd.WorkingDirectory = _fullpath; cmd.Context = _fullpath; - if (File.Exists(Path.Combine(_gitDir, "CHERRY_PICK_HEAD"))) { + if (File.Exists(Path.Combine(_gitDir, "CHERRY_PICK_HEAD"))) + { cmd.Args = "cherry-pick --abort"; - } else if (File.Exists(Path.Combine(_gitDir, "REBASE_HEAD"))) { + } + else if (File.Exists(Path.Combine(_gitDir, "REBASE_HEAD"))) + { cmd.Args = "rebase --abort"; - } else if (File.Exists(Path.Combine(_gitDir, "REVERT_HEAD"))) { + } + else if (File.Exists(Path.Combine(_gitDir, "REVERT_HEAD"))) + { cmd.Args = "revert --abort"; - } else if (File.Exists(Path.Combine(_gitDir, "MERGE_HEAD"))) { + } + else if (File.Exists(Path.Combine(_gitDir, "MERGE_HEAD"))) + { cmd.Args = "merge --abort"; - } else { + } + else + { MarkWorkingCopyDirtyManually(); return; } @@ -411,7 +503,8 @@ namespace SourceGit.ViewModels { SetWatcherEnabled(true); } - public void RefreshBranches() { + public void RefreshBranches() + { var branches = new Commands.QueryBranches(FullPath).Result(); var remotes = new Commands.QueryRemotes(FullPath).Result(); @@ -421,7 +514,8 @@ namespace SourceGit.ViewModels { builder.CollectExpandedNodes(_remoteBranchTrees, false); builder.Run(branches, remotes); - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { Remotes = remotes; Branches = branches; LocalBranchTrees = builder.Locals; @@ -432,49 +526,64 @@ namespace SourceGit.ViewModels { }); } - public void RefreshTags() { + public void RefreshTags() + { var tags = new Commands.QueryTags(FullPath).Result(); foreach (var tag in tags) tag.IsFiltered = Filters.Contains(tag.Name); - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { Tags = tags; }); } - public void RefreshCommits() { + public void RefreshCommits() + { Dispatcher.UIThread.Invoke(() => _histories.IsLoading = true); var limits = $"-{Preference.Instance.MaxHistoryCommits} "; var validFilters = new List(); - foreach (var filter in Filters) { - if (filter.StartsWith("refs/", StringComparison.Ordinal)) { + foreach (var filter in Filters) + { + if (filter.StartsWith("refs/", StringComparison.Ordinal)) + { if (_branches.FindIndex(x => x.FullName == filter) >= 0) validFilters.Add(filter); - } else { + } + else + { if (_tags.FindIndex(t => t.Name == filter) >= 0) validFilters.Add(filter); } } - if (validFilters.Count > 0) { + if (validFilters.Count > 0) + { limits += string.Join(" ", validFilters); - } else { + } + else + { limits += "--branches --remotes --tags"; } var commits = new Commands.QueryCommits(FullPath, limits).Result(); - Dispatcher.UIThread.Invoke(() => { - if (_histories != null) { + Dispatcher.UIThread.Invoke(() => + { + if (_histories != null) + { _histories.IsLoading = false; _histories.Commits = commits; - } + } }); } - public void RefreshSubmodules() { + public void RefreshSubmodules() + { var submodules = new Commands.QuerySubmodules(FullPath).Result(); - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { Submodules = submodules; }); } - public void RefreshWorkingCopyChanges() { + public void RefreshWorkingCopyChanges() + { var changes = new Commands.QueryLocalChanges(FullPath, _includeUntracked).Result(); var hasUnsolvedConflict = _workingCopy.SetData(changes); @@ -488,41 +597,49 @@ namespace SourceGit.ViewModels { File.Exists(revertMerge) || File.Exists(otherMerge)); - if (!runningMerge) { + if (!runningMerge) + { if (Directory.Exists(rebaseMergeFolder)) Directory.Delete(rebaseMergeFolder, true); var applyFolder = Path.Combine(_gitDir, "rebase-apply"); if (Directory.Exists(applyFolder)) Directory.Delete(applyFolder, true); } - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { IsConflictBarVisible = runningMerge; HasUnsolvedConflict = hasUnsolvedConflict; OnPropertyChanged(nameof(WorkingCopyChangesCount)); }); } - public void RefreshStashes() { + public void RefreshStashes() + { var stashes = new Commands.QueryStashes(FullPath).Result(); - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { if (_stashesPage != null) _stashesPage.Stashes = stashes; OnPropertyChanged(nameof(StashesCount)); }); } - public void RefreshGitFlow() { + public void RefreshGitFlow() + { var config = new Commands.Config(_fullpath).ListAll(); var gitFlow = new Models.GitFlow(); if (config.ContainsKey("gitflow.prefix.feature")) gitFlow.Feature = config["gitflow.prefix.feature"]; if (config.ContainsKey("gitflow.prefix.release")) gitFlow.Release = config["gitflow.prefix.release"]; if (config.ContainsKey("gitflow.prefix.hotfix")) gitFlow.Hotfix = config["gitflow.prefix.hotfix"]; - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { GitFlow = gitFlow; }); } - public void CreateNewBranch() { + public void CreateNewBranch() + { var current = Branches.Find(x => x.IsCurrent); - if (current == null) { + if (current == null) + { App.RaiseException(_fullpath, "Git do not hold any branch until you do first commit."); return; } @@ -530,9 +647,11 @@ namespace SourceGit.ViewModels { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateBranch(this, current)); } - public void CreateNewTag() { + public void CreateNewTag() + { var current = Branches.Find(x => x.IsCurrent); - if (current == null) { + if (current == null) + { App.RaiseException(_fullpath, "Git do not hold any branch until you do first commit."); return; } @@ -540,36 +659,43 @@ namespace SourceGit.ViewModels { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateTag(this, current)); } - public void AddRemote() { + public void AddRemote() + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new AddRemote(this)); } - public void AddSubmodule() { + public void AddSubmodule() + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new AddSubmodule(this)); } - public ContextMenu CreateContextMenuForGitFlow() { + public ContextMenu CreateContextMenuForGitFlow() + { var menu = new ContextMenu(); menu.Placement = PlacementMode.BottomEdgeAlignedLeft; - if (GitFlow.IsEnabled) { + if (GitFlow.IsEnabled) + { var startFeature = new MenuItem(); startFeature.Header = App.Text("GitFlow.StartFeature"); - startFeature.Click += (o, e) => { + startFeature.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Feature)); e.Handled = true; }; var startRelease = new MenuItem(); startRelease.Header = App.Text("GitFlow.StartRelease"); - startRelease.Click += (o, e) => { + startRelease.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Release)); e.Handled = true; }; var startHotfix = new MenuItem(); startHotfix.Header = App.Text("GitFlow.StartHotfix"); - startHotfix.Click += (o, e) => { + startHotfix.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Hotfix)); e.Handled = true; }; @@ -577,10 +703,13 @@ namespace SourceGit.ViewModels { menu.Items.Add(startFeature); menu.Items.Add(startRelease); menu.Items.Add(startHotfix); - } else { + } + else + { var init = new MenuItem(); init.Header = App.Text("GitFlow.Init"); - init.Click += (o, e) => { + init.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new InitGitFlow(this)); e.Handled = true; }; @@ -589,24 +718,28 @@ namespace SourceGit.ViewModels { return menu; } - public ContextMenu CreateContextMenuForLocalBranch(Models.Branch branch) { + public ContextMenu CreateContextMenuForLocalBranch(Models.Branch branch) + { var menu = new ContextMenu(); var push = new MenuItem(); push.Header = new Views.NameHighlightedTextBlock("BranchCM.Push", branch.Name); push.Icon = App.CreateMenuIcon("Icons.Push"); push.IsEnabled = Remotes.Count > 0; - push.Click += (_, e) => { + push.Click += (_, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Push(this, branch)); e.Handled = true; }; - if (branch.IsCurrent) { + if (branch.IsCurrent) + { var discard = new MenuItem(); discard.Header = App.Text("BranchCM.DiscardAll"); discard.Icon = App.CreateMenuIcon("Icons.Undo"); discard.IsEnabled = _workingCopy.Count > 0; - discard.Click += (o, e) => { + discard.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Discard(this)); e.Handled = true; }; @@ -614,13 +747,15 @@ namespace SourceGit.ViewModels { menu.Items.Add(discard); menu.Items.Add(new MenuItem() { Header = "-" }); - if (!string.IsNullOrEmpty(branch.Upstream)) { + if (!string.IsNullOrEmpty(branch.Upstream)) + { var upstream = branch.Upstream.Substring(13); var fastForward = new MenuItem(); fastForward.Header = new Views.NameHighlightedTextBlock("BranchCM.FastForward", upstream); fastForward.Icon = App.CreateMenuIcon("Icons.FastForward"); fastForward.IsEnabled = !string.IsNullOrEmpty(branch.UpstreamTrackStatus) && branch.UpstreamTrackStatus.IndexOf('↑') < 0; - fastForward.Click += (o, e) => { + fastForward.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new Merge(this, upstream, branch.Name)); e.Handled = true; }; @@ -628,7 +763,8 @@ namespace SourceGit.ViewModels { var pull = new MenuItem(); pull.Header = new Views.NameHighlightedTextBlock("BranchCM.Pull", upstream); pull.Icon = App.CreateMenuIcon("Icons.Pull"); - pull.Click += (o, e) => { + pull.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Pull(this, null)); e.Handled = true; }; @@ -638,25 +774,30 @@ namespace SourceGit.ViewModels { } menu.Items.Add(push); - } else { + } + else + { var current = Branches.Find(x => x.IsCurrent); var checkout = new MenuItem(); checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", branch.Name); checkout.Icon = App.CreateMenuIcon("Icons.Check"); - checkout.Click += (o, e) => { + checkout.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new Checkout(this, branch.Name)); e.Handled = true; }; menu.Items.Add(checkout); var upstream = Branches.Find(x => x.FullName == branch.Upstream); - if (upstream != null) { + if (upstream != null) + { var fastForward = new MenuItem(); fastForward.Header = new Views.NameHighlightedTextBlock("BranchCM.FastForward", $"{upstream.Remote}/{upstream.Name}"); fastForward.Icon = App.CreateMenuIcon("Icons.FastForward"); fastForward.IsEnabled = !string.IsNullOrEmpty(branch.UpstreamTrackStatus) && branch.UpstreamTrackStatus.IndexOf('↑') < 0; - fastForward.Click += (o, e) => { + fastForward.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new FastForwardWithoutCheckout(this, branch, upstream)); e.Handled = true; }; @@ -671,7 +812,8 @@ namespace SourceGit.ViewModels { var merge = new MenuItem(); merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", branch.Name, current.Name); merge.Icon = App.CreateMenuIcon("Icons.Merge"); - merge.Click += (o, e) => { + merge.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Merge(this, branch.Name, current.Name)); e.Handled = true; }; @@ -679,7 +821,8 @@ namespace SourceGit.ViewModels { var rebase = new MenuItem(); rebase.Header = new Views.NameHighlightedTextBlock("BranchCM.Rebase", current.Name, branch.Name); rebase.Icon = App.CreateMenuIcon("Icons.Rebase"); - rebase.Click += (o, e) => { + rebase.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Rebase(this, current, branch)); e.Handled = true; }; @@ -689,11 +832,13 @@ namespace SourceGit.ViewModels { } var type = GitFlow.GetBranchType(branch.Name); - if (type != Models.GitFlowBranchType.None) { + if (type != Models.GitFlowBranchType.None) + { var finish = new MenuItem(); finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name); finish.Icon = App.CreateMenuIcon("Icons.Flow"); - finish.Click += (o, e) => { + finish.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new GitFlowFinish(this, branch, type)); e.Handled = true; }; @@ -704,7 +849,8 @@ namespace SourceGit.ViewModels { var rename = new MenuItem(); rename.Header = new Views.NameHighlightedTextBlock("BranchCM.Rename", branch.Name); rename.Icon = App.CreateMenuIcon("Icons.Rename"); - rename.Click += (o, e) => { + rename.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new RenameBranch(this, branch)); e.Handled = true; }; @@ -713,7 +859,8 @@ namespace SourceGit.ViewModels { delete.Header = new Views.NameHighlightedTextBlock("BranchCM.Delete", branch.Name); delete.Icon = App.CreateMenuIcon("Icons.Clear"); delete.IsEnabled = !branch.IsCurrent; - delete.Click += (o, e) => { + delete.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteBranch(this, branch)); e.Handled = true; }; @@ -721,7 +868,8 @@ namespace SourceGit.ViewModels { var createBranch = new MenuItem(); createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add"); createBranch.Header = App.Text("CreateBranch"); - createBranch.Click += (o, e) => { + createBranch.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateBranch(this, branch)); e.Handled = true; }; @@ -729,7 +877,8 @@ namespace SourceGit.ViewModels { var createTag = new MenuItem(); createTag.Icon = App.CreateMenuIcon("Icons.Tag.Add"); createTag.Header = App.Text("CreateTag"); - createTag.Click += (o, e) => { + createTag.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateTag(this, branch)); e.Handled = true; }; @@ -743,23 +892,28 @@ namespace SourceGit.ViewModels { menu.Items.Add(new MenuItem() { Header = "-" }); var remoteBranches = new List(); - foreach (var b in Branches) { + foreach (var b in Branches) + { if (!b.IsLocal) remoteBranches.Add(b); } - if (remoteBranches.Count > 0) { + if (remoteBranches.Count > 0) + { var tracking = new MenuItem(); tracking.Header = App.Text("BranchCM.Tracking"); tracking.Icon = App.CreateMenuIcon("Icons.Branch"); - foreach (var b in remoteBranches) { + foreach (var b in remoteBranches) + { var upstream = b.FullName.Replace("refs/remotes/", ""); var target = new MenuItem(); target.Header = upstream; if (branch.Upstream == b.FullName) target.Icon = App.CreateMenuIcon("Icons.Check"); - target.Click += (o, e) => { - if (Commands.Branch.SetUpstream(_fullpath, branch.Name, upstream)) { + target.Click += (o, e) => + { + if (Commands.Branch.SetUpstream(_fullpath, branch.Name, upstream)) + { Task.Run(RefreshBranches); } e.Handled = true; @@ -770,8 +924,10 @@ namespace SourceGit.ViewModels { var unsetUpstream = new MenuItem(); unsetUpstream.Header = App.Text("BranchCM.UnsetUpstream"); - unsetUpstream.Click += (_, e) => { - if (Commands.Branch.SetUpstream(_fullpath, branch.Name, string.Empty)) { + unsetUpstream.Click += (_, e) => + { + if (Commands.Branch.SetUpstream(_fullpath, branch.Name, string.Empty)) + { Task.Run(RefreshBranches); } e.Handled = true; @@ -785,7 +941,8 @@ namespace SourceGit.ViewModels { var archive = new MenuItem(); archive.Icon = App.CreateMenuIcon("Icons.Archive"); archive.Header = App.Text("Archive"); - archive.Click += (o, e) => { + archive.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Archive(this, branch)); e.Handled = true; }; @@ -795,7 +952,8 @@ namespace SourceGit.ViewModels { var copy = new MenuItem(); copy.Header = App.Text("BranchCM.CopyName"); copy.Icon = App.CreateMenuIcon("Icons.Copy"); - copy.Click += (o, e) => { + copy.Click += (o, e) => + { App.CopyText(branch.Name); e.Handled = true; }; @@ -804,13 +962,15 @@ namespace SourceGit.ViewModels { return menu; } - public ContextMenu CreateContextMenuForRemote(Models.Remote remote) { + public ContextMenu CreateContextMenuForRemote(Models.Remote remote) + { var menu = new ContextMenu(); var fetch = new MenuItem(); fetch.Header = App.Text("RemoteCM.Fetch"); fetch.Icon = App.CreateMenuIcon("Icons.Fetch"); - fetch.Click += (o, e) => { + fetch.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new Fetch(this, remote)); e.Handled = true; }; @@ -818,7 +978,8 @@ namespace SourceGit.ViewModels { var prune = new MenuItem(); prune.Header = App.Text("RemoteCM.Prune"); prune.Icon = App.CreateMenuIcon("Icons.Clear2"); - prune.Click += (o, e) => { + prune.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new PruneRemote(this, remote)); e.Handled = true; }; @@ -826,7 +987,8 @@ namespace SourceGit.ViewModels { var edit = new MenuItem(); edit.Header = App.Text("RemoteCM.Edit"); edit.Icon = App.CreateMenuIcon("Icons.Edit"); - edit.Click += (o, e) => { + edit.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new EditRemote(this, remote)); e.Handled = true; }; @@ -834,7 +996,8 @@ namespace SourceGit.ViewModels { var delete = new MenuItem(); delete.Header = App.Text("RemoteCM.Delete"); delete.Icon = App.CreateMenuIcon("Icons.Clear"); - delete.Click += (o, e) => { + delete.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteRemote(this, remote)); e.Handled = true; }; @@ -842,7 +1005,8 @@ namespace SourceGit.ViewModels { var copy = new MenuItem(); copy.Header = App.Text("RemoteCM.CopyURL"); copy.Icon = App.CreateMenuIcon("Icons.Copy"); - copy.Click += (o, e) => { + copy.Click += (o, e) => + { App.CopyText(remote.URL); e.Handled = true; }; @@ -857,16 +1021,20 @@ namespace SourceGit.ViewModels { return menu; } - public ContextMenu CreateContextMenuForRemoteBranch(Models.Branch branch) { + public ContextMenu CreateContextMenuForRemoteBranch(Models.Branch branch) + { var menu = new ContextMenu(); var current = Branches.Find(x => x.IsCurrent); var checkout = new MenuItem(); checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", $"{branch.Remote}/{branch.Name}"); checkout.Icon = App.CreateMenuIcon("Icons.Check"); - checkout.Click += (o, e) => { - foreach (var b in Branches) { - if (b.IsLocal && b.Upstream == branch.FullName) { + checkout.Click += (o, e) => + { + foreach (var b in Branches) + { + if (b.IsLocal && b.Upstream == branch.FullName) + { if (b.IsCurrent) return; if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new Checkout(this, b.Name)); return; @@ -879,11 +1047,13 @@ namespace SourceGit.ViewModels { menu.Items.Add(checkout); menu.Items.Add(new MenuItem() { Header = "-" }); - if (current != null) { + if (current != null) + { var pull = new MenuItem(); pull.Header = new Views.NameHighlightedTextBlock("BranchCM.PullInto", $"{branch.Remote}/{branch.Name}", current.Name); pull.Icon = App.CreateMenuIcon("Icons.Pull"); - pull.Click += (o, e) => { + pull.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Pull(this, branch)); e.Handled = true; }; @@ -891,7 +1061,8 @@ namespace SourceGit.ViewModels { var merge = new MenuItem(); merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", $"{branch.Remote}/{branch.Name}", current.Name); merge.Icon = App.CreateMenuIcon("Icons.Merge"); - merge.Click += (o, e) => { + merge.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Merge(this, $"{branch.Remote}/{branch.Name}", current.Name)); e.Handled = true; }; @@ -899,7 +1070,8 @@ namespace SourceGit.ViewModels { var rebase = new MenuItem(); rebase.Header = new Views.NameHighlightedTextBlock("BranchCM.Rebase", current.Name, $"{branch.Remote}/{branch.Name}"); rebase.Icon = App.CreateMenuIcon("Icons.Rebase"); - rebase.Click += (o, e) => { + rebase.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Rebase(this, current, branch)); e.Handled = true; }; @@ -913,7 +1085,8 @@ namespace SourceGit.ViewModels { var delete = new MenuItem(); delete.Header = new Views.NameHighlightedTextBlock("BranchCM.Delete", $"{branch.Remote}/{branch.Name}"); delete.Icon = App.CreateMenuIcon("Icons.Clear"); - delete.Click += (o, e) => { + delete.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteBranch(this, branch)); e.Handled = true; }; @@ -921,7 +1094,8 @@ namespace SourceGit.ViewModels { var createBranch = new MenuItem(); createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add"); createBranch.Header = App.Text("CreateBranch"); - createBranch.Click += (o, e) => { + createBranch.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateBranch(this, branch)); e.Handled = true; }; @@ -929,7 +1103,8 @@ namespace SourceGit.ViewModels { var createTag = new MenuItem(); createTag.Icon = App.CreateMenuIcon("Icons.Tag.Add"); createTag.Header = App.Text("CreateTag"); - createTag.Click += (o, e) => { + createTag.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateTag(this, branch)); e.Handled = true; }; @@ -937,7 +1112,8 @@ namespace SourceGit.ViewModels { var archive = new MenuItem(); archive.Icon = App.CreateMenuIcon("Icons.Archive"); archive.Header = App.Text("Archive"); - archive.Click += (o, e) => { + archive.Click += (o, e) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Archive(this, branch)); e.Handled = true; }; @@ -945,7 +1121,8 @@ namespace SourceGit.ViewModels { var copy = new MenuItem(); copy.Header = App.Text("BranchCM.CopyName"); copy.Icon = App.CreateMenuIcon("Icons.Copy"); - copy.Click += (o, e) => { + copy.Click += (o, e) => + { App.CopyText(branch.Remote + "/" + branch.Name); e.Handled = true; }; @@ -961,11 +1138,13 @@ namespace SourceGit.ViewModels { return menu; } - public ContextMenu CreateContextMenuForTag(Models.Tag tag) { + public ContextMenu CreateContextMenuForTag(Models.Tag tag) + { var createBranch = new MenuItem(); createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add"); createBranch.Header = App.Text("CreateBranch"); - createBranch.Click += (o, ev) => { + createBranch.Click += (o, ev) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateBranch(this, tag)); ev.Handled = true; }; @@ -974,7 +1153,8 @@ namespace SourceGit.ViewModels { pushTag.Header = new Views.NameHighlightedTextBlock("TagCM.Push", tag.Name); pushTag.Icon = App.CreateMenuIcon("Icons.Push"); pushTag.IsEnabled = Remotes.Count > 0; - pushTag.Click += (o, ev) => { + pushTag.Click += (o, ev) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new PushTag(this, tag)); ev.Handled = true; }; @@ -982,7 +1162,8 @@ namespace SourceGit.ViewModels { var deleteTag = new MenuItem(); deleteTag.Header = new Views.NameHighlightedTextBlock("TagCM.Delete", tag.Name); deleteTag.Icon = App.CreateMenuIcon("Icons.Clear"); - deleteTag.Click += (o, ev) => { + deleteTag.Click += (o, ev) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteTag(this, tag)); ev.Handled = true; }; @@ -990,7 +1171,8 @@ namespace SourceGit.ViewModels { var archive = new MenuItem(); archive.Icon = App.CreateMenuIcon("Icons.Archive"); archive.Header = App.Text("Archive"); - archive.Click += (o, ev) => { + archive.Click += (o, ev) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Archive(this, tag)); ev.Handled = true; }; @@ -998,7 +1180,8 @@ namespace SourceGit.ViewModels { var copy = new MenuItem(); copy.Header = App.Text("TagCM.Copy"); copy.Icon = App.CreateMenuIcon("Icons.Copy"); - copy.Click += (o, ev) => { + copy.Click += (o, ev) => + { App.CopyText(tag.Name); ev.Handled = true; }; @@ -1015,15 +1198,18 @@ namespace SourceGit.ViewModels { return menu; } - public ContextMenu CreateContextMenuForSubmodule(string submodule) { + public ContextMenu CreateContextMenuForSubmodule(string submodule) + { var open = new MenuItem(); open.Header = App.Text("Submodule.Open"); open.Icon = App.CreateMenuIcon("Icons.Folder.Open"); - open.Click += (o, ev) => { + open.Click += (o, ev) => + { var root = Path.GetFullPath(Path.Combine(_fullpath, submodule)); var gitDir = new Commands.QueryGitDir(root).Result(); var repo = Preference.AddRepository(root, gitDir); - var node = new RepositoryNode() { + var node = new RepositoryNode() + { Id = repo.FullPath, Name = Path.GetFileName(repo.FullPath), Bookmark = 0, @@ -1031,7 +1217,8 @@ namespace SourceGit.ViewModels { }; var launcher = App.GetTopLevel().DataContext as Launcher; - if (launcher != null) { + if (launcher != null) + { launcher.OpenRepositoryInTab(node, null); } @@ -1041,7 +1228,8 @@ namespace SourceGit.ViewModels { var copy = new MenuItem(); copy.Header = App.Text("Submodule.CopyPath"); copy.Icon = App.CreateMenuIcon("Icons.Copy"); - copy.Click += (o, ev) => { + copy.Click += (o, ev) => + { App.CopyText(submodule); ev.Handled = true; }; @@ -1049,7 +1237,8 @@ namespace SourceGit.ViewModels { var rm = new MenuItem(); rm.Header = App.Text("Submodule.Remove"); rm.Icon = App.CreateMenuIcon("Icons.Clear"); - rm.Click += (o, ev) => { + rm.Click += (o, ev) => + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteSubmodule(this, submodule)); ev.Handled = true; }; @@ -1087,4 +1276,4 @@ namespace SourceGit.ViewModels { private bool _canCommitWithPush = false; private bool _includeUntracked = true; } -} +} \ No newline at end of file diff --git a/src/ViewModels/RepositoryConfigure.cs b/src/ViewModels/RepositoryConfigure.cs index 928d58fd..d97f7a36 100644 --- a/src/ViewModels/RepositoryConfigure.cs +++ b/src/ViewModels/RepositoryConfigure.cs @@ -1,34 +1,42 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class RepositoryConfigure : Popup { - public string UserName { +namespace SourceGit.ViewModels +{ + public class RepositoryConfigure : Popup + { + public string UserName + { get; set; } - public string UserEmail { + public string UserEmail + { get; set; } - public bool GPGSigningEnabled { + public bool GPGSigningEnabled + { get; set; } - public string GPGUserSigningKey { + public string GPGUserSigningKey + { get; set; } - public string HttpProxy { + public string HttpProxy + { get; set; } - public RepositoryConfigure(Repository repo) { + public RepositoryConfigure(Repository repo) + { _repo = repo; _cached = new Commands.Config(repo.FullPath).ListAll(); @@ -41,7 +49,8 @@ namespace SourceGit.ViewModels { View = new Views.RepositoryConfigure() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { SetIfChanged("user.name", UserName); SetIfChanged("user.email", UserEmail); SetIfChanged("commit.gpgsign", GPGSigningEnabled ? "true" : "false"); @@ -50,20 +59,25 @@ namespace SourceGit.ViewModels { return null; } - private void SetIfChanged(string key, string value) { + private void SetIfChanged(string key, string value) + { bool changed = false; - if (_cached.ContainsKey(key)) { + if (_cached.ContainsKey(key)) + { changed = value != _cached[key]; - } else if (!string.IsNullOrEmpty(value)) { + } + else if (!string.IsNullOrEmpty(value)) + { changed = true; } - if (changed) { + if (changed) + { new Commands.Config(_repo.FullPath).Set(key, value); } } - private Repository _repo = null; - private Dictionary _cached = null; + private readonly Repository _repo = null; + private readonly Dictionary _cached = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/RepositoryNode.cs b/src/ViewModels/RepositoryNode.cs index 0955f028..611df4b4 100644 --- a/src/ViewModels/RepositoryNode.cs +++ b/src/ViewModels/RepositoryNode.cs @@ -1,67 +1,84 @@ -using Avalonia.Collections; -using CommunityToolkit.Mvvm.ComponentModel; -using System.Text.Json.Serialization; +using System.Text.Json.Serialization; -namespace SourceGit.ViewModels { - public class RepositoryNode : ObservableObject { - public string Id { +using Avalonia.Collections; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class RepositoryNode : ObservableObject + { + public string Id + { get => _id; - set { + set + { var normalized = value.Replace('\\', '/'); SetProperty(ref _id, normalized); } } - public string Name { + public string Name + { get => _name; set => SetProperty(ref _name, value); } - public int Bookmark { + public int Bookmark + { get => _bookmark; set => SetProperty(ref _bookmark, value); } - public bool IsRepository { + public bool IsRepository + { get => _isRepository; set => SetProperty(ref _isRepository, value); } - public bool IsExpanded { + public bool IsExpanded + { get => _isExpanded; set => SetProperty(ref _isExpanded, value); } [JsonIgnore] - public bool IsVisible { + public bool IsVisible + { get => _isVisible; set => SetProperty(ref _isVisible, value); } - - public AvaloniaList SubNodes { + + public AvaloniaList SubNodes + { get => _subNodes; set => SetProperty(ref _subNodes, value); } - public void Edit() { + public void Edit() + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new EditRepositoryNode(this)); } - public void AddSubFolder() { + public void AddSubFolder() + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateGroup(this)); } - public void OpenInFileManager() { + public void OpenInFileManager() + { if (!IsRepository) return; Native.OS.OpenInFileManager(_id); } - public void OpenTerminal() { + public void OpenTerminal() + { if (!IsRepository) return; Native.OS.OpenTerminal(_id); } - public void Delete() { + public void Delete() + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteRepositoryNode(this)); } @@ -73,4 +90,4 @@ namespace SourceGit.ViewModels { private bool _isVisible = true; private AvaloniaList _subNodes = new AvaloniaList(); } -} +} \ No newline at end of file diff --git a/src/ViewModels/Reset.cs b/src/ViewModels/Reset.cs index 12ba31ed..9b8b73cc 100644 --- a/src/ViewModels/Reset.cs +++ b/src/ViewModels/Reset.cs @@ -1,15 +1,19 @@ -using Avalonia.Media; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class ResetMode { +using Avalonia.Media; + +namespace SourceGit.ViewModels +{ + public class ResetMode + { public string Name { get; set; } public string Desc { get; set; } public string Arg { get; set; } public IBrush Color { get; set; } - public ResetMode(string n, string d, string a, IBrush b) { + public ResetMode(string n, string d, string a, IBrush b) + { Name = n; Desc = d; Arg = a; @@ -17,28 +21,34 @@ namespace SourceGit.ViewModels { } } - public class Reset : Popup { - public Models.Branch Current { + public class Reset : Popup + { + public Models.Branch Current + { get; private set; } - public Models.Commit To { + public Models.Commit To + { get; private set; } - public List Modes { + public List Modes + { get; private set; } - public ResetMode SelectedMode { + public ResetMode SelectedMode + { get; set; } - public Reset(Repository repo, Models.Branch current, Models.Commit to) { + public Reset(Repository repo, Models.Branch current, Models.Commit to) + { _repo = repo; Current = current; To = to; @@ -51,17 +61,19 @@ namespace SourceGit.ViewModels { View = new Views.Reset() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = $"Reset current branch to {To.SHA} ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Reset(_repo.FullPath, To.SHA, SelectedMode.Arg).Exec(); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } - private Repository _repo = null; + private readonly Repository _repo = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Revert.cs b/src/ViewModels/Revert.cs index ab3dd927..f13707d3 100644 --- a/src/ViewModels/Revert.cs +++ b/src/ViewModels/Revert.cs @@ -1,35 +1,42 @@ using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Revert : Popup { - public Models.Commit Target { +namespace SourceGit.ViewModels +{ + public class Revert : Popup + { + public Models.Commit Target + { get; private set; } - public bool AutoCommit { + public bool AutoCommit + { get; set; } - public Revert(Repository repo, Models.Commit target) { + public Revert(Repository repo, Models.Commit target) + { _repo = repo; Target = target; AutoCommit = true; View = new Views.Revert() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = $"Revert commit '{Target.SHA}' ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Revert(_repo.FullPath, Target.SHA, AutoCommit).Exec(); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } - private Repository _repo = null; + private readonly Repository _repo = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/RevisionCompare.cs b/src/ViewModels/RevisionCompare.cs index c85e5865..4fab38eb 100644 --- a/src/ViewModels/RevisionCompare.cs +++ b/src/ViewModels/RevisionCompare.cs @@ -1,41 +1,55 @@ -using Avalonia.Controls; -using Avalonia.Threading; -using CommunityToolkit.Mvvm.ComponentModel; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class RevisionCompare : ObservableObject { - public Models.Commit StartPoint { +using Avalonia.Controls; +using Avalonia.Threading; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class RevisionCompare : ObservableObject + { + public Models.Commit StartPoint + { get; private set; } - public Models.Commit EndPoint { + public Models.Commit EndPoint + { get; private set; } - public List VisibleChanges { + public List VisibleChanges + { get => _visibleChanges; private set => SetProperty(ref _visibleChanges, value); } - public List ChangeTree { + public List ChangeTree + { get => _changeTree; private set => SetProperty(ref _changeTree, value); } - public Models.Change SelectedChange { + public Models.Change SelectedChange + { get => _selectedChange; - set { - if (SetProperty(ref _selectedChange, value)) { - if (value == null) { + set + { + if (SetProperty(ref _selectedChange, value)) + { + if (value == null) + { SelectedNode = null; DiffContext = null; - } else { + } + else + { SelectedNode = FileTreeNode.SelectByPath(_changeTree, value.Path); DiffContext = new DiffContext(_repo, new Models.DiffOption(StartPoint.SHA, EndPoint.SHA, value)); } @@ -43,60 +57,77 @@ namespace SourceGit.ViewModels { } } - public FileTreeNode SelectedNode { + public FileTreeNode SelectedNode + { get => _selectedNode; - set { - if (SetProperty(ref _selectedNode, value)) { - if (value == null) { + set + { + if (SetProperty(ref _selectedNode, value)) + { + if (value == null) + { SelectedChange = null; - } else { + } + else + { SelectedChange = value.Backend as Models.Change; } } } } - public string SearchFilter { + public string SearchFilter + { get => _searchFilter; - set { - if (SetProperty(ref _searchFilter, value)) { + set + { + if (SetProperty(ref _searchFilter, value)) + { RefreshVisible(); } } } - public DiffContext DiffContext { + public DiffContext DiffContext + { get => _diffContext; private set => SetProperty(ref _diffContext, value); } - public RevisionCompare(string repo, Models.Commit startPoint, Models.Commit endPoint) { + public RevisionCompare(string repo, Models.Commit startPoint, Models.Commit endPoint) + { _repo = repo; StartPoint = startPoint; EndPoint = endPoint; - Task.Run(() => { + Task.Run(() => + { _changes = new Commands.CompareRevisions(_repo, startPoint.SHA, endPoint.SHA).Result(); var visible = _changes; - if (!string.IsNullOrWhiteSpace(_searchFilter)) { + if (!string.IsNullOrWhiteSpace(_searchFilter)) + { visible = new List(); - foreach (var c in _changes) { - if (c.Path.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase)) { + foreach (var c in _changes) + { + if (c.Path.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase)) + { visible.Add(c); } } } var tree = FileTreeNode.Build(visible); - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { VisibleChanges = visible; ChangeTree = tree; }); }); } - public void Cleanup() { + public void Cleanup() + { _repo = null; if (_changes != null) _changes.Clear(); if (_visibleChanges != null) _visibleChanges.Clear(); @@ -107,22 +138,27 @@ namespace SourceGit.ViewModels { _diffContext = null; } - public void NavigateTo(string commitSHA) { + public void NavigateTo(string commitSHA) + { var repo = Preference.FindRepository(_repo); if (repo != null) repo.NavigateToCommit(commitSHA); } - public void ClearSearchFilter() { + public void ClearSearchFilter() + { SearchFilter = string.Empty; } - public ContextMenu CreateChangeContextMenu(Models.Change change) { + public ContextMenu CreateChangeContextMenu(Models.Change change) + { var menu = new ContextMenu(); - if (change.Index != Models.ChangeState.Deleted) { + if (change.Index != Models.ChangeState.Deleted) + { var history = new MenuItem(); history.Header = App.Text("FileHistory"); - history.Click += (_, ev) => { + history.Click += (_, ev) => + { var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path) }; window.Show(); ev.Handled = true; @@ -132,7 +168,8 @@ namespace SourceGit.ViewModels { var explore = new MenuItem(); explore.Header = App.Text("RevealFile"); explore.IsEnabled = File.Exists(full); - explore.Click += (_, ev) => { + explore.Click += (_, ev) => + { Native.OS.OpenInFileManager(full, true); ev.Handled = true; }; @@ -143,7 +180,8 @@ namespace SourceGit.ViewModels { var copyPath = new MenuItem(); copyPath.Header = App.Text("CopyPath"); - copyPath.Click += (_, ev) => { + copyPath.Click += (_, ev) => + { App.CopyText(change.Path); ev.Handled = true; }; @@ -152,15 +190,21 @@ namespace SourceGit.ViewModels { return menu; } - private void RefreshVisible() { + private void RefreshVisible() + { if (_changes == null) return; - if (string.IsNullOrEmpty(_searchFilter)) { + if (string.IsNullOrEmpty(_searchFilter)) + { VisibleChanges = _changes; - } else { + } + else + { var visible = new List(); - foreach (var c in _changes) { - if (c.Path.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase)) { + foreach (var c in _changes) + { + if (c.Path.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase)) + { visible.Add(c); } } @@ -180,4 +224,4 @@ namespace SourceGit.ViewModels { private string _searchFilter = string.Empty; private DiffContext _diffContext = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Reword.cs b/src/ViewModels/Reword.cs index de034162..29ee4c21 100644 --- a/src/ViewModels/Reword.cs +++ b/src/ViewModels/Reword.cs @@ -1,40 +1,47 @@ using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Reword : Popup { - public Models.Commit Head { +namespace SourceGit.ViewModels +{ + public class Reword : Popup + { + public Models.Commit Head + { get; private set; } [Required(ErrorMessage = "Commit message is required!!!")] - public string Message { + public string Message + { get => _message; set => SetProperty(ref _message, value, true); } - public Reword(Repository repo, Models.Commit head) { + public Reword(Repository repo, Models.Commit head) + { _repo = repo; Head = head; Message = head.FullMessage; View = new Views.Reword() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { if (_message == Head.FullMessage) return null; _repo.SetWatcherEnabled(false); ProgressDescription = $"Editing head commit message ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Commit(_repo.FullPath, _message, true, true).Exec(); CallUIThread(() => _repo.SetWatcherEnabled(true)); return succ; }); } - private Repository _repo = null; + private readonly Repository _repo = null; private string _message = string.Empty; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Squash.cs b/src/ViewModels/Squash.cs index 1c4a5547..a1991a77 100644 --- a/src/ViewModels/Squash.cs +++ b/src/ViewModels/Squash.cs @@ -1,25 +1,31 @@ using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Squash : Popup { - public Models.Commit Head { +namespace SourceGit.ViewModels +{ + public class Squash : Popup + { + public Models.Commit Head + { get; private set; } - public Models.Commit Parent { + public Models.Commit Parent + { get; private set; } [Required(ErrorMessage = "Commit message is required!!!")] - public string Message { + public string Message + { get => _message; set => SetProperty(ref _message, value, true); } - public Squash(Repository repo, Models.Commit head, Models.Commit parent) { + public Squash(Repository repo, Models.Commit head, Models.Commit parent) + { _repo = repo; _message = parent.FullMessage; Head = head; @@ -27,11 +33,13 @@ namespace SourceGit.ViewModels { View = new Views.Squash() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { _repo.SetWatcherEnabled(false); ProgressDescription = "Squashing ..."; - return Task.Run(() => { + return Task.Run(() => + { var succ = new Commands.Reset(_repo.FullPath, Parent.SHA, "--soft").Exec(); if (succ) succ = new Commands.Commit(_repo.FullPath, _message, true).Exec(); CallUIThread(() => _repo.SetWatcherEnabled(true)); @@ -39,7 +47,7 @@ namespace SourceGit.ViewModels { }); } - private Repository _repo = null; + private readonly Repository _repo = null; private string _message = string.Empty; } -} +} \ No newline at end of file diff --git a/src/ViewModels/StashChanges.cs b/src/ViewModels/StashChanges.cs index 43d24ab5..d4c90b0b 100644 --- a/src/ViewModels/StashChanges.cs +++ b/src/ViewModels/StashChanges.cs @@ -1,39 +1,49 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class StashChanges : Popup { +namespace SourceGit.ViewModels +{ + public class StashChanges : Popup + { - public string Message { + public string Message + { get; set; } - public bool CanIgnoreUntracked { + public bool CanIgnoreUntracked + { get; private set; } - public bool IncludeUntracked { + public bool IncludeUntracked + { get; set; } - public StashChanges(Repository repo, List changes, bool canIgnoreUntracked) { + public StashChanges(Repository repo, List changes, bool canIgnoreUntracked) + { _repo = repo; _changes = changes; - + CanIgnoreUntracked = canIgnoreUntracked; IncludeUntracked = true; View = new Views.StashChanges() { DataContext = this }; } - public override Task Sure() { + public override Task Sure() + { var jobs = _changes; - if (CanIgnoreUntracked && !IncludeUntracked) { + if (CanIgnoreUntracked && !IncludeUntracked) + { jobs = new List(); - foreach (var job in _changes) { - if (job.WorkTree != Models.ChangeState.Untracked && job.WorkTree != Models.ChangeState.Added) { + foreach (var job in _changes) + { + if (job.WorkTree != Models.ChangeState.Untracked && job.WorkTree != Models.ChangeState.Added) + { jobs.Add(job); } } @@ -44,14 +54,15 @@ namespace SourceGit.ViewModels { _repo.SetWatcherEnabled(false); ProgressDescription = $"Stash changes ..."; - return Task.Run(() => { + return Task.Run(() => + { new Commands.Stash(_repo.FullPath).Push(jobs, Message); CallUIThread(() => _repo.SetWatcherEnabled(true)); return true; }); } - private Repository _repo = null; - private List _changes = null; + private readonly Repository _repo = null; + private readonly List _changes = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/StashesPage.cs b/src/ViewModels/StashesPage.cs index c3dc0d8f..a5fc75be 100644 --- a/src/ViewModels/StashesPage.cs +++ b/src/ViewModels/StashesPage.cs @@ -1,33 +1,49 @@ -using Avalonia.Threading; -using CommunityToolkit.Mvvm.ComponentModel; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class StashesPage : ObservableObject { - public int Count { +using Avalonia.Threading; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class StashesPage : ObservableObject + { + public int Count + { get => _stashes == null ? 0 : _stashes.Count; } - public List Stashes { + public List Stashes + { get => _stashes; - set { - if (SetProperty(ref _stashes, value)) { + set + { + if (SetProperty(ref _stashes, value)) + { SelectedStash = null; } } } - public Models.Stash SelectedStash { + public Models.Stash SelectedStash + { get => _selectedStash; - set { - if (SetProperty(ref _selectedStash, value)) { - if (value == null) { + set + { + if (SetProperty(ref _selectedStash, value)) + { + if (value == null) + { Changes = null; - } else { - Task.Run(() => { + } + else + { + Task.Run(() => + { var changes = new Commands.QueryStashChanges(_repo.FullPath, value.SHA).Result(); - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { Changes = changes; }); }); @@ -36,38 +52,50 @@ namespace SourceGit.ViewModels { } } - public List Changes { + public List Changes + { get => _changes; - private set { - if (SetProperty(ref _changes, value)) { + private set + { + if (SetProperty(ref _changes, value)) + { SelectedChange = null; } } } - public Models.Change SelectedChange { + public Models.Change SelectedChange + { get => _selectedChange; - set { - if (SetProperty(ref _selectedChange, value)) { - if (value == null) { + set + { + if (SetProperty(ref _selectedChange, value)) + { + if (value == null) + { DiffContext = null; - } else { + } + else + { DiffContext = new DiffContext(_repo.FullPath, new Models.DiffOption($"{_selectedStash.SHA}^", _selectedStash.SHA, value)); } } } } - public DiffContext DiffContext { + public DiffContext DiffContext + { get => _diffContext; private set => SetProperty(ref _diffContext, value); } - public StashesPage(Repository repo) { + public StashesPage(Repository repo) + { _repo = repo; } - public void Cleanup() { + public void Cleanup() + { _repo = null; if (_stashes != null) _stashes.Clear(); _selectedStash = null; @@ -76,30 +104,40 @@ namespace SourceGit.ViewModels { _diffContext = null; } - public void Apply(object param) { - if (param is Models.Stash stash) { - Task.Run(() => { + public void Apply(object param) + { + if (param is Models.Stash stash) + { + Task.Run(() => + { new Commands.Stash(_repo.FullPath).Apply(stash.Name); }); } } - public void Pop(object param) { - if (param is Models.Stash stash) { - Task.Run(() => { + public void Pop(object param) + { + if (param is Models.Stash stash) + { + Task.Run(() => + { new Commands.Stash(_repo.FullPath).Pop(stash.Name); }); } } - public void Drop(object param) { - if (param is Models.Stash stash && PopupHost.CanCreatePopup()) { + public void Drop(object param) + { + if (param is Models.Stash stash && PopupHost.CanCreatePopup()) + { PopupHost.ShowPopup(new DropStash(_repo.FullPath, stash)); - } + } } - public void Clear() { - if (PopupHost.CanCreatePopup()) { + public void Clear() + { + if (PopupHost.CanCreatePopup()) + { PopupHost.ShowPopup(new ClearStashes(_repo)); } } @@ -111,4 +149,4 @@ namespace SourceGit.ViewModels { private Models.Change _selectedChange = null; private DiffContext _diffContext = null; } -} +} \ No newline at end of file diff --git a/src/ViewModels/Statistics.cs b/src/ViewModels/Statistics.cs index 661c4e32..297efac3 100644 --- a/src/ViewModels/Statistics.cs +++ b/src/ViewModels/Statistics.cs @@ -1,32 +1,43 @@ -using Avalonia.Threading; -using CommunityToolkit.Mvvm.ComponentModel; -using System.Threading.Tasks; +using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class Statistics : ObservableObject { - public bool IsLoading { +using Avalonia.Threading; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class Statistics : ObservableObject + { + public bool IsLoading + { get => _isLoading; private set => SetProperty(ref _isLoading, value); } - public int SelectedIndex { + public int SelectedIndex + { get => _selectedIndex; - set { + set + { if (SetProperty(ref _selectedIndex, value)) RefreshReport(); } } - - public Models.StatisticsReport SelectedReport { + + public Models.StatisticsReport SelectedReport + { get => _selectedReport; private set => SetProperty(ref _selectedReport, value); } - public Statistics(string repo) { + public Statistics(string repo) + { _repo = repo; - Task.Run(() => { + Task.Run(() => + { var result = new Commands.Statistics(_repo).Result(); - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { _data = result; RefreshReport(); IsLoading = false; @@ -34,20 +45,22 @@ namespace SourceGit.ViewModels { }); } - private void RefreshReport() { + private void RefreshReport() + { if (_data == null) return; - switch (_selectedIndex) { - case 0: SelectedReport = _data.Year; break; - case 1: SelectedReport = _data.Month; break; - default: SelectedReport = _data.Week; break; + switch (_selectedIndex) + { + case 0: SelectedReport = _data.Year; break; + case 1: SelectedReport = _data.Month; break; + default: SelectedReport = _data.Week; break; } } - private string _repo = string.Empty; + private readonly string _repo = string.Empty; private bool _isLoading = true; private Models.Statistics _data = null; private Models.StatisticsReport _selectedReport = null; private int _selectedIndex = 0; } -} +} \ No newline at end of file diff --git a/src/ViewModels/TwoSideTextDiff.cs b/src/ViewModels/TwoSideTextDiff.cs index a916f54f..e96e48a8 100644 --- a/src/ViewModels/TwoSideTextDiff.cs +++ b/src/ViewModels/TwoSideTextDiff.cs @@ -1,44 +1,54 @@ -using CommunityToolkit.Mvvm.ComponentModel; -using System.Collections.Generic; +using System.Collections.Generic; -namespace SourceGit.ViewModels { - public class TwoSideTextDiff : ObservableObject { +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class TwoSideTextDiff : ObservableObject + { public string File { get; set; } = string.Empty; public List Old { get; set; } = new List(); public List New { get; set; } = new List(); public int MaxLineNumber = 0; - public TwoSideTextDiff(Models.TextDiff diff) { + public TwoSideTextDiff(Models.TextDiff diff) + { File = diff.File; MaxLineNumber = diff.MaxLineNumber; - foreach (var line in diff.Lines) { - switch (line.Type) { - case Models.TextDiffLineType.Added: - New.Add(line); - break; - case Models.TextDiffLineType.Deleted: - Old.Add(line); - break; - default: - FillEmptyLines(); - Old.Add(line); - New.Add(line); - break; + foreach (var line in diff.Lines) + { + switch (line.Type) + { + case Models.TextDiffLineType.Added: + New.Add(line); + break; + case Models.TextDiffLineType.Deleted: + Old.Add(line); + break; + default: + FillEmptyLines(); + Old.Add(line); + New.Add(line); + break; } } FillEmptyLines(); } - private void FillEmptyLines() { - if (Old.Count < New.Count) { + private void FillEmptyLines() + { + if (Old.Count < New.Count) + { int diff = New.Count - Old.Count; for (int i = 0; i < diff; i++) Old.Add(new Models.TextDiffLine()); - } else if (Old.Count > New.Count) { + } + else if (Old.Count > New.Count) + { int diff = Old.Count - New.Count; for (int i = 0; i < diff; i++) New.Add(new Models.TextDiffLine()); } } } -} +} \ No newline at end of file diff --git a/src/ViewModels/Welcome.cs b/src/ViewModels/Welcome.cs index e9e43434..4066627b 100644 --- a/src/ViewModels/Welcome.cs +++ b/src/ViewModels/Welcome.cs @@ -1,103 +1,138 @@ -using Avalonia.Collections; -using CommunityToolkit.Mvvm.ComponentModel; -using System; +using System; -namespace SourceGit.ViewModels { - public class Welcome : ObservableObject { - public bool IsClearSearchVisible { +using Avalonia.Collections; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class Welcome : ObservableObject + { + public bool IsClearSearchVisible + { get => !string.IsNullOrEmpty(_searchFilter); } - public AvaloniaList RepositoryNodes { + public AvaloniaList RepositoryNodes + { get => Preference.Instance.RepositoryNodes; } - public string SearchFilter { + public string SearchFilter + { get => _searchFilter; - set { - if (SetProperty(ref _searchFilter, value)) { + set + { + if (SetProperty(ref _searchFilter, value)) + { Referesh(); OnPropertyChanged(nameof(IsClearSearchVisible)); } } } - public void InitRepository(string path) { - if (!Preference.Instance.IsGitConfigured) { + public void InitRepository(string path) + { + if (!Preference.Instance.IsGitConfigured) + { App.RaiseException(PopupHost.Active.GetId(), App.Text("NotConfigured")); return; } - if (PopupHost.CanCreatePopup()) { + if (PopupHost.CanCreatePopup()) + { PopupHost.ShowPopup(new Init(path)); } } - public void Clone(object param) { + public void Clone(object param) + { var launcher = param as Launcher; var page = launcher.ActivePage; - if (!Preference.Instance.IsGitConfigured) { + if (!Preference.Instance.IsGitConfigured) + { App.RaiseException(page.GetId(), App.Text("NotConfigured")); return; } - if (PopupHost.CanCreatePopup()) { + if (PopupHost.CanCreatePopup()) + { PopupHost.ShowPopup(new Clone(launcher, page)); } } - public void OpenTerminal() { - if (!Preference.Instance.IsGitConfigured) { + public void OpenTerminal() + { + if (!Preference.Instance.IsGitConfigured) + { App.RaiseException(PopupHost.Active.GetId(), App.Text("NotConfigured")); - } else { + } + else + { Native.OS.OpenTerminal(null); - } + } } - public void ClearSearchFilter() { + public void ClearSearchFilter() + { SearchFilter = string.Empty; } - public void AddFolder() { + public void AddFolder() + { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateGroup(null)); } - public void MoveNode(RepositoryNode from, RepositoryNode to) { + public void MoveNode(RepositoryNode from, RepositoryNode to) + { Preference.MoveNode(from, to); } - private void Referesh() { - if (string.IsNullOrWhiteSpace(_searchFilter)) { + private void Referesh() + { + if (string.IsNullOrWhiteSpace(_searchFilter)) + { foreach (var node in RepositoryNodes) ResetVisibility(node); - } else { + } + else + { foreach (var node in RepositoryNodes) SetVisibilityBySearch(node); } } - private void ResetVisibility(RepositoryNode node) { + private void ResetVisibility(RepositoryNode node) + { node.IsVisible = true; foreach (var subNode in node.SubNodes) ResetVisibility(subNode); } - private void SetVisibilityBySearch(RepositoryNode node) { - if (!node.IsRepository) { - if (node.Name.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase)) { + private void SetVisibilityBySearch(RepositoryNode node) + { + if (!node.IsRepository) + { + if (node.Name.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase)) + { node.IsVisible = true; foreach (var subNode in node.SubNodes) ResetVisibility(subNode); - } else { + } + else + { bool hasVisibleSubNode = false; - foreach (var subNode in node.SubNodes) { + foreach (var subNode in node.SubNodes) + { SetVisibilityBySearch(subNode); hasVisibleSubNode |= subNode.IsVisible; } node.IsVisible = hasVisibleSubNode; } - } else { + } + else + { node.IsVisible = node.Name.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase); } } private string _searchFilter = string.Empty; } -} +} \ No newline at end of file diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 9ed133b3..cacaab5a 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -1,57 +1,72 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Platform.Storage; -using Avalonia.Threading; -using CommunityToolkit.Mvvm.ComponentModel; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -namespace SourceGit.ViewModels { - public class ConflictContext { +using Avalonia; +using Avalonia.Controls; +using Avalonia.Platform.Storage; +using Avalonia.Threading; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class ConflictContext + { public Models.Change Change { get; set; } } - public class WorkingCopy : ObservableObject { - public bool IsStaging { + public class WorkingCopy : ObservableObject + { + public bool IsStaging + { get => _isStaging; private set => SetProperty(ref _isStaging, value); } - public bool IsUnstaging { + public bool IsUnstaging + { get => _isUnstaging; private set => SetProperty(ref _isUnstaging, value); } - public bool IsCommitting { - get => _isCommitting; + public bool IsCommitting + { + get => _isCommitting; private set => SetProperty(ref _isCommitting, value); } - public bool UseAmend { + public bool UseAmend + { get => _useAmend; set => SetProperty(ref _useAmend, value); } - public List Unstaged { + public List Unstaged + { get => _unstaged; private set => SetProperty(ref _unstaged, value); } - public List Staged { + public List Staged + { get => _staged; private set => SetProperty(ref _staged, value); } - public int Count { + public int Count + { get => _count; } - public Models.Change SelectedUnstagedChange { + public Models.Change SelectedUnstagedChange + { get => _selectedUnstagedChange; - set { - if (SetProperty(ref _selectedUnstagedChange, value) && value != null) { + set + { + if (SetProperty(ref _selectedUnstagedChange, value) && value != null) + { SelectedStagedChange = null; SelectedStagedTreeNode = null; SetDetail(value, true); @@ -59,10 +74,13 @@ namespace SourceGit.ViewModels { } } - public Models.Change SelectedStagedChange { + public Models.Change SelectedStagedChange + { get => _selectedStagedChange; - set { - if (SetProperty(ref _selectedStagedChange, value) && value != null) { + set + { + if (SetProperty(ref _selectedStagedChange, value) && value != null) + { SelectedUnstagedChange = null; SelectedUnstagedTreeNode = null; SetDetail(value, false); @@ -70,28 +88,37 @@ namespace SourceGit.ViewModels { } } - public List UnstagedTree { - get => _unstagedTree; + public List UnstagedTree + { + get => _unstagedTree; private set => SetProperty(ref _unstagedTree, value); } - public List StagedTree { + public List StagedTree + { get => _stagedTree; private set => SetProperty(ref _stagedTree, value); } - public FileTreeNode SelectedUnstagedTreeNode { + public FileTreeNode SelectedUnstagedTreeNode + { get => _selectedUnstagedTreeNode; - set { - if (SetProperty(ref _selectedUnstagedTreeNode, value)) { - if (value == null) { + set + { + if (SetProperty(ref _selectedUnstagedTreeNode, value)) + { + if (value == null) + { SelectedUnstagedChange = null; - } else { + } + else + { SelectedUnstagedChange = value.Backend as Models.Change; SelectedStagedTreeNode = null; SelectedStagedChange = null; - if (value.IsFolder) { + if (value.IsFolder) + { SetDetail(null, true); } } @@ -99,18 +126,25 @@ namespace SourceGit.ViewModels { } } - public FileTreeNode SelectedStagedTreeNode { + public FileTreeNode SelectedStagedTreeNode + { get => _selectedStagedTreeNode; - set { - if (SetProperty(ref _selectedStagedTreeNode, value)) { - if (value == null) { + set + { + if (SetProperty(ref _selectedStagedTreeNode, value)) + { + if (value == null) + { SelectedStagedChange = null; - } else { + } + else + { SelectedStagedChange = value.Backend as Models.Change; SelectedUnstagedTreeNode = null; SelectedUnstagedChange = null; - if (value.IsFolder) { + if (value.IsFolder) + { SetDetail(null, false); } } @@ -118,21 +152,25 @@ namespace SourceGit.ViewModels { } } - public object DetailContext { + public object DetailContext + { get => _detailContext; private set => SetProperty(ref _detailContext, value); } - public string CommitMessage { + public string CommitMessage + { get => _commitMessage; set => SetProperty(ref _commitMessage, value); } - public WorkingCopy(Repository repo) { + public WorkingCopy(Repository repo) + { _repo = repo; } - public void Cleanup() { + public void Cleanup() + { _repo = null; if (_unstaged != null) _unstaged.Clear(); if (_staged != null) _staged.Clear(); @@ -146,36 +184,45 @@ namespace SourceGit.ViewModels { _commitMessage = string.Empty; } - public bool SetData(List changes) { + public bool SetData(List changes) + { var unstaged = new List(); var staged = new List(); - + var viewFile = string.Empty; var lastSelectedIsUnstaged = false; - if (_selectedUnstagedChange != null) { + if (_selectedUnstagedChange != null) + { viewFile = _selectedUnstagedChange.Path; lastSelectedIsUnstaged = true; - } else if (_selectedStagedChange != null) { + } + else if (_selectedStagedChange != null) + { viewFile = _selectedStagedChange.Path; } var viewChange = null as Models.Change; var hasConflict = false; - foreach (var c in changes) { + foreach (var c in changes) + { if (c.Index == Models.ChangeState.Modified || c.Index == Models.ChangeState.Added || c.Index == Models.ChangeState.Deleted - || c.Index == Models.ChangeState.Renamed) { + || c.Index == Models.ChangeState.Renamed) + { staged.Add(c); - if (!lastSelectedIsUnstaged && c.Path == viewFile) { + if (!lastSelectedIsUnstaged && c.Path == viewFile) + { viewChange = c; } } - if (c.WorkTree != Models.ChangeState.None) { + if (c.WorkTree != Models.ChangeState.None) + { unstaged.Add(c); hasConflict |= c.IsConflit; - if (lastSelectedIsUnstaged && c.Path == viewFile) { + if (lastSelectedIsUnstaged && c.Path == viewFile) + { viewChange = c; } } @@ -185,7 +232,8 @@ namespace SourceGit.ViewModels { var unstagedTree = FileTreeNode.Build(unstaged); var stagedTree = FileTreeNode.Build(staged); - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { _isLoadingData = true; Unstaged = unstaged; Staged = staged; @@ -194,20 +242,26 @@ namespace SourceGit.ViewModels { _isLoadingData = false; // Restore last selection states. - if (viewChange != null) { + if (viewChange != null) + { var scrollOffset = Vector.Zero; if (_detailContext is DiffContext old) scrollOffset = old.SyncScrollOffset; - if (lastSelectedIsUnstaged) { + if (lastSelectedIsUnstaged) + { SelectedUnstagedChange = viewChange; SelectedUnstagedTreeNode = FileTreeNode.SelectByPath(_unstagedTree, viewFile); - } else { + } + else + { SelectedStagedChange = viewChange; SelectedStagedTreeNode = FileTreeNode.SelectByPath(_stagedTree, viewFile); } if (_detailContext is DiffContext cur) cur.SyncScrollOffset = scrollOffset; - } else { + } + else + { SelectedUnstagedChange = null; SelectedUnstagedTreeNode = null; SelectedStagedChange = null; @@ -219,28 +273,39 @@ namespace SourceGit.ViewModels { return hasConflict; } - public void SetDetail(Models.Change change, bool isUnstaged) { + public void SetDetail(Models.Change change, bool isUnstaged) + { if (_isLoadingData) return; - if (change == null) { + if (change == null) + { DetailContext = null; - } else if (change.IsConflit) { + } + else if (change.IsConflit) + { DetailContext = new ConflictContext() { Change = change }; - } else { + } + else + { DetailContext = new DiffContext(_repo.FullPath, new Models.DiffOption(change, isUnstaged)); } } - public async void StageChanges(List changes) { + public async void StageChanges(List changes) + { if (_unstaged.Count == 0 || changes.Count == 0) return; SetDetail(null, true); IsStaging = true; _repo.SetWatcherEnabled(false); - if (changes.Count == _unstaged.Count) { + if (changes.Count == _unstaged.Count) + { await Task.Run(() => new Commands.Add(_repo.FullPath).Exec()); - } else { - for (int i = 0; i < changes.Count; i += 10) { + } + else + { + for (int i = 0; i < changes.Count; i += 10) + { var count = Math.Min(10, changes.Count - i); var step = changes.GetRange(i, count); await Task.Run(() => new Commands.Add(_repo.FullPath, step).Exec()); @@ -251,16 +316,21 @@ namespace SourceGit.ViewModels { IsStaging = false; } - public async void UnstageChanges(List changes) { + public async void UnstageChanges(List changes) + { if (_staged.Count == 0 || changes.Count == 0) return; SetDetail(null, false); IsUnstaging = true; _repo.SetWatcherEnabled(false); - if (changes.Count == _staged.Count) { + if (changes.Count == _staged.Count) + { await Task.Run(() => new Commands.Reset(_repo.FullPath).Exec()); - } else { - for (int i = 0; i < changes.Count; i += 10) { + } + else + { + for (int i = 0; i < changes.Count; i += 10) + { var count = Math.Min(10, changes.Count - i); var step = changes.GetRange(i, count); await Task.Run(() => new Commands.Reset(_repo.FullPath, step).Exec()); @@ -271,29 +341,43 @@ namespace SourceGit.ViewModels { IsUnstaging = false; } - public void Discard(List changes, bool isUnstaged) { - if (PopupHost.CanCreatePopup()) { - if (isUnstaged) { - if (changes.Count == _unstaged.Count && _staged.Count == 0) { + public void Discard(List changes, bool isUnstaged) + { + if (PopupHost.CanCreatePopup()) + { + if (isUnstaged) + { + if (changes.Count == _unstaged.Count && _staged.Count == 0) + { PopupHost.ShowPopup(new Discard(_repo)); - } else { + } + else + { PopupHost.ShowPopup(new Discard(_repo, changes, true)); } - } else { - if (changes.Count == _staged.Count && _unstaged.Count == 0) { + } + else + { + if (changes.Count == _staged.Count && _unstaged.Count == 0) + { PopupHost.ShowPopup(new Discard(_repo)); - } else { + } + else + { PopupHost.ShowPopup(new Discard(_repo, changes, false)); } } - } + } } - public async void UseTheirs() { - if (_detailContext is ConflictContext ctx) { + public async void UseTheirs() + { + if (_detailContext is ConflictContext ctx) + { _repo.SetWatcherEnabled(false); var succ = await Task.Run(() => new Commands.Checkout(_repo.FullPath).File(ctx.Change.Path, true)); - if (succ) { + if (succ) + { await Task.Run(() => new Commands.Add(_repo.FullPath, [ctx.Change]).Exec()); } _repo.MarkWorkingCopyDirtyManually(); @@ -301,11 +385,14 @@ namespace SourceGit.ViewModels { } } - public async void UseMine() { - if (_detailContext is ConflictContext ctx) { + public async void UseMine() + { + if (_detailContext is ConflictContext ctx) + { _repo.SetWatcherEnabled(false); var succ = await Task.Run(() => new Commands.Checkout(_repo.FullPath).File(ctx.Change.Path, false)); - if (succ) { + if (succ) + { await Task.Run(() => new Commands.Add(_repo.FullPath, [ctx.Change]).Exec()); } _repo.MarkWorkingCopyDirtyManually(); @@ -313,13 +400,16 @@ namespace SourceGit.ViewModels { } } - public async void UseExternalMergeTool() { - if (_detailContext is ConflictContext ctx) { + public async void UseExternalMergeTool() + { + if (_detailContext is ConflictContext ctx) + { var type = Preference.Instance.ExternalMergeToolType; var exec = Preference.Instance.ExternalMergeToolPath; var tool = Models.ExternalMergeTools.Supported.Find(x => x.Type == type); - if (tool == null) { + if (tool == null) + { App.RaiseException(_repo.FullPath, "Invalid merge tool in preference setting!"); return; } @@ -332,18 +422,22 @@ namespace SourceGit.ViewModels { } } - public async void DoCommit(bool autoPush) { - if (!PopupHost.CanCreatePopup()) { + public async void DoCommit(bool autoPush) + { + if (!PopupHost.CanCreatePopup()) + { App.RaiseException(_repo.FullPath, "Repository has unfinished job! Please wait!"); return; } - if (_staged.Count == 0) { + if (_staged.Count == 0) + { App.RaiseException(_repo.FullPath, "No files added to commit!"); return; } - if (string.IsNullOrWhiteSpace(_commitMessage)) { + if (string.IsNullOrWhiteSpace(_commitMessage)) + { App.RaiseException(_repo.FullPath, "Commit without message is NOT allowed!"); return; } @@ -354,11 +448,13 @@ namespace SourceGit.ViewModels { IsCommitting = true; _repo.SetWatcherEnabled(false); var succ = await Task.Run(() => new Commands.Commit(_repo.FullPath, _commitMessage, _useAmend).Exec()); - if (succ) { + if (succ) + { CommitMessage = string.Empty; UseAmend = false; - if (autoPush) { + if (autoPush) + { PopupHost.ShowAndStartPopup(new Push(_repo, null)); } } @@ -367,11 +463,13 @@ namespace SourceGit.ViewModels { IsCommitting = false; } - public ContextMenu CreateContextMenuForUnstagedChanges(List changes) { + public ContextMenu CreateContextMenuForUnstagedChanges(List changes) + { if (changes.Count == 0) return null; var menu = new ContextMenu(); - if (changes.Count == 1) { + if (changes.Count == 1) + { var change = changes[0]; var path = Path.GetFullPath(Path.Combine(_repo.FullPath, change.Path)); @@ -379,16 +477,18 @@ namespace SourceGit.ViewModels { explore.Header = App.Text("RevealFile"); explore.Icon = App.CreateMenuIcon("Icons.Folder.Open"); explore.IsEnabled = File.Exists(path) || Directory.Exists(path); - explore.Click += (_, e) => { + explore.Click += (_, e) => + { Native.OS.OpenInFileManager(path, true); e.Handled = true; }; - + var openWith = new MenuItem(); openWith.Header = App.Text("OpenWith"); openWith.Icon = App.CreateMenuIcon("Icons.OpenWith"); openWith.IsEnabled = File.Exists(path); - openWith.Click += (_, e) => { + openWith.Click += (_, e) => + { Native.OS.OpenWithDefaultEditor(path); e.Handled = true; }; @@ -396,7 +496,8 @@ namespace SourceGit.ViewModels { var stage = new MenuItem(); stage.Header = App.Text("FileCM.Stage"); stage.Icon = App.CreateMenuIcon("Icons.File.Add"); - stage.Click += (_, e) => { + stage.Click += (_, e) => + { StageChanges(changes); e.Handled = true; }; @@ -404,7 +505,8 @@ namespace SourceGit.ViewModels { var discard = new MenuItem(); discard.Header = App.Text("FileCM.Discard"); discard.Icon = App.CreateMenuIcon("Icons.Undo"); - discard.Click += (_, e) => { + discard.Click += (_, e) => + { Discard(changes, true); e.Handled = true; }; @@ -412,8 +514,10 @@ namespace SourceGit.ViewModels { var stash = new MenuItem(); stash.Header = App.Text("FileCM.Stash"); stash.Icon = App.CreateMenuIcon("Icons.Stashes"); - stash.Click += (_, e) => { - if (PopupHost.CanCreatePopup()) { + stash.Click += (_, e) => + { + if (PopupHost.CanCreatePopup()) + { PopupHost.ShowPopup(new StashChanges(_repo, changes, false)); } e.Handled = true; @@ -422,7 +526,8 @@ namespace SourceGit.ViewModels { var patch = new MenuItem(); patch.Header = App.Text("FileCM.SaveAsPatch"); patch.Icon = App.CreateMenuIcon("Icons.Diff"); - patch.Click += async (_, e) => { + patch.Click += async (_, e) => + { var topLevel = App.GetTopLevel(); if (topLevel == null) return; @@ -432,7 +537,8 @@ namespace SourceGit.ViewModels { options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; var storageFile = await topLevel.StorageProvider.SaveFilePickerAsync(options); - if (storageFile != null) { + if (storageFile != null) + { var succ = await Task.Run(() => Commands.SaveChangesAsPatch.Exec(_repo.FullPath, changes, true, storageFile.Path.LocalPath)); if (succ) App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess")); } @@ -443,7 +549,8 @@ namespace SourceGit.ViewModels { var history = new MenuItem(); history.Header = App.Text("FileHistory"); history.Icon = App.CreateMenuIcon("Icons.Histories"); - history.Click += (_, e) => { + history.Click += (_, e) => + { var window = new Views.FileHistories() { DataContext = new FileHistories(_repo.FullPath, change.Path) }; window.Show(); e.Handled = true; @@ -453,7 +560,8 @@ namespace SourceGit.ViewModels { assumeUnchanged.Header = App.Text("FileCM.AssumeUnchanged"); assumeUnchanged.Icon = App.CreateMenuIcon("Icons.File.Ignore"); assumeUnchanged.IsEnabled = change.WorkTree != Models.ChangeState.Untracked; - assumeUnchanged.Click += (_, e) => { + assumeUnchanged.Click += (_, e) => + { new Commands.AssumeUnchanged(_repo.FullPath).Add(change.Path); e.Handled = true; }; @@ -461,7 +569,8 @@ namespace SourceGit.ViewModels { var copy = new MenuItem(); copy.Header = App.Text("CopyPath"); copy.Icon = App.CreateMenuIcon("Icons.Copy"); - copy.Click += (_, e) => { + copy.Click += (_, e) => + { App.CopyText(change.Path); e.Handled = true; }; @@ -478,11 +587,14 @@ namespace SourceGit.ViewModels { menu.Items.Add(assumeUnchanged); menu.Items.Add(new MenuItem() { Header = "-" }); menu.Items.Add(copy); - } else { + } + else + { var stage = new MenuItem(); stage.Header = App.Text("FileCM.StageMulti", changes.Count); stage.Icon = App.CreateMenuIcon("Icons.File.Add"); - stage.Click += (_, e) => { + stage.Click += (_, e) => + { StageChanges(changes); e.Handled = true; }; @@ -490,7 +602,8 @@ namespace SourceGit.ViewModels { var discard = new MenuItem(); discard.Header = App.Text("FileCM.DiscardMulti", changes.Count); discard.Icon = App.CreateMenuIcon("Icons.Undo"); - discard.Click += (_, e) => { + discard.Click += (_, e) => + { Discard(changes, true); e.Handled = true; }; @@ -498,8 +611,10 @@ namespace SourceGit.ViewModels { var stash = new MenuItem(); stash.Header = App.Text("FileCM.StashMulti", changes.Count); stash.Icon = App.CreateMenuIcon("Icons.Stashes"); - stash.Click += (_, e) => { - if (PopupHost.CanCreatePopup()) { + stash.Click += (_, e) => + { + if (PopupHost.CanCreatePopup()) + { PopupHost.ShowPopup(new StashChanges(_repo, changes, false)); } e.Handled = true; @@ -508,7 +623,8 @@ namespace SourceGit.ViewModels { var patch = new MenuItem(); patch.Header = App.Text("FileCM.SaveAsPatch"); patch.Icon = App.CreateMenuIcon("Icons.Diff"); - patch.Click += async (o, e) => { + patch.Click += async (o, e) => + { var topLevel = App.GetTopLevel(); if (topLevel == null) return; @@ -516,9 +632,10 @@ namespace SourceGit.ViewModels { options.Title = App.Text("FileCM.SaveAsPatch"); options.DefaultExtension = ".patch"; options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; - + var storageFile = await topLevel.StorageProvider.SaveFilePickerAsync(options); - if (storageFile != null) { + if (storageFile != null) + { var succ = await Task.Run(() => Commands.SaveChangesAsPatch.Exec(_repo.FullPath, changes, true, storageFile.Path.LocalPath)); if (succ) App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess")); } @@ -530,16 +647,18 @@ namespace SourceGit.ViewModels { menu.Items.Add(discard); menu.Items.Add(stash); menu.Items.Add(patch); - } + } return menu; } - public ContextMenu CreateContextMenuForStagedChanges(List changes) { + public ContextMenu CreateContextMenuForStagedChanges(List changes) + { if (changes.Count == 0) return null; var menu = new ContextMenu(); - if (changes.Count == 1) { + if (changes.Count == 1) + { var change = changes[0]; var path = Path.GetFullPath(Path.Combine(_repo.FullPath, change.Path)); @@ -547,7 +666,8 @@ namespace SourceGit.ViewModels { explore.IsEnabled = File.Exists(path) || Directory.Exists(path); explore.Header = App.Text("RevealFile"); explore.Icon = App.CreateMenuIcon("Icons.Folder.Open"); - explore.Click += (o, e) => { + explore.Click += (o, e) => + { Native.OS.OpenInFileManager(path, true); e.Handled = true; }; @@ -556,7 +676,8 @@ namespace SourceGit.ViewModels { openWith.Header = App.Text("OpenWith"); openWith.Icon = App.CreateMenuIcon("Icons.OpenWith"); openWith.IsEnabled = File.Exists(path); - openWith.Click += (_, e) => { + openWith.Click += (_, e) => + { Native.OS.OpenWithDefaultEditor(path); e.Handled = true; }; @@ -564,7 +685,8 @@ namespace SourceGit.ViewModels { var unstage = new MenuItem(); unstage.Header = App.Text("FileCM.Unstage"); unstage.Icon = App.CreateMenuIcon("Icons.File.Remove"); - unstage.Click += (o, e) => { + unstage.Click += (o, e) => + { UnstageChanges(changes); e.Handled = true; }; @@ -572,7 +694,8 @@ namespace SourceGit.ViewModels { var discard = new MenuItem(); discard.Header = App.Text("FileCM.Discard"); discard.Icon = App.CreateMenuIcon("Icons.Undo"); - discard.Click += (_, e) => { + discard.Click += (_, e) => + { Discard(changes, false); e.Handled = true; }; @@ -580,8 +703,10 @@ namespace SourceGit.ViewModels { var stash = new MenuItem(); stash.Header = App.Text("FileCM.Stash"); stash.Icon = App.CreateMenuIcon("Icons.Stashes"); - stash.Click += (_, e) => { - if (PopupHost.CanCreatePopup()) { + stash.Click += (_, e) => + { + if (PopupHost.CanCreatePopup()) + { PopupHost.ShowPopup(new StashChanges(_repo, changes, false)); } e.Handled = true; @@ -590,7 +715,8 @@ namespace SourceGit.ViewModels { var patch = new MenuItem(); patch.Header = App.Text("FileCM.SaveAsPatch"); patch.Icon = App.CreateMenuIcon("Icons.Diff"); - patch.Click += async (o, e) => { + patch.Click += async (o, e) => + { var topLevel = App.GetTopLevel(); if (topLevel == null) return; @@ -600,7 +726,8 @@ namespace SourceGit.ViewModels { options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; var storageFile = await topLevel.StorageProvider.SaveFilePickerAsync(options); - if (storageFile != null) { + if (storageFile != null) + { var succ = await Task.Run(() => Commands.SaveChangesAsPatch.Exec(_repo.FullPath, changes, false, storageFile.Path.LocalPath)); if (succ) App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess")); } @@ -611,7 +738,8 @@ namespace SourceGit.ViewModels { var copyPath = new MenuItem(); copyPath.Header = App.Text("CopyPath"); copyPath.Icon = App.CreateMenuIcon("Icons.Copy"); - copyPath.Click += (o, e) => { + copyPath.Click += (o, e) => + { App.CopyText(change.Path); e.Handled = true; }; @@ -625,11 +753,14 @@ namespace SourceGit.ViewModels { menu.Items.Add(patch); menu.Items.Add(new MenuItem() { Header = "-" }); menu.Items.Add(copyPath); - } else { + } + else + { var unstage = new MenuItem(); unstage.Header = App.Text("FileCM.UnstageMulti", changes.Count); unstage.Icon = App.CreateMenuIcon("Icons.File.Remove"); - unstage.Click += (o, e) => { + unstage.Click += (o, e) => + { UnstageChanges(changes); e.Handled = true; }; @@ -637,7 +768,8 @@ namespace SourceGit.ViewModels { var discard = new MenuItem(); discard.Header = App.Text("FileCM.DiscardMulti", changes.Count); discard.Icon = App.CreateMenuIcon("Icons.Undo"); - discard.Click += (_, e) => { + discard.Click += (_, e) => + { Discard(changes, false); e.Handled = true; }; @@ -645,8 +777,10 @@ namespace SourceGit.ViewModels { var stash = new MenuItem(); stash.Header = App.Text("FileCM.StashMulti", changes.Count); stash.Icon = App.CreateMenuIcon("Icons.Stashes"); - stash.Click += (_, e) => { - if (PopupHost.CanCreatePopup()) { + stash.Click += (_, e) => + { + if (PopupHost.CanCreatePopup()) + { PopupHost.ShowPopup(new StashChanges(_repo, changes, false)); } e.Handled = true; @@ -655,7 +789,8 @@ namespace SourceGit.ViewModels { var patch = new MenuItem(); patch.Header = App.Text("FileCM.SaveAsPatch"); patch.Icon = App.CreateMenuIcon("Icons.Diff"); - patch.Click += async (_, e) => { + patch.Click += async (_, e) => + { var topLevel = App.GetTopLevel(); if (topLevel == null) return; @@ -665,7 +800,8 @@ namespace SourceGit.ViewModels { options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; var storageFile = await topLevel.StorageProvider.SaveFilePickerAsync(options); - if (storageFile != null) { + if (storageFile != null) + { var succ = await Task.Run(() => Commands.SaveChangesAsPatch.Exec(_repo.FullPath, changes, false, storageFile.Path.LocalPath)); if (succ) App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess")); } @@ -682,9 +818,11 @@ namespace SourceGit.ViewModels { return menu; } - public ContextMenu CreateContextMenuForCommitMessages() { + public ContextMenu CreateContextMenuForCommitMessages() + { var menu = new ContextMenu(); - if (_repo.CommitMessages.Count == 0) { + if (_repo.CommitMessages.Count == 0) + { var empty = new MenuItem(); empty.Header = App.Text("WorkingCopy.NoCommitHistories"); empty.IsEnabled = false; @@ -698,12 +836,14 @@ namespace SourceGit.ViewModels { menu.Items.Add(tip); menu.Items.Add(new MenuItem() { Header = "-" }); - foreach (var message in _repo.CommitMessages) { + foreach (var message in _repo.CommitMessages) + { var dump = message; var item = new MenuItem(); item.Header = dump; - item.Click += (o, e) => { + item.Click += (o, e) => + { CommitMessage = dump; e.Handled = true; }; @@ -714,16 +854,21 @@ namespace SourceGit.ViewModels { return menu; } - private void PushCommitMessage() { + private void PushCommitMessage() + { var existIdx = _repo.CommitMessages.IndexOf(CommitMessage); - if (existIdx == 0) { + if (existIdx == 0) + { return; - } else if (existIdx > 0) { + } + else if (existIdx > 0) + { _repo.CommitMessages.Move(existIdx, 0); return; } - if (_repo.CommitMessages.Count > 9) { + if (_repo.CommitMessages.Count > 9) + { _repo.CommitMessages.RemoveRange(9, _repo.CommitMessages.Count - 9); } @@ -748,4 +893,4 @@ namespace SourceGit.ViewModels { private object _detailContext = null; private string _commitMessage = string.Empty; } -} +} \ No newline at end of file diff --git a/src/Views/About.axaml.cs b/src/Views/About.axaml.cs index 955e2c05..54bd8c5b 100644 --- a/src/Views/About.axaml.cs +++ b/src/Views/About.axaml.cs @@ -1,43 +1,53 @@ +using System.Reflection; + using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; -using System.Reflection; -namespace SourceGit.Views { - public partial class About : Window { - public string Version { +namespace SourceGit.Views +{ + public partial class About : Window + { + public string Version + { get; private set; } - public About() { + public About() + { var ver = Assembly.GetExecutingAssembly().GetName().Version; Version = $"{ver.Major}.{ver.Minor}"; DataContext = this; InitializeComponent(); } - private void BeginMoveWindow(object sender, PointerPressedEventArgs e) { + private void BeginMoveWindow(object sender, PointerPressedEventArgs e) + { BeginMoveDrag(e); } - private void CloseWindow(object sender, RoutedEventArgs e) { + private void CloseWindow(object sender, RoutedEventArgs e) + { Close(); } - private void OnVisitAvaloniaUI(object sender, PointerPressedEventArgs e) { + private void OnVisitAvaloniaUI(object sender, PointerPressedEventArgs e) + { Native.OS.OpenBrowser("https://www.avaloniaui.net/"); e.Handled = true; } - private void OnVisitAvaloniaEdit(object sender, PointerPressedEventArgs e) { + private void OnVisitAvaloniaEdit(object sender, PointerPressedEventArgs e) + { Native.OS.OpenBrowser("https://github.com/AvaloniaUI/AvaloniaEdit"); e.Handled = true; } - private void OnVisitJetBrainsMonoFont(object sender, PointerPressedEventArgs e) { + private void OnVisitJetBrainsMonoFont(object sender, PointerPressedEventArgs e) + { Native.OS.OpenBrowser("https://www.jetbrains.com/lp/mono/"); e.Handled = true; } } -} +} \ No newline at end of file diff --git a/src/Views/AddRemote.axaml.cs b/src/Views/AddRemote.axaml.cs index f3640e30..b8ed0186 100644 --- a/src/Views/AddRemote.axaml.cs +++ b/src/Views/AddRemote.axaml.cs @@ -2,21 +2,26 @@ using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.Platform.Storage; -namespace SourceGit.Views { - public partial class AddRemote : UserControl { - public AddRemote() { +namespace SourceGit.Views +{ + public partial class AddRemote : UserControl + { + public AddRemote() + { InitializeComponent(); } - private async void SelectSSHKey(object sender, RoutedEventArgs e) { + private async void SelectSSHKey(object sender, RoutedEventArgs e) + { var options = new FilePickerOpenOptions() { AllowMultiple = false, FileTypeFilter = [new FilePickerFileType("SSHKey") { Patterns = ["*.*"] }] }; var toplevel = TopLevel.GetTopLevel(this); var selected = await toplevel.StorageProvider.OpenFilePickerAsync(options); - if (selected.Count == 1) { + if (selected.Count == 1) + { txtSSHKey.Text = selected[0].Path.LocalPath; } e.Handled = true; } } -} +} \ No newline at end of file diff --git a/src/Views/AddSubmodule.axaml.cs b/src/Views/AddSubmodule.axaml.cs index 358faaa7..e6cd6573 100644 --- a/src/Views/AddSubmodule.axaml.cs +++ b/src/Views/AddSubmodule.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class AddSubmodule : UserControl { - public AddSubmodule() { +namespace SourceGit.Views +{ + public partial class AddSubmodule : UserControl + { + public AddSubmodule() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/Apply.axaml.cs b/src/Views/Apply.axaml.cs index 3f61a4dd..955aaa77 100644 --- a/src/Views/Apply.axaml.cs +++ b/src/Views/Apply.axaml.cs @@ -2,23 +2,28 @@ using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.Platform.Storage; -namespace SourceGit.Views { - public partial class Apply : UserControl { - public Apply() { +namespace SourceGit.Views +{ + public partial class Apply : UserControl + { + public Apply() + { InitializeComponent(); } - private async void SelectPatchFile(object sender, RoutedEventArgs e) { + private async void SelectPatchFile(object sender, RoutedEventArgs e) + { var topLevel = TopLevel.GetTopLevel(this); if (topLevel == null) return; - var options = new FilePickerOpenOptions() { AllowMultiple = false, FileTypeFilter = [ new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }] }; + var options = new FilePickerOpenOptions() { AllowMultiple = false, FileTypeFilter = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }] }; var selected = await topLevel.StorageProvider.OpenFilePickerAsync(options); - if (selected.Count == 1) { + if (selected.Count == 1) + { txtPatchFile.Text = selected[0].Path.LocalPath; } e.Handled = true; } } -} +} \ No newline at end of file diff --git a/src/Views/Archive.axaml.cs b/src/Views/Archive.axaml.cs index 63e73448..22e92f0a 100644 --- a/src/Views/Archive.axaml.cs +++ b/src/Views/Archive.axaml.cs @@ -2,21 +2,26 @@ using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.Platform.Storage; -namespace SourceGit.Views { - public partial class Archive : UserControl { - public Archive() { +namespace SourceGit.Views +{ + public partial class Archive : UserControl + { + public Archive() + { InitializeComponent(); } - private async void SelectOutputFile(object sender, RoutedEventArgs e) { - var options = new FilePickerSaveOptions() { DefaultExtension = ".zip", FileTypeChoices = [ new FilePickerFileType("ZIP") { Patterns = [ "*.zip" ]}] }; + private async void SelectOutputFile(object sender, RoutedEventArgs e) + { + var options = new FilePickerSaveOptions() { DefaultExtension = ".zip", FileTypeChoices = [new FilePickerFileType("ZIP") { Patterns = ["*.zip"] }] }; var toplevel = TopLevel.GetTopLevel(this); var selected = await toplevel.StorageProvider.SaveFilePickerAsync(options); - if (selected != null) { + if (selected != null) + { txtSaveFile.Text = selected.Path.LocalPath; } e.Handled = true; } } -} +} \ No newline at end of file diff --git a/src/Views/AssumeUnchangedManager.axaml.cs b/src/Views/AssumeUnchangedManager.axaml.cs index 32bf574e..cb74b3ac 100644 --- a/src/Views/AssumeUnchangedManager.axaml.cs +++ b/src/Views/AssumeUnchangedManager.axaml.cs @@ -2,18 +2,23 @@ using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; -namespace SourceGit.Views { - public partial class AssumeUnchangedManager : Window { - public AssumeUnchangedManager() { +namespace SourceGit.Views +{ + public partial class AssumeUnchangedManager : Window + { + public AssumeUnchangedManager() + { InitializeComponent(); } - private void BeginMoveWindow(object sender, PointerPressedEventArgs e) { + private void BeginMoveWindow(object sender, PointerPressedEventArgs e) + { BeginMoveDrag(e); } - private void CloseWindow(object sender, RoutedEventArgs e) { + private void CloseWindow(object sender, RoutedEventArgs e) + { Close(); } } -} +} \ No newline at end of file diff --git a/src/Views/Avatar.cs b/src/Views/Avatar.cs index b7643ca4..61060cfb 100644 --- a/src/Views/Avatar.cs +++ b/src/Views/Avatar.cs @@ -1,14 +1,17 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Media; -using System; +using System; using System.Globalization; using System.Security.Cryptography; using System.Text; -namespace SourceGit.Views { - public class Avatar : Control, Models.IAvatarHost { +using Avalonia; +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Media; + +namespace SourceGit.Views +{ + public class Avatar : Control, Models.IAvatarHost + { private static readonly GradientStops[] FALLBACK_GRADIENTS = [ new GradientStops() { new GradientStop(Colors.Orange, 0), new GradientStop(Color.FromRgb(255, 213, 134), 1) }, new GradientStops() { new GradientStop(Colors.DodgerBlue, 0), new GradientStop(Colors.LightSkyBlue, 1) }, @@ -20,19 +23,24 @@ namespace SourceGit.Views { public static readonly StyledProperty UserProperty = AvaloniaProperty.Register(nameof(User)); - public Models.User User { + public Models.User User + { get => GetValue(UserProperty); set => SetValue(UserProperty, value); } - static Avatar() { + static Avatar() + { UserProperty.Changed.AddClassHandler(OnUserPropertyChanged); } - public Avatar() { + public Avatar() + { var refetch = new MenuItem() { Header = App.Text("RefetchAvatar") }; - refetch.Click += (o, e) => { - if (User != null) { + refetch.Click += (o, e) => + { + if (User != null) + { Models.AvatarManager.Request(_emailMD5, true); InvalidateVisual(); } @@ -42,40 +50,50 @@ namespace SourceGit.Views { ContextMenu.Items.Add(refetch); } - public override void Render(DrawingContext context) { + public override void Render(DrawingContext context) + { if (User == null) return; var corner = (float)Math.Max(2, Bounds.Width / 16); var img = Models.AvatarManager.Request(_emailMD5, false); - if (img != null) { + if (img != null) + { var rect = new Rect(0, 0, Bounds.Width, Bounds.Height); context.PushClip(new RoundedRect(rect, corner)); context.DrawImage(img, rect); - } else { + } + else + { Point textOrigin = new Point((Bounds.Width - _fallbackLabel.Width) * 0.5, (Bounds.Height - _fallbackLabel.Height) * 0.5); context.DrawRectangle(_fallbackBrush, null, new Rect(0, 0, Bounds.Width, Bounds.Height), corner, corner); context.DrawText(_fallbackLabel, textOrigin); - } + } } - public void OnAvatarResourceChanged(string md5) { - if (_emailMD5 == md5) { + public void OnAvatarResourceChanged(string md5) + { + if (_emailMD5 == md5) + { InvalidateVisual(); } } - protected override void OnLoaded(RoutedEventArgs e) { + protected override void OnLoaded(RoutedEventArgs e) + { base.OnLoaded(e); Models.AvatarManager.Subscribe(this); } - protected override void OnUnloaded(RoutedEventArgs e) { + protected override void OnUnloaded(RoutedEventArgs e) + { base.OnUnloaded(e); Models.AvatarManager.Unsubscribe(this); } - private static void OnUserPropertyChanged(Avatar avatar, AvaloniaPropertyChangedEventArgs e) { - if (avatar.User == null) { + private static void OnUserPropertyChanged(Avatar avatar, AvaloniaPropertyChangedEventArgs e) + { + if (avatar.User == null) + { avatar._emailMD5 = null; return; } @@ -91,7 +109,8 @@ namespace SourceGit.Views { var md5 = builder.ToString(); if (avatar._emailMD5 != md5) avatar._emailMD5 = md5; - avatar._fallbackBrush = new LinearGradientBrush { + avatar._fallbackBrush = new LinearGradientBrush + { GradientStops = FALLBACK_GRADIENTS[sum % FALLBACK_GRADIENTS.Length], StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), @@ -100,8 +119,8 @@ namespace SourceGit.Views { var typeface = new Typeface("fonts:SourceGit#JetBrains Mono"); avatar._fallbackLabel = new FormattedText( - placeholder, - CultureInfo.CurrentCulture, + placeholder, + CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, avatar.Width * 0.65, @@ -114,4 +133,4 @@ namespace SourceGit.Views { private LinearGradientBrush _fallbackBrush = null; private string _emailMD5 = null; } -} +} \ No newline at end of file diff --git a/src/Views/Blame.axaml.cs b/src/Views/Blame.axaml.cs index 91693a68..c98f6d9a 100644 --- a/src/Views/Blame.axaml.cs +++ b/src/Views/Blame.axaml.cs @@ -1,39 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; + using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Media; -using Avalonia.Controls; -using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Styling; + using AvaloniaEdit; using AvaloniaEdit.Document; using AvaloniaEdit.Editing; using AvaloniaEdit.Rendering; using AvaloniaEdit.TextMate; using AvaloniaEdit.Utils; -using System; -using System.Globalization; -using System.IO; -using TextMateSharp.Grammars; -using System.Collections.Generic; -namespace SourceGit.Views { - public class BlameTextEditor : TextEditor { - public class CommitInfoMargin : AbstractMargin { - public CommitInfoMargin(BlameTextEditor editor) { +using TextMateSharp.Grammars; + +namespace SourceGit.Views +{ + public class BlameTextEditor : TextEditor + { + public class CommitInfoMargin : AbstractMargin + { + public CommitInfoMargin(BlameTextEditor editor) + { _editor = editor; ClipToBounds = true; } - public override void Render(DrawingContext context) { + public override void Render(DrawingContext context) + { if (_editor.BlameData == null) return; var view = TextView; - if (view != null && view.VisualLinesValid) { + if (view != null && view.VisualLinesValid) + { var typeface = view.CreateTypeface(); var underlinePen = new Pen(Brushes.DarkOrange, 1); - foreach (var line in view.VisualLines) { + foreach (var line in view.VisualLines) + { var lineNumber = line.FirstDocumentLine.LineNumber; if (lineNumber > _editor.BlameData.LineInfos.Count) break; @@ -75,13 +85,16 @@ namespace SourceGit.Views { } } - protected override Size MeasureOverride(Size availableSize) { + protected override Size MeasureOverride(Size availableSize) + { var view = TextView; var maxWidth = 0.0; - if (view != null && view.VisualLinesValid && _editor.BlameData != null) { + if (view != null && view.VisualLinesValid && _editor.BlameData != null) + { var typeface = view.CreateTypeface(); var calculated = new HashSet(); - foreach (var line in view.VisualLines) { + foreach (var line in view.VisualLines) + { var lineNumber = line.FirstDocumentLine.LineNumber; if (lineNumber > _editor.BlameData.LineInfos.Count) break; @@ -125,15 +138,18 @@ namespace SourceGit.Views { return new Size(maxWidth, 0); } - protected override void OnPointerPressed(PointerPressedEventArgs e) { + protected override void OnPointerPressed(PointerPressedEventArgs e) + { base.OnPointerPressed(e); var view = TextView; - if (!e.Handled && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed && view != null && view.VisualLinesValid) { + if (!e.Handled && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed && view != null && view.VisualLinesValid) + { var pos = e.GetPosition(this); var typeface = view.CreateTypeface(); - foreach (var line in view.VisualLines) { + foreach (var line in view.VisualLines) + { var lineNumber = line.FirstDocumentLine.LineNumber; if (lineNumber >= _editor.BlameData.LineInfos.Count) break; @@ -148,7 +164,8 @@ namespace SourceGit.Views { Brushes.DarkOrange); var rect = new Rect(0, y, shaLink.Width, shaLink.Height); - if (rect.Contains(pos)) { + if (rect.Contains(pos)) + { _editor.OnCommitSHAClicked(info.CommitSHA); e.Handled = true; break; @@ -157,49 +174,58 @@ namespace SourceGit.Views { } } - private BlameTextEditor _editor = null; + private readonly BlameTextEditor _editor = null; } - public class VerticalSeperatorMargin : AbstractMargin { - public VerticalSeperatorMargin(BlameTextEditor editor) { + public class VerticalSeperatorMargin : AbstractMargin + { + public VerticalSeperatorMargin(BlameTextEditor editor) + { _editor = editor; } - public override void Render(DrawingContext context) { + public override void Render(DrawingContext context) + { var pen = new Pen(_editor.BorderBrush, 1); context.DrawLine(pen, new Point(0, 0), new Point(0, Bounds.Height)); } - protected override Size MeasureOverride(Size availableSize) { + protected override Size MeasureOverride(Size availableSize) + { return new Size(1, 0); } - private BlameTextEditor _editor = null; + private readonly BlameTextEditor _editor = null; } public static readonly StyledProperty BlameDataProperty = AvaloniaProperty.Register(nameof(BlameData)); - public Models.BlameData BlameData { + public Models.BlameData BlameData + { get => GetValue(BlameDataProperty); set => SetValue(BlameDataProperty, value); } protected override Type StyleKeyOverride => typeof(TextEditor); - public BlameTextEditor() : base(new TextArea(), new TextDocument()) { + public BlameTextEditor() : base(new TextArea(), new TextDocument()) + { IsReadOnly = true; ShowLineNumbers = false; WordWrap = false; } - public void OnCommitSHAClicked(string sha) { - if (DataContext is ViewModels.Blame blame) { + public void OnCommitSHAClicked(string sha) + { + if (DataContext is ViewModels.Blame blame) + { blame.NavigateToCommit(sha); } } - protected override void OnLoaded(RoutedEventArgs e) { + protected override void OnLoaded(RoutedEventArgs e) + { base.OnLoaded(e); TextArea.LeftMargins.Add(new LineNumberMargin() { Margin = new Thickness(8, 0) }); @@ -210,9 +236,12 @@ namespace SourceGit.Views { TextArea.TextView.VisualLinesChanged += OnTextViewVisualLinesChanged; TextArea.TextView.Margin = new Thickness(4, 0); - if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) { + if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) + { _registryOptions = new RegistryOptions(ThemeName.DarkPlus); - } else { + } + else + { _registryOptions = new RegistryOptions(ThemeName.LightPlus); } @@ -220,7 +249,8 @@ namespace SourceGit.Views { UpdateGrammar(); } - protected override void OnUnloaded(RoutedEventArgs e) { + protected override void OnUnloaded(RoutedEventArgs e) + { base.OnUnloaded(e); TextArea.LeftMargins.Clear(); @@ -232,26 +262,37 @@ namespace SourceGit.Views { _textMate = null; } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { base.OnPropertyChanged(change); - if (change.Property == BlameDataProperty) { - if (BlameData != null) { + if (change.Property == BlameDataProperty) + { + if (BlameData != null) + { Text = BlameData.Content; UpdateGrammar(); - } else { + } + else + { Text = string.Empty; } - } else if (change.Property.Name == "ActualThemeVariant" && change.NewValue != null && _textMate != null) { - if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) { + } + else if (change.Property.Name == "ActualThemeVariant" && change.NewValue != null && _textMate != null) + { + if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) + { _textMate.SetTheme(_registryOptions.LoadTheme(ThemeName.DarkPlus)); - } else { + } + else + { _textMate.SetTheme(_registryOptions.LoadTheme(ThemeName.LightPlus)); } } } - private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e) { + private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e) + { var selected = SelectedText; if (string.IsNullOrEmpty(selected)) return; @@ -264,7 +305,8 @@ namespace SourceGit.Views { var copy = new MenuItem(); copy.Header = App.Text("Copy"); copy.Icon = icon; - copy.Click += (o, ev) => { + copy.Click += (o, ev) => + { App.CopyText(selected); ev.Handled = true; }; @@ -275,22 +317,29 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnTextViewVisualLinesChanged(object sender, EventArgs e) { - foreach (var margin in TextArea.LeftMargins) { - if (margin is CommitInfoMargin commitInfo) { + private void OnTextViewVisualLinesChanged(object sender, EventArgs e) + { + foreach (var margin in TextArea.LeftMargins) + { + if (margin is CommitInfoMargin commitInfo) + { commitInfo.InvalidateMeasure(); break; } } } - private void UpdateGrammar() { + private void UpdateGrammar() + { if (_textMate == null || BlameData == null) return; var ext = Path.GetExtension(BlameData.File); - if (ext == ".h") { + if (ext == ".h") + { _textMate.SetGrammar(_registryOptions.GetScopeByLanguageId("cpp")); - } else { + } + else + { _textMate.SetGrammar(_registryOptions.GetScopeByExtension(ext)); } } @@ -299,47 +348,61 @@ namespace SourceGit.Views { private TextMate.Installation _textMate = null; } - public partial class Blame : Window { - public Blame() { - if (App.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { + public partial class Blame : Window + { + public Blame() + { + if (App.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { Owner = desktop.MainWindow; } InitializeComponent(); } - private void MaximizeOrRestoreWindow(object sender, TappedEventArgs e) { - if (WindowState == WindowState.Maximized) { + private void MaximizeOrRestoreWindow(object sender, TappedEventArgs e) + { + if (WindowState == WindowState.Maximized) + { WindowState = WindowState.Normal; - } else { + } + else + { WindowState = WindowState.Maximized; } e.Handled = true; } - private void CustomResizeWindow(object sender, PointerPressedEventArgs e) { - if (sender is Border border) { - if (border.Tag is WindowEdge edge) { + private void CustomResizeWindow(object sender, PointerPressedEventArgs e) + { + if (sender is Border border) + { + if (border.Tag is WindowEdge edge) + { BeginResizeDrag(edge, e); } } } - private void BeginMoveWindow(object sender, PointerPressedEventArgs e) { + private void BeginMoveWindow(object sender, PointerPressedEventArgs e) + { BeginMoveDrag(e); } - protected override void OnClosed(EventArgs e) { + protected override void OnClosed(EventArgs e) + { base.OnClosed(e); GC.Collect(); } - private void OnCommitSHAPointerPressed(object sender, PointerPressedEventArgs e) { - if (DataContext is ViewModels.Blame blame) { + private void OnCommitSHAPointerPressed(object sender, PointerPressedEventArgs e) + { + if (DataContext is ViewModels.Blame blame) + { var txt = sender as TextBlock; blame.NavigateToCommit(txt.Text); } e.Handled = true; } } -} +} \ No newline at end of file diff --git a/src/Views/CaptionButtons.axaml.cs b/src/Views/CaptionButtons.axaml.cs index 09f70dad..aa75b402 100644 --- a/src/Views/CaptionButtons.axaml.cs +++ b/src/Views/CaptionButtons.axaml.cs @@ -2,32 +2,40 @@ using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.VisualTree; -namespace SourceGit.Views { - public partial class CaptionButtons : UserControl { - public CaptionButtons() { +namespace SourceGit.Views +{ + public partial class CaptionButtons : UserControl + { + public CaptionButtons() + { InitializeComponent(); } - private void MinimizeWindow(object sender, RoutedEventArgs e) { + private void MinimizeWindow(object sender, RoutedEventArgs e) + { var window = this.FindAncestorOfType(); - if (window != null) { + if (window != null) + { window.WindowState = WindowState.Minimized; } } - private void MaximizeOrRestoreWindow(object sender, RoutedEventArgs e) { + private void MaximizeOrRestoreWindow(object sender, RoutedEventArgs e) + { var window = this.FindAncestorOfType(); - if (window != null) { + if (window != null) + { window.WindowState = window.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; } } - private void CloseWindow(object sender, RoutedEventArgs e) { + private void CloseWindow(object sender, RoutedEventArgs e) + { var window = this.FindAncestorOfType(); - if (window != null) { + if (window != null) + { window.Close(); } } } -} - +} \ No newline at end of file diff --git a/src/Views/CaptionButtonsMacOS.axaml.cs b/src/Views/CaptionButtonsMacOS.axaml.cs index 64b93d21..9d5af115 100644 --- a/src/Views/CaptionButtonsMacOS.axaml.cs +++ b/src/Views/CaptionButtonsMacOS.axaml.cs @@ -2,32 +2,40 @@ using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.VisualTree; -namespace SourceGit.Views { - public partial class CaptionButtonsMacOS : UserControl { - public CaptionButtonsMacOS() { +namespace SourceGit.Views +{ + public partial class CaptionButtonsMacOS : UserControl + { + public CaptionButtonsMacOS() + { InitializeComponent(); } - private void MinimizeWindow(object sender, RoutedEventArgs e) { + private void MinimizeWindow(object sender, RoutedEventArgs e) + { var window = this.FindAncestorOfType(); - if (window != null) { + if (window != null) + { window.WindowState = WindowState.Minimized; } } - private void MaximizeOrRestoreWindow(object sender, RoutedEventArgs e) { + private void MaximizeOrRestoreWindow(object sender, RoutedEventArgs e) + { var window = this.FindAncestorOfType(); - if (window != null) { + if (window != null) + { window.WindowState = window.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; } } - private void CloseWindow(object sender, RoutedEventArgs e) { + private void CloseWindow(object sender, RoutedEventArgs e) + { var window = this.FindAncestorOfType(); - if (window != null) { + if (window != null) + { window.Close(); } } } -} - +} \ No newline at end of file diff --git a/src/Views/ChangeStatusIcon.cs b/src/Views/ChangeStatusIcon.cs index b4eac523..4ac295b6 100644 --- a/src/Views/ChangeStatusIcon.cs +++ b/src/Views/ChangeStatusIcon.cs @@ -1,44 +1,54 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Media; -using System; +using System; using System.Globalization; -namespace SourceGit.Views { - public class ChangeStatusIcon : Control { +using Avalonia; +using Avalonia.Controls; +using Avalonia.Media; + +namespace SourceGit.Views +{ + public class ChangeStatusIcon : Control + { private static readonly IBrush[] BACKGROUNDS = [ Brushes.Transparent, - new LinearGradientBrush { + new LinearGradientBrush + { GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(238, 160, 14), 0), new GradientStop(Color.FromRgb(228, 172, 67), 1) }, StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), }, - new LinearGradientBrush { + new LinearGradientBrush + { GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(47, 185, 47), 0), new GradientStop(Color.FromRgb(75, 189, 75), 1) }, StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), }, - new LinearGradientBrush { + new LinearGradientBrush + { GradientStops = new GradientStops() { new GradientStop(Colors.Tomato, 0), new GradientStop(Color.FromRgb(252, 165, 150), 1) }, StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), }, - new LinearGradientBrush { + new LinearGradientBrush + { GradientStops = new GradientStops() { new GradientStop(Colors.Orchid, 0), new GradientStop(Color.FromRgb(248, 161, 245), 1) }, StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), }, - new LinearGradientBrush { + new LinearGradientBrush + { GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(238, 160, 14), 0), new GradientStop(Color.FromRgb(228, 172, 67), 1) }, StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), }, - new LinearGradientBrush { + new LinearGradientBrush + { GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(238, 160, 14), 0), new GradientStop(Color.FromRgb(228, 172, 67), 1) }, StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), }, - new LinearGradientBrush { + new LinearGradientBrush + { GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(47, 185, 47), 0), new GradientStop(Color.FromRgb(75, 189, 75), 1) }, StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), @@ -50,7 +60,8 @@ namespace SourceGit.Views { public static readonly StyledProperty IsWorkingCopyChangeProperty = AvaloniaProperty.Register(nameof(IsWorkingCopyChange)); - public bool IsWorkingCopyChange { + public bool IsWorkingCopyChange + { get => GetValue(IsWorkingCopyChangeProperty); set => SetValue(IsWorkingCopyChangeProperty, value); } @@ -58,31 +69,40 @@ namespace SourceGit.Views { public static readonly StyledProperty ChangeProperty = AvaloniaProperty.Register(nameof(Change)); - public Models.Change Change { + public Models.Change Change + { get => GetValue(ChangeProperty); set => SetValue(ChangeProperty, value); } - static ChangeStatusIcon() { + static ChangeStatusIcon() + { AffectsRender(IsWorkingCopyChangeProperty, ChangeProperty); } - public override void Render(DrawingContext context) { + public override void Render(DrawingContext context) + { if (Change == null || Bounds.Width <= 0) return; var typeface = new Typeface("fonts:SourceGit#JetBrains Mono"); IBrush background = null; string indicator; - if (IsWorkingCopyChange) { - if (Change.IsConflit) { + if (IsWorkingCopyChange) + { + if (Change.IsConflit) + { background = Brushes.OrangeRed; indicator = "!"; - } else { + } + else + { background = BACKGROUNDS[(int)Change.WorkTree]; indicator = INDICATOR[(int)Change.WorkTree]; } - } else { + } + else + { background = BACKGROUNDS[(int)Change.Index]; indicator = INDICATOR[(int)Change.Index]; } @@ -101,4 +121,4 @@ namespace SourceGit.Views { context.DrawText(txt, textOrigin); } } -} +} \ No newline at end of file diff --git a/src/Views/ChangeViewModeSwitcher.axaml.cs b/src/Views/ChangeViewModeSwitcher.axaml.cs index 59a041e9..d918f4d6 100644 --- a/src/Views/ChangeViewModeSwitcher.axaml.cs +++ b/src/Views/ChangeViewModeSwitcher.axaml.cs @@ -1,23 +1,28 @@ using Avalonia; using Avalonia.Controls; -namespace SourceGit.Views { - public partial class ChangeViewModeSwitcher : UserControl { +namespace SourceGit.Views +{ + public partial class ChangeViewModeSwitcher : UserControl + { public static readonly StyledProperty ViewModeProperty = AvaloniaProperty.Register(nameof(ViewMode)); - public Models.ChangeViewMode ViewMode { + public Models.ChangeViewMode ViewMode + { get => GetValue(ViewModeProperty); set => SetValue(ViewModeProperty, value); } - public ChangeViewModeSwitcher() { + public ChangeViewModeSwitcher() + { DataContext = this; InitializeComponent(); } - public void SwitchMode(object param) { + public void SwitchMode(object param) + { ViewMode = (Models.ChangeViewMode)param; } } -} +} \ No newline at end of file diff --git a/src/Views/Checkout.axaml.cs b/src/Views/Checkout.axaml.cs index d2d9edca..5b516ec3 100644 --- a/src/Views/Checkout.axaml.cs +++ b/src/Views/Checkout.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class Checkout : UserControl { - public Checkout() { +namespace SourceGit.Views +{ + public partial class Checkout : UserControl + { + public Checkout() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/CherryPick.axaml.cs b/src/Views/CherryPick.axaml.cs index 306d4702..069e13ba 100644 --- a/src/Views/CherryPick.axaml.cs +++ b/src/Views/CherryPick.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class CherryPick : UserControl { - public CherryPick() { +namespace SourceGit.Views +{ + public partial class CherryPick : UserControl + { + public CherryPick() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/Cleanup.axaml.cs b/src/Views/Cleanup.axaml.cs index a098d9a4..35f1e1ad 100644 --- a/src/Views/Cleanup.axaml.cs +++ b/src/Views/Cleanup.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class Cleanup : UserControl { - public Cleanup() { +namespace SourceGit.Views +{ + public partial class Cleanup : UserControl + { + public Cleanup() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/ClearStashes.axaml.cs b/src/Views/ClearStashes.axaml.cs index d95e18c1..b81ba4a9 100644 --- a/src/Views/ClearStashes.axaml.cs +++ b/src/Views/ClearStashes.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class ClearStashes : UserControl { - public ClearStashes() { +namespace SourceGit.Views +{ + public partial class ClearStashes : UserControl + { + public ClearStashes() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/Clone.axaml.cs b/src/Views/Clone.axaml.cs index cd52e0bf..9f403571 100644 --- a/src/Views/Clone.axaml.cs +++ b/src/Views/Clone.axaml.cs @@ -2,32 +2,39 @@ using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.Platform.Storage; -namespace SourceGit.Views { - public partial class Clone : UserControl { - public Clone() { +namespace SourceGit.Views +{ + public partial class Clone : UserControl + { + public Clone() + { InitializeComponent(); } - private async void SelectParentFolder(object sender, RoutedEventArgs e) { + private async void SelectParentFolder(object sender, RoutedEventArgs e) + { var options = new FolderPickerOpenOptions() { AllowMultiple = false }; var toplevel = TopLevel.GetTopLevel(this); var selected = await toplevel.StorageProvider.OpenFolderPickerAsync(options); - if (selected.Count == 1) { + if (selected.Count == 1) + { txtParentFolder.Text = selected[0].Path.LocalPath; } e.Handled = true; } - private async void SelectSSHKey(object sender, RoutedEventArgs e) { + private async void SelectSSHKey(object sender, RoutedEventArgs e) + { var options = new FilePickerOpenOptions() { AllowMultiple = false, FileTypeFilter = [new FilePickerFileType("SSHKey") { Patterns = ["*.*"] }] }; var toplevel = TopLevel.GetTopLevel(this); var selected = await toplevel.StorageProvider.OpenFilePickerAsync(options); - if (selected.Count == 1) { + if (selected.Count == 1) + { txtSSHKey.Text = selected[0].Path.LocalPath; } e.Handled = true; } } -} +} \ No newline at end of file diff --git a/src/Views/CommitBaseInfo.axaml.cs b/src/Views/CommitBaseInfo.axaml.cs index ac25c46b..fae3489c 100644 --- a/src/Views/CommitBaseInfo.axaml.cs +++ b/src/Views/CommitBaseInfo.axaml.cs @@ -1,17 +1,22 @@ using Avalonia.Controls; using Avalonia.Input; -namespace SourceGit.Views { - public partial class CommitBaseInfo : UserControl { - public CommitBaseInfo() { +namespace SourceGit.Views +{ + public partial class CommitBaseInfo : UserControl + { + public CommitBaseInfo() + { InitializeComponent(); } - private void OnParentSHAPressed(object sender, PointerPressedEventArgs e) { - if (DataContext is ViewModels.CommitDetail detail) { + private void OnParentSHAPressed(object sender, PointerPressedEventArgs e) + { + if (DataContext is ViewModels.CommitDetail detail) + { detail.NavigateTo((sender as Control).DataContext as string); } e.Handled = true; } } -} +} \ No newline at end of file diff --git a/src/Views/CommitChanges.axaml.cs b/src/Views/CommitChanges.axaml.cs index db65922d..1cdc8da5 100644 --- a/src/Views/CommitChanges.axaml.cs +++ b/src/Views/CommitChanges.axaml.cs @@ -1,20 +1,27 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class CommitChanges : UserControl { - public CommitChanges() { +namespace SourceGit.Views +{ + public partial class CommitChanges : UserControl + { + public CommitChanges() + { InitializeComponent(); } - private void OnDataGridSelectionChanged(object sender, SelectionChangedEventArgs e) { - if (sender is DataGrid datagrid && datagrid.IsVisible && datagrid.SelectedItem != null) { + private void OnDataGridSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (sender is DataGrid datagrid && datagrid.IsVisible && datagrid.SelectedItem != null) + { datagrid.ScrollIntoView(datagrid.SelectedItem, null); } e.Handled = true; } - private void OnDataGridContextRequested(object sender, ContextRequestedEventArgs e) { - if (sender is DataGrid datagrid && datagrid.SelectedItem != null) { + private void OnDataGridContextRequested(object sender, ContextRequestedEventArgs e) + { + if (sender is DataGrid datagrid && datagrid.SelectedItem != null) + { var detail = DataContext as ViewModels.CommitDetail; var menu = detail.CreateChangeContextMenu(datagrid.SelectedItem as Models.Change); menu.Open(datagrid); @@ -23,11 +30,14 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnTreeViewContextRequested(object sender, ContextRequestedEventArgs e) { - if (sender is TreeView view && view.SelectedItem != null) { + private void OnTreeViewContextRequested(object sender, ContextRequestedEventArgs e) + { + if (sender is TreeView view && view.SelectedItem != null) + { var detail = DataContext as ViewModels.CommitDetail; var node = view.SelectedItem as ViewModels.FileTreeNode; - if (node != null && !node.IsFolder) { + if (node != null && !node.IsFolder) + { var menu = detail.CreateChangeContextMenu(node.Backend as Models.Change); menu.Open(view); } @@ -36,4 +46,4 @@ namespace SourceGit.Views { e.Handled = true; } } -} +} \ No newline at end of file diff --git a/src/Views/CommitDetail.axaml.cs b/src/Views/CommitDetail.axaml.cs index 00873a72..b2218629 100644 --- a/src/Views/CommitDetail.axaml.cs +++ b/src/Views/CommitDetail.axaml.cs @@ -1,14 +1,19 @@ using Avalonia.Controls; using Avalonia.Input; -namespace SourceGit.Views { - public partial class CommitDetail : UserControl { - public CommitDetail() { +namespace SourceGit.Views +{ + public partial class CommitDetail : UserControl + { + public CommitDetail() + { InitializeComponent(); } - private void OnChangeListDoubleTapped(object sender, TappedEventArgs e) { - if (DataContext is ViewModels.CommitDetail detail) { + private void OnChangeListDoubleTapped(object sender, TappedEventArgs e) + { + if (DataContext is ViewModels.CommitDetail detail) + { var datagrid = sender as DataGrid; detail.ActivePageIndex = 1; detail.SelectedChange = datagrid.SelectedItem as Models.Change; @@ -16,10 +21,13 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnChangeListContextRequested(object sender, ContextRequestedEventArgs e) { - if (DataContext is ViewModels.CommitDetail detail) { + private void OnChangeListContextRequested(object sender, ContextRequestedEventArgs e) + { + if (DataContext is ViewModels.CommitDetail detail) + { var datagrid = sender as DataGrid; - if (datagrid.SelectedItem == null) { + if (datagrid.SelectedItem == null) + { e.Handled = true; return; } @@ -30,4 +38,4 @@ namespace SourceGit.Views { e.Handled = true; } } -} +} \ No newline at end of file diff --git a/src/Views/CreateBranch.axaml.cs b/src/Views/CreateBranch.axaml.cs index 5ac02c5b..526684ec 100644 --- a/src/Views/CreateBranch.axaml.cs +++ b/src/Views/CreateBranch.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class CreateBranch : UserControl { - public CreateBranch() { +namespace SourceGit.Views +{ + public partial class CreateBranch : UserControl + { + public CreateBranch() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/CreateGroup.axaml.cs b/src/Views/CreateGroup.axaml.cs index c9c91190..c40158a9 100644 --- a/src/Views/CreateGroup.axaml.cs +++ b/src/Views/CreateGroup.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class CreateGroup : UserControl { - public CreateGroup() { +namespace SourceGit.Views +{ + public partial class CreateGroup : UserControl + { + public CreateGroup() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/CreateTag.axaml.cs b/src/Views/CreateTag.axaml.cs index d22f53ff..827d4a08 100644 --- a/src/Views/CreateTag.axaml.cs +++ b/src/Views/CreateTag.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class CreateTag : UserControl { - public CreateTag() { +namespace SourceGit.Views +{ + public partial class CreateTag : UserControl + { + public CreateTag() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/DeleteBranch.axaml.cs b/src/Views/DeleteBranch.axaml.cs index 6d59f864..967dec70 100644 --- a/src/Views/DeleteBranch.axaml.cs +++ b/src/Views/DeleteBranch.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class DeleteBranch : UserControl { - public DeleteBranch() { +namespace SourceGit.Views +{ + public partial class DeleteBranch : UserControl + { + public DeleteBranch() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/DeleteRemote.axaml.cs b/src/Views/DeleteRemote.axaml.cs index 19222573..cb016ef6 100644 --- a/src/Views/DeleteRemote.axaml.cs +++ b/src/Views/DeleteRemote.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class DeleteRemote : UserControl { - public DeleteRemote() { +namespace SourceGit.Views +{ + public partial class DeleteRemote : UserControl + { + public DeleteRemote() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/DeleteRepositoryNode.axaml.cs b/src/Views/DeleteRepositoryNode.axaml.cs index 4e562c36..f64d9971 100644 --- a/src/Views/DeleteRepositoryNode.axaml.cs +++ b/src/Views/DeleteRepositoryNode.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class DeleteRepositoryNode : UserControl { - public DeleteRepositoryNode() { +namespace SourceGit.Views +{ + public partial class DeleteRepositoryNode : UserControl + { + public DeleteRepositoryNode() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/DeleteSubmodule.axaml.cs b/src/Views/DeleteSubmodule.axaml.cs index 8753c6e5..2a38edbd 100644 --- a/src/Views/DeleteSubmodule.axaml.cs +++ b/src/Views/DeleteSubmodule.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class DeleteSubmodule : UserControl { - public DeleteSubmodule() { +namespace SourceGit.Views +{ + public partial class DeleteSubmodule : UserControl + { + public DeleteSubmodule() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/DeleteTag.axaml.cs b/src/Views/DeleteTag.axaml.cs index 3c7fb1a2..8df43aeb 100644 --- a/src/Views/DeleteTag.axaml.cs +++ b/src/Views/DeleteTag.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class DeleteTag : UserControl { - public DeleteTag() { +namespace SourceGit.Views +{ + public partial class DeleteTag : UserControl + { + public DeleteTag() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/DiffView.axaml.cs b/src/Views/DiffView.axaml.cs index 911eba66..16eefe0b 100644 --- a/src/Views/DiffView.axaml.cs +++ b/src/Views/DiffView.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class DiffView : UserControl { - public DiffView() { +namespace SourceGit.Views +{ + public partial class DiffView : UserControl + { + public DiffView() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/Discard.axaml.cs b/src/Views/Discard.axaml.cs index 1d28e7e4..2fd0220b 100644 --- a/src/Views/Discard.axaml.cs +++ b/src/Views/Discard.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class Discard : UserControl { - public Discard() { +namespace SourceGit.Views +{ + public partial class Discard : UserControl + { + public Discard() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/DropStash.axaml.cs b/src/Views/DropStash.axaml.cs index ff96d490..496391ca 100644 --- a/src/Views/DropStash.axaml.cs +++ b/src/Views/DropStash.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class DropStash : UserControl { - public DropStash() { +namespace SourceGit.Views +{ + public partial class DropStash : UserControl + { + public DropStash() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/EditRemote.axaml.cs b/src/Views/EditRemote.axaml.cs index 16076cdb..aa6510a9 100644 --- a/src/Views/EditRemote.axaml.cs +++ b/src/Views/EditRemote.axaml.cs @@ -2,21 +2,26 @@ using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.Platform.Storage; -namespace SourceGit.Views { - public partial class EditRemote : UserControl { - public EditRemote() { +namespace SourceGit.Views +{ + public partial class EditRemote : UserControl + { + public EditRemote() + { InitializeComponent(); } - private async void SelectSSHKey(object sender, RoutedEventArgs e) { + private async void SelectSSHKey(object sender, RoutedEventArgs e) + { var options = new FilePickerOpenOptions() { AllowMultiple = false, FileTypeFilter = [new FilePickerFileType("SSHKey") { Patterns = ["*.*"] }] }; var toplevel = TopLevel.GetTopLevel(this); var selected = await toplevel.StorageProvider.OpenFilePickerAsync(options); - if (selected.Count == 1) { + if (selected.Count == 1) + { txtSSHKey.Text = selected[0].Path.LocalPath; } e.Handled = true; } } -} +} \ No newline at end of file diff --git a/src/Views/EditRepositoryNode.axaml.cs b/src/Views/EditRepositoryNode.axaml.cs index 3f0c6f95..2e6ab75e 100644 --- a/src/Views/EditRepositoryNode.axaml.cs +++ b/src/Views/EditRepositoryNode.axaml.cs @@ -1,10 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class EditRepositoryNode : UserControl { - public EditRepositoryNode() { +namespace SourceGit.Views +{ + public partial class EditRepositoryNode : UserControl + { + public EditRepositoryNode() + { InitializeComponent(); } } -} - +} \ No newline at end of file diff --git a/src/Views/FastForwardWithoutCheckout.axaml.cs b/src/Views/FastForwardWithoutCheckout.axaml.cs index 23a76bb2..c3115754 100644 --- a/src/Views/FastForwardWithoutCheckout.axaml.cs +++ b/src/Views/FastForwardWithoutCheckout.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class FastForwardWithoutCheckout : UserControl { - public FastForwardWithoutCheckout() { +namespace SourceGit.Views +{ + public partial class FastForwardWithoutCheckout : UserControl + { + public FastForwardWithoutCheckout() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/Fetch.axaml.cs b/src/Views/Fetch.axaml.cs index 8f728d4c..5019537a 100644 --- a/src/Views/Fetch.axaml.cs +++ b/src/Views/Fetch.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class Fetch : UserControl { - public Fetch() { +namespace SourceGit.Views +{ + public partial class Fetch : UserControl + { + public Fetch() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/FileHistories.axaml.cs b/src/Views/FileHistories.axaml.cs index 25250584..7e7278f7 100644 --- a/src/Views/FileHistories.axaml.cs +++ b/src/Views/FileHistories.axaml.cs @@ -1,35 +1,48 @@ using Avalonia.Controls; using Avalonia.Input; -namespace SourceGit.Views { - public partial class FileHistories : Window { - public FileHistories() { +namespace SourceGit.Views +{ + public partial class FileHistories : Window + { + public FileHistories() + { InitializeComponent(); } - private void MaximizeOrRestoreWindow(object sender, TappedEventArgs e) { - if (WindowState == WindowState.Maximized) { + private void MaximizeOrRestoreWindow(object sender, TappedEventArgs e) + { + if (WindowState == WindowState.Maximized) + { WindowState = WindowState.Normal; - } else { + } + else + { WindowState = WindowState.Maximized; } e.Handled = true; } - private void CustomResizeWindow(object sender, PointerPressedEventArgs e) { - if (sender is Border border) { - if (border.Tag is WindowEdge edge) { + private void CustomResizeWindow(object sender, PointerPressedEventArgs e) + { + if (sender is Border border) + { + if (border.Tag is WindowEdge edge) + { BeginResizeDrag(edge, e); } } } - private void BeginMoveWindow(object sender, PointerPressedEventArgs e) { + private void BeginMoveWindow(object sender, PointerPressedEventArgs e) + { BeginMoveDrag(e); } - private void OnPressedSHA(object sender, PointerPressedEventArgs e) { - if (sender is TextBlock block) { + private void OnPressedSHA(object sender, PointerPressedEventArgs e) + { + if (sender is TextBlock block) + { var histories = DataContext as ViewModels.FileHistories; histories.NavigateToCommit(block.Text); } @@ -37,4 +50,4 @@ namespace SourceGit.Views { e.Handled = true; } } -} +} \ No newline at end of file diff --git a/src/Views/GitFlowFinish.axaml.cs b/src/Views/GitFlowFinish.axaml.cs index 8ce65040..313d0417 100644 --- a/src/Views/GitFlowFinish.axaml.cs +++ b/src/Views/GitFlowFinish.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class GitFlowFinish : UserControl { - public GitFlowFinish() { +namespace SourceGit.Views +{ + public partial class GitFlowFinish : UserControl + { + public GitFlowFinish() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/GitFlowStart.axaml.cs b/src/Views/GitFlowStart.axaml.cs index 564a2a7e..f5ffd97d 100644 --- a/src/Views/GitFlowStart.axaml.cs +++ b/src/Views/GitFlowStart.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class GitFlowStart : UserControl { - public GitFlowStart() { +namespace SourceGit.Views +{ + public partial class GitFlowStart : UserControl + { + public GitFlowStart() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/Histories.axaml.cs b/src/Views/Histories.axaml.cs index 775f21e1..7e457006 100644 --- a/src/Views/Histories.axaml.cs +++ b/src/Views/Histories.axaml.cs @@ -1,44 +1,56 @@ +using System; + using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Media; using Avalonia.VisualTree; -using System; -namespace SourceGit.Views { - public class LayoutableGrid : Grid { +namespace SourceGit.Views +{ + public class LayoutableGrid : Grid + { public static readonly StyledProperty UseHorizontalProperty = AvaloniaProperty.Register(nameof(UseHorizontal), false); - public bool UseHorizontal { + public bool UseHorizontal + { get => GetValue(UseHorizontalProperty); set => SetValue(UseHorizontalProperty, value); } protected override Type StyleKeyOverride => typeof(Grid); - static LayoutableGrid() { + static LayoutableGrid() + { UseHorizontalProperty.Changed.AddClassHandler((o, _) => o.RefreshLayout()); } - public override void ApplyTemplate() { + public override void ApplyTemplate() + { base.ApplyTemplate(); RefreshLayout(); } - private void RefreshLayout() { - if (UseHorizontal) { + private void RefreshLayout() + { + if (UseHorizontal) + { var rowSpan = RowDefinitions.Count; - for (int i = 0; i < Children.Count; i++) { + for (int i = 0; i < Children.Count; i++) + { var child = Children[i]; child.SetValue(RowProperty, 0); child.SetValue(RowSpanProperty, rowSpan); child.SetValue(ColumnProperty, i); child.SetValue(ColumnSpanProperty, 1); } - } else { + } + else + { var colSpan = ColumnDefinitions.Count; - for (int i = 0; i < Children.Count; i++) { + for (int i = 0; i < Children.Count; i++) + { var child = Children[i]; child.SetValue(RowProperty, i); child.SetValue(RowSpanProperty, 1); @@ -49,7 +61,8 @@ namespace SourceGit.Views { } } - public class CommitGraph : Control { + public class CommitGraph : Control + { public static readonly Pen[] Pens = [ new Pen(Brushes.Orange, 2), new Pen(Brushes.ForestGreen, 2), @@ -64,7 +77,8 @@ namespace SourceGit.Views { public static readonly StyledProperty GraphProperty = AvaloniaProperty.Register(nameof(Graph)); - public Models.CommitGraph Graph { + public Models.CommitGraph Graph + { get => GetValue(GraphProperty); set => SetValue(GraphProperty, value); } @@ -72,24 +86,29 @@ namespace SourceGit.Views { public static readonly StyledProperty BindingDataGridProperty = AvaloniaProperty.Register(nameof(BindingDataGrid)); - public DataGrid BindingDataGrid { + public DataGrid BindingDataGrid + { get => GetValue(BindingDataGridProperty); set => SetValue(BindingDataGridProperty, value); } - static CommitGraph() { + static CommitGraph() + { AffectsRender(BindingDataGridProperty, GraphProperty); } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { base.OnPropertyChanged(change); - if (change.Property.Name == "ActualThemeVariant") { + if (change.Property.Name == "ActualThemeVariant") + { InvalidateVisual(); } } - public override void Render(DrawingContext context) { + public override void Render(DrawingContext context) + { base.Render(context); var graph = Graph; @@ -102,9 +121,11 @@ namespace SourceGit.Views { // Find the content display offset Y of binding DataGrid. double rowHeight = grid.RowHeight; double startY = 0; - foreach (var child in rowsPresenter.Children) { + foreach (var child in rowsPresenter.Children) + { var row = child as DataGridRow; - if (row.IsVisible && row.Bounds.Top <= 0 && row.Bounds.Top > -rowHeight) { + if (row.IsVisible && row.Bounds.Top <= 0 && row.Bounds.Top > -rowHeight) + { var test = rowHeight * row.GetIndex() - row.Bounds.Top; if (startY < test) startY = test; } @@ -123,10 +144,12 @@ namespace SourceGit.Views { // Draw connect dots Brush dotFill = null; - if (App.Current.TryGetResource("Brush.Contents", App.Current.ActualThemeVariant, out object res) && res is SolidColorBrush) { + if (App.Current.TryGetResource("Brush.Contents", App.Current.ActualThemeVariant, out object res) && res is SolidColorBrush) + { dotFill = res as SolidColorBrush; } - foreach (var dot in graph.Dots) { + foreach (var dot in graph.Dots) + { if (dot.Center.Y < top) continue; if (dot.Center.Y > bottom) break; @@ -134,8 +157,10 @@ namespace SourceGit.Views { } } - private void DrawCurves(DrawingContext context, double top, double bottom) { - foreach (var line in Graph.Paths) { + private void DrawCurves(DrawingContext context, double top, double bottom) + { + foreach (var line in Graph.Paths) + { var last = line.Points[0]; var size = line.Points.Count; @@ -144,38 +169,51 @@ namespace SourceGit.Views { var geo = new StreamGeometry(); var pen = Pens[line.Color]; - using (var ctx = geo.Open()) { + using (var ctx = geo.Open()) + { var started = false; var ended = false; - for (int i = 1; i < size; i++) { + for (int i = 1; i < size; i++) + { var cur = line.Points[i]; - if (cur.Y < top) { + if (cur.Y < top) + { last = cur; continue; } - if (!started) { + if (!started) + { ctx.BeginFigure(last, false); started = true; } - if (cur.Y > bottom) { + if (cur.Y > bottom) + { cur = new Point(cur.X, bottom); ended = true; } - if (cur.X > last.X) { + if (cur.X > last.X) + { ctx.QuadraticBezierTo(new Point(cur.X, last.Y), cur); - } else if (cur.X < last.X) { - if (i < size - 1) { + } + else if (cur.X < last.X) + { + if (i < size - 1) + { var midY = (last.Y + cur.Y) / 2; var midX = (last.X + cur.X) / 2; ctx.QuadraticBezierTo(new Point(last.X, midY), new Point(midX, midY)); ctx.QuadraticBezierTo(new Point(cur.X, midY), cur); - } else { + } + else + { ctx.QuadraticBezierTo(new Point(last.X, cur.Y), cur); } - } else { + } + else + { ctx.LineTo(cur); } @@ -187,12 +225,14 @@ namespace SourceGit.Views { context.DrawGeometry(null, pen, geo); } - foreach (var link in Graph.Links) { + foreach (var link in Graph.Links) + { if (link.End.Y < top) continue; if (link.Start.Y > bottom) break; var geo = new StreamGeometry(); - using (var ctx = geo.Open()) { + using (var ctx = geo.Open()) + { ctx.BeginFigure(link.Start, false); ctx.QuadraticBezierTo(link.Control, link.End); } @@ -202,32 +242,40 @@ namespace SourceGit.Views { } } - public partial class Histories : UserControl { - public Histories() { + public partial class Histories : UserControl + { + public Histories() + { InitializeComponent(); } - private void OnCommitDataGridLayoutUpdated(object sender, EventArgs e) { + private void OnCommitDataGridLayoutUpdated(object sender, EventArgs e) + { commitGraph.InvalidateVisual(); } - private void OnCommitDataGridSelectionChanged(object sender, SelectionChangedEventArgs e) { - if (DataContext is ViewModels.Histories histories) { + private void OnCommitDataGridSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (DataContext is ViewModels.Histories histories) + { histories.Select(commitDataGrid.SelectedItems); - if (histories.DetailContext is ViewModels.CommitDetail detail) { + if (histories.DetailContext is ViewModels.CommitDetail detail) + { commitDataGrid.ScrollIntoView(detail.Commit, null); } } e.Handled = true; } - private void OnCommitDataGridContextRequested(object sender, ContextRequestedEventArgs e) { - if (DataContext is ViewModels.Histories histories) { + private void OnCommitDataGridContextRequested(object sender, ContextRequestedEventArgs e) + { + if (DataContext is ViewModels.Histories histories) + { var menu = histories.MakeContextMenu(); menu?.Open(sender as Control); } e.Handled = true; } } -} +} \ No newline at end of file diff --git a/src/Views/Hotkeys.axaml.cs b/src/Views/Hotkeys.axaml.cs index f56f2d5f..333d3e2d 100644 --- a/src/Views/Hotkeys.axaml.cs +++ b/src/Views/Hotkeys.axaml.cs @@ -2,18 +2,23 @@ using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; -namespace SourceGit.Views { - public partial class Hotkeys : Window { - public Hotkeys() { +namespace SourceGit.Views +{ + public partial class Hotkeys : Window + { + public Hotkeys() + { InitializeComponent(); } - private void BeginMoveWindow(object sender, PointerPressedEventArgs e) { + private void BeginMoveWindow(object sender, PointerPressedEventArgs e) + { BeginMoveDrag(e); } - private void CloseWindow(object sender, RoutedEventArgs e) { + private void CloseWindow(object sender, RoutedEventArgs e) + { Close(); } } -} +} \ No newline at end of file diff --git a/src/Views/Init.axaml.cs b/src/Views/Init.axaml.cs index 85658074..c4437da1 100644 --- a/src/Views/Init.axaml.cs +++ b/src/Views/Init.axaml.cs @@ -1,10 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class Init : UserControl { - public Init() { +namespace SourceGit.Views +{ + public partial class Init : UserControl + { + public Init() + { InitializeComponent(); } } -} - +} \ No newline at end of file diff --git a/src/Views/InitGitFlow.axaml.cs b/src/Views/InitGitFlow.axaml.cs index aa2b6132..31e52790 100644 --- a/src/Views/InitGitFlow.axaml.cs +++ b/src/Views/InitGitFlow.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class InitGitFlow : UserControl { - public InitGitFlow() { +namespace SourceGit.Views +{ + public partial class InitGitFlow : UserControl + { + public InitGitFlow() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/Launcher.axaml.cs b/src/Views/Launcher.axaml.cs index 1456e5d0..959f0061 100644 --- a/src/Views/Launcher.axaml.cs +++ b/src/Views/Launcher.axaml.cs @@ -1,67 +1,90 @@ +using System; + using Avalonia; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; -using System; -namespace SourceGit.Views { - public class LauncherTab : Grid { +namespace SourceGit.Views +{ + public class LauncherTab : Grid + { public static readonly StyledProperty UseFixedTabWidthProperty = AvaloniaProperty.Register(nameof(UseFixedTabWidth), false); - public bool UseFixedTabWidth { + public bool UseFixedTabWidth + { get => GetValue(UseFixedTabWidthProperty); set => SetValue(UseFixedTabWidthProperty, value); } protected override Type StyleKeyOverride => typeof(Grid); - static LauncherTab() { - UseFixedTabWidthProperty.Changed.AddClassHandler((tab, ev) => { + static LauncherTab() + { + UseFixedTabWidthProperty.Changed.AddClassHandler((tab, ev) => + { tab.Width = tab.UseFixedTabWidth ? 200.0 : double.NaN; }); } } - public class LauncherBody : Border { + public class LauncherBody : Border + { public static readonly StyledProperty DataProperty = AvaloniaProperty.Register(nameof(Data), false); - public object Data { + public object Data + { get => GetValue(DataProperty); set => SetValue(DataProperty, value); } protected override Type StyleKeyOverride => typeof(Border); - static LauncherBody() { - DataProperty.Changed.AddClassHandler((body, ev) => { + static LauncherBody() + { + DataProperty.Changed.AddClassHandler((body, ev) => + { var data = body.Data; - - if (data == null) { + + if (data == null) + { body.Child = null; - } else if (data is ViewModels.Welcome) { + } + else if (data is ViewModels.Welcome) + { body.Child = new Welcome { DataContext = data }; - } else if (data is ViewModels.Repository) { + } + else if (data is ViewModels.Repository) + { body.Child = new Repository { DataContext = data }; - } else { + } + else + { body.Child = null; } }); } } - public partial class Launcher : Window, Models.INotificationReceiver { - public Launcher() { + public partial class Launcher : Window, Models.INotificationReceiver + { + public Launcher() + { DataContext = new ViewModels.Launcher(); InitializeComponent(); } - public void OnReceiveNotification(string ctx, Models.Notification notice) { - if (DataContext is ViewModels.Launcher vm) { - foreach (var page in vm.Pages) { + public void OnReceiveNotification(string ctx, Models.Notification notice) + { + if (DataContext is ViewModels.Launcher vm) + { + foreach (var page in vm.Pages) + { var pageId = page.Node.Id.Replace("\\", "/"); - if (pageId == ctx) { + if (pageId == ctx) + { page.Notifications.Add(notice); return; } @@ -71,37 +94,53 @@ namespace SourceGit.Views { } } - protected override void OnKeyDown(KeyEventArgs e) { + protected override void OnKeyDown(KeyEventArgs e) + { var vm = DataContext as ViewModels.Launcher; - if (e.KeyModifiers.HasFlag(KeyModifiers.Control)) { - if (e.Key == Key.W) { + if (e.KeyModifiers.HasFlag(KeyModifiers.Control)) + { + if (e.Key == Key.W) + { vm.CloseTab(null); e.Handled = true; return; - } else if (e.Key == Key.Tab) { + } + else if (e.Key == Key.Tab) + { vm.GotoNextTab(); e.Handled = true; return; - } else if (vm.ActivePage.Data is ViewModels.Repository repo) { - if (e.Key == Key.D1 || e.Key == Key.NumPad1) { + } + else if (vm.ActivePage.Data is ViewModels.Repository repo) + { + if (e.Key == Key.D1 || e.Key == Key.NumPad1) + { repo.SelectedViewIndex = 0; e.Handled = true; return; - } else if (e.Key == Key.D2 || e.Key == Key.NumPad2) { + } + else if (e.Key == Key.D2 || e.Key == Key.NumPad2) + { repo.SelectedViewIndex = 1; e.Handled = true; return; - } else if (e.Key == Key.D3 || e.Key == Key.NumPad3) { + } + else if (e.Key == Key.D3 || e.Key == Key.NumPad3) + { repo.SelectedViewIndex = 2; e.Handled = true; return; - } else if (e.Key == Key.F) { + } + else if (e.Key == Key.F) + { repo.IsSearching = !repo.IsSearching; e.Handled = true; return; } - } - } else if (e.Key == Key.Escape) { + } + } + else if (e.Key == Key.Escape) + { vm.ActivePage.CancelPopup(); e.Handled = true; return; @@ -110,84 +149,107 @@ namespace SourceGit.Views { base.OnKeyDown(e); } - protected override void OnClosing(WindowClosingEventArgs e) { + protected override void OnClosing(WindowClosingEventArgs e) + { var vm = DataContext as ViewModels.Launcher; vm.Quit(); base.OnClosing(e); } - private void MaximizeOrRestoreWindow(object sender, TappedEventArgs e) { - if (WindowState == WindowState.Maximized) { + private void MaximizeOrRestoreWindow(object sender, TappedEventArgs e) + { + if (WindowState == WindowState.Maximized) + { WindowState = WindowState.Normal; - } else { + } + else + { WindowState = WindowState.Maximized; } e.Handled = true; } - private void CustomResizeWindow(object sender, PointerPressedEventArgs e) { - if (sender is Border border) { - if (border.Tag is WindowEdge edge) { + private void CustomResizeWindow(object sender, PointerPressedEventArgs e) + { + if (sender is Border border) + { + if (border.Tag is WindowEdge edge) + { BeginResizeDrag(edge, e); } } } - private void BeginMoveWindow(object sender, PointerPressedEventArgs e) { + private void BeginMoveWindow(object sender, PointerPressedEventArgs e) + { BeginMoveDrag(e); } - private void ScrollTabs(object sender, PointerWheelEventArgs e) { - if (!e.KeyModifiers.HasFlag(KeyModifiers.Shift)) { + private void ScrollTabs(object sender, PointerWheelEventArgs e) + { + if (!e.KeyModifiers.HasFlag(KeyModifiers.Shift)) + { if (e.Delta.Y < 0) launcherTabsScroller.LineRight(); else launcherTabsScroller.LineLeft(); e.Handled = true; } } - private void ScrollTabsLeft(object sender, RoutedEventArgs e) { + private void ScrollTabsLeft(object sender, RoutedEventArgs e) + { launcherTabsScroller.LineLeft(); e.Handled = true; } - private void ScrollTabsRight(object sender, RoutedEventArgs e) { + private void ScrollTabsRight(object sender, RoutedEventArgs e) + { launcherTabsScroller.LineRight(); e.Handled = true; } - private void UpdateScrollIndicator(object sender, SizeChangedEventArgs e) { - if (launcherTabsBar.Bounds.Width > launcherTabsContainer.Bounds.Width) { + private void UpdateScrollIndicator(object sender, SizeChangedEventArgs e) + { + if (launcherTabsBar.Bounds.Width > launcherTabsContainer.Bounds.Width) + { leftScrollIndicator.IsVisible = true; rightScrollIndicator.IsVisible = true; - } else { + } + else + { leftScrollIndicator.IsVisible = false; rightScrollIndicator.IsVisible = false; } e.Handled = true; } - private void SetupDragAndDrop(object sender, RoutedEventArgs e) { - if (sender is Border border) { + private void SetupDragAndDrop(object sender, RoutedEventArgs e) + { + if (sender is Border border) + { DragDrop.SetAllowDrop(border, true); border.AddHandler(DragDrop.DropEvent, DropTab); } e.Handled = true; } - private void OnPointerPressedTab(object sender, PointerPressedEventArgs e) { + private void OnPointerPressedTab(object sender, PointerPressedEventArgs e) + { _pressedTab = true; _startDrag = false; _pressedTabPosition = e.GetPosition(sender as Border); } - private void OnPointerReleasedTab(object sender, PointerReleasedEventArgs e) { + private void OnPointerReleasedTab(object sender, PointerReleasedEventArgs e) + { _pressedTab = false; _startDrag = false; } - private void OnPointerMovedOverTab(object sender, PointerEventArgs e) { - if (_pressedTab && !_startDrag && sender is Border border) { + private void OnPointerMovedOverTab(object sender, PointerEventArgs e) + { + if (_pressedTab && !_startDrag && sender is Border border) + { var delta = e.GetPosition(border) - _pressedTabPosition; var sizeSquired = delta.X * delta.X + delta.Y * delta.Y; if (sizeSquired < 64) return; @@ -201,11 +263,14 @@ namespace SourceGit.Views { e.Handled = true; } - private void DropTab(object sender, DragEventArgs e) { - if (e.Data.Contains("MovedTab") && sender is Border border) { + private void DropTab(object sender, DragEventArgs e) + { + if (e.Data.Contains("MovedTab") && sender is Border border) + { var to = border.DataContext as ViewModels.LauncherPage; var moved = e.Data.Get("MovedTab") as ViewModels.LauncherPage; - if (to != null && moved != null && to != moved && DataContext is ViewModels.Launcher vm) { + if (to != null && moved != null && to != moved && DataContext is ViewModels.Launcher vm) + { vm.MoveTab(moved, to); } } @@ -215,37 +280,45 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnPopupSure(object sender, RoutedEventArgs e) { - if (DataContext is ViewModels.Launcher vm) { + private void OnPopupSure(object sender, RoutedEventArgs e) + { + if (DataContext is ViewModels.Launcher vm) + { vm.ActivePage.ProcessPopup(); } e.Handled = true; } - private void OnPopupCancel(object sender, RoutedEventArgs e) { - if (DataContext is ViewModels.Launcher vm) { + private void OnPopupCancel(object sender, RoutedEventArgs e) + { + if (DataContext is ViewModels.Launcher vm) + { vm.ActivePage.CancelPopup(); } e.Handled = true; } - private void OnPopupCancelByClickMask(object sender, PointerPressedEventArgs e) { + private void OnPopupCancelByClickMask(object sender, PointerPressedEventArgs e) + { OnPopupCancel(sender, e); } - private async void OpenPreference(object sender, RoutedEventArgs e) { + private async void OpenPreference(object sender, RoutedEventArgs e) + { var dialog = new Preference(); await dialog.ShowDialog(this); e.Handled = true; } - private async void OpenHotkeys(object sender, RoutedEventArgs e) { + private async void OpenHotkeys(object sender, RoutedEventArgs e) + { var dialog = new Hotkeys(); await dialog.ShowDialog(this); e.Handled = true; } - private async void OpenAboutDialog(object sender, RoutedEventArgs e) { + private async void OpenAboutDialog(object sender, RoutedEventArgs e) + { var dialog = new About(); await dialog.ShowDialog(this); e.Handled = true; @@ -253,6 +326,6 @@ namespace SourceGit.Views { private bool _pressedTab = false; private Point _pressedTabPosition = new Point(); - private bool _startDrag = false; + private bool _startDrag = false; } } \ No newline at end of file diff --git a/src/Views/Merge.axaml.cs b/src/Views/Merge.axaml.cs index a4d6018b..175f0192 100644 --- a/src/Views/Merge.axaml.cs +++ b/src/Views/Merge.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class Merge : UserControl { - public Merge() { +namespace SourceGit.Views +{ + public partial class Merge : UserControl + { + public Merge() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/NameHighlightedTextBlock.cs b/src/Views/NameHighlightedTextBlock.cs index c6473116..f54e3e75 100644 --- a/src/Views/NameHighlightedTextBlock.cs +++ b/src/Views/NameHighlightedTextBlock.cs @@ -1,16 +1,20 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Media; -using System; +using System; using System.Globalization; -namespace SourceGit.Views { - public class NameHighlightedTextBlock : Control { +using Avalonia; +using Avalonia.Controls; +using Avalonia.Media; + +namespace SourceGit.Views +{ + public class NameHighlightedTextBlock : Control + { public static readonly StyledProperty TextProperty = AvaloniaProperty.Register(nameof(Text)); - public string Text { + public string Text + { get => GetValue(TextProperty); set => SetValue(TextProperty, value); } @@ -18,7 +22,8 @@ namespace SourceGit.Views { public static readonly StyledProperty FontFamilyProperty = TextBlock.FontFamilyProperty.AddOwner(); - public FontFamily FontFamily { + public FontFamily FontFamily + { get => GetValue(FontFamilyProperty); set => SetValue(FontFamilyProperty, value); } @@ -26,7 +31,8 @@ namespace SourceGit.Views { public static readonly StyledProperty FontSizeProperty = TextBlock.FontSizeProperty.AddOwner(); - public double FontSize { + public double FontSize + { get => GetValue(FontSizeProperty); set => SetValue(FontSizeProperty, value); } @@ -34,21 +40,25 @@ namespace SourceGit.Views { public static readonly StyledProperty ForegroundProperty = TextBlock.ForegroundProperty.AddOwner(); - public IBrush Foreground { + public IBrush Foreground + { get => GetValue(ForegroundProperty); set => SetValue(ForegroundProperty, value); } - static NameHighlightedTextBlock() { + static NameHighlightedTextBlock() + { AffectsMeasure(TextProperty); } - public NameHighlightedTextBlock(string nameKey, params object[] args) { + public NameHighlightedTextBlock(string nameKey, params object[] args) + { Text = App.Text(nameKey, args); VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center; } - protected override Size MeasureOverride(Size availableSize) { + protected override Size MeasureOverride(Size availableSize) + { var text = Text; if (string.IsNullOrEmpty(text)) return base.MeasureOverride(availableSize); @@ -64,7 +74,8 @@ namespace SourceGit.Views { return new Size(formatted.Width - 16, formatted.Height); } - public override void Render(DrawingContext context) { + public override void Render(DrawingContext context) + { var text = Text; if (string.IsNullOrEmpty(text)) return; @@ -75,8 +86,10 @@ namespace SourceGit.Views { var parts = text.Split('$', StringSplitOptions.None); var isName = false; - foreach (var part in parts) { - if (string.IsNullOrEmpty(part)) { + foreach (var part in parts) + { + if (string.IsNullOrEmpty(part)) + { isName = !isName; continue; } @@ -90,13 +103,16 @@ namespace SourceGit.Views { FontSize, Foreground); - if (isName) { + if (isName) + { var lineY = formatted.Baseline + 2; offsetX += 4; context.DrawText(formatted, new Point(offsetX, 0)); context.DrawLine(underlinePen, new Point(offsetX, lineY), new Point(offsetX + formatted.Width, lineY)); offsetX += formatted.Width + 4; - } else { + } + else + { context.DrawText(formatted, new Point(offsetX, 0)); offsetX += formatted.Width; } @@ -105,4 +121,4 @@ namespace SourceGit.Views { } } } -} +} \ No newline at end of file diff --git a/src/Views/Preference.axaml.cs b/src/Views/Preference.axaml.cs index f0eb830b..799c1dc9 100644 --- a/src/Views/Preference.axaml.cs +++ b/src/Views/Preference.axaml.cs @@ -1,48 +1,59 @@ +using System; +using System.IO; + using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Platform.Storage; -using System; -using System.IO; -namespace SourceGit.Views { - public partial class Preference : Window { - public string DefaultUser { +namespace SourceGit.Views +{ + public partial class Preference : Window + { + public string DefaultUser + { get; set; } - public string DefaultEmail { + public string DefaultEmail + { get; set; } - public Models.CRLFMode CRLFMode { + public Models.CRLFMode CRLFMode + { get; set; } - public bool EnableGPGSigning { + public bool EnableGPGSigning + { get; set; } - public string GPGExecutableFile { + public string GPGExecutableFile + { get; set; } - public string GPGUserKey { + public string GPGUserKey + { get; set; } - public Preference() { + public Preference() + { var pref = ViewModels.Preference.Instance; DataContext = pref; var ver = string.Empty; - if (pref.IsGitConfigured) { + if (pref.IsGitConfigured) + { var config = new Commands.Config(null).ListAll(); if (config.ContainsKey("user.name")) DefaultUser = config["user.name"]; @@ -59,11 +70,13 @@ namespace SourceGit.Views { txtVersion.Text = ver; } - private void BeginMoveWindow(object sender, PointerPressedEventArgs e) { + private void BeginMoveWindow(object sender, PointerPressedEventArgs e) + { BeginMoveDrag(e); } - private void CloseWindow(object sender, RoutedEventArgs e) { + private void CloseWindow(object sender, RoutedEventArgs e) + { var cmd = new Commands.Config(null); var config = cmd.ListAll(); @@ -78,21 +91,24 @@ namespace SourceGit.Views { if (DefaultEmail != oldEmail) cmd.Set("user.email", DefaultEmail); if (GPGUserKey != oldGPGSignKey) cmd.Set("user.signingkey", GPGUserKey); if (CRLFMode != null && CRLFMode.Value != oldCRLF) cmd.Set("core.autocrlf", CRLFMode.Value); - if (EnableGPGSigning != (oldGPGSignEnable == "true")) cmd.Set("commit.gpgsign", EnableGPGSigning ? "true" : "false"); + if (EnableGPGSigning != (oldGPGSignEnable == "true")) cmd.Set("commit.gpgsign", EnableGPGSigning ? "true" : "false"); if (GPGExecutableFile != oldGPGExec) cmd.Set("gpg.program", GPGExecutableFile); Close(); } - private async void SelectGitExecutable(object sender, RoutedEventArgs e) { + private async void SelectGitExecutable(object sender, RoutedEventArgs e) + { var pattern = OperatingSystem.IsWindows() ? "git.exe" : "git"; - var options = new FilePickerOpenOptions() { - FileTypeFilter = [new FilePickerFileType("Git Executable") { Patterns = [ pattern ] }], + var options = new FilePickerOpenOptions() + { + FileTypeFilter = [new FilePickerFileType("Git Executable") { Patterns = [pattern] }], AllowMultiple = false, }; var selected = await StorageProvider.OpenFilePickerAsync(options); - if (selected.Count == 1) { + if (selected.Count == 1) + { ViewModels.Preference.Instance.GitInstallPath = selected[0].Path.LocalPath; txtVersion.Text = new Commands.Version().Query(); } @@ -100,45 +116,54 @@ namespace SourceGit.Views { e.Handled = true; } - private async void SelectDefaultCloneDir(object sender, RoutedEventArgs e) { + private async void SelectDefaultCloneDir(object sender, RoutedEventArgs e) + { var options = new FolderPickerOpenOptions() { AllowMultiple = false }; var selected = await StorageProvider.OpenFolderPickerAsync(options); - if (selected.Count == 1) { + if (selected.Count == 1) + { ViewModels.Preference.Instance.GitDefaultCloneDir = selected[0].Path.LocalPath; } } - private async void SelectGPGExecutable(object sender, RoutedEventArgs e) { + private async void SelectGPGExecutable(object sender, RoutedEventArgs e) + { var pattern = OperatingSystem.IsWindows() ? "gpg.exe" : "gpg"; - var options = new FilePickerOpenOptions() { - FileTypeFilter = [new FilePickerFileType("GPG Executable") { Patterns = [ pattern ] }], + var options = new FilePickerOpenOptions() + { + FileTypeFilter = [new FilePickerFileType("GPG Executable") { Patterns = [pattern] }], AllowMultiple = false, }; var selected = await StorageProvider.OpenFilePickerAsync(options); - if (selected.Count == 1) { + if (selected.Count == 1) + { GPGExecutableFile = selected[0].Path.LocalPath; } } - private async void SelectExternalMergeTool(object sender, RoutedEventArgs e) { + private async void SelectExternalMergeTool(object sender, RoutedEventArgs e) + { var type = ViewModels.Preference.Instance.ExternalMergeToolType; - if (type < 0 || type >= Models.ExternalMergeTools.Supported.Count) { + if (type < 0 || type >= Models.ExternalMergeTools.Supported.Count) + { ViewModels.Preference.Instance.ExternalMergeToolType = 0; type = 0; } var tool = Models.ExternalMergeTools.Supported[type]; var pattern = Path.GetFileName(tool.Exec); - var options = new FilePickerOpenOptions() { + var options = new FilePickerOpenOptions() + { FileTypeFilter = [new FilePickerFileType(tool.Name) { Patterns = [pattern] }], AllowMultiple = false, }; var selected = await StorageProvider.OpenFilePickerAsync(options); - if (selected.Count == 1) { + if (selected.Count == 1) + { ViewModels.Preference.Instance.ExternalMergeToolPath = selected[0].Path.LocalPath; } } } -} +} \ No newline at end of file diff --git a/src/Views/PruneRemote.axaml.cs b/src/Views/PruneRemote.axaml.cs index 6e92da86..79336e19 100644 --- a/src/Views/PruneRemote.axaml.cs +++ b/src/Views/PruneRemote.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class PruneRemote : UserControl { - public PruneRemote() { +namespace SourceGit.Views +{ + public partial class PruneRemote : UserControl + { + public PruneRemote() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/Pull.axaml.cs b/src/Views/Pull.axaml.cs index 284adeef..699cc3af 100644 --- a/src/Views/Pull.axaml.cs +++ b/src/Views/Pull.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class Pull : UserControl { - public Pull() { +namespace SourceGit.Views +{ + public partial class Pull : UserControl + { + public Pull() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/Push.axaml.cs b/src/Views/Push.axaml.cs index c5e0b363..ced5f270 100644 --- a/src/Views/Push.axaml.cs +++ b/src/Views/Push.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class Push : UserControl { - public Push() { +namespace SourceGit.Views +{ + public partial class Push : UserControl + { + public Push() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/PushTag.axaml.cs b/src/Views/PushTag.axaml.cs index d94b4ae7..27d8b184 100644 --- a/src/Views/PushTag.axaml.cs +++ b/src/Views/PushTag.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class PushTag : UserControl { - public PushTag() { +namespace SourceGit.Views +{ + public partial class PushTag : UserControl + { + public PushTag() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/Rebase.axaml.cs b/src/Views/Rebase.axaml.cs index ed27d4dd..ed464d05 100644 --- a/src/Views/Rebase.axaml.cs +++ b/src/Views/Rebase.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class Rebase : UserControl { - public Rebase() { +namespace SourceGit.Views +{ + public partial class Rebase : UserControl + { + public Rebase() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/RenameBranch.axaml.cs b/src/Views/RenameBranch.axaml.cs index 284bcd97..f7d3f4a8 100644 --- a/src/Views/RenameBranch.axaml.cs +++ b/src/Views/RenameBranch.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class RenameBranch : UserControl { - public RenameBranch() { +namespace SourceGit.Views +{ + public partial class RenameBranch : UserControl + { + public RenameBranch() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/Repository.axaml.cs b/src/Views/Repository.axaml.cs index c1effb46..a5b33da7 100644 --- a/src/Views/Repository.axaml.cs +++ b/src/Views/Repository.axaml.cs @@ -1,37 +1,53 @@ +using System; +using System.Threading.Tasks; + using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; -using SourceGit.ViewModels; -using System; -using System.Threading.Tasks; -namespace SourceGit.Views { - public class RepositorySubView : Border { +using SourceGit.ViewModels; + +namespace SourceGit.Views +{ + public class RepositorySubView : Border + { public static readonly StyledProperty DataProperty = AvaloniaProperty.Register(nameof(Data), false); - public object Data { + public object Data + { get => GetValue(DataProperty); set => SetValue(DataProperty, value); } protected override Type StyleKeyOverride => typeof(Border); - static RepositorySubView() { - DataProperty.Changed.AddClassHandler((view, ev) => { + static RepositorySubView() + { + DataProperty.Changed.AddClassHandler((view, ev) => + { var data = view.Data; - if (data == null) { + if (data == null) + { view.Child = null; - } else if (data is ViewModels.Histories) { + } + else if (data is ViewModels.Histories) + { view.Child = new Histories { DataContext = data }; - } else if (data is ViewModels.WorkingCopy) { + } + else if (data is ViewModels.WorkingCopy) + { view.Child = new WorkingCopy { DataContext = data }; - } else if (data is ViewModels.StashesPage) { + } + else if (data is ViewModels.StashesPage) + { view.Child = new StashesPage { DataContext = data }; - } else { + } + else + { view.Child = null; } @@ -40,73 +56,95 @@ namespace SourceGit.Views { } } - public partial class Repository : UserControl { - public Repository() { + public partial class Repository : UserControl + { + public Repository() + { InitializeComponent(); } - private void OnLocalBranchTreeLostFocus(object sender, RoutedEventArgs e) { + private void OnLocalBranchTreeLostFocus(object sender, RoutedEventArgs e) + { if (sender is TreeView tree) tree.UnselectAll(); } - private void OnRemoteBranchTreeLostFocus(object sender, RoutedEventArgs e) { + private void OnRemoteBranchTreeLostFocus(object sender, RoutedEventArgs e) + { if (sender is TreeView tree) tree.UnselectAll(); } - private void OnTagDataGridLostFocus(object sender, RoutedEventArgs e) { + private void OnTagDataGridLostFocus(object sender, RoutedEventArgs e) + { if (sender is DataGrid datagrid) datagrid.SelectedItem = null; } - private void OnLocalBranchTreeSelectionChanged(object sender, SelectionChangedEventArgs e) { - if (sender is TreeView tree && tree.SelectedItem != null) { + private void OnLocalBranchTreeSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (sender is TreeView tree && tree.SelectedItem != null) + { remoteBranchTree.UnselectAll(); var node = tree.SelectedItem as Models.BranchTreeNode; - if (node.IsBranch && DataContext is ViewModels.Repository repo) { + if (node.IsBranch && DataContext is ViewModels.Repository repo) + { repo.NavigateToCommit((node.Backend as Models.Branch).Head); } } } - private void OnRemoteBranchTreeSelectionChanged(object sender, SelectionChangedEventArgs e) { - if (sender is TreeView tree && tree.SelectedItem != null) { + private void OnRemoteBranchTreeSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (sender is TreeView tree && tree.SelectedItem != null) + { localBranchTree.UnselectAll(); var node = tree.SelectedItem as Models.BranchTreeNode; - if (node.IsBranch && DataContext is ViewModels.Repository repo) { + if (node.IsBranch && DataContext is ViewModels.Repository repo) + { repo.NavigateToCommit((node.Backend as Models.Branch).Head); } } } - private void OnTagDataGridSelectionChanged(object sender, SelectionChangedEventArgs e) { - if (sender is DataGrid datagrid && datagrid.SelectedItem != null) { + private void OnTagDataGridSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (sender is DataGrid datagrid && datagrid.SelectedItem != null) + { var tag = datagrid.SelectedItem as Models.Tag; - if (DataContext is ViewModels.Repository repo) { + if (DataContext is ViewModels.Repository repo) + { repo.NavigateToCommit(tag.SHA); } } } - private void OnSearchCommitPanelPropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) { + private void OnSearchCommitPanelPropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) + { var grid = sender as Grid; - if (e.Property == IsVisibleProperty && grid.IsVisible) { + if (e.Property == IsVisibleProperty && grid.IsVisible) + { txtSearchCommitsBox.Focus(); } } - private void OnSearchKeyDown(object sender, KeyEventArgs e) { - if (e.Key == Key.Enter) { - if (DataContext is ViewModels.Repository repo) { + private void OnSearchKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Enter) + { + if (DataContext is ViewModels.Repository repo) + { repo.StartSearchCommits(); } e.Handled = true; } } - private void OnSearchResultDataGridSelectionChanged(object sender, SelectionChangedEventArgs e) { - if (sender is DataGrid datagrid && datagrid.SelectedItem != null) { - if (DataContext is ViewModels.Repository repo) { + private void OnSearchResultDataGridSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (sender is DataGrid datagrid && datagrid.SelectedItem != null) + { + if (DataContext is ViewModels.Repository repo) + { var commit = datagrid.SelectedItem as Models.Commit; repo.NavigateToCommit(commit.SHA); } @@ -114,18 +152,25 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnToggleFilter(object sender, RoutedEventArgs e) { - if (sender is ToggleButton toggle) { + private void OnToggleFilter(object sender, RoutedEventArgs e) + { + if (sender is ToggleButton toggle) + { var filter = string.Empty; - if (toggle.DataContext is Models.BranchTreeNode node) { - if (node.IsBranch) { + if (toggle.DataContext is Models.BranchTreeNode node) + { + if (node.IsBranch) + { filter = (node.Backend as Models.Branch).FullName; } - } else if (toggle.DataContext is Models.Tag tag) { + } + else if (toggle.DataContext is Models.Tag tag) + { filter = tag.Name; } - if (!string.IsNullOrEmpty(filter) && DataContext is ViewModels.Repository repo) { + if (!string.IsNullOrEmpty(filter) && DataContext is ViewModels.Repository repo) + { repo.UpdateFilter(filter, toggle.IsChecked == true); } } @@ -133,11 +178,14 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnLocalBranchContextMenuRequested(object sender, ContextRequestedEventArgs e) { + private void OnLocalBranchContextMenuRequested(object sender, ContextRequestedEventArgs e) + { remoteBranchTree.UnselectAll(); - if (sender is Grid grid && grid.DataContext is Models.BranchTreeNode node) { - if (node.IsBranch && DataContext is ViewModels.Repository repo) { + if (sender is Grid grid && grid.DataContext is Models.BranchTreeNode node) + { + if (node.IsBranch && DataContext is ViewModels.Repository repo) + { var menu = repo.CreateContextMenuForLocalBranch(node.Backend as Models.Branch); if (menu != null) menu.Open(grid); } @@ -146,14 +194,19 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnRemoteBranchContextMenuRequested(object sender, ContextRequestedEventArgs e) { + private void OnRemoteBranchContextMenuRequested(object sender, ContextRequestedEventArgs e) + { localBranchTree.UnselectAll(); - if (sender is Grid grid && grid.DataContext is Models.BranchTreeNode node && DataContext is ViewModels.Repository repo) { - if (node.IsRemote) { + if (sender is Grid grid && grid.DataContext is Models.BranchTreeNode node && DataContext is ViewModels.Repository repo) + { + if (node.IsRemote) + { var menu = repo.CreateContextMenuForRemote(node.Backend as Models.Remote); if (menu != null) menu.Open(grid); - } else if (node.IsBranch) { + } + else if (node.IsBranch) + { var menu = repo.CreateContextMenuForRemoteBranch(node.Backend as Models.Branch); if (menu != null) menu.Open(grid); } @@ -162,8 +215,10 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnTagContextRequested(object sender, ContextRequestedEventArgs e) { - if (sender is DataGrid datagrid && datagrid.SelectedItem != null && DataContext is ViewModels.Repository repo) { + private void OnTagContextRequested(object sender, ContextRequestedEventArgs e) + { + if (sender is DataGrid datagrid && datagrid.SelectedItem != null && DataContext is ViewModels.Repository repo) + { var tag = datagrid.SelectedItem as Models.Tag; var menu = repo.CreateContextMenuForTag(tag); if (menu != null) menu.Open(datagrid); @@ -172,8 +227,10 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnSubmoduleContextRequested(object sender, ContextRequestedEventArgs e) { - if (sender is DataGrid datagrid && datagrid.SelectedItem != null && DataContext is ViewModels.Repository repo) { + private void OnSubmoduleContextRequested(object sender, ContextRequestedEventArgs e) + { + if (sender is DataGrid datagrid && datagrid.SelectedItem != null && DataContext is ViewModels.Repository repo) + { var submodule = datagrid.SelectedItem as string; var menu = repo.CreateContextMenuForSubmodule(submodule); if (menu != null) menu.Open(datagrid); @@ -182,8 +239,10 @@ namespace SourceGit.Views { e.Handled = true; } - private void OpenGitFlowMenu(object sender, RoutedEventArgs e) { - if (DataContext is ViewModels.Repository repo) { + private void OpenGitFlowMenu(object sender, RoutedEventArgs e) + { + if (DataContext is ViewModels.Repository repo) + { var menu = repo.CreateContextMenuForGitFlow(); if (menu != null) menu.Open(sender as Button); } @@ -191,8 +250,10 @@ namespace SourceGit.Views { e.Handled = true; } - private async void UpdateSubmodules(object sender, RoutedEventArgs e) { - if (DataContext is ViewModels.Repository repo) { + private async void UpdateSubmodules(object sender, RoutedEventArgs e) + { + if (DataContext is ViewModels.Repository repo) + { repo.SetWatcherEnabled(false); iconSubmoduleUpdate.Classes.Add("rotating"); await Task.Run(() => new Commands.Submodule(repo.FullPath).Update()); @@ -203,12 +264,15 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnDoubleTappedLocalBranchNode(object sender, TappedEventArgs e) { + private void OnDoubleTappedLocalBranchNode(object sender, TappedEventArgs e) + { if (!PopupHost.CanCreatePopup()) return; - if (sender is Grid grid && DataContext is ViewModels.Repository repo) { + if (sender is Grid grid && DataContext is ViewModels.Repository repo) + { var node = grid.DataContext as Models.BranchTreeNode; - if (node != null && node.IsBranch) { + if (node != null && node.IsBranch) + { var branch = node.Backend as Models.Branch; if (branch.IsCurrent) return; @@ -218,13 +282,14 @@ namespace SourceGit.Views { } } - private async void OpenStatistics(object sender, RoutedEventArgs e) { - if (DataContext is ViewModels.Repository repo) { + private async void OpenStatistics(object sender, RoutedEventArgs e) + { + if (DataContext is ViewModels.Repository repo) + { var dialog = new Statistics() { DataContext = new ViewModels.Statistics(repo.FullPath) }; await dialog.ShowDialog(TopLevel.GetTopLevel(this) as Window); e.Handled = true; } } } -} - +} \ No newline at end of file diff --git a/src/Views/RepositoryConfigure.axaml.cs b/src/Views/RepositoryConfigure.axaml.cs index c7552b94..7c4fd852 100644 --- a/src/Views/RepositoryConfigure.axaml.cs +++ b/src/Views/RepositoryConfigure.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class RepositoryConfigure : UserControl { - public RepositoryConfigure() { +namespace SourceGit.Views +{ + public partial class RepositoryConfigure : UserControl + { + public RepositoryConfigure() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/Reset.axaml.cs b/src/Views/Reset.axaml.cs index febca0dd..269e5d2a 100644 --- a/src/Views/Reset.axaml.cs +++ b/src/Views/Reset.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class Reset : UserControl { - public Reset() { +namespace SourceGit.Views +{ + public partial class Reset : UserControl + { + public Reset() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/Revert.axaml.cs b/src/Views/Revert.axaml.cs index ffbe14bd..025f65c8 100644 --- a/src/Views/Revert.axaml.cs +++ b/src/Views/Revert.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class Revert : UserControl { - public Revert() { +namespace SourceGit.Views +{ + public partial class Revert : UserControl + { + public Revert() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/RevisionCompare.axaml.cs b/src/Views/RevisionCompare.axaml.cs index 544bce15..fce47548 100644 --- a/src/Views/RevisionCompare.axaml.cs +++ b/src/Views/RevisionCompare.axaml.cs @@ -1,21 +1,28 @@ using Avalonia.Controls; using Avalonia.Input; -namespace SourceGit.Views { - public partial class RevisionCompare : UserControl { - public RevisionCompare() { +namespace SourceGit.Views +{ + public partial class RevisionCompare : UserControl + { + public RevisionCompare() + { InitializeComponent(); } - private void OnDataGridSelectionChanged(object sender, SelectionChangedEventArgs e) { - if (sender is DataGrid datagrid && datagrid.IsVisible) { + private void OnDataGridSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (sender is DataGrid datagrid && datagrid.IsVisible) + { datagrid.ScrollIntoView(datagrid.SelectedItem, null); } e.Handled = true; } - private void OnDataGridContextRequested(object sender, ContextRequestedEventArgs e) { - if (sender is DataGrid datagrid && datagrid.SelectedItem != null) { + private void OnDataGridContextRequested(object sender, ContextRequestedEventArgs e) + { + if (sender is DataGrid datagrid && datagrid.SelectedItem != null) + { var compare = DataContext as ViewModels.RevisionCompare; var menu = compare.CreateChangeContextMenu(datagrid.SelectedItem as Models.Change); menu.Open(datagrid); @@ -24,11 +31,14 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnTreeViewContextRequested(object sender, ContextRequestedEventArgs e) { - if (sender is TreeView view && view.SelectedItem != null) { + private void OnTreeViewContextRequested(object sender, ContextRequestedEventArgs e) + { + if (sender is TreeView view && view.SelectedItem != null) + { var compare = DataContext as ViewModels.RevisionCompare; var node = view.SelectedItem as ViewModels.FileTreeNode; - if (node != null && !node.IsFolder) { + if (node != null && !node.IsFolder) + { var menu = compare.CreateChangeContextMenu(node.Backend as Models.Change); menu.Open(view); } @@ -37,8 +47,10 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnPressedSHA(object sender, PointerPressedEventArgs e) { - if (sender is TextBlock block) { + private void OnPressedSHA(object sender, PointerPressedEventArgs e) + { + if (sender is TextBlock block) + { var compare = DataContext as ViewModels.RevisionCompare; compare.NavigateTo(block.Text); } @@ -46,4 +58,4 @@ namespace SourceGit.Views { e.Handled = true; } } -} +} \ No newline at end of file diff --git a/src/Views/RevisionFiles.axaml.cs b/src/Views/RevisionFiles.axaml.cs index 013607a1..1c458729 100644 --- a/src/Views/RevisionFiles.axaml.cs +++ b/src/Views/RevisionFiles.axaml.cs @@ -1,23 +1,29 @@ +using System; +using System.IO; + using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Interactivity; using Avalonia.Media; using Avalonia.Styling; + using AvaloniaEdit; using AvaloniaEdit.Document; using AvaloniaEdit.Editing; using AvaloniaEdit.TextMate; -using System; -using System.IO; + using TextMateSharp.Grammars; -namespace SourceGit.Views { +namespace SourceGit.Views +{ - public class RevisionTextFileView : TextEditor { + public class RevisionTextFileView : TextEditor + { protected override Type StyleKeyOverride => typeof(TextEditor); - public RevisionTextFileView() : base(new TextArea(), new TextDocument()) { + public RevisionTextFileView() : base(new TextArea(), new TextDocument()) + { IsReadOnly = true; ShowLineNumbers = true; WordWrap = false; @@ -28,13 +34,17 @@ namespace SourceGit.Views { TextArea.TextView.Margin = new Thickness(4, 0); } - protected override void OnLoaded(RoutedEventArgs e) { + protected override void OnLoaded(RoutedEventArgs e) + { base.OnLoaded(e); TextArea.TextView.ContextRequested += OnTextViewContextRequested; - if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) { + if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) + { _registryOptions = new RegistryOptions(ThemeName.DarkPlus); - } else { + } + else + { _registryOptions = new RegistryOptions(ThemeName.LightPlus); } @@ -42,7 +52,8 @@ namespace SourceGit.Views { UpdateGrammar(); } - protected override void OnUnloaded(RoutedEventArgs e) { + protected override void OnUnloaded(RoutedEventArgs e) + { base.OnUnloaded(e); TextArea.TextView.ContextRequested -= OnTextViewContextRequested; @@ -52,29 +63,37 @@ namespace SourceGit.Views { GC.Collect(); } - protected override void OnDataContextChanged(EventArgs e) { + protected override void OnDataContextChanged(EventArgs e) + { base.OnDataContextChanged(e); var source = DataContext as Models.RevisionTextFile; - if (source != null) { + if (source != null) + { UpdateGrammar(); Text = source.Content; } } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { base.OnPropertyChanged(change); - if (change.Property.Name == "ActualThemeVariant" && change.NewValue != null && _textMate != null) { - if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) { + if (change.Property.Name == "ActualThemeVariant" && change.NewValue != null && _textMate != null) + { + if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) + { _textMate.SetTheme(_registryOptions.LoadTheme(ThemeName.DarkPlus)); - } else { + } + else + { _textMate.SetTheme(_registryOptions.LoadTheme(ThemeName.LightPlus)); } } } - private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e) { + private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e) + { var selected = SelectedText; if (string.IsNullOrEmpty(selected)) return; @@ -87,7 +106,8 @@ namespace SourceGit.Views { var copy = new MenuItem(); copy.Header = App.Text("Copy"); copy.Icon = icon; - copy.Click += (o, ev) => { + copy.Click += (o, ev) => + { App.CopyText(selected); ev.Handled = true; }; @@ -98,16 +118,20 @@ namespace SourceGit.Views { e.Handled = true; } - private void UpdateGrammar() { + private void UpdateGrammar() + { if (_textMate == null) return; var src = DataContext as Models.RevisionTextFile; if (src == null) return; var ext = Path.GetExtension(src.FileName); - if (ext == ".h") { + if (ext == ".h") + { _textMate.SetGrammar(_registryOptions.GetScopeByLanguageId("cpp")); - } else { + } + else + { _textMate.SetGrammar(_registryOptions.GetScopeByExtension(ext)); } } @@ -116,15 +140,19 @@ namespace SourceGit.Views { private TextMate.Installation _textMate = null; } - public partial class RevisionFiles : UserControl { - public RevisionFiles() { + public partial class RevisionFiles : UserControl + { + public RevisionFiles() + { InitializeComponent(); } - private void OnTreeViewContextRequested(object sender, ContextRequestedEventArgs e) { + private void OnTreeViewContextRequested(object sender, ContextRequestedEventArgs e) + { var detail = DataContext as ViewModels.CommitDetail; var node = detail.SelectedRevisionFileNode; - if (!node.IsFolder) { + if (!node.IsFolder) + { var menu = detail.CreateRevisionFileContextMenu(node.Backend as Models.Object); menu.Open(sender as Control); } @@ -132,4 +160,4 @@ namespace SourceGit.Views { e.Handled = true; } } -} +} \ No newline at end of file diff --git a/src/Views/Reword.axaml.cs b/src/Views/Reword.axaml.cs index 3ed4c27b..bac2cd6e 100644 --- a/src/Views/Reword.axaml.cs +++ b/src/Views/Reword.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class Reword : UserControl { - public Reword() { +namespace SourceGit.Views +{ + public partial class Reword : UserControl + { + public Reword() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/Squash.axaml.cs b/src/Views/Squash.axaml.cs index c0f73ae4..dda430ad 100644 --- a/src/Views/Squash.axaml.cs +++ b/src/Views/Squash.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class Squash : UserControl { - public Squash() { +namespace SourceGit.Views +{ + public partial class Squash : UserControl + { + public Squash() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/StashChanges.axaml.cs b/src/Views/StashChanges.axaml.cs index b9a645b9..dddb8232 100644 --- a/src/Views/StashChanges.axaml.cs +++ b/src/Views/StashChanges.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class StashChanges : UserControl { - public StashChanges() { +namespace SourceGit.Views +{ + public partial class StashChanges : UserControl + { + public StashChanges() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/StashesPage.axaml.cs b/src/Views/StashesPage.axaml.cs index d43d3c53..19904d5c 100644 --- a/src/Views/StashesPage.axaml.cs +++ b/src/Views/StashesPage.axaml.cs @@ -1,9 +1,12 @@ using Avalonia.Controls; -namespace SourceGit.Views { - public partial class StashesPage : UserControl { - public StashesPage() { +namespace SourceGit.Views +{ + public partial class StashesPage : UserControl + { + public StashesPage() + { InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/src/Views/Statistics.axaml.cs b/src/Views/Statistics.axaml.cs index cc069b26..d0c3384e 100644 --- a/src/Views/Statistics.axaml.cs +++ b/src/Views/Statistics.axaml.cs @@ -1,18 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Globalization; + using Avalonia; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Media; -using System; -using System.Collections.Generic; -using System.Globalization; -namespace SourceGit.Views { - public class Chart : Control { +namespace SourceGit.Views +{ + public class Chart : Control + { public static readonly StyledProperty LineBrushProperty = AvaloniaProperty.Register(nameof(LineBrush), Brushes.Gray); - public IBrush LineBrush { + public IBrush LineBrush + { get => GetValue(LineBrushProperty); set => SetValue(LineBrushProperty, value); } @@ -20,7 +24,8 @@ namespace SourceGit.Views { public static readonly StyledProperty ShapeBrushProperty = AvaloniaProperty.Register(nameof(ShapeBrush), Brushes.Gray); - public IBrush ShapeBrush { + public IBrush ShapeBrush + { get => GetValue(ShapeBrushProperty); set => SetValue(ShapeBrushProperty, value); } @@ -28,41 +33,59 @@ namespace SourceGit.Views { public static readonly StyledProperty> SamplesProperty = AvaloniaProperty.Register>(nameof(Samples), null); - public List Samples { + public List Samples + { get => GetValue(SamplesProperty); set => SetValue(SamplesProperty, value); } - static Chart() { - SamplesProperty.Changed.AddClassHandler((c, e) => { + static Chart() + { + SamplesProperty.Changed.AddClassHandler((c, e) => + { c._hitBoxes.Clear(); c._lastHitIdx = -1; c.InvalidateVisual(); }); } - public override void Render(DrawingContext context) { + public override void Render(DrawingContext context) + { if (Samples == null) return; var samples = Samples; int maxV = 0; - foreach (var s in samples) { + foreach (var s in samples) + { if (maxV < s.Count) maxV = s.Count; } - if (maxV < 5) { + if (maxV < 5) + { maxV = 5; - } else if (maxV < 10) { + } + else if (maxV < 10) + { maxV = 10; - } else if (maxV < 50) { + } + else if (maxV < 50) + { maxV = 50; - } else if (maxV < 100) { + } + else if (maxV < 100) + { maxV = 100; - } else if (maxV < 200) { + } + else if (maxV < 200) + { maxV = 200; - } else if (maxV < 500) { + } + else if (maxV < 500) + { maxV = 500; - } else { + } + else + { maxV = (int)Math.Ceiling(maxV / 500.0) * 500; } @@ -89,7 +112,8 @@ namespace SourceGit.Views { var stepV = (height - labelHeight) / 5; var labelStepV = maxV / 5; var gridPen = new Pen(LineBrush, 1, new DashStyle()); - for (int i = 1; i < 5; i++) { + for (int i = 1; i < 5; i++) + { var vLabel = new FormattedText( $"{maxV - i * labelStepV}", CultureInfo.CurrentCulture, @@ -100,16 +124,19 @@ namespace SourceGit.Views { var dashHeight = i * stepV; var vy = Math.Max(0, dashHeight - vLabel.Height * 0.5); - using (context.PushOpacity(.1)) { + using (context.PushOpacity(.1)) + { context.DrawLine(gridPen, new Point(horizonStart + 1, dashHeight), new Point(width, dashHeight)); } context.DrawText(vLabel, new Point(horizonStart - vLabel.Width - 8, vy)); } // Calculate hit boxes - if (_hitBoxes.Count == 0) { + if (_hitBoxes.Count == 0) + { var shapeWidth = Math.Min(32, stepX - 4); - for (int i = 0; i < samples.Count; i++) { + for (int i = 0; i < samples.Count; i++) + { var h = samples[i].Count * (height - labelHeight) / maxV; var x = horizonStart + 1 + stepX * i + (stepX - shapeWidth) * 0.5; var y = height - labelHeight - h; @@ -118,7 +145,8 @@ namespace SourceGit.Views { } // Draw shapes - for (int i = 0; i < samples.Count; i++) { + for (int i = 0; i < samples.Count; i++) + { var hLabel = new FormattedText( samples[i].Name, CultureInfo.CurrentCulture, @@ -132,20 +160,25 @@ namespace SourceGit.Views { context.DrawRectangle(ShapeBrush, null, rect); - if (stepX < 32) { + if (stepX < 32) + { var matrix = Matrix.CreateTranslation(hLabel.Width * 0.5, -hLabel.Height * 0.5) // Center of label * Matrix.CreateRotation(Math.PI * 0.25) // Rotate * Matrix.CreateTranslation(xLabel, yLabel); // Move - using (context.PushTransform(matrix)) { + using (context.PushTransform(matrix)) + { context.DrawText(hLabel, new Point(0, 0)); } - } else { + } + else + { context.DrawText(hLabel, new Point(xLabel, yLabel)); } } // Draw labels on hover - if (_lastHitIdx >= 0 && _lastHitIdx < samples.Count) { + if (_lastHitIdx >= 0 && _lastHitIdx < samples.Count) + { var rect = _hitBoxes[_lastHitIdx]; var tooltip = new FormattedText( $"{samples[_lastHitIdx].Count}", @@ -161,42 +194,51 @@ namespace SourceGit.Views { } } - protected override void OnPointerMoved(PointerEventArgs e) { + protected override void OnPointerMoved(PointerEventArgs e) + { base.OnPointerMoved(e); var p = e.GetPosition(this); - for (int i = 0; i < _hitBoxes.Count; i++) { - if (_hitBoxes[i].Contains(p)) { - if (_lastHitIdx != i) { + for (int i = 0; i < _hitBoxes.Count; i++) + { + if (_hitBoxes[i].Contains(p)) + { + if (_lastHitIdx != i) + { _lastHitIdx = i; InvalidateVisual(); } - + return; } } - if (_lastHitIdx != -1) { + if (_lastHitIdx != -1) + { _lastHitIdx = -1; InvalidateVisual(); - } + } } - private List _hitBoxes = new List(); + private readonly List _hitBoxes = new List(); private int _lastHitIdx = -1; } - public partial class Statistics : Window { - public Statistics() { + public partial class Statistics : Window + { + public Statistics() + { InitializeComponent(); } - private void BeginMoveWindow(object sender, PointerPressedEventArgs e) { + private void BeginMoveWindow(object sender, PointerPressedEventArgs e) + { BeginMoveDrag(e); } - private void CloseWindow(object sender, RoutedEventArgs e) { + private void CloseWindow(object sender, RoutedEventArgs e) + { Close(); } } -} +} \ No newline at end of file diff --git a/src/Views/TextDiffView.axaml.cs b/src/Views/TextDiffView.axaml.cs index 3fc5fb05..1d9ab7ec 100644 --- a/src/Views/TextDiffView.axaml.cs +++ b/src/Views/TextDiffView.axaml.cs @@ -1,3 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; + using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; @@ -5,35 +11,39 @@ using Avalonia.Interactivity; using Avalonia.Media; using Avalonia.Styling; using Avalonia.VisualTree; + using AvaloniaEdit; using AvaloniaEdit.Document; using AvaloniaEdit.Editing; using AvaloniaEdit.Rendering; using AvaloniaEdit.TextMate; using AvaloniaEdit.Utils; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Text; + using TextMateSharp.Grammars; -namespace SourceGit.Views { - public class CombinedTextDiffPresenter : TextEditor { - public class LineNumberMargin : AbstractMargin { - public LineNumberMargin(CombinedTextDiffPresenter editor, bool isOldLine) { +namespace SourceGit.Views +{ + public class CombinedTextDiffPresenter : TextEditor + { + public class LineNumberMargin : AbstractMargin + { + public LineNumberMargin(CombinedTextDiffPresenter editor, bool isOldLine) + { _editor = editor; _isOldLine = isOldLine; ClipToBounds = true; } - public override void Render(DrawingContext context) { + public override void Render(DrawingContext context) + { if (_editor.DiffData == null) return; var view = TextView; - if (view != null && view.VisualLinesValid) { + if (view != null && view.VisualLinesValid) + { var typeface = view.CreateTypeface(); - foreach (var line in view.VisualLines) { + foreach (var line in view.VisualLines) + { var index = line.FirstDocumentLine.LineNumber; if (index > _editor.DiffData.Lines.Count) break; @@ -54,10 +64,14 @@ namespace SourceGit.Views { } } - protected override Size MeasureOverride(Size availableSize) { - if (_editor.DiffData == null || TextView == null) { + protected override Size MeasureOverride(Size availableSize) + { + if (_editor.DiffData == null || TextView == null) + { return new Size(32, 0); - } else { + } + else + { var typeface = TextView.CreateTypeface(); var test = new FormattedText( $"{_editor.DiffData.MaxLineNumber}", @@ -70,43 +84,51 @@ namespace SourceGit.Views { } } - private CombinedTextDiffPresenter _editor; - private bool _isOldLine; + private readonly CombinedTextDiffPresenter _editor; + private readonly bool _isOldLine; } - public class VerticalSeperatorMargin : AbstractMargin { - public VerticalSeperatorMargin(CombinedTextDiffPresenter editor) { + public class VerticalSeperatorMargin : AbstractMargin + { + public VerticalSeperatorMargin(CombinedTextDiffPresenter editor) + { _editor = editor; } - public override void Render(DrawingContext context) { + public override void Render(DrawingContext context) + { var pen = new Pen(_editor.BorderBrush, 1); context.DrawLine(pen, new Point(0, 0), new Point(0, Bounds.Height)); } - protected override Size MeasureOverride(Size availableSize) { + protected override Size MeasureOverride(Size availableSize) + { return new Size(1, 0); } - private CombinedTextDiffPresenter _editor = null; + private readonly CombinedTextDiffPresenter _editor = null; } - public class LineBackgroundRenderer : IBackgroundRenderer { + public class LineBackgroundRenderer : IBackgroundRenderer + { private static readonly Brush BG_EMPTY = new SolidColorBrush(Color.FromArgb(60, 0, 0, 0)); private static readonly Brush BG_ADDED = new SolidColorBrush(Color.FromArgb(60, 0, 255, 0)); private static readonly Brush BG_DELETED = new SolidColorBrush(Color.FromArgb(60, 255, 0, 0)); public KnownLayer Layer => KnownLayer.Background; - public LineBackgroundRenderer(CombinedTextDiffPresenter editor) { + public LineBackgroundRenderer(CombinedTextDiffPresenter editor) + { _editor = editor; } - public void Draw(TextView textView, DrawingContext drawingContext) { + public void Draw(TextView textView, DrawingContext drawingContext) + { if (_editor.Document == null || !textView.VisualLinesValid) return; var width = textView.Bounds.Width; - foreach (var line in textView.VisualLines) { + foreach (var line in textView.VisualLines) + { var index = line.FirstDocumentLine.LineNumber; if (index > _editor.DiffData.Lines.Count) break; @@ -119,35 +141,42 @@ namespace SourceGit.Views { } } - private IBrush GetBrushByLineType(Models.TextDiffLineType type) { - switch (type) { - case Models.TextDiffLineType.None: return BG_EMPTY; - case Models.TextDiffLineType.Added: return BG_ADDED; - case Models.TextDiffLineType.Deleted: return BG_DELETED; - default: return null; + private IBrush GetBrushByLineType(Models.TextDiffLineType type) + { + switch (type) + { + case Models.TextDiffLineType.None: return BG_EMPTY; + case Models.TextDiffLineType.Added: return BG_ADDED; + case Models.TextDiffLineType.Deleted: return BG_DELETED; + default: return null; } } - private CombinedTextDiffPresenter _editor = null; + private readonly CombinedTextDiffPresenter _editor = null; } - public class LineStyleTransformer : DocumentColorizingTransformer { + public class LineStyleTransformer : DocumentColorizingTransformer + { private static readonly Brush HL_ADDED = new SolidColorBrush(Color.FromArgb(90, 0, 255, 0)); private static readonly Brush HL_DELETED = new SolidColorBrush(Color.FromArgb(80, 255, 0, 0)); - public LineStyleTransformer(CombinedTextDiffPresenter editor, IBrush indicatorFG) { + public LineStyleTransformer(CombinedTextDiffPresenter editor, IBrush indicatorFG) + { _editor = editor; _indicatorFG = indicatorFG; _indicatorTypeface = new Typeface("fonts:SourceGit#JetBrains Mono", FontStyle.Italic); } - protected override void ColorizeLine(DocumentLine line) { + protected override void ColorizeLine(DocumentLine line) + { var idx = line.LineNumber; if (idx > _editor.DiffData.Lines.Count) return; var info = _editor.DiffData.Lines[idx - 1]; - if (info.Type == Models.TextDiffLineType.Indicator) { - ChangeLinePart(line.Offset, line.EndOffset, v => { + if (info.Type == Models.TextDiffLineType.Indicator) + { + ChangeLinePart(line.Offset, line.EndOffset, v => + { v.TextRunProperties.SetForegroundBrush(_indicatorFG); v.TextRunProperties.SetTypeface(_indicatorTypeface); }); @@ -155,25 +184,29 @@ namespace SourceGit.Views { return; } - if (info.Highlights.Count > 0) { + if (info.Highlights.Count > 0) + { var bg = info.Type == Models.TextDiffLineType.Added ? HL_ADDED : HL_DELETED; - foreach (var highlight in info.Highlights) { - ChangeLinePart(line.Offset + highlight.Start, line.Offset + highlight.Start + highlight.Count, v => { + foreach (var highlight in info.Highlights) + { + ChangeLinePart(line.Offset + highlight.Start, line.Offset + highlight.Start + highlight.Count, v => + { v.TextRunProperties.SetBackgroundBrush(bg); }); } } } - private CombinedTextDiffPresenter _editor; - private IBrush _indicatorFG = Brushes.DarkGray; - private Typeface _indicatorTypeface = Typeface.Default; + private readonly CombinedTextDiffPresenter _editor; + private readonly IBrush _indicatorFG = Brushes.DarkGray; + private readonly Typeface _indicatorTypeface = Typeface.Default; } public static readonly StyledProperty DiffDataProperty = AvaloniaProperty.Register(nameof(DiffData)); - public Models.TextDiff DiffData { + public Models.TextDiff DiffData + { get => GetValue(DiffDataProperty); set => SetValue(DiffDataProperty, value); } @@ -181,7 +214,8 @@ namespace SourceGit.Views { public static readonly StyledProperty SecondaryFGProperty = AvaloniaProperty.Register(nameof(SecondaryFG), Brushes.Gray); - public IBrush SecondaryFG { + public IBrush SecondaryFG + { get => GetValue(SecondaryFGProperty); set => SetValue(SecondaryFGProperty, value); } @@ -189,20 +223,23 @@ namespace SourceGit.Views { public static readonly StyledProperty SyncScrollOffsetProperty = AvaloniaProperty.Register(nameof(SyncScrollOffset)); - public Vector SyncScrollOffset { + public Vector SyncScrollOffset + { get => GetValue(SyncScrollOffsetProperty); set => SetValue(SyncScrollOffsetProperty, value); } protected override Type StyleKeyOverride => typeof(TextEditor); - public CombinedTextDiffPresenter() : base(new TextArea(), new TextDocument()) { + public CombinedTextDiffPresenter() : base(new TextArea(), new TextDocument()) + { IsReadOnly = true; ShowLineNumbers = false; WordWrap = false; } - protected override void OnLoaded(RoutedEventArgs e) { + protected override void OnLoaded(RoutedEventArgs e) + { base.OnLoaded(e); TextArea.LeftMargins.Add(new LineNumberMargin(this, true) { Margin = new Thickness(8, 0) }); @@ -215,9 +252,12 @@ namespace SourceGit.Views { TextArea.TextView.ContextRequested += OnTextViewContextRequested; TextArea.TextView.ScrollOffsetChanged += OnTextViewScrollOffsetChanged; - if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) { + if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) + { _registryOptions = new RegistryOptions(ThemeName.DarkPlus); - } else { + } + else + { _registryOptions = new RegistryOptions(ThemeName.LightPlus); } @@ -228,7 +268,8 @@ namespace SourceGit.Views { TextArea.TextView.LineTransformers.Add(new LineStyleTransformer(this, SecondaryFG)); } - protected override void OnUnloaded(RoutedEventArgs e) { + protected override void OnUnloaded(RoutedEventArgs e) + { base.OnUnloaded(e); TextArea.LeftMargins.Clear(); @@ -242,20 +283,23 @@ namespace SourceGit.Views { GC.Collect(); } - private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e) { + private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e) + { var selection = TextArea.Selection; if (selection.IsEmpty) return; var menu = new ContextMenu(); var parentView = this.FindAncestorOfType(); - if (parentView != null) { + if (parentView != null) + { parentView.FillContextMenuForWorkingCopyChange(menu, selection.StartPosition.Line, selection.EndPosition.Line, false); } var copy = new MenuItem(); copy.Header = App.Text("Copy"); copy.Icon = App.CreateMenuIcon("Icons.Copy"); - copy.Click += (o, ev) => { + copy.Click += (o, ev) => + { App.CopyText(SelectedText); ev.Handled = true; }; @@ -265,46 +309,65 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnTextViewScrollOffsetChanged(object sender, EventArgs e) { + private void OnTextViewScrollOffsetChanged(object sender, EventArgs e) + { SyncScrollOffset = TextArea.TextView.ScrollOffset; } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { base.OnPropertyChanged(change); - if (change.Property == DiffDataProperty) { - if (DiffData != null) { + if (change.Property == DiffDataProperty) + { + if (DiffData != null) + { var builder = new StringBuilder(); - foreach (var line in DiffData.Lines) { + foreach (var line in DiffData.Lines) + { builder.AppendLine(line.Content); } UpdateGrammar(); Text = builder.ToString(); - } else { + } + else + { Text = string.Empty; } - } else if (change.Property == SyncScrollOffsetProperty) { - if (TextArea.TextView.ScrollOffset != SyncScrollOffset) { + } + else if (change.Property == SyncScrollOffsetProperty) + { + if (TextArea.TextView.ScrollOffset != SyncScrollOffset) + { IScrollable scrollable = TextArea.TextView; scrollable.Offset = SyncScrollOffset; } - } else if (change.Property.Name == "ActualThemeVariant" && change.NewValue != null && _textMate != null) { - if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) { + } + else if (change.Property.Name == "ActualThemeVariant" && change.NewValue != null && _textMate != null) + { + if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) + { _textMate.SetTheme(_registryOptions.LoadTheme(ThemeName.DarkPlus)); - } else { + } + else + { _textMate.SetTheme(_registryOptions.LoadTheme(ThemeName.LightPlus)); } } } - private void UpdateGrammar() { + private void UpdateGrammar() + { if (_textMate == null || DiffData == null) return; var ext = Path.GetExtension(DiffData.File); - if (ext == ".h") { + if (ext == ".h") + { _textMate.SetGrammar(_registryOptions.GetScopeByLanguageId("cpp")); - } else { + } + else + { _textMate.SetGrammar(_registryOptions.GetScopeByExtension(ext)); } } @@ -313,21 +376,27 @@ namespace SourceGit.Views { private TextMate.Installation _textMate; } - public class SingleSideTextDiffPresenter : TextEditor { - public class LineNumberMargin : AbstractMargin { - public LineNumberMargin(SingleSideTextDiffPresenter editor) { + public class SingleSideTextDiffPresenter : TextEditor + { + public class LineNumberMargin : AbstractMargin + { + public LineNumberMargin(SingleSideTextDiffPresenter editor) + { _editor = editor; ClipToBounds = true; } - public override void Render(DrawingContext context) { + public override void Render(DrawingContext context) + { if (_editor.DiffData == null) return; var view = TextView; - if (view != null && view.VisualLinesValid) { + if (view != null && view.VisualLinesValid) + { var typeface = view.CreateTypeface(); var infos = _editor.IsOld ? _editor.DiffData.Old : _editor.DiffData.New; - foreach (var line in view.VisualLines) { + foreach (var line in view.VisualLines) + { var index = line.FirstDocumentLine.LineNumber; if (index > infos.Count) break; @@ -348,10 +417,14 @@ namespace SourceGit.Views { } } - protected override Size MeasureOverride(Size availableSize) { - if (_editor.DiffData == null || TextView == null) { + protected override Size MeasureOverride(Size availableSize) + { + if (_editor.DiffData == null || TextView == null) + { return new Size(32, 0); - } else { + } + else + { var typeface = TextView.CreateTypeface(); var test = new FormattedText( $"{_editor.DiffData.MaxLineNumber}", @@ -364,43 +437,51 @@ namespace SourceGit.Views { } } - private SingleSideTextDiffPresenter _editor; + private readonly SingleSideTextDiffPresenter _editor; } - public class VerticalSeperatorMargin : AbstractMargin { - public VerticalSeperatorMargin(SingleSideTextDiffPresenter editor) { + public class VerticalSeperatorMargin : AbstractMargin + { + public VerticalSeperatorMargin(SingleSideTextDiffPresenter editor) + { _editor = editor; } - public override void Render(DrawingContext context) { + public override void Render(DrawingContext context) + { var pen = new Pen(_editor.BorderBrush, 1); context.DrawLine(pen, new Point(0, 0), new Point(0, Bounds.Height)); } - protected override Size MeasureOverride(Size availableSize) { + protected override Size MeasureOverride(Size availableSize) + { return new Size(1, 0); } - private SingleSideTextDiffPresenter _editor = null; + private readonly SingleSideTextDiffPresenter _editor = null; } - public class LineBackgroundRenderer : IBackgroundRenderer { + public class LineBackgroundRenderer : IBackgroundRenderer + { private static readonly Brush BG_EMPTY = new SolidColorBrush(Color.FromArgb(60, 0, 0, 0)); private static readonly Brush BG_ADDED = new SolidColorBrush(Color.FromArgb(60, 0, 255, 0)); private static readonly Brush BG_DELETED = new SolidColorBrush(Color.FromArgb(60, 255, 0, 0)); public KnownLayer Layer => KnownLayer.Background; - public LineBackgroundRenderer(SingleSideTextDiffPresenter editor) { + public LineBackgroundRenderer(SingleSideTextDiffPresenter editor) + { _editor = editor; } - public void Draw(TextView textView, DrawingContext drawingContext) { + public void Draw(TextView textView, DrawingContext drawingContext) + { if (_editor.Document == null || !textView.VisualLinesValid) return; var width = textView.Bounds.Width; var infos = _editor.IsOld ? _editor.DiffData.Old : _editor.DiffData.New; - foreach (var line in textView.VisualLines) { + foreach (var line in textView.VisualLines) + { var index = line.FirstDocumentLine.LineNumber; if (index > infos.Count) break; @@ -413,36 +494,43 @@ namespace SourceGit.Views { } } - private IBrush GetBrushByLineType(Models.TextDiffLineType type) { - switch (type) { - case Models.TextDiffLineType.None: return BG_EMPTY; - case Models.TextDiffLineType.Added: return BG_ADDED; - case Models.TextDiffLineType.Deleted: return BG_DELETED; - default: return null; + private IBrush GetBrushByLineType(Models.TextDiffLineType type) + { + switch (type) + { + case Models.TextDiffLineType.None: return BG_EMPTY; + case Models.TextDiffLineType.Added: return BG_ADDED; + case Models.TextDiffLineType.Deleted: return BG_DELETED; + default: return null; } } - private SingleSideTextDiffPresenter _editor = null; + private readonly SingleSideTextDiffPresenter _editor = null; } - public class LineStyleTransformer : DocumentColorizingTransformer { + public class LineStyleTransformer : DocumentColorizingTransformer + { private static readonly Brush HL_ADDED = new SolidColorBrush(Color.FromArgb(90, 0, 255, 0)); private static readonly Brush HL_DELETED = new SolidColorBrush(Color.FromArgb(80, 255, 0, 0)); - public LineStyleTransformer(SingleSideTextDiffPresenter editor, IBrush indicatorFG) { + public LineStyleTransformer(SingleSideTextDiffPresenter editor, IBrush indicatorFG) + { _editor = editor; _indicatorFG = indicatorFG; _indicatorTypeface = new Typeface("fonts:SourceGit#JetBrains Mono", FontStyle.Italic); } - protected override void ColorizeLine(DocumentLine line) { + protected override void ColorizeLine(DocumentLine line) + { var infos = _editor.IsOld ? _editor.DiffData.Old : _editor.DiffData.New; var idx = line.LineNumber; if (idx > infos.Count) return; var info = infos[idx - 1]; - if (info.Type == Models.TextDiffLineType.Indicator) { - ChangeLinePart(line.Offset, line.EndOffset, v => { + if (info.Type == Models.TextDiffLineType.Indicator) + { + ChangeLinePart(line.Offset, line.EndOffset, v => + { v.TextRunProperties.SetForegroundBrush(_indicatorFG); v.TextRunProperties.SetTypeface(_indicatorTypeface); }); @@ -450,25 +538,29 @@ namespace SourceGit.Views { return; } - if (info.Highlights.Count > 0) { + if (info.Highlights.Count > 0) + { var bg = info.Type == Models.TextDiffLineType.Added ? HL_ADDED : HL_DELETED; - foreach (var highlight in info.Highlights) { - ChangeLinePart(line.Offset + highlight.Start, line.Offset + highlight.Start + highlight.Count, v => { + foreach (var highlight in info.Highlights) + { + ChangeLinePart(line.Offset + highlight.Start, line.Offset + highlight.Start + highlight.Count, v => + { v.TextRunProperties.SetBackgroundBrush(bg); }); } } } - private SingleSideTextDiffPresenter _editor; - private IBrush _indicatorFG = Brushes.DarkGray; - private Typeface _indicatorTypeface = Typeface.Default; + private readonly SingleSideTextDiffPresenter _editor; + private readonly IBrush _indicatorFG = Brushes.DarkGray; + private readonly Typeface _indicatorTypeface = Typeface.Default; } public static readonly StyledProperty IsOldProperty = AvaloniaProperty.Register(nameof(IsOld)); - public bool IsOld { + public bool IsOld + { get => GetValue(IsOldProperty); set => SetValue(IsOldProperty, value); } @@ -476,7 +568,8 @@ namespace SourceGit.Views { public static readonly StyledProperty DiffDataProperty = AvaloniaProperty.Register(nameof(DiffData)); - public ViewModels.TwoSideTextDiff DiffData { + public ViewModels.TwoSideTextDiff DiffData + { get => GetValue(DiffDataProperty); set => SetValue(DiffDataProperty, value); } @@ -484,7 +577,8 @@ namespace SourceGit.Views { public static readonly StyledProperty SecondaryFGProperty = AvaloniaProperty.Register(nameof(SecondaryFG), Brushes.Gray); - public IBrush SecondaryFG { + public IBrush SecondaryFG + { get => GetValue(SecondaryFGProperty); set => SetValue(SecondaryFGProperty, value); } @@ -492,24 +586,28 @@ namespace SourceGit.Views { public static readonly StyledProperty SyncScrollOffsetProperty = AvaloniaProperty.Register(nameof(SyncScrollOffset), Vector.Zero); - public Vector SyncScrollOffset { + public Vector SyncScrollOffset + { get => GetValue(SyncScrollOffsetProperty); set => SetValue(SyncScrollOffsetProperty, value); } protected override Type StyleKeyOverride => typeof(TextEditor); - public SingleSideTextDiffPresenter() : base(new TextArea(), new TextDocument()) { + public SingleSideTextDiffPresenter() : base(new TextArea(), new TextDocument()) + { IsReadOnly = true; ShowLineNumbers = false; WordWrap = false; } - protected override void OnLoaded(RoutedEventArgs e) { + protected override void OnLoaded(RoutedEventArgs e) + { base.OnLoaded(e); _scrollViewer = this.FindDescendantOfType(); - if (_scrollViewer != null) { + if (_scrollViewer != null) + { _scrollViewer.Offset = SyncScrollOffset; _scrollViewer.ScrollChanged += OnTextViewScrollChanged; } @@ -520,9 +618,12 @@ namespace SourceGit.Views { TextArea.TextView.BackgroundRenderers.Add(new LineBackgroundRenderer(this)); TextArea.TextView.ContextRequested += OnTextViewContextRequested; - if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) { + if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) + { _registryOptions = new RegistryOptions(ThemeName.DarkPlus); - } else { + } + else + { _registryOptions = new RegistryOptions(ThemeName.LightPlus); } @@ -533,13 +634,15 @@ namespace SourceGit.Views { TextArea.TextView.LineTransformers.Add(new LineStyleTransformer(this, SecondaryFG)); } - protected override void OnUnloaded(RoutedEventArgs e) { + protected override void OnUnloaded(RoutedEventArgs e) + { base.OnUnloaded(e); - if (_scrollViewer != null) { + if (_scrollViewer != null) + { _scrollViewer.ScrollChanged -= OnTextViewScrollChanged; _scrollViewer = null; - } + } TextArea.LeftMargins.Clear(); TextArea.TextView.BackgroundRenderers.Clear(); @@ -551,28 +654,35 @@ namespace SourceGit.Views { GC.Collect(); } - private void OnTextViewScrollChanged(object sender, ScrollChangedEventArgs e) { - if (_syncScrollingByOthers) { + private void OnTextViewScrollChanged(object sender, ScrollChangedEventArgs e) + { + if (_syncScrollingByOthers) + { _syncScrollingByOthers = false; - } else { + } + else + { SyncScrollOffset = _scrollViewer.Offset; } } - private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e) { + private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e) + { var selection = TextArea.Selection; if (selection.IsEmpty) return; var menu = new ContextMenu(); var parentView = this.FindAncestorOfType(); - if (parentView != null) { + if (parentView != null) + { parentView.FillContextMenuForWorkingCopyChange(menu, selection.StartPosition.Line, selection.EndPosition.Line, IsOld); } var copy = new MenuItem(); copy.Header = App.Text("Copy"); copy.Icon = App.CreateMenuIcon("Icons.Copy"); - copy.Click += (o, ev) => { + copy.Click += (o, ev) => + { App.CopyText(SelectedText); ev.Handled = true; }; @@ -582,57 +692,82 @@ namespace SourceGit.Views { e.Handled = true; } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { base.OnPropertyChanged(change); - if (change.Property == DiffDataProperty) { - if (DiffData != null) { + if (change.Property == DiffDataProperty) + { + if (DiffData != null) + { var builder = new StringBuilder(); - if (IsOld) { - foreach (var line in DiffData.Old) { + if (IsOld) + { + foreach (var line in DiffData.Old) + { builder.AppendLine(line.Content); } - } else { - foreach (var line in DiffData.New) { + } + else + { + foreach (var line in DiffData.New) + { builder.AppendLine(line.Content); } } UpdateGrammar(); Text = builder.ToString(); - } else { + } + else + { Text = string.Empty; } - } else if (change.Property == SyncScrollOffsetProperty) { + } + else if (change.Property == SyncScrollOffsetProperty) + { if (_scrollViewer == null) return; var curOffset = _scrollViewer.Offset; - if (!curOffset.Equals(SyncScrollOffset)) { + if (!curOffset.Equals(SyncScrollOffset)) + { _syncScrollingByOthers = true; - - if (curOffset.X != SyncScrollOffset.X) { + + if (curOffset.X != SyncScrollOffset.X) + { var offset = new Vector(Math.Min(_scrollViewer.ScrollBarMaximum.X, SyncScrollOffset.X), SyncScrollOffset.Y); _scrollViewer.Offset = offset; - } else { + } + else + { _scrollViewer.Offset = SyncScrollOffset; } } - } else if (change.Property.Name == "ActualThemeVariant" && change.NewValue != null && _textMate != null) { - if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) { + } + else if (change.Property.Name == "ActualThemeVariant" && change.NewValue != null && _textMate != null) + { + if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) + { _textMate.SetTheme(_registryOptions.LoadTheme(ThemeName.DarkPlus)); - } else { + } + else + { _textMate.SetTheme(_registryOptions.LoadTheme(ThemeName.LightPlus)); } } } - private void UpdateGrammar() { + private void UpdateGrammar() + { if (_textMate == null || DiffData == null) return; var ext = Path.GetExtension(DiffData.File); - if (ext == ".h") { + if (ext == ".h") + { _textMate.SetGrammar(_registryOptions.GetScopeByLanguageId("cpp")); - } else { + } + else + { _textMate.SetGrammar(_registryOptions.GetScopeByExtension(ext)); } } @@ -644,11 +779,13 @@ namespace SourceGit.Views { private bool _syncScrollingByOthers = false; } - public partial class TextDiffView : UserControl { + public partial class TextDiffView : UserControl + { public static readonly StyledProperty TextDiffProperty = AvaloniaProperty.Register(nameof(TextDiff), null); - public Models.TextDiff TextDiff { + public Models.TextDiff TextDiff + { get => GetValue(TextDiffProperty); set => SetValue(TextDiffProperty, value); } @@ -656,16 +793,19 @@ namespace SourceGit.Views { public static readonly StyledProperty UseCombinedProperty = AvaloniaProperty.Register(nameof(UseCombined), false); - public bool UseCombined { + public bool UseCombined + { get => GetValue(UseCombinedProperty); set => SetValue(UseCombinedProperty, value); } - public TextDiffView() { + public TextDiffView() + { InitializeComponent(); } - public void FillContextMenuForWorkingCopyChange(ContextMenu menu, int startLine, int endLine, bool isOldSide) { + public void FillContextMenuForWorkingCopyChange(ContextMenu menu, int startLine, int endLine, bool isOldSide) + { var parentView = this.FindAncestorOfType(); if (parentView == null) return; @@ -675,7 +815,8 @@ namespace SourceGit.Views { var change = ctx.WorkingCopyChange; if (change == null) return; - if (startLine > endLine) { + if (startLine > endLine) + { var tmp = startLine; startLine = endLine; endLine = tmp; @@ -686,15 +827,18 @@ namespace SourceGit.Views { // If all changes has been selected the use method provided by ViewModels.WorkingCopy. // Otherwise, use `git apply` - if (!selection.HasLeftChanges) { + if (!selection.HasLeftChanges) + { var workcopyView = this.FindAncestorOfType(); if (workcopyView == null) return; - if (ctx.IsUnstaged) { + if (ctx.IsUnstaged) + { var stage = new MenuItem(); stage.Header = App.Text("FileCM.StageSelectedLines"); stage.Icon = App.CreateMenuIcon("Icons.File.Add"); - stage.Click += (_, e) => { + stage.Click += (_, e) => + { var workcopy = workcopyView.DataContext as ViewModels.WorkingCopy; workcopy.StageChanges(new List { change }); e.Handled = true; @@ -703,7 +847,8 @@ namespace SourceGit.Views { var discard = new MenuItem(); discard.Header = App.Text("FileCM.DiscardSelectedLines"); discard.Icon = App.CreateMenuIcon("Icons.Undo"); - discard.Click += (_, e) => { + discard.Click += (_, e) => + { var workcopy = workcopyView.DataContext as ViewModels.WorkingCopy; workcopy.Discard(new List { change }, true); e.Handled = true; @@ -711,11 +856,14 @@ namespace SourceGit.Views { menu.Items.Add(stage); menu.Items.Add(discard); - } else { + } + else + { var unstage = new MenuItem(); unstage.Header = App.Text("FileCM.UnstageSelectedLines"); unstage.Icon = App.CreateMenuIcon("Icons.File.Remove"); - unstage.Click += (_, e) => { + unstage.Click += (_, e) => + { var workcopy = workcopyView.DataContext as ViewModels.WorkingCopy; workcopy.UnstageChanges(new List { change }); e.Handled = true; @@ -724,7 +872,8 @@ namespace SourceGit.Views { var discard = new MenuItem(); discard.Header = App.Text("FileCM.DiscardSelectedLines"); discard.Icon = App.CreateMenuIcon("Icons.Undo"); - discard.Click += (_, e) => { + discard.Click += (_, e) => + { var workcopy = workcopyView.DataContext as ViewModels.WorkingCopy; workcopy.Discard(new List { change }, false); e.Handled = true; @@ -733,25 +882,34 @@ namespace SourceGit.Views { menu.Items.Add(unstage); menu.Items.Add(discard); } - } else { + } + else + { var repoView = this.FindAncestorOfType(); if (repoView == null) return; - if (ctx.IsUnstaged) { + if (ctx.IsUnstaged) + { var stage = new MenuItem(); stage.Header = App.Text("FileCM.StageSelectedLines"); stage.Icon = App.CreateMenuIcon("Icons.File.Add"); - stage.Click += (_, e) => { + stage.Click += (_, e) => + { var repo = repoView.DataContext as ViewModels.Repository; repo.SetWatcherEnabled(false); var tmpFile = Path.GetTempFileName(); - if (change.WorkTree == Models.ChangeState.Untracked) { + if (change.WorkTree == Models.ChangeState.Untracked) + { TextDiff.GenerateNewPatchFromSelection(change, null, selection, false, tmpFile); - } else if (UseCombined) { + } + else if (UseCombined) + { var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result(); TextDiff.GeneratePatchFromSelection(change, treeGuid, selection, false, tmpFile); - } else { + } + else + { var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result(); TextDiff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, false, isOldSide, tmpFile); } @@ -767,17 +925,23 @@ namespace SourceGit.Views { var discard = new MenuItem(); discard.Header = App.Text("FileCM.DiscardSelectedLines"); discard.Icon = App.CreateMenuIcon("Icons.Undo"); - discard.Click += (_, e) => { + discard.Click += (_, e) => + { var repo = repoView.DataContext as ViewModels.Repository; repo.SetWatcherEnabled(false); var tmpFile = Path.GetTempFileName(); - if (change.WorkTree == Models.ChangeState.Untracked) { + if (change.WorkTree == Models.ChangeState.Untracked) + { TextDiff.GenerateNewPatchFromSelection(change, null, selection, true, tmpFile); - } else if (UseCombined) { + } + else if (UseCombined) + { var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result(); TextDiff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile); - } else { + } + else + { var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result(); TextDiff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile); } @@ -792,21 +956,29 @@ namespace SourceGit.Views { menu.Items.Add(stage); menu.Items.Add(discard); - } else { + } + else + { var unstage = new MenuItem(); unstage.Header = App.Text("FileCM.UnstageSelectedLines"); unstage.Icon = App.CreateMenuIcon("Icons.File.Remove"); - unstage.Click += (_, e) => { + unstage.Click += (_, e) => + { var repo = repoView.DataContext as ViewModels.Repository; repo.SetWatcherEnabled(false); var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result(); var tmpFile = Path.GetTempFileName(); - if (change.Index == Models.ChangeState.Added) { + if (change.Index == Models.ChangeState.Added) + { TextDiff.GenerateNewPatchFromSelection(change, treeGuid, selection, true, tmpFile); - } else if (UseCombined) { + } + else if (UseCombined) + { TextDiff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile); - } else { + } + else + { TextDiff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile); } @@ -821,17 +993,23 @@ namespace SourceGit.Views { var discard = new MenuItem(); discard.Header = App.Text("FileCM.DiscardSelectedLines"); discard.Icon = App.CreateMenuIcon("Icons.Undo"); - discard.Click += (_, e) => { + discard.Click += (_, e) => + { var repo = repoView.DataContext as ViewModels.Repository; repo.SetWatcherEnabled(false); var tmpFile = Path.GetTempFileName(); - if (change.WorkTree == Models.ChangeState.Untracked) { + if (change.WorkTree == Models.ChangeState.Untracked) + { TextDiff.GenerateNewPatchFromSelection(change, null, selection, true, tmpFile); - } else if (UseCombined) { + } + else if (UseCombined) + { var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result(); TextDiff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile); - } else { + } + else + { var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result(); TextDiff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile); } @@ -852,31 +1030,42 @@ namespace SourceGit.Views { menu.Items.Add(new MenuItem() { Header = "-" }); } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { base.OnPropertyChanged(change); - if (change.Property == TextDiffProperty || change.Property == UseCombinedProperty) { - if (TextDiff == null) { + if (change.Property == TextDiffProperty || change.Property == UseCombinedProperty) + { + if (TextDiff == null) + { Content = null; - } else if (UseCombined) { + } + else if (UseCombined) + { Content = TextDiff; - } else { + } + else + { Content = new ViewModels.TwoSideTextDiff(TextDiff); } } } - private Models.TextDiffSelection GetUnifiedSelection(int startLine, int endLine, bool isOldSide) { + private Models.TextDiffSelection GetUnifiedSelection(int startLine, int endLine, bool isOldSide) + { var rs = new Models.TextDiffSelection(); var diff = TextDiff; endLine = Math.Min(endLine, TextDiff.Lines.Count); - if (Content is ViewModels.TwoSideTextDiff twoSides) { + if (Content is ViewModels.TwoSideTextDiff twoSides) + { var target = isOldSide ? twoSides.Old : twoSides.New; var firstContentLine = -1; - for (int i = startLine - 1; i < endLine; i++) { + for (int i = startLine - 1; i < endLine; i++) + { var line = target[i]; - if (line.Type != Models.TextDiffLineType.None) { + if (line.Type != Models.TextDiffLineType.None) + { firstContentLine = i; break; } @@ -885,9 +1074,11 @@ namespace SourceGit.Views { if (firstContentLine < 0) return rs; var endContentLine = -1; - for (int i = Math.Min(endLine - 1, target.Count - 1); i >= startLine - 1; i--) { + for (int i = Math.Min(endLine - 1, target.Count - 1); i >= startLine - 1; i--) + { var line = target[i]; - if (line.Type != Models.TextDiffLineType.None) { + if (line.Type != Models.TextDiffLineType.None) + { endContentLine = i; break; } @@ -904,44 +1095,65 @@ namespace SourceGit.Views { rs.StartLine = startLine; rs.EndLine = endLine; - for (int i = 0; i < startLine - 1; i++) { + for (int i = 0; i < startLine - 1; i++) + { var line = diff.Lines[i]; - if (line.Type == Models.TextDiffLineType.Added) { + if (line.Type == Models.TextDiffLineType.Added) + { rs.HasLeftChanges = true; rs.IgnoredAdds++; - } else if (line.Type == Models.TextDiffLineType.Deleted) { + } + else if (line.Type == Models.TextDiffLineType.Deleted) + { rs.HasLeftChanges = true; rs.IgnoredDeletes++; } } - for (int i = startLine - 1; i < endLine; i++) { + for (int i = startLine - 1; i < endLine; i++) + { var line = diff.Lines[i]; - if (line.Type == Models.TextDiffLineType.Added) { - if (UseCombined) { + if (line.Type == Models.TextDiffLineType.Added) + { + if (UseCombined) + { rs.HasChanges = true; break; - } else if (isOldSide) { + } + else if (isOldSide) + { rs.HasLeftChanges = true; - } else { + } + else + { rs.HasChanges = true; } - } else if (line.Type == Models.TextDiffLineType.Deleted) { - if (UseCombined) { + } + else if (line.Type == Models.TextDiffLineType.Deleted) + { + if (UseCombined) + { rs.HasChanges = true; break; - } else if (isOldSide) { + } + else if (isOldSide) + { rs.HasChanges = true; - } else { + } + else + { rs.HasLeftChanges = true; } } } - if (!rs.HasLeftChanges) { - for (int i = endLine; i < diff.Lines.Count; i++) { + if (!rs.HasLeftChanges) + { + for (int i = endLine; i < diff.Lines.Count; i++) + { var line = diff.Lines[i]; - if (line.Type == Models.TextDiffLineType.Added || line.Type == Models.TextDiffLineType.Deleted) { + if (line.Type == Models.TextDiffLineType.Added || line.Type == Models.TextDiffLineType.Deleted) + { rs.HasLeftChanges = true; break; } @@ -949,6 +1161,6 @@ namespace SourceGit.Views { } return rs; - } + } } -} +} \ No newline at end of file diff --git a/src/Views/Welcome.axaml.cs b/src/Views/Welcome.axaml.cs index 3dd23bb3..c82b3271 100644 --- a/src/Views/Welcome.axaml.cs +++ b/src/Views/Welcome.axaml.cs @@ -1,52 +1,67 @@ +using System.IO; +using System.Threading.Tasks; + using Avalonia; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Platform.Storage; using Avalonia.Threading; -using System.IO; -using System.Threading.Tasks; -namespace SourceGit.Views { - public partial class Welcome : UserControl { - public Welcome() { +namespace SourceGit.Views +{ + public partial class Welcome : UserControl + { + public Welcome() + { InitializeComponent(); } - private void SetupTreeViewDragAndDrop(object sender, RoutedEventArgs e) { - if (sender is TreeView view) { + private void SetupTreeViewDragAndDrop(object sender, RoutedEventArgs e) + { + if (sender is TreeView view) + { DragDrop.SetAllowDrop(view, true); view.AddHandler(DragDrop.DragOverEvent, DragOverTreeView); view.AddHandler(DragDrop.DropEvent, DropOnTreeView); } } - private void SetupTreeNodeDragAndDrop(object sender, RoutedEventArgs e) { - if (sender is Grid grid) { + private void SetupTreeNodeDragAndDrop(object sender, RoutedEventArgs e) + { + if (sender is Grid grid) + { DragDrop.SetAllowDrop(grid, true); grid.AddHandler(DragDrop.DragOverEvent, DragOverTreeNode); grid.AddHandler(DragDrop.DropEvent, DropOnTreeNode); } } - private void OnPointerPressedTreeNode(object sender, PointerPressedEventArgs e) { - if (e.GetCurrentPoint(sender as Visual).Properties.IsLeftButtonPressed) { + private void OnPointerPressedTreeNode(object sender, PointerPressedEventArgs e) + { + if (e.GetCurrentPoint(sender as Visual).Properties.IsLeftButtonPressed) + { _pressedTreeNode = true; _startDragTreeNode = false; _pressedTreeNodePosition = e.GetPosition(sender as Grid); - } else { + } + else + { _pressedTreeNode = false; _startDragTreeNode = false; - } + } } - private void OnPointerReleasedOnTreeNode(object sender, PointerReleasedEventArgs e) { + private void OnPointerReleasedOnTreeNode(object sender, PointerReleasedEventArgs e) + { _pressedTreeNode = false; _startDragTreeNode = false; } - private void OnPointerMovedOverTreeNode(object sender, PointerEventArgs e) { - if (_pressedTreeNode && !_startDragTreeNode && sender is Grid grid) { + private void OnPointerMovedOverTreeNode(object sender, PointerEventArgs e) + { + if (_pressedTreeNode && !_startDragTreeNode && sender is Grid grid) + { var delta = e.GetPosition(grid) - _pressedTreeNodePosition; var sizeSquired = delta.X * delta.X + delta.Y * delta.Y; if (sizeSquired < 64) return; @@ -59,34 +74,45 @@ namespace SourceGit.Views { } } - private void OnTreeViewLostFocus(object sender, RoutedEventArgs e) { + private void OnTreeViewLostFocus(object sender, RoutedEventArgs e) + { _pressedTreeNode = false; _startDragTreeNode = false; } - private void DragOverTreeView(object sender, DragEventArgs e) { - if (e.Data.Contains("MovedRepositoryTreeNode") || e.Data.Contains(DataFormats.Files)) { + private void DragOverTreeView(object sender, DragEventArgs e) + { + if (e.Data.Contains("MovedRepositoryTreeNode") || e.Data.Contains(DataFormats.Files)) + { e.DragEffects = DragDropEffects.Move; e.Handled = true; - } else { + } + else + { e.DragEffects = DragDropEffects.None; e.Handled = true; } } - private async void DropOnTreeView(object sender, DragEventArgs e) { - if (e.Data.Contains("MovedRepositoryTreeNode")) { + private async void DropOnTreeView(object sender, DragEventArgs e) + { + if (e.Data.Contains("MovedRepositoryTreeNode")) + { e.Handled = true; var moved = e.Data.Get("MovedRepositoryTreeNode") as ViewModels.RepositoryNode; - if (moved != null && DataContext is ViewModels.Welcome vm) { + if (moved != null && DataContext is ViewModels.Welcome vm) + { vm.MoveNode(moved, null); } - } else if (e.Data.Contains(DataFormats.Files)) { + } + else if (e.Data.Contains(DataFormats.Files)) + { e.Handled = true; var items = e.Data.GetFiles(); - foreach (var item in items) { + foreach (var item in items) + { await OpenOrInitRepository(item.Path.LocalPath); break; } @@ -96,46 +122,58 @@ namespace SourceGit.Views { _startDragTreeNode = false; } - private void DragOverTreeNode(object sender, DragEventArgs e) { - if (e.Data.Contains("MovedRepositoryTreeNode") || e.Data.Contains(DataFormats.Files)) { + private void DragOverTreeNode(object sender, DragEventArgs e) + { + if (e.Data.Contains("MovedRepositoryTreeNode") || e.Data.Contains(DataFormats.Files)) + { var grid = sender as Grid; if (grid == null) return; var to = grid.DataContext as ViewModels.RepositoryNode; if (to == null) return; - if (to.IsRepository) { + if (to.IsRepository) + { e.DragEffects = DragDropEffects.None; e.Handled = true; - } else { + } + else + { e.DragEffects = DragDropEffects.Move; e.Handled = true; } } } - private async void DropOnTreeNode(object sender, DragEventArgs e) { + private async void DropOnTreeNode(object sender, DragEventArgs e) + { var grid = sender as Grid; if (grid == null) return; var to = grid.DataContext as ViewModels.RepositoryNode; - if (to == null || to.IsRepository) { + if (to == null || to.IsRepository) + { e.Handled = true; return; } - if (e.Data.Contains("MovedRepositoryTreeNode")) { + if (e.Data.Contains("MovedRepositoryTreeNode")) + { e.Handled = true; var moved = e.Data.Get("MovedRepositoryTreeNode") as ViewModels.RepositoryNode; - if (to != null && moved != null && to != moved && DataContext is ViewModels.Welcome vm) { + if (to != null && moved != null && to != moved && DataContext is ViewModels.Welcome vm) + { vm.MoveNode(moved, to); } - } else if (e.Data.Contains(DataFormats.Files)) { + } + else if (e.Data.Contains(DataFormats.Files)) + { e.Handled = true; var items = e.Data.GetFiles(); - foreach (var item in items) { + foreach (var item in items) + { await OpenOrInitRepository(item.Path.LocalPath, to); break; } @@ -145,12 +183,14 @@ namespace SourceGit.Views { _startDragTreeNode = false; } - private void OnDoubleTappedTreeNode(object sender, TappedEventArgs e) { + private void OnDoubleTappedTreeNode(object sender, TappedEventArgs e) + { var grid = sender as Grid; if (grid == null) return; var to = grid.DataContext as ViewModels.RepositoryNode; - if (to == null || !to.IsRepository) { + if (to == null || !to.IsRepository) + { return; } @@ -159,39 +199,48 @@ namespace SourceGit.Views { e.Handled = true; } - private async void OpenLocalRepository(object sender, RoutedEventArgs e) { + private async void OpenLocalRepository(object sender, RoutedEventArgs e) + { if (!ViewModels.PopupHost.CanCreatePopup()) return; var topLevel = TopLevel.GetTopLevel(this); var options = new FolderPickerOpenOptions() { AllowMultiple = false }; var selected = await topLevel.StorageProvider.OpenFolderPickerAsync(options); - if (selected.Count == 1) { + if (selected.Count == 1) + { await OpenOrInitRepository(selected[0].Path.LocalPath); } } - private Task OpenOrInitRepository(string path, ViewModels.RepositoryNode parent = null) { + private Task OpenOrInitRepository(string path, ViewModels.RepositoryNode parent = null) + { var launcher = TopLevel.GetTopLevel(this).DataContext as ViewModels.Launcher; var page = launcher.ActivePage; - if (!Directory.Exists(path)) { + if (!Directory.Exists(path)) + { if (File.Exists(path)) path = Path.GetDirectoryName(path); else return null; } - return Task.Run(() => { + return Task.Run(() => + { var root = new Commands.QueryRepositoryRootPath(path).Result(); - if (string.IsNullOrEmpty(root)) { - Dispatcher.UIThread.Invoke(() => { + if (string.IsNullOrEmpty(root)) + { + Dispatcher.UIThread.Invoke(() => + { (DataContext as ViewModels.Welcome).InitRepository(path); - }); + }); return; } var gitDir = new Commands.QueryGitDir(root).Result(); - Dispatcher.UIThread.Invoke(() => { + Dispatcher.UIThread.Invoke(() => + { var repo = ViewModels.Preference.AddRepository(root, gitDir); - var node = new ViewModels.RepositoryNode() { + var node = new ViewModels.RepositoryNode() + { Id = repo.FullPath, Name = Path.GetFileName(repo.FullPath), Bookmark = 0, @@ -199,7 +248,7 @@ namespace SourceGit.Views { }; ViewModels.Preference.AddNode(node, parent); launcher.OpenRepositoryInTab(node, page); - }); + }); }); } diff --git a/src/Views/WorkingCopy.axaml.cs b/src/Views/WorkingCopy.axaml.cs index 350a3fd2..4cae8491 100644 --- a/src/Views/WorkingCopy.axaml.cs +++ b/src/Views/WorkingCopy.axaml.cs @@ -1,18 +1,24 @@ +using System.Collections.Generic; + using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.VisualTree; -using System.Collections.Generic; -namespace SourceGit.Views { - public partial class WorkingCopy : UserControl { - public WorkingCopy() { +namespace SourceGit.Views +{ + public partial class WorkingCopy : UserControl + { + public WorkingCopy() + { InitializeComponent(); } - private void ViewAssumeUnchanged(object sender, RoutedEventArgs e) { + private void ViewAssumeUnchanged(object sender, RoutedEventArgs e) + { var repoPage = this.FindAncestorOfType(); - if (repoPage != null) { + if (repoPage != null) + { var repo = (repoPage.DataContext as ViewModels.Repository).FullPath; var window = new AssumeUnchangedManager(); window.DataContext = new ViewModels.AssumeUnchangedManager(repo); @@ -22,34 +28,40 @@ namespace SourceGit.Views { e.Handled = true; } - private void StageSelected(object sender, RoutedEventArgs e) { + private void StageSelected(object sender, RoutedEventArgs e) + { var vm = DataContext as ViewModels.WorkingCopy; if (vm == null) return; List selected = new List(); - switch (ViewModels.Preference.Instance.UnstagedChangeViewMode) { - case Models.ChangeViewMode.List: - foreach (var item in unstagedList.SelectedItems) { - if (item is Models.Change change) selected.Add(change); - } - break; - case Models.ChangeViewMode.Grid: - foreach (var item in unstagedGrid.SelectedItems) { - if (item is Models.Change change) selected.Add(change); - } - break; - default: - foreach (var item in unstagedTree.SelectedItems) { - if (item is ViewModels.FileTreeNode node) CollectChangesFromNode(selected, node); - } - break; + switch (ViewModels.Preference.Instance.UnstagedChangeViewMode) + { + case Models.ChangeViewMode.List: + foreach (var item in unstagedList.SelectedItems) + { + if (item is Models.Change change) selected.Add(change); + } + break; + case Models.ChangeViewMode.Grid: + foreach (var item in unstagedGrid.SelectedItems) + { + if (item is Models.Change change) selected.Add(change); + } + break; + default: + foreach (var item in unstagedTree.SelectedItems) + { + if (item is ViewModels.FileTreeNode node) CollectChangesFromNode(selected, node); + } + break; } vm.StageChanges(selected); e.Handled = true; } - private void StageAll(object sender, RoutedEventArgs e) { + private void StageAll(object sender, RoutedEventArgs e) + { var vm = DataContext as ViewModels.WorkingCopy; if (vm == null) return; @@ -57,34 +69,40 @@ namespace SourceGit.Views { e.Handled = true; } - private void UnstageSelected(object sender, RoutedEventArgs e) { + private void UnstageSelected(object sender, RoutedEventArgs e) + { var vm = DataContext as ViewModels.WorkingCopy; if (vm == null) return; List selected = new List(); - switch (ViewModels.Preference.Instance.StagedChangeViewMode) { - case Models.ChangeViewMode.List: - foreach (var item in stagedList.SelectedItems) { - if (item is Models.Change change) selected.Add(change); - } - break; - case Models.ChangeViewMode.Grid: - foreach (var item in stagedGrid.SelectedItems) { - if (item is Models.Change change) selected.Add(change); - } - break; - default: - foreach (var item in stagedTree.SelectedItems) { - if (item is ViewModels.FileTreeNode node) CollectChangesFromNode(selected, node); - } - break; + switch (ViewModels.Preference.Instance.StagedChangeViewMode) + { + case Models.ChangeViewMode.List: + foreach (var item in stagedList.SelectedItems) + { + if (item is Models.Change change) selected.Add(change); + } + break; + case Models.ChangeViewMode.Grid: + foreach (var item in stagedGrid.SelectedItems) + { + if (item is Models.Change change) selected.Add(change); + } + break; + default: + foreach (var item in stagedTree.SelectedItems) + { + if (item is ViewModels.FileTreeNode node) CollectChangesFromNode(selected, node); + } + break; } vm.UnstageChanges(selected); e.Handled = true; } - private void UnstageAll(object sender, RoutedEventArgs e) { + private void UnstageAll(object sender, RoutedEventArgs e) + { var vm = DataContext as ViewModels.WorkingCopy; if (vm == null) return; @@ -92,11 +110,14 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnUnstagedListKeyDown(object sender, KeyEventArgs e) { + private void OnUnstagedListKeyDown(object sender, KeyEventArgs e) + { var datagrid = sender as DataGrid; - if (datagrid.SelectedItems.Count > 0 && e.Key == Key.Space && DataContext is ViewModels.WorkingCopy vm) { + if (datagrid.SelectedItems.Count > 0 && e.Key == Key.Space && DataContext is ViewModels.WorkingCopy vm) + { List selected = new List(); - foreach (var item in datagrid.SelectedItems) { + foreach (var item in datagrid.SelectedItems) + { if (item is Models.Change change) selected.Add(change); } @@ -106,11 +127,14 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnUnstagedTreeViewKeyDown(object sender, KeyEventArgs e) { + private void OnUnstagedTreeViewKeyDown(object sender, KeyEventArgs e) + { var tree = sender as TreeView; - if (tree.SelectedItems.Count > 0 && e.Key == Key.Space && DataContext is ViewModels.WorkingCopy vm) { + if (tree.SelectedItems.Count > 0 && e.Key == Key.Space && DataContext is ViewModels.WorkingCopy vm) + { List selected = new List(); - foreach (var item in tree.SelectedItems) { + foreach (var item in tree.SelectedItems) + { if (item is ViewModels.FileTreeNode node) CollectChangesFromNode(selected, node); } @@ -120,11 +144,14 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnStagedListKeyDown(object sender, KeyEventArgs e) { + private void OnStagedListKeyDown(object sender, KeyEventArgs e) + { var datagrid = sender as DataGrid; - if (datagrid.SelectedItems.Count > 0 && e.Key == Key.Space && DataContext is ViewModels.WorkingCopy vm) { + if (datagrid.SelectedItems.Count > 0 && e.Key == Key.Space && DataContext is ViewModels.WorkingCopy vm) + { List selected = new List(); - foreach (var item in datagrid.SelectedItems) { + foreach (var item in datagrid.SelectedItems) + { if (item is Models.Change change) selected.Add(change); } @@ -134,11 +161,14 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnStagedTreeViewKeyDown(object sender, KeyEventArgs e) { + private void OnStagedTreeViewKeyDown(object sender, KeyEventArgs e) + { var tree = sender as TreeView; - if (tree.SelectedItems.Count > 0 && e.Key == Key.Space && DataContext is ViewModels.WorkingCopy vm) { + if (tree.SelectedItems.Count > 0 && e.Key == Key.Space && DataContext is ViewModels.WorkingCopy vm) + { List selected = new List(); - foreach (var item in tree.SelectedItems) { + foreach (var item in tree.SelectedItems) + { if (item is ViewModels.FileTreeNode node) CollectChangesFromNode(selected, node); } @@ -148,11 +178,14 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnUnstagedListContextRequested(object sender, ContextRequestedEventArgs e) { + private void OnUnstagedListContextRequested(object sender, ContextRequestedEventArgs e) + { var datagrid = sender as DataGrid; - if (datagrid.SelectedItems.Count > 0 && DataContext is ViewModels.WorkingCopy vm) { + if (datagrid.SelectedItems.Count > 0 && DataContext is ViewModels.WorkingCopy vm) + { List selected = new List(); - foreach (var item in datagrid.SelectedItems) { + foreach (var item in datagrid.SelectedItems) + { if (item is Models.Change change) selected.Add(change); } @@ -163,11 +196,14 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnUnstagedTreeViewContextRequested(object sender, ContextRequestedEventArgs e) { + private void OnUnstagedTreeViewContextRequested(object sender, ContextRequestedEventArgs e) + { var tree = sender as TreeView; - if (tree.SelectedItems.Count > 0 && DataContext is ViewModels.WorkingCopy vm) { + if (tree.SelectedItems.Count > 0 && DataContext is ViewModels.WorkingCopy vm) + { List selected = new List(); - foreach (var item in tree.SelectedItems) { + foreach (var item in tree.SelectedItems) + { if (item is ViewModels.FileTreeNode node) CollectChangesFromNode(selected, node); } @@ -178,11 +214,14 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnStagedListContextRequested(object sender, ContextRequestedEventArgs e) { + private void OnStagedListContextRequested(object sender, ContextRequestedEventArgs e) + { var datagrid = sender as DataGrid; - if (datagrid.SelectedItems.Count > 0 && DataContext is ViewModels.WorkingCopy vm) { + if (datagrid.SelectedItems.Count > 0 && DataContext is ViewModels.WorkingCopy vm) + { List selected = new List(); - foreach (var item in datagrid.SelectedItems) { + foreach (var item in datagrid.SelectedItems) + { if (item is Models.Change change) selected.Add(change); } @@ -193,11 +232,14 @@ namespace SourceGit.Views { e.Handled = true; } - private void OnStagedTreeViewContextRequested(object sender, ContextRequestedEventArgs e) { + private void OnStagedTreeViewContextRequested(object sender, ContextRequestedEventArgs e) + { var tree = sender as TreeView; - if (tree.SelectedItems.Count > 0 && DataContext is ViewModels.WorkingCopy vm) { + if (tree.SelectedItems.Count > 0 && DataContext is ViewModels.WorkingCopy vm) + { List selected = new List(); - foreach (var item in tree.SelectedItems) { + foreach (var item in tree.SelectedItems) + { if (item is ViewModels.FileTreeNode node) CollectChangesFromNode(selected, node); } @@ -208,12 +250,15 @@ namespace SourceGit.Views { e.Handled = true; } - private void StartAmend(object sender, RoutedEventArgs e) { + private void StartAmend(object sender, RoutedEventArgs e) + { var repoPage = this.FindAncestorOfType(); - if (repoPage != null) { + if (repoPage != null) + { var repo = (repoPage.DataContext as ViewModels.Repository).FullPath; var commits = new Commands.QueryCommits(repo, "-n 1", false).Result(); - if (commits.Count == 0) { + if (commits.Count == 0) + { App.RaiseException(repo, "No commits to amend!!!"); var chkBox = sender as CheckBox; @@ -229,29 +274,37 @@ namespace SourceGit.Views { e.Handled = true; } - private void Commit(object sender, RoutedEventArgs e) { + private void Commit(object sender, RoutedEventArgs e) + { var vm = DataContext as ViewModels.WorkingCopy; vm.DoCommit(false); e.Handled = true; } - private void CommitWithPush(object sender, RoutedEventArgs e) { + private void CommitWithPush(object sender, RoutedEventArgs e) + { var vm = DataContext as ViewModels.WorkingCopy; vm.DoCommit(true); e.Handled = true; } - private void CollectChangesFromNode(List outs, ViewModels.FileTreeNode node) { - if (node.IsFolder) { + private void CollectChangesFromNode(List outs, ViewModels.FileTreeNode node) + { + if (node.IsFolder) + { foreach (var child in node.Children) CollectChangesFromNode(outs, child); - } else { + } + else + { var change = node.Backend as Models.Change; if (change != null && !outs.Contains(change)) outs.Add(change); } } - private void OnOpenCommitMessagePicker(object sender, RoutedEventArgs e) { - if (sender is Button button && DataContext is ViewModels.WorkingCopy vm) { + private void OnOpenCommitMessagePicker(object sender, RoutedEventArgs e) + { + if (sender is Button button && DataContext is ViewModels.WorkingCopy vm) + { var menu = vm.CreateContextMenuForCommitMessages(); menu.Placement = PlacementMode.TopEdgeAlignedLeft; menu.Open(button); @@ -259,4 +312,4 @@ namespace SourceGit.Views { } } } -} +} \ No newline at end of file