diff --git a/ConsoleUI/DependencyScreen.cs b/ConsoleUI/DependencyScreen.cs
index b252230da5..254e45b435 100644
--- a/ConsoleUI/DependencyScreen.cs
+++ b/ConsoleUI/DependencyScreen.cs
@@ -16,8 +16,10 @@ public class DependencyScreen : ConsoleScreen {
/// KSP manager containing instances
/// Plan of mods to add and remove
/// Mods that the user saw and did not select, in this pass or a previous pass
- public DependencyScreen(KSPManager mgr, ChangePlan cp, HashSet rej) : base()
+ /// True if debug options should be available, false otherwise
+ public DependencyScreen(KSPManager mgr, ChangePlan cp, HashSet rej, bool dbg) : base()
{
+ debug = dbg;
manager = mgr;
plan = cp;
registry = RegistryManager.Instance(manager.CurrentInstance).registry;
@@ -79,7 +81,8 @@ public DependencyScreen(KSPManager mgr, ChangePlan cp, HashSet rej) : ba
if (dependencyList.Selection != null) {
LaunchSubScreen(new ModInfoScreen(
manager, plan,
- registry.LatestAvailable(dependencyList.Selection.identifier, manager.CurrentInstance.VersionCriteria())
+ registry.LatestAvailable(dependencyList.Selection.identifier, manager.CurrentInstance.VersionCriteria()),
+ debug
));
}
return true;
@@ -207,6 +210,7 @@ private string StatusSymbol(string identifier)
private IRegistryQuerier registry;
private KSPManager manager;
private ChangePlan plan;
+ private bool debug;
private Dictionary dependencies = new Dictionary();
private ConsoleListBox dependencyList;
diff --git a/ConsoleUI/InstallScreen.cs b/ConsoleUI/InstallScreen.cs
index ea87efb2c0..042af1b347 100644
--- a/ConsoleUI/InstallScreen.cs
+++ b/ConsoleUI/InstallScreen.cs
@@ -15,12 +15,14 @@ public class InstallScreen : ProgressScreen {
///
/// KSP manager containing instances
/// Plan of mods to install or remove
- public InstallScreen(KSPManager mgr, ChangePlan cp)
+ /// True if debug options should be available, false otherwise
+ public InstallScreen(KSPManager mgr, ChangePlan cp, bool dbg)
: base(
"Installing, Updating, and Removing Mods",
"Calculating..."
)
{
+ debug = dbg;
manager = mgr;
plan = cp;
}
@@ -45,7 +47,7 @@ public override void Run(Action process = null)
// CmdLine assumes recs and ignores sugs
if (plan.Install.Count > 0) {
// Track previously rejected optional dependencies and don't prompt for them again.
- DependencyScreen ds = new DependencyScreen(manager, plan, rejected);
+ DependencyScreen ds = new DependencyScreen(manager, plan, rejected, debug);
if (ds.HaveOptions()) {
LaunchSubScreen(ds);
}
@@ -142,6 +144,7 @@ private void OnModInstalled(CkanModule mod)
private KSPManager manager;
private ChangePlan plan;
+ private bool debug;
}
}
diff --git a/ConsoleUI/ModInfoScreen.cs b/ConsoleUI/ModInfoScreen.cs
index 4cbb889a48..964619b22a 100644
--- a/ConsoleUI/ModInfoScreen.cs
+++ b/ConsoleUI/ModInfoScreen.cs
@@ -18,8 +18,10 @@ public class ModInfoScreen : ConsoleScreen {
/// KSP manager containing game instances
/// Plan of other mods to be added or removed
/// The module to display
- public ModInfoScreen(KSPManager mgr, ChangePlan cp, CkanModule m)
+ /// True if debug options should be available, false otherwise
+ public ModInfoScreen(KSPManager mgr, ChangePlan cp, CkanModule m, bool dbg)
{
+ debug = dbg;
mod = m;
manager = mgr;
plan = cp;
@@ -145,6 +147,14 @@ public ModInfoScreen(KSPManager mgr, ChangePlan cp, CkanModule m)
() => LaunchURL(mod.resources.curse)
));
}
+ if (debug) {
+ opts.Add(null);
+ opts.Add(new ConsoleMenuOption(
+ "DEBUG: View metadata", "", "Display the full registry data for this mod",
+ true,
+ ViewMetadata
+ ));
+ }
if (opts.Count > 0) {
mainMenu = new ConsolePopupMenu(opts);
@@ -155,6 +165,19 @@ public ModInfoScreen(KSPManager mgr, ChangePlan cp, CkanModule m)
CenterHeader = () => "Mod Details";
}
+ private bool ViewMetadata()
+ {
+ ConsoleMessageDialog md = new ConsoleMessageDialog(
+ $"\"{mod.identifier}\": {registry.GetAvailableMetadata(mod.identifier)}",
+ new List {"OK"},
+ () => $"{mod.name} Metadata",
+ TextAlign.Left
+ );
+ md.Run();
+ DrawBackground();
+ return true;
+ }
+
private bool LaunchURL(Uri u)
{
// I'm getting error output on Linux, because this runs xdg-open which
@@ -491,6 +514,7 @@ private void Download()
private IRegistryQuerier registry;
private ChangePlan plan;
private CkanModule mod;
+ private bool debug;
}
}
diff --git a/ConsoleUI/ModListScreen.cs b/ConsoleUI/ModListScreen.cs
index 5e2d1cebb8..dab595216c 100644
--- a/ConsoleUI/ModListScreen.cs
+++ b/ConsoleUI/ModListScreen.cs
@@ -156,7 +156,7 @@ public ModListScreen(KSPManager mgr, bool dbg)
);
moduleList.AddBinding(Keys.Enter, (object sender) => {
if (moduleList.Selection != null) {
- LaunchSubScreen(new ModInfoScreen(manager, plan, moduleList.Selection));
+ LaunchSubScreen(new ModInfoScreen(manager, plan, moduleList.Selection, debug));
}
return true;
});
@@ -329,7 +329,7 @@ private bool ViewSuggestions()
}
}
try {
- DependencyScreen ds = new DependencyScreen(manager, reinstall, new HashSet());
+ DependencyScreen ds = new DependencyScreen(manager, reinstall, new HashSet(), debug);
if (ds.HaveOptions()) {
LaunchSubScreen(ds);
bool needRefresh = false;
@@ -484,7 +484,7 @@ private bool Help()
private bool ApplyChanges()
{
- LaunchSubScreen(new InstallScreen(manager, plan));
+ LaunchSubScreen(new InstallScreen(manager, plan, debug));
RefreshList();
return true;
}
diff --git a/ConsoleUI/ProgressScreen.cs b/ConsoleUI/ProgressScreen.cs
index b88dd4abd7..2fa3e09572 100644
--- a/ConsoleUI/ProgressScreen.cs
+++ b/ConsoleUI/ProgressScreen.cs
@@ -59,6 +59,8 @@ public override bool RaiseYesNoDialog(string question)
// The installer's questions include embedded newlines for spacing in CmdLine
question.Trim(),
new List() {"Yes", "No"},
+ null,
+ TextAlign.Center,
-Console.WindowHeight / 2
);
d.AddBinding(Keys.Y, (object sender) => {
@@ -71,27 +73,37 @@ public override bool RaiseYesNoDialog(string question)
});
// Scroll messages
- d.AddTip("Home / End / Page Up / Page Down", "Scroll messages");
- d.AddBinding(Keys.Home, (object sender) => {
+ d.AddTip("Cursor keys", "Scroll messages");
+ d.AddBinding(Keys.Home, (object sender) => {
messages.ScrollToTop();
messages.Draw(false);
return true;
});
- d.AddBinding(Keys.End, (object sender) => {
+ d.AddBinding(Keys.End, (object sender) => {
messages.ScrollToBottom();
messages.Draw(false);
return true;
});
- d.AddBinding(Keys.PageUp, (object sender) => {
+ d.AddBinding(Keys.PageUp, (object sender) => {
messages.ScrollUp();
messages.Draw(false);
return true;
});
- d.AddBinding(Keys.PageDown, (object sender) => {
+ d.AddBinding(Keys.PageDown, (object sender) => {
messages.ScrollDown();
messages.Draw(false);
return true;
});
+ d.AddBinding(Keys.UpArrow, (object sender) => {
+ messages.ScrollUp(1);
+ messages.Draw(false);
+ return true;
+ });
+ d.AddBinding(Keys.DownArrow, (object sender) => {
+ messages.ScrollDown(1);
+ messages.Draw(false);
+ return true;
+ });
bool val = d.Run() == 0;
DrawBackground();
diff --git a/ConsoleUI/Toolkit/ConsoleMessageDialog.cs b/ConsoleUI/Toolkit/ConsoleMessageDialog.cs
index 9d93ed0ea1..751474a609 100644
--- a/ConsoleUI/Toolkit/ConsoleMessageDialog.cs
+++ b/ConsoleUI/Toolkit/ConsoleMessageDialog.cs
@@ -13,13 +13,20 @@ public class ConsoleMessageDialog : ConsoleDialog {
///
/// Message to show
/// List of captions for buttons
+ /// Function to generate the header
+ /// Alignment of the contents
/// Pass non-zero to move popup vertically
- public ConsoleMessageDialog(string m, List btns, int vertOffset = 0)
+ public ConsoleMessageDialog(string m, List btns, Func hdr = null, TextAlign ta = TextAlign.Center, int vertOffset = 0)
: base()
{
- int l = GetLeft(),
- r = GetRight();
- int w = Console.WindowWidth / 2;
+ int maxLen = Formatting.MaxLineLength(m);
+ int w = Math.Min(maxLen + 6, Console.WindowWidth - 4);
+ int l = (Console.WindowWidth - w) / 2;
+ int r = -l;
+ if (hdr != null) {
+ CenterHeader = hdr;
+ }
+
int btnW = btns.Count * buttonWidth + (btns.Count - 1) * buttonPadding;
if (w < btnW + 4) {
// Widen the window to fit the buttons
@@ -32,6 +39,9 @@ public ConsoleMessageDialog(string m, List btns, int vertOffset = 0)
List messageLines = Formatting.WordWrap(m, w - 4);
int h = 2 + messageLines.Count + (btns.Count > 0 ? 2 : 0) + 2;
+ if (h > Console.WindowHeight - 4) {
+ h = Console.WindowHeight - 4;
+ }
// Calculate vertical position including offset
int t, b;
@@ -55,13 +65,43 @@ public ConsoleMessageDialog(string m, List btns, int vertOffset = 0)
ConsoleTextBox tb = new ConsoleTextBox(
GetLeft() + 2, GetTop() + 2, GetRight() - 2, GetBottom() - 2 - (btns.Count > 0 ? 2 : 0),
false,
- TextAlign.Center,
+ ta,
() => ConsoleTheme.Current.PopupBg,
() => ConsoleTheme.Current.PopupFg
);
AddObject(tb);
tb.AddLine(m);
+ int boxH = GetBottom() - 2 - (btns.Count > 0 ? 2 : 0) - (GetTop() + 2) + 1;
+
+ if (messageLines.Count > boxH) {
+ // Scroll
+ AddBinding(Keys.Home, (object sender) => {
+ tb.ScrollToTop();
+ return true;
+ });
+ AddBinding(Keys.End, (object sender) => {
+ tb.ScrollToBottom();
+ return true;
+ });
+ AddBinding(Keys.PageUp, (object sender) => {
+ tb.ScrollUp();
+ return true;
+ });
+ AddBinding(Keys.PageDown, (object sender) => {
+ tb.ScrollDown();
+ return true;
+ });
+ AddBinding(Keys.UpArrow, (object sender) => {
+ tb.ScrollUp(1);
+ return true;
+ });
+ AddBinding(Keys.DownArrow, (object sender) => {
+ tb.ScrollDown(1);
+ return true;
+ });
+ }
+
int btnLeft = (Console.WindowWidth - btnW) / 2;
for (int i = 0; i < btns.Count; ++i) {
string cap = btns[i];
diff --git a/ConsoleUI/Toolkit/ConsoleTextBox.cs b/ConsoleUI/Toolkit/ConsoleTextBox.cs
index fbc2cef23d..10b86dd581 100644
--- a/ConsoleUI/Toolkit/ConsoleTextBox.cs
+++ b/ConsoleUI/Toolkit/ConsoleTextBox.cs
@@ -67,10 +67,9 @@ public void ScrollToBottom()
///
/// Scroll the text box up one page
///
- public void ScrollUp()
+ public void ScrollUp(int? howFar = null)
{
- int h = GetBottom() - GetTop() + 1;
- topLine -= h;
+ topLine -= howFar ?? (GetBottom() - GetTop() + 1);
if (topLine < 0) {
topLine = 0;
}
@@ -79,11 +78,12 @@ public void ScrollUp()
///
/// Scroll the text box down one page
///
- public void ScrollDown()
+ public void ScrollDown(int? howFar = null)
{
- int h = GetBottom() - GetTop() + 1;
- if (topLine + h <= lines.Count - h) {
- topLine += h;
+ int h = GetBottom() - GetTop() + 1;
+ int diff = howFar ?? h;
+ if (topLine + diff <= lines.Count - h) {
+ topLine += diff;
} else {
ScrollToBottom();
}
diff --git a/ConsoleUI/Toolkit/Formatting.cs b/ConsoleUI/Toolkit/Formatting.cs
index a09a467f0e..6b891836b7 100644
--- a/ConsoleUI/Toolkit/Formatting.cs
+++ b/ConsoleUI/Toolkit/Formatting.cs
@@ -28,6 +28,25 @@ public static int ConvertCoord(int val, int max)
}
}
+ ///
+ /// Calculate the longest line length in a string when split on newlines
+ ///
+ /// String to analyze
+ ///
+ /// Length of longest line
+ ///
+ public static int MaxLineLength(string msg)
+ {
+ int len = 0;
+ string[] hardLines = msg.Split(new string[] {"\r\n", "\n"}, StringSplitOptions.None);
+ foreach (string line in hardLines) {
+ if (len < line.Length) {
+ len = line.Length;
+ }
+ }
+ return len;
+ }
+
///
/// Word wrap a long string into separate lines
///
@@ -42,9 +61,11 @@ public static List WordWrap(string msg, int w)
if (!string.IsNullOrEmpty(msg)) {
// The string is allowed to contain line breaks.
string[] hardLines = msg.Split(new string[] {"\r\n", "\n"}, StringSplitOptions.None);
- foreach (var line in hardLines) {
+ foreach (string line in hardLines) {
if (string.IsNullOrEmpty(line)) {
messageLines.Add("");
+ } else if (line.Length <= w) {
+ messageLines.Add(line);
} else {
int used = 0;
while (used < line.Length) {
diff --git a/ConsoleUI/Toolkit/ScreenContainer.cs b/ConsoleUI/Toolkit/ScreenContainer.cs
index 7a1494775f..d7773ca41d 100644
--- a/ConsoleUI/Toolkit/ScreenContainer.cs
+++ b/ConsoleUI/Toolkit/ScreenContainer.cs
@@ -67,7 +67,11 @@ protected void AddObject(ScreenObject so)
/// Action to bind to the key
public void AddBinding(ConsoleKeyInfo k, KeyAction a)
{
- bindings.Add(k, a);
+ if (bindings.ContainsKey(k)) {
+ bindings[k] = a;
+ } else {
+ bindings.Add(k, a);
+ }
}
///
diff --git a/Core/Registry/AvailableModule.cs b/Core/Registry/AvailableModule.cs
index d84ec4b9b0..3db3d2c350 100644
--- a/Core/Registry/AvailableModule.cs
+++ b/Core/Registry/AvailableModule.cs
@@ -1,4 +1,6 @@
using System;
+using System.IO;
+using System.Text;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@@ -162,6 +164,26 @@ public List AllAvailable()
return new List(module_version.Values.Reverse());
}
+ ///
+ /// Return the entire section of registry.json for this mod
+ ///
+ ///
+ /// Nicely formatted JSON string containing metadata for all of this mod's available versions
+ ///
+ public string FullMetadata()
+ {
+ StringWriter sw = new StringWriter(new StringBuilder());
+ using (JsonTextWriter writer = new JsonTextWriter(sw) {
+ Formatting = Formatting.Indented,
+ Indentation = 4,
+ IndentChar = ' '
+ })
+ {
+ new JsonSerializer().Serialize(writer, this);
+ }
+ return sw.ToString();
+ }
+
}
}
diff --git a/Core/Registry/IRegistryQuerier.cs b/Core/Registry/IRegistryQuerier.cs
index 35331bc6d4..6dcd18fa7c 100644
--- a/Core/Registry/IRegistryQuerier.cs
+++ b/Core/Registry/IRegistryQuerier.cs
@@ -18,6 +18,15 @@ public interface IRegistryQuerier
// TODO: This name is misleading. It's more a LatestAvailable's'
List Available(KspVersionCriteria ksp_version);
+ ///
+ /// Get full JSON metadata string for a mod's available versions
+ ///
+ /// Name of the mod to look up
+ ///
+ /// JSON formatted string for all the available versions of the mod
+ ///
+ string GetAvailableMetadata(string identifier);
+
///
/// Returns the latest available version of a module that
/// satisifes the specified version.
diff --git a/Core/Registry/Registry.cs b/Core/Registry/Registry.cs
index c860b2ef8e..d7632a1636 100644
--- a/Core/Registry/Registry.cs
+++ b/Core/Registry/Registry.cs
@@ -523,6 +523,25 @@ public List AllAvailable(string module)
}
}
+ ///
+ /// Get full JSON metadata string for a mod's available versions
+ ///
+ /// Name of the mod to look up
+ ///
+ /// JSON formatted string for all the available versions of the mod
+ ///
+ public string GetAvailableMetadata(string identifier)
+ {
+ try
+ {
+ return available_modules[identifier].FullMetadata();
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
///
/// Return the latest game version compatible with the given mod.
///
diff --git a/Core/Registry/RegistryManager.cs b/Core/Registry/RegistryManager.cs
index 778e574b3c..b8a86130fc 100644
--- a/Core/Registry/RegistryManager.cs
+++ b/Core/Registry/RegistryManager.cs
@@ -256,18 +256,6 @@ public static void DisposeAll()
}
}
- ///
- /// Call Dispose on all the registry managers in the cache.
- /// Useful for exiting without Dispose-related exceptions.
- ///
- public static void DisposeAll()
- {
- foreach (RegistryManager rm in new List(registryCache.Values))
- {
- rm.Dispose();
- }
- }
-
///
/// Returns the currently installed modules in json format suitable for outputting to a ckan file.
/// Defaults to using depends and with version numbers.