Lots of work on web config

Change to make fish immediately show color changes
This commit is contained in:
ridiculousfish 2012-03-25 03:00:38 -07:00
parent c0655b6b08
commit 0c9a1a56c2
9 changed files with 576 additions and 129 deletions

12
env.cpp
View file

@ -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);
}
/**

View file

@ -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;
}
}
}

View file

@ -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
*/

View file

@ -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;
}

View file

@ -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.

View file

@ -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, );

View file

@ -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

View file

@ -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>

View file

@ -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: