code_style: using avalonia's editorconfig and run dotnet format.

This commit is contained in:
leo 2024-03-31 16:54:29 +08:00
parent 3c38f681bd
commit d89a00e559
233 changed files with 1806 additions and 1254 deletions

View file

@ -1,151 +1,138 @@
# editorconfig.org
# top-most EditorConfig file
root = true root = true
# All files # Default settings:
# A newline ending every file
# Use 4 spaces as indentation
[*] [*]
insert_final_newline = true
indent_style = space indent_style = space
indent_size = 4
# Xml files dotnet_style_operator_placement_when_wrapping = beginning_of_line
[*.xml] tab_width = 4
indent_size = 2 end_of_line = crlf
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_object_initializer = true:suggestion
dotnet_style_prefer_collection_expression = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_prefer_conditional_expression_over_return = true:silent
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_compound_assignment = true:suggestion
dotnet_style_prefer_simplified_interpolation = true:suggestion
dotnet_style_namespace_match_folder = true:suggestion
dotnet_style_readonly_field = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
dotnet_style_allow_multiple_blank_lines_experimental = true:silent
# C# files # C# files
[*.cs] [*.cs]
#### Core EditorConfig Options ####
# Indentation and spacing
indent_size = 4
tab_width = 4
# New line preferences # 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
# Namespaces
dotnet_style_namespace_match_folder = true:suggestion
csharp_style_namespace_declarations = block_scoped:error
# 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_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true csharp_new_line_between_query_expression_clauses = true
# trim_trailing_whitespace = true
# Indentation preferences # Indentation preferences
csharp_indent_block_contents = true csharp_indent_block_contents = true
csharp_indent_braces = false csharp_indent_braces = false
csharp_indent_case_contents = true csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_labels = one_less_than_current
csharp_indent_switch_labels = true csharp_indent_switch_labels = true
csharp_indent_labels = one_less_than_current
# avoid this. unless absolutely necessary
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion
# prefer var
csharp_style_var_for_built_in_types = true
csharp_style_var_when_type_is_apparent = true
csharp_style_var_elsewhere = true:suggestion
# use language keywords instead of BCL types
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
# name all constant fields using PascalCase
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.required_modifiers = const
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# private static fields should have s_ prefix
dotnet_naming_rule.private_static_fields_should_have_prefix.severity = suggestion
dotnet_naming_rule.private_static_fields_should_have_prefix.symbols = private_static_fields
dotnet_naming_rule.private_static_fields_should_have_prefix.style = private_static_prefix_style
dotnet_naming_symbols.private_static_fields.applicable_kinds = field
dotnet_naming_symbols.private_static_fields.required_modifiers = static
dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private
dotnet_naming_style.private_static_prefix_style.required_prefix = s_
dotnet_naming_style.private_static_prefix_style.capitalization = camel_case
# internal and private fields should be _camelCase
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
# use accessibility modifiers
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
# Code style defaults
dotnet_sort_system_directives_first = true
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = false
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
# Expression-bodied members
csharp_style_expression_bodied_methods = false:none
csharp_style_expression_bodied_constructors = false:none
csharp_style_expression_bodied_operators = false:none
csharp_style_expression_bodied_properties = true:none
csharp_style_expression_bodied_indexers = true:none
csharp_style_expression_bodied_accessors = true:none
# Pattern matching
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
# Null checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Space preferences # Space preferences
csharp_space_after_cast = false csharp_space_after_cast = false
@ -170,199 +157,138 @@ csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false csharp_space_between_square_brackets = false
space_within_single_line_array_initializer_braces = true
#Net Analyzer
dotnet_analyzer_diagnostic.category-Performance.severity = none #error - Uncomment when all violations are fixed.
# CS0649: Field 'field' is never assigned to, and will always have its default value 'value'
dotnet_diagnostic.CS0649.severity = error
# CS1591: Missing XML comment for publicly visible type or member
dotnet_diagnostic.CS1591.severity = suggestion
# CS0162: Remove unreachable code
dotnet_diagnostic.CS0162.severity = error
# CA1018: Mark attributes with AttributeUsageAttribute
dotnet_diagnostic.CA1018.severity = error
# CA1304: Specify CultureInfo
dotnet_diagnostic.CA1304.severity = warning
# CA1802: Use literals where appropriate
dotnet_diagnostic.CA1802.severity = warning
# CA1813: Avoid unsealed attributes
dotnet_diagnostic.CA1813.severity = error
# CA1815: Override equals and operator equals on value types
dotnet_diagnostic.CA1815.severity = warning
# CA1820: Test for empty strings using string length
dotnet_diagnostic.CA1820.severity = warning
# CA1821: Remove empty finalizers
dotnet_diagnostic.CA1821.severity = warning
# CA1822: Mark members as static
dotnet_diagnostic.CA1822.severity = suggestion
# CA1823: Avoid unused private fields
dotnet_diagnostic.CA1823.severity = warning
dotnet_code_quality.CA1822.api_surface = private, internal
# CA1825: Avoid zero-length array allocations
dotnet_diagnostic.CA1825.severity = warning
# CA1826: Use property instead of Linq Enumerable method
dotnet_diagnostic.CA1826.severity = suggestion
# CA1827: Do not use Count/LongCount when Any can be used
dotnet_diagnostic.CA1827.severity = warning
# CA1828: Do not use CountAsync/LongCountAsync when AnyAsync can be used
dotnet_diagnostic.CA1828.severity = warning
# CA1829: Use Length/Count property instead of Enumerable.Count method
dotnet_diagnostic.CA1829.severity = warning
#CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
dotnet_diagnostic.CA1847.severity = warning
#CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method
dotnet_diagnostic.CA1854.severity = warning
#CA2211:Non-constant fields should not be visible
dotnet_diagnostic.CA2211.severity = error
# Wrapping preferences # Wrapping preferences
csharp_preserve_single_line_blocks = true csharp_wrap_before_ternary_opsigns = false
csharp_preserve_single_line_statements = true
#### Naming styles #### # Avalonia DevAnalyzer preferences
[*.{cs,vb}] dotnet_diagnostic.AVADEV2001.severity = error
# Naming rules # Avalonia PublicAnalyzer preferences
dotnet_diagnostic.AVP1000.severity = error
dotnet_diagnostic.AVP1001.severity = error
dotnet_diagnostic.AVP1002.severity = error
dotnet_diagnostic.AVP1010.severity = error
dotnet_diagnostic.AVP1011.severity = error
dotnet_diagnostic.AVP1012.severity = warning
dotnet_diagnostic.AVP1013.severity = error
dotnet_diagnostic.AVP1020.severity = error
dotnet_diagnostic.AVP1021.severity = error
dotnet_diagnostic.AVP1022.severity = error
dotnet_diagnostic.AVP1030.severity = error
dotnet_diagnostic.AVP1031.severity = error
dotnet_diagnostic.AVP1032.severity = error
dotnet_diagnostic.AVP1040.severity = error
dotnet_diagnostic.AVA2001.severity = error
csharp_using_directive_placement = outside_namespace:silent
csharp_prefer_simple_using_statement = true:suggestion
csharp_prefer_braces = true:silent
csharp_style_namespace_declarations = block_scoped:silent
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
csharp_style_prefer_primary_constructors = true:suggestion
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent
csharp_style_prefer_null_check_over_type_check = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_prefer_local_over_anonymous_function = true:suggestion
csharp_style_prefer_index_operator = true:suggestion
csharp_style_prefer_range_operator = true:suggestion
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
csharp_style_prefer_tuple_swap = true:suggestion
csharp_style_prefer_utf8_string_literals = true:suggestion
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
csharp_style_prefer_readonly_struct = true:suggestion
csharp_prefer_static_local_function = true:suggestion
csharp_style_prefer_readonly_struct_member = true:suggestion
dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.severity = suggestion # Xaml files
dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.symbols = types_and_namespaces [*.{xaml,axaml}]
dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.style = pascalcase indent_size = 2
# DuplicateSetterError
avalonia_xaml_diagnostic.AVLN2203.severity = error
# StyleInMergedDictionaries
avalonia_xaml_diagnostic.AVLN2204.severity = error
# RequiredTemplatePartMissing
avalonia_xaml_diagnostic.AVLN2205.severity = error
# OptionalTemplatePartMissing
avalonia_xaml_diagnostic.AVLN2206.severity = info
# TemplatePartWrongType
avalonia_xaml_diagnostic.AVLN2207.severity = error
# Obsolete
avalonia_xaml_diagnostic.AVLN5001.severity = error
dotnet_naming_rule.interfaces_should_be_ipascalcase.severity = suggestion # Xml project files
dotnet_naming_rule.interfaces_should_be_ipascalcase.symbols = interfaces [*.{csproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]
dotnet_naming_rule.interfaces_should_be_ipascalcase.style = ipascalcase indent_size = 2
dotnet_naming_rule.type_parameters_should_be_tpascalcase.severity = suggestion # Xml build files
dotnet_naming_rule.type_parameters_should_be_tpascalcase.symbols = type_parameters [*.builds]
dotnet_naming_rule.type_parameters_should_be_tpascalcase.style = tpascalcase indent_size = 2
dotnet_naming_rule.methods_should_be_pascalcase.severity = suggestion # Xml files
dotnet_naming_rule.methods_should_be_pascalcase.symbols = methods [*.{xml,stylecop,resx,ruleset}]
dotnet_naming_rule.methods_should_be_pascalcase.style = pascalcase indent_size = 2
dotnet_naming_rule.properties_should_be_pascalcase.severity = suggestion # Xml config files
dotnet_naming_rule.properties_should_be_pascalcase.symbols = properties [*.{props,targets,config,nuspec}]
dotnet_naming_rule.properties_should_be_pascalcase.style = pascalcase indent_size = 2
dotnet_naming_rule.events_should_be_pascalcase.severity = suggestion [*.json]
dotnet_naming_rule.events_should_be_pascalcase.symbols = events indent_size = 2
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
# Shell scripts
[*.sh]
end_of_line = lf
[*.{cmd,bat}]
end_of_line = crlf

136
README.md
View file

@ -1,68 +1,68 @@
# SourceGit # SourceGit
Opensource Git GUI client. Opensource Git GUI client.
## Highlights ## Highlights
* Supports Windows/macOS/Linux * Supports Windows/macOS/Linux
* Opensource/Free * Opensource/Free
* Fast * Fast
* English/简体中文 * English/简体中文
* Built-in light/dark themes * Built-in light/dark themes
* Visual commit graph * Visual commit graph
* Supports SSH access with each remote * Supports SSH access with each remote
* GIT commands with GUI * GIT commands with GUI
* Clone/Fetch/Pull/Push... * Clone/Fetch/Pull/Push...
* Branches * Branches
* Remotes * Remotes
* Tags * Tags
* Stashes * Stashes
* Submodules * Submodules
* Archive * Archive
* Diff * Diff
* Save as patch/apply * Save as patch/apply
* File histories * File histories
* Blame * Blame
* Revision Diffs * Revision Diffs
* GitFlow support * GitFlow support
> **Linux** only tested on **Ubuntu 22.04** on **X11**. > **Linux** only tested on **Ubuntu 22.04** on **X11**.
## How to use ## How to use
**To use this tool, you need to install Git first.** **To use this tool, you need to install Git first.**
You can download the latest stable from [Releases](https://github.com/sourcegit-scm/sourcegit/releases/latest) or download workflow artifacts from [Github Actions](https://github.com/sourcegit-scm/sourcegit/actions) to try this app based on each commits. You can download the latest stable from [Releases](https://github.com/sourcegit-scm/sourcegit/releases/latest) or download workflow artifacts from [Github Actions](https://github.com/sourcegit-scm/sourcegit/actions) to try this app based on each commits.
For **macOS** users: For **macOS** users:
* Download `SourceGit.osx-x64.zip` or `SourceGit.osx-arm64.zip` from Releases. `x64` for Intel and `arm64` for Apple Silicon. * Download `SourceGit.osx-x64.zip` or `SourceGit.osx-arm64.zip` from Releases. `x64` for Intel and `arm64` for Apple Silicon.
* Move `SourceGit.app` to `Applications` folder. * Move `SourceGit.app` to `Applications` folder.
* Make sure your mac trusts all software from anywhere. For more information, search `spctl --master-disable`. * Make sure your mac trusts all software from anywhere. For more information, search `spctl --master-disable`.
* Make sure [git-credential-manager](https://github.com/git-ecosystem/git-credential-manager/releases) is installed on your mac. * Make sure [git-credential-manager](https://github.com/git-ecosystem/git-credential-manager/releases) is installed on your mac.
* You may need to run `sudo xattr -cr /Applications/SourceGit.app` to make sure the software works. * You may need to run `sudo xattr -cr /Applications/SourceGit.app` to make sure the software works.
For **Linux** users: For **Linux** users:
* `xdg-open` must be installed to support open native file manager. * `xdg-open` must be installed to support open native file manager.
* Make sure [git-credential-manager](https://github.com/git-ecosystem/git-credential-manager/releases) is installed on your linux, and it requires `ttf-mscorefonts-installer` installed. * Make sure [git-credential-manager](https://github.com/git-ecosystem/git-credential-manager/releases) is installed on your linux, and it requires `ttf-mscorefonts-installer` installed.
* Maybe you need to set environment variable `AVALONIA_SCREEN_SCALE_FACTORS`. See https://github.com/AvaloniaUI/Avalonia/wiki/Configuring-X11-per-monitor-DPI. * Maybe you need to set environment variable `AVALONIA_SCREEN_SCALE_FACTORS`. See https://github.com/AvaloniaUI/Avalonia/wiki/Configuring-X11-per-monitor-DPI.
* Modify `SourceGit.desktop.template` (replace SOURCEGIT_LOCAL_FOLDER with real path) and move it into `~/.local/share/applications`. * Modify `SourceGit.desktop.template` (replace SOURCEGIT_LOCAL_FOLDER with real path) and move it into `~/.local/share/applications`.
## Screen Shots ## Screen Shots
* Dark Theme * Dark Theme
![Theme Dark](./screenshots/theme_dark.png) ![Theme Dark](./screenshots/theme_dark.png)
* Light Theme * Light Theme
![Theme Light](./screenshots/theme_light.png) ![Theme Light](./screenshots/theme_light.png)
## Contributing ## Contributing
Thanks to all the people who contribute. Thanks to all the people who contribute.
<a href="https://github.com/sourcegit-scm/sourcegit/graphs/contributors"> <a href="https://github.com/sourcegit-scm/sourcegit/graphs/contributors">
<img src="https://contrib.rocks/image?repo=sourcegit-scm/sourcegit" /> <img src="https://contrib.rocks/image?repo=sourcegit-scm/sourcegit" />
</a> </a>

View file

@ -6,4 +6,4 @@ namespace SourceGit
[JsonSerializable(typeof(Models.Version))] [JsonSerializable(typeof(Models.Version))]
[JsonSerializable(typeof(ViewModels.Preference))] [JsonSerializable(typeof(ViewModels.Preference))]
internal partial class JsonCodeGen : JsonSerializerContext { } internal partial class JsonCodeGen : JsonSerializerContext { }
} }

View file

@ -143,7 +143,8 @@ namespace SourceGit
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; var fmt = Current.FindResource($"Text.{key}") as string;
if (string.IsNullOrWhiteSpace(fmt)) return $"Text.{key}"; if (string.IsNullOrWhiteSpace(fmt))
return $"Text.{key}";
return string.Format(fmt, args); return string.Format(fmt, args);
} }
@ -178,12 +179,14 @@ namespace SourceGit
// Parse json into Models.Version. // Parse json into Models.Version.
var ver = JsonSerializer.Deserialize(data, JsonCodeGen.Default.Version); var ver = JsonSerializer.Deserialize(data, JsonCodeGen.Default.Version);
if (ver == null) return; if (ver == null)
return;
// Check if already up-to-date. // Check if already up-to-date.
if (!ver.IsNewVersion) if (!ver.IsNewVersion)
{ {
if (manually) ShowSelfUpdateResult(new Models.AlreadyUpToDate()); if (manually)
ShowSelfUpdateResult(new Models.AlreadyUpToDate());
return; return;
} }
@ -191,14 +194,16 @@ namespace SourceGit
if (!manually) if (!manually)
{ {
var pref = ViewModels.Preference.Instance; var pref = ViewModels.Preference.Instance;
if (ver.TagName == pref.IgnoreUpdateTag) return; if (ver.TagName == pref.IgnoreUpdateTag)
return;
} }
ShowSelfUpdateResult(ver); ShowSelfUpdateResult(ver);
} }
catch (Exception e) catch (Exception e)
{ {
if (manually) ShowSelfUpdateResult(e); if (manually)
ShowSelfUpdateResult(e);
} }
}); });
} }
@ -232,7 +237,8 @@ namespace SourceGit
_notificationReceiver = launcher; _notificationReceiver = launcher;
desktop.MainWindow = launcher; desktop.MainWindow = launcher;
if (ViewModels.Preference.Instance.Check4UpdatesOnStartup) Check4Update(); if (ViewModels.Preference.Instance.Check4UpdatesOnStartup)
Check4Update();
} }
base.OnFrameworkInitializationCompleted(); base.OnFrameworkInitializationCompleted();
@ -260,4 +266,4 @@ namespace SourceGit
private ResourceDictionary _activeLocale = null; private ResourceDictionary _activeLocale = null;
private Models.INotificationReceiver _notificationReceiver = null; private Models.INotificationReceiver _notificationReceiver = null;
} }
} }

