diff --git a/fish-init b/fish-init index 9c29511..bf58ff7 100644 --- a/fish-init +++ b/fish-init @@ -1,5 +1,9 @@ #! /bin/fish function fish_prompt - ./render .1 .35 + ~/git/over-prompt/render .1 .35 $COLUMNS $status + # ^ ^ ^ ^- last command's exit status + # | \- terminal width + # | \- yellow threshold + # \- red threshold end diff --git a/render.cpp b/render.cpp index 8bdb9e7..d9a37d9 100644 --- a/render.cpp +++ b/render.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #define ATTR_NONE 0 #define ATTR_BOLD 1 @@ -26,34 +27,29 @@ /* -------------------------------------------------- */ -void term_size(uint *columns, uint *rows) { - struct winsize w; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - - if (columns) *columns = w.ws_col; - if (rows) *rows = w.ws_row; -} - -/* -------------------------------------------------- */ - class Config { public: Config(int argc, char **argv) { - if (argc != 3) { - fprintf(stderr, "Usage: %s red_threshold yellow_threshold\n", argv[0]); + if (argc != 5) { + fprintf(stderr, "Usage: %s red_threshold yellow_threshold terminal_width last_exit_status\n", argv[0]); this->failed = true; return; } this->red_thresh = strtof(argv[1], NULL); this->yellow_thresh = strtof(argv[2], NULL); - term_size(&(this->term_width), NULL); + this->term_width = strtol(argv[3], NULL, 10); + this->last_exit_status = strtol(argv[4], NULL, 10); + this->is_root = (geteuid() == 0); + this->failed = false; } uint term_width; float red_thresh; float yellow_thresh; + uint last_exit_status; + bool is_root; bool failed; }; @@ -108,21 +104,24 @@ public: } } - void set_colors(uint fg, uint bg, const char *transition=NULL) { + void set_colors(uint fg, uint bg, const char *transition=NULL, bool left_to_right=true) { if (transition) { this->push(" "); } - this->_push_color(bg, true); + if (left_to_right) this->_push_color(bg, true); if (transition) { - this->_push_color(this->col_bg); + this->_push_color(left_to_right? this->col_bg : bg); this->push(transition); - this->push(" "); + if (left_to_right) this->push(" "); } + if (not left_to_right) this->_push_color(bg, true); this->_push_color(fg); + if (transition and not left_to_right) this->push(" "); + this->col_fg = fg; this->col_bg = bg; } @@ -159,7 +158,12 @@ public: this->push(new Segment(str)); } -protected: + void push(uint n) { + char tmp[1024]; + sprintf(tmp, "%d", n); + this->push(tmp); + } + Segment **segments; size_t ptr, max; size_t raw_length; @@ -223,12 +227,6 @@ void render_path(Output *output) { output->push(tokens[i]); delete[] tokens[i]; } - - // if cwd is not writable, show a warning - if (access(".", W_OK) != 0) { - output->set_colors(232, 88, SYM_RIGHTBLK); - output->push(SYM_LOCK); - } } void render_git(Output *output) { @@ -262,6 +260,71 @@ void render_git(Output *output) { } } +void render_lock(Output *output) { + if (access(".", W_OK) != 0) { + output->set_colors(196, 232, SYM_RIGHTBLK); + output->push(SYM_LOCK); + } +} + +void render_padding(const uint term_width, const uint length, FILE *stream) { + int delta = term_width - length; + + if (delta >= 0) { + delta--; // fish refuses to write to the last column + + for (uint i = 0; i < (uint) delta; i++) { + fputc(' ', stream); + } + } else { + fputc('!', stream); + } +} + +void render_time(Output *output) { + time_t rawtime; + struct tm *info; + char buffer[1024]; + + time(&rawtime); + info = localtime(&rawtime); + + strftime(buffer, 1024, "%H:%M", info); + + output->push(buffer); +} + +void render_sysload(Output *output) { + double load; + char tmp[16]; + uint bg, fg; + + if (getloadavg(&load, 1) == 1) { + load = 4.1; + + if (load > 12) { + bg = 196; + fg = 15; + } else if (load > 8) { + bg = 88; + fg = 15; + } else if (load > 4) { + bg = 3; + fg = 232; + } else { + bg = 34; + fg = 232; + } + + output->set_colors(fg, bg, SYM_RIGHTBLK); + sprintf(tmp, "%.2f", load); + output->push(tmp); + } else { + output->set_colors(15, 196, SYM_RIGHTBLK); + output->push("ERR"); + } +} + /* -------------------------------------------------- */ int main(int argc, char **argv) { @@ -273,16 +336,16 @@ int main(int argc, char **argv) { */ Output top_left; - Output top_path; Output top_right; + Output prompt; /* -------------------------------------------------- - * user@host[:screen] + * top_left: user@host[:screen] path > to > cwd [git branch] [lock] */ char buf[PATH_MAX]; - if (geteuid() == 0) { + if (config.is_root) { top_left.set_colors(232, 124); // red bg } else { top_left.set_colors(232, 202); // aware orange bg @@ -299,18 +362,49 @@ int main(int argc, char **argv) { render_screen(&top_left); render_path(&top_left); render_git(&top_left); - - /* -------------------------------------------------- - * end - */ + render_lock(&top_left); top_left.set_colors(7, 0, SYM_RIGHTBLK); /* -------------------------------------------------- - * finally, output the prompt + * prompt: [last_exit_status:]$|# > + */ + + if (config.last_exit_status) { + prompt.set_colors(7, 88); + prompt.push(" "); + prompt.push(config.last_exit_status); + } else { + prompt.set_colors(232, 34); + prompt.push(" "); + + if (config.is_root) { + prompt.push("#"); + } else { + prompt.push("$"); + } + } + + prompt.set_colors(7, 0, SYM_RIGHTBLK); + + /* -------------------------------------------------- + * top_right: < time < spaces < sysload + */ + + top_right.set_colors(232, 202, SYM_LEFTBLK, false); + render_time(&top_right); + render_sysload(&top_right); + top_right.set_colors(7, 0, SYM_RIGHTBLK); + + /* -------------------------------------------------- + * output the prompt */ top_left.output(stdout); + render_padding(config.term_width, top_left.printable_length + top_right.printable_length, stdout); + top_right.output(stdout); + fputs("\n", stdout); + prompt.output(stdout); return 0; }