mirror of
https://github.com/marcusDenslow/FERRUM.git
synced 2026-10-25 15:48:50 +01:00
409 lines
9.2 KiB
C
409 lines
9.2 KiB
C
/**
|
|
* bookmarks.c
|
|
* Implementation of directory bookmarks functionality
|
|
*/
|
|
|
|
#include "bookmarks.h"
|
|
#include <fcntl.h>
|
|
#include <termios.h>
|
|
|
|
// Global variables for bookmark storage
|
|
BookmarkEntry *bookmarks = NULL;
|
|
int bookmark_count = 0;
|
|
int bookmark_capacity = 0;
|
|
|
|
// Path to the bookmarks file
|
|
char bookmarks_file_path[PATH_MAX];
|
|
|
|
/**
|
|
* Initialize the bookmark system
|
|
*/
|
|
void init_bookmarks(void) {
|
|
// Set initial capacity
|
|
bookmark_capacity = 10;
|
|
bookmarks =
|
|
(BookmarkEntry *)malloc(bookmark_capacity * sizeof(BookmarkEntry));
|
|
|
|
if (!bookmarks) {
|
|
fprintf(stderr, "lsh: allocation error in init_bookmarks\n");
|
|
return;
|
|
}
|
|
|
|
// Determine bookmarks file location - in user's home directory
|
|
char *home_dir = getenv("HOME");
|
|
if (home_dir) {
|
|
snprintf(bookmarks_file_path, PATH_MAX, "%s/.lsh_bookmarks", home_dir);
|
|
} else {
|
|
// Fallback to current directory if HOME not available
|
|
strcpy(bookmarks_file_path, ".lsh_bookmarks");
|
|
}
|
|
|
|
// Load bookmarks from file
|
|
load_bookmarks();
|
|
}
|
|
|
|
/**
|
|
* Clean up the bookmark system
|
|
*/
|
|
void cleanup_bookmarks(void) {
|
|
if (!bookmarks)
|
|
return;
|
|
|
|
// Free all bookmark entries
|
|
for (int i = 0; i < bookmark_count; i++) {
|
|
free(bookmarks[i].name);
|
|
free(bookmarks[i].path);
|
|
}
|
|
|
|
// Free the array
|
|
free(bookmarks);
|
|
bookmarks = NULL;
|
|
bookmark_count = 0;
|
|
bookmark_capacity = 0;
|
|
}
|
|
|
|
/**
|
|
* Shutdown the bookmark system
|
|
*/
|
|
void shutdown_bookmarks(void) {
|
|
// Save bookmarks to file
|
|
save_bookmarks();
|
|
|
|
// Clean up
|
|
cleanup_bookmarks();
|
|
}
|
|
|
|
/**
|
|
* Load bookmarks from file
|
|
*/
|
|
int load_bookmarks(void) {
|
|
FILE *fp = fopen(bookmarks_file_path, "r");
|
|
if (!fp) {
|
|
return 0; // File doesn't exist or can't be opened
|
|
}
|
|
|
|
char line[LSH_RL_BUFSIZE];
|
|
char name[LSH_RL_BUFSIZE / 2];
|
|
char path[LSH_RL_BUFSIZE / 2];
|
|
|
|
while (fgets(line, sizeof(line), fp)) {
|
|
// Skip comments and empty lines
|
|
if (line[0] == '#' || line[0] == '\n') {
|
|
continue;
|
|
}
|
|
|
|
// Try to parse using tab as delimiter first
|
|
char *tab = strchr(line, '\t');
|
|
if (tab) {
|
|
// Split at tab
|
|
*tab = '\0';
|
|
strncpy(name, line, sizeof(name) - 1);
|
|
name[sizeof(name) - 1] = '\0';
|
|
strncpy(path, tab + 1, sizeof(path) - 1);
|
|
path[sizeof(path) - 1] = '\0';
|
|
|
|
// Remove newline if present
|
|
char *newline = strchr(path, '\n');
|
|
if (newline) {
|
|
*newline = '\0';
|
|
}
|
|
|
|
add_bookmark(name, path);
|
|
} else {
|
|
// Parse in name=path format as fallback
|
|
if (sscanf(line, "%[^=]=%s", name, path) == 2) {
|
|
add_bookmark(name, path);
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Save bookmarks to file
|
|
*/
|
|
int save_bookmarks(void) {
|
|
FILE *fp = fopen(bookmarks_file_path, "w");
|
|
if (!fp) {
|
|
fprintf(stderr, "lsh: error saving bookmarks to %s\n", bookmarks_file_path);
|
|
return 0;
|
|
}
|
|
|
|
// Write file header
|
|
time_t t = time(NULL);
|
|
struct tm *tm_info = localtime(&t);
|
|
char timestamp[26];
|
|
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", tm_info);
|
|
|
|
fprintf(fp, "# LSH Bookmarks - Last updated: %s\n\n", timestamp);
|
|
|
|
// Write each bookmark
|
|
for (int i = 0; i < bookmark_count; i++) {
|
|
fprintf(fp, "%s\t%s\n", bookmarks[i].name, bookmarks[i].path);
|
|
}
|
|
|
|
fclose(fp);
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Add a new bookmark
|
|
*/
|
|
int add_bookmark(const char *name, const char *path) {
|
|
if (!name || !path) {
|
|
return 0;
|
|
}
|
|
|
|
// Check if bookmark already exists
|
|
for (int i = 0; i < bookmark_count; i++) {
|
|
if (strcmp(bookmarks[i].name, name) == 0) {
|
|
// Update existing bookmark
|
|
free(bookmarks[i].path);
|
|
bookmarks[i].path = strdup(path);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Check if we need to expand the array
|
|
if (bookmark_count >= bookmark_capacity) {
|
|
bookmark_capacity *= 2;
|
|
BookmarkEntry *new_bookmarks = (BookmarkEntry *)realloc(
|
|
bookmarks, bookmark_capacity * sizeof(BookmarkEntry));
|
|
if (!new_bookmarks) {
|
|
fprintf(stderr, "lsh: allocation error in add_bookmark\n");
|
|
return 0;
|
|
}
|
|
bookmarks = new_bookmarks;
|
|
}
|
|
|
|
// Add new bookmark
|
|
bookmarks[bookmark_count].name = strdup(name);
|
|
bookmarks[bookmark_count].path = strdup(path);
|
|
bookmark_count++;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Remove a bookmark
|
|
*/
|
|
int remove_bookmark(const char *name) {
|
|
if (!name) {
|
|
return 0;
|
|
}
|
|
|
|
for (int i = 0; i < bookmark_count; i++) {
|
|
if (strcmp(bookmarks[i].name, name) == 0) {
|
|
// Free memory for this bookmark
|
|
free(bookmarks[i].name);
|
|
free(bookmarks[i].path);
|
|
|
|
// Shift remaining bookmarks down
|
|
for (int j = i; j < bookmark_count - 1; j++) {
|
|
bookmarks[j] = bookmarks[j + 1];
|
|
}
|
|
|
|
bookmark_count--;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0; // Bookmark not found
|
|
}
|
|
|
|
/**
|
|
* Find a bookmark by name
|
|
*/
|
|
BookmarkEntry *find_bookmark(const char *name) {
|
|
for (int i = 0; i < bookmark_count; i++) {
|
|
if (strcmp(bookmarks[i].name, name) == 0) {
|
|
return &bookmarks[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* Command handler for the "bookmark" command
|
|
*/
|
|
int lsh_bookmark(char **args) {
|
|
char cwd[PATH_MAX];
|
|
|
|
// No arguments - add bookmark for current directory
|
|
if (args[1] == NULL) {
|
|
printf("Usage: bookmark <name> [path]\n");
|
|
printf("If path is omitted, the current directory is used.\n");
|
|
return 1;
|
|
}
|
|
|
|
// Get current working directory if no path is specified
|
|
if (args[2] == NULL) {
|
|
if (getcwd(cwd, sizeof(cwd)) == NULL) {
|
|
perror("lsh: getcwd");
|
|
return 1;
|
|
}
|
|
add_bookmark(args[1], cwd);
|
|
printf("Bookmark added: %s -> %s\n", args[1], cwd);
|
|
} else {
|
|
add_bookmark(args[1], args[2]);
|
|
printf("Bookmark added: %s -> %s\n", args[1], args[2]);
|
|
}
|
|
|
|
// Save bookmarks to file
|
|
save_bookmarks();
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Command handler for the "bookmarks" command
|
|
*/
|
|
int lsh_bookmarks(char **args) {
|
|
if (bookmark_count == 0) {
|
|
printf("No bookmarks defined.\n");
|
|
printf("Use 'bookmark <name> [path]' to add a bookmark.\n");
|
|
return 1;
|
|
}
|
|
|
|
// Check if we should use a pager
|
|
if (bookmark_count > 20) {
|
|
// Check for neovim first
|
|
FILE *test_nvim = popen("which nvim 2>/dev/null", "r");
|
|
if (test_nvim) {
|
|
char buffer[128];
|
|
if (fgets(buffer, sizeof(buffer), test_nvim) != NULL) {
|
|
pclose(test_nvim);
|
|
FILE *pager = popen("nvim -R -c 'set nonumber' -", "w");
|
|
if (pager) {
|
|
fprintf(pager, "LSH Bookmarks:\n\n");
|
|
for (int i = 0; i < bookmark_count; i++) {
|
|
fprintf(pager, " %s -> %s\n", bookmarks[i].name, bookmarks[i].path);
|
|
}
|
|
pclose(pager);
|
|
return 1;
|
|
}
|
|
}
|
|
pclose(test_nvim);
|
|
|
|
// Try vim
|
|
FILE *test_vim = popen("which vim 2>/dev/null", "r");
|
|
if (test_vim) {
|
|
char buffer[128];
|
|
if (fgets(buffer, sizeof(buffer), test_vim) != NULL) {
|
|
pclose(test_vim);
|
|
FILE *pager = popen("vim -R -c 'set nonumber' -", "w");
|
|
if (pager) {
|
|
fprintf(pager, "LSH Bookmarks:\n\n");
|
|
for (int i = 0; i < bookmark_count; i++) {
|
|
fprintf(pager, " %s -> %s\n", bookmarks[i].name, bookmarks[i].path);
|
|
}
|
|
pclose(pager);
|
|
return 1;
|
|
}
|
|
}
|
|
pclose(test_vim);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Simple output if no pager available or bookmark count is small
|
|
printf("LSH Bookmarks:\n\n");
|
|
|
|
// Use ANSI escape codes for colored output
|
|
for (int i = 0; i < bookmark_count; i++) {
|
|
printf(" " ANSI_COLOR_GREEN "%s" ANSI_COLOR_RESET " -> %s\n",
|
|
bookmarks[i].name, bookmarks[i].path);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Command handler for the "goto" command
|
|
*/
|
|
int lsh_goto(char **args) {
|
|
if (args[1] == NULL) {
|
|
printf("Usage: goto <bookmark_name>\n");
|
|
return 1;
|
|
}
|
|
|
|
BookmarkEntry *bookmark = find_bookmark(args[1]);
|
|
if (bookmark) {
|
|
if (chdir(bookmark->path) != 0) {
|
|
perror("lsh: chdir");
|
|
return 1;
|
|
}
|
|
printf("Changed directory to: %s\n", bookmark->path);
|
|
} else {
|
|
printf("Bookmark '%s' not found.\n", args[1]);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Command handler for the "unbookmark" command
|
|
*/
|
|
int lsh_unbookmark(char **args) {
|
|
if (args[1] == NULL) {
|
|
printf("Usage: unbookmark <bookmark_name>\n");
|
|
return 1;
|
|
}
|
|
|
|
if (remove_bookmark(args[1])) {
|
|
printf("Bookmark '%s' removed.\n", args[1]);
|
|
save_bookmarks();
|
|
} else {
|
|
printf("Bookmark '%s' not found.\n", args[1]);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Get bookmark names for tab completion
|
|
*/
|
|
char **get_bookmark_names(int *count) {
|
|
if (bookmark_count == 0 || !count) {
|
|
*count = 0;
|
|
return NULL;
|
|
}
|
|
|
|
char **names = (char **)malloc(bookmark_count * sizeof(char *));
|
|
if (!names) {
|
|
*count = 0;
|
|
return NULL;
|
|
}
|
|
|
|
for (int i = 0; i < bookmark_count; i++) {
|
|
names[i] = strdup(bookmarks[i].name);
|
|
}
|
|
|
|
*count = bookmark_count;
|
|
return names;
|
|
}
|
|
|
|
/**
|
|
* Find a matching bookmark by partial name
|
|
*/
|
|
char *find_matching_bookmark(const char *partial_name) {
|
|
if (!partial_name || strlen(partial_name) == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
// If only one bookmark exists, return it if there's any match
|
|
if (bookmark_count == 1) {
|
|
return strdup(bookmarks[0].name);
|
|
}
|
|
|
|
// Look for partial matches
|
|
for (int i = 0; i < bookmark_count; i++) {
|
|
if (strncasecmp(bookmarks[i].name, partial_name, strlen(partial_name)) == 0) {
|
|
return strdup(bookmarks[i].name);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
} |