KEEP K.I.S.S.

tk's blog

无聊写的谷歌拼音颜文字扩展

谷歌输入法的颜文字扩展已经有好多了,反正也不差我再写一个吧 o(* ̄▽ ̄*)o ,表情比较多(300+)

源码和扩展文件都放在 Github 上了:https://github.com/tisyang/kaos

示例1:

示例2:

 

安装方法:
在谷歌输入法设置的 扩展 页面,选择 安装扩展包 ,选择下载的 kaos.lua 文件即可。
安装后需要重启输入法,也就是关闭输入法然后再开启。
 
 
 
更新历史:
      2. 当一个拼音对应多个表情时,现在可以随机返回其中的一个,2012-06-06
      1. 修正潜在的 Lua 关键字冲突问题,2012-06-05
 
已知问题:
      1. 候选的表情总是在候选列表最后,这是谷歌输入法本身的设置所致
      2. 某些拼音对应多个表情,但是目前谷歌输入法只能显示第一个

 

用 C 扩展写 Lua closure

这个是《programming in lua》中的有的一个例子,通过 closure(闭包)来实现一个 tuple(元组)。

元组是一种具有匿名字段的常量记录。可以用一个数字索引来检索某个字段,或者一次性检索所有字段。

这里的实现将元组表示为函数,元组的值存放在函数绑定的 upvalue 中。大概的 Lua 代码示意如下:

local tuple = {}
function tuple.new(...)
    local t = {...}
    return function(index)
        if index then
            if type(index) ~= "number" then error("invalid index type") end
            if index < 0 then error("index is out of range") end
            return t[index]            
        else
            return unpack(t)
        end
    end
end

闭包工厂 tuple.new 中的 table t 就是用于存放元组内容的 upvalue,这个 tuple 的使用如下:

local x = tuple.new(10, "hi", {}, 4)
print(x(1))
print(x(2))
print(x())

当用一个数字参数来调用此函数时,它会返回指定的字段。当不用参数来调用此函数时,则返回所有的字段。输出为:

10
hi
10 hi table: 0041B870 4
 
下面使用 Lua 的 C 扩展来实现这个 tuple:
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

static int
t_tuple(lua_State *L) 
{
    int op = luaL_optint(L, 1, 0);
    if (op == 0) { /* 无参数? */
        int i;
        /* 将所有合法 upvalue 压入栈中 */
        for (i = 1; !lua_isnone(L, lua_upvalueindex(i)); i++)
            lua_pushvalue(L, lua_upvalueindex(i));

        return i - 1; /* 栈中值的数量 */
    }
    else { /* 获取 'op' 字段 */
        luaL_argcheck(L, 0 < op, 1, "index out of range");
        if (lua_isnone(L, lua_upvalueindex(op))) { /* 无此字段 */
            lua_pushnil(L);  /* 返回 nil 表明不存在 */
            return 1;
        }
        lua_pushvalue(L, lua_upvalueindex(op));
        return 1;
    }
}

static int 
t_new(lua_State *L)
{
    lua_pushcclosure(L, t_tuple, lua_gettop(L));
    return 1;
}

static const struct luaL_Reg tuplelib[] = {
    {"new", t_new},
    {NULL, NULL}
};

int luaopen_tuple(lua_State *L)
{
    luaL_register(L, "tuple", tuplelib);
    return 1;
}

编译成“tuple.dll”(windows 下)然后仍然用上面的 tuple 使用代码测试,不过要先“require 'tuple'”来加载这个扩展。DLL 中的需要导出 lutopen_tuple 这个函数符号。

t_new 是创建元组的工厂函数。将需要作为 upvalue 的参数实现压入栈中,然后调用 lua_pushcclosure 来创建一个基于 t_tuple 的 closure 。lua_gettop 返回栈的大小,在这里也就等于已经压入栈中作为 upvalue 的数量。lua_upvalueindex 是一个用来索引 upvalue 的宏,当索引一个不存在的 upvalue ,结果会是一个类型为 LUA_TNONE 的伪值(pseudo-value),当索引超出当前栈范围时候,也会得到这样的 LUA_TNONE 的伪值。不能以负数来调用 lua_upvalueindex ,所以做了范围检查,luaL_argcheck(L, 0 < op, 1, "index out of range") 第二个参数是个条件表达式,第三个是检查的参数数量,最后一个是检查失败传递的消息。

