Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
235 changes: 213 additions & 22 deletions .gitignore

Large diffs are not rendered by default.

41 changes: 41 additions & 0 deletions src/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[*]

# Microsoft .NET properties
csharp_new_line_before_members_in_object_initializers = false
csharp_preferred_modifier_order = private, public, protected, internal, file, new, static, sealed, override, virtual, abstract, async, extern, unsafe, volatile, readonly, required:suggestion
csharp_style_namespace_declarations = block_scoped:suggestion
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:none
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:none

# ReSharper properties
resharper_align_linq_query = true
resharper_align_multiline_binary_expressions_chain = false
resharper_align_multiline_statement_conditions = false
resharper_blank_lines_after_block_statements = 0
resharper_blank_lines_around_single_line_auto_property = 1
resharper_braces_for_foreach = required
resharper_braces_for_using = required
resharper_braces_for_while = required
resharper_braces_redundant = false
resharper_csharp_blank_lines_around_field = 0
resharper_csharp_blank_lines_around_region = 0
resharper_csharp_blank_lines_around_single_line_invocable = 1
resharper_csharp_insert_final_newline = true
resharper_csharp_max_line_length = 201
resharper_csharp_remove_blank_lines_near_braces_in_code = false
resharper_csharp_remove_blank_lines_near_braces_in_declarations = false
resharper_indent_pars = outside_and_inside
resharper_instance_members_qualify_declared_in =
resharper_keep_existing_attribute_arrangement = true
resharper_nested_ternary_style = simple_wrap
resharper_object_creation_when_type_evident = explicitly_typed
resharper_parentheses_redundancy_style = remove
resharper_parentheses_same_type_operations = true
resharper_place_accessorholder_attribute_on_same_line = false
resharper_place_expr_accessor_on_single_line = true
resharper_place_expr_method_on_single_line = true
resharper_place_simple_embedded_statement_on_same_line = false
resharper_place_simple_initializer_on_single_line = false
resharper_space_within_single_line_array_initializer_braces = false
resharper_wrap_object_and_collection_initializer_style = chop_always
13 changes: 13 additions & 0 deletions src/.idea/.idea.QBittorrent.CommandLineInterface/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 3 additions & 46 deletions src/QBittorrent.CommandLineInterface.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,47 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/@KeyIndexDefined">True</s:Boolean>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Applicability/=Live/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Field/=DISP_005FNAME/@KeyIndexDefined">True</s:Boolean>
<s:Int64 x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Field/=DISP_005FNAME/Order/@EntryValue">3</s:Int64>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Field/=JSON_005FNAME/@KeyIndexDefined">True</s:Boolean>
<s:Int64 x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Field/=JSON_005FNAME/Order/@EntryValue">0</s:Int64>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Field/=PROP/@KeyIndexDefined">True</s:Boolean>
<s:Int64 x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Field/=PROP/Order/@EntryValue">2</s:Int64>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Field/=TYPE/@KeyIndexDefined">True</s:Boolean>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Field/=TYPE/Expression/@EntryValue">completeSmart()</s:String>
<s:Int64 x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Field/=TYPE/Order/@EntryValue">1</s:Int64>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Reformat/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Scope/=B68999B9D6B43E47A02B22C12A54C3CC/@KeyIndexDefined">True</s:Boolean>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Scope/=B68999B9D6B43E47A02B22C12A54C3CC/CustomProperties/=minimumLanguageVersion/@EntryIndexedValue">2.0</s:String>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Scope/=B68999B9D6B43E47A02B22C12A54C3CC/Type/@EntryValue">InCSharpTypeMember</s:String>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Shortcut/@EntryValue">jdprop</s:String>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/ShortenQualifiedReferences/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=4D56C100BD875946996CF9119DAB01A4/Text/@EntryValue">/// &lt;summary&gt;&#xD;
/// &#xD;
/// &lt;/summary&gt;&#xD;
[JsonProperty("$JSON_NAME$")]&#xD;
[Display(Name = "$DISP_NAME$")]&#xD;
public $TYPE$ $PROP$ { get; set; }</s:String>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/@KeyIndexDefined">True</s:Boolean>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/Field/=JSON_005FNAME/@KeyIndexDefined">True</s:Boolean>
<s:Int64 x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/Field/=JSON_005FNAME/Order/@EntryValue">0</s:Int64>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/Field/=PROP/@KeyIndexDefined">True</s:Boolean>
<s:Int64 x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/Field/=PROP/Order/@EntryValue">2</s:Int64>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/Field/=TYPE/@KeyIndexDefined">True</s:Boolean>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/Field/=TYPE/Expression/@EntryValue">completeSmart()</s:String>
<s:Int64 x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/Field/=TYPE/Order/@EntryValue">1</s:Int64>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/Shortcut/@EntryValue">jprop</s:String>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/Description/@EntryValue">JSON Property</s:String>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/Reformat/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/ShortenQualifiedReferences/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/Applicability/=Live/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/Scope/=B68999B9D6B43E47A02B22C12A54C3CC/@KeyIndexDefined">True</s:Boolean>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/Scope/=B68999B9D6B43E47A02B22C12A54C3CC/Type/@EntryValue">InCSharpTypeMember</s:String>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/Scope/=B68999B9D6B43E47A02B22C12A54C3CC/CustomProperties/=minimumLanguageVersion/@EntryIndexedValue">2.0</s:String>
<s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=89800366A3AA8A4C82F3214623886197/Text/@EntryValue">/// &lt;summary&gt;&#xD;
/// &#xD;
/// &lt;/summary&gt;&#xD;
[JsonProperty("$JSON_NAME$")]&#xD;
public $TYPE$ $PROP$ { get; set; }</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Bittorrent/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BT/@EntryIndexedValue">BT</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DHT/@EntryIndexedValue">DHT</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String></wpf:ResourceDictionary>
11 changes: 0 additions & 11 deletions src/QBittorrent.CommandLineInterface/App.config

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ public EnumValidationAttribute(Type enumType)

