-- encoding: UTF-8 _CHINESE_DIGITS = { [0] = "〇", [1] = "一", [2] = "二", [3] = "三", [4] = "四", [5] = "五", [6] = "六", [7] = "七", [8] = "八", [9] = "九", [10] = "十", } _DATE_PATTERN = "^(%d+)-(%d+)-(%d+)$" _TIME_PATTERN = "^(%d+):(%d+)$" function GetChineseMathNum(num) local ret if num < 10 then ret = _CHINESE_DIGITS[num] elseif num < 20 then ret = _CHINESE_DIGITS[10] if num > 10 then ret = ret .. _CHINESE_DIGITS[num % 10] end elseif num < 100 then local mod = num % 10 ret = _CHINESE_DIGITS[(num - mod) / 10] .. _CHINESE_DIGITS[10] if mod > 0 then ret = ret .. _CHINESE_DIGITS[mod] end else error("Invalid number") end return ret end function GetChineseNonMathNum(num) local ret = "" for ch in tostring(num):gmatch(".") do if ch >= "0" and ch <= "9" then ch = _CHINESE_DIGITS[tonumber(ch)] end ret = ret .. ch end return ret end function _VerifyTime(hour, minute) if hour < 0 or hour > 23 or minute < 0 or minute > 59 then error("Invalid time") end end function _VerifyDate(month, day) if month < 1 or month > 12 or day < 1 or day > _MONTH_TABLE_LEAF[month] then error("Invalid date") end end function _VerifyDateWithYear(year, month, day) _VerifyDate(month, day) if year < 1 or year > 9999 then error("Invalid year") end if month == 2 and day == 29 then if year % 400 ~= 0 and year % 100 == 0 then error("Invalid lunar day") end if year % 4 ~= 0 then error("Invalid lunar day") end end end function GetChineseDate(y, m, d, full) if full then return GetChineseNonMathNum(y) .. "年" .. GetChineseMathNum(m) .. "月" .. GetChineseMathNum(d) .. "日" else return y .. "年" .. m .. "月" .. d .. "日" end end function GetChineseTime(h, m, full) if full then local ret = GetChineseMathNum(h) .. "时" if m > 0 then ret = ret .. GetChineseMathNum(m) .. "分" end return ret else return h .. "时" .. m .. "分" end end function NormalizeDate(y, m, d) return string.format("%d-%02d-%02d", y, m, d) end function NormalizeTime(h, m) return string.format("%02d:%02d", h, m) end function GetTime(input) local now = input if #input == 0 then now = os.date("%H:%M") end local hour, minute now:gsub(_TIME_PATTERN, function(h, m) hour = tonumber(h) minute = tonumber(m) end) _VerifyTime(hour, minute) return { NormalizeTime(hour, minute), GetChineseTime(hour, minute, false), GetChineseTime(hour, minute, true), } end function GetDate(input) local now = input if #input == 0 then now = os.date("%Y-%m-%d") end local year, month, day now:gsub(_DATE_PATTERN, function(y, m, d) year = tonumber(y) month = tonumber(m) day = tonumber(d) end) _VerifyDateWithYear(year, month, day) return { NormalizeDate(year, month, day), GetChineseDate(year, month, day, false), GetChineseDate(year, month, day, true), } end ---------------------------------- _MATH_KEYWORDS = { "abs", "acos", "asin", "atan", "atan2", "ceil", "cos", "cosh", "deg", "exp", "floor", "fmod", "frexp", "ldexp", "log", "log10", "max", "min", "modf", "pi", "pow", "rad", "random", "randomseed", "sin", "sinh", "sqrt", "tan", "tanh", } function _AddMathKeyword(input) local ret = input for _, keyword in pairs(_MATH_KEYWORDS) do ret = ret:gsub(string.format("([^%%a\.])(%s\(.-\))", keyword), "%1math\.%2") ret = ret:gsub(string.format("^(%s\(.-\))", keyword), "math\.%1") end return ret end function Compute(input) local expr = "return " .. _AddMathKeyword(input) local func = loadstring(expr) if func == nil then return "-- 未完整表达式 --" end local ret = func() if ret == math.huge then -- div/0 return "-- 计算错误 --" end if ret ~= ret then -- We rely on the property that NaN is the only value not equal to itself. return "-- 计算错误 --" end return ret end ---------------------------------- _TO_BE_REPLACED_FLAG = "#TO_BE_REPLACED#" _ASCII_IMAGE_TABLE = { ["birthday"] = { [[ .......................................................................... H A P P Y B I R T H D A Y #TO_BE_REPLACED# ! .......................................................................... .....................**............................*...................... .....................++..............**..........*+.*..................... ...................*+*+..............**..........*++*..................... .................*+***++*............*+........*.*.*++*................... .................**..*+*.*..........*+.......*..*+.*.**................... ................+*.**++**+*........*+*+*.....*.*+**+***................... ................+**+*.*+**+*.....*+*.*++*.....**+**++*.................... .................**++**+*++*....**..*++.*+.....**+..+*.................... ..................*+++.++*......+*.*+***.+.......*.+..**.................. .............********..*.***...*.**+*.*+**.....+*+..****.................. ............*+*...****...+*....*+++++**++.....********.................... .............++....***+++**....+.*******....****...*******................ ..............*+*........*+******+***..****.**+.......*+**................ ..............*+*..........+++...***+.#+**...*+*.......+*................. ..............*+*..........+**+*.....**+++*..++.........++................ ..............*+*..........**.*+*........*+*..*+*......*+**............... ..............*+*............+++*..........**.*+*........*++.............. ..............*+*............+++*...........*+*..........*++.............. ...........***+.*............+++*...........*+*..........*+***............ .......******.*+*............+++*...........*+*..........*+*.++*.......... ......***......++...........*+*+*...........*++*************...**++....... ....*+*.**......***************+*...........*+*********....*.....***...... ....++...*+**.................*+*...........*+*............*....**.**..... ...*+*.....*******.............*+*..........*+*....**********.***...**.... ...*+*...*......************....*************...**..........****......*... ...++....*******.......***+++*********************************.......**... ..++.....++...*+*......*+***+*..........*********..........**...*..*..*... ..+*....*+*...*+......*+....*+*.......*+**.....*+*........**.....*+**++... ....*+.....**+.......**.....**........**........+*........**.......**+*... ...*.+......*+***.*****.....*+......***.........+*........+*.......*+**... ...*.+........******.........*********..........****..*****......***+*.... ....*.*.....................................................**....*+...... ....**+*...................................................+*****+*....... ........**++......................................*++*....*++*............ ........*+******...............................*************.............. ...............****++*###*******###########*****++........................ .......................................................................... ]], "生日蛋糕"}, ["search"] = { [[            --\--+--/--             { o_o } ┏━━━━━━━━━━oOo━(__)━oOo━┓  #TO_BE_REPLACED# ┗━━━━━━━━━━━━━━━━━━┛    ┏━━━━┓  ┏━━━━┓    ┃ 搜索 ┃  ┃手气不错┃    ┗━━━━┛  ┗━━━━┛ ]], "搜索"}, } function PrintAscii(input) if #input <= 0 then local metatables = {} for k, v in pairs(_ASCII_IMAGE_TABLE) do table.insert(metatables, {["suggest"] = k, ["help"] = v[2]}) end return metatables elseif _ASCII_IMAGE_TABLE[input] then local result = _ASCII_IMAGE_TABLE[input][1] local last_commit = ime.get_last_commit() if #last_commit <= 0 or #last_commit > 20 then last_commit = "" end return result:gsub(_TO_BE_REPLACED_FLAG, last_commit) else error("Invalid argument") end end ---------------------------------- -- Bitmaps table used for ascii_large_letters(), in 5x7 bitmaps. _LARGE_LETTER_BITMAPS = { [","] = [[ ,, , , ]], ["-"] = [[ ----- ]], ["."] = [[ .. .. ]], ["0"] = [[ 000 0 0 0 0 0 0 0 0 0 0 000 ]], ["1"] = [[ 1 111 1 1 1 1 11111 ]], ["2"] = [[ 222 2 2 2 2 2 2 22222 ]], ["3"] = [[ 333 3 3 3 33 3 3 3 333 ]], ["4"] = [[ 4 44 4 4 4 4 44444 4 444 ]], ["5"] = [[ 55555 5 5555 5 5 5 5 555 ]], ["6"] = [[ 66 6 6 6666 6 6 6 6 666 ]], ["7"] = [[ 77777 7 7 7 7 7 7 7 ]], ["8"] = [[ 888 8 8 8 8 888 8 8 8 8 888 ]], ["9"] = [[ 999 9 9 9 9 9999 9 9 99 ]], ["A"] = [[ A A A A A A AAAAA A A A A ]], ["B"] = [[ BBBB B B B B BBBB B B B B BBBB ]], ["C"] = [[ CCC C C C C C C C CCC ]], ["D"] = [[ DDD D D D D D D D D D D DDD ]], ["E"] = [[ EEEEE E E EEEE E E EEEEE ]], ["F"] = [[ FFFFF F F FFFF F F F ]], ["G"] = [[ GGG G G G G GG G G G G GGG ]], ["H"] = [[ H H H H H H HHHHH H H H H H H ]], ["I"] = [[ IIIII I I I I I IIIII ]], ["J"] = [[ JJJJJ J J J J J JJ ]], ["K"] = [[ K K K K K K KK K K K K K K ]], ["L"] = [[ L L L L L L LLLLL ]], ["M"] = [[ M M MMM MMM MMM M M M M M M M M ]], ["N"] = [[ N N N N NN N N N N N NN N N N N ]], ["O"] = [[ OOO O O O O O O O O O O OOO ]], ["P"] = [[ PPPP P P P P PPPP P P P ]], ["Q"] = [[ QQQ Q Q Q Q Q Q Q Q Q Q Q Q QQQQ ]], ["R"] = [[ RRRR R R R R RRRR R R R R R R ]], ["S"] = [[ SSS S S S SSS S S S SSS ]], ["T"] = [[ TTTTT T T T T T T ]], ["U"] = [[ U U U U U U U U U U U U UUU ]], ["V"] = [[ V V V V V V V V V V V V V ]], ["W"] = [[ W W W W W W W W WWW WWW WWW W W ]], ["X"] = [[ X X X X X X X X X X X X X ]], ["Y"] = [[ Y Y Y Y Y Y Y Y Y Y ]], ["Z"] = [[ ZZZZZ Z Z Z Z Z ZZZZZ ]], } -- Converts input string to ascii image of large letters. function PrintLetter(input_string) if #input_string == 0 then return {} end local letter_width = 5 local letter_height = 7 local max_string_length = 16 local result_lines = {} for i = 1, letter_height do result_lines[i] = "" end input_string = input_string:upper() -- Limits the input string size. input_string = input_string:sub(1, max_string_length) -- Only interate on valid characters. for c in input_string:gmatch("[0-9A-Z ,.-]") do local letter = _LARGE_LETTER_BITMAPS[c] -- Splits the letter bitmap into lines and appends each line to the -- corresponding line of the result. local lines = ime.split_string(letter, "\n") for i, line in ipairs(lines) do if i > letter_height then break end for i = 1, letter_width - #line do line = line .. ' ' end result_lines[i] = result_lines[i] .. line .. ' ' end end -- Merges result lines. for i, line in ipairs(result_lines) do result_lines[i] = ime.trim_string_right(result_lines[i]) end local result = "\n" .. ime.join_string(result_lines, "\n") .. "\n" return result end -- Dice images. _DICE_BITMAPS = { [[ /---------\ | | | | | (O) | | | | | \---------/ ]], [[ /---------\ | | | @ | | | | @ | | | \---------/ ]], [[ /---------\ | | | @ | | @ | | @ | | | \---------/ ]], [[ /---------\ | | | @ @ | | | | @ @ | | | \---------/ ]], [[ /---------\ | | | @ @ | | @ | | @ @ | | | \---------/ ]], [[ /---------\ | | | @ @ | | @ @ | | @ @ | | | \---------/ ]], } math.randomseed(os.time()) -- Plays and shows n dices. function PlayDice(n) n = math.min(n, 6) n = math.max(n, 1) local dice_height = 7 local result_lines = {} for i = 1, dice_height do result_lines[i] = "" end for i = 1, n do local index = math.random(1, 6) local dice = _DICE_BITMAPS[index] -- Splits the dice bitmap into lines and appends each line to the -- corresponding line of the result. local lines = ime.split_string(dice, "\n") for i, line in ipairs(lines) do if i > dice_height then break end result_lines[i] = result_lines[i] .. line .. ' ' end end -- Merges result lines. for i, line in ipairs(result_lines) do result_lines[i] = ime.trim_string_right(result_lines[i]) end local result = "\n" .. ime.join_string(result_lines, "\n") .. "\n" return result end -------------------------- _ZODIAC_TABLE = { [{3, 21, 4, 19}] = "白羊座(Aries) ♈", [{4, 20, 5, 20}] = "金牛座(Taurus) ♉", [{5, 21, 6, 21}] = "双子座(Gemini) ♊", [{6, 22, 7, 22}] = "巨蟹座(Cancer) ♋", [{7, 23, 8, 22}] = "狮子座(Leo) ♌", [{8, 23, 9, 23}] = "处女座(Virgo) ♍", [{9, 24, 10, 23}] = "天秤座(Libra) ♎", [{10, 24, 11, 21}] = "天蝎座(Scorpio) ♏", [{11, 22, 12, 21}] = "射手座(Sagittarius) ♐", [{12, 22, 12, 31}] = "摩羯座(Capricorn) ♑", [{1, 1, 1, 19}] = "摩羯座(Capricorn) ♑", [{1, 20, 2, 18}] = "水瓶座(Aquarius) ♒", [{2, 19, 3, 20}] = "双鱼座(Pisces) ♓", } _MONTH_TABLE_NORMAL = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } _MONTH_TABLE_LEAF = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } function _CompareMonthAndDay(month1, day1, month2, day2) if month1 < month2 then return -1 elseif month1 > month2 then return 1 elseif day1 < day2 then return -1 elseif day1 > day2 then return 1 else return 0 end end -- birthday is a string in MM-DD format. function QueryZodiac(birthday) local month = 0 local day = 0 birthday:gsub("([0-9]+)-([0-9]+)$", function(m, d) month = tonumber(m) day = tonumber(d) end ) _VerifyDate(month, day) for range, name in pairs(_ZODIAC_TABLE) do local from_month = range[1] local from_day = range[2] local to_month = range[3] local to_day = range[4] if _CompareMonthAndDay(month, day, from_month, from_day) >=0 and _CompareMonthAndDay(month, day, to_month, to_day) <=0 then return name end end error("Should never reach here") end ----- -- Print Chinese manuscript grids. width_and_height in "WxH" format. -- ┏━━━━━━━━━┓ -- ┣━┳━┳━┳━┳━┫ -- ┃ ┃ ┃ ┃ ┃ ┃ -- ┣━┻━┻━┻━┻━┫ -- ┣━┳━┳━┳━┳━┫ -- ┃ ┃ ┃ ┃ ┃ ┃ -- ┣━┻━┻━┻━┻━┫ -- ┣━┳━┳━┳━┳━┫ -- ┃ ┃ ┃ ┃ ┃ ┃ -- ┣━┻━┻━┻━┻━┫ -- ┗━━━━━━━━━┛ function PrintGaozhi(width_and_height) local width local height width_and_height:gsub("([0-9]+)[x%*]([0-9]+)$", function(w, h) width = w height = h end ) width = math.min(width, 20) width = math.max(width, 1) height = math.min(height, 20) height = math.max(height, 1) local result = "\n" local print_line = function(leading, middle, middle_repeat, ending) result = result .. leading for i = 1, middle_repeat do result = result .. middle end result = result .. ending result = result .. "\n" end print_line("┏", "━", width * 2 - 1, "┓") for i = 1, height do print_line("┣", "━┳", width - 1, "━┫") print_line("┃", " ┃", width, "") print_line("┣", "━┻", width - 1, "━┫") end print_line("┗", "━", width * 2 - 1, "┛") return result .. "\n" end function GetCurrentTime() return GetTime("") end function GetToday() return GetDate("") end ------------ ime.register_command("sj", "GetTime", "输入时间", "alpha", "输入可选时间,例如12:34") ime.register_command("rq", "GetDate", "输入日期", "alpha", "输入可选日期,例如2008-08-08") ime.register_command("js", "Compute", "计算模式", "none", "输入表达式,例如3*log(4+2)") ime.register_command("gz", "PrintGaozhi", "打印稿纸", "none", "输入稿纸大小,例如2x3") ime.register_command("xz", "QueryZodiac", "查询星座", "none", "输入您的生日,例如12-14") ime.register_command("sz", "PlayDice", "掷骰子", "none", "输入骰子个数,例如3") ime.register_command("zf", "PrintLetter", "打印字符", "none", "请输入字母或数字序列,例如hello") ime.register_command("hh", "PrintAscii", "画画") ime.register_trigger("GetCurrentTime", "显示时间", {}, {'时间'}) ime.register_trigger("GetToday", "显示日期", {}, {'日期'})