Skip to content

Commit

Permalink
Ignore special chars in mod search
Browse files Browse the repository at this point in the history
  • Loading branch information
DasSkelett committed Apr 23, 2019
1 parent 12803bc commit 54d003a
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 35 deletions.
16 changes: 7 additions & 9 deletions Cmdline/Action/Search.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,19 @@ public int RunCommand(CKAN.KSP ksp, object raw_options)
/// <param name="term">The search term. Case insensitive.</param>
public List<CkanModule> PerformSearch(CKAN.KSP ksp, string term)
{
// Remove spaces and special characters from the search term.
term = CkanModule.nonAlphaNums.Replace(term, "");

var registry = RegistryManager.Instance(ksp).registry;
return registry
.Available(ksp.VersionCriteria())
.Where((module) =>
{
// Extract the description. This is an optional field and may be null.
string modDesc = string.Empty;
if (!string.IsNullOrEmpty(module.description))
{
modDesc = module.description;
}
// Look for a match in each string.
return module.name.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1 || module.identifier.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1 || modDesc.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1;
return module.SearchableName.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1
|| module.SearchableIdentifier.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1
|| module.SearchableAbstract.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1
|| module.SearchableDescription.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1;
}).ToList();
}

Expand Down
22 changes: 12 additions & 10 deletions ConsoleUI/ModListScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,17 @@ public ModListScreen(KSPManager mgr, bool dbg)
},
1, 0, ListSortDirection.Descending,
(CkanModule m, string filter) => {
// Search for author
if (filter.StartsWith("@")) {
string authorFilt = filter.Substring(1);
if (string.IsNullOrEmpty(authorFilt)) {
return true;
} else if (m.author != null) {
foreach (string auth in m.author) {
if (auth.IndexOf(authorFilt, StringComparison.CurrentCultureIgnoreCase) == 0) {
return true;
}
}
} else {
// Remove special characters from search term
authorFilt = CkanModule.nonAlphaNums.Replace(authorFilt, "");
return m.SearchableAuthors.IndexOf(authorFilt, StringComparison.CurrentCultureIgnoreCase) == 0;
}
return false;
// Other special search params: installed, updatable, new, conflicting and dependends
} else if (filter.StartsWith("~")) {
if (filter.Length <= 1) {
// Don't blank the list for just "~" by itself
Expand Down Expand Up @@ -97,9 +96,12 @@ public ModListScreen(KSPManager mgr, bool dbg)
}
return false;
} else {
return m.identifier.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase) >= 0
|| m.name.IndexOf( filter, StringComparison.CurrentCultureIgnoreCase) >= 0
|| m.@abstract.IndexOf( filter, StringComparison.CurrentCultureIgnoreCase) >= 0;
filter = CkanModule.nonAlphaNums.Replace(filter, "");
return m.SearchableIdentifier.IndexOf( filter, StringComparison.CurrentCultureIgnoreCase) >= 0
|| m.SearchableName.IndexOf( filter, StringComparison.CurrentCultureIgnoreCase) >= 0
|| m.SearchableAbstract.IndexOf( filter, StringComparison.CurrentCultureIgnoreCase) >= 0
|| m.SearchableDescription.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase) >= 0;
}
}
);
Expand Down
3 changes: 2 additions & 1 deletion Core/Registry/AvailableModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ private AvailableModule()
}

[OnDeserialized]
internal void SetIdentifier(StreamingContext context)
internal void DeserialisationFixes(StreamingContext context)
{
// Set identifier
var mod = module_version.Values.LastOrDefault();
identifier = mod.identifier;
Debug.Assert(module_version.Values.All(m=>identifier.Equals(m.identifier)));
Expand Down
33 changes: 32 additions & 1 deletion Core/Types/CkanModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,21 @@ public List<string> ProvidesList
}
}

// These are used to simplify the search by dropping special chars.
[JsonIgnore]
public string SearchableName;
[JsonIgnore]
public string SearchableIdentifier;
[JsonIgnore]
public string SearchableAbstract;
[JsonIgnore]
public string SearchableDescription;
[JsonIgnore]
public string SearchableAuthors;
// This regex finds all those special chars.
[JsonIgnore]
public static readonly Regex nonAlphaNums = new Regex("[^a-zA-Z0-9]", RegexOptions.Compiled);

#endregion

#region Constructors
Expand Down Expand Up @@ -527,7 +542,6 @@ public CkanModule(string json, IGameComparator comparator)

// Check everything in the spec is defined.
// TODO: This *can* and *should* be done with JSON attributes!