用于检测可选参数的函数是 luaL_optint ,它允许参数不存在,如果不存在,则返回一个指定的默认值,也就是最后一个参数。

给 lua 写 C 模块示例

主要内容出在《programming in lua》第二版 26章

本例是在 VS2008下,配合 lua on windows 包内的 lua 库使用。

1. 配置好 VS 的lua 环境,主要是引用的头文件目录,库目录,然后将 dll 加入 path 环境。

2. 新建一个 Win32 DLL 空项目(例如 "l_lib",这也是本例所提供的模块名),配置项目 链接器》输入》附加依赖库:lua5.1.lib

3. 添加一个 C 源文件:

#include <math.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

static int l_sin(lua_State *L) 
{
    double d = luaL_checknumber(L, 1);
    lua_pushnumber(L, sin(d));
    return 1;
}

static const struct luaL_Reg l_lib[] = {
    {"l_sin", l_sin},
    {NULL, NULL}
};

int luaopen_l_lib(lua_State *L)
{
    luaL_register(L, "l_lib", l_lib);
    return 1;
} 

4. 给项目添加一个模块定义文件(.def),用于导出dll 符号:

    LIBRARY "l_lib"
    EXPORTS
        luaopen_l_lib
 
5. 编译生成: l_lib.dll
​6. 编写一个测试的 lua 文件,与生成的 dll 在同一目录:
require 'l_lib'
print(l_lib.l_sin(1)) 
 
运行如果没有报错说明一切OK
 
------------------------------------- 分割线 ----------------------------------
如果只是给个步骤不给解释是不好玩的。
所有注册到 Lua 中的函数都具有相同的原型,该原型就是定义在 lua.h 中的 lua_CFunction:
typedef int (*lua_CFunction)(lua_State *L);
从 C 语言的观点来看,这个 C 函数仅有一个参数,即 Lua 的状态。它返回一个整数,表示其压入栈中的返回值数量。因此,这个函数无须在压入结果前清空栈。在它返回后,Lua 会自动删除栈中结果之下的内容。
上面C文件里的 l_sin 函数就是我们要提供的模块内部函数,其原型与 lua_CFunction 一致。
 
lua_open_l_lib 是模块被 require 时调用的函数,是一个模块的主函数,它的原型也是与 lua_CFunction 一致,它的职责是注册模块中所有的 C 函数,并且还应初始化模块中所有需要初始化的东西。这个函数的名字是特定的,与模块名称有关。
 
luaL_Reg 结构数组是包含模块中所有函数以及名称的容器,luaL_Reg 结构有两个字段,一个函数名字符串(提供给调用模块的用户)以及一个函数指针。该数组中最后一个元素总是 {NULL, NULL} 以此标识结尾。该结构体是在辅助库内定义的。
 
模块主函数中调用了辅助库的 luaL_register 用于注册模块,它根据给定的名称("l_lib")创建一个table,并用数组 l_lib 中的信息填充这个table。在luaL_register 返回时,它会把这个table留在栈中。最后主函数返回1,表示将这个table返回给Lua。
 
通常一个模块只有一个公共函数,就是模块主函数,其他函数都应该是私有的,在 C 中就是 static。

 

lua 之爱

《programming in lua》第二版的中文版这本书快看完了,中间夹杂着英文版的看,因为翻译并非完美,而且英文版的也很容易看懂。

这里是我的读书笔记:http://book.douban.com/people/tisyang/annotation/3076942/ 但并非每个要点都会有笔记。

lua 是一个值得学习的语言而且也不会需要过多时间,这本书是学 lua 一定要看的,云风 大神也这样推荐

愈学愈爱