public bool AllowEmpty { get; set; }

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
if (value == null && AllowEmpty)
return ValidationResult.Success;

if (value is string str &&
(EnumHelper.TryParse(EnumType, str, !CaseSensitive, out _) || (AllowEmpty && string.IsNullOrEmpty(str)))
)
return ValidationResult.Success;
switch (value)
{
case null when AllowEmpty:
case string str when
Enum.TryParse(EnumType, str, !CaseSensitive, out _) || AllowEmpty && string.IsNullOrEmpty(str):
return ValidationResult.Success;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason in all this rewriting?

There were nothing wrong with the original piece of code here. And it did excactly what it supposed to.
And you rewrite it to do the very same think. But in syntax you like. Why?
It just produces more changes without a solid reason. And that accordingly leads to increasing complicity of reviewing.

You named this commit "Update all dependencies and fix any issues / deprecations" and I don't see neither any depenecies to update or any issues / deprecations to fix in this pieces of code here and further (in this commit. I didin't check other ones).
And even so more it has nothing to do with a problem you described as the reason of your PR.

So what's the reason? If you really wanted to propose this code style to maintainer and contributors than you coluld release another separate PR with all this changes for team or maintainer to decide. But u said it's fixes when it actualy not.


var values = string.Join(", ", Enum.GetValues(EnumType).Cast<object>());
if (!CaseSensitive)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Text;

