feat: add rudimentary tab completion for executables to shell
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* tabcompletion.cpp
|
||||
* Tab completion module
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#include <montauk/string.h>
|
||||
#include <montauk/syscall.h>
|
||||
|
||||
#define RD_MAX 128
|
||||
|
||||
/*
|
||||
Does the file path end with .elf?
|
||||
*/
|
||||
bool is_executable(const char* path) {
|
||||
size_t len = montauk::slen(path);
|
||||
|
||||
if (path[len - 1] == 'f' &&
|
||||
path[len - 2] == 'l' &&
|
||||
path[len - 3] == 'e' &&
|
||||
path[len - 4] == '.')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
i.e., "shell.elf" => "shell"
|
||||
*/
|
||||
const char* strip_elf_extension(const char* path) {
|
||||
size_t len = montauk::slen(path);
|
||||
|
||||
char* p = (char* ) path;
|
||||
p[len - 4] = '\0';
|
||||
|
||||
return (const char*)p;
|
||||
}
|
||||
|
||||
int get_completions( // returns no. of results
|
||||
char* string, // String to match/complete
|
||||
char** array, // Array of strings containing completions
|
||||
int arrayMax
|
||||
) {
|
||||
|
||||
const char* names[RD_MAX] = { };
|
||||
|
||||
int n = montauk::readdir("0:/os", names, RD_MAX);
|
||||
int r = 0;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
/*
|
||||
Shift by 3 characters (names[i] + 3):
|
||||
"os/shell.elf" => "shell.elf"
|
||||
|
||||
This is somewhat of a workaround.
|
||||
*/
|
||||
if (montauk::starts_with(names[i] + 3, (const char*)string)) {
|
||||
if (
|
||||
r > arrayMax ||
|
||||
!is_executable(names[i])
|
||||
) break;
|
||||
|
||||
char* p = (char *)names[i] + 3;
|
||||
strip_elf_extension(p);
|
||||
|
||||
array[r] = (char *)p;
|
||||
r++;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
Reference in New Issue
Block a user