ektoplayer 0.1.6 → 0.1.11
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.
- checksums.yaml +4 -4
- data/README.md +26 -12
- data/lib/ektoplayer/application.rb +6 -5
- data/lib/ektoplayer/bindings.rb +61 -55
- data/lib/ektoplayer/common.rb +19 -6
- data/lib/ektoplayer/compat.rb +3 -3
- data/lib/ektoplayer/config.rb +1 -11
- data/lib/ektoplayer/controllers/browser.rb +7 -5
- data/lib/ektoplayer/controllers/help.rb +1 -1
- data/lib/ektoplayer/controllers/info.rb +1 -1
- data/lib/ektoplayer/controllers/playlist.rb +24 -12
- data/lib/ektoplayer/icurses.rb +21 -0
- data/lib/ektoplayer/icurses/curses.rb +53 -0
- data/lib/ektoplayer/icurses/ffi_ncurses.rb +69 -0
- data/lib/ektoplayer/icurses/ncurses.rb +79 -0
- data/lib/ektoplayer/icurses/ncursesw.rb +1 -0
- data/lib/ektoplayer/icurses/sugar.rb +65 -0
- data/lib/ektoplayer/icurses/test.rb +99 -0
- data/lib/ektoplayer/models/player.rb +2 -2
- data/lib/ektoplayer/{mp3player.rb → players/mpg_portaudio_player.rb} +3 -3
- data/lib/ektoplayer/players/mpg_wrapper_player.rb +107 -0
- data/lib/ektoplayer/theme.rb +1 -6
- data/lib/ektoplayer/ui.rb +100 -129
- data/lib/ektoplayer/ui/colors.rb +14 -14
- data/lib/ektoplayer/ui/widgets.rb +4 -4
- data/lib/ektoplayer/ui/widgets/labelwidget.rb +1 -1
- data/lib/ektoplayer/ui/widgets/listwidget.rb +115 -46
- data/lib/ektoplayer/views/help.rb +7 -10
- data/lib/ektoplayer/views/info.rb +29 -38
- data/lib/ektoplayer/views/mainwindow.rb +2 -5
- data/lib/ektoplayer/views/playinginfo.rb +15 -20
- data/lib/ektoplayer/views/progressbar.rb +30 -10
- data/lib/ektoplayer/views/splash.rb +24 -25
- data/lib/ektoplayer/views/tabbar.rb +6 -5
- data/lib/ektoplayer/views/trackrenderer.rb +20 -14
- metadata +15 -47
- data/lib/ektoplayer/views/volumemeter.rb +0 -76
data/lib/ektoplayer/ui/colors.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative '../icurses'
|
2
2
|
|
3
3
|
module UI
|
4
4
|
class ColorFader
|
@@ -29,14 +29,14 @@ module UI
|
|
29
29
|
class Colors
|
30
30
|
COLORS = {
|
31
31
|
none: -1, default: -1, nil => -1,
|
32
|
-
white:
|
33
|
-
black:
|
34
|
-
red:
|
35
|
-
blue:
|
36
|
-
cyan:
|
37
|
-
green:
|
38
|
-
yellow:
|
39
|
-
magenta:
|
32
|
+
white: ICurses::COLOR_WHITE,
|
33
|
+
black: ICurses::COLOR_BLACK,
|
34
|
+
red: ICurses::COLOR_RED,
|
35
|
+
blue: ICurses::COLOR_BLUE,
|
36
|
+
cyan: ICurses::COLOR_CYAN,
|
37
|
+
green: ICurses::COLOR_GREEN,
|
38
|
+
yellow: ICurses::COLOR_YELLOW,
|
39
|
+
magenta: ICurses::COLOR_MAGENTA
|
40
40
|
}
|
41
41
|
COLORS.default_proc = proc do |h, key|
|
42
42
|
fail "Unknown color #{key}" unless key.is_a?Integer
|
@@ -45,8 +45,8 @@ module UI
|
|
45
45
|
COLORS.freeze
|
46
46
|
|
47
47
|
ATTRIBUTES = {
|
48
|
-
bold:
|
49
|
-
blink:
|
48
|
+
bold: ICurses::A_BOLD, standout: ICurses::A_STANDOUT,
|
49
|
+
blink: ICurses::A_BLINK, underline: ICurses::A_UNDERLINE
|
50
50
|
}
|
51
51
|
ATTRIBUTES.default_proc = proc { |h,k| k }
|
52
52
|
ATTRIBUTES.freeze
|
@@ -68,8 +68,8 @@ module UI
|
|
68
68
|
@@id += 1
|
69
69
|
end
|
70
70
|
|
71
|
-
|
72
|
-
|
71
|
+
ICurses.init_pair(id, fg, bg) #or fail
|
72
|
+
ICurses.color_pair(id)
|
73
73
|
end
|
74
74
|
|
75
75
|
def self.add_attributes(*attrs)
|
@@ -99,7 +99,7 @@ module UI
|
|
99
99
|
@@id += 1
|
100
100
|
end
|
101
101
|
|
102
|
-
@@volatile[name] =
|
102
|
+
@@volatile[name] = ICurses.init_pair(id, fg, bg)
|
103
103
|
end
|
104
104
|
end
|
105
105
|
end
|
@@ -143,8 +143,8 @@ module UI
|
|
143
143
|
|
144
144
|
def initialize(**opts)
|
145
145
|
super(**opts)
|
146
|
-
@win =
|
147
|
-
@win.keypad
|
146
|
+
@win = ICurses.newwin(@size.height, @size.width, @pos.y, @pos.x)
|
147
|
+
@win.keypad(true)
|
148
148
|
end
|
149
149
|
|
150
150
|
def layout
|
@@ -163,7 +163,7 @@ module UI
|
|
163
163
|
|
164
164
|
def initialize(**opts)
|
165
165
|
super(**opts)
|
166
|
-
@win =
|
166
|
+
@win = ICurses.newpad(@size.height, @size.width)
|
167
167
|
@pad_minrow = @pad_mincol = 0
|
168
168
|
end
|
169
169
|
|
@@ -230,7 +230,7 @@ module UI
|
|
230
230
|
end
|
231
231
|
|
232
232
|
def refresh
|
233
|
-
@win.
|
233
|
+
@win.pnoutrefresh(
|
234
234
|
@pad_minrow, @pad_mincol,
|
235
235
|
@pos.y, @pos.x,
|
236
236
|
@pos.y + @size.height - 1, @pos.x + @size.width - 1
|
@@ -12,12 +12,28 @@ module UI
|
|
12
12
|
|
13
13
|
def layout; end
|
14
14
|
|
15
|
-
def render(scr, item, selected: false, marked: false)
|
15
|
+
def render(scr, item, selected: false, marked: false, selection: false)
|
16
16
|
scr << (selected ? ?> : ' ')
|
17
17
|
scr << item_to.s
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
+
class ListSelector
|
22
|
+
attr_reader :start_pos
|
23
|
+
def start(pos)
|
24
|
+
@start_pos = pos
|
25
|
+
end
|
26
|
+
|
27
|
+
def started?; @start_pos end
|
28
|
+
|
29
|
+
def stop(pos)
|
30
|
+
return [] unless @start_pos
|
31
|
+
r = [pos, @start_pos].min.upto([pos, @start_pos].max).to_a
|
32
|
+
@start_pos = nil
|
33
|
+
r
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
21
37
|
class ListSearch
|
22
38
|
attr_accessor :direction, :source
|
23
39
|
|
@@ -28,7 +44,7 @@ module UI
|
|
28
44
|
end
|
29
45
|
|
30
46
|
def comp(item, search)
|
31
|
-
if item.is_a?String
|
47
|
+
if item.is_a?String or item.is_a?Symbol
|
32
48
|
return item.downcase =~ Regexp.new(search.downcase)
|
33
49
|
elsif item.is_a?Hash
|
34
50
|
%w(title artist album).each do |key|
|
@@ -46,24 +62,29 @@ module UI
|
|
46
62
|
@result = @source.size.times.select {|i| self.comp(@source[i], search) }
|
47
63
|
end
|
48
64
|
|
49
|
-
def current; @
|
50
|
-
def next
|
51
|
-
def prev
|
65
|
+
def current; @current or 0 end #or 0 end
|
66
|
+
def next(p) @direction == :up ? search_up(p): search_down(p) end
|
67
|
+
def prev(p) @direction == :up ? search_down(p) : search_up(p) end
|
68
|
+
|
69
|
+
def search_up(p)
|
70
|
+
@current = (
|
71
|
+
@result.reverse.select { |v| v < p }[0] or @result[-1]
|
72
|
+
)
|
52
73
|
|
53
|
-
def search_up
|
54
|
-
@current -= 1
|
55
|
-
@current = @result.size - 1 if @current < 0
|
56
74
|
self
|
57
75
|
end
|
58
76
|
|
59
|
-
def search_down
|
60
|
-
@current =
|
77
|
+
def search_down(p)
|
78
|
+
@current = (
|
79
|
+
@result.select { |v| v > p }[0] or @result[0]
|
80
|
+
)
|
81
|
+
|
61
82
|
self
|
62
83
|
end
|
63
84
|
end
|
64
85
|
|
65
86
|
class ListWidget < Window
|
66
|
-
attr_reader :list, :selected, :cursor
|
87
|
+
attr_reader :list, :selected, :cursor, :selection
|
67
88
|
attr_accessor :item_renderer
|
68
89
|
|
69
90
|
def initialize(list: [], item_renderer: nil, **opts)
|
@@ -72,13 +93,14 @@ module UI
|
|
72
93
|
@item_renderer = (item_renderer or ListItemRenderer.new)
|
73
94
|
@cursor = @selected = 0
|
74
95
|
@search = ListSearch.new
|
96
|
+
@selection = ListSelector.new
|
75
97
|
end
|
76
98
|
|
77
|
-
def search_next; self.selected=(@search.next.current) end
|
78
|
-
def search_prev; self.selected=(@search.prev.current) end
|
99
|
+
def search_next; self.selected=(@search.next(@selected).current) end
|
100
|
+
def search_prev; self.selected=(@search.prev(@selected).current) end
|
79
101
|
def search_up; self.search_start(:up) end
|
80
102
|
def search_down; self.search_start(:down) end
|
81
|
-
def search_start(direction
|
103
|
+
def search_start(direction)
|
82
104
|
UI::Input.readline(@pos, @size.update(height: 1), prompt: '> ', add_hist: true) do |result|
|
83
105
|
if result
|
84
106
|
@search.source=(@list)
|
@@ -89,9 +111,39 @@ module UI
|
|
89
111
|
end
|
90
112
|
end
|
91
113
|
|
114
|
+
def toggle_selection
|
115
|
+
with_lock do
|
116
|
+
if @selection.started?
|
117
|
+
@selection.stop(@selected)
|
118
|
+
want_redraw
|
119
|
+
else
|
120
|
+
@selection.start(@selected)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def get_selection
|
126
|
+
self.lock
|
127
|
+
r = @selection.stop(@selected)
|
128
|
+
r << @selected if r.empty?
|
129
|
+
r
|
130
|
+
ensure
|
131
|
+
want_redraw
|
132
|
+
self.unlock
|
133
|
+
end
|
134
|
+
|
92
135
|
def render(index, **opts)
|
93
136
|
return unless @item_renderer
|
94
|
-
return unless @list[index]
|
137
|
+
return Ektoplayer::Application.log(self, 'render todo') unless @list[index]
|
138
|
+
|
139
|
+
opts[:selection] = (@selection.started? and (
|
140
|
+
opts[:selected] or index.between?(
|
141
|
+
[@selection.start_pos, @selected].min,
|
142
|
+
[@selection.start_pos, @selected].max
|
143
|
+
)
|
144
|
+
)
|
145
|
+
)
|
146
|
+
|
95
147
|
@item_renderer.render(@win, @list[index], index, **opts)
|
96
148
|
end
|
97
149
|
|
@@ -119,56 +171,64 @@ module UI
|
|
119
171
|
|
120
172
|
def selected=(new_index)
|
121
173
|
fail ArgumentError unless new_index
|
122
|
-
|
123
|
-
|
174
|
+
old_index_bottom = index_bottom
|
175
|
+
old_index_top = index_top
|
176
|
+
old_selected, @selected = @selected, new_index.clamp(0, index_last)
|
177
|
+
return if old_selected == @selected or @list.empty?
|
124
178
|
|
125
179
|
self.lock
|
126
180
|
|
127
|
-
new_cursor = @cursor +
|
181
|
+
old_cursor, new_cursor = @cursor, @cursor + @selected - old_selected
|
182
|
+
|
128
183
|
if new_cursor.between?(0, @size.height - 1)
|
129
184
|
# new selected item resides in current screen,
|
130
185
|
# just want_redraw the old line and the newly selected one
|
131
|
-
|
186
|
+
@cursor = new_cursor
|
187
|
+
|
188
|
+
# redraw whole screen in selection mode!
|
189
|
+
return want_redraw if @selection.started?
|
190
|
+
|
191
|
+
write_at(old_cursor); render(old_selected)
|
132
192
|
write_at(new_cursor); render(new_index, selected: true)
|
133
|
-
@selected, @cursor = new_index, new_cursor
|
134
193
|
_check
|
135
194
|
want_refresh
|
136
195
|
elsif (new_cursor.between?(-(@size.height - 1), (2 * @size.height - 1)))
|
137
196
|
# new selected item is max a half screen size away
|
138
|
-
if
|
139
|
-
if lines_after_cursor > (
|
140
|
-
write_at(
|
197
|
+
if @selected < old_selected
|
198
|
+
if lines_after_cursor > (old_selected - @selected)
|
199
|
+
write_at(old_cursor); render(old_selected)
|
141
200
|
end
|
142
201
|
|
143
|
-
(
|
202
|
+
(old_index_top - 1).downto(@selected + 1).each do |index|
|
144
203
|
@win.insert_top; render(index)
|
145
204
|
end
|
146
205
|
|
147
|
-
@win.insert_top; render(
|
148
|
-
@
|
206
|
+
@win.insert_top; render(@selected, selected: true)
|
207
|
+
@cursor = 0
|
149
208
|
_check
|
150
209
|
else
|
151
|
-
if lines_before_cursor > (
|
152
|
-
write_at(
|
210
|
+
if lines_before_cursor > (@selected - old_selected)
|
211
|
+
write_at(old_cursor); render(old_selected)
|
153
212
|
end
|
154
213
|
|
155
|
-
(
|
214
|
+
(old_index_bottom + 1).upto(@selected - 1).each do |index|
|
156
215
|
@win.append_bottom; render(index)
|
157
216
|
end
|
158
217
|
|
159
|
-
@win.append_bottom; render(
|
160
|
-
@
|
218
|
+
@win.append_bottom; render(@selected, selected: true)
|
219
|
+
@cursor = cursor_max
|
161
220
|
_check
|
162
221
|
end
|
163
222
|
|
164
223
|
want_refresh
|
165
224
|
else
|
166
|
-
|
167
|
-
@cursor = new_index.clamp(0, cursor_max)
|
225
|
+
#@selected = new_index
|
226
|
+
@cursor = new_index.clamp(0, cursor_max) # todo new_index<>new_cursor? ne muess scho pasn
|
168
227
|
_check
|
169
228
|
want_redraw
|
170
229
|
end
|
171
230
|
|
231
|
+
ensure
|
172
232
|
self.unlock
|
173
233
|
end
|
174
234
|
|
@@ -179,12 +239,17 @@ module UI
|
|
179
239
|
return if (new_cursor == @cursor) or @list.empty?
|
180
240
|
|
181
241
|
with_lock do
|
182
|
-
|
183
|
-
|
184
|
-
write_at(new_cursor); render(new_index, selected: true)
|
185
|
-
@selected, @cursor = new_index, new_cursor
|
242
|
+
old_cursor, @cursor = @cursor, new_cursor
|
243
|
+
old_selected, @selected = @selected, (@selected - (old_cursor - @cursor)).clamp(0, index_last)
|
186
244
|
_check
|
187
|
-
|
245
|
+
|
246
|
+
if @selection.started?
|
247
|
+
want_redraw
|
248
|
+
else
|
249
|
+
write_at(old_cursor); render(old_selected)
|
250
|
+
write_at(new_cursor); render(@selected, selected: true)
|
251
|
+
want_refresh
|
252
|
+
end
|
188
253
|
end
|
189
254
|
end
|
190
255
|
|
@@ -211,23 +276,25 @@ module UI
|
|
211
276
|
# list is already on top
|
212
277
|
select_from_cursorpos((@cursor - n).clamp(0, cursor_max))
|
213
278
|
elsif n < @size.height
|
279
|
+
old_index_top = index_top
|
280
|
+
old_selected, @selected = @selected, @selected - n
|
281
|
+
|
214
282
|
if lines_after_cursor > n
|
215
|
-
write_at(@cursor); render(
|
283
|
+
write_at(@cursor); render(old_selected)
|
216
284
|
end
|
217
285
|
|
218
|
-
(
|
286
|
+
(old_index_top - 1).downto(old_index_top - n).each do |index|
|
219
287
|
@win.insert_top; render(index)
|
220
288
|
end
|
221
289
|
|
222
|
-
@selected -= n
|
223
290
|
write_at(@cursor); render(@selected, selected: true)
|
224
291
|
|
225
292
|
_check
|
226
293
|
want_refresh
|
227
294
|
else
|
228
|
-
@selected -= n
|
295
|
+
@selected -= n # TODO: move up?
|
229
296
|
force_cursorpos(@cursor)
|
230
|
-
_check
|
297
|
+
_check # todo: move up
|
231
298
|
want_redraw
|
232
299
|
end
|
233
300
|
|
@@ -244,15 +311,17 @@ module UI
|
|
244
311
|
select_from_cursorpos((@cursor + n).clamp(0, cursor_max))
|
245
312
|
_check
|
246
313
|
elsif n < @size.height
|
314
|
+
old_index_bottom = index_bottom
|
315
|
+
old_selected, @selected = @selected, @selected + n
|
316
|
+
|
247
317
|
if lines_before_cursor > n
|
248
|
-
write_at(@cursor); render(
|
318
|
+
write_at(@cursor); render(old_selected)
|
249
319
|
end
|
250
320
|
|
251
|
-
(
|
321
|
+
(old_index_bottom + 1).upto(old_index_bottom + n).each do |index|
|
252
322
|
@win.append_bottom; render(index)
|
253
323
|
end
|
254
324
|
|
255
|
-
@selected += n
|
256
325
|
write_at(@cursor); render(@selected, selected: true)
|
257
326
|
|
258
327
|
_check
|
@@ -15,9 +15,8 @@ module Ektoplayer
|
|
15
15
|
@win.erase
|
16
16
|
|
17
17
|
Bindings.bindings.each do |widget, commands|
|
18
|
-
@win.
|
19
|
-
|
20
|
-
end
|
18
|
+
@win.attrset(Theme[:'help.widget_name'])
|
19
|
+
@win.addstr("\n#{widget}\n")
|
21
20
|
|
22
21
|
commands.each do |name, keys|
|
23
22
|
next if keys.empty?
|
@@ -29,15 +28,13 @@ module Ektoplayer
|
|
29
28
|
@win.with_attr(Theme[:'help.key_name']) { @win << key }
|
30
29
|
end
|
31
30
|
|
32
|
-
@win.
|
33
|
-
|
34
|
-
end
|
31
|
+
@win.attrset(Theme[:'help.command_name'])
|
32
|
+
@win.mvaddstr(@win.cury, 18, name.to_s)
|
35
33
|
|
36
|
-
@win.
|
37
|
-
|
38
|
-
end
|
34
|
+
@win.attrset(Theme[:'help.command_desc'])
|
35
|
+
@win.mvaddstr(@win.cury, 43, Bindings.commands[name.to_sym])
|
39
36
|
|
40
|
-
@win.
|
37
|
+
@win.next_line
|
41
38
|
end
|
42
39
|
end
|
43
40
|
end
|
@@ -25,55 +25,47 @@ module Ektoplayer
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def draw_heading(heading)
|
28
|
-
@win.
|
29
|
-
|
30
|
-
end
|
28
|
+
@win.attrset(Theme[:'info.head'])
|
29
|
+
@win.mvaddstr(@win.cury + 1, START_HEADING, heading)
|
31
30
|
end
|
32
31
|
|
33
32
|
def draw_tag(tag, value=nil)
|
34
|
-
@win.
|
35
|
-
|
36
|
-
end
|
33
|
+
@win.attrset(Theme[:'info.tag'])
|
34
|
+
@win.mvaddstr(@win.cury + 1, START_TAG, tag)
|
37
35
|
|
38
|
-
@win.
|
39
|
-
@win.
|
40
|
-
@win.addstr(value.to_s)
|
41
|
-
end
|
36
|
+
@win.attrset(Theme[:'info.value'])
|
37
|
+
@win.mvaddstr(@win.cury, START_TAG_VALUE, value.to_s)
|
42
38
|
end
|
43
39
|
|
44
40
|
def draw_info(string, value=nil)
|
45
|
-
@win.
|
46
|
-
|
47
|
-
end
|
41
|
+
@win.attrset(Theme[:'info.tag'])
|
42
|
+
@win.mvaddstr(@win.cury + 1, START_INFO, string)
|
48
43
|
|
49
|
-
@win.
|
50
|
-
@win.
|
51
|
-
@win.addstr(value.to_s)
|
52
|
-
end
|
44
|
+
@win.attrset(Theme[:'info.value'])
|
45
|
+
@win.mvaddstr(@win.cury, START_INFO_VALUE, value.to_s)
|
53
46
|
end
|
54
47
|
|
55
48
|
def draw_url(url, title=nil)
|
56
49
|
title ||= url
|
57
50
|
mevent = with_mouse_section_event do
|
58
|
-
@win.
|
51
|
+
@win.attrset(Theme[:url])
|
52
|
+
@win << title
|
59
53
|
end
|
60
|
-
mevent.on(
|
54
|
+
mevent.on(ICurses::BUTTON1_CLICKED) do
|
61
55
|
Common::open_url_extern(url)
|
62
56
|
end
|
63
57
|
end
|
64
58
|
|
65
59
|
def draw_download(file, percent, error)
|
66
|
-
@win.
|
67
|
-
|
68
|
-
|
69
|
-
@win.
|
70
|
-
|
71
|
-
end
|
60
|
+
@win.attrset(Theme[:'info.download.file'])
|
61
|
+
@win.mvaddstr(@win.cury + 1, START_TAG, file)
|
62
|
+
|
63
|
+
@win.attrset(Theme[:'info.download.percent'])
|
64
|
+
@win.addstr(" #{percent}")
|
72
65
|
|
73
66
|
if error
|
74
|
-
@win.
|
75
|
-
|
76
|
-
end
|
67
|
+
@win.attrset(Theme[:'info.download.error'])
|
68
|
+
@win.addstr(" #{error}")
|
77
69
|
end
|
78
70
|
end
|
79
71
|
|
@@ -87,7 +79,7 @@ module Ektoplayer
|
|
87
79
|
|
88
80
|
mouse_section.clear
|
89
81
|
@win.erase
|
90
|
-
@win.
|
82
|
+
@win.move(0,0)
|
91
83
|
|
92
84
|
if @track = (@playlist[@playlist.current_playing] rescue nil)
|
93
85
|
draw_heading('Current track')
|
@@ -123,30 +115,29 @@ module Ektoplayer
|
|
123
115
|
draw_heading('Description')
|
124
116
|
line_length = START_TAG
|
125
117
|
wrap_length = @size.width.clamp(1, LINE_WRAP)
|
126
|
-
@win.
|
118
|
+
@win.move(@win.cury + 1, START_TAG)
|
127
119
|
|
128
120
|
Nokogiri::HTML("<p>#{@track['description']}</p>").css(?p).each do |p|
|
129
121
|
p.children.each do |element|
|
130
122
|
if element[:href]
|
131
123
|
if (line_length += element.text.size) > wrap_length
|
132
|
-
@win.
|
124
|
+
@win.move(@win.cury + 1, START_TAG)
|
133
125
|
line_length = START_TAG
|
134
126
|
end
|
135
127
|
|
136
128
|
draw_url(element[:href], element.text.strip)
|
137
|
-
@win.addch(' '
|
129
|
+
@win.addch(32) # ' '
|
138
130
|
else
|
139
131
|
element.text.split(' ').each do |text|
|
140
132
|
if (line_length += text.size) > wrap_length
|
141
|
-
@win.
|
133
|
+
@win.move(@win.cury + 1, START_TAG)
|
142
134
|
line_length = START_TAG
|
143
135
|
end
|
144
136
|
|
145
|
-
@win.
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
end
|
137
|
+
@win.attrset(Theme[:'info.description'])
|
138
|
+
@win.mv_left(1) if text =~ /^[\.,:;]$/
|
139
|
+
@win << text
|
140
|
+
@win.addch(32) # ' '
|
150
141
|
end
|
151
142
|
end
|
152
143
|
end
|