Compare commits

...

8 Commits

Author SHA1 Message Date
b25a5cde19 Add Bobfile 2025-04-11 19:18:11 +10:00
Maxwell Jeffress
aa91afacba Update da readme 2025-04-07 20:28:53 +10:00
Maxwell Jeffress
b2b0d96831 Merge branch 'main' of https://git.maxwellj.xyz/max/space 2025-04-07 20:25:08 +10:00
Maxwell Jeffress
d2641fc2ca Push some stuff I forgot to push 2 weeks ago 2025-04-07 20:24:48 +10:00
Maxwell Jeffress
f01ea8af6d Update README 2025-03-24 15:46:46 +11:00
Maxwell Jeffress
862336da96 Merge branch 'main' of https://git.maxwellj.xyz/max/space 2025-03-24 15:37:01 +11:00
Maxwell Jeffress
9f05a58157 Substitutions 2025-03-24 15:36:08 +11:00
cb9a5ea202 Update README.md 2025-03-24 14:52:21 +11:00
3 changed files with 216 additions and 44 deletions

4
Bobfile Normal file
View File

@@ -0,0 +1,4 @@
compiler "g++";
binary "space";
source "src/main.cpp";
compile;

View File

@@ -2,11 +2,11 @@
## What is space? ## What is space?
Space is a shell. Not much else. Space is a shell. There is a simple substitutions feature, which can substitute something for something else.
## How to use? ## How to use?
1. Compile (`g++ src/main.cpp -o space`). 1. Compile (`g++ src/main.cpp -o space`). (may differ by OS or personal preference, this works for Linux)
2. Run the outputted binary (`space`). 2. Run the outputted binary (`space`).
@@ -14,6 +14,14 @@ Space is a shell. Not much else.
If you need to change your directory, run `cd (directory)`. If you need to exit the shell, type `exit`. If you need to change your directory, run `cd (directory)`. If you need to exit the shell, type `exit`.
The path is hard-coded into the source code, change the vector on line 40 to add directories to your path. If you would like to create a substitution, type `sub (string) (anotherstring)`. List all your substitutions with `listsubs`. By default, `ls` is substituted with `ls -l`. If you'd like to make your substitutions include extra command line arguments, write your arguments inside quotation marks.
Change environment variables with `set key value`. At present there is no way to access environment variables.
A file located at ~/.config/space/Spacefile is essentially a script that will run on startup. Add any commands or substitutions that you would like in this file. These will be run for you.
The path is set with the $PATH environment variable.
The prompt is not able to be changed. Yes, I'm forcing my opinion on you.
If you want to run an executable in your current directory, there's no need for the ./ (keep in mind Space will prioritise local executables over ones in the path) If you want to run an executable in your current directory, there's no need for the ./ (keep in mind Space will prioritise local executables over ones in the path)

View File

