mirror of
https://github.com/tonytins/tomas.git
synced 2025-03-15 04:11:24 +00:00
Rewritten IProgram interface and CST to support arguments.
- With the help of ChatGPT, the IProgram interface has been rewritten to handle command line arguments. - Speaking of, the CST parser has been rewritten to finally support arguments with the help of ChatGPT too. - Separately from the ChatGPT changes, the Run method has been renamed to Entry. - Terminal's entry code is now top-level. See ChangeLog.md for more details.
This commit is contained in:
parent
5888771e20
commit
7c3230685b
29 changed files with 580 additions and 354 deletions
|
@ -1,6 +1,11 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
## v23.0
|
## 23.5
|
||||||
|
|
||||||
|
- With the help of ChatGPT, the ``IProgram`` interface has been rewritten to handle command line arguments. Being ChatGPT derived, it's still rough around the edges (not sure what to do with ``IArguments`` right now), but it's one hell of a jumping start!
|
||||||
|
- Speaking of, the CST parser has been rewritten to finally support arguments with the help of ChatGPT too. While I could have always looked at FreeSO's implantation for reference, that code is just awful. It will be ported back upstream ASAP!
|
||||||
|
|
||||||
|
## 23.0
|
||||||
|
|
||||||
- Split versioning systems between kernal and terminal
|
- Split versioning systems between kernal and terminal
|
||||||
- Calendar versioning, `YY.MINOR.MICRO`, for kernal
|
- Calendar versioning, `YY.MINOR.MICRO`, for kernal
|
||||||
|
@ -10,7 +15,7 @@
|
||||||
|
|
||||||
Due to the huge time skip and architectural changes, I've (retroactively) switched to calendar versioning with ``v0.1`` now known as ``v20.1`` as well.
|
Due to the huge time skip and architectural changes, I've (retroactively) switched to calendar versioning with ``v0.1`` now known as ``v20.1`` as well.
|
||||||
|
|
||||||
## v20.1
|
## 20.1
|
||||||
|
|
||||||
- Filesystem (based on the Cosmos Wiki [guide](https://csos-guide-to-cosmos.fandom.com/wiki/Getting_Started_-_Materials_and_Setting_Up))
|
- Filesystem (based on the Cosmos Wiki [guide](https://csos-guide-to-cosmos.fandom.com/wiki/Getting_Started_-_Materials_and_Setting_Up))
|
||||||
- Semantic versioning
|
- Semantic versioning
|
||||||
|
|
|
@ -18,9 +18,11 @@
|
||||||
|
|
||||||
TOMAS (**To**ny's **Ma**naged Operating **S**ystem) is a hobby operating system based on the [COSMOS](https://github.com/CosmosOS/Cosmos) framework that comes with a respective terminal emulator.
|
TOMAS (**To**ny's **Ma**naged Operating **S**ystem) is a hobby operating system based on the [COSMOS](https://github.com/CosmosOS/Cosmos) framework that comes with a respective terminal emulator.
|
||||||
|
|
||||||
## Requirements
|
## Fictional version
|
||||||
|
|
||||||
### Prerequisites
|
Within [Casey Universe](https://github.com/tonytins/cugame), TOMAS is an operating system that serves as Anthony's tool to explore the galaxy while working for the Akonos Corporation, a company that builds artificial worlds. He can hack into any system he pleases and uses that
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
- Windows 10 or later
|
- Windows 10 or later
|
||||||
- Visual Studio 2022
|
- Visual Studio 2022
|
||||||
|
|
|
@ -8,9 +8,15 @@ namespace Tomas.Core.Programs;
|
||||||
|
|
||||||
public class Clear : IProgram
|
public class Clear : IProgram
|
||||||
{
|
{
|
||||||
public bool Run(IShell shell)
|
public string Name { get; set; }
|
||||||
{
|
|
||||||
Console.Clear();
|
public string Description { get; set; }
|
||||||
return true;
|
|
||||||
}
|
public IEnumerable<IArguments> Arguments { get; set; }
|
||||||
|
|
||||||
|
public bool Entry(IShell shell, IEnumerable<KeyValuePair<string, object>> arguments)
|
||||||
|
{
|
||||||
|
Console.Clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -8,7 +8,13 @@ namespace Tomas.Core.Programs;
|
||||||
|
|
||||||
public class Commands : IProgram
|
public class Commands : IProgram
|
||||||
{
|
{
|
||||||
public bool Run(IShell shell)
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<IArguments> Arguments { get; set; }
|
||||||
|
|
||||||
|
public bool Entry(IShell shell, IEnumerable<KeyValuePair<string, object>> arguments)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Commands:");
|
Console.WriteLine($"Commands:");
|
||||||
var progs = shell.Programs;
|
var progs = shell.Programs;
|
||||||
|
|
|
@ -9,10 +9,10 @@ namespace Tomas.Core.Programs;
|
||||||
public class FenSay : IProgram
|
public class FenSay : IProgram
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fennec art by Todd Vargo
|
/// Fennec art by Todd Vargo
|
||||||
/// </summary>
|
/// </summary>
|
||||||
const string _fennec = @" \/
|
const string _fennec = @" \/
|
||||||
/\ /\
|
/\ /\
|
||||||
//\\_//\\ ____
|
//\\_//\\ ____
|
||||||
\_ _/ / /
|
\_ _/ / /
|
||||||
|
@ -23,19 +23,25 @@ public class FenSay : IProgram
|
||||||
[ [ / \/ _/
|
[ [ / \/ _/
|
||||||
_[ [ \ /_/";
|
_[ [ \ /_/";
|
||||||
|
|
||||||
readonly string[] _phrases =
|
readonly string[] _phrases =
|
||||||
{
|
{
|
||||||
"[SCREAMS IN FENNEC]",
|
"[SCREAMS IN FENNEC]",
|
||||||
"Some people call me a coffee fox.",
|
"Some people call me a coffee fox.",
|
||||||
"Drink Soda. It makes you see faster.",
|
"Drink Soda. It makes you see faster.",
|
||||||
"10/10, Wouldn't Recommend."
|
"10/10, Wouldn't Recommend."
|
||||||
};
|
};
|
||||||
|
|
||||||
public bool Run(IShell shell)
|
public string Name { get; set; }
|
||||||
{
|
|
||||||
var rng = new Random();
|
public string Description { get; set; }
|
||||||
var phrases = _phrases[rng.Next(_phrases.Length)];
|
|
||||||
Console.WriteLine($"{phrases}{Environment.NewLine}{_fennec}");
|
public IEnumerable<IArguments> Arguments { get; set; }
|
||||||
return true;
|
|
||||||
}
|
public bool Entry(IShell shell, IEnumerable<KeyValuePair<string, object>> arguments)
|
||||||
|
{
|
||||||
|
var rng = new Random();
|
||||||
|
var phrases = _phrases[rng.Next(_phrases.Length)];
|
||||||
|
Console.WriteLine($"{phrases}{Environment.NewLine}{_fennec}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -4,6 +4,4 @@ and related or neighboring rights for to this project. In areas where these
|
||||||
waivers are not recognized, BSD-3-Clause is enforced.
|
waivers are not recognized, BSD-3-Clause is enforced.
|
||||||
See the (UN)LICENSE file in the project root for more information.
|
See the (UN)LICENSE file in the project root for more information.
|
||||||
*/
|
*/
|
||||||
global using System.Diagnostics.CodeAnalysis;
|
|
||||||
global using System.Diagnostics;
|
|
||||||
global using Tomas.Interface;
|
global using Tomas.Interface;
|
||||||
|
|
23
src/Tomas.Interface/Globalization/IUIText.cs
Normal file
23
src/Tomas.Interface/Globalization/IUIText.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
In jurisdictions that recognize copyright waivers, I've waived all copyright
|
||||||
|
and related or neighboring rights for to this project. In areas where these
|
||||||
|
waivers are not recognized, BSD-3-Clause is enforced.
|
||||||
|
See the (UN)LICENSE file in the project root for more information.
|
||||||
|
*/
|
||||||
|
namespace Tomas.Interface.Globalization;
|
||||||
|
|
||||||
|
public interface IUIText
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The base directory for the language files.
|
||||||
|
/// </summary>
|
||||||
|
string[] BasePath { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the text for the given id and key.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The id of the text.</param>
|
||||||
|
/// <param name="key">The key of the text.</param>
|
||||||
|
/// <returns>The text for the given id and key.</returns>
|
||||||
|
string GetText(int id, int key);
|
||||||
|
}
|
23
src/Tomas.Interface/IArguments.cs
Normal file
23
src/Tomas.Interface/IArguments.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
In jurisdictions that recognize copyright waivers, I've waived all copyright
|
||||||
|
and related or neighboring rights for to this project. In areas where these
|
||||||
|
waivers are not recognized, BSD-3-Clause is enforced.
|
||||||
|
See the (UN)LICENSE file in the project root for more information.
|
||||||
|
*/
|
||||||
|
namespace Tomas.Interface;
|
||||||
|
|
||||||
|
// Represents an argument that a program expects
|
||||||
|
public interface IArguments
|
||||||
|
{
|
||||||
|
// The name of the argument
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
// A description of the argument
|
||||||
|
string Description { get; }
|
||||||
|
|
||||||
|
// The type of the argument
|
||||||
|
Type Type { get; }
|
||||||
|
|
||||||
|
// Whether the argument is required or optional
|
||||||
|
bool IsRequired { get; }
|
||||||
|
}
|
|
@ -6,13 +6,20 @@ See the (UN)LICENSE file in the project root for more information.
|
||||||
*/
|
*/
|
||||||
namespace Tomas.Interface;
|
namespace Tomas.Interface;
|
||||||
|
|
||||||
|
// Represents a program that can be run by the shell
|
||||||
public interface IProgram
|
public interface IProgram
|
||||||
{
|
{
|
||||||
/// <summary>
|
// The name of the program
|
||||||
/// The program's main entry point. Boolean behaves as an exit point.
|
string Name { get; }
|
||||||
/// True and False are the equivalent to C's 0 and 1, i.e. "Success" and "Failure," respectfully.
|
|
||||||
/// </summary>
|
// A description of the program
|
||||||
/// <param name="shell">Allows the program to interact with the shell.</param>
|
string Description { get; }
|
||||||
/// <returns>Exit back to shell.</returns>
|
|
||||||
bool Run(IShell shell);
|
// The arguments that the program expects
|
||||||
}
|
IEnumerable<IArguments> Arguments { get; }
|
||||||
|
|
||||||
|
// The main entry point of the program
|
||||||
|
// Takes a shell object to allow the program to interact with the shell,
|
||||||
|
// and a dictionary of arguments passed to the program by the shell
|
||||||
|
bool Entry(IShell shell, IEnumerable<KeyValuePair<string, object>> arguments);
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,9 @@ namespace Tomas.Interface;
|
||||||
|
|
||||||
public interface IShell
|
public interface IShell
|
||||||
{
|
{
|
||||||
string ReadLine { get; }
|
string ReadLine { get; }
|
||||||
|
|
||||||
Dictionary<string, IProgram> Programs { get; }
|
Dictionary<string, IProgram> Programs { get; }
|
||||||
|
|
||||||
|
IEnumerable<KeyValuePair<string, object>>? ParseArguments(IProgram program, string[] arguments);
|
||||||
}
|
}
|
|
@ -1 +1 @@
|
||||||
23.0
|
23.5
|
|
@ -4,97 +4,112 @@ and related or neighboring rights for to this project. In areas where these
|
||||||
waivers are not recognized, BSD-3-Clause is enforced.
|
waivers are not recognized, BSD-3-Clause is enforced.
|
||||||
See the (UN)LICENSE file in the project root for more information.
|
See the (UN)LICENSE file in the project root for more information.
|
||||||
*/
|
*/
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace Tomas.Kernel.Globalization;
|
namespace Tomas.Kernel.Globalization;
|
||||||
|
|
||||||
public class CST
|
public class CST
|
||||||
{
|
{
|
||||||
const char CARET = '^';
|
const char CARET = '^';
|
||||||
const string LF = "\u000A";
|
const string LF = "\u000A";
|
||||||
const string CR = "\u000D";
|
const string CR = "\u000D";
|
||||||
const string CRLF = "\u000D\u000A";
|
const string CRLF = "\u000D\u000A";
|
||||||
const string LS = "\u2028";
|
const string LS = "\u2028";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the value from the digit-based key.
|
/// Gets the value from the digit-based key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Returns the entry</returns>
|
/// <returns>Returns the entry</returns>
|
||||||
public static string Parse(string content, int key) => Parse(content, key.ToString());
|
public static string Parse(string content, int key) => Parse(content, key.ToString());
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the value from the string-based key.
|
/// Gets the value from the string-based key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Returns the entry</returns>
|
/// <returns>Returns the entry</returns>
|
||||||
public static string Parse(string content, string key)
|
public static string Parse(string content, string key)
|
||||||
{
|
{
|
||||||
var entries = NormalizeEntries(content);
|
var entries = NormalizeEntries(content);
|
||||||
return GetEntry(entries, key);
|
return GetEntry(entries, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Replaces the document's line endings with the native system line endings.
|
/// Replaces the document's line endings with the native system line endings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>This stage ensures there are no crashes during parsing.</remarks>
|
/// <remarks>This stage ensures there are no crashes during parsing.</remarks>
|
||||||
/// <param name="content">The content of the document.</param>
|
/// <param name="content">The content of the document.</param>
|
||||||
/// <returns>The document's content with native system line endings.</returns>
|
/// <returns>The document's content with native system line endings.</returns>
|
||||||
static IEnumerable<string> NormalizeEntries(string content)
|
static IEnumerable<string> NormalizeEntries(string content)
|
||||||
{
|
{
|
||||||
// Check if the document already uses native system line endings.
|
// Check if the document already uses native system line endings.
|
||||||
if (!content.Contains(Environment.NewLine))
|
if (!content.Contains(Environment.NewLine))
|
||||||
{
|
{
|
||||||
// If not, check for and replace other line ending types.
|
// If not, check for and replace other line ending types.
|
||||||
if (content.Contains(LF))
|
if (content.Contains(LF))
|
||||||
content = content.Replace(LF, Environment.NewLine);
|
content = content.Replace(LF, Environment.NewLine);
|
||||||
|
|
||||||
if (content.Contains(CR))
|
if (content.Contains(CR))
|
||||||
content = content.Replace(CR, Environment.NewLine);
|
content = content.Replace(CR, Environment.NewLine);
|
||||||
|
|
||||||
if (content.Contains(CRLF))
|
if (content.Contains(CRLF))
|
||||||
content = content.Replace(CRLF, Environment.NewLine);
|
content = content.Replace(CRLF, Environment.NewLine);
|
||||||
|
|
||||||
if (content.Contains(LS))
|
if (content.Contains(LS))
|
||||||
content = content.Replace(LS, Environment.NewLine);
|
content = content.Replace(LS, Environment.NewLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split the content by the caret and newline characters.
|
// Split the content by the caret and newline characters.
|
||||||
var lines = content.Split(new[] { $"{CARET}{Environment.NewLine}" },
|
var lines = content.Split(new[] { $"{CARET}{Environment.NewLine}" },
|
||||||
StringSplitOptions.RemoveEmptyEntries);
|
StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
// Filter out any lines that start with "//", "#", "/*", or end with "*/".
|
// Filter out any lines that start with "//", "#", "/*", or end with "*/".
|
||||||
return lines.Where(line =>
|
return lines.Where(line =>
|
||||||
!line.StartsWith("//") &&
|
!line.StartsWith("//") &&
|
||||||
!line.StartsWith("#") &&
|
!line.StartsWith("#") &&
|
||||||
!line.StartsWith("/*") &&
|
!line.StartsWith("/*") &&
|
||||||
!line.EndsWith("*/"))
|
!line.EndsWith("*/"))
|
||||||
.AsEnumerable();
|
.AsEnumerable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
// Retrieves the value for the specified key from the given entries.
|
||||||
/// Retrieves the value for the specified key from the given entries.
|
// Replaces any occurrences of % followed by a number with the corresponding argument value extracted from the entry string.
|
||||||
/// </summary>
|
static string GetEntry(IEnumerable<string> entries, string key)
|
||||||
/// <param name="entries">The entries to search through.</param>
|
{
|
||||||
/// <param name="key">The key to search for.</param>
|
// Iterate through the entries.
|
||||||
/// <returns>The value for the specified key, or a default string if not found.</returns>
|
foreach (var entry in entries)
|
||||||
static string GetEntry(IEnumerable<string> entries, string key)
|
{
|
||||||
{
|
// If the line doesn't start with the key, keep searching.
|
||||||
// Iterate through the entries.
|
if (!entry.StartsWith(key))
|
||||||
foreach (var entry in entries)
|
continue;
|
||||||
{
|
|
||||||
// If the line doesn't start with the key, keep searching.
|
|
||||||
if (!entry.StartsWith(key))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Locate the index of the caret character.
|
// Locate the index of the caret character.
|
||||||
var startIndex = entry.IndexOf(CARET);
|
var startIndex = entry.IndexOf(CARET);
|
||||||
// Get the line from the caret character to the end of the string.
|
// Get the line from the caret character to the end of the string.
|
||||||
var line = entry[startIndex..];
|
var line = entry[startIndex..];
|
||||||
|
|
||||||
// Return the line with the caret characters trimmed.
|
// Extract the arguments from the entry string using a regular expression
|
||||||
return line.TrimStart(CARET).TrimEnd(CARET);
|
var arguments = Regex.Matches(line, @"%(\d+)").Cast<Match>().Select(m => m.Groups[1].Value).ToArray();
|
||||||
}
|
|
||||||
|
// Replace any occurrences of % followed by a number with the corresponding argument value
|
||||||
|
for (int i = 0; i < arguments.Length; i++)
|
||||||
|
{
|
||||||
|
line = line.Replace($"%{arguments[i]}", GetArgumentValue(arguments[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the line with the caret characters trimmed.
|
||||||
|
return line.TrimStart(CARET).TrimEnd(CARET);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no entry is found, return a default string.
|
||||||
|
return "***MISSING***";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieves the value for the specified argument.
|
||||||
|
static string GetArgumentValue(string argument)
|
||||||
|
{
|
||||||
|
// TODO: Implement logic to get the value for the specified argument.
|
||||||
|
return "***ARGUMENT VALUE***";
|
||||||
|
}
|
||||||
|
|
||||||
// If no entry is found, return a default string.
|
|
||||||
return "***MISSING***";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
In jurisdictions that recognize copyright waivers, I've waived all copyright
|
|
||||||
and related or neighboring rights for to this project. In areas where these
|
|
||||||
waivers are not recognized, BSD-3-Clause is enforced.
|
|
||||||
See the (UN)LICENSE file in the project root for more information.
|
|
||||||
*/
|
|
||||||
namespace Tomas.Kernel.Globalization;
|
|
||||||
|
|
||||||
public interface IUIText
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The base directory for the language files.
|
|
||||||
/// </summary>
|
|
||||||
string[] BasePath { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the text for the given id and key.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The id of the text.</param>
|
|
||||||
/// <param name="key">The key of the text.</param>
|
|
||||||
/// <returns>The text for the given id and key.</returns>
|
|
||||||
string GetText(int id, int key);
|
|
||||||
}
|
|
|
@ -8,97 +8,97 @@ namespace Tomas.Kernel.Globalization;
|
||||||
|
|
||||||
public class UIText : IUIText
|
public class UIText : IUIText
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The language of the text.
|
/// The language of the text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Language { get; set; } = "english";
|
string Language { get; set; } = "english";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The base directory for the language files.
|
/// The base directory for the language files.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string[] BasePath { get; set; } = { AppContext.BaseDirectory, "uitext" };
|
public string[] BasePath { get; set; } = { AppContext.BaseDirectory, "translations" };
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor for the UIText class.
|
/// Constructor for the UIText class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public UIText() { }
|
public UIText() { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor for the UIText class.
|
/// Constructor for the UIText class.
|
||||||
/// Loads the language file for the specified language.
|
/// Loads the language file for the specified language.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="language">Language to load</param>
|
/// <param name="language">Language to load</param>
|
||||||
public UIText(string language)
|
public UIText(string language)
|
||||||
{
|
{
|
||||||
Language = language;
|
Language = language;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor for the UIText class.
|
/// Constructor for the UIText class.
|
||||||
/// Loads the language file for the specified language and base directory.
|
/// Loads the language file for the specified language and base directory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="language">Language to load</param>
|
/// <param name="language">Language to load</param>
|
||||||
/// <param name="basePath">Base directory for the language files.</param>
|
/// <param name="basePath">Base directory for the language files.</param>
|
||||||
public UIText(string language, params string[] baseBath)
|
public UIText(string language, params string[] baseBath)
|
||||||
{
|
{
|
||||||
Language = language;
|
Language = language;
|
||||||
BasePath = baseBath;
|
BasePath = baseBath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the text for the given id and key.
|
/// Get the text for the given id and key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The id of the text.</param>
|
/// <param name="id">The id of the text.</param>
|
||||||
/// <param name="key">The key of the text.</param>
|
/// <param name="key">The key of the text.</param>
|
||||||
/// <returns>The text for the given id and key.</returns>
|
/// <returns>The text for the given id and key.</returns>
|
||||||
public string GetText(int id, int key) => GetText(id, key.ToString());
|
public string GetText(int id, int key) => GetText(id, key.ToString());
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the text for the given id and key.
|
/// Get the text for the given id and key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The id of the text.</param>
|
/// <param name="id">The id of the text.</param>
|
||||||
/// <param name="key">The key of the text.</param>
|
/// <param name="key">The key of the text.</param>
|
||||||
/// <returns>The text for the given id and key.</returns>
|
/// <returns>The text for the given id and key.</returns>
|
||||||
public string GetText(int id, string key)
|
public string GetText(int id, string key)
|
||||||
{
|
{
|
||||||
// Combine the base path and language path to get the full path of the language file.
|
// Combine the base path and language path to get the full path of the language file.
|
||||||
var basePath = Path.Combine(BasePath);
|
var basePath = Path.Combine(BasePath);
|
||||||
var langPath = Path.Combine(basePath, $"{Language}.dir");
|
var langPath = Path.Combine(basePath, $"{Language}.dir");
|
||||||
|
|
||||||
// Get all the files in the language directory.
|
// Get all the files in the language directory.
|
||||||
var files = Directory.GetFiles(langPath);
|
var files = Directory.GetFiles(langPath);
|
||||||
|
|
||||||
// Iterate through the files in the language directory.
|
// Iterate through the files in the language directory.
|
||||||
foreach (var file in files)
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
// Skip files that do not have the ".cst" extension.
|
// Skip files that do not have the ".cst" extension.
|
||||||
if (!file.Contains(".cst"))
|
if (!file.Contains(".cst"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Get the id of the current file.
|
// Get the id of the current file.
|
||||||
var ids = Path.GetFileName(file);
|
var ids = Path.GetFileName(file);
|
||||||
var second = ids.IndexOf("_", 1, StringComparison.InvariantCultureIgnoreCase);
|
var second = ids.IndexOf("_", 1, StringComparison.InvariantCultureIgnoreCase);
|
||||||
|
|
||||||
if (second == -1)
|
if (second == -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ids = ids.Substring(1, second - 1);
|
ids = ids.Substring(1, second - 1);
|
||||||
|
|
||||||
// If the id of the current file does not match the id passed to the function,
|
// If the id of the current file does not match the id passed to the function,
|
||||||
// skip to the next file.
|
// skip to the next file.
|
||||||
if (ids != id.ToString())
|
if (ids != id.ToString())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Read the content of the current file.
|
// Read the content of the current file.
|
||||||
var content = File.ReadAllText(file);
|
var content = File.ReadAllText(file);
|
||||||
|
|
||||||
// Return the text for the specified key.
|
// Return the text for the specified key.
|
||||||
return CST.Parse(content, key);
|
return CST.Parse(content, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no text is found, return a default string.
|
// If no text is found, return a default string.
|
||||||
return "***MISSING***";
|
return "***MISSING***";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ public class Kernel : Os.Kernel
|
||||||
Console.WriteLine($"{SysMeta.NAME} booted successfully.");
|
Console.WriteLine($"{SysMeta.NAME} booted successfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method is the main loop of the kernel, which handles input and runs programs
|
|
||||||
protected override void Run()
|
protected override void Run()
|
||||||
{
|
{
|
||||||
// Run the loop indefinitely
|
// Run the loop indefinitely
|
||||||
|
@ -34,34 +33,53 @@ public class Kernel : Os.Kernel
|
||||||
// Read a line of input from the user
|
// Read a line of input from the user
|
||||||
var command = shell.ReadLine;
|
var command = shell.ReadLine;
|
||||||
|
|
||||||
|
// Split the command into words
|
||||||
|
var words = command.Split(' ');
|
||||||
|
|
||||||
|
// If there are no words, skip this iteration
|
||||||
|
if (words.Length == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Get the program name
|
||||||
|
var programName = words[0];
|
||||||
|
|
||||||
// Get the dictionary of programs from the shell
|
// Get the dictionary of programs from the shell
|
||||||
var programs = shell.Programs;
|
var programs = shell.Programs;
|
||||||
|
|
||||||
// If the command is not a key in the dictionary of programs, print an error message
|
// If the program doesn't exist, display an error message
|
||||||
// and continue to the next iteration of the loop
|
if (!programs.TryGetValue(programName, out var program))
|
||||||
if (!programs.TryGetValue(command, out var program))
|
|
||||||
{
|
{
|
||||||
Console.WriteLine("Command Not Found.");
|
Console.WriteLine($"{programName}: command not found");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the arguments
|
||||||
|
var arguments = words.Skip(1).ToArray();
|
||||||
|
|
||||||
|
// Parse and validate the arguments
|
||||||
|
var parsedArguments = shell.ParseArguments(program, arguments);
|
||||||
|
if (parsedArguments == null)
|
||||||
|
{
|
||||||
|
// If the arguments are invalid, display an error message
|
||||||
|
Console.WriteLine($"{programName}: invalid arguments");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to run the program and handle any exceptions that may be thrown
|
// Try to run the program and handle any exceptions that may be thrown
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Run the program and store the returned value in the 'start' variable
|
// Run the program and store the returned value in the 'result' variable
|
||||||
var start = program.Run(shell);
|
var result = program.Entry(shell, parsedArguments);
|
||||||
|
|
||||||
// Check the value of 'start' and take the appropriate action
|
switch (result)
|
||||||
switch (start)
|
|
||||||
{
|
{
|
||||||
case true:
|
case true:
|
||||||
// If 'start' is true, continue to the next iteration of the loop
|
|
||||||
continue;
|
continue;
|
||||||
case false:
|
case false:
|
||||||
// If 'start' is false, print an error message and continue to the next iteration of the loop
|
|
||||||
Console.WriteLine("Program closed unexpectedly.");
|
Console.WriteLine("Program closed unexpectedly.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception err)
|
catch (Exception err)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,13 +8,19 @@ namespace Tomas.Kernel.Programs;
|
||||||
|
|
||||||
public class About : IProgram
|
public class About : IProgram
|
||||||
{
|
{
|
||||||
public bool Run(IShell shell)
|
public string Name { get; set; }
|
||||||
{
|
|
||||||
Console.WriteLine($"TOMAS v{SysMeta.VERSION} ({SysMeta.BuildNumber}) is a hobby operating system written in C# using the COSMOS framework.{Environment.NewLine}Commands:");
|
|
||||||
var progs = shell.Programs;
|
|
||||||
foreach (var commands in progs.Keys)
|
|
||||||
Console.WriteLine(commands);
|
|
||||||
|
|
||||||
return true;
|
public string Description { get; set; }
|
||||||
}
|
|
||||||
|
public IEnumerable<IArguments> Arguments { get; set; }
|
||||||
|
|
||||||
|
public bool Entry(IShell shell, IEnumerable<KeyValuePair<string, object>> arguments)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"TOMAS v{SysMeta.VERSION} ({SysMeta.BuildNumber}) is a hobby operating system written in C# using the COSMOS framework.{Environment.NewLine}Commands:");
|
||||||
|
var progs = shell.Programs;
|
||||||
|
foreach (var commands in progs.Keys)
|
||||||
|
Console.WriteLine(commands);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -13,13 +13,18 @@ public class Shell : IShell
|
||||||
|
|
||||||
// A dictionary containing the programs available to the shell, with the keys being the program names
|
// A dictionary containing the programs available to the shell, with the keys being the program names
|
||||||
// and the values being the program objects
|
// and the values being the program objects
|
||||||
public Dictionary<string, IProgram> Programs => new()
|
public Dictionary<string, IProgram> Programs { get; }
|
||||||
|
|
||||||
|
public Shell()
|
||||||
{
|
{
|
||||||
{"about", new About() },
|
Programs = new Dictionary<string, IProgram>
|
||||||
{"fensay", new FenSay() },
|
{
|
||||||
{"clear", new Clear() },
|
{"about", new About() },
|
||||||
{"commands", new Commands() }
|
{"fensay", new FenSay() },
|
||||||
};
|
{"clear", new Clear() },
|
||||||
|
{"commands", new Commands() }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// A property that allows the shell to read a line of input from the user
|
// A property that allows the shell to read a line of input from the user
|
||||||
public string ReadLine
|
public string ReadLine
|
||||||
|
@ -36,5 +41,132 @@ public class Shell : IShell
|
||||||
return readl;
|
return readl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
public void Run()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// Read a line of input from the user
|
||||||
|
var input = ReadLine;
|
||||||
|
|
||||||
|
// Split the input into words
|
||||||
|
var words = input.Split(' ');
|
||||||
|
|
||||||
|
// If there are no words, skip this iteration
|
||||||
|
if (words.Length == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Get the program name
|
||||||
|
var programName = words[0];
|
||||||
|
|
||||||
|
// Get the arguments
|
||||||
|
var arguments = words.Skip(1).ToArray();
|
||||||
|
|
||||||
|
// Check if the program exists
|
||||||
|
if (!Programs.TryGetValue(programName, out var program))
|
||||||
|
{
|
||||||
|
// If the program doesn't exist, display an error message
|
||||||
|
Console.WriteLine($"{programName}: command not found");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse and validate the arguments
|
||||||
|
var parsedArguments = ParseArguments(program, arguments);
|
||||||
|
if (parsedArguments == null)
|
||||||
|
{
|
||||||
|
// If the arguments are invalid, display an error message
|
||||||
|
Console.WriteLine($"{programName}: invalid arguments");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the program
|
||||||
|
var result = program.Entry(this, parsedArguments);
|
||||||
|
|
||||||
|
// Handle the result
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
// If the program was successful, display a success message
|
||||||
|
Console.WriteLine($"{programName}: success");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If the program failed, display a failure message
|
||||||
|
Console.WriteLine($"{programName}: failure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<KeyValuePair<string, object>>? ParseArguments(IProgram program, string[] arguments)
|
||||||
|
{
|
||||||
|
// Create a dictionary to store the parsed arguments
|
||||||
|
var parsedArguments = new Dictionary<string, object>();
|
||||||
|
|
||||||
|
// Create a list of required arguments
|
||||||
|
var requiredArguments = program.Arguments.Where(x => x.IsRequired).ToList();
|
||||||
|
|
||||||
|
// Iterate over the arguments
|
||||||
|
for (int i = 0; i < arguments.Length; i++)
|
||||||
|
{
|
||||||
|
// Get the current argument
|
||||||
|
var argument = arguments[i];
|
||||||
|
|
||||||
|
// Check if the argument is a flag or a value
|
||||||
|
if (argument.StartsWith("-"))
|
||||||
|
{
|
||||||
|
// If it's a flag, get the flag name and value
|
||||||
|
var flagName = argument.Substring(1);
|
||||||
|
object flagValue = true;
|
||||||
|
if (flagName.EndsWith("="))
|
||||||
|
{
|
||||||
|
// If the flag has a value, extract it
|
||||||
|
var flagNameValue = flagName.Split('=');
|
||||||
|
flagName = flagNameValue[0];
|
||||||
|
flagValue = flagNameValue[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the argument definition
|
||||||
|
var argumentDefinition = program.Arguments.FirstOrDefault(x => x.Name == flagName);
|
||||||
|
if (argumentDefinition == null)
|
||||||
|
{
|
||||||
|
// If the argument is not defined, return null
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the argument to the dictionary
|
||||||
|
parsedArguments[flagName] = flagValue;
|
||||||
|
|
||||||
|
// Remove the argument from the required arguments list
|
||||||
|
requiredArguments.Remove(argumentDefinition);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If it's a value, check if there are any required arguments left
|
||||||
|
if (requiredArguments.Count == 0)
|
||||||
|
{
|
||||||
|
// If there are no required arguments left, return null
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the next required argument
|
||||||
|
var requiredArgument = requiredArguments[0];
|
||||||
|
|
||||||
|
// Convert the value to the correct type
|
||||||
|
var value = Convert.ChangeType(argument, requiredArgument.Type);
|
||||||
|
|
||||||
|
// Add the argument to the dictionary
|
||||||
|
parsedArguments[requiredArgument.Name] = value;
|
||||||
|
|
||||||
|
// Remove the argument from the required arguments list
|
||||||
|
requiredArguments.RemoveAt(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are any required arguments left, return null
|
||||||
|
if (requiredArguments.Count > 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Return the parsed arguments
|
||||||
|
return parsedArguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,12 +4,9 @@ and related or neighboring rights for to this project. In areas where these
|
||||||
waivers are not recognized, BSD-3-Clause is enforced.
|
waivers are not recognized, BSD-3-Clause is enforced.
|
||||||
See the (UN)LICENSE file in the project root for more information.
|
See the (UN)LICENSE file in the project root for more information.
|
||||||
*/
|
*/
|
||||||
global using System.Diagnostics.CodeAnalysis;
|
|
||||||
global using System.Diagnostics;
|
|
||||||
global using Tomas.Core.Programs;
|
global using Tomas.Core.Programs;
|
||||||
global using Tomas.Interface;
|
global using Tomas.Interface;
|
||||||
|
global using Tomas.Interface.Globalization;
|
||||||
global using Tomas.Kernel.Programs;
|
global using Tomas.Kernel.Programs;
|
||||||
global using Cosmos.System.FileSystem;
|
global using Cosmos.System.FileSystem;
|
||||||
global using Cosmos.System.FileSystem.VFS;
|
|
||||||
global using Tomas.Core;
|
|
||||||
global using Os = Cosmos.System;
|
global using Os = Cosmos.System;
|
|
@ -1 +0,0 @@
|
||||||
0.1
|
|
|
@ -4,40 +4,69 @@ and related or neighboring rights for to this project. In areas where these
|
||||||
waivers are not recognized, BSD-3-Clause is enforced.
|
waivers are not recognized, BSD-3-Clause is enforced.
|
||||||
See the (UN)LICENSE file in the project root for more information.
|
See the (UN)LICENSE file in the project root for more information.
|
||||||
*/
|
*/
|
||||||
namespace Tomas.Terminal;
|
|
||||||
|
|
||||||
class Program
|
// Run the loop indefinitely
|
||||||
|
using Tomas.Terminal;
|
||||||
|
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
static void Main()
|
// Create a new instance of the Shell class
|
||||||
{
|
var shell = new Shell();
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
var shell = new Shell();
|
|
||||||
var command = shell.ReadLine;
|
|
||||||
var programs = shell.Programs;
|
|
||||||
|
|
||||||
if (!programs.TryGetValue(command, out var program))
|
// Read a line of input from the user
|
||||||
{
|
var command = shell.ReadLine;
|
||||||
Console.WriteLine("Command Not Found.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
// Split the command into words
|
||||||
{
|
var words = command.Split(' ');
|
||||||
var start = program.Run(shell);
|
|
||||||
switch (start)
|
// If there are no words, skip this iteration
|
||||||
|
if (words.Length == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Get the program name
|
||||||
|
var programName = words[0];
|
||||||
|
|
||||||
|
// Get the dictionary of programs from the shell
|
||||||
|
var programs = shell.Programs;
|
||||||
|
|
||||||
|
// If the program doesn't exist, display an error message
|
||||||
|
if (!programs.TryGetValue(programName, out var program))
|
||||||
{
|
{
|
||||||
case true:
|
Console.WriteLine($"{programName}: command not found");
|
||||||
continue;
|
continue;
|
||||||
case false:
|
|
||||||
Console.WriteLine("Program closed unexpectedly.");
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (Exception err)
|
// Get the arguments
|
||||||
{
|
var arguments = words.Skip(1).ToArray();
|
||||||
Console.WriteLine(err.Message);
|
|
||||||
}
|
// Parse and validate the arguments
|
||||||
}
|
var parsedArguments = shell.ParseArguments(program, arguments);
|
||||||
}
|
if (parsedArguments == null)
|
||||||
}
|
{
|
||||||
|
// If the arguments are invalid, display an error message
|
||||||
|
Console.WriteLine($"{programName}: invalid arguments");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to run the program and handle any exceptions that may be thrown
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Run the program and store the returned value in the 'result' variable
|
||||||
|
var result = program.Entry(shell, parsedArguments);
|
||||||
|
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case true:
|
||||||
|
continue;
|
||||||
|
case false:
|
||||||
|
Console.WriteLine("Program closed unexpectedly.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception err)
|
||||||
|
{
|
||||||
|
// If an exception is caught, print the error message and continue to the next iteration of the loop
|
||||||
|
Console.WriteLine(err.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,9 +8,14 @@ namespace Tomas.Terminal.Programs;
|
||||||
|
|
||||||
public class About : IProgram
|
public class About : IProgram
|
||||||
{
|
{
|
||||||
public bool Run(IShell shell)
|
public string Name { get; set; }
|
||||||
{
|
|
||||||
Console.WriteLine($"{TermMeta.NAME} Terminal Emulator v{TermMeta.VERSION}");
|
public string Description { get; set; }
|
||||||
return true;
|
|
||||||
}
|
public IEnumerable<IArguments> Arguments { get; set; }
|
||||||
|
|
||||||
|
public bool Entry(IShell shell, IEnumerable<KeyValuePair<string, object>> arguments)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -10,9 +10,9 @@ namespace Tomas.Terminal;
|
||||||
|
|
||||||
public class Shell : IShell
|
public class Shell : IShell
|
||||||
{
|
{
|
||||||
const char SYMBOL = '$';
|
const char SYMBOL = '$';
|
||||||
|
|
||||||
public Dictionary<string, IProgram> Programs => new()
|
public Dictionary<string, IProgram> Programs => new()
|
||||||
{
|
{
|
||||||
{"about", new About()},
|
{"about", new About()},
|
||||||
{"fensay", new FenSay()},
|
{"fensay", new FenSay()},
|
||||||
|
@ -20,13 +20,18 @@ public class Shell : IShell
|
||||||
{"commands", new Commands()}
|
{"commands", new Commands()}
|
||||||
};
|
};
|
||||||
|
|
||||||
public string ReadLine
|
public string ReadLine
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Console.Write(SYMBOL);
|
Console.Write(SYMBOL);
|
||||||
var readl = Console.ReadLine();
|
var readl = Console.ReadLine();
|
||||||
return readl;
|
return readl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<KeyValuePair<string, object>>? ParseArguments(IProgram program, string[] arguments)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
In jurisdictions that recognize copyright waivers, I've waived all copyright
|
|
||||||
and related or neighboring rights for to this project. In areas where these
|
|
||||||
waivers are not recognized, BSD-3-Clause is enforced.
|
|
||||||
See the (UN)LICENSE file in the project root for more information.
|
|
||||||
*/
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Tomas.Terminal;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// System metdata, such as name, version and build number.
|
|
||||||
/// </summary>
|
|
||||||
public struct TermMeta
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the operating system.
|
|
||||||
/// </summary>
|
|
||||||
public const string NAME = "TOMAS Emulator";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The version of the operating system, in the Calendar Versioning format: "yy.minor.patch".
|
|
||||||
/// The year, minor, and patch version numbers are automatically extracted from the Git repository
|
|
||||||
/// using the ThisAssembly.Git.SemVer object.
|
|
||||||
/// </summary>
|
|
||||||
public const string VERSION = $"{ThisAssembly.Git.SemVer.Major}.{ThisAssembly.Git.SemVer.Minor}.{ThisAssembly.Git.SemVer.Patch}";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The build number of the operating system, generated from the commit hash.
|
|
||||||
/// The build number is a 6-digit number, with the first 3 digits being the first 3 digits of the commit hash
|
|
||||||
/// converted to a uint, and the last 3 digits being the last 3 digits of the commit hash converted to a uint.
|
|
||||||
/// </summary>
|
|
||||||
public static string BuildNumber = $"Build {BuildNumFromCommit}";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the build number from the commit hash.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The build number as a uint.</returns>
|
|
||||||
static uint BuildNumFromCommit
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
// Get the bytes of the commit hash as a UTF-8 encoded string
|
|
||||||
var commit = Encoding.UTF8.GetBytes(ThisAssembly.Git.Commit);
|
|
||||||
|
|
||||||
// Convert the first 4 bytes of the commit hash to a uint and return it modulo 1000000
|
|
||||||
// (this will give us a 6-digit number with the first 3 digits being the first 3 digits of the commit hash
|
|
||||||
// and the last 3 digits being the last 3 digits of the commit hash)
|
|
||||||
return BitConverter.ToUInt32(commit, 0) % 1000000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
|
@ -8,10 +8,6 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="GitInfo" Version="2.3.0">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="NLua" Version="1.6.0" />
|
<PackageReference Include="NLua" Version="1.6.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,5 @@ and related or neighboring rights for to this project. In areas where these
|
||||||
waivers are not recognized, BSD-3-Clause is enforced.
|
waivers are not recognized, BSD-3-Clause is enforced.
|
||||||
See the (UN)LICENSE file in the project root for more information.
|
See the (UN)LICENSE file in the project root for more information.
|
||||||
*/
|
*/
|
||||||
global using System.Diagnostics.CodeAnalysis;
|
|
||||||
global using System.Diagnostics;
|
|
||||||
global using Tomas.Core.Programs;
|
global using Tomas.Core.Programs;
|
||||||
global using Tomas.Interface;
|
global using Tomas.Interface;
|
|
@ -8,9 +8,22 @@ namespace Tomas.Tests.Shell;
|
||||||
|
|
||||||
internal class MockProgram : IProgram
|
internal class MockProgram : IProgram
|
||||||
{
|
{
|
||||||
public bool Run(IShell shell)
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<IArguments> Arguments { get; set; }
|
||||||
|
|
||||||
|
public bool Entry(IShell shell, IEnumerable<KeyValuePair<string, object>> arguments)
|
||||||
{
|
{
|
||||||
Debug.WriteLine("Test Program.");
|
// Iterate through the arguments
|
||||||
|
foreach (var argument in arguments)
|
||||||
|
{
|
||||||
|
// Print the argument name and value
|
||||||
|
Debug.WriteLine($"Argument name: {argument.Key}, Argument value: {argument.Value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true to indicate success
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,4 +14,9 @@ internal class MockShell : IShell
|
||||||
{
|
{
|
||||||
{ "test", new MockProgram() },
|
{ "test", new MockProgram() },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public IEnumerable<KeyValuePair<string, object>>? ParseArguments(IProgram program, string[] arguments)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,15 @@ public class ShellTests
|
||||||
// Create a mock program instance
|
// Create a mock program instance
|
||||||
var program = new MockProgram();
|
var program = new MockProgram();
|
||||||
|
|
||||||
// Assert that the Run method of the program and returns true when passed the shell object.
|
// Create a dictionary of arguments to pass to the program
|
||||||
Assert.True(program.Run(_mockShell));
|
var arguments = new Dictionary<string, object>
|
||||||
}
|
{
|
||||||
|
{"arg1", "value1"},
|
||||||
|
{"arg2", 123},
|
||||||
|
{"arg3", true},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Assert that the Run method of the program returns true when passed the shell object and the arguments dictionary.
|
||||||
|
Assert.True(program.Entry(_mockShell, arguments));
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -5,7 +5,5 @@ waivers are not recognized, BSD-3-Clause is enforced.
|
||||||
See the (UN)LICENSE file in the project root for more information.
|
See the (UN)LICENSE file in the project root for more information.
|
||||||
*/
|
*/
|
||||||
global using Xunit;
|
global using Xunit;
|
||||||
global using System.Diagnostics.CodeAnalysis;
|
|
||||||
global using System.Diagnostics;
|
global using System.Diagnostics;
|
||||||
global using Tomas.Core;
|
|
||||||
global using Tomas.Interface;
|
global using Tomas.Interface;
|
Loading…
Add table
Reference in a new issue