1--
2-- SPDX-FileCopyrightText: 2010 Peng Wu <alexepico@gmail.com>
3-- SPDX-FileCopyrightText: 2020 Weng Xuetian <wengxt@gmail.com>
4--
5-- SPDX-License-Identifier: GPL-2.0-or-later
6--
7---- encoding: UTF-8
8local fcitx = require("fcitx")
9
10local _CHINESE_DIGITS = {
11  [0] = "〇",
12  [1] = "一",
13  [2] = "二",
14  [3] = "三",
15  [4] = "四",
16  [5] = "五",
17  [6] = "六",
18  [7] = "七",
19  [8] = "八",
20  [9] = "九",
21  [10] = "十",
22}
23local _DATE_PATTERN = "^(%d+)-(%d+)-(%d+)$"
24local _TIME_PATTERN = "^(%d+):(%d+)$"
25local _MONTH_TABLE_LEAF = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
26
27local function get_chinese_math_num(num)
28  local ret
29    if num < 10 then
30        ret = _CHINESE_DIGITS[num]
31    elseif num < 20 then
32        ret = _CHINESE_DIGITS[10]
33        if num > 10 then
34            ret = ret .. _CHINESE_DIGITS[num % 10]
35        end
36    elseif num < 100 then
37        local mod = num % 10
38        ret = _CHINESE_DIGITS[(num - mod) / 10] .. _CHINESE_DIGITS[10]
39        if mod > 0 then
40            ret = ret .. _CHINESE_DIGITS[mod]
41        end
42    else
43        error("Invalid number")
44    end
45    return ret
46end
47
48local function get_chinese_non_math_num(num)
49    local ret = ""
50    for ch in tostring(num):gmatch(".") do
51        if ch >= "0" and ch <= "9" then
52            ch = _CHINESE_DIGITS[tonumber(ch)]
53        end
54        ret = ret .. ch
55    end
56    return ret
57end
58
59local function _verify_time(hour, minute)
60    if hour < 0 or hour > 23 or minute < 0 or minute > 59 then
61        error("Invalid time")
62    end
63end
64
65local function _verify_date(month, day)
66    if month < 1 or month > 12 or day < 1 or day > _MONTH_TABLE_LEAF[month] then
67        error("Invalid date")
68    end
69end
70
71local function _verify_date_with_year(year, month, day)
72    _verify_date(month, day)
73    if year < 1 or year > 9999 then
74        error("Invalid year")
75    end
76    if month == 2 and day == 29 then
77        if year % 400 ~= 0 and year % 100 == 0 then
78            error("Invalid lunar day")
79        end
80        if year % 4 ~= 0 then
81            error("Invalid lunar day")
82        end
83    end
84end
85
86local function get_chinese_date(y, m, d, full)
87    if full then
88        return get_chinese_non_math_num(y) .. "年" ..
89               get_chinese_math_num(m) .. "月" ..
90               get_chinese_math_num(d) .. "日"
91    else
92        return y .. "年" .. m .. "月" .. d .. "日"
93    end
94end
95
96local function get_chinese_time(h, m, full)
97    if full then
98        local ret = get_chinese_math_num(h) .. "时"
99        if m > 0 then
100            ret = ret .. get_chinese_math_num(m) .. "分"
101        end
102        return ret
103    else
104        return h .. "时" .. m .. "分"
105    end
106end
107
108local function normalize_date(y, m, d)
109    return string.format("%d-%02d-%02d", y, m, d)
110end
111
112local function normalize_time(h, m)
113    return string.format("%02d:%02d", h, m)
114end
115
116function pinyin_get_time(input)
117    if fcitx.currentInputMethod() ~= "pinyin" and fcitx.currentInputMethod() ~= "shuangpin"  then
118        return nil
119    end
120
121    local now = input
122    if #input == 0 then
123        now = os.date("%H:%M")
124    end
125    local hour, minute
126    now:gsub(_TIME_PATTERN, function(h, m)
127        hour = tonumber(h)
128        minute = tonumber(m)
129    end)
130    _verify_time(hour, minute)
131    return {
132        normalize_time(hour, minute),
133        get_chinese_time(hour, minute, false),
134        get_chinese_time(hour, minute, true),
135    }
136end
137
138function pinyin_get_date(input)
139    if fcitx.currentInputMethod() ~= "pinyin" and fcitx.currentInputMethod() ~= "shuangpin"  then
140        return nil
141    end
142
143    local now = input
144    if #input == 0 then
145        now = os.date("%Y-%m-%d")
146    end
147    local year, month, day
148    now:gsub(_DATE_PATTERN, function(y, m, d)
149        year = tonumber(y)
150        month = tonumber(m)
151        day = tonumber(d)
152    end)
153    _verify_date_with_year(year, month, day)
154    return {
155        normalize_date(year, month, day),
156        get_chinese_date(year, month, day, false),
157        get_chinese_date(year, month, day, true),
158    }
159end
160
161function pinyin_get_current_time()
162    return pinyin_get_time("")
163end
164
165function pinyin_get_today()
166    return pinyin_get_date("")
167end
168
169local _MATH_SYMBOL = {
170"+",
171"-",
172"<",
173"=",
174">",
175"±",
176"×",
177"÷",
178"∈",
179"∏",
180"∑",
181"∕",
182"√",
183"∝",
184"∞",
185"∟",
186"∠",
187"∣",
188"∥",
189"∧",
190"∨",
191"∩",
192"∪",
193"∫",
194"∮",
195"∴",
196"∵",
197"∶",
198"∷",
199"∽",
200"≈",
201"≌",
202"≒",
203"≠",
204"≡",
205"≤",
206"≥",
207"≦",
208"≧",
209"≮",
210"≯",
211"⊕",
212"⊙",
213"⊥",
214"⊿",
215}
216
217local _ROMAN_NUMBER = {
218"ⅰ",
219"ⅱ",
220"ⅲ",
221"ⅳ",
222"ⅴ",
223"ⅵ",
224"ⅶ",
225"ⅷ",
226"ⅸ",
227"ⅹ",
228"ⅰ",
229"ⅱ",
230"ⅲ",
231"ⅳ",
232"ⅴ",
233"ⅵ",
234"ⅶ",
235"ⅷ",
236"ⅸ",
237"ⅹ",
238}
239
240local _UPPER_GREEK_LETTER = {
241"Α",
242"Β",
243"Γ",
244"Δ",
245"Ε",
246"Ζ",
247"Η",
248"Θ",
249"Ι",
250"Κ",
251"Λ",
252"Μ",
253"Ν",
254"Ξ",
255"Ο",
256"Π",
257"Ρ",
258"Σ",
259"Τ",
260"Υ",
261"Φ",
262"Χ",
263"Ψ",
264"Ω",
265}
266
267local _LOWER_GREEK_LETTER = {
268"α",
269"β",
270"γ",
271"δ",
272"ε",
273"ζ",
274"η",
275"θ",
276"ι",
277"κ",
278"λ",
279"μ",
280"ν",
281"ξ",
282"ο",
283"π",
284"ρ",
285"σ",
286"τ",
287"υ",
288"φ",
289"χ",
290"ψ",
291"ω",
292}
293
294local _UPPER_RUSSIAN_LETTER = {
295"А",
296"Б",
297"В",
298"Г",
299"Д",
300"Е",
301"Ж",
302"З",
303"И",
304"Й",
305"К",
306"Л",
307"М",
308"Н",
309"О",
310"П",
311"Р",
312"С",
313"Т",
314"У",
315"Ф",
316"Х",
317"Ц",
318"Ч",
319"Ш",
320"Щ",
321"Ъ",
322"Ы",
323"Ь",
324"Э",
325"Ю",
326"Я",
327"Ё",
328}
329
330local _LOWER_RUSSIAN_LETTER = {
331"а",
332"б",
333"в",
334"г",
335"д",
336"е",
337"ж",
338"з",
339"и",
340"й",
341"к",
342"л",
343"м",
344"н",
345"о",
346"п",
347"р",
348"с",
349"т",
350"у",
351"ф",
352"х",
353"ц",
354"ч",
355"ш",
356"щ",
357"ъ",
358"ы",
359"ь",
360"э",
361"ю",
362"я",
363"ё",
364}
365
366local _NUMBER_SYMBOL = {
367"①",
368"②",
369"③",
370"④",
371"⑤",
372"⑥",
373"⑦",
374"⑧",
375"⑨",
376"⑩",
377"⑴",
378"⑵",
379"⑶",
380"⑷",
381"⑸",
382"⑹",
383"⑺",
384"⑻",
385"⑼",
386"⑽",
387"⑾",
388"⑿",
389"⒀",
390"⒁",
391"⒂",
392"⒃",
393"⒄",
394"⒅",
395"⒆",
396"⒇",
397"⒈",
398"⒉",
399"⒊",
400"⒋",
401"⒌",
402"⒍",
403"⒎",
404"⒏",
405"⒐",
406"⒑",
407"⒒",
408"⒓",
409"⒔",
410"⒕",
411"⒖",
412"⒗",
413"⒘",
414"⒙",
415"⒚",
416"⒛",
417"㈠",
418"㈡",
419"㈢",
420"㈣",
421"㈤",
422"㈥",
423"㈦",
424"㈧",
425"㈨",
426"㈩",
427}
428
429local _CURRENCY_SYMBOL = {
430"$",
431"¢",
432"£",
433"¥",
434"¤",
435}
436
437local _ARROW_SYMBOL = {
438"←",
439"↑",
440"→",
441"↓",
442"↖",
443"↗",
444"↘",
445"↙",
446}
447
448function pinyin_get_symbol(input)
449    if fcitx.currentInputMethod() ~= "pinyin" and fcitx.currentInputMethod() ~= "shuangpin"  then
450        return nil
451    end
452
453    if input == "" then
454        return {
455            {suggest="sx", help="数学符号"},
456            {suggest="lmsz", help="罗马数字"},
457            {suggest="dxxl", help="大写希腊"},
458            {suggest="xxxl", help="小写希腊"},
459            {suggest="dxew", help="大写俄文"},
460            {suggest="xxew", help="小写俄文"},
461            {suggest="sz", help="数字符号"},
462            {suggest="hb", help="货币"},
463            {suggest="jt", help="箭头"},
464        }
465    elseif input == "sx" then
466        return _MATH_SYMBOL
467    elseif input == "lmsz" then
468        return _ROMAN_NUMBER
469    elseif input == "dxxl" then
470        return _UPPER_GREEK_LETTER
471    elseif input == "xxxl" then
472        return _LOWER_GREEK_LETTER
473    elseif input == "dxew" then
474        return _UPPER_RUSSIAN_LETTER
475    elseif input == "xxew" then
476        return _LOWER_RUSSIAN_LETTER
477    elseif input == "sz" then
478        return _NUMBER_SYMBOL
479    elseif input == "hb" then
480        return _CURRENCY_SYMBOL
481    elseif input == "jt" then
482        return _ARROW_SYMBOL
483    end
484    return nil
485end
486
487------------
488ime.register_command("fh", "pinyin_get_symbol", "输入符号", "digit", "")
489
490ime.register_command("sj", "pinyin_get_time", "输入时间", "alpha", "输入可选时间,例如12:34")
491ime.register_command("rq", "pinyin_get_date", "输入日期", "alpha", "输入可选日期,例如2013-01-01")
492ime.register_trigger("pinyin_get_current_time", "显示时间", {}, {'时间'})
493ime.register_trigger("pinyin_get_today", "显示日期", {}, {'日期'})
494