mirror of
https://github.com/cs01/gdbgui
synced 2024-11-17 07:48:57 +01:00
add ability to jump to line; add red error label in statusbar
This commit is contained in:
parent
c800218614
commit
0513235793
4 changed files with 169 additions and 101 deletions
|
@ -28,6 +28,10 @@ pre{
|
|||
.flex{
|
||||
display: flex;
|
||||
}
|
||||
.flexrow{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
/* components get their own titlebars */
|
||||
.titlebar{
|
||||
width: 100%;
|
||||
|
@ -46,43 +50,6 @@ pre{
|
|||
border-width: 1px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* specific styling for ids */
|
||||
#always_on_top{
|
||||
position: fixed;
|
||||
top: 0;
|
||||
margin-top: 0;
|
||||
height: 102px;
|
||||
width: 100%;
|
||||
border-bottom: black;
|
||||
border-style: solid;
|
||||
border-width: 0px;
|
||||
border-bottom-width: 1px;
|
||||
z-index: 1000;
|
||||
background: #f1f1f1;
|
||||
border-bottom-color: #ccc;
|
||||
}
|
||||
#console{
|
||||
font-size: 0.9em !important;
|
||||
background-color: #292929 !important;
|
||||
color: #f9f9f9 !important;
|
||||
font-family: monospace !important;
|
||||
}
|
||||
#gdb_command{
|
||||
padding-left: 45px;
|
||||
border-top: 0;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
font-size: 0.9em !important;
|
||||
background-color: #3c3c3c !important;
|
||||
color: #f9f9f9 !important;
|
||||
font-family: monospace !important;
|
||||
}
|
||||
#gdb_mi_output{
|
||||
font-family: monospace;
|
||||
overflow: auto;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.sent_command:hover{
|
||||
/* lighten background */
|
||||
background-color:rgba(255,255,255,0.1)
|
||||
|
@ -154,13 +121,6 @@ pre{
|
|||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
/* auto-complete librarie's dropdown should only be 200px high, and should
|
||||
have scrollbar, so it doesn't take over the page */
|
||||
.awesomplete ul {
|
||||
overflow: auto;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
/* show a flash of color */
|
||||
.flash {
|
||||
-webkit-animation-name: flash-animation;
|
||||
|
@ -180,6 +140,44 @@ have scrollbar, so it doesn't take over the page */
|
|||
to { background: default; }
|
||||
}
|
||||
|
||||
/* specific styling for ids */
|
||||
#always_on_top{
|
||||
position: fixed;
|
||||
top: 0;
|
||||
margin-top: 0;
|
||||
height: 102px;
|
||||
width: 100%;
|
||||
border-bottom: black;
|
||||
border-style: solid;
|
||||
border-width: 0px;
|
||||
border-bottom-width: 1px;
|
||||
z-index: 1000;
|
||||
background: #f1f1f1;
|
||||
border-bottom-color: #ccc;
|
||||
}
|
||||
#console{
|
||||
font-size: 0.9em !important;
|
||||
background-color: #292929 !important;
|
||||
color: #f9f9f9 !important;
|
||||
font-family: monospace !important;
|
||||
}
|
||||
#gdb_command{
|
||||
padding-left: 45px;
|
||||
border-top: 0;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
font-size: 0.9em !important;
|
||||
background-color: #3c3c3c !important;
|
||||
color: #f9f9f9 !important;
|
||||
font-family: monospace !important;
|
||||
}
|
||||
#gdb_mi_output{
|
||||
font-family: monospace;
|
||||
overflow: auto;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
/* styling for "Variables" component */
|
||||
#variables li{
|
||||
list-style: none;
|
||||
}
|
||||
|
@ -194,3 +192,17 @@ have scrollbar, so it doesn't take over the page */
|
|||
.toggle_children_visibility{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
/* Vendor Overrides */
|
||||
|
||||
/* awesomeplete wraps inputs in a div, and the div is really small. Make it big. */
|
||||
div.awesomplete{
|
||||
width: 100%;
|
||||
}
|
||||
/* auto-complete library (awesomplete) has unlimited dropdown size.
|
||||
Limit to 200px high, and add scrollbar, so it doesn't take over the page */
|
||||
.awesomplete ul {
|
||||
overflow: auto;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
|
|
@ -14,14 +14,18 @@ const ENTER_BUTTON_NUM = 13
|
|||
|
||||
const Status = {
|
||||
el: $('#status'),
|
||||
render: function(status){
|
||||
Status.el.text(status)
|
||||
render: function(status_str, error=false){
|
||||
if(error){
|
||||
Status.el.html(`<span class='label label-danger'>error</span> ${status_str}`)
|
||||
}else{
|
||||
Status.el.html(status_str)
|
||||
}
|
||||
},
|
||||
render_ajax_error_msg: function(data){
|
||||
if (data.responseJSON && data.responseJSON.message){
|
||||
Status.render(_.escape(data.responseJSON.message))
|
||||
Status.render(_.escape(data.responseJSON.message), true)
|
||||
}else{
|
||||
Status.render(`${data.statusText} (${data.status} error)`)
|
||||
Status.render(`${data.statusText} (${data.status} error)`, true)
|
||||
}
|
||||
},
|
||||
render_from_gdb_mi_response: function(mi_obj){
|
||||
|
@ -30,9 +34,14 @@ const Status = {
|
|||
return
|
||||
}
|
||||
// Update status
|
||||
let status = [];
|
||||
let status = [],
|
||||
error = false
|
||||
if (mi_obj.message){
|
||||
status.push(mi_obj.message)
|
||||
if(mi_obj.message === 'error'){
|
||||
error = true
|
||||
}else{
|
||||
status.push(mi_obj.message)
|
||||
}
|
||||
}
|
||||
if (mi_obj.payload){
|
||||
if (mi_obj.payload.msg) {status.push(mi_obj.payload.msg)}
|
||||
|
@ -45,7 +54,7 @@ const Status = {
|
|||
}
|
||||
}
|
||||
}
|
||||
Status.render(status.join(', '))
|
||||
Status.render(status.join(', '), error)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -368,11 +377,13 @@ const SourceCode = {
|
|||
el: $('#code_table'),
|
||||
el_code_container: $('#code_container'),
|
||||
el_title: $('#source_code_heading'),
|
||||
el_jump_to_line_input: $('#jump_to_line'),
|
||||
rendered_source_file_fullname: null,
|
||||
rendered_source_file_line: null,
|
||||
init: function(){
|
||||
$("body").on("click", ".source_code_row td .line_num", SourceCode.click_gutter)
|
||||
$("body").on("click", ".view_file", SourceCode.click_view_file)
|
||||
SourceCode.el_jump_to_line_input.keydown(SourceCode.keydown_jump_to_line)
|
||||
},
|
||||
cached_source_files: [], // list with keys fullname, source_code
|
||||
click_gutter: function(e){
|
||||
|
@ -394,7 +405,7 @@ const SourceCode = {
|
|||
is_cached: function(fullname){
|
||||
return SourceCode.cached_source_files.some(f => f.fullname === fullname)
|
||||
},
|
||||
render_source_file: function(fullname, source_code, current_line=0, options={'highlight': false, 'scroll': false}){
|
||||
render_source_file: function(fullname, source_code, current_line=1, options={'highlight': false, 'scroll': false}){
|
||||
current_line = parseInt(current_line)
|
||||
let line_num = 1,
|
||||
tbody = [],
|
||||
|
@ -423,6 +434,7 @@ const SourceCode = {
|
|||
line_num++;
|
||||
}
|
||||
SourceCode.el_title.text(fullname)
|
||||
SourceCode.el_jump_to_line_input.val(current_line)
|
||||
SourceCode.el.html(tbody.join(''))
|
||||
|
||||
SourceCode.rendered_source_file_fullname = fullname
|
||||
|
@ -432,14 +444,18 @@ const SourceCode = {
|
|||
SourceCode.make_current_line_visible()
|
||||
}
|
||||
},
|
||||
make_current_line_visible: function(){
|
||||
SourceCode.scroll_to_jq_selector($("#current_line"))
|
||||
},
|
||||
// call this to rerender a file when breakpoints change, for example
|
||||
rerender: function(){
|
||||
if(_.isString(SourceCode.rendered_source_file_fullname)){
|
||||
// TODO redraw only breakpoint rows, not the whole source file
|
||||
SourceCode.fetch_and_render_file(SourceCode.rendered_source_file_fullname, SourceCode.rendered_source_file_line, {'highlight': false, 'scroll': false})
|
||||
}
|
||||
},
|
||||
// fetch file and render it, or used cached file if we have it
|
||||
fetch_and_render_file: function(fullname, current_line=0, options={'highlight': false, 'scroll': false}){
|
||||
fetch_and_render_file: function(fullname, current_line=1, options={'highlight': false, 'scroll': false}){
|
||||
if (!_.isString(fullname)){
|
||||
console.error('cannot render file without a name')
|
||||
|
||||
|
@ -467,22 +483,25 @@ const SourceCode = {
|
|||
})
|
||||
}
|
||||
},
|
||||
make_current_line_visible: function(){
|
||||
const time_to_scroll = 0
|
||||
let jq_current_line = $("#current_line")
|
||||
if (jq_current_line.length === 1){ // make sure a line is selected before trying to scroll to it
|
||||
/**
|
||||
* Scroll to a jQuery selection in the source code table
|
||||
* Used to jump around to various lines
|
||||
*/
|
||||
scroll_to_jq_selector: function(jq_selector){
|
||||
if (jq_selector.length === 1){ // make sure a line is selected before trying to scroll to it
|
||||
let top_of_container = SourceCode.el_code_container.position().top,
|
||||
height_of_container = SourceCode.el_code_container.height(),
|
||||
bottom_of_container = top_of_container + height_of_container,
|
||||
top_of_line = jq_current_line.position().top,
|
||||
bottom_of_line = top_of_line+ jq_current_line.height(),
|
||||
top_of_table = jq_current_line.closest('table').position().top
|
||||
top_of_line = jq_selector.position().top,
|
||||
bottom_of_line = top_of_line+ jq_selector.height(),
|
||||
top_of_table = jq_selector.closest('table').position().top
|
||||
|
||||
if ((top_of_line >= top_of_container) && (bottom_of_line < (bottom_of_container))){
|
||||
// do nothing, it's already in view
|
||||
}else{
|
||||
// line is out of view, scroll so it's in the middle of the table
|
||||
SourceCode.el_code_container.animate({'scrollTop': top_of_line - (top_of_table + height_of_container/2)}, 0)
|
||||
const time_to_scroll = 0
|
||||
SourceCode.el_code_container.animate({'scrollTop': top_of_line - (top_of_table + height_of_container/2)}, time_to_scroll)
|
||||
}
|
||||
|
||||
}else{
|
||||
|
@ -514,6 +533,16 @@ const SourceCode = {
|
|||
line = e.currentTarget.dataset['line'],
|
||||
highlight = e.currentTarget.dataset['highlight'] === 'true'
|
||||
SourceCode.fetch_and_render_file(fullname, line, {'highlight': highlight, 'scroll': true})
|
||||
},
|
||||
keydown_jump_to_line: function(e){
|
||||
if (e.keyCode === ENTER_BUTTON_NUM){
|
||||
let line = e.currentTarget.value
|
||||
SourceCode.jump_to_line(line)
|
||||
}
|
||||
},
|
||||
jump_to_line: function(line){
|
||||
let jq_selector = $(`.line_num[data-line=${line}]`)
|
||||
SourceCode.scroll_to_jq_selector(jq_selector)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -551,14 +580,31 @@ const SourceFileAutocomplete = {
|
|||
|
||||
// perform action when an item is selected
|
||||
Awesomplete.$('#source_file_input').addEventListener('awesomplete-selectcomplete', function(e){
|
||||
SourceCode.fetch_and_render_file(e.currentTarget.value)
|
||||
let fullname = e.currentTarget.value,
|
||||
line = 1
|
||||
SourceCode.fetch_and_render_file(fullname, 1, {'highlight': false, 'scroll': true})
|
||||
})
|
||||
},
|
||||
keyup_source_file_input: function(e){
|
||||
if (e.keyCode === ENTER_BUTTON_NUM){
|
||||
SourceCode.fetch_and_render_file(e.currentTarget.value)
|
||||
let user_input = _.trim(e.currentTarget.value)
|
||||
|
||||
if(user_input.length === 0){
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// if user enterted "/path/to/file.c:line", be friendly and parse out the line for them
|
||||
let user_input_array = user_input.split(':'),
|
||||
file = user_input_array[0],
|
||||
line = 1
|
||||
if(user_input_array.length === 2){
|
||||
line = user_input_array[1]
|
||||
}
|
||||
|
||||
SourceCode.fetch_and_render_file(file, line, {'highlight': false, 'scroll': true})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,7 +28,7 @@ body
|
|||
form(role=form)
|
||||
div.input-group.input-group-sm
|
||||
span.input-group-btn
|
||||
button.btn.btn-primary#set_target_app(type="button") Load This Binary
|
||||
button.btn.btn-primary#set_target_app(type="button") Load This Binary and Args
|
||||
input.form-control#binary(type="text", placeholder="/path/to/target/executable -and -flags", list='past_binaries', style="font-family: courier")
|
||||
datalist#past_binaries
|
||||
|
||||
|
@ -63,26 +63,31 @@ body
|
|||
//- source
|
||||
div.no_padding.col-md-12#source_div
|
||||
|
||||
div.titlebar.flex
|
||||
span#source_code_heading.lighttext (no source code file loaded)
|
||||
input#jump_to_line.form-control.dropdown-input(autocomplete='on', placeholder='line', title='Enter line number, then press enter', style="width: 150px; position: inline")
|
||||
div.titlebar
|
||||
div
|
||||
input#source_file_input.dropdown-input(autocomplete='off', placeholder='Enter source file path here, or select from dropdown', style="width: 500px")
|
||||
div.flexrow
|
||||
input#source_file_input.form-control.dropdown-input(autocomplete='off', placeholder='Enter source file path to view, or load binary then populate and select from dropdown', style='flex:1')
|
||||
|
||||
button.dropdown-btn(type="button")
|
||||
span.caret
|
||||
button.dropdown-btn(type="button")
|
||||
span.caret
|
||||
|
||||
button.btn.btn-default.gdb_cmd.btn-xs(type="button", data-cmd='-file-list-exec-source-files') Populate List
|
||||
button.btn.btn-default.gdb_cmd.btn-xs(type="button", data-cmd='-file-list-exec-source-files') Populate List
|
||||
|
||||
div.flex
|
||||
//- display loaded file path and input to jump to line
|
||||
span#source_code_heading.lighttext (no source code file loaded)
|
||||
span.glyphicon.glyphicon-plus.resizer.pointer(data-target_selector="#code_container" data-resize_type="enlarge")
|
||||
span.glyphicon.glyphicon-minus.resizer.pointer(data-target_selector="#code_container" data-resize_type="shrink")
|
||||
|
||||
//- input to jump to a line in the source code
|
||||
input#jump_to_line.form-control.dropdown-input(autocomplete='on', placeholder='jump to line', title='Enter line number, then press enter', style="width: 150px; height: 25px; margin-left: 10")
|
||||
|
||||
div#code_container.gdb_content_div(style="height: 300px")
|
||||
table#code_table.code
|
||||
tr
|
||||
td Source code will be displayed here when applicable
|
||||
|
||||
div.col-md-6.no_padding
|
||||
div.col-md-12.no_padding
|
||||
div.titlebar
|
||||
span.lighttext stack
|
||||
span.glyphicon.glyphicon-plus.resizer.pointer(data-target_selector="#stack" data-resize_type="enlarge")
|
||||
|
@ -91,24 +96,24 @@ body
|
|||
span.glyphicon.glyphicon-refresh.padding_left
|
||||
div#stack.gdb_content_div
|
||||
|
||||
div.col-md-6.no_padding
|
||||
div.col-md-12.no_padding
|
||||
div.titlebar
|
||||
span.lighttext breakpoints
|
||||
button.btn.btn-default.btn-xs.gdb_cmd(type='button', data-cmd='-break-list', title="Get table of all breakpoints (-break-list')") Refresh
|
||||
span.glyphicon.glyphicon-refresh.padding_left
|
||||
span.glyphicon.glyphicon-plus.resizer.pointer(data-target_selector="#breakpoints" data-resize_type="enlarge")
|
||||
span.glyphicon.glyphicon-minus.resizer.pointer(data-target_selector="#breakpoints" data-resize_type="shrink")
|
||||
button.btn.btn-default.btn-xs.gdb_cmd(type='button', data-cmd='-break-list', title="Get table of all breakpoints (-break-list')") Refresh
|
||||
span.glyphicon.glyphicon-refresh.padding_left
|
||||
div#breakpoints.gdb_content_div
|
||||
|
||||
div.col-md-6.no_padding
|
||||
div.col-md-12.no_padding
|
||||
div.titlebar.flex
|
||||
span.lighttext variables
|
||||
span.glyphicon.glyphicon-plus.resizer.pointer(data-target_selector="#variables" data-resize_type="enlarge")
|
||||
span.glyphicon.glyphicon-minus.resizer.pointer(data-target_selector="#variables" data-resize_type="shrink")
|
||||
input#variable_input.form-control(placeholder='reach breakpoint, then enter expression or variable and press enter', style="height:20px")
|
||||
input#variable_input.form-control(placeholder='reach breakpoint, then enter expression or variable and press enter', style="height:25px")
|
||||
div#variables.gdb_content_div
|
||||
|
||||
div.col-md-6.no_padding
|
||||
div.col-md-2.no_padding
|
||||
div.titlebar
|
||||
span.lighttext registers
|
||||
span.glyphicon.glyphicon-plus.resizer.pointer(data-target_selector="#registers" data-resize_type="enlarge")
|
||||
|
@ -116,9 +121,16 @@ body
|
|||
button.btn.btn-default.btn-xs.gdb_cmd(type='button', data-cmd0='-data-list-register-names', data-cmd1='-data-list-register-values x', title='Refresh all register names and values (-data-list-register-values x)') Refresh
|
||||
span.glyphicon.glyphicon-refresh.padding_left
|
||||
div#registers.gdb_content_div
|
||||
|
||||
div.col-md-6.no_padding
|
||||
div.col-md-10.no_padding
|
||||
div.titlebar
|
||||
span.lighttext memory
|
||||
span.glyphicon.glyphicon-plus.resizer.pointer(data-target_selector="#memory" data-resize_type="enlarge")
|
||||
span.glyphicon.glyphicon-minus.resizer.pointer(data-target_selector="#memory" data-resize_type="shrink")
|
||||
div#memory.gdb_content_div
|
||||
|
||||
div.row
|
||||
div.col-md-6.no_padding
|
||||
div.titlebar.flex
|
||||
span.lighttext disassembly
|
||||
span#disassembly_heading
|
||||
span.glyphicon.glyphicon-plus.resizer.pointer(data-target_selector="#disassembly" data-resize_type="enlarge")
|
||||
|
@ -127,32 +139,25 @@ body
|
|||
span.glyphicon.glyphicon-refresh.padding_left
|
||||
div#disassembly.gdb_content_div
|
||||
|
||||
div.col-md-6.no_padding
|
||||
div.titlebar
|
||||
span.lighttext memory
|
||||
span.glyphicon.glyphicon-plus.resizer.pointer(data-target_selector="#memory" data-resize_type="enlarge")
|
||||
span.glyphicon.glyphicon-minus.resizer.pointer(data-target_selector="#memory" data-resize_type="shrink")
|
||||
div#memory.gdb_content_div
|
||||
|
||||
div.col-md-6.no_padding
|
||||
div.titlebar
|
||||
span.lighttext All Local Variables
|
||||
button.btn.btn-default.btn-xs.gdb_cmd(type='button', data-cmd='-stack-list-locals --all-values', title="Refresh all data names and values (-stack-list-locals --all-values')") Refresh
|
||||
span.glyphicon.glyphicon-plus.resizer.pointer(data-target_selector="#all_local_variables" data-resize_type="enlarge")
|
||||
span.glyphicon.glyphicon-minus.resizer.pointer(data-target_selector="#all_local_variables" data-resize_type="shrink")
|
||||
button.btn.btn-default.btn-xs.gdb_cmd(type='button', data-cmd='-stack-list-locals --all-values', title="Refresh all data names and values (-stack-list-locals --all-values')") Refresh
|
||||
div#all_local_variables.gdb_content_div
|
||||
|
||||
div.col-md-12.no_padding
|
||||
//- text/buttons above the gdb console output
|
||||
div.titlebar
|
||||
span.lighttext gdb console
|
||||
span.glyphicon.glyphicon-plus.resizer.pointer(data-target_selector="#console" data-resize_type="enlarge")
|
||||
span.glyphicon.glyphicon-minus.resizer.pointer(data-target_selector="#console" data-resize_type="shrink")
|
||||
div.btn-group
|
||||
button.btn.btn-default.btn-xs.clear_console(type='button', title='Clear Console (clears ui element, does not send a gdb command)') Clear Console
|
||||
span.glyphicon.glyphicon-ban-circle.padding_left
|
||||
button.btn.btn-default.btn-xs.gdb_cmd(type='button', data-cmd='-data-evaluate-expression fflush(0)', title='Flush output buffers by evaluating fflush(0) call (-data-evaluate-expression fflush(0))') Flush Output
|
||||
span.glyphicon.glyphicon-download.padding_left
|
||||
span.glyphicon.glyphicon-plus.resizer.pointer(data-target_selector="#console" data-resize_type="enlarge")
|
||||
span.glyphicon.glyphicon-minus.resizer.pointer(data-target_selector="#console" data-resize_type="shrink")
|
||||
|
||||
//- gdb console output
|
||||
div#console.gdb_content_div(style='border-bottom: 0; border-bottom-left-radius: 0; border-bottom-right-radius: 0')
|
||||
|
@ -161,16 +166,22 @@ body
|
|||
span(style="position: absolute; left: 5px; margin-top: 9px; color: #777; font-family: monospace; font-size: 0.9em") (gdb)
|
||||
input.form-control.dropdown-input#gdb_command(type="text", autocomplete="on", data-list="#gdb_command_reference", placeholder='enter any gdb command, or gdb machine interface command')
|
||||
|
||||
div.col-md-6.no_padding
|
||||
div.titlebar
|
||||
span.lighttext gdb machine interface output
|
||||
span.glyphicon.glyphicon-plus.resizer.pointer(data-target_selector="#gdb_mi_output" data-resize_type="enlarge")
|
||||
span.glyphicon.glyphicon-minus.resizer.pointer(data-target_selector="#gdb_mi_output" data-resize_type="shrink")
|
||||
button.btn.btn-default.btn-xs.clear_mi_output(type='button', title='Clear (clears ui element, does not send a gdb command)') Clear
|
||||
span.glyphicon.glyphicon-ban-circle.padding_left
|
||||
div#gdb_mi_output.gdb_content_div
|
||||
//- Uncomment to assist when developing/debugging gdbgui
|
||||
//- div.col-md-6.no_padding
|
||||
//- div.titlebar
|
||||
//- span.lighttext gdb machine interface output
|
||||
//- span.glyphicon.glyphicon-plus.resizer.pointer(data-target_selector="#gdb_mi_output" data-resize_type="enlarge")
|
||||
//- span.glyphicon.glyphicon-minus.resizer.pointer(data-target_selector="#gdb_mi_output" data-resize_type="shrink")
|
||||
//- button.btn.btn-default.btn-xs.clear_mi_output(type='button', title='Clear (clears ui element, does not send a gdb command)') Clear
|
||||
//- span.glyphicon.glyphicon-ban-circle.padding_left
|
||||
//- div#gdb_mi_output.gdb_content_div
|
||||
|
||||
footer(style='height:200px; width:100%; margin:0; margin-top: 50px; padding:20px; background-color: #f5f5f5')
|
||||
span made by
|
||||
=' '
|
||||
a(href='https://linkedin.com/in/chadsmith27', target='_blank') Chad Smith
|
||||
=' | '
|
||||
a(href='http://grasssfedcom.com', target='_blank') grassfedcode.com
|
||||
div.row
|
||||
iframe(src="https://ghbtns.com/github-btn.html?user=cs01&repo=gdbgui&type=star&count=false", frameborder="0", scrolling="0", width="70px", height="20px")
|
||||
br
|
||||
|
|
3
setup.py
3
setup.py
|
@ -1,7 +1,6 @@
|
|||
from setuptools import find_packages, setup, Command
|
||||
import sys
|
||||
|
||||
# from distutils.core import setup,
|
||||
EXCLUDE_FROM_PACKAGES = []
|
||||
version = '0.5'
|
||||
|
||||
|
@ -45,7 +44,7 @@ setup(
|
|||
cmdclass={'test': TestCommand},
|
||||
install_requires=[
|
||||
'Flask>=0.11.1',
|
||||
'pygdbmi>=0.0.1.9',
|
||||
'pygdbmi>=0.6',
|
||||
'pyjade>=4.0.0'
|
||||
],
|
||||
classifiers=[
|
||||
|
|
Loading…
Reference in a new issue