mirror of
https://github.com/openbullet/openbullet.git
synced 2023-10-21 07:33:42 -05:00
Expanded and improved File and Folder sections in Utility Block
This commit is contained in:
@@ -183,12 +183,24 @@
|
||||
<Label Content="Path:" DockPanel.Dock="Left"/>
|
||||
<TextBox Text="{Binding FilePath, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</DockPanel>
|
||||
<Label Foreground="{DynamicResource ForegroundCustom}" Content="Path can be relative or absolute" />
|
||||
<DockPanel>
|
||||
<Label Content="Input String:" DockPanel.Dock="Left" />
|
||||
<TextBox Text="{Binding InputString, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</DockPanel>
|
||||
<Label Foreground="{DynamicResource ForegroundCustom}" Content="Newline escape sequences will be evaluated. "Lines" accept LIST[*]." />
|
||||
<Label Foreground="{DynamicResource ForegroundCustom}" Content="On Copy and Move, Input String needs to be the destination file path." />
|
||||
</StackPanel>
|
||||
</TabItem>
|
||||
<TabItem x:Name="folderTab">
|
||||
<StackPanel>
|
||||
<DockPanel>
|
||||
<Label Content="Action:" DockPanel.Dock="Left" />
|
||||
<ComboBox x:Name="folderActionCombobox" SelectionChanged="folderActionCombobox_SelectionChanged" />
|
||||
</DockPanel>
|
||||
<DockPanel>
|
||||
<Label Content="Path:" DockPanel.Dock="Left"/>
|
||||
<TextBox Text="{Binding FolderPath, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
@@ -49,6 +49,11 @@ namespace OpenBullet.Views.StackerBlocks
|
||||
|
||||
fileActionCombobox.SelectedIndex = (int)block.FileAction;
|
||||
|
||||
foreach (var a in Enum.GetNames(typeof(FolderAction)))
|
||||
folderActionCombobox.Items.Add(a);
|
||||
|
||||
folderActionCombobox.SelectedIndex = (int)block.FolderAction;
|
||||
|
||||
foreach (var c in Enum.GetNames(typeof(Comparer)))
|
||||
removeComparerCombobox.Items.Add(c);
|
||||
|
||||
@@ -80,6 +85,10 @@ namespace OpenBullet.Views.StackerBlocks
|
||||
case UtilityGroup.File:
|
||||
groupTabControl.SelectedIndex = 4;
|
||||
break;
|
||||
|
||||
case UtilityGroup.Folder:
|
||||
groupTabControl.SelectedIndex = 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,6 +148,11 @@ namespace OpenBullet.Views.StackerBlocks
|
||||
block.FileAction = (FileAction)((ComboBox)e.OriginalSource).SelectedIndex;
|
||||
}
|
||||
|
||||
private void folderActionCombobox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
block.FolderAction = (FolderAction)((ComboBox)e.OriginalSource).SelectedIndex;
|
||||
}
|
||||
|
||||
private void removeComparerCombobox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
block.ListElementComparer = (Comparer)((ComboBox)e.OriginalSource).SelectedIndex;
|
||||
|
||||
@@ -28,7 +28,10 @@ namespace RuriLib
|
||||
Conversion,
|
||||
|
||||
/// <summary>The group of actions that interact with files.</summary>
|
||||
File
|
||||
File,
|
||||
|
||||
/// <summary>The group of actions that interact with folders.</summary>
|
||||
Folder
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -90,6 +93,9 @@ namespace RuriLib
|
||||
/// </summary>
|
||||
public enum FileAction
|
||||
{
|
||||
/// <summary>Checks if a file exists.</summary>
|
||||
Exists,
|
||||
|
||||
/// <summary>Reads a file to a single variable.</summary>
|
||||
Read,
|
||||
|
||||
@@ -106,7 +112,25 @@ namespace RuriLib
|
||||
Append,
|
||||
|
||||
/// <summary>Appends a list variable to a file.</summary>
|
||||
AppendLines
|
||||
AppendLines,
|
||||
|
||||
/// <summary>Copies a file to a new file.</summary>
|
||||
Copy,
|
||||
|
||||
/// <summary>Moves a file to a different location.</summary>
|
||||
Move
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Actions that can be performed on folders.
|
||||
/// </summary>
|
||||
public enum FolderAction
|
||||
{
|
||||
/// <summary>Checks if a folder exists.</summary>
|
||||
Exists,
|
||||
|
||||
/// <summary>Creates a folder.</summary>
|
||||
Create
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -200,13 +224,22 @@ namespace RuriLib
|
||||
|
||||
// Files
|
||||
private string filePath = "test.txt";
|
||||
/// <summary>The path to the file to read/write.</summary>
|
||||
/// <summary>The path to the file to interact with.</summary>
|
||||
public string FilePath { get { return filePath; } set { filePath = value; OnPropertyChanged(); } }
|
||||
|
||||
private FileAction fileAction = FileAction.Read;
|
||||
/// <summary>The action to be performed on the file.</summary>
|
||||
public FileAction FileAction { get { return fileAction; } set { fileAction = value; OnPropertyChanged(); } }
|
||||
|
||||
// Folders
|
||||
private string folderPath = "TestFolder";
|
||||
/// <summary>The path to the folder to interact with.</summary>
|
||||
public string FolderPath { get { return folderPath; } set { folderPath = value; OnPropertyChanged(); } }
|
||||
|
||||
private FolderAction folderAction = FolderAction.Create;
|
||||
/// <summary>The action to be performed on the folder.</summary>
|
||||
public FolderAction FolderAction { get { return folderAction; } set { folderAction = value; OnPropertyChanged(); } }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Utility block.
|
||||
/// </summary>
|
||||
@@ -297,10 +330,17 @@ namespace RuriLib
|
||||
case FileAction.WriteLines:
|
||||
case FileAction.Append:
|
||||
case FileAction.AppendLines:
|
||||
case FileAction.Copy:
|
||||
case FileAction.Move:
|
||||
InputString = LineParser.ParseLiteral(ref input, "Input String");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case UtilityGroup.Folder:
|
||||
FolderPath = LineParser.ParseLiteral(ref input, "Folder Name");
|
||||
FolderAction = (FolderAction)LineParser.ParseEnum(ref input, "Folder Action", typeof(FolderAction));
|
||||
break;
|
||||
}
|
||||
|
||||
// Try to parse the arrow, otherwise just return the block as is with default var name and var / cap choice
|
||||
@@ -410,11 +450,19 @@ namespace RuriLib
|
||||
case FileAction.WriteLines:
|
||||
case FileAction.Append:
|
||||
case FileAction.AppendLines:
|
||||
case FileAction.Copy:
|
||||
case FileAction.Move:
|
||||
writer
|
||||
.Literal(InputString);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case UtilityGroup.Folder:
|
||||
writer
|
||||
.Literal(FolderPath)
|
||||
.Token(FolderAction);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!writer.CheckDefault(VariableName, "VariableName"))
|
||||
@@ -556,8 +604,14 @@ namespace RuriLib
|
||||
|
||||
case UtilityGroup.File:
|
||||
var file = ReplaceValues(filePath, data);
|
||||
ThrowIfNotInCWD(file);
|
||||
|
||||
switch (fileAction)
|
||||
{
|
||||
case FileAction.Exists:
|
||||
data.Variables.Set(new CVar(variableName, File.Exists(file).ToString(), isCapture));
|
||||
break;
|
||||
|
||||
case FileAction.Read:
|
||||
data.Variables.Set(new CVar(variableName, File.ReadAllText(file), isCapture));
|
||||
break;
|
||||
@@ -567,10 +621,12 @@ namespace RuriLib
|
||||
break;
|
||||
|
||||
case FileAction.Write:
|
||||
CreatePath(file);
|
||||
File.WriteAllText(file, replacedInput.Unescape());
|
||||
break;
|
||||
|
||||
case FileAction.WriteLines:
|
||||
CreatePath(file);
|
||||
File.WriteAllLines(file, ReplaceValuesRecursive(inputString, data).Select(i => i.Unescape()));
|
||||
break;
|
||||
|
||||
@@ -581,15 +637,62 @@ namespace RuriLib
|
||||
case FileAction.AppendLines:
|
||||
File.AppendAllLines(file, ReplaceValuesRecursive(inputString, data).Select(i => i.Unescape()));
|
||||
break;
|
||||
|
||||
case FileAction.Copy:
|
||||
var fileCopyLocation = ReplaceValues(inputString, data);
|
||||
ThrowIfNotInCWD(fileCopyLocation);
|
||||
CreatePath(fileCopyLocation);
|
||||
File.Copy(file, fileCopyLocation);
|
||||
break;
|
||||
|
||||
case FileAction.Move:
|
||||
var fileMoveLocation = ReplaceValues(inputString, data);
|
||||
ThrowIfNotInCWD(fileMoveLocation);
|
||||
CreatePath(fileMoveLocation);
|
||||
File.Move(file, fileMoveLocation);
|
||||
break;
|
||||
}
|
||||
data.Log(new LogEntry($"Executed action {fileAction} on file {file}", isCapture ? Colors.Tomato : Colors.Yellow));
|
||||
break;
|
||||
|
||||
case UtilityGroup.Folder:
|
||||
var folder = ReplaceValues(folderPath, data);
|
||||
ThrowIfNotInCWD(folder);
|
||||
|
||||
switch (folderAction)
|
||||
{
|
||||
case FolderAction.Exists:
|
||||
data.Variables.Set(new CVar(variableName, Directory.Exists(folder).ToString(), isCapture));
|
||||
break;
|
||||
|
||||
case FolderAction.Create:
|
||||
data.Variables.Set(new CVar(variableName, Directory.CreateDirectory(folder).ToString(), isCapture));
|
||||
break;
|
||||
}
|
||||
data.Log(new LogEntry($"Executed action {folderAction} on folder {folder}", isCapture ? Colors.Tomato : Colors.Yellow));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch(Exception ex) { data.Log(new LogEntry(ex.Message, Colors.Tomato)); }
|
||||
}
|
||||
|
||||
private void ThrowIfNotInCWD(string path)
|
||||
{
|
||||
if (!path.IsSubPathOf(Directory.GetCurrentDirectory()))
|
||||
{
|
||||
throw new UnauthorizedAccessException("For security reasons, you cannot interact with paths outside of the current working directory");
|
||||
}
|
||||
}
|
||||
|
||||
private void CreatePath(string file)
|
||||
{
|
||||
if (!Directory.Exists(Path.GetDirectoryName(file)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -56,5 +57,64 @@ namespace RuriLib
|
||||
.Replace(@"\\t", @"\t")
|
||||
.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if <paramref name="path"/> starts with the path <paramref name="baseDirPath"/>.
|
||||
/// The comparison is case-insensitive, handles / and \ slashes as folder separators and
|
||||
/// only matches if the base dir folder name is matched exactly ("c:\foobar\file.txt" is not a sub path of "c:\foo").
|
||||
/// </summary>
|
||||
public static bool IsSubPathOf(this string path, string baseDirPath)
|
||||
{
|
||||
string normalizedPath = Path.GetFullPath(path.Replace('/', '\\')
|
||||
.WithEnding("\\"));
|
||||
|
||||
string normalizedBaseDirPath = Path.GetFullPath(baseDirPath.Replace('/', '\\')
|
||||
.WithEnding("\\"));
|
||||
|
||||
return normalizedPath.StartsWith(normalizedBaseDirPath, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <paramref name="str"/> with the minimal concatenation of <paramref name="ending"/> (starting from end) that
|
||||
/// results in satisfying .EndsWith(ending).
|
||||
/// </summary>
|
||||
/// <example>"hel".WithEnding("llo") returns "hello", which is the result of "hel" + "lo".</example>
|
||||
public static string WithEnding(this string str, string ending)
|
||||
{
|
||||
if (str == null)
|
||||
return ending;
|
||||
|
||||
string result = str;
|
||||
|
||||
// Right() is 1-indexed, so include these cases
|
||||
// * Append no characters
|
||||
// * Append up to N characters, where N is ending length
|
||||
for (int i = 0; i <= ending.Length; i++)
|
||||
{
|
||||
string tmp = result + ending.Right(i);
|
||||
if (tmp.EndsWith(ending))
|
||||
return tmp;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>Gets the rightmost <paramref name="length" /> characters from a string.</summary>
|
||||
/// <param name="value">The string to retrieve the substring from. Must not be null.</param>
|
||||
/// <param name="length">The number of characters to retrieve.</param>
|
||||
/// <returns>The substring.</returns>
|
||||
public static string Right(this string value, int length)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
if (length < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("length", length, "Length is less than zero");
|
||||
}
|
||||
|
||||
return (length < value.Length) ? value.Substring(value.Length - length) : value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user