foreach (string field in required_fields)
{
object value = null;
Expand All @@ -552,6 +566,21 @@ public CkanModule(string json, IGameComparator comparator)
throw new BadMetadataKraken(null, error);
}
}

// Calculate the Searchables.
CalculateSearchables();
}

/// <summary>
/// Calculate the mod properties used for searching via Regex.
/// </summary>
public void CalculateSearchables()
{
SearchableIdentifier = identifier == null ? string.Empty : CkanModule.nonAlphaNums.Replace(identifier, "");
SearchableName = name == null ? string.Empty : CkanModule.nonAlphaNums.Replace(name, "");
SearchableAbstract = @abstract == null ? string.Empty : CkanModule.nonAlphaNums.Replace(@abstract, "");
SearchableDescription = description == null ? string.Empty : CkanModule.nonAlphaNums.Replace(description, "");
SearchableAuthors = author == null ? string.Empty : CkanModule.nonAlphaNums.Replace(String.Join("", author), "");
}

public string serialise()
Expand All @@ -575,6 +604,8 @@ private void DeSerialisationFixes(StreamingContext like_i_could_care)
license = license ?? new List<License> { License.UnknownLicense };
@abstract = @abstract ?? string.Empty;
name = name ?? string.Empty;

CalculateSearchables();
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion GUI/CKAN-GUI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@
<SubType>Component</SubType>
</Compile>
<Compile Include="SelectionDialog.cs">
<Subtype>Form</Subtype>
<SubType>Form</SubType>
</Compile>
<Compile Include="SelectionDialog.Designer.cs">
<DependentUpon>SelectionDialog.cs</DependentUpon>
Expand Down
18 changes: 16 additions & 2 deletions GUI/GUIMod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Windows.Forms;
using System.Linq;
using CKAN.Versioning;
using CKAN.GameVersionProviders;

namespace CKAN
{
Expand Down Expand Up @@ -32,6 +31,7 @@ public sealed class GUIMod
public string KSPCompatibilityLong { get; private set; }

public string Abstract { get; private set; }
public string Description { get; private set; }
public string Homepage { get; private set; }
public string Identifier { get; private set; }
public bool IsInstallChecked { get; set; }
Expand All @@ -41,6 +41,12 @@ public sealed class GUIMod
public bool IsCKAN { get; private set; }
public string Abbrevation { get; private set; }

public string SearchableName { get; private set; }
public string SearchableIdentifier { get; private set; }
public string SearchableAbstract { get; private set; }
public string SearchableDescription { get; private set; }
public string SearchableAuthors { get; private set; }

/// <summary>
/// Return whether this mod is installable.
/// Used for determining whether to show a checkbox in the leftmost column.
Expand Down Expand Up @@ -99,6 +105,7 @@ public GUIMod(CkanModule mod, IRegistryQuerier registry, KspVersionCriteria curr

Name = mod.name.Trim();
Abstract = mod.@abstract.Trim();
Description = mod.description?.Trim() ?? string.Empty;
Abbrevation = new string(Name.Split(' ').Where(s => s.Length > 0).Select(s => s[0]).ToArray());
Authors = mod.author == null ? "N/A" : String.Join(",", mod.author);

Expand All @@ -116,6 +123,12 @@ public GUIMod(CkanModule mod, IRegistryQuerier registry, KspVersionCriteria curr
?? "N/A";
}

// Get the Searchables.
SearchableName = mod.SearchableName;
SearchableAbstract = mod.SearchableAbstract;
SearchableDescription = mod.SearchableDescription;
SearchableAuthors = mod.SearchableAuthors;

UpdateIsCached();
}

Expand Down Expand Up @@ -186,8 +199,9 @@ public GUIMod(string identifier, IRegistryQuerier registry, KspVersionCriteria c
}

// If we have a homepage provided, use that; otherwise use the spacedock page, curse page or the github repo so that users have somewhere to get more info than just the abstract.

Homepage = "N/A";

SearchableIdentifier = CkanModule.nonAlphaNums.Replace(Identifier, "");
}

