1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
-- Copyright 2007-2020 Mitchell. See LICENSE.
local M = {}
--[[ This comment is for LuaDoc.
---
-- The ansi_c module.
-- It provides utilities for editing C code.
-- @field autocomplete_snippets (boolean)
-- Whether or not to include snippets in autocompletion lists.
-- The default value is `true`.
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', _HOME .. '/modules/ansi_c/lua_tags',
_USERHOME .. '/modules/ansi_c/tags'
}
M.autocomplete_snippets = true
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()return 0 end})
textadept.editing.autocompleters.ansi_c = function()
-- Retrieve the symbol behind the caret.
local line, pos = buffer:get_cur_line()
local symbol, op, part = line:sub(1, pos - 1):match(
'([%w_]-)([%.%->]*)([%w_]*)$')
if symbol == '' and part == '' then return nil end -- nothing to complete
if op ~= '' and op ~= '.' and op ~= '->' then return nil end
-- Attempt to identify the symbol type.
if symbol ~= '' then
local decl = '([%w_]+)[%s%*&]+' .. symbol:gsub('%p', '%%%0') .. '[^%w_]'
for i = buffer:line_from_position(buffer.current_pos) - 1, 1, -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)
::rescan::
local list = {}
for _, filename in ipairs(tags_files) do
if not lfs.attributes(filename) then goto continue end
for tag_line in io.lines(filename) do
local name = tag_line:match('^%S+')
if (name:find(name_patt) and not name:find('^!') and not list[name]) or
name == symbol and op == '' then
local fields = tag_line:match(';"\t(.*)$')
local type = fields:match('class:(%S+)') or
fields:match('enum:(%S+)') or fields:match('struct:(%S+)') or ''
if type == symbol then
list[#list + 1] = name .. sep .. xpms[fields:sub(1, 1)]
list[name] = true
elseif name == symbol and fields:match('typeref:') then
-- For typeref, change the lookup symbol to the referenced name and
-- rescan tags files.
symbol = fields:match('[^:]+$')
goto rescan
end
end
end
::continue::
end
if symbol == '' and M.autocomplete_snippets then
local _, snippets = textadept.editing.autocompleters.snippet()
for i = 1, #snippets do list[#list + 1] = snippets[i] end
end
return #part, list
end
for _, tags in ipairs(M.tags) do
table.insert(textadept.editing.api_files.ansi_c, (tags:gsub('tags$', 'api')))
end
-- Commands.
---
-- Table of C-specific key bindings.
-- @class table
-- @name _G.keys.ansi_c
keys.ansi_c = {}
-- Snippets.
---
-- Table of C-specific snippets.
-- @class table
-- @name _G.snippets.ansi_c
snippets.ansi_c = {
func = '%1(int) %2(name)(%3(args)) {\n\t%0\n\treturn %4(0);\n}',
vfunc = 'void %1(name)(%2(args)) {\n\t%0\n}',
['if'] = 'if (%1) {\n\t%0\n}',
eif = 'else if (%1) {\n\t%0\n}',
['else'] = 'else {\n\t%0\n}',
['for'] = 'for (%1; %2; %3) {\n\t%0\n}',
['fori'] = 'for (%1(int) %2(i) = %3(0); %2 %4(<) %5(count); %2%6(++)) {\n'..
'\t%0\n}',
['while'] = 'while (%1) {\n\t%0\n}',
['do'] = 'do {\n\t%0\n} while (%1);',
sw = 'switch (%1) {\n\tcase %2:\n\t\t%0\n\t\tbreak;\n}',
case = 'case %1:\n\t%0\n\tbreak;',
st = 'struct %1(name) {\n\t%0\n};',
td = 'typedef %1(int) %2(name_t);',
tds = 'typedef struct %1(name) {\n\t%0\n} %1%2(_t);',
def = '#define %1(name) %2(value)',
inc = '#include "%1"',
Inc = '#include <%1>',
pif = '#if %1\n%0\n#endif',
main = 'int main(int argc, const char **argv) {\n\t%0\n\treturn 0;\n}',
printf = 'printf("%1(%s)\\n", %2);',
}
return M
|