namespace QBittorrent.CommandLineInterface.Attributes
{
public class IpAddressValidationAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
if (value is null)
return ValidationResult.Success;
switch (value)
{
case null:
case string str when IPAddress.TryParse(str, out _):
return ValidationResult.Success;
default:
return new ValidationResult($"The value {value} is not a correct IP address.");
}

if (value is string str && IPAddress.TryParse(str, out _))
return ValidationResult.Success;

return new ValidationResult($"The value {value} is not a correct IP address.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,23 @@ namespace QBittorrent.CommandLineInterface.Attributes
{
public class IpEndpointValidationAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
if (value is null)
return ValidationResult.Success;

if (value is string str && TryParse(str.AsSpan(), out _))
return ValidationResult.Success;
switch (value)
{
case null:
case string str when TryParse(str.AsSpan(), out _):
return ValidationResult.Success;
default:
return new ValidationResult($"The value {value} is not a correct IP endpoint.");
}

return new ValidationResult($"The value {value} is not a correct IP endpoint.");
}

private static bool TryParse(ReadOnlySpan<char> s, out IPEndPoint result)
private static bool TryParse(ReadOnlySpan<char> s, out IPEndPoint? result)
{
int addressLength = s.Length; // If there's no port then send the entire string to the address parser
int lastColonPos = s.LastIndexOf(':');
var addressLength = s.Length; // If there's no port then send the entire string to the address parser
var lastColonPos = s.LastIndexOf(':');

// Look to see if this is an IPv6 address with a port.
if (lastColonPos > 0)
Expand All @@ -31,45 +33,23 @@ private static bool TryParse(ReadOnlySpan<char> s, out IPEndPoint result)
addressLength = lastColonPos;
}
// Look to see if this is IPv4 with a port (IPv6 will have another colon)
else if (s.Slice(0, lastColonPos).LastIndexOf(':') == -1)
else if (s[..lastColonPos].LastIndexOf(':') == -1)
{
addressLength = lastColonPos;
}
}

#if NETFRAMEWORK
if (IPAddress.TryParse(GetString(s.Slice(0, addressLength)), out var address))
{
uint port = 0;
if (addressLength == s.Length ||
(uint.TryParse(GetString(s.Slice(addressLength + 1)), NumberStyles.None, CultureInfo.InvariantCulture, out port) && port <= IPEndPoint.MaxPort))

{
result = new IPEndPoint(address, (int)port);
return true;
}
}

unsafe static string GetString(in ReadOnlySpan<char> span)
{
fixed (char* p = span)
{
return new string(p, 0, span.Length);
}
}
#else
if (IPAddress.TryParse(s.Slice(0, addressLength), out var address))
if (IPAddress.TryParse(s[..addressLength], out var address))
{
uint port = 0;
if (addressLength == s.Length ||
(uint.TryParse(s.Slice(addressLength + 1), NumberStyles.None, CultureInfo.InvariantCulture, out port) && port <= IPEndPoint.MaxPort))
uint.TryParse(s[(addressLength + 1)..], NumberStyles.None, CultureInfo.InvariantCulture, out port) && port <= IPEndPoint.MaxPort)

{
result = new IPEndPoint(address, (int)port);
return true;
}
}
#endif

result = null;
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ namespace QBittorrent.CommandLineInterface.Attributes
{
public class IpNetworkValidationAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
if (value is null)
return ValidationResult.Success;
switch (value)
{
case null:
case string str when IPNetwork.TryParse(str, out _):
return ValidationResult.Success;
default:
return new ValidationResult($"The value {value} is not a correct IP network.");
}

if (value is string str && IPNetwork.TryParse(str, out _))
return ValidationResult.Success;

return new ValidationResult($"The value {value} is not a correct IP network.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,24 @@ namespace QBittorrent.CommandLineInterface.Attributes
{
public class ShareRatioLimitValidationAttribute : ValidationAttribute
{
private static readonly string[] Keywords = {"GLOBAL", "NONE"};
private static readonly string[] Keywords = ["GLOBAL", "NONE"];

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
if (value is null)
return ValidationResult.Success;

if (value is string str)
switch (value)
{
if (Keywords.Contains(str, StringComparer.OrdinalIgnoreCase))
case null:
case string str when Keywords.Contains(str, StringComparer.OrdinalIgnoreCase):
return ValidationResult.Success;

if (double.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out _))
case string str when double.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out _):
return ValidationResult.Success;

if (double.TryParse(str, out _))
case string str when double.TryParse(str, out _):
return ValidationResult.Success;
default:
return new ValidationResult($"The value {value} is not a correct share ratio limit. " +
"The value must be either a number or one of the keywords: GLOBAL, NONE");
}

return new ValidationResult($"The value {value} is not a correct share ratio limit. " +
"The value must be either a number or one of the keywords: GLOBAL, NONE");
}
}
}
Loading