/// <summary>
Expand Down
6 changes: 3 additions & 3 deletions GUI/MainModInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ private void UpdateModInfo(GUIMod gui_module)
Util.Invoke(MetadataModuleVersionTextBox, () => MetadataModuleVersionTextBox.Text = gui_module.LatestVersion.ToString());
Util.Invoke(MetadataModuleLicenseTextBox, () => MetadataModuleLicenseTextBox.Text = string.Join(", ", module.license));
Util.Invoke(MetadataModuleAuthorTextBox, () => MetadataModuleAuthorTextBox.Text = gui_module.Authors);
Util.Invoke(MetadataModuleAbstractLabel, () => MetadataModuleAbstractLabel.Text = module.@abstract);
Util.Invoke(MetadataModuleDescriptionTextBox, () => MetadataModuleDescriptionTextBox.Text = module.description);
Util.Invoke(MetadataIdentifierTextBox, () => MetadataIdentifierTextBox.Text = module.identifier);
Util.Invoke(MetadataModuleAbstractLabel, () => MetadataModuleAbstractLabel.Text = gui_module.Abstract);
Util.Invoke(MetadataModuleDescriptionTextBox, () => MetadataModuleDescriptionTextBox.Text = gui_module.Description);
Util.Invoke(MetadataIdentifierTextBox, () => MetadataIdentifierTextBox.Text = gui_module.Identifier);

// If we have a homepage provided, use that; otherwise use the spacedock page, curse page or the github repo so that users have somewhere to get more info than just the abstract.
Util.Invoke(MetadataModuleHomePageLinkLabel, () => MetadataModuleHomePageLinkLabel.Text = gui_module.Homepage.ToString());
Expand Down
21 changes: 14 additions & 7 deletions GUI/MainModList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,7 @@ public async Task<IEnumerable<ModChange>> ComputeChangeSetFromModList(
public bool IsVisible(GUIMod mod)
{
var nameMatchesFilter = IsNameInNameFilter(mod);
var authorMatchesFilter = IsAuthorInauthorFilter(mod);
var authorMatchesFilter = IsAuthorInAuthorFilter(mod);
var abstractMatchesFilter = IsAbstractInDescriptionFilter(mod);
var modMatchesType = IsModInFilter(ModFilter, mod);
var isVisible = nameMatchesFilter && modMatchesType && authorMatchesFilter && abstractMatchesFilter;
Expand Down Expand Up @@ -934,19 +934,26 @@ public string StripEpoch(string version)

private bool IsNameInNameFilter(GUIMod mod)
{
return mod.Name.IndexOf(ModNameFilter, StringComparison.InvariantCultureIgnoreCase) != -1
|| mod.Abbrevation.IndexOf(ModNameFilter, StringComparison.InvariantCultureIgnoreCase) != -1
|| mod.Identifier.IndexOf(ModNameFilter, StringComparison.InvariantCultureIgnoreCase) != -1;
string sanitisedModNameFilter = CkanModule.nonAlphaNums.Replace(ModNameFilter, "");

return mod.Abbrevation.IndexOf(ModNameFilter, StringComparison.InvariantCultureIgnoreCase) != -1
|| mod.SearchableName.IndexOf(sanitisedModNameFilter, StringComparison.InvariantCultureIgnoreCase) != -1
|| mod.SearchableIdentifier.IndexOf(sanitisedModNameFilter, StringComparison.InvariantCultureIgnoreCase) != -1;
}

private bool IsAuthorInauthorFilter(GUIMod mod)
private bool IsAuthorInAuthorFilter(GUIMod mod)
{
return mod.Authors.IndexOf(ModAuthorFilter, StringComparison.InvariantCultureIgnoreCase) != -1;
string sanitisedModAuthorFilter = CkanModule.nonAlphaNums.Replace(ModAuthorFilter, "");

return mod.SearchableAuthors.IndexOf(sanitisedModAuthorFilter, StringComparison.InvariantCultureIgnoreCase) != -1;
}

private bool IsAbstractInDescriptionFilter(GUIMod mod)
{
return mod.Abstract.IndexOf(ModDescriptionFilter, StringComparison.InvariantCultureIgnoreCase) != -1;
string sanitisedModDescriptionFilter = CkanModule.nonAlphaNums.Replace(ModDescriptionFilter, "");

return mod.SearchableAbstract.IndexOf(sanitisedModDescriptionFilter, StringComparison.InvariantCultureIgnoreCase) != -1
|| mod.SearchableDescription.IndexOf(sanitisedModDescriptionFilter, StringComparison.InvariantCultureIgnoreCase) != -1;
}

private static bool IsModInFilter(GUIModFilter filter, GUIMod m)
Expand Down
2 changes: 1 addition & 1 deletion GUI/SelectionDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace CKAN
{
public partial class SelectionDialog : FormCompatibility
public partial class SelectionDialog : Form
{
int currentSelected;

Expand Down

0 comments on commit 54d003a

Please sign in to comment.