emonti-hexwrench 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +7 -0
- data/README.rdoc +69 -0
- data/Rakefile +42 -0
- data/bin/hexwrench +14 -0
- data/hexwrench.gemspec +38 -0
- data/lib/hexwrench/build_xrc.sh +1 -0
- data/lib/hexwrench/data_inspector.rb +138 -0
- data/lib/hexwrench/edit_frame.rb +501 -0
- data/lib/hexwrench/edit_window.rb +910 -0
- data/lib/hexwrench/gui.rb +62 -0
- data/lib/hexwrench/stringsgrid.rb +72 -0
- data/lib/hexwrench/stringslist.rb +105 -0
- data/lib/hexwrench/stringsvlist.rb +123 -0
- data/lib/hexwrench/ui/gui.xrc +93 -0
- data/lib/hexwrench.rb +14 -0
- data/samples/ascii_heat_map.rb +13 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- metadata +105 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
|
2
|
+
# This class was automatically generated from XRC source. It is not
|
3
|
+
# recommended that this file is edited directly; instead, inherit from
|
4
|
+
# this class and extend its behaviour there.
|
5
|
+
#
|
6
|
+
# Source file: ui/gui.xrc
|
7
|
+
# Generated at: Sun Feb 15 15:08:37 -0600 2009
|
8
|
+
|
9
|
+
class Hexwrench::EditorFrameBase < Wx::Frame
|
10
|
+
|
11
|
+
attr_reader :top_menu_bar, :mitem_open, :mitem_new, :mitem_save,
|
12
|
+
:mitem_quit, :mitem_copy, :mitem_cut, :mitem_paste,
|
13
|
+
:mitem_select_all, :mitem_select_range,
|
14
|
+
:mitem_adv_search, :mitem_data_inspector,
|
15
|
+
:mitem_strings, :util_bar, :util_jump, :util_search,
|
16
|
+
:util_search_kind, :util_ins_chk, :status_bar
|
17
|
+
|
18
|
+
def initialize(parent = nil)
|
19
|
+
super()
|
20
|
+
xml = Wx::XmlResource.get
|
21
|
+
xml.flags = 2 # Wx::XRC_NO_SUBCLASSING
|
22
|
+
xml.init_all_handlers
|
23
|
+
xml.load(File.dirname(__FILE__) + "/ui/gui.xrc")
|
24
|
+
xml.load_frame_subclass(self, parent, "editor_frame")
|
25
|
+
|
26
|
+
finder = lambda do | x |
|
27
|
+
int_id = Wx::xrcid(x)
|
28
|
+
begin
|
29
|
+
Wx::Window.find_window_by_id(int_id, self) || int_id
|
30
|
+
# Temporary hack to work around regression in 1.9.2; remove
|
31
|
+
# begin/rescue clause in later versions
|
32
|
+
rescue RuntimeError
|
33
|
+
int_id
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
@top_menu_bar = finder.call("top_menu_bar")
|
38
|
+
@mitem_open = finder.call("mitem_open")
|
39
|
+
@mitem_new = finder.call("mitem_new")
|
40
|
+
@mitem_save = finder.call("mitem_save")
|
41
|
+
@mitem_quit = finder.call("mitem_quit")
|
42
|
+
@mitem_copy = finder.call("mitem_copy")
|
43
|
+
@mitem_cut = finder.call("mitem_cut")
|
44
|
+
@mitem_paste = finder.call("mitem_paste")
|
45
|
+
@mitem_select_all = finder.call("mitem_select_all")
|
46
|
+
@mitem_select_range = finder.call("mitem_select_range")
|
47
|
+
@mitem_adv_search = finder.call("mitem_adv_search")
|
48
|
+
@mitem_data_inspector = finder.call("mitem_data_inspector")
|
49
|
+
@mitem_strings = finder.call("mitem_strings")
|
50
|
+
@util_bar = finder.call("util_bar")
|
51
|
+
@util_jump = finder.call("util_jump")
|
52
|
+
@util_search = finder.call("util_search")
|
53
|
+
@util_search_kind = finder.call("util_search_kind")
|
54
|
+
@util_ins_chk = finder.call("util_ins_chk")
|
55
|
+
@status_bar = finder.call("status_bar")
|
56
|
+
if self.class.method_defined? "on_init"
|
57
|
+
self.on_init()
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# experimental "Wx::Grid" version of the strings window
|
2
|
+
|
3
|
+
require 'rbkb/extends'
|
4
|
+
|
5
|
+
module Hexwrench
|
6
|
+
class StringsFrame < Wx::Frame
|
7
|
+
def initialize(parent, data, strings_opts=nil)
|
8
|
+
super(parent, :title => "Strings")
|
9
|
+
@grid = Wx::Grid.new(self)
|
10
|
+
|
11
|
+
@data = data
|
12
|
+
@strings_opts =(strings_opts || {})
|
13
|
+
@strings_opts[:font] ||=
|
14
|
+
Wx::Font.new(10, Wx::MODERN, Wx::NORMAL, Wx::NORMAL)
|
15
|
+
|
16
|
+
make_grid()
|
17
|
+
end
|
18
|
+
|
19
|
+
def make_grid()
|
20
|
+
tbl = StringsTableBase.new(@data, @strings_opts)
|
21
|
+
@grid.set_table(tbl, Wx::Grid::GridSelectRows)
|
22
|
+
@grid.set_row_label_size(0)
|
23
|
+
@grid.enable_grid_lines(false)
|
24
|
+
@grid.disable_drag_row_size()
|
25
|
+
@grid.disable_drag_grid_size()
|
26
|
+
@grid.set_label_font(@strings_opts[:font])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class StringsTableBase < Wx::GridTableBase
|
31
|
+
def initialize(data, strings_opts=nil)
|
32
|
+
super()
|
33
|
+
strings_opts ||= {}
|
34
|
+
@font = strings_opts[:font]
|
35
|
+
@font ||= Wx::Font.new(10, Wx::MODERN, Wx::NORMAL, Wx::NORMAL)
|
36
|
+
@cell_attr = Wx::GridCellAttr.new( Wx::BLACK, Wx::WHITE, @font,
|
37
|
+
Wx::ALIGN_LEFT, Wx::ALIGN_CENTRE)
|
38
|
+
@cell_attr.set_read_only(true)
|
39
|
+
@strings = data.strings(strings_opts)
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_number_cols
|
43
|
+
4
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_number_rows
|
47
|
+
@strings.size
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_col_label_value(col)
|
51
|
+
["start", "end", "kind", "string"][col]
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_row_label_value(row)
|
55
|
+
""
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_value(row, col)
|
59
|
+
val=@strings[row][col].to_s
|
60
|
+
return (col > 2)? val.inspect : val
|
61
|
+
end
|
62
|
+
|
63
|
+
def is_empty_cell(row, col)
|
64
|
+
(r=@strings[row]).nil? or r[col].nil?
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_attr(*args)
|
68
|
+
@cell_attr.clone
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
### DEPRECATED by stringsvlist.rb
|
2
|
+
|
3
|
+
require 'rbkb/extends'
|
4
|
+
|
5
|
+
module Hexwrench
|
6
|
+
class StringsFrame < Wx::Frame
|
7
|
+
attr_reader :strings_list
|
8
|
+
def initialize(parent, editor, strings_opts=nil)
|
9
|
+
unless @editor = editor
|
10
|
+
Kernel.raise "#{self.class}.new() requires an editor window parameter"
|
11
|
+
end
|
12
|
+
|
13
|
+
super(parent, :title => "Strings")
|
14
|
+
|
15
|
+
@strings_list = StringsList.new(self, @editor, strings_opts)
|
16
|
+
@strings_list.evt_window_destroy do |evt|
|
17
|
+
self.destroy() rescue (ObjectPreviouslyDeleted)
|
18
|
+
evt.skip(true)
|
19
|
+
end
|
20
|
+
|
21
|
+
evt_list_item_selected(@strings_list) do |evt|
|
22
|
+
s_off, e_off, kind, str = evt.item.data
|
23
|
+
if @editor.select_range(s_off..e_off-1)
|
24
|
+
@editor.set_area_ascii
|
25
|
+
@editor.scroll_to_idx(s_off)
|
26
|
+
@editor.refresh
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
# Fire our strings operation only on switching (via activation)
|
32
|
+
# we do this because strings is a costly operation
|
33
|
+
evt_activate do |evt|
|
34
|
+
if @data_changed
|
35
|
+
@data_changed=false
|
36
|
+
@strings_list.do_strings
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def notify_data_change
|
42
|
+
@data_changed=true
|
43
|
+
end
|
44
|
+
|
45
|
+
def do_strings
|
46
|
+
@strings_list.do_strings
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class StringsList < Wx::ListCtrl
|
51
|
+
attr_reader :strings_opts
|
52
|
+
|
53
|
+
def initialize(parent, editor, strings_opts=nil)
|
54
|
+
unless @editor = editor
|
55
|
+
Kernel.raise "#{self.class}.new() requires an editor window parameter"
|
56
|
+
end
|
57
|
+
|
58
|
+
super(parent, :style => Wx::LC_REPORT|Wx::LC_SINGLE_SEL|Wx::LC_HRULES|Wx::LC_VRULES)
|
59
|
+
insert_column(0, "start")
|
60
|
+
insert_column(1, "len")
|
61
|
+
insert_column(2, "kind")
|
62
|
+
insert_column(3, "string")
|
63
|
+
|
64
|
+
@strings_opts = (strings_opts || {})
|
65
|
+
@strings_opts[:encoding] ||= :both
|
66
|
+
|
67
|
+
@font = Wx::Font.new(10, Wx::MODERN, Wx::NORMAL, Wx::NORMAL)
|
68
|
+
set_font(@font)
|
69
|
+
end
|
70
|
+
|
71
|
+
GAUGE_STYLE = Wx::PD_CAN_ABORT |
|
72
|
+
Wx::PD_REMAINING_TIME |
|
73
|
+
Wx::PD_ESTIMATED_TIME |
|
74
|
+
Wx::PD_ELAPSED_TIME
|
75
|
+
|
76
|
+
def do_strings
|
77
|
+
gauge =
|
78
|
+
Wx::ProgressDialog.new("", "Generating Strings",
|
79
|
+
@editor.data.size, self, GAUGE_STYLE)
|
80
|
+
|
81
|
+
self.hide
|
82
|
+
delete_all_items
|
83
|
+
i=0
|
84
|
+
@editor.data.strings(@strings_opts) do |startoff, endoff, stype, str|
|
85
|
+
unless gauge.update(endoff)
|
86
|
+
# the "abort" button was pressed
|
87
|
+
destroy
|
88
|
+
return nil
|
89
|
+
end
|
90
|
+
d_str = ((stype == :unicode)? str.gsub(/(.)\x00/){$1} : str).inspect
|
91
|
+
insert_item(i, startoff.to_s)
|
92
|
+
set_item i, 1, (endoff-startoff).to_s
|
93
|
+
set_item i, 2, stype.to_s
|
94
|
+
set_item i, 3, d_str
|
95
|
+
set_item_data(i, [startoff, endoff, stype])
|
96
|
+
i+=1
|
97
|
+
end
|
98
|
+
|
99
|
+
0.upto(3) {|c| set_column_width c, Wx::LIST_AUTOSIZE } if i > 0
|
100
|
+
self.show
|
101
|
+
gauge.destroy()
|
102
|
+
return i
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
|
2
|
+
require 'rbkb/extends.rb'
|
3
|
+
|
4
|
+
module Hexwrench
|
5
|
+
class StringsFrame < Wx::Frame
|
6
|
+
attr_reader :strings_list
|
7
|
+
|
8
|
+
def initialize(parent, editor, strings_opts=nil)
|
9
|
+
unless @editor = editor
|
10
|
+
Kernel.raise "#{self.class}.new() requires an editor window parameter"
|
11
|
+
end
|
12
|
+
|
13
|
+
@strings_opts = (strings_opts || {})
|
14
|
+
@strings_opts[:min] ||= 5
|
15
|
+
|
16
|
+
super(parent, :title => "Strings")
|
17
|
+
|
18
|
+
# Fire our strings operation only on switching windows (via activation)
|
19
|
+
# we do this because finding strings (to a lesser extent) and
|
20
|
+
# populating the window (to a larger extent) may be a costly operation
|
21
|
+
evt_idle do |evt|
|
22
|
+
if @data_changed and active?
|
23
|
+
@data_changed=false
|
24
|
+
do_strings
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
do_strings
|
29
|
+
end
|
30
|
+
|
31
|
+
def notify_data_change
|
32
|
+
@data_changed=true
|
33
|
+
end
|
34
|
+
|
35
|
+
def do_strings
|
36
|
+
if @strings_list.nil?
|
37
|
+
@strings_list = StringsList.new(self, @editor) unless @strings_list
|
38
|
+
|
39
|
+
evt_list_item_selected(@strings_list) do |evt|
|
40
|
+
s_off, e_off, kind, str = @strings_list.strings[evt.get_index]
|
41
|
+
if @editor.select_range(s_off..e_off-1)
|
42
|
+
@editor.set_area_ascii
|
43
|
+
@editor.scroll_to_idx(s_off)
|
44
|
+
@editor.refresh
|
45
|
+
end
|
46
|
+
end
|
47
|
+
else
|
48
|
+
@strings_list.refresh_strings()
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class StringsList < Wx::ListCtrl
|
54
|
+
attr_accessor :strings_opts, :strings, :editor
|
55
|
+
|
56
|
+
def initialize(parent, editor, strings_opts=nil)
|
57
|
+
@strings_opts ||= {}
|
58
|
+
@editor = editor
|
59
|
+
|
60
|
+
super(parent, :style => Wx::LC_REPORT|Wx::LC_SINGLE_SEL|Wx::LC_HRULES|Wx::LC_VRULES|Wx::LC_VIRTUAL)
|
61
|
+
|
62
|
+
@font = Wx::Font.new(10, Wx::MODERN, Wx::NORMAL, Wx::NORMAL)
|
63
|
+
set_font(@font)
|
64
|
+
|
65
|
+
@dc = Wx::WindowDC.new(self)
|
66
|
+
@labels = ["start idx", "end idx", "kind", "string"]
|
67
|
+
@labels.each_index {|i| insert_column(i, @labels[i]) }
|
68
|
+
|
69
|
+
refresh_strings()
|
70
|
+
|
71
|
+
@attr = Wx::ListItemAttr.new
|
72
|
+
@attr.set_background_colour(Wx::WHITE)
|
73
|
+
end
|
74
|
+
|
75
|
+
def refresh_strings()
|
76
|
+
@strings = []
|
77
|
+
colwids = @labels.map {|l| @dc.get_text_extent("@@#{l}@@", @font)[0]}
|
78
|
+
@editor.data.strings(@strings_opts) do |*mtch|
|
79
|
+
@strings << mtch[0..2]
|
80
|
+
|
81
|
+
# calculate column widths during loop so we don't have to autosize
|
82
|
+
# later. (autosize can be slow on large lists)
|
83
|
+
0.upto(2) do |i|
|
84
|
+
owid = colwids[i]
|
85
|
+
nwid = @dc.get_text_extent("@#{mtch[i]}@", @font)[0]
|
86
|
+
colwids[i] = nwid if nwid > owid
|
87
|
+
end
|
88
|
+
swid=colwids[3]
|
89
|
+
nswid=@dc.get_text_extent("@#{get_string(mtch)}@", @font)[0]
|
90
|
+
colwids[3] = nswid if nswid > swid
|
91
|
+
end
|
92
|
+
colwids.each_index {|i| set_column_width(i, colwids[i])}
|
93
|
+
set_item_count(@strings.size)
|
94
|
+
end
|
95
|
+
|
96
|
+
def get_string(match)
|
97
|
+
dat = @editor.data[(match[0]..match[1]-1)]
|
98
|
+
if match[2] == :unicode
|
99
|
+
dat.gsub(/(.)\x00/){$1}
|
100
|
+
else
|
101
|
+
dat
|
102
|
+
end.inspect
|
103
|
+
end
|
104
|
+
|
105
|
+
def create_strings(data)
|
106
|
+
end
|
107
|
+
|
108
|
+
def on_get_item_text(row, col)
|
109
|
+
if r = @strings[row]
|
110
|
+
if col == 3
|
111
|
+
get_string(r)
|
112
|
+
else
|
113
|
+
r[col].to_s
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def on_get_item_attr(item)
|
119
|
+
@attr
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
@@ -0,0 +1,93 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<resource version="2.3.0.1" xmlns="http://www.wxwidgets.org/wxxrc">
|
3
|
+
<object class="wxFrame" name="editor_frame" subclass="EditorFrameBase">
|
4
|
+
<style>wxCAPTION|wxRESIZE_BORDER|wxSYSTEM_MENU|wxMINIMIZE_BOX|wxMAXIMIZE_BOX|wxCLOSE_BOX</style>
|
5
|
+
<size>400,300</size>
|
6
|
+
<title>Hexwrench</title>
|
7
|
+
<object class="wxMenuBar" name="top_menu_bar">
|
8
|
+
<object class="wxMenu">
|
9
|
+
<label>&File</label>
|
10
|
+
<object class="wxMenuItem" name="mitem_open">
|
11
|
+
<label>Open</label>
|
12
|
+
</object>
|
13
|
+
<object class="wxMenuItem" name="mitem_new">
|
14
|
+
<label>New</label>
|
15
|
+
</object>
|
16
|
+
<object class="wxMenuItem" name="mitem_save">
|
17
|
+
<label>Save</label>
|
18
|
+
</object>
|
19
|
+
<object class="wxMenuItem" name="mitem_quit">
|
20
|
+
<label>Quit</label>
|
21
|
+
</object>
|
22
|
+
</object>
|
23
|
+
<object class="wxMenu">
|
24
|
+
<label>&Edit</label>
|
25
|
+
<object class="wxMenuItem" name="mitem_copy">
|
26
|
+
<label>Copy</label>
|
27
|
+
</object>
|
28
|
+
<object class="wxMenuItem" name="mitem_cut">
|
29
|
+
<label>Cut</label>
|
30
|
+
</object>
|
31
|
+
<object class="wxMenuItem" name="mitem_paste">
|
32
|
+
<label>Paste</label>
|
33
|
+
</object>
|
34
|
+
<object class="wxMenuItem" name="mitem_select_all">
|
35
|
+
<label>Select All</label>
|
36
|
+
</object>
|
37
|
+
<object class="wxMenuItem" name="mitem_select_range">
|
38
|
+
<label>Select Range</label>
|
39
|
+
</object>
|
40
|
+
<object class="separator">
|
41
|
+
</object>
|
42
|
+
<object class="wxMenuItem" name="mitem_adv_search">
|
43
|
+
<label>Advanced Search</label>
|
44
|
+
</object>
|
45
|
+
</object>
|
46
|
+
<object class="wxMenu">
|
47
|
+
<label>&Tools</label>
|
48
|
+
<object class="wxMenuItem" name="mitem_data_inspector">
|
49
|
+
<label>Data Inspector</label>
|
50
|
+
</object>
|
51
|
+
<object class="wxMenuItem" name="mitem_strings">
|
52
|
+
<label>Strings</label>
|
53
|
+
</object>
|
54
|
+
</object>
|
55
|
+
</object>
|
56
|
+
<object class="wxToolBar" name="util_bar">
|
57
|
+
<style>wxTB_FLAT|wxTB_HORIZONTAL</style>
|
58
|
+
<object class="wxTextCtrl" name="util_jump">
|
59
|
+
<style>wxTE_PROCESS_ENTER</style>
|
60
|
+
<value>jump to addr.</value>
|
61
|
+
</object>
|
62
|
+
<object class="separator">
|
63
|
+
</object>
|
64
|
+
<object class="wxTextCtrl" name="util_search">
|
65
|
+
<style>wxTE_PROCESS_ENTER</style>
|
66
|
+
<value>search</value>
|
67
|
+
</object>
|
68
|
+
<object class="wxChoice" name="util_search_kind">
|
69
|
+
<size>70,-1</size>
|
70
|
+
<font>
|
71
|
+
<size>10</size>
|
72
|
+
<family>modern</family>
|
73
|
+
</font>
|
74
|
+
<content>
|
75
|
+
<item>ASCII</item>
|
76
|
+
<item>Hex</item>
|
77
|
+
</content>
|
78
|
+
<selection>0</selection>
|
79
|
+
</object>
|
80
|
+
<object class="separator">
|
81
|
+
</object>
|
82
|
+
<object class="wxCheckBox" name="util_ins_chk">
|
83
|
+
<label>INS</label>
|
84
|
+
<checked>1</checked>
|
85
|
+
</object>
|
86
|
+
</object>
|
87
|
+
<object class="wxStatusBar" name="status_bar">
|
88
|
+
<style>wxST_SIZEGRIP|wxNO_BORDER</style>
|
89
|
+
<fields>2</fields>
|
90
|
+
<widths></widths>
|
91
|
+
</object>
|
92
|
+
</object>
|
93
|
+
</resource>
|
data/lib/hexwrench.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
begin
|
2
|
+
require 'rubygems'
|
3
|
+
rescue LoadError
|
4
|
+
end
|
5
|
+
|
6
|
+
module Hexwrench
|
7
|
+
VERSION = "0.2.0"
|
8
|
+
end
|
9
|
+
require 'wx'
|
10
|
+
require 'hexwrench/edit_window'
|
11
|
+
require 'hexwrench/gui.rb' # gui.rb provides EditFrame's layout from XRC
|
12
|
+
require 'hexwrench/edit_frame'
|
13
|
+
require 'hexwrench/data_inspector'
|
14
|
+
require 'hexwrench/stringsvlist'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# a byte-value heat colorizer based on colorbindump
|
2
|
+
|
3
|
+
raw_palette = [[0x30, 0x30, 0x30] ] +
|
4
|
+
(1..31).map {|x| [96,96,96]} +
|
5
|
+
(32..127).map {|x| [128,196,128]} +
|
6
|
+
(128..255).map {|x| [96,96,96]}
|
7
|
+
|
8
|
+
@palette = raw_palette.map {|p| Wx::Brush.new(Wx::Colour.new(*p[0..2]))}
|
9
|
+
editor.post_paint_proc = lambda {|this,dc,idx,c,hX,aX,y|
|
10
|
+
brush = [@palette[c], Wx::TRANSPARENT_BRUSH]
|
11
|
+
this.colorize_byte_bg(brush, dc, hX,aX,y)
|
12
|
+
}
|
13
|
+
editor.refresh
|
data/tasks/ann.rake
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
begin
|
3
|
+
require 'bones/smtp_tls'
|
4
|
+
rescue LoadError
|
5
|
+
require 'net/smtp'
|
6
|
+
end
|
7
|
+
require 'time'
|
8
|
+
|
9
|
+
namespace :ann do
|
10
|
+
|
11
|
+
# A prerequisites task that all other tasks depend upon
|
12
|
+
task :prereqs
|
13
|
+
|
14
|
+
file PROJ.ann.file do
|
15
|
+
ann = PROJ.ann
|
16
|
+
puts "Generating #{ann.file}"
|
17
|
+
File.open(ann.file,'w') do |fd|
|
18
|
+
fd.puts("#{PROJ.name} version #{PROJ.version}")
|
19
|
+
fd.puts(" by #{Array(PROJ.authors).first}") if PROJ.authors
|
20
|
+
fd.puts(" #{PROJ.url}") if PROJ.url.valid?
|
21
|
+
fd.puts(" (the \"#{PROJ.release_name}\" release)") if PROJ.release_name
|
22
|
+
fd.puts
|
23
|
+
fd.puts("== DESCRIPTION")
|
24
|
+
fd.puts
|
25
|
+
fd.puts(PROJ.description)
|
26
|
+
fd.puts
|
27
|
+
fd.puts(PROJ.changes.sub(%r/^.*$/, '== CHANGES'))
|
28
|
+
fd.puts
|
29
|
+
ann.paragraphs.each do |p|
|
30
|
+
fd.puts "== #{p.upcase}"
|
31
|
+
fd.puts
|
32
|
+
fd.puts paragraphs_of(PROJ.readme_file, p).join("\n\n")
|
33
|
+
fd.puts
|
34
|
+
end
|
35
|
+
fd.puts ann.text if ann.text
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "Create an announcement file"
|
40
|
+
task :announcement => ['ann:prereqs', PROJ.ann.file]
|
41
|
+
|
42
|
+
desc "Send an email announcement"
|
43
|
+
task :email => ['ann:prereqs', PROJ.ann.file] do
|
44
|
+
ann = PROJ.ann
|
45
|
+
from = ann.email[:from] || Array(PROJ.authors).first || PROJ.email
|
46
|
+
to = Array(ann.email[:to])
|
47
|
+
|
48
|
+
### build a mail header for RFC 822
|
49
|
+
rfc822msg = "From: #{from}\n"
|
50
|
+
rfc822msg << "To: #{to.join(',')}\n"
|
51
|
+
rfc822msg << "Subject: [ANN] #{PROJ.name} #{PROJ.version}"
|
52
|
+
rfc822msg << " (#{PROJ.release_name})" if PROJ.release_name
|
53
|
+
rfc822msg << "\n"
|
54
|
+
rfc822msg << "Date: #{Time.new.rfc822}\n"
|
55
|
+
rfc822msg << "Message-Id: "
|
56
|
+
rfc822msg << "<#{"%.8f" % Time.now.to_f}@#{ann.email[:domain]}>\n\n"
|
57
|
+
rfc822msg << File.read(ann.file)
|
58
|
+
|
59
|
+
params = [:server, :port, :domain, :acct, :passwd, :authtype].map do |key|
|
60
|
+
ann.email[key]
|
61
|
+
end
|
62
|
+
|
63
|
+
params[3] = PROJ.email if params[3].nil?
|
64
|
+
|
65
|
+
if params[4].nil?
|
66
|
+
STDOUT.write "Please enter your e-mail password (#{params[3]}): "
|
67
|
+
params[4] = STDIN.gets.chomp
|
68
|
+
end
|
69
|
+
|
70
|
+
### send email
|
71
|
+
Net::SMTP.start(*params) {|smtp| smtp.sendmail(rfc822msg, from, to)}
|
72
|
+
end
|
73
|
+
end # namespace :ann
|
74
|
+
|
75
|
+
desc 'Alias to ann:announcement'
|
76
|
+
task :ann => 'ann:announcement'
|
77
|
+
|
78
|
+
CLOBBER << PROJ.ann.file
|
79
|
+
|
80
|
+
# EOF
|
data/tasks/bones.rake
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
if HAVE_BONES
|
3
|
+
|
4
|
+
namespace :bones do
|
5
|
+
|
6
|
+
desc 'Show the PROJ open struct'
|
7
|
+
task :debug do |t|
|
8
|
+
atr = if t.application.top_level_tasks.length == 2
|
9
|
+
t.application.top_level_tasks.pop
|
10
|
+
end
|
11
|
+
|
12
|
+
if atr then Bones::Debug.show_attr(PROJ, atr)
|
13
|
+
else Bones::Debug.show PROJ end
|
14
|
+
end
|
15
|
+
|
16
|
+
end # namespace :bones
|
17
|
+
|
18
|
+
end # HAVE_BONES
|
19
|
+
|
20
|
+
# EOF
|