View file

@ -28,4 +28,4 @@ namespace SourceGit.Commands
} }
} }
} }
} }

View file

@ -7,10 +7,13 @@
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = "apply "; Args = "apply ";
if (ignoreWhitespace) Args += "--ignore-whitespace "; if (ignoreWhitespace)
else Args += $"--whitespace={whitespaceMode} "; Args += "--ignore-whitespace ";
if (!string.IsNullOrEmpty(extra)) Args += $"{extra} "; else
Args += $"--whitespace={whitespaceMode} ";
if (!string.IsNullOrEmpty(extra))
Args += $"{extra} ";
Args += $"\"{file}\""; Args += $"\"{file}\"";
} }
} }
} }

View file

@ -20,4 +20,4 @@ namespace SourceGit.Commands
private readonly Action<string> _outputHandler; private readonly Action<string> _outputHandler;
} }
} }

View file

@ -7,7 +7,6 @@ namespace SourceGit.Commands
{ {
partial class ViewCommand : Command partial class ViewCommand : Command
{ {
[GeneratedRegex(@"^(\w)\s+(.+)$")] [GeneratedRegex(@"^(\w)\s+(.+)$")]
private static partial Regex REG(); private static partial Regex REG();
@ -27,7 +26,8 @@ namespace SourceGit.Commands
protected override void OnReadline(string line) protected override void OnReadline(string line)
{ {
var match = REG().Match(line); var match = REG().Match(line);
if (!match.Success) return; if (!match.Success)
return;
if (match.Groups[1].Value == "h") if (match.Groups[1].Value == "h")
{ {
@ -72,4 +72,4 @@ namespace SourceGit.Commands
private readonly string _repo; private readonly string _repo;
} }
} }

View file

@ -46,8 +46,10 @@ namespace SourceGit.Commands
protected override void OnReadline(string line) protected override void OnReadline(string line)
{ {
if (_result.IsBinary) return; if (_result.IsBinary)
if (string.IsNullOrEmpty(line)) return; return;
if (string.IsNullOrEmpty(line))
return;
if (line.IndexOf('\0', StringComparison.Ordinal) >= 0) if (line.IndexOf('\0', StringComparison.Ordinal) >= 0)
{ {
@ -57,7 +59,8 @@ namespace SourceGit.Commands
} }
var match = REG_FORMAT().Match(line); var match = REG_FORMAT().Match(line);
if (!match.Success) return; if (!match.Success)
return;
_content.AppendLine(match.Groups[4].Value); _content.AppendLine(match.Groups[4].Value);
@ -90,4 +93,4 @@ namespace SourceGit.Commands
private bool _needUnifyCommitSHA = false; private bool _needUnifyCommitSHA = false;
private int _minSHALen = 64; private int _minSHALen = 64;
} }
} }

View file

@ -45,4 +45,4 @@
return cmd.Exec(); return cmd.Exec();
} }
} }
} }

View file

@ -69,4 +69,4 @@ namespace SourceGit.Commands
private Action<string> _outputHandler; private Action<string> _outputHandler;
} }
} }

View file

@ -10,4 +10,4 @@
Args = $"cherry-pick {mode} {commit}"; Args = $"cherry-pick {mode} {commit}";
} }
} }
} }

View file

@ -28,4 +28,4 @@ namespace SourceGit.Commands
Args = builder.ToString(); Args = builder.ToString();
} }
} }
} }

View file

@ -23,9 +23,11 @@ namespace SourceGit.Commands
Args += "clone --progress --verbose --recurse-submodules "; Args += "clone --progress --verbose --recurse-submodules ";
if (!string.IsNullOrEmpty(extraArgs)) Args += $"{extraArgs} "; if (!string.IsNullOrEmpty(extraArgs))
Args += $"{extraArgs} ";
Args += $"{url} "; Args += $"{url} ";
if (!string.IsNullOrEmpty(localName)) Args += localName; if (!string.IsNullOrEmpty(localName))
Args += localName;
_notifyProgress = ouputHandler; _notifyProgress = ouputHandler;
} }
@ -35,4 +37,4 @@ namespace SourceGit.Commands
_notifyProgress?.Invoke(line); _notifyProgress?.Invoke(line);
} }
} }
} }

View file

@ -47,7 +47,8 @@ namespace SourceGit.Commands
start.Environment.Add("LANG", "en_US.UTF-8"); start.Environment.Add("LANG", "en_US.UTF-8");
} }
if (!string.IsNullOrEmpty(WorkingDirectory)) start.WorkingDirectory = WorkingDirectory; if (!string.IsNullOrEmpty(WorkingDirectory))
start.WorkingDirectory = WorkingDirectory;
var errs = new List<string>(); var errs = new List<string>();
var proc = new Process() { StartInfo = start }; var proc = new Process() { StartInfo = start };
@ -60,11 +61,13 @@ namespace SourceGit.Commands
isCancelled = true; isCancelled = true;
proc.CancelErrorRead(); proc.CancelErrorRead();
proc.CancelOutputRead(); proc.CancelOutputRead();
if (!proc.HasExited) proc.Kill(true); if (!proc.HasExited)
proc.Kill(true);
return; return;
} }
if (e.Data != null) OnReadline(e.Data); if (e.Data != null)
OnReadline(e.Data);
}; };
proc.ErrorDataReceived += (_, e) => proc.ErrorDataReceived += (_, e) =>
@ -74,19 +77,27 @@ namespace SourceGit.Commands
isCancelled = true; isCancelled = true;
proc.CancelErrorRead(); proc.CancelErrorRead();
proc.CancelOutputRead(); proc.CancelOutputRead();
if (!proc.HasExited) proc.Kill(true); if (!proc.HasExited)
proc.Kill(true);
return; return;
} }
if (string.IsNullOrEmpty(e.Data)) return; if (string.IsNullOrEmpty(e.Data))
if (TraitErrorAsOutput) OnReadline(e.Data); return;
if (TraitErrorAsOutput)
OnReadline(e.Data);
// Ignore progress messages // Ignore progress messages
if (e.Data.StartsWith("remote: Enumerating objects:", StringComparison.Ordinal)) return; if (e.Data.StartsWith("remote: Enumerating objects:", StringComparison.Ordinal))
if (e.Data.StartsWith("remote: Counting objects:", StringComparison.Ordinal)) return; return;
if (e.Data.StartsWith("remote: Compressing objects:", StringComparison.Ordinal)) return; if (e.Data.StartsWith("remote: Counting objects:", StringComparison.Ordinal))
if (e.Data.StartsWith("Filtering content:", StringComparison.Ordinal)) return; return;
if (_progressRegex().IsMatch(e.Data)) return; if (e.Data.StartsWith("remote: Compressing objects:", StringComparison.Ordinal))
return;
if (e.Data.StartsWith("Filtering content:", StringComparison.Ordinal))
return;
if (_progressRegex().IsMatch(e.Data))
return;
errs.Add(e.Data); errs.Add(e.Data);
}; };
@ -142,7 +153,8 @@ namespace SourceGit.Commands
start.StandardOutputEncoding = Encoding.UTF8; start.StandardOutputEncoding = Encoding.UTF8;
start.StandardErrorEncoding = Encoding.UTF8; start.StandardErrorEncoding = Encoding.UTF8;
if (!string.IsNullOrEmpty(WorkingDirectory)) start.WorkingDirectory = WorkingDirectory; if (!string.IsNullOrEmpty(WorkingDirectory))
start.WorkingDirectory = WorkingDirectory;
var proc = new Process() { StartInfo = start }; var proc = new Process() { StartInfo = start };
try try
@ -177,4 +189,4 @@ namespace SourceGit.Commands
[GeneratedRegex(@"\d+%")] [GeneratedRegex(@"\d+%")]
private static partial Regex _progressRegex(); private static partial Regex _progressRegex();
} }
} }