@@ -1,32 +1,73 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <ctime>
#include <filesystem> #include <filesystem>
#include <unistd.h> #include <unistd.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/types.h> #include <sys/types.h>
#include <pwd.h> #include <pwd.h>
#include <cstring> #include <cstring>
#include <limits.h>
#include <fstream>
#include <signal.h>
using namespace std; using namespace std;
vector<string> builtInFunctions = {"exit", "cd"}; vector<string> functions = {"exit", "cd", "sub", "listsubs", "set", "get", "run"};
vector<pair<string, vector<string>>> substitutions;
void log(string input) { void log(string input) {
cout << input << endl; cout << input << endl;
} }
string getTime() {
time_t rawtime;
struct tm * timeinfo;
char buffer[40];
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(buffer, sizeof(buffer),"%H:%M:%S", timeinfo);
string str(buffer);
return str;
}
string prompt() { string prompt() {
string input; string input;
cout << filesystem::current_path() << " > "; char hostname[HOST_NAME_MAX];
gethostname(hostname, HOST_NAME_MAX);
cout << "\x1B[0m{" << getTime() << "}\x1B[32m " << getenv("USER") << "@" << hostname << "\x1B[96m " << string(filesystem::current_path()) << endl << "\x1B[0m> ";
getline(cin, input); getline(cin, input);
return input; return input;
} }
vector<string> getPath() {
string pathstr = getenv("PATH");
if (pathstr == "") {
log("WARNING! SPACE CANNOT FIND THE PATH! Please ensure your path is set as an environment variable in your Spacefile, or one of Space's parents has set the PATH environment variable. For now, enjoy the default path :)");
} else {
vector<string> path;
string buffer;
for (int i = 0; i < pathstr.size(); i++) {
if (pathstr[i] == ':') {
path.push_back(buffer);
buffer = "";
} else {
buffer += pathstr[i];
}
}
path.push_back(buffer);
return path;
}
return {"/bin", "/usr/bin", "/usr/local/bin"};
}
string findExecutable(string executable) { string findExecutable(string executable) {
for (int i = 0; i < builtInFunctions.size(); i++) { for (int i = 0; i < functions.size(); i++) {
if (builtInFunctions[i] == executable) { if (functions[i] == executable) {
return executable; return executable;
} }
} }
@@ -37,7 +78,7 @@ string findExecutable(string executable) {
return executable; return executable;
} }
string output; string output;
vector<string> path = {"/bin", "/usr/bin", "/usr/local/bin"}; vector<string> path = getPath();
for (int i = 0; i < path.size(); i++) { for (int i = 0; i < path.size(); i++) {
output = path[i] + "/" + executable; output = path[i] + "/" + executable;
if (filesystem::exists(output)) { if (filesystem::exists(output)) {
@@ -58,8 +99,11 @@ string getHomeDir() {
vector<string> tokenise(string input) { vector<string> tokenise(string input) {
vector<string> output; vector<string> output;
string currentArg; string currentArg;
bool isString = false;
for (int i = 0; i < input.size(); i++) { for (int i = 0; i < input.size(); i++) {
if (input[i] == ' ' && !currentArg.empty()) { if (input[i] == '"') {
isString = !isString;
} else if (input[i] == ' ' && !currentArg.empty() && !isString) {
output.push_back(currentArg); output.push_back(currentArg);
currentArg.clear(); currentArg.clear();
} else if (input[i] == '~') { } else if (input[i] == '~') {
@@ -71,19 +115,97 @@ vector<string> tokenise(string input) {
if (!currentArg.empty()) { if (!currentArg.empty()) {
output.push_back(currentArg); output.push_back(currentArg);
} }
for (int i = 0; i < substitutions.size(); i++) {
for (int j = 0; j < output.size(); j++) {
if (output[j] == substitutions[i].first) {
output.erase(output.begin() + j);
int substitutionSize = substitutions[i].second.size();
for (int k = 0; k < substitutionSize; k++) {
output.insert(output.begin() + j, substitutions[i].second[k]);
j++;
}
j -= substitutionSize;
break;
}
}
}
string executableLocation = findExecutable(output[0]); string executableLocation = findExecutable(output[0]);
if (!executableLocation.empty()) { if (!executableLocation.empty()) {
output[0] = executableLocation; output[0] = executableLocation;
} else { } else {
log("Couldn't find an executable in the path"); log("Couldn't find an executable in the path");
output.clear();
} }
return output;
}
vector<string> tokeniseSubstitutions(string input) {
vector<string> output;
string currentArg;
bool isString = false;
for (int i = 0; i < input.size(); i++) {
if (input[i] == '"') {
isString = !isString;
} else if (input[i] == ' ' && !isString) {
if (!currentArg.empty()) {
output.push_back(currentArg);
currentArg.clear();
}
} else {
currentArg += input[i];
}
}
if (!currentArg.empty()) {
output.push_back(currentArg);
}
return output; return output;
} }
int runProcess(vector<string> args) { int runProcess(vector<string> args) {
if (args[0] == "exit") {
exit(0);
} else if (args[0] == "cd") {
if (args.size() == 1) {
log("cd requires an argument");
return 1;
} else {
filesystem::current_path(args[1]);
}
} else if (args[0] == "set") {
if (args.size() < 3) {
log("set requires 2 arguments");
return 1;
}
string envStr = (args[1] + "=" + args[2]);
char* cEnvStr = strdup(envStr.c_str());
putenv(cEnvStr);
} else if (args[0] == "get") {
if (args.size() < 2) {
log("get requires an argument");
return 1;
}
char* value = getenv(args[1].c_str());
if (value == nullptr) {
log("Environment variable " + args[1] + " not found");
return 1;
}
cout << value << endl;
} else if (args[0] == "sub") {
if (args.size() < 3) {
log("substitute requires 2 arguments");
return 1;
}
vector<string> subArgs = tokeniseSubstitutions(args[2]);
substitutions.push_back({args[1], subArgs});
} else if (args[0] == "listsubs") {
log("Substitutions:");
for (int i = 0; i < substitutions.size(); i++) {
string substring;
for (int j = 0; j < substitutions[i].second.size(); j++) {
substring += substitutions[i].second[j] + " ";
}
cout << substitutions[i].first << " -> " << substring << endl;
}
} else {
pid_t pid = fork(); pid_t pid = fork();
if (pid == -1) { if (pid == -1) {
cerr << "Fork failed!" << endl; cerr << "Fork failed!" << endl;
@@ -108,27 +230,61 @@ int runProcess(vector<string> args) {
return WEXITSTATUS(status); return WEXITSTATUS(status);
} }
return -1; return -1;
}
return 0;
} }
void runScript(string script) {
string scriptLine;
ifstream scriptFile(script);
while (getline(scriptFile, scriptLine)) {
vector<string> tokens = tokenise(scriptLine);
if (tokens.empty()) continue;
int returnCode = runProcess(tokens);
if (returnCode != 0) {
log("Script error:\nCommand " + tokens[0] + " failed with exit code " + to_string(returnCode));
}
}
scriptFile.close();
}
void doStartup() {
struct passwd* pw = getpwuid(getuid());
const char* homedir = pw->pw_dir;
string configLocation = string(homedir) + "/.config/space/Spacefile";
if (filesystem::exists(configLocation)) {
string config;
ifstream configFile(configLocation);
while (getline(configFile, config)) {
vector<string> tokens = tokenise(config);
if (tokens.empty()) continue;
int returnCode = runProcess(tokens);
if (returnCode != 0) {
log("Config file error:\nCommand " + tokens[0] + " failed with exit code " + to_string(returnCode));
}
}
configFile.close();
} else {
log("Spacefile does not exist");
}
}
void handler(int signum);
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
signal(SIGINT, handler);
if (argc > 1) {
runScript(argv[2]);
}
doStartup();
bool continueLoop = true; bool continueLoop = true;
while (continueLoop) { while (continueLoop) {
string input = prompt(); string input = prompt();
if (input == "") { if (input == "") {
break; continue;
} }
vector<string> tokens = tokenise(input); vector<string> tokens = tokenise(input);
auto path = filesystem::current_path(); auto path = filesystem::current_path();
if (tokens[0] == "exit") {
exit(0);
} else if (tokens[0] == "cd") {
if (tokens.size() == 1) {
log("cd requires an argument");
} else {
filesystem::current_path(tokens[1]);
}
continue;
}
if (tokens.empty()) { if (tokens.empty()) {
continue; continue;
} }
@@ -139,3 +295,7 @@ int main(int argc, char *argv[]) {
} }
return 0; return 0;
} }
void handler(int signum) {
main(1, nullptr);
}