add base.lua
authorPeng Wu <alexepico@gmail.com>
Mon, 21 Jun 2010 05:06:01 +0000 (13:06 +0800)
committerPeng Wu <alexepico@gmail.com>
Mon, 21 Jun 2010 05:06:01 +0000 (13:06 +0800)
lua/base.lua [new file with mode: 0644]

diff --git a/lua/base.lua b/lua/base.lua
new file mode 100644 (file)
index 0000000..898c65c
--- /dev/null
@@ -0,0 +1,912 @@
+-- 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", "显示日期", {}, {'日期'})