View file

@ -12,8 +12,10 @@ namespace SourceGit.Commands
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"commit --file=\"{file}\""; Args = $"commit --file=\"{file}\"";
if (amend) Args += " --amend --no-edit"; if (amend)
if (allowEmpty) Args += " --allow-empty"; Args += " --amend --no-edit";
if (allowEmpty)
Args += " --allow-empty";
} }
} }
} }

View file

@ -25,21 +25,37 @@ namespace SourceGit.Commands
protected override void OnReadline(string line) protected override void OnReadline(string line)
{ {
var match = REG_FORMAT().Match(line); var match = REG_FORMAT().Match(line);
if (!match.Success) return; if (!match.Success)
return;
var change = new Models.Change() { Path = match.Groups[2].Value }; var change = new Models.Change() { Path = match.Groups[2].Value };
var status = match.Groups[1].Value; var status = match.Groups[1].Value;
switch (status[0]) switch (status[0])
{ {
case 'M': change.Set(Models.ChangeState.Modified); _changes.Add(change); break; case 'M':
case 'A': change.Set(Models.ChangeState.Added); _changes.Add(change); break; change.Set(Models.ChangeState.Modified);
case 'D': change.Set(Models.ChangeState.Deleted); _changes.Add(change); break; _changes.Add(change);
case 'R': change.Set(Models.ChangeState.Renamed); _changes.Add(change); break; break;
case 'C': change.Set(Models.ChangeState.Copied); _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 readonly List<Models.Change> _changes = new List<Models.Change>(); private readonly List<Models.Change> _changes = new List<Models.Change>();
} }
} }

View file

@ -77,4 +77,4 @@ namespace SourceGit.Commands
return Exec(); return Exec();
} }
} }
} }

View file

@ -8,9 +8,9 @@ namespace SourceGit.Commands
{ {
[GeneratedRegex(@"^@@ \-(\d+),?\d* \+(\d+),?\d* @@")] [GeneratedRegex(@"^@@ \-(\d+),?\d* \+(\d+),?\d* @@")]
private static partial Regex REG_INDICATOR(); private static partial Regex REG_INDICATOR();
private static readonly string PREFIX_LFS_NEW = "+version https://git-lfs.github.com/spec/"; private const 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 const 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/"; private const 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)
{ {
@ -46,7 +46,8 @@ namespace SourceGit.Commands
protected override void OnReadline(string line) protected override void OnReadline(string line)
{ {
if (_result.IsBinary) return; if (_result.IsBinary)
return;
if (_result.IsLFS) if (_result.IsLFS)
{ {
@ -85,7 +86,8 @@ namespace SourceGit.Commands
var match = REG_INDICATOR().Match(line); var match = REG_INDICATOR().Match(line);
if (!match.Success) if (!match.Success)
{ {
if (line.StartsWith("Binary", StringComparison.Ordinal)) _result.IsBinary = true; if (line.StartsWith("Binary", StringComparison.Ordinal))
_result.IsBinary = true;
return; return;
} }
@ -167,10 +169,12 @@ namespace SourceGit.Commands
var left = _deleted[i]; var left = _deleted[i];
var right = _added[i]; var right = _added[i];
if (left.Content.Length > 1024 || right.Content.Length > 1024) continue; if (left.Content.Length > 1024 || right.Content.Length > 1024)
continue;
var chunks = Models.TextInlineChange.Compare(left.Content, right.Content); var chunks = Models.TextInlineChange.Compare(left.Content, right.Content);
if (chunks.Count > 4) continue; if (chunks.Count > 4)
continue;
foreach (var chunk in chunks) foreach (var chunk in chunks)
{ {
@ -204,4 +208,4 @@ namespace SourceGit.Commands
private int _oldLine = 0; private int _oldLine = 0;
private int _newLine = 0; private int _newLine = 0;
} }
} }

View file

@ -47,9 +47,10 @@ namespace SourceGit.Commands
{ {
var count = Math.Min(10, changes.Count - i); var count = Math.Min(10, changes.Count - i);
var files = new List<string>(); var files = new List<string>();
for (int j = 0; j < count; j++) files.Add(changes[i + j].Path); for (int j = 0; j < count; j++)
files.Add(changes[i + j].Path);
new Restore(repo, files, "--staged --worktree").Exec(); new Restore(repo, files, "--staged --worktree").Exec();
} }
} }
} }
} }

View file

@ -25,7 +25,8 @@ namespace SourceGit.Commands
} }
Args += "fetch --progress --verbose "; Args += "fetch --progress --verbose ";
if (prune) Args += "--prune "; if (prune)
Args += "--prune ";
Args += remote; Args += remote;
AutoFetch.MarkFetched(repo); AutoFetch.MarkFetched(repo);
@ -61,6 +62,8 @@ namespace SourceGit.Commands
public class AutoFetch public class AutoFetch
{ {
private const double INTERVAL = 10 * 60;
public static bool IsEnabled public static bool IsEnabled
{ {
get; get;
@ -101,7 +104,7 @@ namespace SourceGit.Commands
foreach (var job in uptodate) foreach (var job in uptodate)
{ {
job.Cmd.Exec(); job.Cmd.Exec();
job.NextRunTimepoint = DateTime.Now.AddSeconds(_fetchInterval); job.NextRunTimepoint = DateTime.Now.AddSeconds(INTERVAL);
} }
Thread.Sleep(2000); Thread.Sleep(2000);
@ -114,7 +117,7 @@ namespace SourceGit.Commands
var job = new Job var job = new Job
{ {
Cmd = new Fetch(repo, "--all", true, null) { RaiseError = false }, Cmd = new Fetch(repo, "--all", true, null) { RaiseError = false },
NextRunTimepoint = DateTime.Now.AddSeconds(_fetchInterval), NextRunTimepoint = DateTime.Now.AddSeconds(INTERVAL),
}; };
lock (_lock) lock (_lock)
@ -142,15 +145,14 @@ namespace SourceGit.Commands
{ {
lock (_lock) lock (_lock)
{ {
if (_jobs.ContainsKey(repo)) if (_jobs.TryGetValue(repo, out var value))
{ {
_jobs[repo].NextRunTimepoint = DateTime.Now.AddSeconds(_fetchInterval); value.NextRunTimepoint = DateTime.Now.AddSeconds(INTERVAL);
} }
} }
} }
private static readonly Dictionary<string, Job> _jobs = new Dictionary<string, Job>(); private static readonly Dictionary<string, Job> _jobs = new Dictionary<string, Job>();
private static readonly object _lock = new object(); private static readonly object _lock = new object();
private static readonly double _fetchInterval = 10 * 60;
} }
} }

View file

@ -9,4 +9,4 @@
Args = $"format-patch {commit} -1 -o \"{saveTo}\""; Args = $"format-patch {commit} -1 -o \"{saveTo}\"";
} }
} }
} }

View file

@ -20,4 +20,4 @@ namespace SourceGit.Commands
private readonly Action<string> _outputHandler; private readonly Action<string> _outputHandler;
} }
} }

View file

@ -37,4 +37,4 @@ namespace SourceGit.Commands
} }
} }
} }
} }

View file

@ -17,10 +17,12 @@ namespace SourceGit.Commands
var current = branches.Find(x => x.IsCurrent); var current = branches.Find(x => x.IsCurrent);
var masterBranch = branches.Find(x => x.Name == master); var masterBranch = branches.Find(x => x.Name == master);
if (masterBranch == null && current != null) Branch.Create(WorkingDirectory, master, current.Head); if (masterBranch == null && current != null)
Branch.Create(WorkingDirectory, master, current.Head);
var devBranch = branches.Find(x => x.Name == develop); var devBranch = branches.Find(x => x.Name == develop);
if (devBranch == null && current != null) Branch.Create(WorkingDirectory, develop, current.Head); if (devBranch == null && current != null)
Branch.Create(WorkingDirectory, develop, current.Head);
var cmd = new Config(WorkingDirectory); var cmd = new Config(WorkingDirectory);
cmd.Set("gitflow.branch.master", master); cmd.Set("gitflow.branch.master", master);
@ -85,4 +87,4 @@ namespace SourceGit.Commands
return Exec(); return Exec();
} }
} }
} }

View file

@ -9,4 +9,4 @@
Args = "init -q"; Args = "init -q";
} }
} }
} }

View file

@ -20,4 +20,4 @@ namespace SourceGit.Commands
return REG_TEST().IsMatch(ReadToEnd().StdOut); return REG_TEST().IsMatch(ReadToEnd().StdOut);
} }
} }
} }

View file

@ -16,4 +16,4 @@
return rs.IsSuccess && rs.StdOut.Contains("filter\0lfs"); return rs.IsSuccess && rs.StdOut.Contains("filter\0lfs");
} }
} }
} }

View file

@ -32,7 +32,8 @@ namespace SourceGit.Commands
public bool IsEnabled() public bool IsEnabled()
{ {
var path = Path.Combine(_repo, ".git", "hooks", "pre-push"); var path = Path.Combine(_repo, ".git", "hooks", "pre-push");
if (!File.Exists(path)) return false; if (!File.Exists(path))
return false;
var content = File.ReadAllText(path); var content = File.ReadAllText(path);
return content.Contains("git lfs pre-push"); return content.Contains("git lfs pre-push");
@ -45,4 +46,4 @@ namespace SourceGit.Commands
private readonly string _repo; private readonly string _repo;
} }
} }

View file

@ -20,4 +20,4 @@ namespace SourceGit.Commands
private readonly Action<string> _outputHandler = null; private readonly Action<string> _outputHandler = null;
} }
} }

View file

@ -60,4 +60,4 @@ namespace SourceGit.Commands
return cmd.Exec(); return cmd.Exec();
} }
} }
} }

View file

@ -22,7 +22,8 @@ namespace SourceGit.Commands
} }
Args += "pull --verbose --progress --tags "; Args += "pull --verbose --progress --tags ";
if (useRebase) Args += "--rebase "; if (useRebase)
Args += "--rebase ";
Args += $"{remote} {branch}"; Args += $"{remote} {branch}";
} }
@ -33,4 +34,4 @@ namespace SourceGit.Commands
private readonly Action<string> _outputHandler; private readonly Action<string> _outputHandler;
} }
} }

View file

@ -23,9 +23,12 @@ namespace SourceGit.Commands
Args += "push --progress --verbose "; Args += "push --progress --verbose ";
if (withTags) Args += "--tags "; if (withTags)
if (track) Args += "-u "; Args += "--tags ";
if (force) Args += "--force-with-lease "; if (track)
Args += "-u ";
if (force)
Args += "--force-with-lease ";
Args += $"{remote} {local}:{remoteBranch}"; Args += $"{remote} {local}:{remoteBranch}";
} }
@ -71,7 +74,8 @@ namespace SourceGit.Commands
} }
Args += "push "; Args += "push ";
if (isDelete) Args += "--delete "; if (isDelete)
Args += "--delete ";
Args += $"{remote} refs/tags/{tag}"; Args += $"{remote} refs/tags/{tag}";
} }
@ -82,4 +86,4 @@ namespace SourceGit.Commands
private readonly Action<string> _outputHandler = null; private readonly Action<string> _outputHandler = null;
} }
} }

View file

@ -6,8 +6,8 @@ namespace SourceGit.Commands
{ {
public partial class QueryBranches : Command public partial class QueryBranches : Command
{ {
private static readonly string PREFIX_LOCAL = "refs/heads/"; private const string PREFIX_LOCAL = "refs/heads/";
private static readonly string PREFIX_REMOTE = "refs/remotes/"; private const string PREFIX_REMOTE = "refs/remotes/";
[GeneratedRegex(@"^(\d+)\s(\d+)$")] [GeneratedRegex(@"^(\d+)\s(\d+)$")]
private static partial Regex REG_AHEAD_BEHIND(); private static partial Regex REG_AHEAD_BEHIND();
@ -44,11 +44,13 @@ namespace SourceGit.Commands
protected override void OnReadline(string line) protected override void OnReadline(string line)
{ {
var parts = line.Split('$'); var parts = line.Split('$');
if (parts.Length != 5) return; if (parts.Length != 5)
return;
var branch = new Models.Branch(); var branch = new Models.Branch();
var refName = parts[0]; var refName = parts[0];
if (refName.EndsWith("/HEAD", StringComparison.Ordinal)) return; if (refName.EndsWith("/HEAD", StringComparison.Ordinal))
return;
if (refName.StartsWith(PREFIX_LOCAL, StringComparison.Ordinal)) if (refName.StartsWith(PREFIX_LOCAL, StringComparison.Ordinal))
{ {
@ -59,7 +61,8 @@ namespace SourceGit.Commands
{ {
var name = refName.Substring(PREFIX_REMOTE.Length); var name = refName.Substring(PREFIX_REMOTE.Length);
var shortNameIdx = name.IndexOf('/', StringComparison.Ordinal); var shortNameIdx = name.IndexOf('/', StringComparison.Ordinal);
if (shortNameIdx < 0) return; if (shortNameIdx < 0)
return;
branch.Remote = name.Substring(0, shortNameIdx); branch.Remote = name.Substring(0, shortNameIdx);
branch.Name = name.Substring(branch.Remote.Length + 1); branch.Name = name.Substring(branch.Remote.Length + 1);
@ -87,19 +90,23 @@ namespace SourceGit.Commands
cmd.Args = $"rev-list --left-right --count {local}...{upstream}"; cmd.Args = $"rev-list --left-right --count {local}...{upstream}";
var rs = cmd.ReadToEnd(); var rs = cmd.ReadToEnd();
if (!rs.IsSuccess) return string.Empty; if (!rs.IsSuccess)
return string.Empty;
var match = REG_AHEAD_BEHIND().Match(rs.StdOut); var match = REG_AHEAD_BEHIND().Match(rs.StdOut);
if (!match.Success) return string.Empty; if (!match.Success)
return string.Empty;
var ahead = int.Parse(match.Groups[1].Value); var ahead = int.Parse(match.Groups[1].Value);
var behind = int.Parse(match.Groups[2].Value); var behind = int.Parse(match.Groups[2].Value);
var track = ""; var track = "";
if (ahead > 0) track += $"{ahead}↑"; if (ahead > 0)
if (behind > 0) track += $" {behind}↓"; track += $"{ahead}↑";
if (behind > 0)
track += $" {behind}↓";
return track.Trim(); return track.Trim();
} }
private readonly List<Models.Branch> _branches = new List<Models.Branch>(); private readonly List<Models.Branch> _branches = new List<Models.Branch>();
} }
} }

View file

@ -25,21 +25,37 @@ namespace SourceGit.Commands
protected override void OnReadline(string line) protected override void OnReadline(string line)
{ {
var match = REG_FORMAT().Match(line); var match = REG_FORMAT().Match(line);
if (!match.Success) return; if (!match.Success)
return;
var change = new Models.Change() { Path = match.Groups[2].Value }; var change = new Models.Change() { Path = match.Groups[2].Value };
var status = match.Groups[1].Value; var status = match.Groups[1].Value;
switch (status[0]) switch (status[0])
{ {
case 'M': change.Set(Models.ChangeState.Modified); _changes.Add(change); break; case 'M':
case 'A': change.Set(Models.ChangeState.Added); _changes.Add(change); break; change.Set(Models.ChangeState.Modified);
case 'D': change.Set(Models.ChangeState.Deleted); _changes.Add(change); break; _changes.Add(change);
case 'R': change.Set(Models.ChangeState.Renamed); _changes.Add(change); break; break;
case 'C': change.Set(Models.ChangeState.Copied); _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 readonly List<Models.Change> _changes = new List<Models.Change>(); private readonly List<Models.Change> _changes = new List<Models.Change>();
} }
} }

View file

@ -5,8 +5,8 @@ namespace SourceGit.Commands
{ {
public class QueryCommits : Command public class QueryCommits : Command
{ {
private static readonly string GPGSIG_START = "gpgsig -----BEGIN PGP SIGNATURE-----"; private const string GPGSIG_START = "gpgsig -----BEGIN PGP SIGNATURE-----";
private static readonly string GPGSIG_END = " -----END PGP SIGNATURE-----"; private const string GPGSIG_END = " -----END PGP SIGNATURE-----";
private readonly List<Models.Commit> commits = new List<Models.Commit>(); private readonly List<Models.Commit> commits = new List<Models.Commit>();
private Models.Commit current = null; private Models.Commit current = null;
@ -43,7 +43,8 @@ namespace SourceGit.Commands
{ {
if (isSkipingGpgsig) if (isSkipingGpgsig)
{ {
if (line.StartsWith(GPGSIG_END, StringComparison.Ordinal)) isSkipingGpgsig = false; if (line.StartsWith(GPGSIG_END, StringComparison.Ordinal))
isSkipingGpgsig = false;
return; return;
} }
else if (line.StartsWith(GPGSIG_START, StringComparison.Ordinal)) else if (line.StartsWith(GPGSIG_START, StringComparison.Ordinal))
@ -72,13 +73,15 @@ namespace SourceGit.Commands
{ {
current.SHA = line.Substring(0, decoratorStart).Trim(); current.SHA = line.Substring(0, decoratorStart).Trim();
current.IsMerged = ParseDecorators(current.Decorators, line.Substring(decoratorStart + 1)); current.IsMerged = ParseDecorators(current.Decorators, line.Substring(decoratorStart + 1));
if (!isHeadFounded) isHeadFounded = current.IsMerged; if (!isHeadFounded)
isHeadFounded = current.IsMerged;
} }
return; return;
} }
if (current == null) return; if (current == null)
return;
if (line.StartsWith("tree ", StringComparison.Ordinal)) if (line.StartsWith("tree ", StringComparison.Ordinal))
{ {
@ -182,10 +185,12 @@ namespace SourceGit.Commands
var rs = ReadToEnd(); var rs = ReadToEnd();
var shas = rs.StdOut.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); var shas = rs.StdOut.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
if (shas.Length == 0) return; if (shas.Length == 0)
return;
var set = new HashSet<string>(); var set = new HashSet<string>();
foreach (var sha in shas) set.Add(sha); foreach (var sha in shas)
set.Add(sha);
foreach (var c in commits) foreach (var c in commits)
{ {
@ -197,4 +202,4 @@ namespace SourceGit.Commands
} }
} }
} }
} }

View file

@ -25,4 +25,4 @@ namespace SourceGit.Commands
private readonly StringBuilder _builder = new StringBuilder(); private readonly StringBuilder _builder = new StringBuilder();
} }
} }

View file

@ -17,7 +17,8 @@ namespace SourceGit.Commands
public long Result() public long Result()
{ {
if (_result != 0) return _result; if (_result != 0)
return _result;
var rs = ReadToEnd(); var rs = ReadToEnd();
if (rs.IsSuccess) if (rs.IsSuccess)
@ -34,4 +35,4 @@ namespace SourceGit.Commands
private readonly long _result = 0; private readonly long _result = 0;
} }
} }

View file

@ -14,11 +14,13 @@ namespace SourceGit.Commands
public string Result() public string Result()
{ {
var rs = ReadToEnd().StdOut; var rs = ReadToEnd().StdOut;
if (string.IsNullOrEmpty(rs)) return null; if (string.IsNullOrEmpty(rs))
return null;
rs = rs.Trim(); rs = rs.Trim();
if (Path.IsPathRooted(rs)) return rs; if (Path.IsPathRooted(rs))
return rs;
return Path.GetFullPath(Path.Combine(WorkingDirectory, rs)); return Path.GetFullPath(Path.Combine(WorkingDirectory, rs));
} }
} }
} }

View file

@ -26,43 +26,102 @@ namespace SourceGit.Commands
protected override void OnReadline(string line) protected override void OnReadline(string line)
{ {
var match = REG_FORMAT().Match(line); var match = REG_FORMAT().Match(line);
if (!match.Success) return; if (!match.Success)
if (line.EndsWith("/", StringComparison.Ordinal)) return; // Ignore changes with git-worktree return;
if (line.EndsWith("/", StringComparison.Ordinal))
return; // Ignore changes with git-worktree
var change = new Models.Change() { Path = match.Groups[2].Value }; var change = new Models.Change() { Path = match.Groups[2].Value };
var status = match.Groups[1].Value; var status = match.Groups[1].Value;
switch (status) switch (status)
{ {
case " M": change.Set(Models.ChangeState.None, Models.ChangeState.Modified); break; case " M":
case " A": change.Set(Models.ChangeState.None, Models.ChangeState.Added); break; change.Set(Models.ChangeState.None, Models.ChangeState.Modified);
case " D": change.Set(Models.ChangeState.None, Models.ChangeState.Deleted); break; break;
case " R": change.Set(Models.ChangeState.None, Models.ChangeState.Renamed); break; case " A":
case " C": change.Set(Models.ChangeState.None, Models.ChangeState.Copied); break; change.Set(Models.ChangeState.None, Models.ChangeState.Added);
case "M": change.Set(Models.ChangeState.Modified, Models.ChangeState.None); break; break;
case "MM": change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified); break; case " D":
case "MD": change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted); break; change.Set(Models.ChangeState.None, Models.ChangeState.Deleted);
case "A": change.Set(Models.ChangeState.Added, Models.ChangeState.None); break; break;
case "AM": change.Set(Models.ChangeState.Added, Models.ChangeState.Modified); break; case " R":
case "AD": change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted); break; change.Set(Models.ChangeState.None, Models.ChangeState.Renamed);
case "D": change.Set(Models.ChangeState.Deleted, Models.ChangeState.None); break; break;
case "R": change.Set(Models.ChangeState.Renamed, Models.ChangeState.None); break; case " C":
case "RM": change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified); break; change.Set(Models.ChangeState.None, Models.ChangeState.Copied);
case "RD": change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted); break; break;
case "C": change.Set(Models.ChangeState.Copied, Models.ChangeState.None); break; case "M":
case "CM": change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified); break; change.Set(Models.ChangeState.Modified, Models.ChangeState.None);
case "CD": change.Set(Models.ChangeState.Copied, Models.ChangeState.Deleted); break; break;
case "DR": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Renamed); break; case "MM":
case "DC": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Copied); break; change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified);
case "DD": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Deleted); break; break;
case "AU": change.Set(Models.ChangeState.Added, Models.ChangeState.Unmerged); break; case "MD":
case "UD": change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Deleted); break; change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted);
case "UA": change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Added); break; break;
case "DU": change.Set(Models.ChangeState.Deleted, Models.ChangeState.Unmerged); break; case "A":
case "AA": change.Set(Models.ChangeState.Added, Models.ChangeState.Added); break; change.Set(Models.ChangeState.Added, Models.ChangeState.None);
case "UU": change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Unmerged); break; break;
case "??": change.Set(Models.ChangeState.Untracked, Models.ChangeState.Untracked); break; case "AM":
default: return; 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); _changes.Add(change);
@ -70,4 +129,4 @@ namespace SourceGit.Commands
private readonly List<Models.Change> _changes = new List<Models.Change>(); private readonly List<Models.Change> _changes = new List<Models.Change>();
} }
} }

View file

@ -24,7 +24,8 @@ namespace SourceGit.Commands
protected override void OnReadline(string line) protected override void OnReadline(string line)
{ {
var match = REG_REMOTE().Match(line); var match = REG_REMOTE().Match(line);
if (!match.Success) return; if (!match.Success)
return;
var remote = new Models.Remote() var remote = new Models.Remote()
{ {
@ -32,10 +33,11 @@ namespace SourceGit.Commands
URL = match.Groups[2].Value, URL = match.Groups[2].Value,
}; };
if (_loaded.Find(x => x.Name == remote.Name) != null) return; if (_loaded.Find(x => x.Name == remote.Name) != null)
return;
_loaded.Add(remote); _loaded.Add(remote);
} }
private readonly List<Models.Remote> _loaded = new List<Models.Remote>(); private readonly List<Models.Remote> _loaded = new List<Models.Remote>();
} }
} }

View file

@ -12,8 +12,9 @@
public string Result() public string Result()
{ {
var rs = ReadToEnd().StdOut; var rs = ReadToEnd().StdOut;
if (string.IsNullOrEmpty(rs)) return null; if (string.IsNullOrEmpty(rs))
return null;
return rs.Trim(); return rs.Trim();
} }
} }
} }

View file

@ -26,7 +26,8 @@ namespace SourceGit.Commands
protected override void OnReadline(string line) protected override void OnReadline(string line)
{ {
var match = REG_FORMAT().Match(line); var match = REG_FORMAT().Match(line);
if (!match.Success) return; if (!match.Success)
return;
var obj = new Models.Object(); var obj = new Models.Object();
obj.SHA = match.Groups[2].Value; obj.SHA = match.Groups[2].Value;
@ -35,13 +36,21 @@ namespace SourceGit.Commands
switch (match.Groups[1].Value) switch (match.Groups[1].Value)
{ {
case "blob": obj.Type = Models.ObjectType.Blob; break; case "blob":
case "tree": obj.Type = Models.ObjectType.Tree; break; obj.Type = Models.ObjectType.Blob;
case "tag": obj.Type = Models.ObjectType.Tag; break; break;
case "commit": obj.Type = Models.ObjectType.Commit; 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); objects.Add(obj);
} }
} }
} }

