wip universal prompt renderer, using Powerline symbols
This commit is contained in:
parent
63d4b8c1fd
commit
0703ad5399
5 changed files with 382 additions and 2 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
render
|
||||
colors.sh
|
5
fish-init
Normal file
5
fish-init
Normal file
|
@ -0,0 +1,5 @@
|
|||
#! /bin/fish
|
||||
|
||||
function fish_prompt
|
||||
./render .1 .35
|
||||
end
|
316
render.cpp
Normal file
316
render.cpp
Normal file
|
@ -0,0 +1,316 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <unistr.h>
|
||||
|
||||
#define ATTR_NONE 0
|
||||
#define ATTR_BOLD 1
|
||||
#define ATTR_UNDER 4
|
||||
#define ATTR_BLINK 5
|
||||
|
||||
#define SYM_GIT "\ue0a0"
|
||||
#define SYM_LN "\ue0a1"
|
||||
#define SYM_LOCK "\ue0a2"
|
||||
#define SYM_RIGHTBLK "\ue0b0"
|
||||
#define SYM_RIGHT "\ue0b1"
|
||||
#define SYM_LEFTBLK "\ue0b2"
|
||||
#define SYM_LEFT "\ue0b3"
|
||||
|
||||
#define PATH_MAX 4096
|
||||
|
||||
#ifndef uint
|
||||
#define uint unsigned int
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
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]);
|
||||
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->failed = false;
|
||||
}
|
||||
|
||||
uint term_width;
|
||||
float red_thresh;
|
||||
float yellow_thresh;
|
||||
|
||||
bool failed;
|
||||
};
|
||||
|
||||
class Segment {
|
||||
public:
|
||||
Segment(const char *str, bool printable=true) {
|
||||
this->raw_length = strlen(str);
|
||||
this->raw_str = new char[(this->raw_length + 1) * sizeof(char)]; // +1 for null
|
||||
strcpy(this->raw_str, str);
|
||||
|
||||
if (printable) {
|
||||
this->printable_length = u8_mbsnlen((const uint8_t*)str, this->raw_length);
|
||||
} else {
|
||||
this->printable_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
~Segment(void) {
|
||||
delete[] this->raw_str;
|
||||
}
|
||||
|
||||
char *raw_str;
|
||||
size_t raw_length;
|
||||
size_t printable_length;
|
||||
};
|
||||
|
||||
class Output {
|
||||
public:
|
||||
Output(void) {
|
||||
this->printable_length = 0;
|
||||
this->raw_length = 0;
|
||||
this->ptr = 0;
|
||||
this->max = 256; // a reasonable amount?
|
||||
|
||||
this->segments = new Segment*[this->max];
|
||||
|
||||
this->set_colors(7, 0);
|
||||
}
|
||||
|
||||
~Output(void) {
|
||||
for (uint i = 0; i < this->ptr; i++) {
|
||||
delete this->segments[i];
|
||||
}
|
||||
|
||||
delete[] this->segments;
|
||||
}
|
||||
|
||||
void output(FILE *stream) {
|
||||
for (uint i = 0; i < this->ptr; i++) {
|
||||
fputs(this->segments[i]->raw_str, stream);
|
||||
}
|
||||
}
|
||||
|
||||
void set_colors(uint fg, uint bg, const char *transition=NULL) {
|
||||
if (transition) {
|
||||
this->push(" ");
|
||||
}
|
||||
|
||||
this->_push_color(bg, true);
|
||||
|
||||
if (transition) {
|
||||
this->_push_color(this->col_bg);
|
||||
this->push(transition);
|
||||
this->push(" ");
|
||||
}
|
||||
|
||||
this->_push_color(fg);
|
||||
|
||||
this->col_fg = fg;
|
||||
this->col_bg = bg;
|
||||
}
|
||||
|
||||
void _push_color(uint color=ATTR_NONE, bool bg=false) {
|
||||
if (color == ATTR_NONE) {
|
||||
this->set_attr();
|
||||
} else {
|
||||
char tmp[16];
|
||||
snprintf(tmp, 16, "\e[%d;5;%dm", (bg? 48:38), color);
|
||||
|
||||
this->push(new Segment(tmp, false));
|
||||
}
|
||||
}
|
||||
|
||||
void set_attr(uint attr=ATTR_NONE) {
|
||||
char tmp[10];
|
||||
snprintf(tmp, 10, "\e[%dm", attr);
|
||||
|
||||
this->push(new Segment(tmp, false));
|
||||
}
|
||||
|
||||
void push(Segment *segment) {
|
||||
if (this->ptr + 1 == this->max) {
|
||||
fprintf(stderr, "Output.segments full, this will probably fail.\n");
|
||||
}
|
||||
|
||||
this->segments[this->ptr++] = segment;
|
||||
this->printable_length += segment->printable_length;
|
||||
this->raw_length += segment->raw_length;
|
||||
}
|
||||
|
||||
void push(const char *str) {
|
||||
this->push(new Segment(str));
|
||||
}
|
||||
|
||||
protected:
|
||||
Segment **segments;
|
||||
size_t ptr, max;
|
||||
size_t raw_length;
|
||||
size_t printable_length;
|
||||
|
||||
uint col_fg, col_bg;
|
||||
};
|
||||
|
||||
void render_screen(Output *output) {
|
||||
char *tmp = getenv("WINDOW");
|
||||
|
||||
if (tmp) {
|
||||
output->push(":");
|
||||
output->push(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void render_path(Output *output) {
|
||||
char buf[PATH_MAX];
|
||||
|
||||
getcwd(buf, PATH_MAX);
|
||||
|
||||
// tokenize path TODO replace homes with ~
|
||||
char *ptr = buf;
|
||||
char *ptr_end;
|
||||
char *tokens[100]; // a sensible default?
|
||||
char token[4096];
|
||||
uint token_count = 0;
|
||||
uint token_length;
|
||||
|
||||
while (*ptr) { // until NULL terminator
|
||||
ptr = strchrnul(ptr, '/') + 1;
|
||||
ptr_end = strchrnul(ptr, '/');
|
||||
token_length = ptr_end - ptr;
|
||||
memcpy(token, ptr, token_length);
|
||||
token[token_length] = 0;
|
||||
|
||||
if (token_length) {
|
||||
tokens[token_count] = new char[(token_length + 1) * sizeof(char)];
|
||||
memcpy(tokens[token_count], token, token_length);
|
||||
tokens[token_count][token_length] = 0;
|
||||
token_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// render path with increasing background brightness
|
||||
uint fg = 202;
|
||||
uint bg = 233;
|
||||
|
||||
for (uint i = 0; i < token_count; i++) {
|
||||
if (bg == 241) fg = 232;
|
||||
|
||||
if (bg < 255) {
|
||||
output->set_colors(fg, bg++, SYM_RIGHTBLK);
|
||||
} else {
|
||||
output->push(" ");
|
||||
output->push(SYM_RIGHT);
|
||||
output->push(" ");
|
||||
}
|
||||
|
||||
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) {
|
||||
FILE *pipe;
|
||||
char branch_name[1024];
|
||||
|
||||
pipe = popen("git rev-parse --abbrev-ref HEAD 2> /dev/null", "r");
|
||||
|
||||
if (pipe) {
|
||||
if (fgets(branch_name, 1024, pipe)) {
|
||||
branch_name[strlen(branch_name) - 1] = 0; // kill the newline
|
||||
|
||||
// rebuild index
|
||||
system("git update-index -q --ignore-submodules --refresh");
|
||||
|
||||
// so that I can check if there are unstaged changes
|
||||
if (system("git diff-files --quiet --ignore-submodules")) {
|
||||
output->set_colors(232, 88, SYM_RIGHTBLK);
|
||||
} else {
|
||||
output->set_colors(232, 46, SYM_RIGHTBLK);
|
||||
}
|
||||
|
||||
output->push(SYM_GIT);
|
||||
output->push(" ");
|
||||
output->push(branch_name);
|
||||
}
|
||||
|
||||
pclose(pipe);
|
||||
} else {
|
||||
fprintf(stderr, "--- failed to run git\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
Config config(argc, argv);
|
||||
if (config.failed) return 1;
|
||||
|
||||
/* --------------------------------------------------
|
||||
* output init
|
||||
*/
|
||||
|
||||
Output top_left;
|
||||
Output top_path;
|
||||
Output top_right;
|
||||
|
||||
/* --------------------------------------------------
|
||||
* user@host[:screen]
|
||||
*/
|
||||
|
||||
char buf[PATH_MAX];
|
||||
|
||||
if (geteuid() == 0) {
|
||||
top_left.set_colors(232, 124); // red bg
|
||||
} else {
|
||||
top_left.set_colors(232, 202); // aware orange bg
|
||||
}
|
||||
|
||||
top_left.push(" ");
|
||||
top_left.push(getlogin());
|
||||
|
||||
top_left.set_colors(202, 232, SYM_RIGHTBLK);
|
||||
|
||||
gethostname(buf, 256);
|
||||
top_left.push(buf);
|
||||
|
||||
render_screen(&top_left);
|
||||
render_path(&top_left);
|
||||
render_git(&top_left);
|
||||
|
||||
/* --------------------------------------------------
|
||||
* end
|
||||
*/
|
||||
|
||||
top_left.set_colors(7, 0, SYM_RIGHTBLK);
|
||||
|
||||
/* --------------------------------------------------
|
||||
* finally, output the prompt
|
||||
*/
|
||||
|
||||
top_left.output(stdout);
|
||||
|
||||
return 0;
|
||||
}
|
51
screeenrc.over
Normal file
51
screeenrc.over
Normal file
|
@ -0,0 +1,51 @@
|
|||
defutf8 on
|
||||
autodetach on
|
||||
startup_message off
|
||||
defscrollback 10240
|
||||
|
||||
# scroll through scrollback
|
||||
termcapinfo xterm* ti@:te@
|
||||
|
||||
# let's get high-tech with 256 colors over here
|
||||
attrcolor b ".I" # allow bold colors - necessary for some reason
|
||||
termcapinfo xterm "Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm" # tell screen how to set colors. AB = background, AF=foreground
|
||||
defbce on # use current bg color for erased chars
|
||||
|
||||
# remapping dangerous keybindings
|
||||
bind k
|
||||
bind ^k
|
||||
bind .
|
||||
bind ^\
|
||||
bind \\
|
||||
bind ^h
|
||||
bind h
|
||||
bind 'K' kill
|
||||
bind 'I' login on
|
||||
bind 'O' login off
|
||||
bind '}' history
|
||||
|
||||
# custom keybindings
|
||||
bind '/' eval "scrollback 0" "scrollback 15000"
|
||||
|
||||
# status line
|
||||
#backtick 1 5 5 true
|
||||
#termcapinfo rxvt* 'hs:ts=\E]2;:fs=\007:ds=\E]2;\007'
|
||||
#hardstatus string "screen (%n: %t)"
|
||||
#caption string "%{= kw}%Y-%m-%d;%c %{= kw}%-Lw%{= kG}%{+b}[%n %t]%{-b}%{= kw}%+Lw%1`"
|
||||
#caption always
|
||||
|
||||
# environment
|
||||
setenv DISPLAY ":0"
|
||||
|
||||
# start with a bunch of windows
|
||||
#screen -t "Nice Rootshell" 0 sudo ionice -c 3 nice su -
|
||||
#screen -t "Nice Rootshell" 1 sudo ionice -c 3 nice su -
|
||||
#screen -t "Rootshell" 2 sudo su -
|
||||
#screen -t "Shell" 3 zsh
|
||||
#screen -t "Shell" 4 zsh
|
||||
#screen -t "Shell" 5 zsh
|
||||
#screen -t "Shell" 6 zsh
|
||||
#screen -t "Dictionary" 7 /home/eridanus/Software/Development/Et/et-dictionary/screen-wrapper.sh
|
||||
#screen -t "Equalizer" 8 alsamixer -D equal
|
||||
#screen -t "Red Noise" 9 red-noise.sh
|
||||
#screen -t "Syncthing" 10 syncthing -no-browser
|
10
zsh-init
10
zsh-init
|
@ -12,11 +12,11 @@ function strlen {
|
|||
local PLAIN
|
||||
PLAIN="$(echo $1 | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g")"
|
||||
|
||||
echo $#PLAIN
|
||||
echo ${#PLAIN}
|
||||
}
|
||||
|
||||
function precmd {
|
||||
local OVER_OPTS RAW_DATA LOGIN_PART STATS_PART DATA TOP_LEFT TOP_RIGHT PADDING PADDING_SIZE GIT_BRANCH COLOR
|
||||
local CUT OVER_OPTS RAW_DATA LOGIN_PART STATS_PART DATA TOP_LEFT TOP_RIGHT PADDING PADDING_SIZE GIT_BRANCH COLOR
|
||||
set -A OVER_OPTS ${(s. .)OVER_PROMPT_OPTS}
|
||||
|
||||
PS1="$(print "%(?.%{\e[1;36m%}.%{\e[1;31m%}%?%{\e[0m%}:%{\e[1;31m%})%(\!.#.$)%{\e[0m%} ")"
|
||||
|
@ -51,6 +51,12 @@ function precmd {
|
|||
TOP_LEFT=$(print -P "%(\!.\e[1;31m.\e[1;32m)%n\e[0m@$LOGIN_PART")
|
||||
TOP_RIGHT=$(print -P "[ \e[1;36m%T\e[0m | $STATS_PART")
|
||||
PADDING_SIZE=$(($COLUMNS - $(strlen "$TOP_LEFT") - $(strlen "$TOP_RIGHT")))
|
||||
|
||||
# if [[ $PADDING_SIZE -lt 0 ]]; then
|
||||
# CUT=$((0 - $PADDING_SIZE))
|
||||
# TOP_LEFT="${TOP_LEFT[$CUT,-1]}"
|
||||
# fi
|
||||
|
||||
PADDING=$(printf " "%.0s {1..$PADDING_SIZE})
|
||||
|
||||
print "$TOP_LEFT$PADDING$TOP_RIGHT"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue