ghi 0.9.0.dev → 0.9.0.dev1
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/lib/ghi.rb +1 -0
- data/lib/ghi/authorization.rb +1 -1
- data/lib/ghi/client.rb +2 -3
- data/lib/ghi/commands/close.rb +6 -5
- data/lib/ghi/commands/command.rb +0 -15
- data/lib/ghi/commands/comment.rb +15 -13
- data/lib/ghi/commands/edit.rb +22 -1
- data/lib/ghi/commands/label.rb +11 -3
- data/lib/ghi/commands/list.rb +10 -5
- data/lib/ghi/commands/milestone.rb +2 -3
- data/lib/ghi/commands/open.rb +13 -8
- data/lib/ghi/commands/show.rb +10 -4
- data/lib/ghi/commands/version.rb +1 -1
- data/lib/ghi/editor.rb +26 -0
- data/lib/ghi/formatting.rb +100 -32
- metadata +5 -3
data/lib/ghi.rb
CHANGED
data/lib/ghi/authorization.rb
CHANGED
data/lib/ghi/client.rb
CHANGED
@@ -2,9 +2,8 @@ require 'cgi'
|
|
2
2
|
require 'net/https'
|
3
3
|
|
4
4
|
unless defined? Net::HTTP::Patch
|
5
|
-
|
6
|
-
|
7
|
-
end
|
5
|
+
# PATCH support for 1.8.7.
|
6
|
+
Net::HTTP::Patch = Class.new(Net::HTTP::Post) { METHOD = 'PATCH' }
|
8
7
|
end
|
9
8
|
|
10
9
|
module GHI
|
data/lib/ghi/commands/close.rb
CHANGED
@@ -12,7 +12,7 @@ EOF
|
|
12
12
|
end
|
13
13
|
opts.separator ''
|
14
14
|
opts.separator 'Issue modification options'
|
15
|
-
opts.on '-m', '--message <text>', 'close with message' do |text|
|
15
|
+
opts.on '-m', '--message [<text>]', 'close with message' do |text|
|
16
16
|
assigns[:comment] = text
|
17
17
|
end
|
18
18
|
opts.separator ''
|
@@ -27,11 +27,12 @@ EOF
|
|
27
27
|
List.execute %W(-sc -- #{repo})
|
28
28
|
else
|
29
29
|
require_issue
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
if assigns.key? :comment
|
31
|
+
Comment.execute [
|
32
|
+
issue, '-m', assigns[:comment], '--', repo
|
33
|
+
].compact
|
34
34
|
end
|
35
|
+
Edit.execute %W(-sc #{issue} -- #{repo})
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
data/lib/ghi/commands/command.rb
CHANGED
@@ -94,21 +94,6 @@ module GHI
|
|
94
94
|
def any_or_none_or input
|
95
95
|
input ? input : { nil => '*', false => 'none' }[input]
|
96
96
|
end
|
97
|
-
|
98
|
-
def page? message = 'Load more?'
|
99
|
-
return unless STDIN.tty?
|
100
|
-
|
101
|
-
STDOUT.print "#{message} [Yn] "
|
102
|
-
begin
|
103
|
-
system 'stty raw -echo'
|
104
|
-
# Continue on y, j, <ENTER>, <DOWN>...
|
105
|
-
exit unless [?y, ?Y, ?j, 13, 27].include? STDIN.getc
|
106
|
-
STDOUT.print "\r" + ' ' * columns
|
107
|
-
STDOUT.print "\r Loading..."
|
108
|
-
ensure
|
109
|
-
system 'stty -raw echo'
|
110
|
-
end
|
111
|
-
end
|
112
97
|
end
|
113
98
|
end
|
114
99
|
end
|
data/lib/ghi/commands/comment.rb
CHANGED
@@ -15,7 +15,7 @@ EOF
|
|
15
15
|
# opts.on '-v', '--verbose', 'list events, too'
|
16
16
|
opts.separator ''
|
17
17
|
opts.separator 'Comment modification options'
|
18
|
-
opts.on '-m', '--message <text>', 'comment body' do |text|
|
18
|
+
opts.on '-m', '--message [<text>]', 'comment body' do |text|
|
19
19
|
assigns[:body] = text
|
20
20
|
end
|
21
21
|
opts.on '--amend', 'amend previous comment' do
|
@@ -40,10 +40,9 @@ EOF
|
|
40
40
|
case action
|
41
41
|
when 'list'
|
42
42
|
res = index
|
43
|
-
|
43
|
+
page do
|
44
44
|
puts format_comments(res.body)
|
45
45
|
break unless res.next_page
|
46
|
-
page?
|
47
46
|
res = throb { api.get res.next_page }
|
48
47
|
end
|
49
48
|
when 'create'
|
@@ -60,7 +59,7 @@ EOF
|
|
60
59
|
abort 'No recent comment found.'
|
61
60
|
end
|
62
61
|
when 'close'
|
63
|
-
Close.execute
|
62
|
+
Close.execute [issue, '-m', assigns[:body], '--', repo].compact
|
64
63
|
end
|
65
64
|
end
|
66
65
|
|
@@ -72,19 +71,21 @@ EOF
|
|
72
71
|
|
73
72
|
def create
|
74
73
|
require_body
|
75
|
-
throb { api.post uri, assigns }
|
76
|
-
puts
|
74
|
+
c = throb { api.post uri, assigns }.body
|
75
|
+
puts format_comment c
|
76
|
+
puts 'Commented.'
|
77
77
|
end
|
78
78
|
|
79
79
|
def update
|
80
80
|
require_body
|
81
|
-
throb { api.patch uri, assigns }
|
82
|
-
puts
|
81
|
+
c = throb { api.patch uri, assigns }.body
|
82
|
+
puts format_comment c
|
83
|
+
puts 'Updated.'
|
83
84
|
end
|
84
85
|
|
85
86
|
def destroy
|
86
87
|
throb { api.delete uri }
|
87
|
-
puts '
|
88
|
+
puts 'Deleted.'
|
88
89
|
end
|
89
90
|
|
90
91
|
private
|
@@ -94,10 +95,11 @@ EOF
|
|
94
95
|
end
|
95
96
|
|
96
97
|
def require_body
|
97
|
-
if assigns[:body]
|
98
|
-
|
99
|
-
|
100
|
-
|
98
|
+
return if assigns[:body]
|
99
|
+
message = Editor.gets format_comment_editor(issue, comment)
|
100
|
+
abort 'No comment.' if message.nil? || message.empty?
|
101
|
+
abort 'No change.' if comment && message.strip == comment['body'].strip
|
102
|
+
assigns[:body] = message if message
|
101
103
|
end
|
102
104
|
end
|
103
105
|
end
|
data/lib/ghi/commands/edit.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module GHI
|
2
2
|
module Commands
|
3
3
|
class Edit < Command
|
4
|
+
attr_accessor :edit
|
5
|
+
|
4
6
|
def options
|
5
7
|
OptionParser.new do |opts|
|
6
8
|
opts.banner = <<EOF
|
@@ -8,8 +10,9 @@ usage: ghi edit [options] <issueno>
|
|
8
10
|
EOF
|
9
11
|
opts.separator ''
|
10
12
|
opts.on(
|
11
|
-
'-m', '--message <text>', 'change issue description'
|
13
|
+
'-m', '--message [<text>]', 'change issue description'
|
12
14
|
) do |text|
|
15
|
+
next self.edit = true if text.nil?
|
13
16
|
assigns[:title], assigns[:body] = text.split(/\n+/, 2)
|
14
17
|
end
|
15
18
|
opts.on(
|
@@ -41,8 +44,26 @@ EOF
|
|
41
44
|
require_issue
|
42
45
|
require_repo
|
43
46
|
options.parse! args
|
47
|
+
if edit || assigns.empty?
|
48
|
+
i = throb { api.get "/repos/#{repo}/issues/#{issue}" }.body
|
49
|
+
message = Editor.gets format_editor(i)
|
50
|
+
abort "There's no issue." if message.nil? || message.empty?
|
51
|
+
assigns[:title], assigns[:body] = message.split(/\n+/, 2)
|
52
|
+
end
|
53
|
+
if assigns[:title]
|
54
|
+
titles_match = assigns[:title].strip == i['title'].strip
|
55
|
+
if assigns[:body]
|
56
|
+
bodies_match = assigns[:body].to_s.strip == i['body'].to_s.strip
|
57
|
+
end
|
58
|
+
end
|
59
|
+
if titles_match && bodies_match
|
60
|
+
abort 'No change.' if assigns.dup.delete_if { |k, v|
|
61
|
+
[:title, :body].include? k
|
62
|
+
}
|
63
|
+
end
|
44
64
|
i = throb { api.patch "/repos/#{repo}/issues/#{issue}", assigns }.body
|
45
65
|
puts format_issue(i)
|
66
|
+
puts 'Updated.'
|
46
67
|
end
|
47
68
|
end
|
48
69
|
end
|
data/lib/ghi/commands/label.rb
CHANGED
@@ -61,6 +61,7 @@ EOF
|
|
61
61
|
if issue
|
62
62
|
self.action ||= 'add'
|
63
63
|
self.name = args.shift.to_s.split ','
|
64
|
+
self.name.concat args
|
64
65
|
else
|
65
66
|
self.action ||= 'create'
|
66
67
|
self.name ||= args.shift
|
@@ -117,7 +118,6 @@ EOF
|
|
117
118
|
labels = throb {
|
118
119
|
api.post "/repos/#{repo}/issues/#{issue}/labels", name
|
119
120
|
}.body
|
120
|
-
labels.delete_if { |l| !name.include?(l['name']) }
|
121
121
|
puts "Issue #%d labeled %s." % [issue, format_labels(labels)]
|
122
122
|
end
|
123
123
|
|
@@ -128,7 +128,11 @@ EOF
|
|
128
128
|
puts "Labels removed."
|
129
129
|
when 1
|
130
130
|
labels = throb { api.delete "#{base_uri}/#{name.join}" }.body
|
131
|
-
|
131
|
+
if labels.empty?
|
132
|
+
puts "Issue #%d unlabeled." % issue
|
133
|
+
else
|
134
|
+
puts "Issue #%d labeled %s." % [issue, format_labels(labels)]
|
135
|
+
end
|
132
136
|
else
|
133
137
|
labels = throb {
|
134
138
|
api.get "/repos/#{repo}/issues/#{issue}/labels"
|
@@ -140,7 +144,11 @@ EOF
|
|
140
144
|
|
141
145
|
def replace
|
142
146
|
labels = throb { api.put base_uri, name }.body
|
143
|
-
|
147
|
+
if labels.empty?
|
148
|
+
puts "Issue #%d unlabeled." % issue
|
149
|
+
else
|
150
|
+
puts "Issue #%d labeled %s." % [issue, format_labels(labels)]
|
151
|
+
end
|
144
152
|
end
|
145
153
|
|
146
154
|
private
|
data/lib/ghi/commands/list.rb
CHANGED
@@ -90,20 +90,18 @@ module GHI
|
|
90
90
|
fallback.parse! e.args
|
91
91
|
retry
|
92
92
|
end
|
93
|
-
|
94
93
|
if reverse
|
95
94
|
assigns[:sort] ||= 'created'
|
96
95
|
assigns[:direction] = 'asc'
|
97
96
|
end
|
98
|
-
|
99
97
|
unless quiet
|
100
|
-
print format_issues_header
|
98
|
+
print header = format_issues_header
|
101
99
|
print "\n" unless STDOUT.tty?
|
102
100
|
end
|
103
101
|
res = throb(
|
104
102
|
0, format_state(assigns[:state], quiet ? CURSOR[:up][1] : '#')
|
105
103
|
) { api.get uri, assigns }
|
106
|
-
|
104
|
+
page header && "\r#{CURSOR[:up][1]}#{header}" do
|
107
105
|
issues = res.body
|
108
106
|
if verbose
|
109
107
|
puts issues.map { |i| format_issue i }
|
@@ -111,9 +109,16 @@ module GHI
|
|
111
109
|
puts format_issues(issues, repo.nil?)
|
112
110
|
end
|
113
111
|
break unless res.next_page
|
114
|
-
page?
|
115
112
|
res = throb { api.get res.next_page }
|
116
113
|
end
|
114
|
+
rescue Client::Error => e
|
115
|
+
if e.response.code == '422'
|
116
|
+
e.errors.any? { |err|
|
117
|
+
err['code'] == 'missing' && err['field'] == 'milestone'
|
118
|
+
} and abort 'No such milestone.'
|
119
|
+
end
|
120
|
+
|
121
|
+
raise
|
117
122
|
end
|
118
123
|
|
119
124
|
private
|
@@ -99,8 +99,8 @@ EOF
|
|
99
99
|
state = assigns[:state] || 'open'
|
100
100
|
print format_state state, "# #{repo} #{state} milestones"
|
101
101
|
print "\n" unless STDOUT.tty?
|
102
|
-
res = throb(0, format_state(state, '#')) { api.get uri }
|
103
|
-
|
102
|
+
res = throb(0, format_state(state, '#')) { api.get uri, assigns }
|
103
|
+
page do
|
104
104
|
milestones = res.body
|
105
105
|
if verbose
|
106
106
|
puts milestones.map { |m| format_milestone m }
|
@@ -108,7 +108,6 @@ EOF
|
|
108
108
|
puts format_milestones(milestones)
|
109
109
|
end
|
110
110
|
break unless res.next_page
|
111
|
-
page?
|
112
111
|
res = throb { api.get res.next_page }
|
113
112
|
end
|
114
113
|
when 'show'
|
data/lib/ghi/commands/open.rb
CHANGED
@@ -18,11 +18,11 @@ EOF
|
|
18
18
|
end
|
19
19
|
opts.separator ''
|
20
20
|
opts.separator 'Issue modification options'
|
21
|
-
opts.on '-m', '--message <text>', 'describe issue' do |text|
|
21
|
+
opts.on '-m', '--message [<text>]', 'describe issue' do |text|
|
22
22
|
assigns[:title], assigns[:body] = text.split(/\n+/, 2)
|
23
23
|
end
|
24
24
|
opts.on(
|
25
|
-
'-u', '--[no-]assign <user>', 'assign to specified user'
|
25
|
+
'-u', '--[no-]assign [<user>]', 'assign to specified user'
|
26
26
|
) do |assignee|
|
27
27
|
assigns[:assignee] = assignee
|
28
28
|
end
|
@@ -41,11 +41,11 @@ EOF
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def execute
|
44
|
+
require_repo
|
44
45
|
self.action = 'create'
|
45
46
|
|
46
47
|
if extract_issue
|
47
|
-
Edit.
|
48
|
-
puts 'Reopened.'
|
48
|
+
Edit.execute args.push('-so', issue, '--', repo)
|
49
49
|
exit
|
50
50
|
end
|
51
51
|
|
@@ -53,11 +53,16 @@ EOF
|
|
53
53
|
|
54
54
|
case action
|
55
55
|
when 'index'
|
56
|
-
|
56
|
+
if assigns.key? :assignee
|
57
|
+
args.unshift assigns[:assignee] if assigns[:assignee]
|
58
|
+
args.unshift '-u'
|
59
|
+
end
|
60
|
+
List.execute args.push('--', repo)
|
57
61
|
when 'create'
|
58
|
-
if assigns[:title].nil?
|
59
|
-
|
60
|
-
abort
|
62
|
+
if assigns[:title].nil?
|
63
|
+
message = Editor.gets format_editor
|
64
|
+
abort "There's no issue." if message.nil? || message.empty?
|
65
|
+
assigns[:title], assigns[:body] = message.split(/\n+/, 2)
|
61
66
|
end
|
62
67
|
i = throb { api.post "/repos/#{repo}/issues", assigns }.body
|
63
68
|
puts format_issue(i)
|
data/lib/ghi/commands/show.rb
CHANGED
@@ -3,7 +3,7 @@ module GHI
|
|
3
3
|
class Show < Command
|
4
4
|
def options
|
5
5
|
OptionParser.new do |opts|
|
6
|
-
opts.banner = 'usage: ghi show <issueno>
|
6
|
+
opts.banner = 'usage: ghi show <issueno>'
|
7
7
|
opts.separator ''
|
8
8
|
end
|
9
9
|
end
|
@@ -12,9 +12,15 @@ module GHI
|
|
12
12
|
require_issue
|
13
13
|
require_repo
|
14
14
|
i = throb { api.get "/repos/#{repo}/issues/#{issue}" }.body
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
page do
|
16
|
+
puts format_issue(i)
|
17
|
+
n = i['comments']
|
18
|
+
if n > 0
|
19
|
+
puts "#{n} Comment#{'s' unless n == 1}:\n\n"
|
20
|
+
Comment.execute %W(-l #{issue} -- #{repo})
|
21
|
+
end
|
22
|
+
break
|
23
|
+
end
|
18
24
|
end
|
19
25
|
end
|
20
26
|
end
|
data/lib/ghi/commands/version.rb
CHANGED
data/lib/ghi/editor.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module GHI
|
4
|
+
class Editor
|
5
|
+
class << self
|
6
|
+
def gets prefill
|
7
|
+
Tempfile.open 'GHI_ISSUE' do |f|
|
8
|
+
f << prefill
|
9
|
+
f.rewind
|
10
|
+
system "#{editor} #{f.path}"
|
11
|
+
return File.read(f.path).gsub(/^#.*$\n?/, '').strip
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def editor
|
18
|
+
editor = ENV['GHI_EDITOR']
|
19
|
+
editor ||= ENV['GIT_EDITOR']
|
20
|
+
editor ||= `git config core.editor`.split.first
|
21
|
+
editor ||= ENV['EDITOR']
|
22
|
+
editor ||= 'vi'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/ghi/formatting.rb
CHANGED
@@ -34,13 +34,25 @@ module GHI
|
|
34
34
|
end
|
35
35
|
}
|
36
36
|
}
|
37
|
-
stdout, $stdout = $stdout, IO.popen('less -ErX', 'w')
|
38
37
|
super strings
|
38
|
+
end
|
39
|
+
|
40
|
+
def page header = nil, throttle = 1
|
41
|
+
$stdout = IO.popen('less -EKrX -b1', 'w') if $stdout == STDOUT
|
42
|
+
puts header if header
|
43
|
+
loop do
|
44
|
+
yield
|
45
|
+
sleep throttle
|
46
|
+
end
|
39
47
|
rescue Errno::EPIPE
|
48
|
+
exit
|
40
49
|
ensure
|
41
|
-
$stdout
|
42
|
-
|
43
|
-
|
50
|
+
unless $stdout == STDOUT
|
51
|
+
$stdout.close_write
|
52
|
+
$stdout = STDOUT
|
53
|
+
print CURSOR[:show]
|
54
|
+
exit
|
55
|
+
end
|
44
56
|
end
|
45
57
|
|
46
58
|
def truncate string, reserved
|
@@ -49,11 +61,11 @@ module GHI
|
|
49
61
|
result
|
50
62
|
end
|
51
63
|
|
52
|
-
def indent string, level = 4
|
64
|
+
def indent string, level = 4, maxwidth = columns
|
53
65
|
string = string.gsub(/\r/, '')
|
54
66
|
string.gsub!(/[\t ]+$/, '')
|
55
67
|
string.gsub!(/\n{3,}/, "\n\n")
|
56
|
-
width =
|
68
|
+
width = maxwidth - level - 1
|
57
69
|
lines = string.scan(
|
58
70
|
/.{0,#{width}}(?:\s|\Z)|[\S]{#{width},}/ # TODO: Test long lines.
|
59
71
|
).map { |line| " " * level + line.chomp }
|
@@ -77,7 +89,12 @@ module GHI
|
|
77
89
|
header = "# #{repo || 'Global,'} #{state} issues"
|
78
90
|
if repo
|
79
91
|
if milestone = assigns[:milestone]
|
80
|
-
|
92
|
+
case milestone
|
93
|
+
when '*' then header << ' with a milestone'
|
94
|
+
when 'none' then header << ' without a milestone'
|
95
|
+
else
|
96
|
+
header.sub! repo, "#{repo} milestone ##{milestone}"
|
97
|
+
end
|
81
98
|
end
|
82
99
|
if assignee = assigns[:assignee]
|
83
100
|
header << case assignee
|
@@ -143,11 +160,11 @@ module GHI
|
|
143
160
|
end
|
144
161
|
|
145
162
|
# TODO: Show milestone, number of comments, pull request attached.
|
146
|
-
def format_issue i
|
163
|
+
def format_issue i, width = columns
|
147
164
|
ERB.new(<<EOF).result binding
|
148
|
-
<% p = i['pull_request']
|
149
|
-
<%= bright { \
|
150
|
-
|
165
|
+
<% p = i['pull_request']['html_url'] %>\
|
166
|
+
<%= bright { no_color { indent '%s%s: %s' % [p ? '↑' : '#', \
|
167
|
+
*i.values_at('number', 'title')], 0, width } } %>
|
151
168
|
@<%= i['user']['login'] %> opened this <%= p ? 'pull request' : 'issue' %> \
|
152
169
|
<%= format_date DateTime.parse(i['created_at']) %>. \
|
153
170
|
<%= format_state i['state'], format_tag(i['state']), :bg %>\
|
@@ -155,7 +172,7 @@ indent '%s%s: %s' % [p ? '↑' : '#', *i.values_at('number', 'title')], 0 } %>
|
|
155
172
|
<% if i['assignee'] %>@<%= i['assignee']['login'] %> is assigned. <% end %>\
|
156
173
|
<% unless i['labels'].empty? %><%= format_labels(i['labels']) %><% end %>\
|
157
174
|
<% end %>
|
158
|
-
<% if i['body'] && !i['body'].empty? %>\n<%= indent i['body'] %>
|
175
|
+
<% if i['body'] && !i['body'].empty? %>\n<%= indent i['body'], 4, width %>
|
159
176
|
<% end %>
|
160
177
|
|
161
178
|
EOF
|
@@ -166,11 +183,11 @@ EOF
|
|
166
183
|
comments.map { |comment| format_comment comment }
|
167
184
|
end
|
168
185
|
|
169
|
-
def format_comment c
|
186
|
+
def format_comment c, width = columns
|
170
187
|
<<EOF
|
171
188
|
@#{c['user']['login']} commented \
|
172
189
|
#{format_date DateTime.parse(c['created_at'])}:
|
173
|
-
#{indent c['body']}
|
190
|
+
#{indent c['body'], 4, width}
|
174
191
|
|
175
192
|
|
176
193
|
EOF
|
@@ -196,7 +213,8 @@ EOF
|
|
196
213
|
|
197
214
|
def format_milestone m
|
198
215
|
ERB.new(<<EOF).result binding
|
199
|
-
<%= bright {
|
216
|
+
<%= bright { no_color { \
|
217
|
+
indent '#%s: %s' % m.values_at('number', 'title'), 0 } } %>
|
200
218
|
@<%= m['creator']['login'] %> created this milestone <%= m['created_at'] %>. \
|
201
219
|
<%= format_state m['state'], format_tag(m['state']), :bg %>
|
202
220
|
<% if m['due_on'] %>\
|
@@ -204,13 +222,14 @@ EOF
|
|
204
222
|
Due <%= fg((:red if due_on <= DateTime.now)) { format_date due_on } %>.
|
205
223
|
<% end %>\
|
206
224
|
<% if m['description'] && !m['description'].empty? %>
|
207
|
-
<%= indent m['description']
|
225
|
+
<%= indent m['description'] %>
|
208
226
|
<% end %>
|
227
|
+
|
209
228
|
EOF
|
210
229
|
end
|
211
230
|
|
212
231
|
def format_state state, string = state, layer = :fg
|
213
|
-
send(layer, state == 'closed' ?
|
232
|
+
send(layer, state == 'closed' ? 'ff0000' : '2cc200') { string }
|
214
233
|
end
|
215
234
|
|
216
235
|
def format_labels labels
|
@@ -222,12 +241,62 @@ EOF
|
|
222
241
|
(colorize? ? ' %s ' : '[%s]') % tag
|
223
242
|
end
|
224
243
|
|
244
|
+
#--
|
245
|
+
# Helpers:
|
246
|
+
#++
|
247
|
+
|
248
|
+
def format_editor issue = nil
|
249
|
+
message = ERB.new(<<EOF).result binding
|
250
|
+
|
251
|
+
Please explain the issue. The first line will become the title. Lines
|
252
|
+
starting with '#' will be ignored, and empty messages will not be filed.
|
253
|
+
Issues are formatted with GitHub Flavored Markdown (GFM):
|
254
|
+
|
255
|
+
http://github.github.com/github-flavored-markdown
|
256
|
+
|
257
|
+
On <%= repo %>
|
258
|
+
|
259
|
+
<%= no_color { format_issue issue, columns - 2 if issue } %>
|
260
|
+
EOF
|
261
|
+
message.rstrip!
|
262
|
+
message.gsub!(/(?!\A)^.*$/) { |line| "# #{line}".rstrip }
|
263
|
+
message.insert 0, [issue['title'], issue['body']].join("\n\n") if issue
|
264
|
+
message
|
265
|
+
end
|
266
|
+
|
267
|
+
def format_comment_editor issue, comment = nil
|
268
|
+
message = ERB.new(<<EOF).result binding
|
269
|
+
|
270
|
+
Leave a comment. Lines starting with '#' will be ignored, and empty messages
|
271
|
+
will not be sent. Comments are formatted with GitHub Flavored Markdown (GFM):
|
272
|
+
|
273
|
+
http://github.github.com/github-flavored-markdown
|
274
|
+
|
275
|
+
On <%= repo %> issue #<%= issue %>
|
276
|
+
|
277
|
+
<%= no_color { format_comment comment, columns - 2 } if comment %>
|
278
|
+
EOF
|
279
|
+
message.rstrip!
|
280
|
+
message.gsub!(/(?!\A)^.*$/) { |line| "# #{line}".rstrip }
|
281
|
+
message.insert 0, comment['body'] if comment
|
282
|
+
message
|
283
|
+
end
|
284
|
+
|
225
285
|
def format_markdown string, indent = 4
|
286
|
+
c = '268bd2'
|
287
|
+
|
226
288
|
# Headers.
|
227
289
|
string.gsub!(/^( {#{indent}}\#{1,6} .+)$/, bright{'\1'})
|
228
290
|
string.gsub!(
|
229
291
|
/(^ {#{indent}}.+$\n^ {#{indent}}[-=]+$)/, bright{'\1'}
|
230
292
|
)
|
293
|
+
# Strong.
|
294
|
+
string.gsub!(
|
295
|
+
/(^|\s)(\*{2}\w(?:[^*]*\w)?\*{2})(\s|$)/m, '\1' + bright{'\2'} + '\3'
|
296
|
+
)
|
297
|
+
string.gsub!(
|
298
|
+
/(^|\s)(_{2}\w(?:[^_]*\w)?_{2})(\s|$)/m, '\1' + bright {'\2'} + '\3'
|
299
|
+
)
|
231
300
|
# Emphasis.
|
232
301
|
string.gsub!(
|
233
302
|
/(^|\s)(\*\w(?:[^*]*\w)?\*)(\s|$)/m, '\1' + underline{'\2'} + '\3'
|
@@ -235,33 +304,32 @@ EOF
|
|
235
304
|
string.gsub!(
|
236
305
|
/(^|\s)(_\w(?:[^_]*\w)?_)(\s|$)/m, '\1' + underline{'\2'} + '\3'
|
237
306
|
)
|
238
|
-
#
|
239
|
-
string.gsub!(
|
240
|
-
|
241
|
-
)
|
307
|
+
# Bullets/Blockquotes.
|
308
|
+
string.gsub!(/(^ {#{indent}}(?:[*>-]|\d+\.) )/, fg(c){'\1'})
|
309
|
+
# URIs.
|
242
310
|
string.gsub!(
|
243
|
-
|
311
|
+
%r{\b(<)?(https?://\S+|[^@\s]+@[^@\s]+)(>)?\b},
|
312
|
+
fg(c){'\1' + underline{'\2'} + '\3'}
|
244
313
|
)
|
245
314
|
# Code.
|
246
315
|
string.gsub!(
|
247
316
|
/
|
248
317
|
(^\ {#{indent}}```.*?$)(.+?^\ {#{indent}}```$)|
|
249
318
|
(^|[^`])(`[^`]+`)([^`]|$)
|
250
|
-
/mx
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
%r{\b(<)?(https?://[\s]+|\w+@\w+)(>)?\b},
|
256
|
-
'\1' + underline{'\2'} + '\3'
|
257
|
-
)
|
319
|
+
/mx
|
320
|
+
) {
|
321
|
+
post = $5
|
322
|
+
fg(c){"#$1#$2#$3#$4".gsub(/\e\[[\d;]+m/, '')} + "#{post}"
|
323
|
+
}
|
258
324
|
string
|
259
325
|
end
|
260
326
|
|
261
327
|
def format_date date
|
262
328
|
days = (interval = DateTime.now - date).to_i.abs
|
263
329
|
string = if days.zero?
|
264
|
-
|
330
|
+
seconds, _ = interval.divmod Rational(1, 86400)
|
331
|
+
hours, seconds = seconds.divmod 3600
|
332
|
+
minutes, seconds = seconds.divmod 60
|
265
333
|
if hours > 0
|
266
334
|
"#{hours} hour#{'s' unless hours == 1}"
|
267
335
|
elsif minutes > 0
|
@@ -276,7 +344,7 @@ EOF
|
|
276
344
|
end
|
277
345
|
|
278
346
|
def throb position = 0, redraw = CURSOR[:up][1]
|
279
|
-
return yield unless
|
347
|
+
return yield unless $stdout.tty?
|
280
348
|
|
281
349
|
throb = THROBBERS[rand(THROBBERS.length)]
|
282
350
|
throb.reverse! if rand > 0.5
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ghi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: -
|
4
|
+
hash: -4071658224
|
5
5
|
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 9
|
9
9
|
- 0
|
10
10
|
- dev
|
11
|
-
|
11
|
+
- 1
|
12
|
+
version: 0.9.0.dev1
|
12
13
|
platform: ruby
|
13
14
|
authors:
|
14
15
|
- Stephen Celis
|
@@ -16,7 +17,7 @@ autorequire:
|
|
16
17
|
bindir: bin
|
17
18
|
cert_chain: []
|
18
19
|
|
19
|
-
date: 2012-04-
|
20
|
+
date: 2012-04-05 00:00:00 -07:00
|
20
21
|
default_executable:
|
21
22
|
dependencies: []
|
22
23
|
|
@@ -47,6 +48,7 @@ files:
|
|
47
48
|
- lib/ghi/commands/show.rb
|
48
49
|
- lib/ghi/commands/version.rb
|
49
50
|
- lib/ghi/commands.rb
|
51
|
+
- lib/ghi/editor.rb
|
50
52
|
- lib/ghi/formatting/colors.rb
|
51
53
|
- lib/ghi/formatting.rb
|
52
54
|
- lib/ghi/json.rb
|