View file

@ -26,4 +26,4 @@ namespace SourceGit.Commands
return string.Empty; return string.Empty;
} }
} }
} }

View file

@ -25,21 +25,37 @@ namespace SourceGit.Commands
protected override void OnReadline(string line) protected override void OnReadline(string line)
{ {
var match = REG_FORMAT().Match(line); var match = REG_FORMAT().Match(line);
if (!match.Success) return; if (!match.Success)
return;
var change = new Models.Change() { Path = match.Groups[2].Value }; var change = new Models.Change() { Path = match.Groups[2].Value };
var status = match.Groups[1].Value; var status = match.Groups[1].Value;
switch (status[0]) switch (status[0])
{ {
case 'M': change.Set(Models.ChangeState.Modified); _changes.Add(change); break; case 'M':
case 'A': change.Set(Models.ChangeState.Added); _changes.Add(change); break; change.Set(Models.ChangeState.Modified);
case 'D': change.Set(Models.ChangeState.Deleted); _changes.Add(change); break; _changes.Add(change);
case 'R': change.Set(Models.ChangeState.Renamed); _changes.Add(change); break; break;
case 'C': change.Set(Models.ChangeState.Copied); _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 readonly List<Models.Change> _changes = new List<Models.Change>(); private readonly List<Models.Change> _changes = new List<Models.Change>();
} }
} }

View file

@ -20,7 +20,8 @@ namespace SourceGit.Commands
public List<Models.Stash> Result() public List<Models.Stash> Result()
{ {
Exec(); Exec();
if (_current != null) _stashes.Add(_current); if (_current != null)
_stashes.Add(_current);
return _stashes; return _stashes;
} }
@ -28,17 +29,20 @@ namespace SourceGit.Commands
{ {
if (line.StartsWith("commit ", StringComparison.Ordinal)) if (line.StartsWith("commit ", StringComparison.Ordinal))
{ {
if (_current != null && !string.IsNullOrEmpty(_current.Name)) _stashes.Add(_current); if (_current != null && !string.IsNullOrEmpty(_current.Name))
_stashes.Add(_current);
_current = new Models.Stash() { SHA = line.Substring(7, 8) }; _current = new Models.Stash() { SHA = line.Substring(7, 8) };
return; return;
} }
if (_current == null) return; 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); var match = REG_STASH().Match(line);
if (match.Success) _current.Name = match.Groups[1].Value; 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))
{ {
@ -57,4 +61,4 @@ namespace SourceGit.Commands
private readonly List<Models.Stash> _stashes = new List<Models.Stash>(); private readonly List<Models.Stash> _stashes = new List<Models.Stash>();
private Models.Stash _current = null; private Models.Stash _current = null;
} }
} }

View file

@ -41,4 +41,4 @@ namespace SourceGit.Commands
private readonly List<string> _submodules = new List<string>(); private readonly List<string> _submodules = new List<string>();
} }
} }

View file

@ -41,4 +41,4 @@ namespace SourceGit.Commands
private readonly List<Models.Tag> _loaded = new List<Models.Tag>(); private readonly List<Models.Tag> _loaded = new List<Models.Tag>();
} }
} }

View file

@ -7,8 +7,9 @@
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = "rebase "; Args = "rebase ";
if (autoStash) Args += "--autostash "; if (autoStash)
Args += "--autostash ";
Args += basedOn; Args += basedOn;
} }
} }
} }

View file

@ -38,4 +38,4 @@
return Exec(); return Exec();
} }
} }
} }

View file

@ -35,4 +35,4 @@ namespace SourceGit.Commands
Args = $"reset {mode} {revision}"; Args = $"reset {mode} {revision}";
} }
} }
} }

View file

@ -12,10 +12,12 @@ namespace SourceGit.Commands
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.Append("restore "); builder.Append("restore ");
if (!string.IsNullOrEmpty(extra)) builder.Append(extra).Append(" "); if (!string.IsNullOrEmpty(extra))
builder.Append(extra).Append(" ");
builder.Append("--"); builder.Append("--");
foreach (var f in files) builder.Append(' ').Append('"').Append(f).Append('"'); foreach (var f in files)
builder.Append(' ').Append('"').Append(f).Append('"');
Args = builder.ToString(); Args = builder.ToString();
} }
} }
} }

View file

@ -7,7 +7,8 @@
WorkingDirectory = repo; WorkingDirectory = repo;
Context = repo; Context = repo;
Args = $"revert {commit} --no-edit"; Args = $"revert {commit} --no-edit";
if (!autoCommit) Args += " --no-commit"; if (!autoCommit)
Args += " --no-commit";
} }
} }
} }

View file

@ -15,7 +15,8 @@ namespace SourceGit.Commands
{ {
foreach (var change in changes) foreach (var change in changes)
{ {
if (!ProcessSingleChange(repo, new Models.DiffOption(change, isUnstaged), sw)) return false; if (!ProcessSingleChange(repo, new Models.DiffOption(change, isUnstaged), sw))
return false;
} }
} }
@ -54,4 +55,4 @@ namespace SourceGit.Commands
} }
} }
} }
} }

View file

@ -53,7 +53,8 @@ namespace SourceGit.Commands
while (true) while (true)
{ {
var line = sr.ReadLine(); var line = sr.ReadLine();
if (line == null) break; if (line == null)
break;
proc.StandardInput.WriteLine(line); proc.StandardInput.WriteLine(line);
} }
} }
@ -77,4 +78,4 @@ namespace SourceGit.Commands
} }
} }
} }
} }

View file

@ -79,4 +79,4 @@ namespace SourceGit.Commands
return Exec(); return Exec();
} }
} }
} }

View file

@ -23,15 +23,17 @@ namespace SourceGit.Commands
protected override void OnReadline(string line) protected override void OnReadline(string line)
{ {
var dateEndIdx = line.IndexOf('$', StringComparison.Ordinal); var dateEndIdx = line.IndexOf('$', StringComparison.Ordinal);
if (dateEndIdx == -1) return; if (dateEndIdx == -1)
return;
var dateStr = line.Substring(0, dateEndIdx); var dateStr = line.Substring(0, dateEndIdx);
var date = 0.0; var date = 0.0;
if (!double.TryParse(dateStr, out date)) return; if (!double.TryParse(dateStr, out date))
return;
_statistics.AddCommit(line.Substring(dateEndIdx + 1), date); _statistics.AddCommit(line.Substring(dateEndIdx + 1), date);
} }
private readonly Models.Statistics _statistics = null; private readonly Models.Statistics _statistics = null;
} }
} }

View file

@ -14,7 +14,8 @@ namespace SourceGit.Commands
{ {
_outputHandler = outputHandler; _outputHandler = outputHandler;
Args = $"submodule add {url} {relativePath}"; Args = $"submodule add {url} {relativePath}";
if (!Exec()) return false; if (!Exec())
return false;
if (recursive) if (recursive)
{ {
@ -37,7 +38,8 @@ namespace SourceGit.Commands
public bool Delete(string relativePath) public bool Delete(string relativePath)
{ {
Args = $"submodule deinit -f {relativePath}"; Args = $"submodule deinit -f {relativePath}";
if (!Exec()) return false; if (!Exec())
return false;
Args = $"rm -rf {relativePath}"; Args = $"rm -rf {relativePath}";
return Exec(); return Exec();
@ -50,4 +52,4 @@ namespace SourceGit.Commands
private Action<string> _outputHandler; private Action<string> _outputHandler;
} }
} }

View file

@ -32,7 +32,8 @@ namespace SourceGit.Commands
cmd.WorkingDirectory = repo; cmd.WorkingDirectory = repo;
cmd.Context = repo; cmd.Context = repo;
cmd.Args = $"tag --delete {name}"; cmd.Args = $"tag --delete {name}";
if (!cmd.Exec()) return false; if (!cmd.Exec())
return false;
if (remotes != null) if (remotes != null)
{ {
@ -45,4 +46,4 @@ namespace SourceGit.Commands
return true; return true;
} }
} }
} }

View file

@ -11,8 +11,9 @@
public string Query() public string Query()
{ {
var rs = ReadToEnd(); var rs = ReadToEnd();
if (!rs.IsSuccess || string.IsNullOrWhiteSpace(rs.StdOut)) return string.Empty; if (!rs.IsSuccess || string.IsNullOrWhiteSpace(rs.StdOut))
return string.Empty;
return rs.StdOut.Trim().Substring("git version ".Length); return rs.StdOut.Trim().Substring("git version ".Length);
} }
} }
} }

View file

@ -5,10 +5,10 @@ namespace SourceGit.Converters
{ {
public static class BookmarkConverters public static class BookmarkConverters
{ {
public static FuncValueConverter<int, IBrush> ToBrush = public static readonly FuncValueConverter<int, IBrush> ToBrush =
new FuncValueConverter<int, IBrush>(bookmark => Models.Bookmarks.Brushes[bookmark]); new FuncValueConverter<int, IBrush>(bookmark => Models.Bookmarks.Brushes[bookmark]);
public static FuncValueConverter<int, double> ToStrokeThickness = public static readonly FuncValueConverter<int, double> ToStrokeThickness =
new FuncValueConverter<int, double>(bookmark => bookmark == 0 ? 1.0 : 0); new FuncValueConverter<int, double>(bookmark => bookmark == 0 ? 1.0 : 0);
} }
} }

View file

@ -4,7 +4,7 @@ namespace SourceGit.Converters
{ {
public static class BoolConverters public static class BoolConverters
{ {
public static FuncValueConverter<bool, double> ToCommitOpacity = public static readonly FuncValueConverter<bool, double> ToCommitOpacity =
new FuncValueConverter<bool, double>(x => x ? 1 : 0.5); new FuncValueConverter<bool, double>(x => x ? 1 : 0.5);
} }
} }

View file

@ -4,7 +4,7 @@ namespace SourceGit.Converters
{ {
public static class BranchConverters public static class BranchConverters
{ {
public static FuncValueConverter<Models.Branch, string> ToName = public static readonly FuncValueConverter<Models.Branch, string> ToName =
new FuncValueConverter<Models.Branch, string>(v => v.IsLocal ? v.Name : $"{v.Remote}/{v.Name}"); new FuncValueConverter<Models.Branch, string>(v => v.IsLocal ? v.Name : $"{v.Remote}/{v.Name}");
} }
} }

View file

@ -6,7 +6,7 @@ namespace SourceGit.Converters
{ {
public static class ChangeViewModeConverters public static class ChangeViewModeConverters
{ {
public static FuncValueConverter<Models.ChangeViewMode, StreamGeometry> ToIcon = public static readonly FuncValueConverter<Models.ChangeViewMode, StreamGeometry> ToIcon =
new FuncValueConverter<Models.ChangeViewMode, StreamGeometry>(v => new FuncValueConverter<Models.ChangeViewMode, StreamGeometry>(v =>
{ {
switch (v) switch (v)
@ -20,13 +20,13 @@ namespace SourceGit.Converters
} }
}); });
public static FuncValueConverter<Models.ChangeViewMode, bool> IsList = public static readonly FuncValueConverter<Models.ChangeViewMode, bool> IsList =
new FuncValueConverter<Models.ChangeViewMode, bool>(v => v == Models.ChangeViewMode.List); new FuncValueConverter<Models.ChangeViewMode, bool>(v => v == Models.ChangeViewMode.List);
public static FuncValueConverter<Models.ChangeViewMode, bool> IsGrid = public static readonly FuncValueConverter<Models.ChangeViewMode, bool> IsGrid =
new FuncValueConverter<Models.ChangeViewMode, bool>(v => v == Models.ChangeViewMode.Grid); new FuncValueConverter<Models.ChangeViewMode, bool>(v => v == Models.ChangeViewMode.Grid);
public static FuncValueConverter<Models.ChangeViewMode, bool> IsTree = public static readonly FuncValueConverter<Models.ChangeViewMode, bool> IsTree =
new FuncValueConverter<Models.ChangeViewMode, bool>(v => v == Models.ChangeViewMode.Tree); new FuncValueConverter<Models.ChangeViewMode, bool>(v => v == Models.ChangeViewMode.Tree);
} }
} }

View file

