mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-13 05:28:49 +00:00
Lots of work on web config
Change to make fish immediately show color changes
This commit is contained in:
parent
c0655b6b08
commit
0c9a1a56c2
9 changed files with 576 additions and 129 deletions
12
env.cpp
12
env.cpp
|
@ -341,7 +341,9 @@ static void react_to_variable_change(const wcstring &key) {
|
|||
handle_locale();
|
||||
} else if (key == L"fish_term256") {
|
||||
update_fish_term256();
|
||||
reader_repaint_needed();
|
||||
reader_react_to_color_change();
|
||||
} else if (string_prefixes_string(L"fish_color_", key)) {
|
||||
reader_react_to_color_change();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,11 +357,6 @@ static void universal_callback( int type,
|
|||
{
|
||||
const wchar_t *str=0;
|
||||
|
||||
if( var_is_locale( name ) )
|
||||
{
|
||||
handle_locale();
|
||||
}
|
||||
|
||||
switch( type )
|
||||
{
|
||||
case SET:
|
||||
|
@ -388,6 +385,9 @@ static void universal_callback( int type,
|
|||
event_fire( &ev );
|
||||
ev.arguments.reset(NULL);
|
||||
}
|
||||
|
||||
if (name)
|
||||
react_to_variable_change(name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,16 +44,23 @@ static wint_t lookahead_arr[1024];
|
|||
*/
|
||||
static int lookahead_count = 0;
|
||||
|
||||
/**
|
||||
Callback function for handling interrupts on reading
|
||||
*/
|
||||
/** Callback function for handling interrupts on reading */
|
||||
static int (*interrupt_handler)();
|
||||
|
||||
/** Callback function to be invoked before reading each byte */
|
||||
static void (*poll_handler)();
|
||||
|
||||
|
||||
void input_common_init( int (*ih)() )
|
||||
{
|
||||
interrupt_handler = ih;
|
||||
}
|
||||
|
||||
void input_common_set_poll_callback(void (*handler)(void))
|
||||
{
|
||||
poll_handler = handler;
|
||||
}
|
||||
|
||||
void input_common_destroy()
|
||||
{
|
||||
|
||||
|
@ -66,10 +73,14 @@ void input_common_destroy()
|
|||
static wint_t readb()
|
||||
{
|
||||
unsigned char arr[1];
|
||||
int do_loop = 0;
|
||||
bool do_loop = false;
|
||||
|
||||
do
|
||||
{
|
||||
/* Invoke any poll handler */
|
||||
if (poll_handler)
|
||||
poll_handler();
|
||||
|
||||
fd_set fdset;
|
||||
int fd_max=0;
|
||||
int ioport = iothread_port();
|
||||
|
@ -88,7 +99,7 @@ static wint_t readb()
|
|||
}
|
||||
|
||||
|
||||
do_loop = 0;
|
||||
do_loop = false;
|
||||
|
||||
res = select( fd_max + 1, &fdset, 0, 0, 0 );
|
||||
if( res==-1 )
|
||||
|
@ -113,7 +124,7 @@ static wint_t readb()
|
|||
}
|
||||
|
||||
|
||||
do_loop = 1;
|
||||
do_loop = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -133,7 +144,7 @@ static wint_t readb()
|
|||
{
|
||||
debug( 3, L"Wake up on universal variable event" );
|
||||
env_universal_read_all();
|
||||
do_loop = 1;
|
||||
do_loop = true;
|
||||
|
||||
if( lookahead_count )
|
||||
{
|
||||
|
@ -148,7 +159,7 @@ static wint_t readb()
|
|||
{
|
||||
iothread_service_completion();
|
||||
}
|
||||
do_loop = 1;
|
||||
do_loop = true;
|
||||
}
|
||||
|
||||
if( FD_ISSET( 0, &fdset ) )
|
||||
|
@ -160,7 +171,7 @@ static wint_t readb()
|
|||
*/
|
||||
return R_EOF;
|
||||
}
|
||||
do_loop = 0;
|
||||
do_loop = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,9 @@ enum
|
|||
*/
|
||||
void input_common_init( int (*ih)() );
|
||||
|
||||
/* Sets a callback to be invoked every time a byte is read */
|
||||
void input_common_set_poll_callback(void (*handler)(void));
|
||||
|
||||
/**
|
||||
Free memory used by the library
|
||||
*/
|
||||
|
|
47
reader.cpp
47
reader.cpp
|
@ -302,7 +302,10 @@ class reader_data_t
|
|||
Keep track of whether any internal code has done something
|
||||
which is known to require a repaint.
|
||||
*/
|
||||
int repaint_needed;
|
||||
bool repaint_needed;
|
||||
|
||||
/** Whether the a screen reset is needed after a repaint. */
|
||||
bool screen_reset_needed;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -446,7 +449,7 @@ static void reader_repaint()
|
|||
&indents[0],
|
||||
data->buff_pos );
|
||||
#endif
|
||||
data->repaint_needed = 0;
|
||||
data->repaint_needed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -678,6 +681,9 @@ void reader_init()
|
|||
shell_modes.c_lflag &= ~ECHO; /* turn off echo mode */
|
||||
shell_modes.c_cc[VMIN]=1;
|
||||
shell_modes.c_cc[VTIME]=0;
|
||||
|
||||
/* Repaint if necessary before each byte is read. This lets us react immediately to universal variable color changes. */
|
||||
input_common_set_poll_callback(reader_repaint_if_needed);
|
||||
}
|
||||
|
||||
|
||||
|
@ -699,12 +705,29 @@ void reader_exit( int do_exit, int forced )
|
|||
|
||||
void reader_repaint_needed()
|
||||
{
|
||||
if( data )
|
||||
{
|
||||
data->repaint_needed = 1;
|
||||
if (data) {
|
||||
data->repaint_needed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void reader_repaint_if_needed() {
|
||||
if (data && data->screen_reset_needed) {
|
||||
s_reset( &data->screen, false);
|
||||
data->screen_reset_needed = false;
|
||||
}
|
||||
|
||||
if (data && data->repaint_needed) {
|
||||
reader_repaint();
|
||||
/* reader_repaint clears repaint_needed */
|
||||
}
|
||||
}
|
||||
|
||||
void reader_react_to_color_change() {
|
||||
if (data) {
|
||||
data->repaint_needed = true;
|
||||
data->screen_reset_needed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -1651,7 +1674,7 @@ static int handle_completions( std::vector<completion_t> &comp )
|
|||
}
|
||||
|
||||
free( prefix );
|
||||
s_reset( &data->screen, 1 );
|
||||
s_reset( &data->screen, true);
|
||||
reader_repaint();
|
||||
|
||||
}
|
||||
|
@ -2325,7 +2348,7 @@ void reader_pop()
|
|||
{
|
||||
end_loop = 0;
|
||||
//history_set_mode( data->app_name.c_str() );
|
||||
s_reset( &data->screen, 1 );
|
||||
s_reset( &data->screen, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2678,7 +2701,7 @@ const wchar_t *reader_readline()
|
|||
exec_prompt();
|
||||
|
||||
reader_super_highlight_me_plenty( data->buff_pos );
|
||||
s_reset( &data->screen, 1 );
|
||||
s_reset( &data->screen, true);
|
||||
reader_repaint();
|
||||
|
||||
/*
|
||||
|
@ -2804,9 +2827,7 @@ const wchar_t *reader_readline()
|
|||
|
||||
case R_NULL:
|
||||
{
|
||||
if( data->repaint_needed )
|
||||
reader_repaint();
|
||||
|
||||
reader_repaint_if_needed();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2814,7 +2835,7 @@ const wchar_t *reader_readline()
|
|||
{
|
||||
exec_prompt();
|
||||
write_loop( 1, "\r", 1 );
|
||||
s_reset( &data->screen, 0 );
|
||||
s_reset( &data->screen, false);
|
||||
reader_repaint();
|
||||
break;
|
||||
}
|
||||
|
@ -3084,7 +3105,7 @@ const wchar_t *reader_readline()
|
|||
*/
|
||||
default:
|
||||
{
|
||||
s_reset( &data->screen, 1 );
|
||||
s_reset( &data->screen, true);
|
||||
reader_repaint();
|
||||
break;
|
||||
}
|
||||
|
|
6
reader.h
6
reader.h
|
@ -75,6 +75,12 @@ void reader_write_title();
|
|||
*/
|
||||
void reader_repaint_needed();
|
||||
|
||||
/** Call this function to tell the reader that some color has changed. */
|
||||
void reader_react_to_color_change();
|
||||
|
||||
/* Repaint immediately if needed. */
|
||||
void reader_repaint_if_needed();
|
||||
|
||||
/**
|
||||
Run the specified command with the correct terminal modes, and
|
||||
while taking care to perform job notification, set the title, etc.
|
||||
|
|
|
@ -344,7 +344,7 @@ static void s_check_status( screen_t *s)
|
|||
|
||||
int prev_line = s->actual.cursor[1];
|
||||
write_loop( 1, "\r", 1 );
|
||||
s_reset( s, 0 );
|
||||
s_reset( s, false );
|
||||
s->actual.cursor[1] = prev_line;
|
||||
}
|
||||
}
|
||||
|
@ -606,7 +606,7 @@ static void s_update( screen_t *scr, const wchar_t *prompt )
|
|||
need_clear = 1;
|
||||
s_move( scr, &output, 0, 0 );
|
||||
scr->actual_width = screen_width;
|
||||
s_reset( scr, 0 );
|
||||
s_reset( scr, false );
|
||||
}
|
||||
|
||||
if( wcscmp( prompt, scr->actual_prompt.c_str() ) )
|
||||
|
@ -855,7 +855,7 @@ void s_write( screen_t *s,
|
|||
s_save_status( s );
|
||||
}
|
||||
|
||||
void s_reset( screen_t *s, int reset_cursor )
|
||||
void s_reset( screen_t *s, bool reset_cursor )
|
||||
{
|
||||
CHECK( s, );
|
||||
|
||||
|
|
10
screen.h
10
screen.h
|
@ -85,10 +85,11 @@ class screen_data_t
|
|||
};
|
||||
|
||||
/**
|
||||
The struct representing the current and desired screen contents.
|
||||
The class representing the current and desired screen contents.
|
||||
*/
|
||||
typedef struct
|
||||
class screen_t
|
||||
{
|
||||
public:
|
||||
/**
|
||||
The internal representation of the desired screen contents.
|
||||
*/
|
||||
|
@ -123,8 +124,7 @@ typedef struct
|
|||
other than from fish's main loop, in which case we need to redraw.
|
||||
*/
|
||||
struct stat prev_buff_1, prev_buff_2, post_buff_1, post_buff_2;
|
||||
}
|
||||
screen_t;
|
||||
};
|
||||
|
||||
/**
|
||||
This is the main function for the screen putput library. It is used
|
||||
|
@ -155,6 +155,6 @@ void s_write( screen_t *s,
|
|||
resizing, there will be one line of garbage for every repaint,
|
||||
which will quicly fill the screen.
|
||||
*/
|
||||
void s_reset( screen_t *s, int reset_cursor );
|
||||
void s_reset( screen_t *s, bool reset_cursor );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -56,34 +56,56 @@ body {
|
|||
height: 30px;
|
||||
}
|
||||
|
||||
#master_detail_box {
|
||||
overflow: hidden;
|
||||
#master_detail_table {
|
||||
display: table;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#master {
|
||||
float: left;
|
||||
display: table-cell;
|
||||
text-align: right;
|
||||
min-width: 200px;
|
||||
font-size: 16pt;
|
||||
padding-left: 12px;
|
||||
padding-bottom: 0px;
|
||||
margin-top: -7px;
|
||||
}
|
||||
|
||||
#detail {
|
||||
display: table-cell;
|
||||
border: 1px solid #555;
|
||||
background-color: #181818;
|
||||
padding-top: 30px;
|
||||
padding-bottom: 20px;
|
||||
padding-left: 30px;
|
||||
padding-right: 30px;
|
||||
}
|
||||
|
||||
#detail_function {
|
||||
white-space: pre;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.master_element {
|
||||
padding-top: 7px;
|
||||
padding-bottom: 12px;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 11px;
|
||||
padding-left: 5px;
|
||||
padding-right: 32px;
|
||||
font-size: 12pt;
|
||||
/* Make our border overlap the detail, even if we're unselected (so it doesn't jump when selected) */
|
||||
position: relative;
|
||||
left: 1px;
|
||||
}
|
||||
|
||||
.selected_master_elem {
|
||||
border: 1px solid #555;
|
||||
border-right: none;
|
||||
/* Make our border overlap the box */
|
||||
position: relative;
|
||||
left: 1px;
|
||||
background-color: black;
|
||||
background-color: #181818;
|
||||
|
||||
/* Pad one less than .master_element, to accomodate our border. */
|
||||
padding-top: 5px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.master_element_text {
|
||||
|
@ -93,8 +115,33 @@ body {
|
|||
}
|
||||
|
||||
#colorpicker_term256 {
|
||||
padding: 30px;
|
||||
border: 1px solid #555;
|
||||
border: solid #444 1px;
|
||||
}
|
||||
|
||||
.colorpicker_modifiers {
|
||||
margin-top: 10px;
|
||||
display:inline-block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
color: #AAA;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.colorpicker_modifier_cell {
|
||||
cursor: pointer;
|
||||
display:inline-block;
|
||||
text-align: center;
|
||||
border: solid #333 2px;
|
||||
padding: 5px;
|
||||
margin-top: 5px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.modifier_cell_selected {
|
||||
color: #CCC;
|
||||
border-color: #AAA;
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
#data_table {
|
||||
|
@ -120,16 +167,46 @@ body {
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.colorpicker_ground {
|
||||
position: relative;
|
||||
bottom: 50px;
|
||||
margin: 0px;
|
||||
height: 50px;
|
||||
margin-bottom: -50px;
|
||||
}
|
||||
|
||||
.colorpicker_ground_tab {
|
||||
cursor: pointer;
|
||||
color: #AAA;
|
||||
border: solid 2px #555;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
padding-left: 7px;
|
||||
padding-right: 7px;
|
||||
display: inline-block;
|
||||
background-color: black;
|
||||
margin-right: -2px;
|
||||
min-width: 110px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.colorpicker_ground_selected {
|
||||
background-color: #777;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.colorpicker_term256_row {
|
||||
}
|
||||
|
||||
.colorpicker_term256_cell {
|
||||
width: 24;
|
||||
height: 24;
|
||||
width: 27;
|
||||
height: 27;
|
||||
}
|
||||
|
||||
.colorpicker_cell_selected {
|
||||
border: solid white 3px;
|
||||
border: dashed white 3px;
|
||||
width: 21;
|
||||
height: 21;
|
||||
}
|
||||
|
||||
.error_msg {
|
||||
|
@ -145,6 +222,10 @@ body {
|
|||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function show_error(msg) {
|
||||
$('#global_error').text(msg)
|
||||
}
|
||||
|
||||
function request_failed(jqXHR, textStatus, errorThrown) {
|
||||
msg = ''
|
||||
if (textStatus == "timeout") {
|
||||
|
@ -164,7 +245,7 @@ function request_failed(jqXHR, textStatus, errorThrown) {
|
|||
if (errorThrown.length > 0) {
|
||||
msg = msg + ' The HTTP reply returned ' + errorThrown
|
||||
}
|
||||
$('#global_error').text(msg)
|
||||
show_error(msg)
|
||||
}
|
||||
|
||||
/* Runs a GET request, parses the JSON, and invokes the handler for each element in it. The JSON result is assumed to be an array. */
|
||||
|
@ -182,6 +263,103 @@ function run_get_request(url, handler) {
|
|||
})
|
||||
}
|
||||
|
||||
/* As above but with POST request. */
|
||||
function run_post_request(url, data_map, handler) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: data_map,
|
||||
success: function(data){
|
||||
$('#global_error').text('')
|
||||
$.each($.parseJSON(data), function(idx, contents) {
|
||||
handler(contents)
|
||||
})
|
||||
},
|
||||
error: request_failed
|
||||
})
|
||||
}
|
||||
|
||||
function rgb_to_hsl(r, g, b){
|
||||
r /= 255, g /= 255, b /= 255;
|
||||
var max = Math.max(r, g, b), min = Math.min(r, g, b);
|
||||
var h, s, l = (max + min) / 2;
|
||||
|
||||
if(max == min){
|
||||
h = s = 0; // achromatic
|
||||
}else{
|
||||
var d = max - min;
|
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||
switch(max){
|
||||
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
||||
case g: h = (b - r) / d + 2; break;
|
||||
case b: h = (r - g) / d + 4; break;
|
||||
}
|
||||
h /= 6;
|
||||
}
|
||||
|
||||
return [h, s, l];
|
||||
}
|
||||
|
||||
function hsl_to_rgb(h, s, l){
|
||||
var r, g, b;
|
||||
|
||||
if(s == 0){
|
||||
r = g = b = l; // achromatic
|
||||
}else{
|
||||
function hue2rgb(p, q, t){
|
||||
if(t < 0) t += 1;
|
||||
if(t > 1) t -= 1;
|
||||
if(t < 1/6) return p + (q - p) * 6 * t;
|
||||
if(t < 1/2) return q;
|
||||
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
|
||||
return p;
|
||||
}
|
||||
|
||||
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
var p = 2 * l - q;
|
||||
r = hue2rgb(p, q, h + 1.0/3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1.0/3);
|
||||
}
|
||||
|
||||
return [r * 255, g * 255, b * 255]
|
||||
}
|
||||
|
||||
/* Given an RGB color as a hex string, like FF0033, convert to HSL, apply the function to adjust its lightness, then return the new color as an RGB string */
|
||||
function adjust_lightness(color_str, func) {
|
||||
/* Hack to handle for example F00 */
|
||||
if (color_str.length == 3) {
|
||||
color_str = color_str[0] + color_str[0] + color_str[1] + color_str[1] + color_str[2] + color_str[2]
|
||||
}
|
||||
|
||||
rgb = parseInt(color_str, 16)
|
||||
r = (rgb >> 16) & 0xFF
|
||||
g = (rgb >> 8) & 0xFF
|
||||
b = (rgb >> 0) & 0xFF
|
||||
|
||||
hsl = rgb_to_hsl(r, g, b)
|
||||
new_lightness = func(hsl[2])
|
||||
function to_int_str(val) {
|
||||
str = Math.round(val).toString(16)
|
||||
while (str.length < 2)
|
||||
str = '0' + str
|
||||
return str
|
||||
}
|
||||
|
||||
new_rgb = hsl_to_rgb(hsl[0], hsl[1], new_lightness)
|
||||
return to_int_str(new_rgb[0]) + to_int_str(new_rgb[1]) + to_int_str(new_rgb[2])
|
||||
}
|
||||
|
||||
/* Given a color, compute the master text color for it, by giving it a minimum brightness */
|
||||
function master_color_for_color(color_str) {
|
||||
return adjust_lightness(color_str, function(lightness){
|
||||
if (lightness < .33) {
|
||||
lightness = .33
|
||||
}
|
||||
return lightness
|
||||
})
|
||||
}
|
||||
|
||||
function switch_tab(new_tab) {
|
||||
/* Switch selected tab */
|
||||
$(".selected_tab").removeClass("selected_tab")
|
||||
|
@ -190,25 +368,40 @@ function switch_tab(new_tab) {
|
|||
/* Empty master element */
|
||||
$('#master').empty()
|
||||
|
||||
/* Unselect some things */
|
||||
$(".colorpicker_cell_selected").removeClass('colorpicker_cell_selected')
|
||||
|
||||
/* Hide some things */
|
||||
$('#colorpicker_term256').hide()
|
||||
$('#master_detail_table').hide()
|
||||
$('#detail_colorpicker').hide()
|
||||
$('#detail_function').hide()
|
||||
$('#data_table').hide()
|
||||
$('#data_table').empty()
|
||||
|
||||
/* Load something new */
|
||||
if (new_tab == 'tab_colors') {
|
||||
run_get_request('/colors/', function(contents){
|
||||
var key = contents[0]
|
||||
var value = contents[1]
|
||||
var color = (value.length > 0 ? '#' + value : '')
|
||||
create_master_element(key, color)
|
||||
/* Keep track of whether this is the first element */
|
||||
var first = true
|
||||
run_get_request('/colors/', function(key_and_values){
|
||||
var key = key_and_values[0]
|
||||
var style = new Style(key_and_values[1])
|
||||
style_map[key] = style
|
||||
|
||||
elem = create_master_element(key, style.color, select_color_master_element)
|
||||
if (first) {
|
||||
/* It's the first element, so select it, so something gets selected */
|
||||
select_color_master_element(elem)
|
||||
first = false
|
||||
}
|
||||
})
|
||||
$('#colorpicker_term256').show()
|
||||
$('#detail_colorpicker').show()
|
||||
$('#master_detail_table').show()
|
||||
} else if (new_tab == 'tab_functions') {
|
||||
run_get_request('/functions/', function(contents){
|
||||
create_master_element(contents, '')
|
||||
create_master_element(contents, 'AAAAAA', select_function_master_element)
|
||||
})
|
||||
$('#data_table').show()
|
||||
$('#detail_function').show()
|
||||
$('#master_detail_table').show()
|
||||
} else if (new_tab == 'tab_variables') {
|
||||
run_get_request('/variables/', function(contents){
|
||||
var name = contents[0]
|
||||
|
@ -228,47 +421,172 @@ function switch_tab(new_tab) {
|
|||
return false
|
||||
}
|
||||
|
||||
function select_master_element(elem) {
|
||||
$(".selected_master_elem").removeClass("selected_master_elem")
|
||||
$(elem).addClass("selected_master_elem")
|
||||
|
||||
function current_master_element_name() {
|
||||
/* Get the name of the current color variable, like 'autosuggestion' */
|
||||
var elems = $('.selected_master_elem')
|
||||
if (elems.length == 0) {
|
||||
return ''
|
||||
}
|
||||
elem = elems[0]
|
||||
if (elem.id.indexOf('master_') != 0) {
|
||||
show_error('Unknown color variable')
|
||||
return ''
|
||||
}
|
||||
return elem.id.substring(7)
|
||||
}
|
||||
|
||||
/* The first index here corresponds to value 16 */
|
||||
term256_colors = [
|
||||
"ffd7d7", "d7afaf", "af8787", "875f5f", "ffafaf", "d78787", "af5f5f", "ff8787", //8
|
||||
"d75f5f", "ff5f5f", "5f0000", "870000", "af0000", "d70000", "ff0000", "ff875f", //16
|
||||
"ffaf87", "d7875f", "ff5f00", "d75f00", "ffd7af", "d7af87", "af875f", "ffaf5f", //24
|
||||
"ff8700", "af5f00", "d78700", "ffd787", "d7af5f", "ffaf00", "875f00", "ffd75f", //32
|
||||
"af8700", "d7af00", "ffd700", "ffffd7", "d7d7af", "afaf87", "87875f", "ffffaf", //40
|
||||
"d7d787", "afaf5f", "ffff87", "d7d75f", "ffff5f", "5f5f00", "878700", "afaf00", //48
|
||||
"d7d700", "ffff00", "d7ff00", "afd700", "87af00", "d7ff5f", "5f8700", "afff00", //56
|
||||
"d7ff87", "afd75f", "87d700", "5faf00", "87ff00", "d7ffaf", "afd787", "87af5f", //64
|
||||
"afff5f", "5fd700", "5fff00", "afff87", "87d75f", "87ff5f", "d7ffd7", "afd7af", //72
|
||||
"87af87", "5f875f", "afffaf", "87d787", "5faf5f", "87ff87", "5fd75f", "5fff5f", //80
|
||||
"005f00", "008700", "00af00", "00d700", "00ff00", "5fff87", "87ffaf", "5fd787", //88
|
||||
"00ff5f", "00d75f", "afffd7", "87d7af", "5faf87", "5fffaf", "00ff87", "00af5f", //96
|
||||
"00d787", "87ffd7", "5fd7af", "00ffaf", "00875f", "5fffd7", "00af87", "00d7af", //104
|
||||
"00ffd7", "d7ffff", "afd7d7", "87afaf", "5f8787", "afffff", "87d7d7", "5fafaf", //112
|
||||
"87ffff", "5fd7d7", "5fffff", "005f5f", "008787", "00afaf", "00d7d7", "00ffff", //120
|
||||
"00d7ff", "00afd7", "0087af", "5fd7ff", "005f87", "00afff", "87d7ff", "5fafd7", //128
|
||||
"0087d7", "005faf", "0087ff", "afd7ff", "87afd7", "5f87af", "5fafff", "005fd7", //136
|
||||
"005fff", "87afff", "5f87d7", "5f87ff", "d7d7ff", "afafd7", "8787af", "5f5f87", //144
|
||||
"afafff", "8787d7", "5f5faf", "8787ff", "5f5fd7", "5f5fff", "00005f", "000087", //152
|
||||
"0000af", "0000d7", "0000ff", "875fff", "af87ff", "875fd7", "5f00ff", "5f00d7", //160
|
||||
"d7afff", "af87d7", "875faf", "af5fff", "8700ff", "5f00af", "8700d7", "d787ff", //168
|
||||
"af5fd7", "af00ff", "5f0087", "d75fff", "8700af", "af00d7", "d700ff", "ffd7ff", //176
|
||||
"d7afd7", "af87af", "875f87", "ffafff", "d787d7", "af5faf", "ff87ff", "d75fd7", //184
|
||||
"ff5fff", "5f005f", "870087", "af00af", "d700d7", "ff00ff", "ff00d7", "d700af", //192
|
||||
"af0087", "ff5fd7", "87005f", "ff00af", "ff87d7", "d75faf", "d70087", "af005f", //200
|
||||
"ff0087", "ffafd7", "d787af", "af5f87", "ff5faf", "d7005f", "ff005f", "ff87af", //208
|
||||
"d75f87", "ff5f87", "000000", "080808", "121212", "1c1c1c", "262626", "303030", //216
|
||||
"3a3a3a", "444444", "4e4e4e", "585858", "5f5f5f", "626262", "6c6c6c", "767676", //224
|
||||
"808080", "878787", "8a8a8a", "949494", "9e9e9e", "a8a8a8", "afafaf", "b2b2b2", //232
|
||||
"bcbcbc", "c6c6c6", "d0d0d0", "d7d7d7", "dadada", "e4e4e4", "eeeeee", "ffffff" //240
|
||||
]
|
||||
function is_foreground() {
|
||||
/* Returns true if the selected tab is foreground, false if it's background */
|
||||
who = $('.colorpicker_ground_selected')
|
||||
if (who.length == 0) {
|
||||
show_error('Not sure if we are in foreground or background')
|
||||
return false
|
||||
}
|
||||
return who[0].id == 'foreground'
|
||||
}
|
||||
|
||||
term256_colors = [ //222
|
||||
function current_style() {
|
||||
/* Returns the style object corresponding to the current color variable */
|
||||
return style_map[current_master_element_name()]
|
||||
}
|
||||
|
||||
function reflect_style() {
|
||||
/* Unselect everything */
|
||||
$('.colorpicker_cell_selected').removeClass('colorpicker_cell_selected')
|
||||
$('.modifier_cell_selected').removeClass('modifier_cell_selected')
|
||||
|
||||
/* Now update the color picker with the current style (if we have one) */
|
||||
style = current_style()
|
||||
if (style) {
|
||||
|
||||
var adjust = .5
|
||||
function compute_constrast(lightness){
|
||||
var new_lightness = lightness + adjust
|
||||
if (new_lightness > 1.0 || new_lightness < 0.0) {
|
||||
new_lightness -= 2 * adjust
|
||||
}
|
||||
return new_lightness
|
||||
}
|
||||
|
||||
color = is_foreground() ? style.color : style.background_color
|
||||
var color_cell = $('#color_' + color)
|
||||
color_cell.addClass('colorpicker_cell_selected')
|
||||
color_cell.css('border-color', adjust_lightness(is_foreground() ? style.color : style.background_color, compute_constrast))
|
||||
|
||||
if (style.underline) {
|
||||
$('#modifier_underline').addClass('modifier_cell_selected')
|
||||
}
|
||||
|
||||
/* In the master list, ensure the color is visible against the dark background. If we're deselecting, use COLOR_NORMAL */
|
||||
master_color = style.color ? master_color_for_color(style.color) : COLOR_NORMAL
|
||||
$('.selected_master_elem').children('.master_element_text').css({'color': master_color, 'border-bottom-color': master_color})
|
||||
}
|
||||
}
|
||||
|
||||
function select_master_element(elem) {
|
||||
$('.selected_master_elem').removeClass('selected_master_elem')
|
||||
$(elem).addClass('selected_master_elem')
|
||||
}
|
||||
|
||||
function select_color_master_element(elem) {
|
||||
select_master_element(elem)
|
||||
|
||||
/* This changed the current style; reflect that */
|
||||
reflect_style()
|
||||
}
|
||||
|
||||
function select_function_master_element(elem) {
|
||||
select_master_element(elem)
|
||||
|
||||
run_post_request('/get_function/', {
|
||||
what: current_master_element_name()
|
||||
}, function(contents){
|
||||
$('#detail_function').text(contents)
|
||||
});
|
||||
}
|
||||
|
||||
function post_style_to_server() {
|
||||
style = current_style()
|
||||
if (! style)
|
||||
return
|
||||
|
||||
run_post_request('/set_color/', {
|
||||
what: current_master_element_name(),
|
||||
color: style.color,
|
||||
background_color: style.background_color,
|
||||
bold: style.bold,
|
||||
underline: style.underline
|
||||
}, function(contents){
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
function picked_color_cell(cell) {
|
||||
|
||||
/* Get the color to set */
|
||||
if (cell.id.indexOf('color_') != 0) {
|
||||
show_error('Unknown cell')
|
||||
return
|
||||
}
|
||||
color = cell.id.substring(6)
|
||||
|
||||
/* Determine whether we are going to select or unselect this cell */
|
||||
var deselect = $(cell).hasClass('colorpicker_cell_selected')
|
||||
|
||||
/* Get the current style */
|
||||
style = current_style()
|
||||
if (! style)
|
||||
return
|
||||
|
||||
/* Change the color */
|
||||
if (is_foreground()) {
|
||||
style.color = deselect ? '' : color
|
||||
} else {
|
||||
style.background_color = deselect ? '' : color
|
||||
}
|
||||
|
||||
/* Show our changes */
|
||||
reflect_style()
|
||||
|
||||
/* Tell the server */
|
||||
post_style_to_server()
|
||||
}
|
||||
|
||||
function picked_modifier(cell) {
|
||||
style = current_style()
|
||||
if (! style)
|
||||
return
|
||||
if (cell.id == 'modifier_underline') {
|
||||
style.underline = ! style.underline
|
||||
} else if (cell.id == 'modifier_bold') {
|
||||
style.bold = ! style.bold
|
||||
} else {
|
||||
show_error('Unknown cell')
|
||||
}
|
||||
|
||||
reflect_style()
|
||||
post_style_to_server()
|
||||
}
|
||||
|
||||
function picked_ground(tab) {
|
||||
/* The function that gets called when a tab is selected */
|
||||
$('.colorpicker_ground_selected').removeClass('colorpicker_ground_selected')
|
||||
$(tab).addClass('colorpicker_ground_selected')
|
||||
reflect_style()
|
||||
}
|
||||
|
||||
/* Class representing a color style */
|
||||
function Style(stuff) {
|
||||
this.color = stuff[0]
|
||||
this.background_color = stuff[1]
|
||||
this.bold = stuff[2]
|
||||
this.underline = stuff[3]
|
||||
}
|
||||
|
||||
var style_map = new Array();
|
||||
|
||||
/* The first index here corresponds to value 16 */
|
||||
term256_colors = [ //247
|
||||
"ffd7d7",
|
||||
"d7afaf",
|
||||
"af8787",
|
||||
|
@ -514,15 +832,21 @@ term256_colors = [ //222
|
|||
var items_per_row = 15
|
||||
var show_labels = 0
|
||||
|
||||
var COLOR_NORMAL = 'DDDDDD'
|
||||
|
||||
/* Adds a new element to master */
|
||||
function create_master_element(contents, color) {
|
||||
function create_master_element(contents, color, click_handler) {
|
||||
if (color.length == 0) color = 'inherit'
|
||||
style_str = 'color: ' + color + '; border-bottom: 1px solid ' + color + ' ;'
|
||||
$('<div/>', {
|
||||
|
||||
/* In the master list, ensure the color is visible against the dark background */
|
||||
master_color = master_color_for_color(color)
|
||||
style_str = 'color: #' + master_color + '; border-bottom: 1px solid #' + master_color + ' ;'
|
||||
|
||||
elem = $('<div/>', {
|
||||
class: 'master_element',
|
||||
id: 'master_' + contents,
|
||||
click: function(){
|
||||
select_master_element(this)
|
||||
//$(this).toggleClass('master_element');
|
||||
click_handler(this)
|
||||
}
|
||||
}).append(
|
||||
$("<span/>", {
|
||||
|
@ -530,7 +854,10 @@ function create_master_element(contents, color) {
|
|||
style: style_str,
|
||||
text: contents,
|
||||
})
|
||||
).appendTo('#master')
|
||||
)
|
||||
|
||||
elem.appendTo('#master')
|
||||
return elem
|
||||
}
|
||||
|
||||
/* Toggle the no_overflow class */
|
||||
|
@ -555,7 +882,7 @@ function create_data_table_element(contents_list) {
|
|||
cell = $('<td>', {
|
||||
class: 'data_table_cell no_overflow',
|
||||
style: 'text-align: left',
|
||||
onClick: "toggle_overflow(this)"
|
||||
onClick: 'toggle_overflow(this)'
|
||||
});
|
||||
}
|
||||
text_list = contents_list[idx].split("\n")
|
||||
|
@ -578,19 +905,19 @@ function populate_colorpicker_term256() {
|
|||
class: 'colorpicker_term256_row'
|
||||
})
|
||||
|
||||
var subidx
|
||||
for (subidx = 0; subidx < items_per_row && idx + subidx < term256_colors.length; subidx++) {
|
||||
for (var subidx = 0; subidx < items_per_row && idx + subidx < term256_colors.length; subidx++) {
|
||||
cell_style = 'background-color: #' + term256_colors[idx + subidx]
|
||||
row.append($('<td>', {
|
||||
class: 'colorpicker_term256_cell',
|
||||
style: cell_style,
|
||||
text: show_labels ? String(subidx + idx + 223) : ''
|
||||
id: 'color_' + term256_colors[idx + subidx],
|
||||
text: show_labels ? String(subidx + idx + 223) : '',
|
||||
onClick: 'picked_color_cell(this)'
|
||||
}))
|
||||
}
|
||||
|
||||
$('#colorpicker_term256').append(row)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
|
@ -611,11 +938,22 @@ $(document).ready(function() {
|
|||
<div class="tab" id="tab_variables" onClick="switch_tab('tab_variables')">variables</div>
|
||||
<div class="tab" id="tab_history" onClick="switch_tab('tab_history')">history</div>
|
||||
</div>
|
||||
<div id="master_detail_box">
|
||||
<div id="master_detail_table">
|
||||
<div id="master">
|
||||
</div>
|
||||
<table id="colorpicker_term256">
|
||||
</table>
|
||||
<div id="detail">
|
||||
<div id="detail_colorpicker">
|
||||
<div class="colorpicker_ground">
|
||||
<div class="colorpicker_ground_tab colorpicker_ground_selected" id="foreground" onClick="picked_ground(this)">Foreground</div><div class="colorpicker_ground_tab" id="background" onClick="picked_ground(this)">Background</div>
|
||||
</div>
|
||||
<table id="colorpicker_term256">
|
||||
</table>
|
||||
<div class="colorpicker_modifiers">
|
||||
<div class="colorpicker_modifier_cell" id="modifier_underline" style="text-decoration: underline" onClick='picked_modifier(this)'>Underline</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="detail_function"></div>
|
||||
</div>
|
||||
</div>
|
||||
<table id="data_table">
|
||||
<table>
|
||||
|
@ -624,6 +962,4 @@ $(document).ready(function() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<a id="thelink">Click me</a>
|
||||
|
||||
</body></html>
|
||||
|
|
|
@ -4,7 +4,7 @@ import SimpleHTTPServer
|
|||
import SocketServer
|
||||
import webbrowser
|
||||
import subprocess
|
||||
import re, json, socket, sys
|
||||
import re, json, socket, sys, cgi
|
||||
|
||||
def run_fish_cmd(text):
|
||||
from subprocess import PIPE
|
||||
|
@ -25,12 +25,24 @@ named_colors = {
|
|||
'white' : 'FFFFFF'
|
||||
}
|
||||
|
||||
def parse_one_color(comp):
|
||||
""" A basic function to parse a single color value like 'FFA000' """
|
||||
if comp in named_colors:
|
||||
# Named color
|
||||
return named_colors[comp]
|
||||
elif re.match(r"[0-9a-fA-F]{3}", comp) is not None or re.match(r"[0-9a-fA-F]{6}", comp) is not None:
|
||||
# Hex color
|
||||
return comp
|
||||
else:
|
||||
# Unknown
|
||||
return ''
|
||||
|
||||
|
||||
def parse_color(color_str):
|
||||
""" A basic function to parse a color string, for example, 'red' '--bold' """
|
||||
comps = color_str.split(' ')
|
||||
print "comps: ", comps
|
||||
color = 'normal'
|
||||
background_color = ''
|
||||
bold, underline = False, False
|
||||
for comp in comps:
|
||||
# Remove quotes
|
||||
|
@ -39,16 +51,22 @@ def parse_color(color_str):
|
|||
bold = True
|
||||
elif comp == '--underline':
|
||||
underline = True
|
||||
elif comp in named_colors:
|
||||
# Named color
|
||||
color = named_colors[comp]
|
||||
elif re.match(r"[0-9a-fA-F]{3}", comp) is not None or re.match(r"[0-9a-fA-F]{6}", comp) is not None:
|
||||
# Hex color
|
||||
color = comp
|
||||
elif comp.startswith('--background='):
|
||||
# Background color
|
||||
background_color = parse_one_color(comp[len('--background='):])
|
||||
else:
|
||||
# Unknown component
|
||||
pass
|
||||
return color
|
||||
# Regular color
|
||||
maybe_color = parse_one_color(comp)
|
||||
if maybe_color: color = maybe_color
|
||||
|
||||
return [color, background_color, bold, underline]
|
||||
|
||||
|
||||
def parse_bool(val):
|
||||
val = val.lower()
|
||||
if val.startswith('f') or val.startswith('0'): return False
|
||||
if val.startswith('t') or val.startswith('1'): return True
|
||||
return bool(val)
|
||||
|
||||
class FishVar:
|
||||
""" A class that represents a variable """
|
||||
|
@ -72,7 +90,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|||
result = []
|
||||
out, err = run_fish_cmd('set -L')
|
||||
for line in out.split('\n'):
|
||||
for match in re.finditer(r"^fish_color_(\S+) (.+)", line):
|
||||
for match in re.finditer(r"^fish_color_(\S+) ?(.*)", line):
|
||||
color_name, color_value = match.group(1, 2)
|
||||
result.append([color_name.strip(), parse_color(color_value)])
|
||||
print result
|
||||
|
@ -81,7 +99,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|||
def do_get_functions(self):
|
||||
out, err = run_fish_cmd('functions')
|
||||
out = out.strip()
|
||||
print out
|
||||
|
||||
# Not sure why fish sometimes returns this with newlines
|
||||
if "\n" in out:
|
||||
return out.split('\n')
|
||||
|
@ -124,7 +142,23 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|||
"Return the color with the given name, or the empty string if there is none"
|
||||
out, err = run_fish_cmd("echo -n $" + name)
|
||||
return out
|
||||
|
||||
|
||||
def do_set_color_for_variable(self, name, color, background_color, bold, underline):
|
||||
if not color: color = 'normal'
|
||||
"Sets a color for a fish color name, like 'autosuggestion'"
|
||||
command = 'set -U fish_color_' + name
|
||||
if color: command += ' ' + color
|
||||
if background_color: command += ' --background=' + background_color
|
||||
if bold: command += ' --bold'
|
||||
if underline: command += ' --underline'
|
||||
|
||||
out, err = run_fish_cmd(command)
|
||||
return out
|
||||
|
||||
def do_get_function(self, func_name):
|
||||
out, err = run_fish_cmd('functions ' + func_name)
|
||||
return out
|
||||
|
||||
def do_GET(self):
|
||||
p = self.path
|
||||
if p == '/colors/':
|
||||
|
@ -149,7 +183,43 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|||
# Output JSON
|
||||
json.dump(output, self.wfile)
|
||||
|
||||
def do_POST(self):
|
||||
p = self.path
|
||||
ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
|
||||
if ctype == 'multipart/form-data':
|
||||
postvars = cgi.parse_multipart(self.rfile, pdict)
|
||||
elif ctype == 'application/x-www-form-urlencoded':
|
||||
length = int(self.headers.getheader('content-length'))
|
||||
postvars = cgi.parse_qs(self.rfile.read(length), keep_blank_values=1)
|
||||
else:
|
||||
postvars = {}
|
||||
|
||||
if p == '/set_color/':
|
||||
what = postvars.get('what')
|
||||
color = postvars.get('color')
|
||||
background_color = postvars.get('background_color')
|
||||
bold = postvars.get('bold')
|
||||
underline = postvars.get('underline')
|
||||
print "underline: ", underline
|
||||
if what:
|
||||
# Not sure why we get lists here?
|
||||
output = self.do_set_color_for_variable(what[0], color[0], background_color[0], parse_bool(bold[0]), parse_bool(underline[0]))
|
||||
else:
|
||||
output = 'Bad request'
|
||||
elif p == '/get_function/':
|
||||
what = postvars.get('what')
|
||||
output = [self.do_get_function(what[0])]
|
||||
else:
|
||||
return SimpleHTTPServer.SimpleHTTPRequestHandler.do_POST(self)
|
||||
|
||||
# Return valid output
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type','text/html')
|
||||
self.wfile.write('\n')
|
||||
|
||||
# Output JSON
|
||||
json.dump(output, self.wfile)
|
||||
|
||||
|
||||
PORT = 8000
|
||||
while PORT <= 9000:
|
||||
|
|
Loading…
Reference in a new issue