mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-13 13:39:02 +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();
|
handle_locale();
|
||||||
} else if (key == L"fish_term256") {
|
} else if (key == L"fish_term256") {
|
||||||
update_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;
|
const wchar_t *str=0;
|
||||||
|
|
||||||
if( var_is_locale( name ) )
|
|
||||||
{
|
|
||||||
handle_locale();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch( type )
|
switch( type )
|
||||||
{
|
{
|
||||||
case SET:
|
case SET:
|
||||||
|
@ -388,6 +385,9 @@ static void universal_callback( int type,
|
||||||
event_fire( &ev );
|
event_fire( &ev );
|
||||||
ev.arguments.reset(NULL);
|
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;
|
static int lookahead_count = 0;
|
||||||
|
|
||||||
/**
|
/** Callback function for handling interrupts on reading */
|
||||||
Callback function for handling interrupts on reading
|
|
||||||
*/
|
|
||||||
static int (*interrupt_handler)();
|
static int (*interrupt_handler)();
|
||||||
|
|
||||||
|
/** Callback function to be invoked before reading each byte */
|
||||||
|
static void (*poll_handler)();
|
||||||
|
|
||||||
|
|
||||||
void input_common_init( int (*ih)() )
|
void input_common_init( int (*ih)() )
|
||||||
{
|
{
|
||||||
interrupt_handler = ih;
|
interrupt_handler = ih;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void input_common_set_poll_callback(void (*handler)(void))
|
||||||
|
{
|
||||||
|
poll_handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
void input_common_destroy()
|
void input_common_destroy()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -66,10 +73,14 @@ void input_common_destroy()
|
||||||
static wint_t readb()
|
static wint_t readb()
|
||||||
{
|
{
|
||||||
unsigned char arr[1];
|
unsigned char arr[1];
|
||||||
int do_loop = 0;
|
bool do_loop = false;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
/* Invoke any poll handler */
|
||||||
|
if (poll_handler)
|
||||||
|
poll_handler();
|
||||||
|
|
||||||
fd_set fdset;
|
fd_set fdset;
|
||||||
int fd_max=0;
|
int fd_max=0;
|
||||||
int ioport = iothread_port();
|
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 );
|
res = select( fd_max + 1, &fdset, 0, 0, 0 );
|
||||||
if( res==-1 )
|
if( res==-1 )
|
||||||
|
@ -113,7 +124,7 @@ static wint_t readb()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
do_loop = 1;
|
do_loop = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -133,7 +144,7 @@ static wint_t readb()
|
||||||
{
|
{
|
||||||
debug( 3, L"Wake up on universal variable event" );
|
debug( 3, L"Wake up on universal variable event" );
|
||||||
env_universal_read_all();
|
env_universal_read_all();
|
||||||
do_loop = 1;
|
do_loop = true;
|
||||||
|
|
||||||
if( lookahead_count )
|
if( lookahead_count )
|
||||||
{
|
{
|
||||||
|
@ -148,7 +159,7 @@ static wint_t readb()
|
||||||
{
|
{
|
||||||
iothread_service_completion();
|
iothread_service_completion();
|
||||||
}
|
}
|
||||||
do_loop = 1;
|
do_loop = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( FD_ISSET( 0, &fdset ) )
|
if( FD_ISSET( 0, &fdset ) )
|
||||||
|
@ -160,7 +171,7 @@ static wint_t readb()
|
||||||
*/
|
*/
|
||||||
return R_EOF;
|
return R_EOF;
|
||||||
}
|
}
|
||||||
do_loop = 0;
|
do_loop = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,9 @@ enum
|
||||||
*/
|
*/
|
||||||
void input_common_init( int (*ih)() );
|
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
|
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
|
Keep track of whether any internal code has done something
|
||||||
which is known to require a repaint.
|
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],
|
&indents[0],
|
||||||
data->buff_pos );
|
data->buff_pos );
|
||||||
#endif
|
#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_lflag &= ~ECHO; /* turn off echo mode */
|
||||||
shell_modes.c_cc[VMIN]=1;
|
shell_modes.c_cc[VMIN]=1;
|
||||||
shell_modes.c_cc[VTIME]=0;
|
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()
|
void reader_repaint_needed()
|
||||||
{
|
{
|
||||||
if( data )
|
if (data) {
|
||||||
{
|
data->repaint_needed = true;
|
||||||
data->repaint_needed = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 );
|
free( prefix );
|
||||||
s_reset( &data->screen, 1 );
|
s_reset( &data->screen, true);
|
||||||
reader_repaint();
|
reader_repaint();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2325,7 +2348,7 @@ void reader_pop()
|
||||||
{
|
{
|
||||||
end_loop = 0;
|
end_loop = 0;
|
||||||
//history_set_mode( data->app_name.c_str() );
|
//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();
|
exec_prompt();
|
||||||
|
|
||||||
reader_super_highlight_me_plenty( data->buff_pos );
|
reader_super_highlight_me_plenty( data->buff_pos );
|
||||||
s_reset( &data->screen, 1 );
|
s_reset( &data->screen, true);
|
||||||
reader_repaint();
|
reader_repaint();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2804,9 +2827,7 @@ const wchar_t *reader_readline()
|
||||||
|
|
||||||
case R_NULL:
|
case R_NULL:
|
||||||
{
|
{
|
||||||
if( data->repaint_needed )
|
reader_repaint_if_needed();
|
||||||
reader_repaint();
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2814,7 +2835,7 @@ const wchar_t *reader_readline()
|
||||||
{
|
{
|
||||||
exec_prompt();
|
exec_prompt();
|
||||||
write_loop( 1, "\r", 1 );
|
write_loop( 1, "\r", 1 );
|
||||||
s_reset( &data->screen, 0 );
|
s_reset( &data->screen, false);
|
||||||
reader_repaint();
|
reader_repaint();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3084,7 +3105,7 @@ const wchar_t *reader_readline()
|
||||||
*/
|
*/
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
s_reset( &data->screen, 1 );
|
s_reset( &data->screen, true);
|
||||||
reader_repaint();
|
reader_repaint();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
6
reader.h
6
reader.h
|
@ -75,6 +75,12 @@ void reader_write_title();
|
||||||
*/
|
*/
|
||||||
void reader_repaint_needed();
|
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
|
Run the specified command with the correct terminal modes, and
|
||||||
while taking care to perform job notification, set the title, etc.
|
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];
|
int prev_line = s->actual.cursor[1];
|
||||||
write_loop( 1, "\r", 1 );
|
write_loop( 1, "\r", 1 );
|
||||||
s_reset( s, 0 );
|
s_reset( s, false );
|
||||||
s->actual.cursor[1] = prev_line;
|
s->actual.cursor[1] = prev_line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -606,7 +606,7 @@ static void s_update( screen_t *scr, const wchar_t *prompt )
|
||||||
need_clear = 1;
|
need_clear = 1;
|
||||||
s_move( scr, &output, 0, 0 );
|
s_move( scr, &output, 0, 0 );
|
||||||
scr->actual_width = screen_width;
|
scr->actual_width = screen_width;
|
||||||
s_reset( scr, 0 );
|
s_reset( scr, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( wcscmp( prompt, scr->actual_prompt.c_str() ) )
|
if( wcscmp( prompt, scr->actual_prompt.c_str() ) )
|
||||||
|
@ -855,7 +855,7 @@ void s_write( screen_t *s,
|
||||||
s_save_status( 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, );
|
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.
|
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.
|
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;
|
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
|
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,
|
resizing, there will be one line of garbage for every repaint,
|
||||||
which will quicly fill the screen.
|
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
|
#endif
|
||||||
|
|
|
@ -56,34 +56,56 @@ body {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#master_detail_box {
|
#master_detail_table {
|
||||||
overflow: hidden;
|
display: table;
|
||||||
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#master {
|
#master {
|
||||||
float: left;
|
display: table-cell;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
font-size: 16pt;
|
font-size: 16pt;
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
|
padding-bottom: 0px;
|
||||||
margin-top: -7px;
|
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 {
|
.master_element {
|
||||||
padding-top: 7px;
|
padding-top: 6px;
|
||||||
padding-bottom: 12px;
|
padding-bottom: 11px;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
padding-right: 32px;
|
padding-right: 32px;
|
||||||
font-size: 12pt;
|
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 {
|
.selected_master_elem {
|
||||||
border: 1px solid #555;
|
border: 1px solid #555;
|
||||||
border-right: none;
|
border-right: none;
|
||||||
/* Make our border overlap the box */
|
background-color: #181818;
|
||||||
position: relative;
|
|
||||||
left: 1px;
|
/* Pad one less than .master_element, to accomodate our border. */
|
||||||
background-color: black;
|
padding-top: 5px;
|
||||||
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.master_element_text {
|
.master_element_text {
|
||||||
|
@ -93,8 +115,33 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
#colorpicker_term256 {
|
#colorpicker_term256 {
|
||||||
padding: 30px;
|
border: solid #444 1px;
|
||||||
border: 1px solid #555;
|
}
|
||||||
|
|
||||||
|
.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 {
|
#data_table {
|
||||||
|
@ -120,16 +167,46 @@ body {
|
||||||
white-space: nowrap;
|
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_row {
|
||||||
}
|
}
|
||||||
|
|
||||||
.colorpicker_term256_cell {
|
.colorpicker_term256_cell {
|
||||||
width: 24;
|
width: 27;
|
||||||
height: 24;
|
height: 27;
|
||||||
}
|
}
|
||||||
|
|
||||||
.colorpicker_cell_selected {
|
.colorpicker_cell_selected {
|
||||||
border: solid white 3px;
|
border: dashed white 3px;
|
||||||
|
width: 21;
|
||||||
|
height: 21;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error_msg {
|
.error_msg {
|
||||||
|
@ -145,6 +222,10 @@ body {
|
||||||
<script type="text/javascript" src="jquery.js"></script>
|
<script type="text/javascript" src="jquery.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
function show_error(msg) {
|
||||||
|
$('#global_error').text(msg)
|
||||||
|
}
|
||||||
|
|
||||||
function request_failed(jqXHR, textStatus, errorThrown) {
|
function request_failed(jqXHR, textStatus, errorThrown) {
|
||||||
msg = ''
|
msg = ''
|
||||||
if (textStatus == "timeout") {
|
if (textStatus == "timeout") {
|
||||||
|
@ -164,7 +245,7 @@ function request_failed(jqXHR, textStatus, errorThrown) {
|
||||||
if (errorThrown.length > 0) {
|
if (errorThrown.length > 0) {
|
||||||
msg = msg + ' The HTTP reply returned ' + errorThrown
|
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. */
|
/* 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) {
|
function switch_tab(new_tab) {
|
||||||
/* Switch selected tab */
|
/* Switch selected tab */
|
||||||
$(".selected_tab").removeClass("selected_tab")
|
$(".selected_tab").removeClass("selected_tab")
|
||||||
|
@ -190,25 +368,40 @@ function switch_tab(new_tab) {
|
||||||
/* Empty master element */
|
/* Empty master element */
|
||||||
$('#master').empty()
|
$('#master').empty()
|
||||||
|
|
||||||
|
/* Unselect some things */
|
||||||
|
$(".colorpicker_cell_selected").removeClass('colorpicker_cell_selected')
|
||||||
|
|
||||||
/* Hide some things */
|
/* Hide some things */
|
||||||
$('#colorpicker_term256').hide()
|
$('#master_detail_table').hide()
|
||||||
|
$('#detail_colorpicker').hide()
|
||||||
|
$('#detail_function').hide()
|
||||||
$('#data_table').hide()
|
$('#data_table').hide()
|
||||||
$('#data_table').empty()
|
$('#data_table').empty()
|
||||||
|
|
||||||
/* Load something new */
|
/* Load something new */
|
||||||
if (new_tab == 'tab_colors') {
|
if (new_tab == 'tab_colors') {
|
||||||
run_get_request('/colors/', function(contents){
|
/* Keep track of whether this is the first element */
|
||||||
var key = contents[0]
|
var first = true
|
||||||
var value = contents[1]
|
run_get_request('/colors/', function(key_and_values){
|
||||||
var color = (value.length > 0 ? '#' + value : '')
|
var key = key_and_values[0]
|
||||||
create_master_element(key, color)
|
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') {
|
} else if (new_tab == 'tab_functions') {
|
||||||
run_get_request('/functions/', function(contents){
|
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') {
|
} else if (new_tab == 'tab_variables') {
|
||||||
run_get_request('/variables/', function(contents){
|
run_get_request('/variables/', function(contents){
|
||||||
var name = contents[0]
|
var name = contents[0]
|
||||||
|
@ -228,47 +421,172 @@ function switch_tab(new_tab) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
function select_master_element(elem) {
|
function current_master_element_name() {
|
||||||
$(".selected_master_elem").removeClass("selected_master_elem")
|
/* Get the name of the current color variable, like 'autosuggestion' */
|
||||||
$(elem).addClass("selected_master_elem")
|
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 */
|
function is_foreground() {
|
||||||
term256_colors = [
|
/* Returns true if the selected tab is foreground, false if it's background */
|
||||||
"ffd7d7", "d7afaf", "af8787", "875f5f", "ffafaf", "d78787", "af5f5f", "ff8787", //8
|
who = $('.colorpicker_ground_selected')
|
||||||
"d75f5f", "ff5f5f", "5f0000", "870000", "af0000", "d70000", "ff0000", "ff875f", //16
|
if (who.length == 0) {
|
||||||
"ffaf87", "d7875f", "ff5f00", "d75f00", "ffd7af", "d7af87", "af875f", "ffaf5f", //24
|
show_error('Not sure if we are in foreground or background')
|
||||||
"ff8700", "af5f00", "d78700", "ffd787", "d7af5f", "ffaf00", "875f00", "ffd75f", //32
|
return false
|
||||||
"af8700", "d7af00", "ffd700", "ffffd7", "d7d7af", "afaf87", "87875f", "ffffaf", //40
|
}
|
||||||
"d7d787", "afaf5f", "ffff87", "d7d75f", "ffff5f", "5f5f00", "878700", "afaf00", //48
|
return who[0].id == 'foreground'
|
||||||
"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
|
|
||||||
]
|
|
||||||
|
|
||||||
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",
|
"ffd7d7",
|
||||||
"d7afaf",
|
"d7afaf",
|
||||||
"af8787",
|
"af8787",
|
||||||
|
@ -514,15 +832,21 @@ term256_colors = [ //222
|
||||||
var items_per_row = 15
|
var items_per_row = 15
|
||||||
var show_labels = 0
|
var show_labels = 0
|
||||||
|
|
||||||
|
var COLOR_NORMAL = 'DDDDDD'
|
||||||
|
|
||||||
/* Adds a new element to master */
|
/* 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'
|
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',
|
class: 'master_element',
|
||||||
|
id: 'master_' + contents,
|
||||||
click: function(){
|
click: function(){
|
||||||
select_master_element(this)
|
click_handler(this)
|
||||||
//$(this).toggleClass('master_element');
|
|
||||||
}
|
}
|
||||||
}).append(
|
}).append(
|
||||||
$("<span/>", {
|
$("<span/>", {
|
||||||
|
@ -530,7 +854,10 @@ function create_master_element(contents, color) {
|
||||||
style: style_str,
|
style: style_str,
|
||||||
text: contents,
|
text: contents,
|
||||||
})
|
})
|
||||||
).appendTo('#master')
|
)
|
||||||
|
|
||||||
|
elem.appendTo('#master')
|
||||||
|
return elem
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Toggle the no_overflow class */
|
/* Toggle the no_overflow class */
|
||||||
|
@ -555,7 +882,7 @@ function create_data_table_element(contents_list) {
|
||||||
cell = $('<td>', {
|
cell = $('<td>', {
|
||||||
class: 'data_table_cell no_overflow',
|
class: 'data_table_cell no_overflow',
|
||||||
style: 'text-align: left',
|
style: 'text-align: left',
|
||||||
onClick: "toggle_overflow(this)"
|
onClick: 'toggle_overflow(this)'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
text_list = contents_list[idx].split("\n")
|
text_list = contents_list[idx].split("\n")
|
||||||
|
@ -578,19 +905,19 @@ function populate_colorpicker_term256() {
|
||||||
class: 'colorpicker_term256_row'
|
class: 'colorpicker_term256_row'
|
||||||
})
|
})
|
||||||
|
|
||||||
var subidx
|
for (var subidx = 0; subidx < items_per_row && idx + subidx < term256_colors.length; subidx++) {
|
||||||
for (subidx = 0; subidx < items_per_row && idx + subidx < term256_colors.length; subidx++) {
|
|
||||||
cell_style = 'background-color: #' + term256_colors[idx + subidx]
|
cell_style = 'background-color: #' + term256_colors[idx + subidx]
|
||||||
row.append($('<td>', {
|
row.append($('<td>', {
|
||||||
class: 'colorpicker_term256_cell',
|
class: 'colorpicker_term256_cell',
|
||||||
style: cell_style,
|
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)
|
$('#colorpicker_term256').append(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(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_variables" onClick="switch_tab('tab_variables')">variables</div>
|
||||||
<div class="tab" id="tab_history" onClick="switch_tab('tab_history')">history</div>
|
<div class="tab" id="tab_history" onClick="switch_tab('tab_history')">history</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="master_detail_box">
|
<div id="master_detail_table">
|
||||||
<div id="master">
|
<div id="master">
|
||||||
</div>
|
</div>
|
||||||
<table id="colorpicker_term256">
|
<div id="detail">
|
||||||
</table>
|
<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>
|
</div>
|
||||||
<table id="data_table">
|
<table id="data_table">
|
||||||
<table>
|
<table>
|
||||||
|
@ -624,6 +962,4 @@ $(document).ready(function() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a id="thelink">Click me</a>
|
|
||||||
|
|
||||||
</body></html>
|
</body></html>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import SimpleHTTPServer
|
||||||
import SocketServer
|
import SocketServer
|
||||||
import webbrowser
|
import webbrowser
|
||||||
import subprocess
|
import subprocess
|
||||||
import re, json, socket, sys
|
import re, json, socket, sys, cgi
|
||||||
|
|
||||||
def run_fish_cmd(text):
|
def run_fish_cmd(text):
|
||||||
from subprocess import PIPE
|
from subprocess import PIPE
|
||||||
|
@ -25,12 +25,24 @@ named_colors = {
|
||||||
'white' : 'FFFFFF'
|
'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):
|
def parse_color(color_str):
|
||||||
""" A basic function to parse a color string, for example, 'red' '--bold' """
|
""" A basic function to parse a color string, for example, 'red' '--bold' """
|
||||||
comps = color_str.split(' ')
|
comps = color_str.split(' ')
|
||||||
print "comps: ", comps
|
|
||||||
color = 'normal'
|
color = 'normal'
|
||||||
|
background_color = ''
|
||||||
bold, underline = False, False
|
bold, underline = False, False
|
||||||
for comp in comps:
|
for comp in comps:
|
||||||
# Remove quotes
|
# Remove quotes
|
||||||
|
@ -39,16 +51,22 @@ def parse_color(color_str):
|
||||||
bold = True
|
bold = True
|
||||||
elif comp == '--underline':
|
elif comp == '--underline':
|
||||||
underline = True
|
underline = True
|
||||||
elif comp in named_colors:
|
elif comp.startswith('--background='):
|
||||||
# Named color
|
# Background color
|
||||||
color = named_colors[comp]
|
background_color = parse_one_color(comp[len('--background='):])
|
||||||
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
|
|
||||||
else:
|
else:
|
||||||
# Unknown component
|
# Regular color
|
||||||
pass
|
maybe_color = parse_one_color(comp)
|
||||||
return color
|
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:
|
class FishVar:
|
||||||
""" A class that represents a variable """
|
""" A class that represents a variable """
|
||||||
|
@ -72,7 +90,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||||
result = []
|
result = []
|
||||||
out, err = run_fish_cmd('set -L')
|
out, err = run_fish_cmd('set -L')
|
||||||
for line in out.split('\n'):
|
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)
|
color_name, color_value = match.group(1, 2)
|
||||||
result.append([color_name.strip(), parse_color(color_value)])
|
result.append([color_name.strip(), parse_color(color_value)])
|
||||||
print result
|
print result
|
||||||
|
@ -81,7 +99,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||||
def do_get_functions(self):
|
def do_get_functions(self):
|
||||||
out, err = run_fish_cmd('functions')
|
out, err = run_fish_cmd('functions')
|
||||||
out = out.strip()
|
out = out.strip()
|
||||||
print out
|
|
||||||
# Not sure why fish sometimes returns this with newlines
|
# Not sure why fish sometimes returns this with newlines
|
||||||
if "\n" in out:
|
if "\n" in out:
|
||||||
return out.split('\n')
|
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"
|
"Return the color with the given name, or the empty string if there is none"
|
||||||
out, err = run_fish_cmd("echo -n $" + name)
|
out, err = run_fish_cmd("echo -n $" + name)
|
||||||
return out
|
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):
|
def do_GET(self):
|
||||||
p = self.path
|
p = self.path
|
||||||
if p == '/colors/':
|
if p == '/colors/':
|
||||||
|
@ -149,7 +183,43 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||||
# Output JSON
|
# Output JSON
|
||||||
json.dump(output, self.wfile)
|
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
|
PORT = 8000
|
||||||
while PORT <= 9000:
|
while PORT <= 9000:
|
||||||
|
|
Loading…
Reference in a new issue