@ -7,14 +7,15 @@ namespace SourceGit.Converters
{ {
public static class DecoratorTypeConverters public static class DecoratorTypeConverters
{ {
public static FuncValueConverter<Models.DecoratorType, IBrush> ToBackground = public static readonly FuncValueConverter<Models.DecoratorType, IBrush> ToBackground =
new FuncValueConverter<Models.DecoratorType, IBrush>(v => new FuncValueConverter<Models.DecoratorType, IBrush>(v =>
{ {
if (v == Models.DecoratorType.Tag) return Models.DecoratorResources.Backgrounds[0]; if (v == Models.DecoratorType.Tag)
return Models.DecoratorResources.Backgrounds[0];
return Models.DecoratorResources.Backgrounds[1]; return Models.DecoratorResources.Backgrounds[1];
}); });
public static FuncValueConverter<Models.DecoratorType, StreamGeometry> ToIcon = public static readonly FuncValueConverter<Models.DecoratorType, StreamGeometry> ToIcon =
new FuncValueConverter<Models.DecoratorType, StreamGeometry>(v => new FuncValueConverter<Models.DecoratorType, StreamGeometry>(v =>
{ {
var key = "Icons.Tag"; var key = "Icons.Tag";
@ -36,4 +37,4 @@ namespace SourceGit.Converters
return Application.Current?.FindResource(key) as StreamGeometry; return Application.Current?.FindResource(key) as StreamGeometry;
}); });
} }
} }

View file

@ -4,10 +4,10 @@ namespace SourceGit.Converters
{ {
public static class FontSizeModifyConverters public static class FontSizeModifyConverters
{ {
public static FuncValueConverter<double, double> Increase = public static readonly FuncValueConverter<double, double> Increase =
new FuncValueConverter<double, double>(v => v + 1.0); new FuncValueConverter<double, double>(v => v + 1.0);
public static FuncValueConverter<double, double> Decrease = public static readonly FuncValueConverter<double, double> Decrease =
new FuncValueConverter<double, double>(v => v - 1.0); new FuncValueConverter<double, double>(v => v - 1.0);
} }
} }

View file

@ -4,13 +4,13 @@ namespace SourceGit.Converters
{ {
public static class IntConverters public static class IntConverters
{ {
public static FuncValueConverter<int, bool> IsGreaterThanZero = public static readonly FuncValueConverter<int, bool> IsGreaterThanZero =
new FuncValueConverter<int, bool>(v => v > 0); new FuncValueConverter<int, bool>(v => v > 0);
public static FuncValueConverter<int, bool> IsZero = public static readonly FuncValueConverter<int, bool> IsZero =
new FuncValueConverter<int, bool>(v => v == 0); new FuncValueConverter<int, bool>(v => v == 0);
public static FuncValueConverter<int, bool> IsOne = public static readonly FuncValueConverter<int, bool> IsOne =
new FuncValueConverter<int, bool>(v => v == 1); new FuncValueConverter<int, bool>(v => v == 1);
} }
} }

View file

@ -7,17 +7,20 @@ namespace SourceGit.Converters
{ {
public static class LauncherPageConverters public static class LauncherPageConverters
{ {
public static FuncMultiValueConverter<object, bool> ToTabSeperatorVisible = public static readonly FuncMultiValueConverter<object, bool> ToTabSeperatorVisible =
new FuncMultiValueConverter<object, bool>(v => new FuncMultiValueConverter<object, bool>(v =>
{ {
if (v == null) return false; if (v == null)
return false;
var array = new List<object>(); var array = new List<object>();
array.AddRange(v); array.AddRange(v);
if (array.Count != 3) return false; if (array.Count != 3)
return false;
var self = array[0] as ViewModels.LauncherPage; var self = array[0] as ViewModels.LauncherPage;
if (self == null) return false; if (self == null)
return false;
var selected = array[1] as ViewModels.LauncherPage; var selected = array[1] as ViewModels.LauncherPage;
var collections = array[2] as AvaloniaList<ViewModels.LauncherPage>; var collections = array[2] as AvaloniaList<ViewModels.LauncherPage>;
@ -32,4 +35,4 @@ namespace SourceGit.Converters
} }
}); });
} }
} }

View file

@ -6,10 +6,10 @@ namespace SourceGit.Converters
{ {
public static class ListConverters public static class ListConverters
{ {
public static FuncValueConverter<IList, string> ToCount = public static readonly FuncValueConverter<IList, string> ToCount =
new FuncValueConverter<IList, string>(v => $" ({v.Count})"); new FuncValueConverter<IList, string>(v => $" ({v.Count})");
public static FuncValueConverter<IList, bool> IsNotNullOrEmpty = public static readonly FuncValueConverter<IList, bool> IsNotNullOrEmpty =
new FuncValueConverter<IList, bool>(v => v != null && v.Count > 0); new FuncValueConverter<IList, bool>(v => v != null && v.Count > 0);
} }
} }

View file

@ -6,17 +6,18 @@ namespace SourceGit.Converters
{ {
public static class PathConverters public static class PathConverters
{ {
public static FuncValueConverter<string, string> PureFileName = public static readonly FuncValueConverter<string, string> PureFileName =
new FuncValueConverter<string, string>(fullpath => Path.GetFileName(fullpath) ?? ""); new FuncValueConverter<string, string>(fullpath => Path.GetFileName(fullpath) ?? "");
public static FuncValueConverter<string, string> PureDirectoryName = public static readonly FuncValueConverter<string, string> PureDirectoryName =
new FuncValueConverter<string, string>(fullpath => Path.GetDirectoryName(fullpath) ?? ""); new FuncValueConverter<string, string>(fullpath => Path.GetDirectoryName(fullpath) ?? "");
public static FuncValueConverter<string, string> TruncateIfTooLong = public static readonly FuncValueConverter<string, string> TruncateIfTooLong =
new FuncValueConverter<string, string>(fullpath => new FuncValueConverter<string, string>(fullpath =>
{ {
if (fullpath.Length <= 50) return fullpath; if (fullpath.Length <= 50)
return fullpath;
return fullpath.Substring(0, 20) + ".../" + Path.GetFileName(fullpath); return fullpath.Substring(0, 20) + ".../" + Path.GetFileName(fullpath);
}); });
} }
} }

View file

@ -2,7 +2,6 @@
using System.Globalization; using System.Globalization;
using Avalonia.Data.Converters; using Avalonia.Data.Converters;
using Avalonia.Media;
using Avalonia.Styling; using Avalonia.Styling;
namespace SourceGit.Converters namespace SourceGit.Converters
@ -22,7 +21,7 @@ namespace SourceGit.Converters
} }
} }
public static ToLocaleConverter ToLocale = new ToLocaleConverter(); public static readonly ToLocaleConverter ToLocale = new ToLocaleConverter();
public class ToThemeConverter : IValueConverter public class ToThemeConverter : IValueConverter
{ {
@ -50,7 +49,7 @@ namespace SourceGit.Converters
} }
} }
public static ToThemeConverter ToTheme = new ToThemeConverter(); public static readonly ToThemeConverter ToTheme = new ToThemeConverter();
public class FormatByResourceKeyConverter : IValueConverter public class FormatByResourceKeyConverter : IValueConverter
{ {
@ -66,9 +65,9 @@ namespace SourceGit.Converters
} }
} }
public static FormatByResourceKeyConverter FormatByResourceKey = new FormatByResourceKeyConverter(); public static readonly FormatByResourceKeyConverter FormatByResourceKey = new FormatByResourceKeyConverter();
public static FuncValueConverter<string, string> ToShortSHA = public static readonly FuncValueConverter<string, string> ToShortSHA =
new FuncValueConverter<string, string>(v => v.Length > 10 ? v.Substring(0, 10) : v); new FuncValueConverter<string, string>(v => v.Length > 10 ? v.Substring(0, 10) : v);
} }
} }

View file

@ -9,7 +9,7 @@ namespace SourceGit.Converters
{ {
public static class WindowStateConverters public static class WindowStateConverters
{ {
public static FuncValueConverter<WindowState, Thickness> ToContentMargin = public static readonly FuncValueConverter<WindowState, Thickness> ToContentMargin =
new FuncValueConverter<WindowState, Thickness>(state => new FuncValueConverter<WindowState, Thickness>(state =>
{ {
if (OperatingSystem.IsWindows() && state == WindowState.Maximized) if (OperatingSystem.IsWindows() && state == WindowState.Maximized)
@ -26,7 +26,7 @@ namespace SourceGit.Converters
} }
}); });
public static FuncValueConverter<WindowState, GridLength> ToTitleBarHeight = public static readonly FuncValueConverter<WindowState, GridLength> ToTitleBarHeight =
new FuncValueConverter<WindowState, GridLength>(state => new FuncValueConverter<WindowState, GridLength>(state =>
{ {
if (state == WindowState.Maximized) if (state == WindowState.Maximized)
@ -39,7 +39,7 @@ namespace SourceGit.Converters
} }
}); });
public static FuncValueConverter<WindowState, StreamGeometry> ToMaxOrRestoreIcon = public static readonly FuncValueConverter<WindowState, StreamGeometry> ToMaxOrRestoreIcon =
new FuncValueConverter<WindowState, StreamGeometry>(state => new FuncValueConverter<WindowState, StreamGeometry>(state =>
{ {
if (state == WindowState.Maximized) if (state == WindowState.Maximized)
@ -52,7 +52,7 @@ namespace SourceGit.Converters
} }
}); });
public static FuncValueConverter<WindowState, bool> IsNormal = public static readonly FuncValueConverter<WindowState, bool> IsNormal =
new FuncValueConverter<WindowState, bool>(state => state == WindowState.Normal); new FuncValueConverter<WindowState, bool>(state => state == WindowState.Normal);
} }
} }

View file

@ -13,4 +13,4 @@
Arg = a; Arg = a;
} }
} }
} }

View file

@ -26,7 +26,8 @@ namespace SourceGit.Models
static AvatarManager() static AvatarManager()
{ {
_storePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "SourceGit", "avatars"); _storePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "SourceGit", "avatars");
if (!Directory.Exists(_storePath)) Directory.CreateDirectory(_storePath); if (!Directory.Exists(_storePath))
Directory.CreateDirectory(_storePath);
Task.Run(() => Task.Run(() =>
{ {
@ -83,8 +84,10 @@ namespace SourceGit.Models
Dispatcher.UIThread.InvokeAsync(() => Dispatcher.UIThread.InvokeAsync(() =>
{ {
if (_resources.ContainsKey(md5)) _resources[md5] = img; if (_resources.ContainsKey(md5))
else _resources.Add(md5, img); _resources[md5] = img;
else
_resources.Add(md5, img);
NotifyResourceChanged(md5); NotifyResourceChanged(md5);
}); });
} }
@ -105,16 +108,19 @@ namespace SourceGit.Models
{ {
if (forceRefetch) if (forceRefetch)
{ {
if (_resources.ContainsKey(md5)) _resources.Remove(md5); if (_resources.ContainsKey(md5))
_resources.Remove(md5);
var localFile = Path.Combine(_storePath, md5); var localFile = Path.Combine(_storePath, md5);
if (File.Exists(localFile)) File.Delete(localFile); if (File.Exists(localFile))
File.Delete(localFile);
NotifyResourceChanged(md5); NotifyResourceChanged(md5);
} }
else else
{ {
if (_resources.ContainsKey(md5)) return _resources[md5]; if (_resources.TryGetValue(md5, out var value))
return value;
var localFile = Path.Combine(_storePath, md5); var localFile = Path.Combine(_storePath, md5);
if (File.Exists(localFile)) if (File.Exists(localFile))
@ -134,7 +140,8 @@ namespace SourceGit.Models
lock (_synclock) lock (_synclock)
{ {
if (!_requesting.Contains(md5)) _requesting.Add(md5); if (!_requesting.Contains(md5))
_requesting.Add(md5);
} }
return null; return null;
@ -154,4 +161,4 @@ namespace SourceGit.Models
private static readonly Dictionary<string, Bitmap> _resources = new Dictionary<string, Bitmap>(); private static readonly Dictionary<string, Bitmap> _resources = new Dictionary<string, Bitmap>();
private static readonly HashSet<string> _requesting = new HashSet<string>(); private static readonly HashSet<string> _requesting = new HashSet<string>();
} }
} }

View file

@ -17,4 +17,4 @@ namespace SourceGit.Models
public string Content { get; set; } = string.Empty; public string Content { get; set; } = string.Empty;
public bool IsBinary { get; set; } = false; public bool IsBinary { get; set; } = false;
} }
} }

View file

@ -19,7 +19,8 @@ namespace SourceGit.Models
static Bookmarks() static Bookmarks()
{ {
for (int i = 0; i < Brushes.Length; i++) Supported.Add(i); for (int i = 0; i < Brushes.Length; i++)
Supported.Add(i);
} }
} }
} }

View file

@ -11,4 +11,4 @@
public string UpstreamTrackStatus { get; set; } public string UpstreamTrackStatus { get; set; }
public string Remote { get; set; } public string Remote { get; set; }
} }
} }

View file

@ -83,7 +83,8 @@ namespace SourceGit.Models
else else
{ {
var remote = _remotes.Find(x => x.Name == branch.Remote); var remote = _remotes.Find(x => x.Name == branch.Remote);
if (remote != null) MakeBranchNode(branch, remote.Children, $"remote/{remote.Name}", isFiltered); if (remote != null)
MakeBranchNode(branch, remote.Children, $"remote/{remote.Name}", isFiltered);
} }
} }
@ -106,7 +107,8 @@ namespace SourceGit.Models
foreach (var node in nodes) foreach (var node in nodes)
{ {
var path = prefix + "/" + node.Name; var path = prefix + "/" + node.Name;
if (node.Type != BranchTreeNodeType.Branch && node.IsExpanded) _expanded.Add(path); if (node.Type != BranchTreeNodeType.Branch && node.IsExpanded)
_expanded.Add(path);
CollectExpandedNodes(node.Children, path); CollectExpandedNodes(node.Children, path);
} }
} }
@ -134,9 +136,9 @@ namespace SourceGit.Models
for (int i = 0; i < subs.Length - 1; i++) for (int i = 0; i < subs.Length - 1; i++)
{ {
path = string.Concat(path, "/", subs[i]); path = string.Concat(path, "/", subs[i]);
if (_maps.ContainsKey(path)) if (_maps.TryGetValue(path, out var value))
{ {
lastFolder = _maps[path]; lastFolder = value;
} }
else if (lastFolder == null) else if (lastFolder == null)
{ {
@ -188,7 +190,8 @@ namespace SourceGit.Models
} }
}); });
foreach (var node in nodes) SortNodes(node.Children); foreach (var node in nodes)
SortNodes(node.Children);
} }
private readonly List<BranchTreeNode> _locals = new List<BranchTreeNode>(); private readonly List<BranchTreeNode> _locals = new List<BranchTreeNode>();
@ -198,4 +201,4 @@ namespace SourceGit.Models
private readonly Dictionary<string, BranchTreeNode> _maps = new Dictionary<string, BranchTreeNode>(); private readonly Dictionary<string, BranchTreeNode> _maps = new Dictionary<string, BranchTreeNode>();
} }
} }
} }

View file

@ -8,7 +8,7 @@ namespace SourceGit.Models
public string Value { get; set; } public string Value { get; set; }
public string Desc { get; set; } public string Desc { get; set; }
public static List<CRLFMode> Supported = new List<CRLFMode>() { public static readonly List<CRLFMode> Supported = new List<CRLFMode>() {
new CRLFMode("TRUE", "true", "Commit as LF, checkout as CRLF"), new CRLFMode("TRUE", "true", "Commit as LF, checkout as CRLF"),
new CRLFMode("INPUT", "input", "Only convert for commit"), new CRLFMode("INPUT", "input", "Only convert for commit"),
new CRLFMode("FALSE", "false", "Do NOT convert"), new CRLFMode("FALSE", "false", "Do NOT convert"),
@ -21,4 +21,4 @@ namespace SourceGit.Models
Desc = desc; Desc = desc;
} }
} }
} }

View file

@ -32,9 +32,12 @@ namespace SourceGit.Models
{ {
get get
{ {
if (Index == ChangeState.Unmerged || WorkTree == ChangeState.Unmerged) return true; if (Index == ChangeState.Unmerged || WorkTree == ChangeState.Unmerged)
if (Index == ChangeState.Added && WorkTree == ChangeState.Added) return true; return true;
if (Index == ChangeState.Deleted && WorkTree == ChangeState.Deleted) return true; if (Index == ChangeState.Added && WorkTree == ChangeState.Added)
return true;
if (Index == ChangeState.Deleted && WorkTree == ChangeState.Deleted)
return true;
return false; return false;
} }
} }
@ -63,8 +66,10 @@ namespace SourceGit.Models
} }
} }
if (Path[0] == '"') Path = Path.Substring(1, Path.Length - 2); if (Path[0] == '"')
if (!string.IsNullOrEmpty(OriginalPath) && OriginalPath[0] == '"') OriginalPath = OriginalPath.Substring(1, OriginalPath.Length - 2); Path = Path.Substring(1, Path.Length - 2);
if (!string.IsNullOrEmpty(OriginalPath) && OriginalPath[0] == '"')
OriginalPath = OriginalPath.Substring(1, OriginalPath.Length - 2);
} }
} }
} }

View file

@ -38,7 +38,8 @@ namespace SourceGit.Models
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); var userEndIdx = data.IndexOf('>', StringComparison.Ordinal);
if (userEndIdx < 0) return; if (userEndIdx < 0)
return;
var timeEndIdx = data.IndexOf(' ', userEndIdx + 2); var timeEndIdx = data.IndexOf(' ', userEndIdx + 2);
user = User.FindOrAdd(data.Substring(0, userEndIdx)); user = User.FindOrAdd(data.Substring(0, userEndIdx));
@ -47,4 +48,4 @@ namespace SourceGit.Models
private static readonly DateTime _utcStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime(); private static readonly DateTime _utcStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime();
} }
} }

View file

@ -55,11 +55,13 @@ namespace SourceGit.Models
{ {
Add(new Point(LastX, LastY)); Add(new Point(LastX, LastY));
Add(new Point(x, y - halfHeight)); Add(new Point(x, y - halfHeight));
if (isEnd) Add(new Point(x, y)); 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)); if (y > LastY + halfHeight)
Add(new Point(LastX, LastY + halfHeight));
Add(new Point(x, y)); Add(new Point(x, y));
} }
else if (isEnd) else if (isEnd)
@ -136,7 +138,8 @@ namespace SourceGit.Models
if (commit.Parents.Count > 0) if (commit.Parents.Count > 0)
{ {
major.Next = commit.Parents[0]; major.Next = commit.Parents[0];
if (!mapUnsolved.ContainsKey(major.Next)) mapUnsolved.Add(major.Next, major); if (!mapUnsolved.ContainsKey(major.Next))
mapUnsolved.Add(major.Next, major);
} }
else else
{ {
@ -155,7 +158,8 @@ namespace SourceGit.Models
} }
else else
{ {
if (!mapUnsolved.ContainsKey(l.Next)) mapUnsolved.Add(l.Next, l); if (!mapUnsolved.ContainsKey(l.Next))
mapUnsolved.Add(l.Next, l);
offsetX += UNIT_WIDTH; offsetX += UNIT_WIDTH;
l.Add(offsetX, offsetY, HALF_HEIGHT); l.Add(offsetX, offsetY, HALF_HEIGHT);
} }
@ -188,9 +192,9 @@ namespace SourceGit.Models
for (int j = 1; j < commit.Parents.Count; j++) for (int j = 1; j < commit.Parents.Count; j++)
{ {
var parent = commit.Parents[j]; var parent = commit.Parents[j];
if (mapUnsolved.ContainsKey(parent)) if (mapUnsolved.TryGetValue(parent, out var value))
{ {
var l = mapUnsolved[parent]; var l = value;
var link = new Link(); var link = new Link();
link.Start = position; link.Start = position;
@ -233,7 +237,8 @@ namespace SourceGit.Models
var path = unsolved[i]; var path = unsolved[i];
var endY = (commits.Count - 0.5) * UNIT_HEIGHT; var endY = (commits.Count - 0.5) * UNIT_HEIGHT;
if (path.Path.Points.Count == 1 && path.Path.Points[0].Y == endY) continue; if (path.Path.Points.Count == 1 && path.Path.Points[0].Y == endY)
continue;
path.Add((i + 0.5) * UNIT_WIDTH, endY + HALF_HEIGHT, HALF_HEIGHT, true); path.Add((i + 0.5) * UNIT_WIDTH, endY + HALF_HEIGHT, HALF_HEIGHT, true);
} }
unsolved.Clear(); unsolved.Clear();
@ -241,4 +246,4 @@ namespace SourceGit.Models
return temp; return temp;
} }
} }
} }

View file

@ -24,4 +24,4 @@ namespace SourceGit.Models
new SolidColorBrush(0xFFFFB835), new SolidColorBrush(0xFFFFB835),
]; ];
} }
} }

View file

@ -93,11 +93,14 @@ namespace SourceGit.Models
public override string ToString() public override string ToString()
{ {
var builder = new StringBuilder(); var builder = new StringBuilder();
if (!string.IsNullOrEmpty(_extra)) builder.Append($"{_extra} "); if (!string.IsNullOrEmpty(_extra))
foreach (var r in _revisions) builder.Append($"{r} "); builder.Append($"{_extra} ");
foreach (var r in _revisions)
builder.Append($"{r} ");
builder.Append("-- "); builder.Append("-- ");
if (!string.IsNullOrEmpty(_orgPath)) builder.Append($"\"{_orgPath}\" "); if (!string.IsNullOrEmpty(_orgPath))
builder.Append($"\"{_orgPath}\" ");
builder.Append($"\"{_path}\""); builder.Append($"\"{_path}\"");
return builder.ToString(); return builder.ToString();
@ -110,4 +113,4 @@ namespace SourceGit.Models
private readonly string _extra = string.Empty; private readonly string _extra = string.Empty;
private readonly List<string> _revisions = new List<string>(); private readonly List<string> _revisions = new List<string>();
} }
} }

View file

@ -71,13 +71,15 @@ namespace SourceGit.Models
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.Append("diff --git a/").Append(change.Path).Append(" b/").Append(change.Path).Append('\n'); builder.Append("diff --git a/").Append(change.Path).Append(" b/").Append(change.Path).Append('\n');
if (!revert && !isTracked) builder.Append("new file mode 100644\n"); if (!revert && !isTracked)
builder.Append("new file mode 100644\n");
builder.Append("index 00000000...").Append(fileGuid).Append('\n'); builder.Append("index 00000000...").Append(fileGuid).Append('\n');
builder.Append("--- ").Append((revert || isTracked) ? $"a/{change.Path}\n" : "/dev/null\n"); builder.Append("--- ").Append((revert || isTracked) ? $"a/{change.Path}\n" : "/dev/null\n");
builder.Append("+++ b/").Append(change.Path).Append('\n'); builder.Append("+++ b/").Append(change.Path).Append('\n');
var additions = selection.EndLine - selection.StartLine; var additions = selection.EndLine - selection.StartLine;
if (selection.StartLine != 1) additions++; if (selection.StartLine != 1)
additions++;
if (revert) if (revert)
{ {
@ -86,7 +88,8 @@ namespace SourceGit.Models
for (int i = 1; i <= totalLines; i++) for (int i = 1; i <= totalLines; i++)
{ {
var line = Lines[i]; var line = Lines[i];
if (line.Type != TextDiffLineType.Added) continue; if (line.Type != TextDiffLineType.Added)
continue;
builder.Append(selection.IsInRange(i) ? "\n+" : "\n ").Append(line.Content); builder.Append(selection.IsInRange(i) ? "\n+" : "\n ").Append(line.Content);
} }
} }
@ -96,7 +99,8 @@ namespace SourceGit.Models
for (int i = selection.StartLine - 1; i < selection.EndLine; i++) for (int i = selection.StartLine - 1; i < selection.EndLine; i++)
{ {
var line = Lines[i]; var line = Lines[i];
if (line.Type != TextDiffLineType.Added) continue; if (line.Type != TextDiffLineType.Added)
continue;
builder.Append("\n+").Append(line.Content); builder.Append("\n+").Append(line.Content);
} }
} }
@ -125,7 +129,8 @@ namespace SourceGit.Models
for (int i = selection.EndLine; i < Lines.Count; i++) for (int i = selection.EndLine; i < Lines.Count; i++)
{ {
var line = Lines[i]; var line = Lines[i];
if (line.Type == TextDiffLineType.Indicator) break; if (line.Type == TextDiffLineType.Indicator)
break;
if (revert) if (revert)
{ {
if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Added) if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Added)
@ -184,11 +189,13 @@ namespace SourceGit.Models
} }
else if (line.Type == TextDiffLineType.Added) else if (line.Type == TextDiffLineType.Added)
{ {
if (revert) builder.Append("\n ").Append(line.Content); 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); if (!revert)
builder.Append("\n ").Append(line.Content);
} }
else if (line.Type == TextDiffLineType.Normal) else if (line.Type == TextDiffLineType.Normal)
{ {
@ -247,7 +254,8 @@ namespace SourceGit.Models
for (int i = selection.EndLine; i < Lines.Count; i++) for (int i = selection.EndLine; i < Lines.Count; i++)
{ {
var line = Lines[i]; var line = Lines[i];
if (line.Type == TextDiffLineType.Indicator) break; if (line.Type == TextDiffLineType.Indicator)
break;
if (revert) if (revert)
{ {
if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Added) if (line.Type == TextDiffLineType.Normal || line.Type == TextDiffLineType.Added)
@ -306,11 +314,13 @@ namespace SourceGit.Models
} }
else if (line.Type == TextDiffLineType.Added) else if (line.Type == TextDiffLineType.Added)
{ {
if (revert) builder.Append("\n ").Append(line.Content); 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); if (!revert)
builder.Append("\n ").Append(line.Content);
} }
else if (line.Type == TextDiffLineType.Normal) else if (line.Type == TextDiffLineType.Normal)
{ {
@ -390,7 +400,8 @@ namespace SourceGit.Models
for (int i = idx + 1; i < end; i++) for (int i = idx + 1; i < end; i++)
{ {
var test = Lines[i]; var test = Lines[i];
if (test.Type == TextDiffLineType.Indicator) break; if (test.Type == TextDiffLineType.Indicator)
break;
if (test.Type == TextDiffLineType.Normal) if (test.Type == TextDiffLineType.Normal)
{ {
@ -441,7 +452,8 @@ namespace SourceGit.Models
} }
} }
if (oldCount == 0 && newCount == 0) return false; if (oldCount == 0 && newCount == 0)
return false;
builder.Append($"\n@@ -{oldStart},{oldCount} +{newStart},{newCount} @@"); builder.Append($"\n@@ -{oldStart},{oldCount} +{newStart},{newCount} @@");
return true; return true;
@ -457,7 +469,8 @@ namespace SourceGit.Models
for (int i = idx + 1; i < end; i++) for (int i = idx + 1; i < end; i++)
{ {
var test = Lines[i]; var test = Lines[i];
if (test.Type == TextDiffLineType.Indicator) break; if (test.Type == TextDiffLineType.Indicator)
break;
if (test.Type == TextDiffLineType.Normal) if (test.Type == TextDiffLineType.Normal)
{ {
@ -530,7 +543,8 @@ namespace SourceGit.Models
} }
} }
if (oldCount == 0 && newCount == 0) return false; if (oldCount == 0 && newCount == 0)
return false;
builder.Append($"\n@@ -{oldStart},{oldCount} +{newStart},{newCount} @@"); builder.Append($"\n@@ -{oldStart},{oldCount} +{newStart},{newCount} @@");
return true; return true;
@ -569,4 +583,4 @@ namespace SourceGit.Models
public TextDiff TextDiff { get; set; } = null; public TextDiff TextDiff { get; set; } = null;
public LFSDiff LFSDiff { get; set; } = null; public LFSDiff LFSDiff { get; set; } = null;
} }
} }

View file

@ -11,7 +11,7 @@ namespace SourceGit.Models
public string Cmd { get; set; } public string Cmd { get; set; }
public string DiffCmd { get; set; } public string DiffCmd { get; set; }
public static List<ExternalMergeTools> Supported; public static readonly List<ExternalMergeTools> Supported;
static ExternalMergeTools() static ExternalMergeTools()
{ {
@ -63,4 +63,4 @@ namespace SourceGit.Models
DiffCmd = diffCmd; DiffCmd = diffCmd;
} }
} }
} }

View file

@ -26,11 +26,15 @@
public GitFlowBranchType GetBranchType(string name) public GitFlowBranchType GetBranchType(string name)
{ {
if (!IsEnabled) return GitFlowBranchType.None; if (!IsEnabled)
if (name.StartsWith(Feature)) return GitFlowBranchType.Feature; return GitFlowBranchType.None;
if (name.StartsWith(Release)) return GitFlowBranchType.Release; if (name.StartsWith(Feature))
if (name.StartsWith(Hotfix)) return GitFlowBranchType.Hotfix; return GitFlowBranchType.Feature;
if (name.StartsWith(Release))
return GitFlowBranchType.Release;
if (name.StartsWith(Hotfix))
return GitFlowBranchType.Hotfix;
return GitFlowBranchType.None; return GitFlowBranchType.None;
} }
} }
} }

View file

@ -5,4 +5,4 @@
public string Oid { get; set; } = string.Empty; public string Oid { get; set; } = string.Empty;
public long Size { get; set; } = 0; public long Size { get; set; } = 0;
} }
} }

View file

@ -7,7 +7,7 @@ namespace SourceGit.Models
public string Name { get; set; } public string Name { get; set; }
public string Key { get; set; } public string Key { get; set; }
public static List<Locale> Supported = new List<Locale>() { public static readonly List<Locale> Supported = new List<Locale>() {
new Locale("English", "en_US"), new Locale("English", "en_US"),
new Locale("简体中文", "zh_CN"), new Locale("简体中文", "zh_CN"),
}; };
@ -18,4 +18,4 @@ namespace SourceGit.Models
Key = key; Key = key;
} }
} }
} }

View file

@ -10,4 +10,4 @@
{ {
void OnReceiveNotification(string ctx, Notification notice); void OnReceiveNotification(string ctx, Notification notice);
} }
} }

View file

@ -15,4 +15,4 @@
public ObjectType Type { get; set; } public ObjectType Type { get; set; }
public string Path { get; set; } public string Path { get; set; }
} }
} }

View file

@ -24,11 +24,13 @@ namespace SourceGit.Models
public static bool IsSSH(string url) public static bool IsSSH(string url)
{ {
if (string.IsNullOrWhiteSpace(url)) return false; 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; if (URL_FORMATS[i].IsMatch(url))
return true;
} }
return false; return false;
@ -38,9 +40,10 @@ namespace SourceGit.Models
{ {
foreach (var fmt in URL_FORMATS) foreach (var fmt in URL_FORMATS)
{ {
if (fmt.IsMatch(url)) return true; if (fmt.IsMatch(url))
return true;
} }
return false; return false;
} }
} }
} }

View file

@ -27,4 +27,4 @@ namespace SourceGit.Models
{ {
public string SHA { get; set; } public string SHA { get; set; }
} }
} }

View file

@ -14,4 +14,4 @@ namespace SourceGit.Models
public string TimeStr => UTC_START.AddSeconds(Time).ToString("yyyy/MM/dd HH:mm:ss"); public string TimeStr => UTC_START.AddSeconds(Time).ToString("yyyy/MM/dd HH:mm:ss");
} }
} }

View file

@ -20,9 +20,9 @@ namespace SourceGit.Models
Total++; Total++;
Samples[index].Count++; Samples[index].Count++;
if (_mapByCommitter.ContainsKey(committer)) if (_mapByCommitter.TryGetValue(committer, out var value))
{ {
_mapByCommitter[committer].Count++; value.Count++;
} }
else else
{ {
@ -141,4 +141,4 @@ namespace SourceGit.Models
private readonly DateTime _thisWeekStart; private readonly DateTime _thisWeekStart;
private readonly DateTime _thisWeekEnd; private readonly DateTime _thisWeekEnd;
} }
} }

View file

@ -6,4 +6,4 @@
public string SHA { get; set; } public string SHA { get; set; }
public bool IsFiltered { get; set; } public bool IsFiltered { get; set; }
} }
} }

View file

@ -79,10 +79,13 @@ namespace SourceGit.Models
var beginNew = posNew; var beginNew = posNew;
var countOld = 0; var countOld = 0;
var countNew = 0; var countNew = 0;
for (; posOld < sizeOld && chunksOld[posOld].Modified; posOld++) countOld += chunksOld[posOld].Size; for (; posOld < sizeOld && chunksOld[posOld].Modified; posOld++)
for (; posNew < sizeNew && chunksNew[posNew].Modified; posNew++) countNew += chunksNew[posNew].Size; countOld += chunksOld[posOld].Size;
for (; posNew < sizeNew && chunksNew[posNew].Modified; posNew++)
countNew += chunksNew[posNew].Size;
if (countOld + countNew == 0) continue; if (countOld + countNew == 0)
continue;
var diff = new TextInlineChange( var diff = new TextInlineChange(
countOld > 0 ? chunksOld[beginOld].Start : 0, countOld > 0 ? chunksOld[beginOld].Start : 0,
@ -120,13 +123,15 @@ namespace SourceGit.Models
var ch = text[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); if (start != i)
AddChunk(chunks, hashes, text.Substring(start, i - start), start);
AddChunk(chunks, hashes, text.Substring(i, 1), i); AddChunk(chunks, hashes, text.Substring(i, 1), i);
start = i + 1; start = i + 1;
} }
} }
if (start < size) AddChunk(chunks, hashes, text.Substring(start), start); if (start < size)
AddChunk(chunks, hashes, text.Substring(start), start);
return chunks; return chunks;
} }
@ -149,7 +154,8 @@ namespace SourceGit.Models
if (lenOld > 0 && lenNew > 0) if (lenOld > 0 && lenNew > 0)
{ {
var rs = CheckModifiedEdit(chunksOld, startOld, endOld, chunksNew, startNew, endNew, forward, reverse); var rs = CheckModifiedEdit(chunksOld, startOld, endOld, chunksNew, startNew, endNew, forward, reverse);
if (rs.State == Edit.None) return; if (rs.State == Edit.None)
return;
if (rs.State == Edit.DeletedRight && rs.DeleteStart - 1 > startOld) if (rs.State == Edit.DeletedRight && rs.DeleteStart - 1 > startOld)
{ {
@ -173,11 +179,13 @@ namespace SourceGit.Models
} }
else if (lenOld > 0) else if (lenOld > 0)
{ {
for (int i = startOld; i < endOld; i++) chunksOld[i].Modified = true; 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; for (int i = startNew; i < endNew; i++)
chunksNew[i].Modified = true;
} }
} }
@ -317,4 +325,4 @@ namespace SourceGit.Models
} }
} }
} }
} }

View file

@ -26,7 +26,8 @@ namespace SourceGit.Models
public static void SetThemeByApp(TextMate.Installation installation) public static void SetThemeByApp(TextMate.Installation installation)
{ {
if (installation == null) return; if (installation == null)
return;
var reg = installation.RegistryOptions as RegistryOptions; var reg = installation.RegistryOptions as RegistryOptions;
if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) if (App.Current?.ActualThemeVariant == ThemeVariant.Dark)
@ -41,7 +42,8 @@ namespace SourceGit.Models
public static void SetGrammarByFileName(TextMate.Installation installation, string filePath) public static void SetGrammarByFileName(TextMate.Installation installation, string filePath)
{ {
if (installation == null) return; if (installation == null)
return;
var ext = Path.GetExtension(filePath); var ext = Path.GetExtension(filePath);
if (ext == ".h") if (ext == ".h")
@ -58,4 +60,4 @@ namespace SourceGit.Models
GC.Collect(); GC.Collect();
} }
} }
} }

View file

@ -4,15 +4,15 @@ namespace SourceGit.Models
{ {
public class User public class User
{ {
public static User Invalid = new User(); public static readonly User Invalid = new User();
public static Dictionary<string, User> Caches = new Dictionary<string, User>();
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
public string Email { 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; if (obj == null || !(obj is User))
return false;
var other = obj as User; var other = obj as User;
return Name == other.Name && Email == other.Email; return Name == other.Name && Email == other.Email;
@ -25,9 +25,9 @@ namespace SourceGit.Models
public static User FindOrAdd(string data) public static User FindOrAdd(string data)
{ {
if (Caches.ContainsKey(data)) if (_caches.TryGetValue(data, out var value))
{ {
return Caches[data]; return value;
} }
else else
{ {
@ -36,9 +36,11 @@ namespace SourceGit.Models
var email = data.Substring(nameEndIdx + 1); var email = data.Substring(nameEndIdx + 1);
User user = new User() { Name = name, Email = email }; User user = new User() { Name = name, Email = email };
Caches.Add(data, user); _caches.Add(data, user);
return user; return user;
} }
} }
private static Dictionary<string, User> _caches = new Dictionary<string, User>();
} }
} }

View file

@ -23,7 +23,8 @@ namespace SourceGit.Models
get get
{ {
var match = REG_VERSION_TAG().Match(TagName); var match = REG_VERSION_TAG().Match(TagName);
if (!match.Success) return false; if (!match.Success)
return false;
var major = int.Parse(match.Groups[1].Value); var major = int.Parse(match.Groups[1].Value);
var minor = int.Parse(match.Groups[2].Value); var minor = int.Parse(match.Groups[2].Value);
@ -34,4 +35,4 @@ namespace SourceGit.Models
} }
public class AlreadyUpToDate { } public class AlreadyUpToDate { }
} }

Some files were not shown because too many files have changed in this diff Show more