diff --git a/aliases.o b/aliases.o index 327b977..bd1ded7 100644 Binary files a/aliases.o and b/aliases.o differ diff --git a/autocorrect.o b/autocorrect.o index 6e277d5..152a731 100644 Binary files a/autocorrect.o and b/autocorrect.o differ diff --git a/bookmarks.o b/bookmarks.o index 5390898..22fa252 100644 Binary files a/bookmarks.o and b/bookmarks.o differ diff --git a/builtins.c b/builtins.c index 18f665b..9318ba8 100644 --- a/builtins.c +++ b/builtins.c @@ -38,7 +38,7 @@ char *builtin_str[] = { "bookmark", "bookmarks", "goto", "unbookmark", "focus_timer", "weather", "grep", "grep-text", "ripgrep", "fzf", "clip", "echo", "theme", "loc", "git_status", - "gg", "ls", "stats", + "gg", "ls", "stats", "monitor", }; // Array of function pointers to built-in command implementations @@ -53,7 +53,7 @@ int (*builtin_func[])(char **) = { &lsh_ripgrep, &lsh_fzf_native, &lsh_clip, &lsh_echo, &lsh_theme, &lsh_loc, &lsh_git_status, &lsh_gg, lsh_dir, - &lsh_stats, + &lsh_stats, &builtin_monitor, }; /** diff --git a/builtins.h b/builtins.h index 8b2ed4e..291e6f1 100644 --- a/builtins.h +++ b/builtins.h @@ -7,6 +7,7 @@ #define BUILTINS_H #include "common.h" +#include "system_monitor.h" #include // Syntax highlighting definitions using ANSI colors @@ -85,9 +86,8 @@ void lsh_add_to_history(const char *command); // Get number of builtin commands int lsh_num_builtins(void); - - // Expose the builtin command strings and function pointers - extern char *builtin_str[]; +// Expose the builtin command strings and function pointers +extern char *builtin_str[]; extern int (*builtin_func[])(char **); /** diff --git a/builtins.o b/builtins.o index 2248deb..8586167 100644 Binary files a/builtins.o and b/builtins.o differ diff --git a/countdown_timer.o b/countdown_timer.o index e255a8d..48534c8 100644 Binary files a/countdown_timer.o and b/countdown_timer.o differ diff --git a/favorite_cities.o b/favorite_cities.o index 59c1383..9a2bd6f 100644 Binary files a/favorite_cities.o and b/favorite_cities.o differ diff --git a/filters.o b/filters.o index 2991410..a4fbb8e 100644 Binary files a/filters.o and b/filters.o differ diff --git a/fzf_native.o b/fzf_native.o index ed1aa60..0c205ac 100644 Binary files a/fzf_native.o and b/fzf_native.o differ diff --git a/git_integration.o b/git_integration.o index a53a97e..ba1067b 100644 Binary files a/git_integration.o and b/git_integration.o differ diff --git a/grep.o b/grep.o index c46edce..9f0b318 100644 Binary files a/grep.o and b/grep.o differ diff --git a/line_reader.o b/line_reader.o index 06ef888..ce74f9b 100644 Binary files a/line_reader.o and b/line_reader.o differ diff --git a/main.o b/main.o index 419f35b..c04b7fb 100644 Binary files a/main.o and b/main.o differ diff --git a/ps_command.o b/ps_command.o index 4f5e1cb..87287b5 100644 Binary files a/ps_command.o and b/ps_command.o differ diff --git a/ripgrep.o b/ripgrep.o index 5cc9f04..89b8d06 100644 Binary files a/ripgrep.o and b/ripgrep.o differ diff --git a/shell b/shell index b136d6f..2f16b67 100755 Binary files a/shell and b/shell differ diff --git a/shell.o b/shell.o index 1f1d5ac..6cb9719 100644 Binary files a/shell.o and b/shell.o differ diff --git a/structured_data.o b/structured_data.o index b5b89cc..f7dea30 100644 Binary files a/structured_data.o and b/structured_data.o differ diff --git a/system_monitor.c b/system_monitor.c new file mode 100644 index 0000000..66c8714 --- /dev/null +++ b/system_monitor.c @@ -0,0 +1,390 @@ +#include "system_monitor.h" +#include "common.h" + +static struct termios old_termios; + +int builtin_monitor(char **args) { + SystemStats stats; + ProcessInfo processes[50]; + int proc_count; + int refresh_rate = 1; // seconds + + if (args[1] != NULL && strcmp(args[1], "--help") == 0) { + printf("monitor: Real-time system monitoring dashboard\n"); + printf("Usage: monitor [refresh_rate]\n"); + printf("Press 'q' to quit, 'r' to refresh immediately\n"); + return 1; + } + + if (args[1] != NULL) { + refresh_rate = atoi(args[1]); + if (refresh_rate < 1) refresh_rate = 1; + } + + // Setup terminal for raw input + tcgetattr(STDIN_FILENO, &old_termios); + struct termios new_termios = old_termios; + new_termios.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &new_termios); + + // Make stdin non-blocking + int flags = fcntl(STDIN_FILENO, F_GETFL, 0); + fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); + + // Enter alternative screen buffer + printf("\033[?1049h"); + hide_cursor(); + fflush(stdout); + + while (1) { + get_system_stats(&stats); + proc_count = get_process_info(processes, 50); + display_dashboard(&stats, processes, proc_count); + + // Check for user input + if (kbhit()) { + char c = getchar(); + if (c == 'q' || c == 'Q') break; + if (c == 'r' || c == 'R') continue; // refresh immediately + } + + sleep(refresh_rate); + } + + // Restore terminal + show_cursor(); + // Exit alternative screen buffer + printf("\033[?1049l"); + tcsetattr(STDIN_FILENO, TCSANOW, &old_termios); + fcntl(STDIN_FILENO, F_SETFL, flags); + fflush(stdout); + return 1; +} + +void display_dashboard(SystemStats *stats, ProcessInfo *processes, int proc_count) { + char buffer[256]; + char display_buffer[8192]; // Large buffer for entire display + char progress_buf[50]; + char mem_used_str[32], mem_total_str[32]; + char disk_read_str[32], disk_write_str[32]; + char net_rx_str[32], net_tx_str[32]; + + time_t now = time(NULL); + struct tm *tm_info = localtime(&now); + + // Format all the data first + float mem_percent = (float)stats->memory_used / stats->memory_total * 100; + format_bytes(stats->memory_used, mem_used_str); + format_bytes(stats->memory_total, mem_total_str); + format_bytes(stats->disk_read, disk_read_str); + format_bytes(stats->disk_write, disk_write_str); + format_bytes(stats->net_rx, net_rx_str); + format_bytes(stats->net_tx, net_tx_str); + + // Build entire display in buffer + int pos = sprintf(display_buffer, "\033[H"); // Move to home position + + pos += sprintf(display_buffer + pos, + "╔══════════════════════════════════════════════════════════════════════════════╗\n" + "║ SYSTEM MONITOR DASHBOARD ║\n" + "║ %02d:%02d:%02d %02d/%02d/%04d ║\n" + "╠══════════════════════════════════════════════════════════════════════════════╣\n", + tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec, + tm_info->tm_mday, tm_info->tm_mon + 1, tm_info->tm_year + 1900); + + // CPU Usage + format_progress_bar((int)stats->cpu_percent, 40, progress_buf); + pos += sprintf(display_buffer + pos, "║ CPU Usage: %s %5.1f%% ║\n", progress_buf, stats->cpu_percent); + + // Memory Usage + format_progress_bar((int)mem_percent, 40, progress_buf); + pos += sprintf(display_buffer + pos, "║ Memory: %s %5.1f%% ║\n", progress_buf, mem_percent); + pos += sprintf(display_buffer + pos, "║ Used: %-15s / %-15s ║\n", + mem_used_str, mem_total_str); + + pos += sprintf(display_buffer + pos, + "║ Disk I/O: Read: %-20s ║\n" + "║ Write: %-20s ║\n" + "║ Network: RX: %-20s ║\n" + "║ TX: %-20s ║\n" + "╠══════════════════════════════════════════════════════════════════════════════╣\n" + "║ TOP PROCESSES ║\n" + "╠═══════╦══════════════════════════════╦═══════╦══════════╦═══════════════════╣\n" + "║ PID ║ NAME ║ STATE ║ CPU%% ║ MEMORY ║\n" + "╠═══════╬══════════════════════════════╬═══════╬══════════╬═══════════════════╣\n", + disk_read_str, disk_write_str, net_rx_str, net_tx_str); + + for (int i = 0; i < proc_count && i < 10; i++) { + format_bytes(processes[i].memory, buffer); + pos += sprintf(display_buffer + pos, "║ %5d ║ %-28s ║ %c ║ %6.1f%% ║ %17s ║\n", + processes[i].pid, + processes[i].name, + processes[i].state, + processes[i].cpu_percent, + buffer); + } + + pos += sprintf(display_buffer + pos, + "╚═══════╩══════════════════════════════╩═══════╩══════════╩═══════════════════╝\n" + "Press 'q' to quit, 'r' to refresh "); + + // Output entire buffer at once + printf("%s", display_buffer); + fflush(stdout); +} + +void get_system_stats(SystemStats *stats) { + FILE *fp; + char buffer[1024]; + static unsigned long prev_idle = 0, prev_total = 0; + static unsigned long prev_disk_read = 0, prev_disk_write = 0; + static unsigned long prev_net_rx = 0, prev_net_tx = 0; + + // CPU Usage + fp = fopen("/proc/stat", "r"); + if (fp) { + fgets(buffer, sizeof(buffer), fp); + unsigned long user, nice, system, idle, iowait, irq, softirq; + sscanf(buffer, "cpu %lu %lu %lu %lu %lu %lu %lu", + &user, &nice, &system, &idle, &iowait, &irq, &softirq); + + unsigned long total = user + nice + system + idle + iowait + irq + softirq; + unsigned long total_diff = total - prev_total; + unsigned long idle_diff = idle - prev_idle; + + if (total_diff > 0) { + stats->cpu_percent = 100.0 * (total_diff - idle_diff) / total_diff; + } else { + stats->cpu_percent = 0.0; + } + + prev_total = total; + prev_idle = idle; + fclose(fp); + } + + // Memory Usage - Read from /proc/meminfo for accuracy + fp = fopen("/proc/meminfo", "r"); + if (fp) { + unsigned long mem_total = 0, mem_free = 0, mem_available = 0; + unsigned long buffers = 0, cached = 0; + + while (fgets(buffer, sizeof(buffer), fp)) { + if (sscanf(buffer, "MemTotal: %lu kB", &mem_total) == 1) { + stats->memory_total = mem_total * 1024; + } else if (sscanf(buffer, "MemAvailable: %lu kB", &mem_available) == 1) { + // MemAvailable accounts for buffers/cache that can be reclaimed + stats->memory_used = (mem_total - mem_available) * 1024; + } else if (sscanf(buffer, "MemFree: %lu kB", &mem_free) == 1) { + // Fallback if MemAvailable is not available + if (mem_available == 0) { + mem_free = mem_free; + } + } else if (sscanf(buffer, "Buffers: %lu kB", &buffers) == 1) { + // For fallback calculation + } else if (sscanf(buffer, "Cached: %lu kB", &cached) == 1) { + // For fallback calculation + } + } + + // If MemAvailable wasn't found, calculate manually + if (mem_available == 0 && mem_total > 0) { + stats->memory_used = (mem_total - mem_free - buffers - cached) * 1024; + } + + fclose(fp); + } + + // Disk I/O + fp = fopen("/proc/diskstats", "r"); + if (fp) { + unsigned long read_sectors = 0, write_sectors = 0; + while (fgets(buffer, sizeof(buffer), fp)) { + unsigned long r_sectors, w_sectors; + char device[32]; + if (sscanf(buffer, "%*d %*d %31s %*d %*d %lu %*d %*d %*d %lu", + device, &r_sectors, &w_sectors) == 3) { + if (strncmp(device, "sd", 2) == 0 || strncmp(device, "nvme", 4) == 0) { + read_sectors += r_sectors; + write_sectors += w_sectors; + } + } + } + stats->disk_read = (read_sectors - prev_disk_read) * 512; + stats->disk_write = (write_sectors - prev_disk_write) * 512; + prev_disk_read = read_sectors; + prev_disk_write = write_sectors; + fclose(fp); + } + + // Network I/O + fp = fopen("/proc/net/dev", "r"); + if (fp) { + fgets(buffer, sizeof(buffer), fp); // skip header + fgets(buffer, sizeof(buffer), fp); // skip header + + unsigned long rx_bytes = 0, tx_bytes = 0; + while (fgets(buffer, sizeof(buffer), fp)) { + char interface[32]; + unsigned long rx, tx; + if (sscanf(buffer, " %31[^:]: %lu %*d %*d %*d %*d %*d %*d %*d %lu", + interface, &rx, &tx) == 3) { + if (strcmp(interface, "lo") != 0) { // skip loopback + rx_bytes += rx; + tx_bytes += tx; + } + } + } + stats->net_rx = rx_bytes - prev_net_rx; + stats->net_tx = tx_bytes - prev_net_tx; + prev_net_rx = rx_bytes; + prev_net_tx = tx_bytes; + fclose(fp); + } +} + +int get_process_info(ProcessInfo *processes, int max_processes) { + DIR *proc_dir; + struct dirent *entry; + FILE *fp; + char path[256]; + char buffer[1024]; + int count = 0; + + proc_dir = opendir("/proc"); + if (!proc_dir) return 0; + + while ((entry = readdir(proc_dir)) != NULL && count < max_processes) { + if (!isdigit(entry->d_name[0])) continue; + + int pid = atoi(entry->d_name); + processes[count].pid = pid; + + // Get process name and state + snprintf(path, sizeof(path), "/proc/%d/stat", pid); + fp = fopen(path, "r"); + if (fp) { + if (fgets(buffer, sizeof(buffer), fp)) { + char *name_start = strchr(buffer, '('); + char *name_end = strrchr(buffer, ')'); + if (name_start && name_end) { + int name_len = name_end - name_start - 1; + if (name_len > 255) name_len = 255; + strncpy(processes[count].name, name_start + 1, name_len); + processes[count].name[name_len] = '\0'; + + char *state_pos = name_end + 2; + processes[count].state = *state_pos; + } + } + fclose(fp); + } + + // Get memory usage + snprintf(path, sizeof(path), "/proc/%d/status", pid); + fp = fopen(path, "r"); + if (fp) { + while (fgets(buffer, sizeof(buffer), fp)) { + if (strncmp(buffer, "VmRSS:", 6) == 0) { + unsigned long mem_kb; + sscanf(buffer, "VmRSS: %lu kB", &mem_kb); + processes[count].memory = mem_kb * 1024; + break; + } + } + fclose(fp); + } + + processes[count].cpu_percent = 0.0; // Simplified for this example + count++; + } + + closedir(proc_dir); + + // Sort by memory usage (descending) + for (int i = 0; i < count - 1; i++) { + for (int j = i + 1; j < count; j++) { + if (processes[i].memory < processes[j].memory) { + ProcessInfo temp = processes[i]; + processes[i] = processes[j]; + processes[j] = temp; + } + } + } + + return count; +} + +void clear_screen(void) { + printf("\033[2J\033[H"); + fflush(stdout); +} + +void move_cursor(int row, int col) { + printf("\033[%d;%dH", row, col); + fflush(stdout); +} + +void hide_cursor(void) { + printf("\033[?25l"); + fflush(stdout); +} + +void show_cursor(void) { + printf("\033[?25h"); + fflush(stdout); +} + +int kbhit(void) { + int ch = getchar(); + if (ch != EOF) { + ungetc(ch, stdin); + return 1; + } + return 0; +} + +void draw_progress_bar(int percentage, int width) { + int filled = (percentage * width) / 100; + printf("["); + for (int i = 0; i < width; i++) { + if (i < filled) { + printf("█"); + } else { + printf(" "); + } + } + printf("]"); +} + +void format_progress_bar(int percentage, int width, char *buffer) { + int filled = (percentage * width) / 100; + int pos = 0; + buffer[pos++] = '['; + for (int i = 0; i < width; i++) { + if (i < filled) { + buffer[pos++] = '#'; // Use # instead of Unicode block + } else { + buffer[pos++] = ' '; + } + } + buffer[pos++] = ']'; + buffer[pos] = '\0'; +} + +void format_bytes(unsigned long bytes, char *buffer) { + const char *units[] = {"B", "KB", "MB", "GB", "TB"}; + int unit = 0; + double size = bytes; + + while (size >= 1024 && unit < 4) { + size /= 1024; + unit++; + } + + if (unit == 0) { + snprintf(buffer, 64, "%lu %s", bytes, units[unit]); + } else { + snprintf(buffer, 64, "%.1f %s", size, units[unit]); + } +} \ No newline at end of file diff --git a/system_monitor.h b/system_monitor.h new file mode 100644 index 0000000..a78f565 --- /dev/null +++ b/system_monitor.h @@ -0,0 +1,49 @@ +#ifndef SYSTEM_MONITOR_H +#define SYSTEM_MONITOR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + float cpu_percent; + unsigned long memory_used; + unsigned long memory_total; + unsigned long disk_read; + unsigned long disk_write; + unsigned long net_rx; + unsigned long net_tx; + int process_count; +} SystemStats; + +typedef struct { + int pid; + char name[256]; + float cpu_percent; + unsigned long memory; + char state; +} ProcessInfo; + +int builtin_monitor(char **args); +void display_dashboard(SystemStats *stats, ProcessInfo *processes, + int proc_count); +void get_system_stats(SystemStats *stats); +int get_process_info(ProcessInfo *processes, int max_processes); +void clear_screen(void); +void move_cursor(int row, int col); +void hide_cursor(void); +void show_cursor(void); +int kbhit(void); +void draw_progress_bar(int percentage, int width); +void format_progress_bar(int percentage, int width, char *buffer); +void format_bytes(unsigned long bytes, char *buffer); + +#endif diff --git a/system_monitor.o b/system_monitor.o new file mode 100644 index 0000000..2b0776f Binary files /dev/null and b/system_monitor.o differ diff --git a/tab_complete.o b/tab_complete.o index 996ec56..8cac2fe 100644 Binary files a/tab_complete.o and b/tab_complete.o differ diff --git a/themes.o b/themes.o index 8d20aa7..5b445c6 100644 Binary files a/themes.o and b/themes.o differ diff --git a/timer.o b/timer.o index c94069f..743d329 100644 Binary files a/timer.o and b/timer.o differ diff --git a/weather.o b/weather.o index 6feccf6..4f5975d 100644 Binary files a/weather.o and b/weather.o differ