Skip to content

Commit

Permalink
feat(Studio): Respect StyleConfig preferences in Project File Formatter
Browse files Browse the repository at this point in the history
  • Loading branch information
psyGamer committed Dec 27, 2024
1 parent 4a90619 commit 1525e99
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 7 deletions.
2 changes: 1 addition & 1 deletion Studio/CelesteStudio/Editing/Editor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,7 @@ private void FormatLines(IEnumerable<int> rows) {
} else if (CommandLine.TryParse(line, out var commandLine)) {
string commandName;
if (StyleConfig.Current.ForceCorrectCommandCasing &&
CommunicationWrapper.Commands.FirstOrDefault(cmd => string.Equals(cmd.Name, commandLine.Command, StringComparison.OrdinalIgnoreCase)) is { } command && !string.IsNullOrEmpty(command.Name))
CommunicationWrapper.Commands.FirstOrDefault(cmd => string.Equals(cmd.Name, commandLine.Command, StringComparison.OrdinalIgnoreCase)) is var command && !string.IsNullOrEmpty(command.Name))
{
commandName = command.Name;
} else {
Expand Down
102 changes: 96 additions & 6 deletions Studio/CelesteStudio/Tool/ProjectFileFormatter.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using CelesteStudio.Communication;
using CelesteStudio.Editing;
using CelesteStudio.Util;
using Eto.Drawing;
using Eto.Forms;
using StudioCommunication;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace CelesteStudio.Tool;
Expand All @@ -16,9 +19,14 @@ public class ProjectFileFormatterDialog : Eto.Forms.Dialog {
private string projectRoot;

private readonly CheckBox editRoomIndices;
private readonly CheckBox editCommands;

private readonly NumericStepper startingIndex;
private readonly DropDown roomIndexType;

private readonly CheckBox forceCorrectCasing;
private readonly TextBox argumentSeparator;

private ProjectFileFormatterDialog() {
Title = $"Project File Formatter v{Version}";
Icon = Assets.AppIcon;
Expand Down Expand Up @@ -55,16 +63,21 @@ private ProjectFileFormatterDialog() {

// Auto-room-indexing
editRoomIndices = new CheckBox { Width = rowWidth, Checked = true };
startingIndex = new NumericStepper { MinValue = 0, DecimalPlaces = 0, Width = rowWidth };
startingIndex = new NumericStepper { MinValue = 0, DecimalPlaces = 0, Width = rowWidth, Value = StyleConfig.Current.RoomLabelStartingIndex ?? 0 };
roomIndexType = new DropDown {
Items = {
new ListItem { Text = "Only current File", Key = nameof(AutoRoomIndexing.CurrentFile) },
new ListItem { Text = "Including Read-commands", Key = nameof(AutoRoomIndexing.IncludeReads) },
},
SelectedKey = nameof(AutoRoomIndexing.CurrentFile),
SelectedKey = StyleConfig.Current.RoomLabelIndexing?.ToString() ?? nameof(AutoRoomIndexing.CurrentFile),
Width = rowWidth
};

// Command formatting
editCommands = new CheckBox { Width = rowWidth, Checked = true };
forceCorrectCasing = new CheckBox { Width = rowWidth, Checked = true };
argumentSeparator = new TextBox { Width = rowWidth, Text = StyleConfig.Current.CommandArgumentSeparator ?? ", " };

var autoRoomIndexingLayout = new DynamicLayout { DefaultSpacing = new Size(10, 10) };
{
autoRoomIndexingLayout.BeginVertical();
Expand All @@ -78,6 +91,19 @@ private ProjectFileFormatterDialog() {
autoRoomIndexingLayout.AddCentered(new Label { Text = "Room Indexing Type" });
autoRoomIndexingLayout.Add(roomIndexType);
}
var commandLayout = new DynamicLayout { DefaultSpacing = new Size(10, 10) };
{
commandLayout.BeginVertical();
commandLayout.BeginHorizontal();

commandLayout.AddCentered(new Label { Text = "Force Correct Casing" });
commandLayout.Add(forceCorrectCasing);

commandLayout.EndBeginHorizontal();

commandLayout.AddCentered(new Label { Text = "Argument Separator" });
commandLayout.Add(argumentSeparator);
}

DefaultButton = new Button((_, _) => Format()) { Text = "&Format" };
AbortButton = new Button((_, _) => Close()) { Text = "&Cancel" };
Expand All @@ -88,14 +114,15 @@ private ProjectFileFormatterDialog() {
Content = new StackLayout {
Padding = 10,
Spacing = 10,
HorizontalContentAlignment = HorizontalAlignment.Center,
HorizontalContentAlignment = HorizontalAlignment.Left,
Items = {
new StackLayout {
Spacing = 10,
Orientation = Orientation.Horizontal,
VerticalContentAlignment = VerticalAlignment.Center,
Items = { new Label { Text = "Select Project Root Folder" }, projectRootButton }
},

new StackLayout {
Spacing = 10,
Orientation = Orientation.Horizontal,
Expand All @@ -104,6 +131,14 @@ private ProjectFileFormatterDialog() {
},
// NOTE: The only reason Scrollables are used, is because they provide a border
new Scrollable { Content = autoRoomIndexingLayout, Padding = 5 }.FixBorder(),

new StackLayout {
Spacing = 10,
Orientation = Orientation.Horizontal,
VerticalContentAlignment = VerticalAlignment.Center,
Items = { new Label { Text = "Format Commands" }, editCommands }
},
new Scrollable { Content = commandLayout, Padding = 5 }.FixBorder(),
}
};
Resizable = false;
Expand All @@ -117,9 +152,14 @@ private void Format() {
string[] files = Directory.GetFiles(projectRoot, "*.tas", new EnumerationOptions { RecurseSubdirectories = true, AttributesToSkip = FileAttributes.Hidden });

bool formatRoomIndices = Application.Instance.Invoke(() => editRoomIndices.Checked == true);
bool formatCommands = Application.Instance.Invoke(() => editCommands.Checked == true);

bool includeReads = Application.Instance.Invoke(() => roomIndexType.SelectedKey == nameof(AutoRoomIndexing.IncludeReads));
int startIndex = (int)Application.Instance.Invoke(() => startingIndex.Value);

bool forceCase = Application.Instance.Invoke(() => forceCorrectCasing.Checked == true);
string separator = Application.Instance.Invoke(() => argumentSeparator.Text);

int totalTasks = 0, finishedTasks = 0;

Label progressLabel;
Expand Down Expand Up @@ -165,9 +205,11 @@ private void Format() {

try {
if (formatRoomIndices) {
//await Task.Delay((int)Random.Shared.NextInt64(5_000)).ConfigureAwait(false);
await UpdateRoomLabelIndices(file, startIndex, includeReads).ConfigureAwait(false);
}
if (formatCommands) {
await UpdateCommands(file, forceCase, separator).ConfigureAwait(false);
}

Console.WriteLine($"Successfully reformatted '{file}'");
} catch (Exception ex) {
Expand Down Expand Up @@ -221,11 +263,11 @@ private async Task UpdateRoomLabelIndices(string filePath, int startIndex, bool

string[]? lines = null;
if (filePath != editor.Document.FilePath) {
await Studio.Instance.Editor.RefactorSemaphore.WaitAsync().ConfigureAwait(false);
await editor.RefactorSemaphore.WaitAsync().ConfigureAwait(false);
if (!Editor.FileCache.TryGetValue(filePath, out lines)) {
Editor.FileCache[filePath] = lines = await File.ReadAllLinesAsync(filePath).ConfigureAwait(false);
}
Studio.Instance.Editor.RefactorSemaphore.Release();
editor.RefactorSemaphore.Release();
}

using var __ = editor.Document.Update(raiseEvents: false);
Expand Down Expand Up @@ -268,5 +310,53 @@ private async Task UpdateRoomLabelIndices(string filePath, int startIndex, bool
}
}

private async Task UpdateCommands(string filePath, bool forceCase, string separator) {
var editor = Studio.Instance.Editor;

if (filePath == editor.Document.FilePath) {
using var __ = editor.Document.Update(raiseEvents: false);

for (int row = 0; row < editor.Document.Lines.Count; row++) {
if (!CommandLine.TryParse(editor.Document.Lines[row], out var commandLine)) {
continue;
}

string commandName;
if (forceCase && CommunicationWrapper.Commands.FirstOrDefault(cmd => string.Equals(cmd.Name, commandLine.Command, StringComparison.OrdinalIgnoreCase)) is var command && !string.IsNullOrEmpty(command.Name)) {
commandName = command.Name;
} else {
commandName = commandLine.Command;
}

editor.Document.ReplaceLine(row, string.Join(separator, [commandName, ..commandLine.Arguments]));
}
} else {
await editor.RefactorSemaphore.WaitAsync().ConfigureAwait(false);
if (!Editor.FileCache.TryGetValue(filePath, out string[]? lines)) {
Editor.FileCache[filePath] = lines = await File.ReadAllLinesAsync(filePath).ConfigureAwait(false);
}
editor.RefactorSemaphore.Release();

for (int row = 0; row < lines.Length; row++) {
if (!CommandLine.TryParse(lines[row], out var commandLine)) {
continue;
}

string commandName;
if (forceCase && CommunicationWrapper.Commands.FirstOrDefault(cmd => string.Equals(cmd.Name, commandLine.Command, StringComparison.OrdinalIgnoreCase)) is var command && !string.IsNullOrEmpty(command.Name)) {
commandName = command.Name;
} else {
commandName = commandLine.Command;
}

lines[row] = string.Join(separator, [commandName, ..commandLine.Arguments]);
}

await editor.RefactorSemaphore.WaitAsync().ConfigureAwait(false);
await File.WriteAllTextAsync(filePath, Document.FormatLinesToText(lines)).ConfigureAwait(false);
editor.RefactorSemaphore.Release();
}
}

public static void Show() => new ProjectFileFormatterDialog().ShowModal();
}

0 comments on commit 1525e99

Please sign in to comment.