Programs now built using IProgram interface

- The old App abstract class has been scrapped in favor of the IProgram interface in the Tomas.Interface library.
- A new terminal emulator was created when not on Windows.
- In both OS and terminal, a single dictionary has the commands and classes that implement IProgram.
- Start() now returns a boolean that behaves similar to C's main in returning an integer.
- A new while loop in both terminal and kernel handles the execution of programs.
This commit is contained in:
Tony Bark 2021-03-30 08:26:18 -04:00
parent 952554b476
commit c11f987521
31 changed files with 387 additions and 219 deletions

91
.gitignore vendored
View file

@ -1,7 +1,7 @@
**/package
# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig
# Created by https://www.gitignore.io/api/linux,macos,backup,windows,monodevelop,visualstudio,visualstudiocode
# Edit at https://www.gitignore.io/?templates=linux,macos,backup,windows,monodevelop,visualstudio,visualstudiocode
# Created by https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode,visualstudio,rider,macos,linux,backup,dotenv
# Edit at https://www.toptal.com/developers/gitignore?templates=windows,visualstudiocode,visualstudio,rider,macos,linux,backup,dotenv
### Backup ###
*.bak
@ -10,6 +10,9 @@
*.orig
*.tmp
### dotenv ###
.env
### Linux ###
*~
@ -34,6 +37,7 @@
# Icon must end with two \r
Icon
# Thumbnails
._*
@ -53,26 +57,69 @@ Network Trash Folder
Temporary Items
.apdisk
### MonoDevelop ###
#User Specific
*.userprefs
*.usertasks
### Rider ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
#Mono Project Files
*.pidb
*.resources
test-results/
# User-specific stuff
.idea/**
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
### Windows ###
# Windows thumbnail cache files
@ -114,6 +161,7 @@ $RECYCLE.BIN/
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
@ -131,6 +179,7 @@ bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
@ -170,6 +219,7 @@ StyleCopReport.xml
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
@ -188,6 +238,7 @@ StyleCopReport.xml
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
@ -225,9 +276,6 @@ _ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
@ -238,6 +286,9 @@ _TeamCity*
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*[.json, .xml, .info]
# Visual Studio code coverage results
*.coverage
*.coveragexml
@ -446,4 +497,10 @@ healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# End of https://www.gitignore.io/api/linux,macos,backup,windows,monodevelop,visualstudio,visualstudiocode
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# End of https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode,visualstudio,rider,macos,linux,backup,dotenv
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)

View file

@ -1,21 +1,19 @@
# TOMAS
TOMAS, an abbreviation of **To**ny's **Ma**naged Operating **S**ystem, is a operating system written in C# using the [COSMOS](https://github.com/CosmosOS/Cosmos) framework.
TOMAS (**To**ny's **Ma**naged Operating **S**ystem) is a operating system based on the [COSMOS](https://github.com/CosmosOS/Cosmos) framework. It comes with a respective terminal emulator.
## Requirements
### Prerequisites
- COSMOS User Kit v20190508+
- VMWare Workstation Player
- .NET Core 2.1+
- Visual Studio 2019
- TOMAS OS
- Visual Studio 2019
- COSMOS User Kit v20190508+
- VMWare Workstation Player
- TOMAS Terminal Emulator and OS
- .NET Core 2.1 or later
## Authors
- **Anthony Foxclaw** - _Initial work_ - [tonytins](https://github.com/tonytins)
See also the list of [contributors](https://github.com/tonytins/simtactics/contributors) who participated in this project.
## License

13
src/.idea/.idea.TOMAS/.idea/.gitignore generated vendored Normal file
View file

@ -0,0 +1,13 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/projectSettingsUpdater.xml
/.idea.TOMAS.iml
/modules.xml
/contentModel.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

1
src/.idea/.idea.TOMAS/.idea/.name generated Normal file
View file

@ -0,0 +1 @@
TOMAS

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ContentModelUserStore">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="RIDER_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$/../../../Changelog.md" />
<content url="file://$MODULE_DIR$/../../../README.md" />
<content url="file://$MODULE_DIR$/../.." />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
src/.idea/.idea.TOMAS/.idea/vcs.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View file

@ -15,6 +15,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
TOMAS.sln.licenseheader = TOMAS.sln.licenseheader
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tomas.Interface", "Tomas.Interface\Tomas.Interface.csproj", "{DAA9EDF4-83C7-4271-9805-FD6CE29E1796}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tomas.Terminal", "Tomas.Terminal\Tomas.Terminal.csproj", "{49E67E55-F9D2-419A-8097-38F39E98A95E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -29,6 +33,14 @@ Global
{C50F3A6F-CFF4-4725-A1A5-21C5A2BC3321}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C50F3A6F-CFF4-4725-A1A5-21C5A2BC3321}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C50F3A6F-CFF4-4725-A1A5-21C5A2BC3321}.Release|Any CPU.Build.0 = Release|Any CPU
{DAA9EDF4-83C7-4271-9805-FD6CE29E1796}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DAA9EDF4-83C7-4271-9805-FD6CE29E1796}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DAA9EDF4-83C7-4271-9805-FD6CE29E1796}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DAA9EDF4-83C7-4271-9805-FD6CE29E1796}.Release|Any CPU.Build.0 = Release|Any CPU
{49E67E55-F9D2-419A-8097-38F39E98A95E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{49E67E55-F9D2-419A-8097-38F39E98A95E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{49E67E55-F9D2-419A-8097-38F39E98A95E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{49E67E55-F9D2-419A-8097-38F39E98A95E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -0,0 +1,13 @@
namespace Tomas.Common
{
public struct ComConsts
{
/// <summary>
/// Name of the operating system
/// </summary>
public const string NAME = "TOMAS";
public static string Version = $"{ThisAssembly.Git.SemVer.Major}.{ThisAssembly.Git.SemVer.Minor}.{ThisAssembly.Git.SemVer.Patch}";
public static string VersionGit = $"{Version}-{ThisAssembly.Git.Commit}";
}
}

View file

@ -0,0 +1 @@
0.1

View file

@ -0,0 +1,14 @@
using System;
using Tomas.Interface.Shell;
namespace Tomas.Kernel.Programs
{
public class Clear : IProgram
{
public bool Start()
{
Console.Clear();
return true;
}
}
}

View file

@ -0,0 +1,33 @@
using System;
using Tomas.Interface.Shell;
namespace Tomas.Kernel.Programs
{
public class FenSay : IProgram
{
/// <summary>
/// Fennec art by Todd Vargo
/// </summary>
const string FENNEC = @" \/
/\ /\
//\\_//\\ ____
\_ _/ / /
/ * * \ /^^^]
\_\O/_/ [ ]
/ \_ [ /
\ \_ / /
[ [ / \/ _/
_[ [ \ /_/";
readonly string[] _fenPhrases = { "Screams in fennec!", "Some people call me a coffee fox." };
public bool Start()
{
var rng = new Random();
var phrases = _fenPhrases[rng.Next(0, _fenPhrases.Length)];
Console.WriteLine($"{phrases}{Environment.NewLine}{FENNEC}");
return true;
}
}
}

View file

@ -4,4 +4,15 @@
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Tomas.Interface\Tomas.Interface.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="GitInfo" Version="2.1.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View file

@ -0,0 +1,7 @@
namespace Tomas.Interface.Shell
{
public interface IProgram
{
bool Start();
}
}

View file

@ -0,0 +1,7 @@
namespace Tomas.Interface.Shell
{
public interface IShell
{
string ReadLine { get; }
}
}

View file

@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
</Project>

View file

@ -1,35 +0,0 @@
// TOMAS is licensed under the MPL 2.0 license.
// See the LICENSE file in the project root for more information.
using System;
namespace Tomas.Kernel
{
internal class EasterEggs
{
/// <summary>
/// Fennec art by Todd Vargo
/// </summary>
const string FENNEC = @" \/
/\ /\
//\\_//\\ ____
\_ _/ / /
/ * * \ /^^^]
\_\O/_/ [ ]
/ \_ [ /
\ \_ / /
[ [ / \/ _/
_[ [ \ /_/";
static readonly string[] _fenPhrases = { "Screams in fennec!", "Some people call me a coffee fox." };
public static string FenSay
{
get
{
var rng = new Random();
var phrases = _fenPhrases[rng.Next(0, _fenPhrases.Length)];
return $"{phrases}{Environment.NewLine}{FENNEC}";
}
}
}
}

View file

@ -1 +0,0 @@
0.1.0

View file

@ -1,15 +1,17 @@
// TOMAS is licensed under the MPL 2.0 license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using Tomas.Common;
using Tomas.Interface.Shell;
using Tomas.Kernel.Programs;
using Tomas.Terminal.Programs;
using Sys = Cosmos.System;
namespace Tomas.Kernel
{
public class Kernel : Sys.Kernel
{
public bool InApp { get; set; }
protected override void BeforeRun()
{
try
@ -29,23 +31,21 @@ namespace Tomas.Kernel
protected override void Run()
{
var input = Terminal.ReadLine("1) About");
switch (input.ToLowerInvariant())
while (true)
{
case "1":
var basic = new AboutApp(this);
basic.Start();
break;
default:
break;
var shell = new Shell();
var command = shell.ReadLine;
OSConsts.Programs.TryGetValue(command, out var program);
var isRun = program.Start();
if (isRun) continue;
break;
}
}
protected override void AfterRun()
{
if (!InApp)
Console.WriteLine($"{OSConsts.NAME} is shutting down.");
Console.WriteLine($"{ComConsts.NAME} is shutting down.");
}
}
}

View file

@ -1,15 +1,20 @@
// TOMAS is licensed under the MPL 2.0 license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Tomas.Interface.Shell;
using Tomas.Kernel.Programs;
using Tomas.Terminal.Programs;
namespace Tomas.Kernel
{
public struct OSConsts
{
/// <summary>
/// Name of the operating system
/// </summary>
public const string NAME = "TOMAS";
public static string Version = $"{ThisAssembly.Git.SemVer.Major}.{ThisAssembly.Git.SemVer.Minor}.{ThisAssembly.Git.SemVer.Patch}";
public static string VersionGit = $"{Version}-{ThisAssembly.Git.Commit}";
public static Dictionary<string, IProgram> Programs => new Dictionary<string, IProgram>()
{
{"about", new About()},
{"fensay", new FenSay()},
{"clear", new Clear()}
};
}
}

View file

@ -0,0 +1,21 @@
using System;
using Tomas.Common;
using Tomas.Interface.Shell;
using Tomas.Kernel;
namespace Tomas.Terminal.Programs
{
public class About : IProgram
{
public bool Start()
{
Console.WriteLine($"{ComConsts.NAME} v{ComConsts.VersionGit}");
var progs = OSConsts.Programs;
foreach (var commands in progs.Keys)
Console.WriteLine(commands);
return true;
}
}
}

View file

@ -1,21 +0,0 @@
// TOMAS is licensed under the MPL 2.0 license.
// See the LICENSE file in the project root for more information.
using System;
namespace Tomas.Kernel.Programs
{
class AboutApp : App
{
public AboutApp(Kernel system) : base(system)
{
}
public override void Start()
{
Console.WriteLine($"{OSConsts.NAME} v{OSConsts.VersionGit}");
Console.WriteLine("TOMAS, an abbreviation of Tony's Managed Operating System, is a operating system written in C# using the COSMOS framework.");
base.Start();
}
}
}

View file

@ -1,32 +0,0 @@
// TOMAS is licensed under the MPL 2.0 license.
// See the LICENSE file in the project root for more information.
using sys = Cosmos.System;
namespace Tomas.Kernel.Programs
{
/// <summary>
/// Basic framework for building terminal applications.
/// </summary>
public abstract class App
{
protected App(Kernel system)
{
System = system;
}
Kernel System { get; set; }
/// <summary>
/// Main entry point of the program
/// </summary>
public virtual void Start()
{
System.InApp = true;
var isRKey = sys.KeyboardManager.ReadKey().Key == sys.ConsoleKeyEx.R;
if (sys.KeyboardManager.ControlPressed && isRKey)
System.Restart();
}
}
}

25
src/Tomas.Kernel/Shell.cs Normal file
View file

@ -0,0 +1,25 @@
// TOMAS is licensed under the MPL 2.0 license.
// See the LICENSE file in the project root for more information.
using System;
using Tomas.Common;
using Tomas.Interface.Shell;
using Tomas.Kernel.Programs;
using Sys = Cosmos.System;
namespace Tomas.Kernel
{
public class Shell : IShell
{
const char SYMBOL = '$';
public string ReadLine
{
get
{
Console.Write(SYMBOL);
var readl = Console.ReadLine();
return readl;
}
}
}
}

View file

@ -1,84 +0,0 @@
// TOMAS is licensed under the MPL 2.0 license.
// See the LICENSE file in the project root for more information.
using System;
using Sys = Cosmos.System;
namespace Tomas.Kernel
{
public class Terminal
{
const char SYMBOL = '$';
static void Commands(string command)
{
switch (command)
{
case "fensay":
Console.WriteLine(EasterEggs.FenSay);
break;
case "version":
Console.WriteLine(OSConsts.VersionGit);
break;
case "reboot":
var rbq = ReadLine($"Are you sure you want to {command}? 1) Yes 2) No");
switch (rbq)
{
case "1":
case "yes":
Sys.Power.Reboot();
break;
case "2":
case "no":
break;
}
break;
case "shutdown":
var shq = ReadLine($"Are you sure you want to {command}? 1) Yes 2) No");
switch (shq)
{
case "1":
case "yes":
Sys.Power.Shutdown();
break;
case "2":
case "no":
break;
}
break;
case "ls":
var dirs = TomFS.ListDirectories(command.Remove(0, 2));
Console.WriteLine(dirs);
break;
}
}
/// <summary>
/// Same as Console.ReadLine() but adds a shell command symbol
/// before the input.
/// </summary>
/// <returns>user's input</returns>
public static string ReadLine()
{
Console.Write(SYMBOL);
var readl = Console.ReadLine();
Commands(readl);
return readl;
}
/// <summary>
/// Provides a message to the user above the shell command symbol.
/// </summary>
/// <param name="message"></param>
/// <returns>user's input</returns>
public static string ReadLine(string message)
{
Console.WriteLine(message);
Console.Write(SYMBOL);
var readl = Console.ReadLine();
Commands(readl);
return readl;
}
}
}

View file

@ -37,6 +37,7 @@
<ItemGroup>
<ProjectReference Include="..\Tomas.Common\Tomas.Common.csproj" />
<ProjectReference Include="..\Tomas.Interface\Tomas.Interface.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,19 @@
namespace Tomas.Terminal
{
class Program
{
static void Main()
{
while (true)
{
var shell = new Shell();
var command = shell.ReadLine;
TermConsts.Programs.TryGetValue(command, out var program);
var isRun = program.Start();
if (isRun) continue;
break;
}
}
}
}

View file

@ -0,0 +1,21 @@
using System;
using Tomas.Common;
using Tomas.Interface.Shell;
namespace Tomas.Terminal.Programs
{
public class About : IProgram
{
public bool Start()
{
Console.WriteLine($"{ComConsts.NAME} v{ComConsts.VersionGit}{Environment.NewLine}");
Console.WriteLine("Commands:");
var progs = TermConsts.Programs;
foreach (var commands in progs.Keys)
Console.WriteLine(commands);
return true;
}
}
}

View file

@ -0,0 +1,20 @@
using System;
using Tomas.Interface.Shell;
namespace Tomas.Terminal
{
public class Shell : IShell
{
const char SYMBOL = '$';
public string ReadLine
{
get
{
Console.Write(SYMBOL);
var readl = Console.ReadLine();
return readl;
}
}
}
}

View file

@ -0,0 +1,17 @@
using System.Collections.Generic;
using Tomas.Interface.Shell;
using Tomas.Kernel.Programs;
using Tomas.Terminal.Programs;
namespace Tomas.Terminal
{
public struct TermConsts
{
public static Dictionary<string, IProgram> Programs => new Dictionary<string, IProgram>()
{
{"about", new About()},
{"fensay", new FenSay()},
{"clear", new Clear()}
};
}
}

View file

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<LangVersion>8</LangVersion>
<Nullable>warnings</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Tomas.Common\Tomas.Common.csproj" />
<ProjectReference Include="..\Tomas.Interface\Tomas.Interface.csproj" />
</ItemGroup>
</Project>