lucaterm 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/exe/luca +8 -5
- data/lib/luca_term/book.rb +141 -61
- data/lib/luca_term/version.rb +1 -1
- metadata +21 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c072f724a2ad3fb09fc648c4912c974d8c874fd82165e525bb6cd3d06073f645
|
4
|
+
data.tar.gz: 6d6a198f22a9fab3ea8c6426f98571927577862b61f1b6b4f955e8442375b778
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d6b3ec02aaf1dac932d47dc74fa0c61604915a7ab79a3198c83075f67d94a5cffd5c5a2673cd8c852806aafcc8d875cc3040d5680c248fcfdcc25797c0030c2
|
7
|
+
data.tar.gz: 74d40973ea0f60f6e5dc9d40fd52d3548683525ffe018b5c1e054175dc06303eac3da2d4da9a10bff02c4f5e496bef4d495180dac7a5b37352c7d5816a606d11
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## LucaTerm 0.2.0
|
2
|
+
|
3
|
+
* `luca book`: Works without args. Show journals of the latest month.
|
4
|
+
* `luca book`: Show categories on Account code selection
|
5
|
+
* `luca book`: Show x-customer header on detail screen
|
6
|
+
|
1
7
|
## LucaTerm 0.1.2
|
2
8
|
|
3
9
|
* `luca book`: '<' for prev month, '>' for next month.
|
data/exe/luca
CHANGED
@@ -3,19 +3,22 @@
|
|
3
3
|
|
4
4
|
require 'optparse'
|
5
5
|
require 'curses'
|
6
|
+
require 'luca_book/journal'
|
6
7
|
require 'luca_term'
|
7
8
|
|
8
9
|
include Curses
|
9
10
|
|
10
|
-
init_screen
|
11
|
-
curs_set(0)
|
12
|
-
noecho
|
13
11
|
|
14
12
|
class LucaCmd
|
15
13
|
def self.book(args, params = {})
|
14
|
+
init_screen
|
15
|
+
curs_set(0)
|
16
|
+
noecho
|
17
|
+
|
16
18
|
begin
|
17
|
-
window = Curses::Window.new(0, 0,
|
18
|
-
|
19
|
+
window = Curses::Window.new(0, 0, 1, 0)
|
20
|
+
args = ARGV.empty? ? LucaBook::Journal.latest_month : ARGV
|
21
|
+
LucaTerm::Book.journals(window, *args)
|
19
22
|
ensure
|
20
23
|
close_screen
|
21
24
|
end
|
data/lib/luca_term/book.rb
CHANGED
@@ -4,13 +4,14 @@ require 'curses'
|
|
4
4
|
require "unicode/display_width/string_ext"
|
5
5
|
require 'mb_string'
|
6
6
|
require 'luca_book'
|
7
|
-
|
7
|
+
require 'json'
|
8
8
|
module LucaTerm
|
9
9
|
class Book
|
10
10
|
include Curses
|
11
|
-
attr_accessor :window
|
11
|
+
attr_accessor :window, :modeline
|
12
12
|
|
13
13
|
def initialize(window, year, month, data=nil)
|
14
|
+
@modeline = Window.new(1, 0, 0, 0)
|
14
15
|
@window = window
|
15
16
|
@year = year
|
16
17
|
@month = month
|
@@ -26,16 +27,22 @@ module LucaTerm
|
|
26
27
|
new(window, args[0], args[1], LucaSupport::Code.readable(LucaBook::List.term(*args).data))
|
27
28
|
end
|
28
29
|
|
30
|
+
# render monthly journal list
|
31
|
+
#
|
29
32
|
def main_loop
|
30
33
|
loop do
|
34
|
+
modeline.setpos(0, 0)
|
35
|
+
modeline << "#{Date::ABBR_MONTHNAMES[@month.to_i]} #{@year}"
|
36
|
+
modeline.clrtoeol
|
37
|
+
modeline.refresh
|
38
|
+
|
31
39
|
window.setpos(0,0)
|
32
40
|
@visible.each.with_index(0) do |dat, i|
|
33
41
|
cursor = i == @active ? :full : nil
|
34
42
|
draw_line(dat, cursor, true)
|
35
|
-
clrtoeol
|
36
43
|
window << "\n"
|
37
44
|
end
|
38
|
-
(window.maxy - window.cury).times { window
|
45
|
+
(window.maxy - window.cury).times { window << "\n" }
|
39
46
|
window.refresh
|
40
47
|
|
41
48
|
window.keypad(true)
|
@@ -52,7 +59,7 @@ module LucaTerm
|
|
52
59
|
when 'G'
|
53
60
|
cursor_last @data
|
54
61
|
when 'm'
|
55
|
-
ym = edit_dialog('
|
62
|
+
ym = edit_dialog('Enter: [yyyy] m', title: 'Change Month')&.split(/[\/\s]/)
|
56
63
|
ym = [@year, ym[0]] if ym.length == 1
|
57
64
|
@data = LucaSupport::Code.readable(LucaBook::List.term(*ym).data)
|
58
65
|
@year, @month = ym
|
@@ -75,8 +82,9 @@ module LucaTerm
|
|
75
82
|
@visible = set_visible(@data)
|
76
83
|
when KEY_ENTER, KEY_CTRL_J
|
77
84
|
show_detail(@data[@index])
|
85
|
+
@visible = set_visible(@data)
|
78
86
|
when 'N'
|
79
|
-
newdate = edit_dialog "Enter date of new record: YYYY-m-d"
|
87
|
+
newdate = edit_dialog "Enter date of new record: YYYY-m-d", title: 'Create Journal'
|
80
88
|
tmpl = {
|
81
89
|
date: newdate,
|
82
90
|
debit: [
|
@@ -93,16 +101,26 @@ module LucaTerm
|
|
93
101
|
end
|
94
102
|
end
|
95
103
|
|
104
|
+
# render each journal
|
105
|
+
#
|
96
106
|
def show_detail(record)
|
97
107
|
@d_v = 0
|
98
108
|
@d_h = 0
|
99
109
|
debit_length = Array(record[:debit]).length
|
100
110
|
credit_length = Array(record[:credit]).length
|
101
111
|
date, txid = LucaSupport::Code.decode_id(record[:id]) if record[:id]
|
112
|
+
fileid = record[:id].split('/').last if record[:id]
|
102
113
|
date ||= record[:date]
|
114
|
+
modeline.setpos(0, 0)
|
115
|
+
modeline << "#{date} #{fileid} "
|
116
|
+
modeline.clrtoeol
|
117
|
+
modeline.refresh
|
118
|
+
|
103
119
|
loop do
|
104
120
|
window.setpos(0, 0)
|
105
|
-
|
121
|
+
if record.dig(:headers, 'x-customer')
|
122
|
+
window << format(" [%s] ", record.dig(:headers, 'x-customer'))
|
123
|
+
end
|
106
124
|
window << record[:note]
|
107
125
|
clrtoeol; window << "\n"
|
108
126
|
[debit_length, credit_length].max.times do |i|
|
@@ -119,7 +137,7 @@ module LucaTerm
|
|
119
137
|
clrtoeol
|
120
138
|
window << "\n"
|
121
139
|
end
|
122
|
-
(window.maxy - window.cury).times { window
|
140
|
+
(window.maxy - window.cury).times { window << "\n" }
|
123
141
|
window.refresh
|
124
142
|
|
125
143
|
window.keypad(true)
|
@@ -173,14 +191,15 @@ module LucaTerm
|
|
173
191
|
debit_length = Array(record[:debit]).length
|
174
192
|
credit_length = Array(record[:credit]).length
|
175
193
|
when KEY_CTRL_J
|
176
|
-
position = [0,1].include?(@d_h) ? :debit : :credit
|
194
|
+
position, counter = [0,1].include?(@d_h) ? [:debit, :credit] : [:credit, :debit]
|
177
195
|
if [0, 2].include? @d_h
|
178
196
|
new_code = select_code
|
179
197
|
next if new_code.nil?
|
180
198
|
|
181
199
|
record[position][@d_v][:code] = new_code
|
182
200
|
else
|
183
|
-
|
201
|
+
diff = record[counter].map { |c| c[:amount] }.sum - record[position].map { |p| p[:amount] }.sum + record[position][@d_v][:amount]
|
202
|
+
new_amount = edit_amount(record[position][@d_v][:amount], diff)
|
184
203
|
next if new_amount.nil?
|
185
204
|
|
186
205
|
record[position][@d_v][:amount] = new_amount
|
@@ -198,9 +217,12 @@ module LucaTerm
|
|
198
217
|
end
|
199
218
|
end
|
200
219
|
|
201
|
-
|
220
|
+
# returns amount after edit
|
221
|
+
#
|
222
|
+
def edit_amount(current = nil, diff = nil)
|
223
|
+
diff_msg = diff.nil? ? '' : "#{diff} meets balance."
|
202
224
|
begin
|
203
|
-
scmd = edit_dialog "Current: #{current&.to_s}"
|
225
|
+
scmd = edit_dialog "Current: #{current&.to_s}", diff_msg, title: 'Edit Amount'
|
204
226
|
return nil if scmd.length == 0
|
205
227
|
# TODO: guard from not number
|
206
228
|
return scmd.to_i
|
@@ -209,17 +231,22 @@ module LucaTerm
|
|
209
231
|
end
|
210
232
|
end
|
211
233
|
|
212
|
-
def edit_dialog(message = '')
|
213
|
-
sub = window.subwin(
|
214
|
-
sub.box(?|, ?-)
|
234
|
+
def edit_dialog(message = '', submessage = '', title: '')
|
235
|
+
sub = window.subwin(5, 30, (window.maxy-5)/2, (window.maxx - 30)/2)
|
215
236
|
sub.setpos(1, 1)
|
216
|
-
|
217
|
-
sub
|
218
|
-
clrtoeol
|
237
|
+
sub << " #{message}"
|
238
|
+
sub.clrtoeol
|
219
239
|
sub.setpos(2, 1)
|
220
|
-
sub
|
221
|
-
sub.setpos(2,
|
222
|
-
|
240
|
+
sub.clrtoeol
|
241
|
+
sub.setpos(2, 3)
|
242
|
+
sub.attron(A_REVERSE) { sub << " > #{' ' * (30 - 9)}" }
|
243
|
+
sub.setpos(3, 1)
|
244
|
+
sub << " #{submessage}"
|
245
|
+
sub.clrtoeol
|
246
|
+
sub.box(?|, ?-)
|
247
|
+
sub.setpos(0, 2)
|
248
|
+
sub << "[ #{title} ]"
|
249
|
+
sub.setpos(2, 7)
|
223
250
|
sub.refresh
|
224
251
|
loop do
|
225
252
|
echo
|
@@ -230,57 +257,75 @@ module LucaTerm
|
|
230
257
|
end
|
231
258
|
end
|
232
259
|
|
260
|
+
# returns Account code after selection from list dialog
|
261
|
+
#
|
233
262
|
def select_code
|
234
|
-
|
235
|
-
|
263
|
+
top = window.maxy >= 25 ? 5 : 2
|
264
|
+
sub = window.subwin(window.maxy - top, window.maxx - 4, top, 2)
|
265
|
+
padding = ' ' * account_index(sub.maxx)[0].length
|
266
|
+
list = @dict.reject{ |code, _e| code.length < 3 || /^[15]0XX/.match(code) || /^[89]ZZ/.match(code) }
|
267
|
+
.map{ |code, entry| { code: code, label: entry[:label], category: padding } }
|
268
|
+
tabstop = ['1', '5', '9', 'A', 'C'].map { |cap| list.index { |ac| /^#{cap}/.match(ac[:code]) } }.compact
|
269
|
+
account_index(sub.maxx).each.with_index do |cat, i|
|
270
|
+
list[tabstop[i]][:category] = cat
|
271
|
+
end
|
236
272
|
visible_dup = @visible
|
237
273
|
index_dup = @index
|
238
274
|
active_dup = @active
|
239
275
|
@index = 0
|
240
276
|
@active = 0
|
241
277
|
@visible = nil
|
242
|
-
@visible = set_visible(list)
|
278
|
+
@visible = set_visible(list, sub.maxy - 2)
|
243
279
|
loop do
|
244
|
-
window.setpos(0,0)
|
245
280
|
@visible.each.with_index(0) do |entry, i|
|
246
|
-
|
281
|
+
sub.setpos(i+1, 1)
|
282
|
+
head = entry[:code].length == 3 ? '' : ' '
|
283
|
+
line = format("%s %s %s %s", head, entry[:category], entry[:code], entry[:label])
|
247
284
|
if i == @active
|
248
|
-
|
285
|
+
sub.attron(A_REVERSE) { sub << line }
|
249
286
|
else
|
250
|
-
|
287
|
+
sub << line
|
251
288
|
end
|
252
|
-
clrtoeol
|
253
|
-
|
289
|
+
sub.clrtoeol
|
290
|
+
#sub << "\n"
|
254
291
|
end
|
255
|
-
(window.maxy - window.cury).times { window
|
256
|
-
|
292
|
+
(window.maxy - window.cury).times { window << "\n" }
|
293
|
+
sub.box(?|, ?-)
|
294
|
+
sub.setpos(0, 2)
|
295
|
+
sub << "[ Select Account ]"
|
296
|
+
sub.refresh
|
257
297
|
|
258
298
|
cmd = window.getch
|
259
299
|
case cmd
|
260
300
|
when KEY_DOWN, 'j', KEY_CTRL_N
|
261
301
|
next if @index >= list.length - 1
|
262
302
|
|
263
|
-
cursor_down list
|
303
|
+
cursor_down list, sub.maxy - 2
|
264
304
|
when KEY_NPAGE
|
265
|
-
cursor_pagedown list
|
305
|
+
cursor_pagedown list, sub.maxy - 2
|
266
306
|
when KEY_UP, 'k', KEY_CTRL_P
|
267
307
|
next if @index <= 0
|
268
308
|
|
269
309
|
cursor_up list
|
270
310
|
when KEY_PPAGE
|
271
|
-
cursor_pageup list
|
311
|
+
cursor_pageup list, sub.maxy - 2
|
312
|
+
when KEY_LEFT
|
313
|
+
cursor_jump tabstop, list, rev: true
|
314
|
+
when KEY_RIGHT
|
315
|
+
cursor_jump tabstop, list
|
272
316
|
when 'G'
|
273
|
-
cursor_last list
|
317
|
+
cursor_last list, sub.maxy - 2
|
274
318
|
when KEY_CTRL_J
|
275
|
-
code = list[@index][:code]
|
276
319
|
@visible = visible_dup
|
277
320
|
@index = index_dup
|
278
321
|
@active = active_dup
|
279
|
-
|
322
|
+
sub.close
|
323
|
+
return list[@index][:code]
|
280
324
|
when 'q'
|
281
325
|
@visible = visible_dup
|
282
326
|
@index = index_dup
|
283
327
|
@active = active_dup
|
328
|
+
sub.close
|
284
329
|
return nil
|
285
330
|
end
|
286
331
|
end
|
@@ -288,17 +333,36 @@ module LucaTerm
|
|
288
333
|
|
289
334
|
private
|
290
335
|
|
336
|
+
def account_index(maxx = 50)
|
337
|
+
term = if maxx >= 45
|
338
|
+
['Assets', 'Liabilities', 'Net Assets', 'Sales', 'Expenses']
|
339
|
+
elsif maxx >= 40
|
340
|
+
['Assets', 'LIAB', 'NetAsset', 'Sales', 'EXP']
|
341
|
+
else
|
342
|
+
['', '', '', '', '']
|
343
|
+
end
|
344
|
+
len = term.map { |str| str.length }.max
|
345
|
+
term.map { |str| str += ' ' * (len - str.length) }
|
346
|
+
end
|
347
|
+
|
291
348
|
def draw_line(dat, cursor = nil, note = false)
|
292
349
|
date, txid = LucaSupport::Code.decode_id(dat[:id]) if dat[:id]
|
350
|
+
date_str = date.nil? ? '' : date.split('-')[1, 2].join('/')&.mb_rjust(5, ' ')
|
293
351
|
debit_cd = fmt_code(dat[:debit])
|
294
352
|
debit_amount = fmt_amount(dat[:debit])
|
295
353
|
credit_cd = fmt_code(dat[:credit])
|
296
354
|
credit_amount = fmt_amount(dat[:credit])
|
297
355
|
lines = [Array(dat[:debit]).length, Array(dat[:credit]).length].max
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
356
|
+
lines = if lines == 1
|
357
|
+
' '
|
358
|
+
elsif lines > 9
|
359
|
+
'+'
|
360
|
+
else
|
361
|
+
lines
|
362
|
+
end
|
363
|
+
window << sprintf("%s |%s| ",
|
364
|
+
date_str,
|
365
|
+
lines,
|
302
366
|
)
|
303
367
|
case cursor
|
304
368
|
when 0
|
@@ -317,8 +381,8 @@ module LucaTerm
|
|
317
381
|
window.attron(A_REVERSE) { window << credit_amount }
|
318
382
|
else
|
319
383
|
rest = format("%s %s | %s %s", debit_cd, debit_amount, credit_cd, credit_amount)
|
320
|
-
if note && window.maxx >
|
321
|
-
rest += " | #{dat[:note]
|
384
|
+
if note && window.maxx > 70
|
385
|
+
rest += " | #{dat[:note]&.mb_truncate(window.maxx - 70)}"
|
322
386
|
end
|
323
387
|
if cursor == :full
|
324
388
|
window.attron(A_REVERSE) { window << rest }
|
@@ -354,46 +418,62 @@ module LucaTerm
|
|
354
418
|
@visible = set_visible(data)
|
355
419
|
end
|
356
420
|
|
357
|
-
def cursor_pageup(data)
|
358
|
-
|
421
|
+
def cursor_pageup(data, maxy = nil)
|
422
|
+
maxy ||= window.maxy
|
423
|
+
n_idx = @index - maxy
|
359
424
|
return if n_idx <= 0
|
360
425
|
|
361
426
|
@index = n_idx
|
362
427
|
@active = 0
|
363
|
-
@visible = set_visible(data)
|
428
|
+
@visible = set_visible(data, maxy)
|
364
429
|
end
|
365
430
|
|
366
|
-
def cursor_down(data)
|
431
|
+
def cursor_down(data, maxy = nil)
|
432
|
+
maxy ||= window.maxy
|
367
433
|
@index += 1
|
368
|
-
@active = @active >=
|
369
|
-
@visible = set_visible(data)
|
434
|
+
@active = @active >= maxy - 1 ? @active : @active + 1
|
435
|
+
@visible = set_visible(data, maxy)
|
370
436
|
end
|
371
437
|
|
372
|
-
def cursor_pagedown(data)
|
373
|
-
|
438
|
+
def cursor_pagedown(data, maxy = nil)
|
439
|
+
maxy ||= window.maxy
|
440
|
+
n_idx = @index + maxy
|
374
441
|
return if n_idx >= data.length - 1
|
375
442
|
|
376
443
|
@index = n_idx
|
444
|
+
@active = 0
|
445
|
+
@visible = set_visible(data, maxy)
|
446
|
+
end
|
447
|
+
|
448
|
+
def cursor_jump(tabstop, data, rev: false)
|
449
|
+
@index = if rev
|
450
|
+
tabstop.filter{ |t| t < @index ? t : nil }.max || @index
|
451
|
+
else
|
452
|
+
tabstop.filter{ |t| t > @index ? t : nil }.min || @index
|
453
|
+
end
|
454
|
+
|
377
455
|
@active = 0
|
378
456
|
@visible = set_visible(data)
|
379
457
|
end
|
380
458
|
|
381
|
-
def cursor_last(data)
|
459
|
+
def cursor_last(data, maxy = nil)
|
460
|
+
maxy ||= window.maxy
|
382
461
|
@index = data.length - 1
|
383
|
-
@active =
|
384
|
-
@visible = set_visible(data)
|
462
|
+
@active = maxy - 1
|
463
|
+
@visible = set_visible(data, maxy)
|
385
464
|
end
|
386
465
|
|
387
|
-
def set_visible(data)
|
388
|
-
|
466
|
+
def set_visible(data, maxy = nil)
|
467
|
+
maxy ||= window.maxy
|
468
|
+
return data if data.nil? || data.length <= maxy
|
389
469
|
|
390
470
|
if @visible.nil?
|
391
|
-
data.slice(0,
|
471
|
+
data.slice(0, maxy)
|
392
472
|
else
|
393
|
-
if @active == (
|
394
|
-
data.slice(@index -
|
473
|
+
if @active == (maxy - 1)
|
474
|
+
data.slice(@index - maxy + 1, maxy)
|
395
475
|
elsif @active == 0
|
396
|
-
data.slice(@index,
|
476
|
+
data.slice(@index, maxy)
|
397
477
|
else
|
398
478
|
@visible
|
399
479
|
end
|
data/lib/luca_term/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lucaterm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chuma Takahiro
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-03-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: curses
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: lucarecord
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.3'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.3'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: bundler
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -96,7 +110,7 @@ dependencies:
|
|
96
110
|
version: 12.3.3
|
97
111
|
description: 'Terminal frontend for Luca Suite
|
98
112
|
|
99
|
-
'
|
113
|
+
'
|
100
114
|
email:
|
101
115
|
- co.chuma@gmail.com
|
102
116
|
executables:
|
@@ -116,7 +130,7 @@ metadata:
|
|
116
130
|
homepage_uri: https://github.com/chumaltd/luca/tree/master/lucaterm
|
117
131
|
source_code_uri: https://github.com/chumaltd/luca/tree/master/lucaterm
|
118
132
|
changelog_uri: https://github.com/chumaltd/luca/tree/master/lucaterm/CHANGELOG.md
|
119
|
-
post_install_message:
|
133
|
+
post_install_message:
|
120
134
|
rdoc_options: []
|
121
135
|
require_paths:
|
122
136
|
- lib
|
@@ -131,8 +145,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
145
|
- !ruby/object:Gem::Version
|
132
146
|
version: '0'
|
133
147
|
requirements: []
|
134
|
-
rubygems_version: 3.2.
|
135
|
-
signing_key:
|
148
|
+
rubygems_version: 3.2.5
|
149
|
+
signing_key:
|
136
150
|
specification_version: 4
|
137
151
|
summary: Terminal frontend for Luca Suite
|
138
152
|
test_files: []
|