Skip to content

Instantly share code, notes, and snippets.

@HalanoSiblee
Created June 8, 2026 16:10
Show Gist options
  • Select an option

  • Save HalanoSiblee/3848ede42725c2ea347de356853e78f4 to your computer and use it in GitHub Desktop.

Select an option

Save HalanoSiblee/3848ede42725c2ea347de356853e78f4 to your computer and use it in GitHub Desktop.
Tab file auto-comp Exa
//g++ -std=c++17 main.cpp -o editor -lncurses
#include <iostream>
#include <string>
#include <vector>
#include <filesystem>
#include <ncurses.h>
namespace fs = std::filesystem;
struct CompletionState {
bool is_active = false;
std::vector<std::string> matches;
size_t current_idx = 0;
size_t trigger_start_pos = 0;
};
// Scans directory for files starting with the specified prefix
void gatherMatches(const std::string& current_word, CompletionState& state) {
state.matches.clear();
state.current_idx = 0;
size_t last_slash = current_word.find_last_of('/');
if (last_slash == std::string::npos) return;
// Split into directory and file prefix
// If last_slash is 0, the directory is just "/" (absolute root)
std::string dir_part = (last_slash == 0) ? "/" : current_word.substr(0, last_slash + 1);
std::string file_prefix = current_word.substr(last_slash + 1);
try {
fs::path search_path(dir_part);
if (!fs::exists(search_path) || !fs::is_directory(search_path)) return;
for (const auto& entry : fs::directory_iterator(search_path)) {
std::string name = entry.path().filename().string();
if (name.rfind(file_prefix, 0) == 0) {
// Construct the full match string cleanly
std::string full_match = dir_part;
if (dir_part.back() != '/') {
full_match += "/";
}
full_match += name;
if (entry.is_directory()) {
full_match += "/";
}
state.matches.push_back(full_match);
}
}
} catch (...) {
// Suppress permission denied errors for certain system root directories
}
}
int main() {
// Initialize ncurses
initscr();
raw();
keypad(stdscr, TRUE);
noecho();
std::string buffer = "";
CompletionState comp;
printw("=== Ncurses Autocomplete Editor Simulation ===\n");
printw("Instructions: Start typing. Supports './', '../', and absolute '/' paths.\n");
printw("Press TAB to cycle options. Press ESC to exit.\n");
printw("----------------------------------------------------------------------\n\n");
int start_y, start_x;
getyx(stdscr, start_y, start_x);
while (true) {
move(start_y, start_x);
clrtoeol();
printw("%s", buffer.c_str());
refresh();
int ch = getch();
if (ch == 27) { // ESC Key
break;
}
else if (ch == '\t') { // TAB Key
if (!comp.is_active) {
size_t space_idx = buffer.find_last_of(" \"'");
size_t word_start = (space_idx == std::string::npos) ? 0 : space_idx + 1;
std::string current_word = buffer.substr(word_start);
// FIXED TRIGGER: Check for ./ , ../ , OR absolute paths starting with /
if (current_word.rfind("./", 0) == 0 ||
current_word.rfind("../", 0) == 0 ||
(current_word.rfind("/", 0) == 0)) {
comp.trigger_start_pos = word_start;
gatherMatches(current_word, comp);
if (!comp.matches.empty()) {
comp.is_active = true;
}
}
}
if (comp.is_active && !comp.matches.empty()) {
buffer.erase(comp.trigger_start_pos);
buffer += comp.matches[comp.current_idx];
comp.current_idx = (comp.current_idx + 1) % comp.matches.size();
}
}
else if (ch == KEY_BACKSPACE || ch == 127 || ch == 8) {
if (!buffer.empty()) {
buffer.pop_back();
}
comp.is_active = false;
}
else {
buffer.push_back(static_cast<char>(ch));
comp.is_active = false;
}
}
endwin();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment