mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-24 03:51:23 +08:00
Merge branch 'master' into ast
This commit is contained in:
commit
426f58aa61
461
share/tools/web_config/fishconfig.css
Normal file
461
share/tools/web_config/fishconfig.css
Normal file
|
@ -0,0 +1,461 @@
|
|||
body {
|
||||
background-color: #292939;
|
||||
font-family: Courier, "Courier New", monospace;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#ancestor {
|
||||
width: 800px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
#parent {
|
||||
width: 100%;
|
||||
min-height: 480px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
#tab_parent {
|
||||
display: table;
|
||||
width: 100%;
|
||||
height: 50px;;
|
||||
}
|
||||
|
||||
.tab {
|
||||
display: table-cell;
|
||||
border: 1px solid #111;
|
||||
border-right: none;
|
||||
padding-bottom: 15px;
|
||||
padding-top: 15px;
|
||||
font-size: 17pt;
|
||||
text-align: center;
|
||||
width: 15%;
|
||||
background-color: #292929;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#tab_parent :first-child {
|
||||
border-top-left-radius: 8px;
|
||||
}
|
||||
|
||||
#tab_parent :last-child {
|
||||
border-right: 1px solid #111;
|
||||
border-top-right-radius: 8px;
|
||||
}
|
||||
|
||||
.tab_first {
|
||||
border-top-left-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
|
||||
.tab_last {
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
}
|
||||
|
||||
.selected_tab {
|
||||
background-color: black;
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
#tab_contents {
|
||||
padding-top: 35px;
|
||||
width: 100%;
|
||||
background-color: black;
|
||||
border-bottom-left-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
clear: both;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.master_detail_table {
|
||||
display: table;
|
||||
margin-top: 10px;
|
||||
margin-left: 12px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.master {
|
||||
display: table-cell;
|
||||
text-align: right;
|
||||
min-width: 200px;
|
||||
font-size: 16pt;
|
||||
padding-bottom: 20px;
|
||||
padding-top: 35px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.detail {
|
||||
display: table-cell;
|
||||
border: 1px solid #555;
|
||||
background-color: #181818;
|
||||
padding-top: 30px;
|
||||
padding-bottom: 20px;
|
||||
padding-left: 30px;
|
||||
padding-right: 30px;
|
||||
border-radius: 5;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.detail_function {
|
||||
white-space: pre-wrap;
|
||||
width: 100%;
|
||||
font-size: 11pt;
|
||||
color: #BBB;
|
||||
}
|
||||
|
||||
.master_element {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 11px;
|
||||
padding-left: 5px;
|
||||
padding-right: 22px;
|
||||
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;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 0px;
|
||||
}
|
||||
|
||||
.selected_master_elem {
|
||||
border: 1px solid #555;
|
||||
border-right: none;
|
||||
background-color: #181818;
|
||||
|
||||
border-top-left-radius: 5;
|
||||
border-bottom-left-radius: 5;
|
||||
|
||||
/* Pad one less than .master_element, to accomodate our border. */
|
||||
padding-top: 5px;
|
||||
padding-bottom: 10px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.master_element_text {
|
||||
text-decoration: none;
|
||||
padding-bottom: 1px;
|
||||
border-bottom-style: inherit;
|
||||
border-bottom-color: inherit;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.master_element_description {
|
||||
text-decoration: none;
|
||||
padding-top: 15px;
|
||||
font-size: 10pt;
|
||||
border-bottom-style: inherit;
|
||||
border-bottom-color: inherit;
|
||||
border-bottom-width: 1px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.selected_master_elem > .master_element_description {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* We have a newline between the label and description; hide it initially, but show it when it's selected */
|
||||
.master_element > br { display: none; }
|
||||
.selected_master_elem > br { display: inherit; }
|
||||
|
||||
/* Set this class to suppress the border bottom on master_element_texts with visible descriptions */
|
||||
.master_element_no_border { border-bottom-width: 0 }
|
||||
|
||||
.colorpicker_term256 {
|
||||
border: solid #444 1px;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.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: groove #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 {
|
||||
table-layout:fixed;
|
||||
color: #CCC;
|
||||
width: 100%;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.data_table_row {
|
||||
}
|
||||
|
||||
.data_table_cell {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
vertical-align: top;
|
||||
overflow:hidden;
|
||||
border-bottom: #444 dotted 1px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.history_text {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
vertical-align: top;
|
||||
overflow:hidden;
|
||||
border-bottom: #444 dotted 1px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.history_delete {
|
||||
width: 20px;
|
||||
border-bottom: #444 dotted 1px;
|
||||
}
|
||||
|
||||
/* The CSS we apply when a table row is filtered */
|
||||
.data_table_row_filtered {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.no_overflow {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.colorpicker_target {
|
||||
margin: 0 0 -50px 0;
|
||||
position: relative;
|
||||
bottom: 47px;
|
||||
float: left; /* for some reason this makes the cells that it overlaps (before adjusting its bottom) clickable in Safari */
|
||||
}
|
||||
|
||||
.colorpicker_target_tab {
|
||||
cursor: pointer;
|
||||
color: #555;
|
||||
border: solid 1px #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_target_selected {
|
||||
background-color: #181818; /* same as #detail */
|
||||
color: white;
|
||||
}
|
||||
|
||||
.colorpicker_term256_row {
|
||||
}
|
||||
|
||||
.colorpicker_term256_cell {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: solid black 1px;
|
||||
}
|
||||
|
||||
.colorpicker_term256_selection_indicator {
|
||||
width: 19px;
|
||||
height: 16px;
|
||||
margin: -2px;
|
||||
border: solid white 3px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.colorpicker_cell_selected {
|
||||
border: dashed white 3px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.colorpicker_text_sample, .colorpicker_text_sample_tight {
|
||||
font-size: 12pt;
|
||||
padding: 25px;
|
||||
margin: 5px 20px 25px 20px; /* top right bottom left */
|
||||
cursor: pointer;
|
||||
line-height: 1.8em;
|
||||
border: solid #777 1px;
|
||||
position: relative; /* so that our absolutely positioned elements work */
|
||||
}
|
||||
|
||||
.colorpicker_text_sample_tight {
|
||||
font-size: 10pt;
|
||||
line-height: 1.2em;
|
||||
margin: 0px 6px;
|
||||
max-width: 220px;
|
||||
padding: 5px;
|
||||
white-space:nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
.color_picker_background_cells {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.color_picker_background_cells div {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-style: solid;
|
||||
border-color: #777;
|
||||
border-width: 0 0 1px 1px; /* top right bottom left */
|
||||
float: left;
|
||||
}
|
||||
|
||||
.color_scheme_choice_label {
|
||||
margin-left: 10px;
|
||||
margin-bottom: 3px;
|
||||
cursor: pointer;
|
||||
font-size: 12pt;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.color_scheme_choices_list {
|
||||
overflow-y: hidden; /* makes our height account for floats */
|
||||
padding: 0 10px 15px 10px; /* top right bottom left */
|
||||
}
|
||||
|
||||
.color_scheme_choice_container {
|
||||
float: left;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.fake_cursor {
|
||||
background-color: #999;
|
||||
}
|
||||
|
||||
.error_msg {
|
||||
color: red;
|
||||
font-size: 12pt;
|
||||
margin-left: 24pt;
|
||||
margin-top: 5pt;
|
||||
margin-bottom: 5pt;
|
||||
}
|
||||
|
||||
img.delete_icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#table_filter_container {
|
||||
/* top right bottom left*/
|
||||
padding: 0 10 10 30;
|
||||
text-align: right;
|
||||
position: relative;
|
||||
bottom: 10px;
|
||||
}
|
||||
|
||||
.filter_text_box {
|
||||
width: 250px;
|
||||
padding: 5 10 5 10;
|
||||
background-color: #888;
|
||||
border: #222 solid 3px;
|
||||
border-radius: 15px;
|
||||
font-size: 12pt;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.text_box_transient {
|
||||
color: #C8C8C8;
|
||||
}
|
||||
|
||||
.prompt_demo {
|
||||
font-size: 12pt;
|
||||
padding: 10px;
|
||||
margin: 5px 20px 25px; /* top right bottom left */
|
||||
cursor: pointer;
|
||||
line-height: 1.8em;
|
||||
border: solid #777 1px;
|
||||
position: relative; /* so that our absolutely positioned elements work */
|
||||
}
|
||||
|
||||
.save_button, .prompt_save_button {
|
||||
border-radius: 5px;
|
||||
border: solid rgba(71,71,71,0.5) 1px;
|
||||
padding: 5px 8px;
|
||||
font-size: 10pt;
|
||||
display: inline-block;
|
||||
margin-top: 12px;
|
||||
background-color: rgba(128,128,128,0.2);
|
||||
color: #FFF;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.prompt_save_button {
|
||||
background-color: #333;
|
||||
border: solid #525252 1px;
|
||||
color: #ffffff;
|
||||
margin: 2px 20px 25px; /* top right bottom left */
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
.prompt_demo_choice_label {
|
||||
margin: 25px 20px 5px;
|
||||
font-size: 12pt;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.prompt_demo_text {
|
||||
white-space: pre;
|
||||
line-height: 170%;
|
||||
padding: 4px 12px;
|
||||
font-size: 14pt;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
vertical-align: middle;
|
||||
display: table-cell;
|
||||
height: 72px; /* this is really the min height */
|
||||
}
|
||||
|
||||
.prompt_function {
|
||||
display: block;
|
||||
border: 1px solid #555;
|
||||
background-color: #181818;
|
||||
margin: 5px 20px 5px;
|
||||
border-radius: 5;
|
||||
}
|
||||
|
||||
.prompt_function_text {
|
||||
white-space: pre-wrap;
|
||||
padding: 15px 3px;
|
||||
width: 100%;
|
||||
height: 25%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.external_link_img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
vertical-align: text-top;
|
||||
margin-left: 10px;
|
||||
};
|
File diff suppressed because it is too large
Load Diff
4
share/tools/web_config/jquery.js
vendored
4
share/tools/web_config/jquery.js
vendored
File diff suppressed because one or more lines are too long
14847
share/tools/web_config/js/angular.js
vendored
Normal file
14847
share/tools/web_config/js/angular.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
69
share/tools/web_config/js/app.js
Normal file
69
share/tools/web_config/js/app.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
fishconfig = angular.module("fishconfig", ["filters", "controllers"]);
|
||||
|
||||
fishconfig.config(
|
||||
["$routeProvider", function($routeProvider) {
|
||||
$routeProvider
|
||||
.when("/colors", {
|
||||
controller: "colorsController",
|
||||
templateUrl: "partials/colors.html"
|
||||
})
|
||||
.when("/prompt", {
|
||||
controller: "promptController",
|
||||
templateUrl: "partials/prompt.html"
|
||||
})
|
||||
.when("/functions", {
|
||||
controller: "functionsController",
|
||||
templateUrl: "partials/functions.html"
|
||||
})
|
||||
.when("/variables", {
|
||||
controller: "variablesController",
|
||||
templateUrl: "partials/variables.html"
|
||||
})
|
||||
.when("/history", {
|
||||
controller: "historyController",
|
||||
templateUrl: "partials/history.html"
|
||||
})
|
||||
.when("/bindings", {
|
||||
controller: "bindingsController",
|
||||
templateUrl: "partials/bindings.html"
|
||||
})
|
||||
.otherwise({
|
||||
redirectTo: "/colors"
|
||||
})
|
||||
}]);
|
||||
|
||||
/* Inspired from http://blog.tomaka17.com/2012/12/random-tricks-when-using-angularjs/ */
|
||||
fishconfig.config(function($httpProvider, $compileProvider) {
|
||||
var global_error_element = null;
|
||||
|
||||
var showMessage = function(content) {
|
||||
global_error_element.text(content);
|
||||
};
|
||||
|
||||
$httpProvider.responseInterceptors.push(function($q) {
|
||||
return function(promise) {
|
||||
return promise.then(function(successResponse) {
|
||||
showMessage('');
|
||||
return successResponse;
|
||||
}, function(errorResponse) {
|
||||
switch (errorResponse.status) {
|
||||
case 0:
|
||||
showMessage("The request received an error. Perhaps the server has shut down.");
|
||||
break;
|
||||
case 500:
|
||||
showMessage('Server internal error: ' + errorResponse.data);
|
||||
break;
|
||||
default:
|
||||
showMessage('Error ' + errorResponse.status + ': ' + errorResponse.data);
|
||||
}
|
||||
return $q.reject(errorResponse);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
$compileProvider.directive('errorMessage', function() {
|
||||
return {
|
||||
link: function(scope, element, attrs) { global_error_element = element; }
|
||||
};
|
||||
});
|
||||
});
|
624
share/tools/web_config/js/colorutils.js
Normal file
624
share/tools/web_config/js/colorutils.js
Normal file
|
@ -0,0 +1,624 @@
|
|||
/* TODO: Write an angularjs service to wrap these methods */
|
||||
|
||||
term_256_colors = [ //247
|
||||
"ffd7d7",
|
||||
"d7afaf",
|
||||
"af8787",
|
||||
"875f5f",
|
||||
"5f0000",
|
||||
"870000",
|
||||
"af0000",
|
||||
"d70000",
|
||||
"ff0000",
|
||||
"ff5f5f",
|
||||
"d75f5f",
|
||||
"d78787",
|
||||
"ff8787",
|
||||
"ffafaf",
|
||||
"ffaf87",
|
||||
"ffaf5f",
|
||||
"ffaf00",
|
||||
"ff875f",
|
||||
"ff8700",
|
||||
"ff5f00",
|
||||
"d75f00",
|
||||
"af5f5f",
|
||||
"af5f00",
|
||||
"d78700",
|
||||
"d7875f",
|
||||
"af875f",
|
||||
"af8700",
|
||||
"875f00",
|
||||
"d7af87",
|
||||
"ffd7af",
|
||||
"ffd787",
|
||||
"ffd75f",
|
||||
"d7af00",
|
||||
"d7af5f",
|
||||
"ffd700",
|
||||
"ffff5f",
|
||||
"ffff00",
|
||||
"ffff87",
|
||||
"ffffaf",
|
||||
"ffffd7",
|
||||
"d7ff00",
|
||||
"afd75f",
|
||||
"d7d700",
|
||||
"d7d787",
|
||||
"d7d7af",
|
||||
"afaf87",
|
||||
"87875f",
|
||||
"5f5f00",
|
||||
"878700",
|
||||
"afaf00",
|
||||
"afaf5f",
|
||||
"d7d75f",
|
||||
"d7ff5f",
|
||||
"d7ff87",
|
||||
"87ff00",
|
||||
"afff00",
|
||||
"afff5f",
|
||||
"afd700",
|
||||
"87d700",
|
||||
"87af00",
|
||||
"5f8700",
|
||||
"87af5f",
|
||||
"5faf00",
|
||||
"afd787",
|
||||
"d7ffd7",
|
||||
"d7ffaf",
|
||||
"afffaf",
|
||||
"afff87",
|
||||
"5fff00",
|
||||
"5fd700",
|
||||
"87d75f",
|
||||
"5fd75f",
|
||||
"87ff5f",
|
||||
"5fff5f",
|
||||
"87ff87",
|
||||
"afd7af",
|
||||
"87d787",
|
||||
"87d7af",
|
||||
"87af87",
|
||||
"5f875f",
|
||||
"5faf5f",
|
||||
"005f00",
|
||||
"008700",
|
||||
"00af00",
|
||||
"00d700",
|
||||
"00ff00",
|
||||
"00ff5f",
|
||||
"5fff87",
|
||||
"00ff87",
|
||||
"87ffaf",
|
||||
"afffd7",
|
||||
"5fd787",
|
||||
"00d75f",
|
||||
"5faf87",
|
||||
"00af5f",
|
||||
"5fffaf",
|
||||
"00ffaf",
|
||||
"5fd7af",
|
||||
"00d787",
|
||||
"00875f",
|
||||
"00af87",
|
||||
"00d7af",
|
||||
"5fffd7",
|
||||
"87ffd7",
|
||||
"00ffd7",
|
||||
"d7ffff",
|
||||
"afd7d7",
|
||||
"87afaf",
|
||||
"5f8787",
|
||||
"5fafaf",
|
||||
"87d7d7",
|
||||
"5fd7d7",
|
||||
"5fffff",
|
||||
"00ffff",
|
||||
"87ffff",
|
||||
"afffff",
|
||||
"00d7d7",
|
||||
"00d7ff",
|
||||
"5fd7ff",
|
||||
"5fafd7",
|
||||
"00afd7",
|
||||
"00afff",
|
||||
"0087af",
|
||||
"00afaf",
|
||||
"008787",
|
||||
"005f5f",
|
||||
"005f87",
|
||||
"0087d7",
|
||||
"0087ff",
|
||||
"5fafff",
|
||||
"87afff",
|
||||
"5f87d7",
|
||||
"5f87ff",
|
||||
"005fd7",
|
||||
"005fff",
|
||||
"005faf",
|
||||
"5f87af",
|
||||
"87afd7",
|
||||
"afd7ff",
|
||||
"87d7ff",
|
||||
"d7d7ff",
|
||||
"afafd7",
|
||||
"8787af",
|
||||
"afafff",
|
||||
"8787d7",
|
||||
"8787ff",
|
||||
"5f5fff",
|
||||
"5f5fd7",
|
||||
"5f5faf",
|
||||
"5f5f87",
|
||||
"00005f",
|
||||
"000087",
|
||||
"0000af",
|
||||
"0000d7",
|
||||
"0000ff",
|
||||
"5f00ff",
|
||||
"5f00d7",
|
||||
"5f00af",
|
||||
"5f0087",
|
||||
"8700af",
|
||||
"8700d7",
|
||||
"8700ff",
|
||||
"af00ff",
|
||||
"af00d7",
|
||||
"d700ff",
|
||||
"d75fff",
|
||||
"d787ff",
|
||||
"ffafd7",
|
||||
"ffafff",
|
||||
"ffd7ff",
|
||||
"d7afff",
|
||||
"d7afd7",
|
||||
"af87af",
|
||||
"af87d7",
|
||||
"af87ff",
|
||||
"875fd7",
|
||||
"875faf",
|
||||
"875fff",
|
||||
"af5fff",
|
||||
"af5fd7",
|
||||
"af5faf",
|
||||
"d75fd7",
|
||||
"d787d7",
|
||||
"ff87ff",
|
||||
"ff5fff",
|
||||
"ff5fd7",
|
||||
"ff00ff",
|
||||
"ff00af",
|
||||
"ff00d7",
|
||||
"d700af",
|
||||
"d700d7",
|
||||
"af00af",
|
||||
"870087",
|
||||
"5f005f",
|
||||
"87005f",
|
||||
"af005f",
|
||||
"af0087",
|
||||
"d70087",
|
||||
"d7005f",
|
||||
"ff0087",
|
||||
"ff005f",
|
||||
"ff5f87",
|
||||
"d75f87",
|
||||
"d75faf",
|
||||
"ff5faf",
|
||||
"ff87af",
|
||||
"ff87d7",
|
||||
"d787af",
|
||||
"af5f87",
|
||||
"875f87",
|
||||
"000000",
|
||||
"080808",
|
||||
"121212",
|
||||
"1c1c1c",
|
||||
"262626",
|
||||
"303030",
|
||||
"3a3a3a",
|
||||
"444444",
|
||||
"4e4e4e",
|
||||
"585858",
|
||||
"5f5f5f",
|
||||
"626262",
|
||||
"6c6c6c",
|
||||
"767676",
|
||||
"808080",
|
||||
"878787",
|
||||
"8a8a8a",
|
||||
"949494",
|
||||
"9e9e9e",
|
||||
"a8a8a8",
|
||||
"afafaf",
|
||||
"b2b2b2",
|
||||
"bcbcbc",
|
||||
"c6c6c6",
|
||||
"d0d0d0",
|
||||
"d7d7d7",
|
||||
"dadada",
|
||||
"e4e4e4",
|
||||
"eeeeee",
|
||||
"ffffff",
|
||||
]
|
||||
|
||||
/* Returns array of values from a dictionary (or any object) */
|
||||
function dict_values(dict) {
|
||||
var result = [];
|
||||
for (var i in dict) result.push(dict[i]);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Return the array of colors as an array of N arrays of length items_per_row */
|
||||
function get_colors_as_nested_array(colors, items_per_row) {
|
||||
var result = new Array();
|
||||
for (var idx = 0; idx < colors.length; idx += items_per_row) {
|
||||
var row = new Array();
|
||||
for (var subidx = 0; subidx < items_per_row && idx + subidx < colors.length; subidx++) {
|
||||
row.push(colors[idx + subidx]);
|
||||
}
|
||||
result.push(row);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* 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]
|
||||
}
|
||||
|
||||
/* More hacks */
|
||||
if (color_str == 'black') color_str = '000000';
|
||||
if (color_str == 'white') color_str = 'FFFFFF';
|
||||
|
||||
|
||||
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 a "border color" for it that can show it selected */
|
||||
function border_color_for_color(color_str) {
|
||||
return adjust_lightness(color_str, function(lightness){
|
||||
var adjust = .5
|
||||
var new_lightness = lightness + adjust
|
||||
if (new_lightness > 1.0 || new_lightness < 0.0) {
|
||||
new_lightness -= 2 * adjust
|
||||
}
|
||||
return new_lightness
|
||||
})
|
||||
}
|
||||
|
||||
/* Use this function to make a color that contrasts well with the given color */
|
||||
function text_color_for_color(color_str) {
|
||||
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
|
||||
}
|
||||
return adjust_lightness(color_str, compute_constrast);
|
||||
}
|
||||
|
||||
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 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
|
||||
})
|
||||
}
|
||||
|
||||
/* Given a color name, like 'normal' or 'red' or 'FF00F0', return an RGB color string (or empty string) */
|
||||
function interpret_color(str) {
|
||||
str = str.toLowerCase()
|
||||
if (str == 'black') return '000000'
|
||||
if (str == 'red') return 'FF0000'
|
||||
if (str == 'green') return '00FF00'
|
||||
if (str == 'brown') return '725000'
|
||||
if (str == 'yellow') return 'FFFF00'
|
||||
if (str == 'blue') return '0000FF'
|
||||
if (str == 'magenta') return 'FF00FF'
|
||||
if (str == 'purple') return 'FF00FF'
|
||||
if (str == 'cyan') return '00FFFF'
|
||||
if (str == 'white') return 'FFFFFF'
|
||||
if (str == 'normal') return ''
|
||||
return str
|
||||
}
|
||||
|
||||
var color_scheme_fish_default = {
|
||||
"name": "fish default",
|
||||
"colors": [],
|
||||
'preferred_background': 'black',
|
||||
|
||||
'autosuggestion': '555',
|
||||
'command': '005fd7',
|
||||
'param': '00afff',
|
||||
'redirection': '00afff',
|
||||
'comment': '990000',
|
||||
'error': 'ff0000',
|
||||
'escape': '00a6b2',
|
||||
'operator': '00a6b2',
|
||||
'quote': '999900',
|
||||
'end': '009900'
|
||||
};
|
||||
|
||||
|
||||
var TomorrowTheme = {
|
||||
tomorrow_night: {'Background': '1d1f21', 'Current Line': '282a2e', 'Selection': '373b41', 'Foreground': 'c5c8c6', 'Comment': '969896', 'Red': 'cc6666', 'Orange': 'de935f', 'Yellow': 'f0c674', 'Green': 'b5bd68', 'Aqua': '8abeb7', 'Blue': '81a2be', 'Purple': 'b294bb'
|
||||
},
|
||||
|
||||
tomorrow: {'Background': 'ffffff', 'Current Line': 'efefef', 'Selection': 'd6d6d6', 'Foreground': '4d4d4c', 'Comment': '8e908c', 'Red': 'c82829', 'Orange': 'f5871f', 'Yellow': 'eab700', 'Green': '718c00', 'Aqua': '3e999f', 'Blue': '4271ae', 'Purple': '8959a8'
|
||||
},
|
||||
|
||||
tomorrow_night_bright: {'Background': '000000', 'Current Line': '2a2a2a', 'Selection': '424242', 'Foreground': 'eaeaea', 'Comment': '969896', 'Red': 'd54e53', 'Orange': 'e78c45', 'Yellow': 'e7c547', 'Green': 'b9ca4a', 'Aqua': '70c0b1', 'Blue': '7aa6da', 'Purple': 'c397d8'},
|
||||
|
||||
apply: function(theme, receiver){
|
||||
receiver['autosuggestion'] = theme['Comment']
|
||||
receiver['command'] = theme['Purple']
|
||||
receiver['comment'] = theme['Yellow'] /* we want to use comment for autosuggestions */
|
||||
receiver['end'] = theme['Purple']
|
||||
receiver['error'] = theme['Red']
|
||||
receiver['param'] = theme['Blue']
|
||||
receiver['quote'] = theme['Green']
|
||||
receiver['redirection'] = theme['Aqua']
|
||||
|
||||
receiver['colors'] = []
|
||||
for (var key in theme) receiver['colors'].push(theme[key])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var solarized = {
|
||||
base03: '002b36', base02: '073642', base01: '586e75', base00: '657b83', base0: '839496', base1: '93a1a1', base2: 'eee8d5', base3: 'fdf6e3', yellow: 'b58900', orange: 'cb4b16', red: 'dc322f', magenta: 'd33682', violet: '6c71c4', blue: '268bd2', cyan: '2aa198', green: '859900'
|
||||
};
|
||||
|
||||
/* Sample color schemes */
|
||||
var color_scheme_solarized_light = {
|
||||
name: "Solarized Light",
|
||||
colors: dict_values(solarized),
|
||||
|
||||
preferred_background: '#' + solarized.base3,
|
||||
|
||||
autosuggestion: solarized.base1,
|
||||
command: solarized.base01,
|
||||
comment: solarized.base1,
|
||||
end: solarized.blue,
|
||||
error: solarized.red,
|
||||
param: solarized.base00,
|
||||
quote: solarized.base0,
|
||||
redirection: solarized.violet,
|
||||
|
||||
url: 'http://ethanschoonover.com/solarized'
|
||||
};
|
||||
|
||||
var color_scheme_solarized_dark = {
|
||||
name: "Solarized Dark",
|
||||
colors: dict_values(solarized),
|
||||
preferred_background: '#' + solarized.base03,
|
||||
|
||||
autosuggestion: solarized.base01,
|
||||
command: solarized.base1,
|
||||
comment: solarized.base01,
|
||||
end: solarized.blue,
|
||||
error: solarized.red,
|
||||
param: solarized.base0,
|
||||
quote: solarized.base00,
|
||||
redirection: solarized.violet,
|
||||
|
||||
url: 'http://ethanschoonover.com/solarized'
|
||||
};
|
||||
|
||||
var color_scheme_tomorrow = {
|
||||
name: 'Tomorrow',
|
||||
preferred_background: 'white',
|
||||
url: 'https://github.com/chriskempson/tomorrow-theme'
|
||||
}
|
||||
TomorrowTheme.apply(TomorrowTheme.tomorrow, color_scheme_tomorrow)
|
||||
|
||||
var color_scheme_tomorrow_night = {
|
||||
name: 'Tomorrow Night',
|
||||
preferred_background: '#232323',
|
||||
url: 'https://github.com/chriskempson/tomorrow-theme'
|
||||
}
|
||||
TomorrowTheme.apply(TomorrowTheme.tomorrow_night, color_scheme_tomorrow_night)
|
||||
|
||||
var color_scheme_tomorrow_night_bright = {
|
||||
'name': 'Tomorrow Night Bright',
|
||||
'preferred_background': 'black',
|
||||
'url': 'https://github.com/chriskempson/tomorrow-theme',
|
||||
|
||||
}
|
||||
TomorrowTheme.apply(TomorrowTheme.tomorrow_night_bright, color_scheme_tomorrow_night_bright)
|
||||
|
||||
function construct_scheme_analogous(label, background, color_list) {
|
||||
return {
|
||||
name: label,
|
||||
preferred_background: background,
|
||||
colors: color_list,
|
||||
|
||||
command: color_list[0],
|
||||
quote: color_list[6],
|
||||
param: color_list[5],
|
||||
autosuggestion: color_list[4],
|
||||
|
||||
error: color_list[9],
|
||||
comment: color_list[12],
|
||||
|
||||
end: color_list[10],
|
||||
redirection: color_list[11]
|
||||
};
|
||||
}
|
||||
|
||||
function construct_scheme_triad(label, background, color_list) {
|
||||
return {
|
||||
name: label,
|
||||
preferred_background: background,
|
||||
colors: color_list,
|
||||
|
||||
command: color_list[0],
|
||||
quote: color_list[2],
|
||||
param: color_list[1],
|
||||
autosuggestion: color_list[3],
|
||||
redirection: color_list[4],
|
||||
|
||||
error: color_list[8],
|
||||
comment: color_list[10],
|
||||
|
||||
end: color_list[7],
|
||||
};
|
||||
}
|
||||
|
||||
function construct_scheme_complementary(label, background, color_list) {
|
||||
return {
|
||||
name: label,
|
||||
preferred_background: background,
|
||||
colors: color_list,
|
||||
|
||||
command: color_list[0],
|
||||
quote: color_list[4],
|
||||
param: color_list[3],
|
||||
autosuggestion: color_list[2],
|
||||
redirection: color_list[6],
|
||||
|
||||
error: color_list[5],
|
||||
comment: color_list[8],
|
||||
|
||||
end: color_list[9],
|
||||
};
|
||||
}
|
||||
|
||||
function construct_color_scheme_mono(label, background, from_end) {
|
||||
var mono_colors = ['000000', '121212', '1c1c1c', '262626', '303030', '3a3a3a', '444444', '4e4e4e', '585858', '5f5f5f', '626262', '6c6c6c', '767676', '808080', '878787', '8a8a8a', '949494', '9e9e9e', 'a8a8a8', 'afafaf', 'b2b2b2', 'bcbcbc', 'c6c6c6', 'd0d0d0', 'd7d7d7', 'dadada', 'e4e4e4', 'eeeeee', 'ffffff'];
|
||||
|
||||
if (from_end) mono_colors.reverse();
|
||||
|
||||
return {
|
||||
name: label,
|
||||
preferred_background: background,
|
||||
colors: mono_colors,
|
||||
|
||||
autosuggestion: '777777',
|
||||
command: mono_colors[0],
|
||||
comment: mono_colors[7],
|
||||
end: mono_colors[12],
|
||||
error: mono_colors[20],
|
||||
param: mono_colors[4],
|
||||
quote: mono_colors[10],
|
||||
redirection: mono_colors[15]
|
||||
};
|
||||
}
|
||||
|
||||
var additional_color_schemes = [
|
||||
construct_scheme_analogous('Snow Day', 'white', ['164CC9', '325197', '072D83', '4C7AE4', '7596E4', '4319CC', '4C3499', '260885', '724EE5', '9177E5', '02BDBD', '248E8E', '007B7B', '39DEDE', '65DEDE']),
|
||||
|
||||
construct_scheme_analogous('Lava', '#232323', ['FF9400', 'BF8330', 'A66000', 'FFAE40', 'FFC473', 'FFC000', 'BF9C30', 'A67D00', 'FFD040', 'FFDD73', 'FF4C00', 'BF5B30', 'A63100', 'FF7940', 'FF9D73']),
|
||||
|
||||
construct_scheme_analogous('Seaweed', '#232323', ['00BF32', '248F40', '007C21', '38DF64', '64DF85', '04819E', '206676', '015367', '38B2CE', '60B9CE', '8EEB00', '7CB02C', '5C9900', 'ACF53D', 'C0F56E']),
|
||||
|
||||
construct_scheme_triad('Fairground', '#003', ['0772A1', '225E79', '024A68', '3BA3D0', '63AFD0', 'D9005B', 'A3295C', '8D003B', 'EC3B86', 'EC6AA1', 'FFE100', 'BFAE30', 'A69200', 'FFE840', 'FFEE73']),
|
||||
|
||||
construct_scheme_complementary('Bay Cruise', 'black', ['009999', '1D7373', '006363', '33CCCC', '5CCCCC', 'FF7400', 'BF7130', 'A64B00', 'FF9640', 'FFB273']),
|
||||
|
||||
{
|
||||
'name': 'Old School',
|
||||
'preferred_background': 'black',
|
||||
|
||||
colors: ['00FF00', '30BE30', '00A400', '44FF44', '7BFF7B', 'FF0000', 'BE3030', 'A40000', 'FF7B7B', '777777', 'CCCCCC'],
|
||||
|
||||
autosuggestion: '777777',
|
||||
command: '00FF00',
|
||||
comment: '30BE30',
|
||||
end: 'FF7B7B',
|
||||
error: 'A40000',
|
||||
param: '30BE30',
|
||||
quote: '44FF44',
|
||||
redirection: '7BFF7B'
|
||||
},
|
||||
|
||||
{
|
||||
'name': 'Just a Touch',
|
||||
'preferred_background': 'black',
|
||||
|
||||
colors: ['B0B0B0', '969696', '789276', 'F4F4F4', 'A0A0F0', '666A80', 'F0F0F0', 'D7D7D7', 'B7B7B7', 'FFA779', 'FAFAFA'],
|
||||
|
||||
autosuggestion: '9C9C9C',
|
||||
command: 'F4F4F4',
|
||||
comment: 'B0B0B0',
|
||||
end: '969696',
|
||||
error: 'FFA779',
|
||||
param: 'A0A0F0',
|
||||
quote: '666A80',
|
||||
redirection: 'FAFAFA'
|
||||
},
|
||||
|
||||
construct_color_scheme_mono('Mono Lace', 'white', false),
|
||||
construct_color_scheme_mono('Mono Smoke', 'black', true)
|
||||
];
|
||||
|
232
share/tools/web_config/js/controllers.js
Normal file
232
share/tools/web_config/js/controllers.js
Normal file
|
@ -0,0 +1,232 @@
|
|||
controllers = angular.module("controllers", []);
|
||||
|
||||
controllers.controller("main", function($scope, $location) {
|
||||
$scope.currentTab = "colors";
|
||||
|
||||
$scope.changeView = function(view) {
|
||||
$location.path(view);
|
||||
$scope.currentTab = view;
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
controllers.controller("colorsController", function($scope, $http) {
|
||||
$scope.changeSelectedColorScheme= function(newScheme) {
|
||||
$scope.selectedColorScheme = newScheme;
|
||||
if ($scope.selectedColorScheme.preferred_background) {
|
||||
$scope.terminalBackgroundColor = $scope.selectedColorScheme.preferred_background;
|
||||
}
|
||||
$scope.selectedColorSetting = 'command';
|
||||
$scope.colorArraysArray = $scope.getColorArraysArray();
|
||||
//TODO: Save button should be shown only when colors are changed
|
||||
$scope.showSaveButton = true;
|
||||
}
|
||||
|
||||
$scope.changeTerminalBackgroundColor = function(color) {
|
||||
$scope.terminalBackgroundColor = color;
|
||||
}
|
||||
|
||||
$scope.text_color_for_color = function(color) {
|
||||
return text_color_for_color(color);
|
||||
}
|
||||
|
||||
$scope.getColorArraysArray = function() {
|
||||
var result = null;
|
||||
if ( $scope.selectedColorScheme.colors && $scope.selectedColorScheme.colors.length > 0)
|
||||
result = get_colors_as_nested_array($scope.selectedColorScheme.colors, 32);
|
||||
else
|
||||
result = get_colors_as_nested_array(term_256_colors, 32);
|
||||
return result;
|
||||
}
|
||||
|
||||
$scope.selectColorSetting = function(name) {
|
||||
$scope.selectedColorSetting = name;
|
||||
}
|
||||
|
||||
$scope.changeSelectedTextColor = function(color) {
|
||||
$scope.selectedColorScheme[$scope.selectedColorSetting] = color;
|
||||
}
|
||||
|
||||
$scope.sampleTerminalBackgroundColors = ['white', '#' + solarized.base3, '#300', '#003', '#' + solarized.base03, '#232323', 'black'];
|
||||
|
||||
/* Array of FishColorSchemes */
|
||||
$scope.colorSchemes = [color_scheme_fish_default, color_scheme_solarized_light, color_scheme_solarized_dark, color_scheme_tomorrow, color_scheme_tomorrow_night, color_scheme_tomorrow_night_bright];
|
||||
for (var i=0; i < additional_color_schemes.length; i++)
|
||||
$scope.colorSchemes.push(additional_color_schemes[i])
|
||||
|
||||
|
||||
$scope.getCurrentTheme = function() {
|
||||
$http.get("/colors/").success(function(data, status, headers, config) {
|
||||
var currentScheme = { "name": "Current", "colors":[], "preferred_background": "" };
|
||||
for (var i in data) {
|
||||
currentScheme[data[i].name] = data[i].color;
|
||||
}
|
||||
$scope.colorSchemes.splice(0, 0, currentScheme);
|
||||
$scope.changeSelectedColorScheme(currentScheme);
|
||||
})};
|
||||
|
||||
$scope.setTheme = function() {
|
||||
var settingNames = ["autosuggestion", "command", "param", "redirection", "comment", "error", "quote", "end"];
|
||||
for (name in settingNames) {
|
||||
var postData = "what=" + settingNames[name] + "&color=" + $scope.selectedColorScheme[settingNames[name]] + "&background_color=&bold=&underline=";
|
||||
$http.post("/set_color/", postData, { headers: {'Content-Type': 'application/x-www-form-urlencoded'} }).success(function(data, status, headers, config) {
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
$scope.getCurrentTheme();
|
||||
});
|
||||
|
||||
controllers.controller("promptController", function($scope, $http) {
|
||||
$scope.selectedPrompt = null;
|
||||
|
||||
$scope.fetchSamplePrompts= function() {
|
||||
$http.get("/sample_prompts/").success(function(data, status, headers, config) {
|
||||
$scope.samplePrompts = data;
|
||||
$scope.samplePromptsArrayArray = get_colors_as_nested_array($scope.samplePrompts, 1);
|
||||
|
||||
if ($scope.selectedPrompt == null) {
|
||||
$scope.selectPrompt($scope.samplePrompts[0]);
|
||||
}
|
||||
})};
|
||||
|
||||
$scope.selectPrompt = function(promptt) {
|
||||
$scope.selectedPrompt= promptt;
|
||||
}
|
||||
|
||||
$scope.setNewPrompt = function(selectedPrompt) {
|
||||
$http.post("/set_prompt/","what=" + encodeURIComponent(selectedPrompt.function), { headers: {'Content-Type': 'application/x-www-form-urlencoded'} }).success(function(data, status, headers, config){
|
||||
|
||||
// Update attributes of current prompt and select it
|
||||
$scope.samplePrompts[0].demo = selectedPrompt.demo;
|
||||
$scope.samplePrompts[0].function = selectedPrompt.function;
|
||||
$scope.samplePrompts[0].font_size = selectedPrompt.font_size;
|
||||
$scope.selectedPrompt = $scope.samplePrompts[0];
|
||||
})};
|
||||
|
||||
$scope.fetchSamplePrompts();
|
||||
});
|
||||
|
||||
controllers.controller("functionsController", function($scope, $http) {
|
||||
$scope.selectedFunction = null;
|
||||
$scope.functionDefinition = "";
|
||||
|
||||
$scope.selectFunction = function(fun) {
|
||||
$scope.selectedFunction = fun;
|
||||
$scope.fetchFunctionDefinition($scope.selectedFunction);
|
||||
}
|
||||
|
||||
$scope.fetchFunctions= function() {
|
||||
$http.get("/functions/").success(function(data, status, headers, config) {
|
||||
$scope.functions = data;
|
||||
$scope.selectFunction($scope.functions[0]);
|
||||
})};
|
||||
|
||||
$scope.cleanupFishFunction = function (contents) {
|
||||
/* Replace leading tabs and groups of four spaces at the beginning of a line with two spaces. */
|
||||
lines = contents.split('\n')
|
||||
rx = /^[\t ]+/
|
||||
for (var i=0; i < lines.length; i++) {
|
||||
line = lines[i]
|
||||
/* Get leading tabs and spaces */
|
||||
whitespace_arr = rx.exec(line)
|
||||
if (whitespace_arr) {
|
||||
/* Replace four spaces with two spaces, and tabs with two spaces */
|
||||
var whitespace = whitespace_arr[0]
|
||||
new_whitespace = whitespace.replace(/( )|(\t)/g, ' ')
|
||||
lines[i] = new_whitespace + line.slice(whitespace.length)
|
||||
}
|
||||
}
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
$scope.fetchFunctionDefinition = function(name) {
|
||||
$http.post("/get_function/","what=" + name, { headers: {'Content-Type': 'application/x-www-form-urlencoded'} }).success(function(data, status, headers, config) {
|
||||
$scope.functionDefinition = $scope.cleanupFishFunction(data[0]);
|
||||
})};
|
||||
|
||||
$scope.fetchFunctions();
|
||||
});
|
||||
|
||||
controllers.controller("variablesController", function($scope, $http) {
|
||||
$scope.query = null;
|
||||
|
||||
$scope.fetchVariables= function() {
|
||||
$http.get("/variables/").success(function(data, status, headers, config) {
|
||||
$scope.variables = data;
|
||||
})};
|
||||
|
||||
$scope.fetchVariables();
|
||||
});
|
||||
|
||||
controllers.controller("historyController", function($scope, $http, $timeout) {
|
||||
$scope.historyItems = [];
|
||||
$scope.historySize = 0;
|
||||
// Stores items which are yet to be added in history items
|
||||
$scope.remainingItems = [];
|
||||
$scope.selectedItems = [];
|
||||
|
||||
// Populate history items in parts
|
||||
$scope.loadHistory = function() {
|
||||
if ($scope.remainingItems.length <= 0) {
|
||||
$scope.loadingText = "";
|
||||
return;
|
||||
}
|
||||
|
||||
var toLoad = $scope.remainingItems.splice(0, 100);
|
||||
for (i in toLoad) {
|
||||
$scope.historyItems.push(toLoad[i]);
|
||||
}
|
||||
|
||||
$scope.loadingText = "Loading " + $scope.historyItems.length + "/" + $scope.historySize;
|
||||
$timeout($scope.loadHistory, 100);
|
||||
}
|
||||
|
||||
$scope.selectItem = function(item) {
|
||||
var index = $scope.selectedItems.indexOf(item);
|
||||
if ( index >= 0) {
|
||||
$scope.selectedItems.splice(index,1);
|
||||
}
|
||||
else {
|
||||
$scope.selectedItems.push(item);
|
||||
}
|
||||
}
|
||||
// Get history from server
|
||||
$scope.fetchHistory = function() {
|
||||
$http.get("/history/").success(function(data, status, headers, config) {
|
||||
$scope.historySize = data.length;
|
||||
$scope.remainingItems = data;
|
||||
|
||||
/* Call this function 10 times/second */
|
||||
$timeout($scope.loadHistory, 100);
|
||||
})};
|
||||
|
||||
$scope.deleteHistoryItem = function(item) {
|
||||
index = $scope.historyItems.indexOf(item);
|
||||
$http.post("/delete_history_item/","what=" + encodeURIComponent(item), { headers: {'Content-Type': 'application/x-www-form-urlencoded'} }).success(function(data, status, headers, config) {
|
||||
$scope.historyItems.splice(index, 1);
|
||||
})};
|
||||
|
||||
var queryInputTimeout = null;
|
||||
$scope.$watch("queryInput", function() {
|
||||
if (queryInputTimeout){
|
||||
$timeout.cancel(queryInputTimeout);
|
||||
}
|
||||
|
||||
queryInputTimeout = $timeout(function() {
|
||||
$scope.query = $scope.queryInput;
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
$scope.fetchHistory();
|
||||
});
|
||||
|
||||
controllers.controller("bindingsController", function($scope, $http) {
|
||||
$scope.bindings = [];
|
||||
$scope.fetchBindings = function() {
|
||||
$http.get("/bindings/").success(function(data, status, headers, config) {
|
||||
$scope.bindings = data;
|
||||
})};
|
||||
|
||||
$scope.fetchBindings();
|
||||
});
|
35
share/tools/web_config/js/filters.js
Normal file
35
share/tools/web_config/js/filters.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
filters = angular.module("filters", []);
|
||||
|
||||
filters.filter("filterVariable", function() {
|
||||
return function(variables, query) {
|
||||
var result = []
|
||||
if (variables == undefined) return result;
|
||||
if (query == null) { return variables };
|
||||
|
||||
for(i=0; i<variables.length; ++i) {
|
||||
variable = variables[i];
|
||||
if (variable.name.indexOf(query) != -1 || variable.value.indexOf(query) != -1) {
|
||||
result.push(variable);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
filters.filter("filterBinding", function() {
|
||||
return function(bindings, query) {
|
||||
var result = []
|
||||
if (bindings == undefined) return result;
|
||||
if (query == null) { return bindings};
|
||||
|
||||
for(i=0; i<bindings.length; ++i) {
|
||||
binding = bindings[i];
|
||||
if (binding.command.indexOf(query) != -1 || binding.readable_binding.toLowerCase().indexOf(query.toLowerCase()) != -1) {
|
||||
result.push(binding);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
13
share/tools/web_config/partials/bindings.html
Normal file
13
share/tools/web_config/partials/bindings.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<div id="table_filter_container" style="display: block;">
|
||||
<input id="table_filter_text_box" class="filter_text_box text_box_transient" placeholder="Filter" ng-model="query">
|
||||
</div>
|
||||
|
||||
<table class="data_table">
|
||||
<tbody>
|
||||
<tr class="data_table_row" ng-repeat="binding in bindings | filterBinding:query">
|
||||
<td ng-class="{ data_table_cell: true, no_overflow: !binding._is_selected }" style="text-align: right; padding-right: 30px;" ng-click="binding._is_selected = !binding._is_selected">{{ binding.command }}</td>
|
||||
<!-- Some bindings are listed multiple times for e.g. function backward-char is bound to \e\[D as well as key left. Users may want to know why some bindings are listed twice, so the actual binding is shown in next line on a click -->
|
||||
<td ng-class="{ data_table_cell: true, no_overflow: !binding._is_selected }" style="text-align: left; padding-right: 30px;" ng-click="binding._is_selected = !binding._is_selected">{{ binding.readable_binding }} <div ng-show="binding._is_selected"> {{ binding.binding }} </div> </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
65
share/tools/web_config/partials/colors.html
Normal file
65
share/tools/web_config/partials/colors.html
Normal file
|
@ -0,0 +1,65 @@
|
|||
<div>
|
||||
<!-- ko with: color_picker -->
|
||||
<span style="padding-left: 25px">Click to customize each color: </span><br>
|
||||
<div class="colorpicker_text_sample" ng-style="{'background-color': terminalBackgroundColor}">
|
||||
<span style="position: absolute; left: 10px; top: -6px;" data-ng-style="{'color': text_color_for_color(selectedColorScheme.preferred_background || 'white')}">{{ selectedColorScheme.name }}</span><br>
|
||||
<div class="color_picker_background_cells">
|
||||
<div ng-style="{'background-color': color}" ng-repeat="color in sampleTerminalBackgroundColors" ng-click="changeTerminalBackgroundColor(color)"></div>
|
||||
</div>
|
||||
<!-- This is the sample text -->
|
||||
<span data-ng-style="{ 'color': selectedColorScheme.command}" ng-click="selectColorSetting('command')">/bright/vixens</span>
|
||||
<span data-ng-style="{ 'color': selectedColorScheme.param}" ng-click="selectColorSetting('param')">jump</span>
|
||||
<span data-ng-style="{ 'color': selectedColorScheme.end}" ng-click="selectColorSetting('end')">|</span>
|
||||
<span data-ng-style="{ 'color': selectedColorScheme.command}" ng-click="selectColorSetting('command')">dozy</span>
|
||||
<span data-ng-style="{ 'color': selectedColorScheme.quote}" ng-click="selectColorSetting('quote')"> "fowl" </span>
|
||||
<span data-ng-style="{ 'color': selectedColorScheme.redirection}" ng-click="selectColorSetting('redirection')">> quack</span>
|
||||
<span data-ng-style="{ 'color': selectedColorScheme.end}" ng-click="selectColorSetting('end')">&</span>
|
||||
<br>
|
||||
<span data-ng-style="{ 'color': selectedColorScheme.command}" ng-click="selectColorSetting('command')">echo</span>
|
||||
<span data-ng-style="{ 'color': selectedColorScheme.error}" ng-click="selectColorSetting('error')">'Errors are the portals to discovery</span>
|
||||
<br>
|
||||
<span data-ng-style="{ 'color': selectedColorScheme.comment}" ng-click="selectColorSetting('comment')"># This is a comment</span>
|
||||
<br>
|
||||
<span data-ng-style="{ 'color': selectedColorScheme.command}" ng-click="selectColorSetting('command')">Th</span><span data-ng-style="{ 'color': selectedColorScheme.autosuggestion }" ng-click="selectColorSetting('autosuggestion')"><span class="fake_cursor"><span style="visibility: hidden">i</span></span>s is an autosuggestion</span>
|
||||
|
||||
<span class="save_button" style="position: absolute; right: 5px; bottom: 5px;" title="Terminal background color is not set automatically on Apply. See your terminal documentation to set its background color." data-ng-style="{'color': text_color_for_color(selectedColorScheme.preferred_background || 'white')}" ng-show="showSaveButton" ng-click="setTheme()">Apply</span>
|
||||
|
||||
</div>
|
||||
|
||||
<table class="colorpicker_term256" style="margin: 0px 20px;">
|
||||
<tbody>
|
||||
<tr class="colorpicker_term256_row" data-ng-repeat="color_array in colorArraysArray">
|
||||
<td class="colorpicker_term256_cell" data-ng-style="{'background-color': color, 'color': color}" ng-click="changeSelectedTextColor(color)" ng-repeat="color in color_array">
|
||||
<div class="colorpicker_term256_selection_indicator" ng-show="selectedColorScheme[selectedColorSetting] == color" ng-style="{'border-color': border_color_for_color(color)}"</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<!-- /ko -->
|
||||
</table>
|
||||
|
||||
<div class="color_scheme_choices_list">
|
||||
<div class="color_scheme_choice_container" data-ng-repeat="colorScheme in colorSchemes" ng-click="changeSelectedColorScheme(colorScheme)">
|
||||
<div class="color_scheme_choice_label">
|
||||
<!-- This click/clickBubble nonsense is so that we can have a separate URL inside a parent with an onClick handler -->
|
||||
<span>{{colorScheme.name }}</span><!--a data-bind="if: $data.url, click: function(){return true;}, clickBubble: false, attr: { href: $data.url}"><img class="external_link_img" src="external_link.png"></a-->
|
||||
</div>
|
||||
<div class="colorpicker_text_sample_tight" data-ng-style="{'background-color': colorScheme.preferred_background}">
|
||||
<span data-ng-style="{'color': colorScheme.command}">/bright/vixens</span>
|
||||
<span data-ng-style="{'color': colorScheme.param}">jump</span>
|
||||
<span data-ng-style="{'color': colorScheme.end}">|</span>
|
||||
<span data-ng-style="{'color': colorScheme.command}">dozy</span>
|
||||
<span data-ng-style="{'color': colorScheme.quote}"> "fowl" </span>
|
||||
<span data-ng-style="{'color': colorScheme.redirection}">> quack</span>
|
||||
<span data-ng-style="{'color': colorScheme.end}">&</span>
|
||||
<br>
|
||||
<span data-ng-style="{'color': colorScheme.command}">echo</span>
|
||||
<span data-ng-style="{'color': colorScheme.error}">'Errors are the portals to discovery</span>
|
||||
<br>
|
||||
<span data-ng-style="{ 'color': colorScheme.comment}"># This is a comment</span>
|
||||
<br>
|
||||
<span data-ng-style="{ 'color': colorScheme.command}">Th</span><span data-ng-style="{ 'color': colorScheme.autosuggestion}"><span class="fake_cursor"><span style="visibility: hidden">i</span></span>s is an autosuggestion</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
</div>
|
12
share/tools/web_config/partials/functions.html
Normal file
12
share/tools/web_config/partials/functions.html
Normal file
|
@ -0,0 +1,12 @@
|
|||
<div class="master_detail_table">
|
||||
<div class="master">
|
||||
<div ng-repeat="func in functions">
|
||||
<div id="master_{{func}}" ng-class="{'master_element': true, 'selected_master_elem': func == selectedFunction }" ng-style="'color: #aaaaaa'" ng-click="selectFunction(func)">
|
||||
<span class="master_element_text" style="font-size: 11pt;">{{ func }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail">
|
||||
<div class="detail_function">{{ functionDefinition }}</div>
|
||||
</div>
|
||||
</div>
|
16
share/tools/web_config/partials/history.html
Normal file
16
share/tools/web_config/partials/history.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
<div id="table_filter_container">
|
||||
<span ng-show="loadingText.length > 0"> {{ loadingText }} </span>
|
||||
<input id="table_filter_text_box" class="filter_text_box text_box_transient" placeholder="Filter" ng-model="queryInput">
|
||||
</div>
|
||||
<table class="data_table">
|
||||
<tbody>
|
||||
<tr ng-repeat="item in historyItems | filter:query">
|
||||
<td ng-class="{'history_text': true, 'no_overflow': selectedItems.indexOf(item) < 0}" ng-click="selectItem(item)">{{ item }}</td>
|
||||
<td class="history_delete">
|
||||
<a ng-click="deleteHistoryItem(item)">
|
||||
<img class="delete_icon" src="delete.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
10
share/tools/web_config/partials/prompt.html
Normal file
10
share/tools/web_config/partials/prompt.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
<div style="padding: 0 10px 15px;">
|
||||
<div ng-repeat="prompt in samplePrompts">
|
||||
<div class="prompt_demo_choice_label">{{ prompt.name }}</div>
|
||||
<div ng-bind-html-unsafe='prompt.demo' class="prompt_demo" ng-click="selectPrompt(prompt)"></div>
|
||||
<div class="prompt_function" ng-show="selectedPrompt == prompt">
|
||||
<div class="prompt_function_text">{{ prompt.function }}</div>
|
||||
</div>
|
||||
<span class="prompt_save_button" ng-click="setNewPrompt(selectedPrompt)" ng-show="selectedPrompt == prompt && selectedPrompt != samplePrompts[0]">Use</span>
|
||||
</div>
|
||||
</div>
|
13
share/tools/web_config/partials/variables.html
Normal file
13
share/tools/web_config/partials/variables.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<div id="table_filter_container">
|
||||
<input id="table_filter_text_box" class="filter_text_box text_box_transient" placeholder="Filter" ng-model="query">
|
||||
</div>
|
||||
|
||||
<table class="data_table">
|
||||
<tbody>
|
||||
<tr class="data_table_row" ng-repeat="variable in variables | filterVariable:query">
|
||||
<td class="data_table_cell no_overflow" style="text-align: right; padding-right: 30px;">{{ variable.name }}</td>
|
||||
<!-- Small hack to select/unselect variables -->
|
||||
<td ng-class="{'data_table_cell': true, 'no_overflow': !variable._is_selected}" style="text-align: left; padding-right: 30px;" ng-click="variable._is_selected=!variable._is_selected">{{ variable.value }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
|
@ -101,7 +101,7 @@ def parse_color(color_str):
|
|||
# Regular color
|
||||
color = better_color(color, parse_one_color(comp))
|
||||
|
||||
return [color, background_color, bold, underline]
|
||||
return {"color": color, "background": background_color, "bold": bold, "underline": underline}
|
||||
|
||||
def parse_bool(val):
|
||||
val = val.lower()
|
||||
|
@ -124,7 +124,7 @@ def get_special_ansi_escapes():
|
|||
import curses
|
||||
g_special_escapes_dict = {}
|
||||
curses.setupterm()
|
||||
|
||||
|
||||
# Helper function to get a value for a tparm
|
||||
def get_tparm(key):
|
||||
val = None
|
||||
|
@ -132,12 +132,12 @@ def get_special_ansi_escapes():
|
|||
if key: val = curses.tparm(key)
|
||||
if val: val = val.decode('utf-8')
|
||||
return val
|
||||
|
||||
|
||||
# Just a few for now
|
||||
g_special_escapes_dict['exit_attribute_mode'] = get_tparm('sgr0')
|
||||
g_special_escapes_dict['bold'] = get_tparm('bold')
|
||||
g_special_escapes_dict['underline'] = get_tparm('smul')
|
||||
|
||||
|
||||
return g_special_escapes_dict
|
||||
|
||||
# Given a known ANSI escape sequence, convert it to HTML and append to the list
|
||||
|
@ -146,12 +146,12 @@ def append_html_for_ansi_escape(full_val, result, span_open):
|
|||
|
||||
# Strip off the initial \x1b[ and terminating m
|
||||
val = full_val[2:-1]
|
||||
|
||||
|
||||
# Helper function to close a span if it's open
|
||||
def close_span():
|
||||
if span_open:
|
||||
result.append('</span>')
|
||||
|
||||
|
||||
# term256 foreground color
|
||||
match = re.match('38;5;(\d+)', val)
|
||||
if match is not None:
|
||||
|
@ -159,7 +159,7 @@ def append_html_for_ansi_escape(full_val, result, span_open):
|
|||
html_color = html_color_for_ansi_color_index(int(match.group(1)))
|
||||
result.append('<span style="color: ' + html_color + '">')
|
||||
return True # span now open
|
||||
|
||||
|
||||
# term8 foreground color
|
||||
if val in [str(x) for x in range(30, 38)]:
|
||||
close_span()
|
||||
|
@ -172,26 +172,26 @@ def append_html_for_ansi_escape(full_val, result, span_open):
|
|||
if full_val == special_escapes['exit_attribute_mode']:
|
||||
close_span()
|
||||
return False
|
||||
|
||||
|
||||
# We don't handle bold or underline yet
|
||||
|
||||
|
||||
# Do nothing on failure
|
||||
return span_open
|
||||
|
||||
|
||||
def strip_ansi(val):
|
||||
# Make a half-assed effort to strip ANSI control sequences
|
||||
# We assume that all such sequences start with 0x1b and end with m,
|
||||
# which catches most cases
|
||||
return re.sub("\x1b[^m]*m", '', val)
|
||||
|
||||
|
||||
def ansi_prompt_line_width(val):
|
||||
# Given an ANSI prompt, return the length of its longest line, as in the number of characters it takes up
|
||||
# Start by stripping off ANSI
|
||||
stripped_val = strip_ansi(val)
|
||||
|
||||
|
||||
# Now count the longest line
|
||||
return max([len(x) for x in stripped_val.split('\n')])
|
||||
|
||||
|
||||
|
||||
def ansi_to_html(val):
|
||||
# Split us up by ANSI escape sequences
|
||||
|
@ -206,13 +206,13 @@ def ansi_to_html(val):
|
|||
) # End capture
|
||||
""", re.VERBOSE)
|
||||
separated = reg.split(val)
|
||||
|
||||
|
||||
# We have to HTML escape the text and convert ANSI escapes into HTML
|
||||
# Collect it all into this array
|
||||
result = []
|
||||
|
||||
|
||||
span_open = False
|
||||
|
||||
|
||||
# Text is at even indexes, escape sequences at odd indexes
|
||||
for i in range(len(separated)):
|
||||
component = separated[i]
|
||||
|
@ -223,13 +223,13 @@ def ansi_to_html(val):
|
|||
else:
|
||||
# It's an escape sequence. Close the previous escape.
|
||||
span_open = append_html_for_ansi_escape(component, result, span_open)
|
||||
|
||||
|
||||
# Close final escape
|
||||
if span_open: result.append('</span>')
|
||||
|
||||
|
||||
# Remove empty elements
|
||||
result = [x for x in result if x]
|
||||
|
||||
|
||||
# Clean up empty spans, the nasty way
|
||||
idx = len(result) - 1
|
||||
while idx >= 1:
|
||||
|
@ -254,7 +254,161 @@ class FishVar:
|
|||
flags = []
|
||||
if self.universal: flags.append('universal')
|
||||
if self.exported: flags.append('exported')
|
||||
return [self.name, self.value, ', '.join(flags)]
|
||||
return {"name": self.name, "value": self.value, "Flags": ', '.join(flags)}
|
||||
|
||||
class FishBinding:
|
||||
"""A class that represents keyboard binding """
|
||||
|
||||
def __init__(self, command, binding, readable_binding, description=None):
|
||||
self.command = command
|
||||
self.binding = binding
|
||||
self.readable_binding = readable_binding
|
||||
self.description = description
|
||||
|
||||
def get_json_obj(self):
|
||||
return {"command" : self.command, "binding": self.binding, "readable_binding": self.readable_binding, "description": self.description }
|
||||
|
||||
def get_readable_binding(command):
|
||||
return command
|
||||
|
||||
class BindingParser:
|
||||
""" Class to parse codes for bind command """
|
||||
|
||||
#TODO: What does snext and sprevious mean ?
|
||||
readable_keys= { "dc":"Delete", "npage": "Page Up", "ppage":"Page Down",
|
||||
"sdc": "Shift Delete", "shome": "Shift Home",
|
||||
"left": "Left Arrow", "right": "Right Arrow",
|
||||
"up": "Up Arrow", "down": "Down Arrow",
|
||||
"sleft": "Shift Left", "sright": "Shift Right"
|
||||
}
|
||||
|
||||
def set_buffer(self, buffer, is_key=False):
|
||||
""" Sets code to parse """
|
||||
|
||||
self.buffer = buffer
|
||||
self.is_key = is_key
|
||||
self.index = 0
|
||||
|
||||
def get_char(self):
|
||||
""" Gets next character from buffer """
|
||||
|
||||
c = self.buffer[self.index]
|
||||
self.index += 1
|
||||
return c
|
||||
|
||||
def unget_char(self):
|
||||
""" Goes back by one character for parsing """
|
||||
|
||||
self.index -= 1
|
||||
|
||||
def end(self):
|
||||
""" Returns true if reached end of buffer """
|
||||
|
||||
return self.index >= len(self.buffer)
|
||||
|
||||
def parse_control_sequence(self):
|
||||
""" Parses terminal specifiec control sequences """
|
||||
|
||||
result = ''
|
||||
c = self.get_char()
|
||||
|
||||
# \e0 is used to denote start of control sequence
|
||||
if c == 'O':
|
||||
c = self.get_char()
|
||||
|
||||
# \[1\; is start of control sequence
|
||||
if c == '1':
|
||||
self.get_char();c = self.get_char()
|
||||
if c == ";":
|
||||
c = self.get_char()
|
||||
|
||||
# 3 is Alt
|
||||
if c == '3':
|
||||
result += "ALT - "
|
||||
c = self.get_char()
|
||||
|
||||
# 5 is Ctrl
|
||||
if c == '5':
|
||||
result += "CTRL - "
|
||||
c = self.get_char()
|
||||
|
||||
# 9 is Alt
|
||||
if c == '9':
|
||||
result += "ALT - "
|
||||
c = self.get_char()
|
||||
|
||||
if c == 'A':
|
||||
result += 'Up Arrow'
|
||||
elif c == 'B':
|
||||
result += 'Down Arrow'
|
||||
elif c == 'C':
|
||||
result += 'Right Arrow'
|
||||
elif c == 'D':
|
||||
result += "Left Arrow"
|
||||
elif c == 'F':
|
||||
result += "End"
|
||||
elif c == 'H':
|
||||
result += "Home"
|
||||
|
||||
return result
|
||||
|
||||
def get_readable_binding(self):
|
||||
""" Gets a readable representation of binding """
|
||||
|
||||
if self.is_key:
|
||||
try:
|
||||
result = BindingParser.readable_keys[self.buffer]
|
||||
except KeyError:
|
||||
result = self.buffer.title()
|
||||
else:
|
||||
result = self.parse_binding()
|
||||
|
||||
return result
|
||||
|
||||
def parse_binding(self):
|
||||
readable_command = ''
|
||||
result = ''
|
||||
alt = ctrl = False
|
||||
|
||||
while not self.end():
|
||||
c = self.get_char()
|
||||
|
||||
if c == '\\':
|
||||
c = self.get_char()
|
||||
if c == 'e':
|
||||
d = self.get_char()
|
||||
if d == 'O':
|
||||
self.unget_char()
|
||||
result += self.parse_control_sequence()
|
||||
elif d == '\\':
|
||||
if self.get_char() == '[':
|
||||
result += self.parse_control_sequence()
|
||||
else:
|
||||
self.unget_char()
|
||||
self.unget_char()
|
||||
alt = True
|
||||
else:
|
||||
alt = True
|
||||
self.unget_char()
|
||||
elif c == 'c':
|
||||
ctrl = True
|
||||
elif c == 'n':
|
||||
result += 'Enter'
|
||||
elif c == 't':
|
||||
result += 'Tab'
|
||||
elif c == 'b':
|
||||
result += 'Backspace'
|
||||
else:
|
||||
result += c
|
||||
else:
|
||||
result += c
|
||||
if ctrl:
|
||||
readable_command += 'CTRL - '
|
||||
if alt:
|
||||
readable_command += 'ALT - '
|
||||
|
||||
return readable_command + result
|
||||
|
||||
|
||||
class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
|
||||
|
@ -314,7 +468,9 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|||
for match in re.finditer(r"^fish_color_(\S+) ?(.*)", line):
|
||||
color_name, color_value = [x.strip() for x in match.group(1, 2)]
|
||||
color_desc = descriptions.get(color_name, '')
|
||||
result.append([color_name, color_desc, parse_color(color_value)])
|
||||
data = { "name": color_name, "description" : color_desc }
|
||||
data.update(parse_color(color_value))
|
||||
result.append(data)
|
||||
remaining.discard(color_name)
|
||||
|
||||
# Ensure that we have all the color names we know about, so that if the
|
||||
|
@ -363,6 +519,39 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|||
|
||||
return [vars[key].get_json_obj() for key in sorted(vars.keys(), key=str.lower)]
|
||||
|
||||
def do_get_bindings(self):
|
||||
""" Get key bindings """
|
||||
|
||||
# Running __fish_config_interactive print fish greeting and
|
||||
# loads key bindings
|
||||
greeting, err = run_fish_cmd(' __fish_config_interactive')
|
||||
|
||||
# Load the key bindings and then list them with bind
|
||||
out, err = run_fish_cmd('__fish_config_interactive; bind')
|
||||
|
||||
# Remove fish greeting from output
|
||||
out = out[len(greeting):]
|
||||
|
||||
# Put all the bindings into a list
|
||||
bindings = []
|
||||
binding_parser = BindingParser()
|
||||
|
||||
for line in out.split('\n'):
|
||||
comps = line.split(' ', 2)
|
||||
if len(comps) < 3:
|
||||
continue
|
||||
if comps[1] == '-k':
|
||||
key_name, command = comps[2].split(' ', 1)
|
||||
binding_parser.set_buffer(key_name, True)
|
||||
fish_binding = FishBinding(command=command, binding=key_name, readable_binding=binding_parser.get_readable_binding())
|
||||
else:
|
||||
binding_parser.set_buffer(comps[1])
|
||||
fish_binding = FishBinding(command=comps[2], binding=comps[1], readable_binding=binding_parser.get_readable_binding())
|
||||
|
||||
bindings.append(fish_binding)
|
||||
|
||||
return [ binding.get_json_obj() for binding in bindings ]
|
||||
|
||||
def do_get_history(self):
|
||||
# Use \x1e ("record separator") to distinguish between history items. The first
|
||||
# backslash is so Python passes one backslash to fish
|
||||
|
@ -371,7 +560,6 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|||
if result: result.pop() # Trim off the trailing element
|
||||
return result
|
||||
|
||||
|
||||
def do_get_color_for_variable(self, name):
|
||||
"Return the color with the given name, or the empty string if there is none"
|
||||
out, err = run_fish_cmd("echo -n $" + name)
|
||||
|
@ -397,12 +585,12 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|||
# It's really lame that we always return success here
|
||||
out, err = run_fish_cmd('builtin history --save --delete -- ' + escape_fish_cmd(history_item_text))
|
||||
return True
|
||||
|
||||
|
||||
def do_set_prompt_function(self, prompt_func):
|
||||
cmd = prompt_func + '\n' + 'funcsave fish_prompt'
|
||||
out, err = run_fish_cmd(cmd)
|
||||
return len(err) == 0
|
||||
|
||||
|
||||
def do_get_prompt(self, command_to_run, prompt_function_text):
|
||||
# Return the prompt output by the given command
|
||||
prompt_demo_ansi, err = run_fish_cmd(command_to_run)
|
||||
|
@ -414,7 +602,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|||
# Return the current prompt
|
||||
prompt_func, err = run_fish_cmd('functions fish_prompt')
|
||||
return self.do_get_prompt('cd "' + initial_wd + '" ; fish_prompt', prompt_func.strip())
|
||||
|
||||
|
||||
def do_get_sample_prompt(self, text):
|
||||
# Return the prompt you get from the given text
|
||||
cmd = text + "\n cd \"" + initial_wd + "\" \n fish_prompt\n"
|
||||
|
@ -424,7 +612,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|||
# Allow us to skip whitespace, etc.
|
||||
if not line: return True
|
||||
if line.isspace(): return True
|
||||
|
||||
|
||||
# Parse a comment hash like '# name: Classic'
|
||||
match = re.match(r"#\s*(\w+?): (.+)", line, re.IGNORECASE)
|
||||
if match:
|
||||
|
@ -434,8 +622,8 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|||
return True
|
||||
# Skip other hash comments
|
||||
return line.startswith('#')
|
||||
|
||||
|
||||
|
||||
|
||||
def read_one_sample_prompt(self, fd):
|
||||
# Read one sample prompt from fd
|
||||
function_lines = []
|
||||
|
@ -448,14 +636,16 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|||
# Maybe not we're not parsing hashes, or maybe we already were not
|
||||
if not parsing_hashes:
|
||||
function_lines.append(line)
|
||||
result['function'] = ''.join(function_lines).strip()
|
||||
return result
|
||||
|
||||
func = ''.join(function_lines).strip()
|
||||
result.update(self.do_get_sample_prompt(func))
|
||||
return result
|
||||
|
||||
def do_get_sample_prompts_list(self):
|
||||
result = []
|
||||
# Start with the "Current" meta-sample
|
||||
result.append({'name': 'Current'})
|
||||
|
||||
result[0].update(self.do_get_current_prompt())
|
||||
|
||||
# Read all of the prompts in sample_prompts
|
||||
paths = glob.iglob('sample_prompts/*.fish')
|
||||
for path in paths:
|
||||
|
@ -467,7 +657,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|||
# Ignore unreadable files, etc
|
||||
pass
|
||||
return result
|
||||
|
||||
|
||||
def font_size_for_ansi_prompt(self, prompt_demo_ansi):
|
||||
width = ansi_prompt_line_width(prompt_demo_ansi)
|
||||
# Pick a font size
|
||||
|
@ -502,6 +692,8 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|||
elif re.match(r"/color/(\w+)/", p):
|
||||
name = re.match(r"/color/(\w+)/", p).group(1)
|
||||
output = self.do_get_color_for_variable(name)
|
||||
elif p == '/bindings/':
|
||||
output = self.do_get_bindings()
|
||||
else:
|
||||
return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
|
||||
|
||||
|
@ -578,7 +770,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|||
def log_request(self, code='-', size='-'):
|
||||
""" Disable request logging """
|
||||
pass
|
||||
|
||||
|
||||
# find fish
|
||||
fish_bin_dir = os.environ.get('__fish_bin_dir')
|
||||
fish_bin_path = None
|
||||
|
@ -599,7 +791,7 @@ if not fish_bin_dir:
|
|||
|
||||
else:
|
||||
fish_bin_path = os.path.join(fish_bin_dir, 'fish')
|
||||
|
||||
|
||||
if not os.access(fish_bin_path, os.X_OK):
|
||||
print("fish could not be executed at path '%s'. Is fish installed correctly?" % fish_bin_path)
|
||||
sys.exit(-1)
|
||||
|
|
Loading…
Reference in New Issue
Block a user