function abook#sum() let l:st = getpos("'<")[1] let l:ed = getpos("'>")[1] + 1 let l:curs = {} let l:wals = {} let l:lnum = l:st while l:lnum < l:ed let [l:record, l:lines] = s:next_record(l:lnum) if 0 == l:lines let l:lnum += 1 continue endif let [l:record_curs, l:record_wals] = s:sum(l:record) for l:cur in keys(l:record_curs) let l:curs = s:extend_or_sum(l:curs, l:cur, l:record_curs[l:cur]) endfor for l:wal in keys(l:record_wals) let l:wals = s:extend_or_sum(l:wals, l:wal, l:record_wals[l:wal]) endfor let l:lnum += l:lines endwhile echo l:curs echo l:wals endfunction function abook#tax(rate) let l:lnum = getcurpos()[1] let [l:record, l:lines] = s:next_record(l:lnum) if 0 == l:lines return endif let l:record = s:multiply(l:record, a:rate) let l:record = split(l:record, "\n", 1) for l:line in l:record[:-2] call setline(l:lnum, l:line) let l:lnum += 1 endfor endfunction function s:sum(src) let l:idx = 0 let l:cur = "" let l:wal = "" let l:curs = {} let l:wals = {} while 1 let [l:token, l:idx] = s:next_token(a:src, l:idx) if l:token == "" return [l:curs, l:wals] endif if l:cur != "" let l:price = str2float(l:token) let l:curs = s:extend_or_sum(l:curs, l:cur, l:price) let l:wals = s:extend_or_sum(l:wals, l:wal, l:price) let l:cur = "" let l:wal = "" elseif stridx(l:token, "@") >= 0 let l:cur = split(l:token, "@")[0] let l:wal = l:token endif endwhile endfunction function s:multiply(src, rate) let l:expect_price = 0 let l:idx = 0 let l:offset = 0 let l:dst = a:src while 1 let [l:token, l:idx] = s:next_token(a:src, l:idx) if l:token == "" return l:dst endif let l:st = l:idx - len(l:token) let l:ed = l:idx if l:expect_price let l:old_price = str2float(l:token) let l:new_price = floor(l:old_price * a:rate) let l:new_price = printf("%.0f", l:new_price) let l:st += l:offset let l:ed += l:offset let l:dst = l:dst[0:l:st-1] . l:new_price . l:dst[l:ed:] let l:offset += len("".l:new_price) - len(l:token) let l:expect_price = 0 else let l:expect_price = stridx(l:token, "@") >= 0 endif endwhile endfunction function s:next_token(str, idx) let l:st = a:idx while l:st < len(a:str) && stridx(" \t\n", a:str[l:st]) >= 0 let l:st += 1 endwhile let l:ed = l:st while l:ed < len(a:str) && stridx(" \t\n", a:str[l:ed]) < 0 let l:ed += 1 endwhile return [a:str[l:st:l:ed-1], l:ed] endfunction function s:next_record(st) let l:st = a:st let l:ed = l:st let l:record = "" while 1 let l:curr = l:ed let l:line = getline(l:ed) let l:ed += 1 if l:line[0] == "#" continue endif let l:break = stridx("0123456789", l:line[0]) >= 0 if l:st == l:curr && !l:break return ["", 0] endif if l:st < l:curr && l:break return [l:record, l:ed-l:st-1] endif let l:record .= l:line . "\n" endwhile endfunction function s:extend_or_sum(dic, key, num) if has_key(a:dic, a:key) let a:dic[a:key] += a:num return a:dic else return extend(a:dic, {a:key: a:num}) endif endfunction