-- Copyright 2007-2014 Mitchell mitchell.att.foicica.com. See LICENSE. local M = {} --[[ This comment is for LuaDoc. --- -- The ansi_c module. -- It provides utilities for editing C code. -- -- ## Key Bindings -- -- + `Ctrl+L, M` (`⌘L, M` on Mac OSX | `M-L, M` in curses) -- Open this module for editing. -- + `Shift+Enter` (`⇧↩` | `S-Enter`) -- Add ';' to the end of the current line and insert a newline. module('_M.ansi_c')]] -- Autocompletion and documentation. --- -- List of ctags files to use for autocompletion in addition to the current -- project's top-level *tags* file or the current directory's *tags* file. -- @class table -- @name tags M.tags = {_HOME..'/modules/ansi_c/tags', _USERHOME..'/modules/ansi_c/tags'} local XPM = textadept.editing.XPM_IMAGES local xpms = setmetatable({ c = XPM.CLASS, d = XPM.SLOT, e = XPM.VARIABLE, f = XPM.METHOD, g = XPM.TYPEDEF, m = XPM.VARIABLE, s = XPM.STRUCT, t = XPM.TYPEDEF, v = XPM.VARIABLE }, {__index = function(t, k) return 0 end}) textadept.editing.autocompleters.ansi_c = function() local list = {} -- Retrieve the symbol behind the caret. local line, pos = buffer:get_cur_line() local symbol, op, part = line:sub(1, pos):match('([%w_]-)([%.%->]*)([%w_]*)$') if symbol == '' and part == '' and op ~= '' then return nil end -- lone ., -> if op ~= '' and op ~= '.' and op ~= '->' then return nil end -- Attempt to identify the symbol type. if symbol ~= '' then local buffer = buffer local decl = '([%w_]+)[%s%*&]+'..symbol:gsub('(%p)', '%%%1')..'[^%w_]' for i = buffer:line_from_position(buffer.current_pos) - 1, 0, -1 do local class = buffer:get_line(i):match(decl) if class then symbol = class break end end end -- Search through ctags for completions for that symbol. local tags_files = {} for i = 1, #M.tags do tags_files[#tags_files + 1] = M.tags[i] end tags_files[#tags_files + 1] = (io.get_project_root(buffer.filename) or lfs.currentdir())..'/tags' local name_patt = '^'..part local sep = string.char(buffer.auto_c_type_separator) for i = 1, #tags_files do if lfs.attributes(tags_files[i]) then for line in io.lines(tags_files[i]) do local name = line:match('^%S+') if name:find(name_patt) and not name:find('^!') and not list[name] then local fields = line:match(';"\t(.*)$') if (fields:match('class:(%S+)') or fields:match('enum:(%S+)') or fields:match('struct:(%S+)') or fields:match('typedef:(%S+)') or '') == symbol then list[#list + 1] = ("%s%s%d"):format(name, sep, xpms[fields:sub(1, 1)]) list[name] = true end end end end end return #part, list end textadept.editing.api_files.ansi_c = { _HOME..'/modules/ansi_c/api', _HOME..'/modules/ansi_c/lua_api', _USERHOME..'/modules/ansi_c/api' } -- Commands. --- -- Table of C-specific key bindings. -- @class table -- @name _G.keys.ansi_c keys.ansi_c = { [keys.LANGUAGE_MODULE_PREFIX] = { m = {io.open_file, _HOME..'/modules/ansi_c/init.lua'}, }, ['s\n'] = function() buffer:line_end() buffer:add_text(';') buffer:new_line() end, } -- Snippets. --- -- Table of C-specific snippets. -- @class table -- @name _G.snippets.ansi_c if type(snippets) == 'table' then snippets.ansi_c = { -- Lua snippets lc = 'lua_call(%1(L), %2(nargs), %3(nresults))', lcs = 'lua_checkstack(%1(L), %2(1))', lf = 'static int %1(func)(lua_State *%2(L)) {\n\t%0\n\treturn %3(0);\n}', lgf = 'lua_getfield(%1(L), %2(-1), %3(field))', lgg = 'lua_getglobal(%1(L), %2(global))', lgmt = 'lua_getmetatable(%1(L), %2(-1))', lgt = 'lua_gettable(%1(L), %2(-2))', ltop = 'lua_gettop(%1(L))', lib = 'lua_isboolean(%1(L), %2(-1))', licf = 'lua_iscfunction(%1(L), %2(-1))', lif = 'lua_isfunction(%1(L), %2(-1))', lilu = 'lua_islightuserdata(%1(L), %2(-1))', linil = 'lua_isnil(%1(L), %2(-1))', linone = 'lua_isnone(%1(L), %2(-1))', linonen = 'lua_isnoneornil(%1(L), %2(-1))', lin = 'lua_isnumber(%1(L), %2(-1))', lis = 'lua_isstring(%1(L), %2(-1))', lit = 'lua_istable(%1(L), %2(-1))', liu = 'lua_isuserdata(%1(L), %2(-1))', llen = 'lua_len(%1(L), %2(-1))', lrlen = 'lua_rawlen(%1(L), %2(-1))', lnt = 'lua_newtable(%1(L))', lnu = '(%3 *)lua_newuserdata(%1(L), %2(sizeof(%3(struct))))', ln = 'lua_next(%1(L), %2(-2))', lpc = 'lua_pcall(%1(L), %2(nargs), %3(nresults), %4(msgh))', lpop = 'lua_pop(%1(L), %2(1))', lpb = 'lua_pushboolean(%1(L), %2(bool))', lpcc = 'lua_pushcclosure(%1(L), %2(cfunc), %3(nvalues))', lpcf = 'lua_pushcfunction(%1(L), %2(cfunc))', lpi = 'lua_pushinteger(%1(L), %2(integer))', lplu = 'lua_pushlightuserdata(%1(L), %2(pointer))', lpnil = 'lua_pushnil(%1(L))', lpn = 'lua_pushnumber(%1(L), %2(number))', lps = 'lua_pushstring(%1(L), %2(string))', lpls = 'lua_pushlstring(%1(L), %2(string), %3(len))', lpv = 'lua_pushvalue(%1(L), %2(-1))', lrg = 'lua_rawget(%1(L), %2(-2))', lrgi = 'lua_rawgeti(%1(L), %2(-2), %3(1))', lrs = 'lua_rawset(%1(L), %2(-3))', lrsi = 'lua_rawseti(%1(L), %2(-2), %3(1))', lr = 'lua_register(%1(L), %2(name), %3(cfunc))', lsf = 'lua_setfield(%1(L), %2(-2), %3(field))', lsg = 'lua_setglobal(%1(L), %2(global))', lsmt = 'lua_setmetatable(%1(L), %2(-2))', lst = 'lua_settable(%1(L), %2(-3))', ltb = 'lua_toboolean(%1(L), %2(-1))', lti = 'lua_tointeger(%1(L), %2(-1))', ltn = 'lua_tonumber(%1(L), %2(-1))', ltls = 'lua_tolstring(%1(L), %2(-1), &%3(int))', lts = 'lua_tostring(%1(L), %2(-1))', ltu = '(%3 *)lua_touserdata(%1(L), %2(-1))', lt = 'lua_type(%1(L), %2(-1))', llac = 'luaL_argcheck(%1(L), %2(expr), %3(1), %4(extramsg))', llci = 'luaL_checkinteger(%1(L), %2(1))', llcl = 'luaL_checklong(%1(L), %2(1))', llcls = 'luaL_checklstring(%1(L), %2(1), &%3(int))', llcn = 'luaL_checknumber(%1(L), %2(1))', llcs = 'luaL_checkstring(%1(L), %2(1))', llcu = '(%4 *)luaL_checkudata(%1(L), %2(1), %3(mt_name))', llerr = 'luaL_error(%1(L), %2(message)%3(, %4(arg)))', llgmt = 'luaL_getmetatable(%1(L), %2(mt_name))', llnmt = 'luaL_newmetatable(%1(L), %2(mt_name))', lloi = 'luaL_optinteger(%1(L), %2(1), %3(default))', llol = 'luaL_optlong(%1(L), %2(1), %3(default))', llon = 'luaL_optnumber(%1(L), %2(1), %3(default))', llos = 'luaL_optstring(%1(L), %2(1), %3(default))', llref = 'luaL_ref(%1(L), %2(LUA_REGISTRYINDEX))', llsmt = 'luaL_setmetatable(%1(L), %2(mt_name))', lluref = 'luaL_unref(%1(L), %2(LUA_REGISTRYINDEX), %3(ref))', } end return M