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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
require "vis"
ec = require "editorconfig"
-- Simple wrapper
function vis_set(option, value)
if type(value) == "boolean" then
if value then
value = "yes"
else
value = "no"
end
end
vis:command("set " .. option .. " " .. value)
end
function set_pre_save(f, value)
if value == "true" then
vis.events.subscribe(vis.events.FILE_SAVE_PRE, f)
else
vis.events.unsubscribe(vis.events.FILE_SAVE_PRE, f)
end
end
function set_file_open(f, value)
if value == "true" then
vis.events.subscribe(vis.events.FILE_OPEN, f)
else
vis.events.unsubscribe(vis.events.FILE_OPEN, f)
end
end
-- Custom functionality
function insert_final_newline(file, path)
-- Technically speaking, this is a pre-save-hook as well and could
-- therefore respect edconf_hooks_enabled. Since this function runs
-- blazingly fast and scales with a complexity of O(1), however,
-- there is no need to disable it.
if file.size > 0 and file:content(file.size-1, 1) ~= '\n' then
file:insert(file.size, '\n')
end
end
function strip_final_newline(file, path)
-- In theory, this would have a complexity of O(n) as well and could
-- thus be made optional via edconf_hooks_enabled. On the other hand,
-- this is probably a very rare edge case, so stripping all trailing
-- newline characters is probably safe enough.
while file:content(file.size-1, 1) == '\n' do
file:delete(file.size-1, 1)
end
end
function trim_trailing_whitespace(file, path)
if not edconf_hooks_enabled then return end
for i=1, #file.lines do
if string.match(file.lines[i], '[ \t]$') then
file.lines[i] = string.gsub(file.lines[i], '[ \t]*$', '')
end
end
end
function enforce_crlf_eol(file, path)
if not edconf_hooks_enabled then return end
for i=1, #file.lines do
if not string.match(file.lines[i], '\r$') then
file.lines[i] = string.gsub(file.lines[i], '$', '\r')
end
end
end
function enforce_lf_eol(file, path)
if not edconf_hooks_enabled then return end
for i=1, #file.lines do
if string.match(file.lines[i], '\r$') then
file.lines[i] = string.gsub(file.lines[i], '\r$', '')
end
end
end
global_max_line_length = 80 -- This is ugly, but we do want to use
-- single function that we can register
-- or unregister as needed
function max_line_length(file, path)
if not edconf_hooks_enabled then return end
local overlong_lines = {}
for i=1, #file.lines do
if string.len(file.lines[i]) > global_max_line_length then
table.insert(overlong_lines, i)
end
end
if #overlong_lines > 0 then
local lines_are = (function(x)
if x>1 then return "lines are" else return "line is" end
end)(#overlong_lines)
vis:info(string.format(
"%d %s longer than %d characters: %s",
#overlong_lines, lines_are, global_max_line_length,
table.concat(overlong_lines, ",")
))
end
end
OPTIONS = {
indent_style = function (value)
vis_set("expandtab", (value == "space"))
end,
indent_size = function (value)
if value ~= "tab" then -- tab_width is a synonym anyway
vis_set("tabwidth", value)
end
end,
tab_width = function (value)
vis_set("tabwidth", value)
end,
spell_language = function (value, file)
file.spell_language = value
end,
insert_final_newline = function (value)
-- According to the editorconfig specification, insert_final_newline
-- false is supposed to mean stripping the final newline, if present.
-- See https://editorconfig-specification.readthedocs.io/#supported-pairs
--
-- Quote: insert_final_newline Set to true ensure file ends with a
-- newline when saving and false to ensure it doesn’t.
--
set_pre_save(insert_final_newline, tostring(value == "true"))
set_pre_save(strip_final_newline, tostring(value == "false"))
end,
trim_trailing_whitespace = function (value)
set_pre_save(trim_trailing_whitespace, value)
end,
-- End of line is only partially implemented. While vis does not
-- support customized newlines, it does work well enough with crlf
-- newlines. Therefore, setting end_of_line=crlf will just ensure
-- that there is a cr at the end of each line. Setting end_of_line=lf
-- will strip any cr characters at the end of lines. This hopefully
-- eases the pain of working with crlf files a little.
end_of_line = function (value)
set_pre_save(enforce_crlf_eol, tostring(value == "crlf"))
set_pre_save(enforce_lf_eol, tostring(value == "lf"))
end,
-- There is probably no straightforward way to enforce a maximum line
-- length across different programming languages. If a maximum line
-- length is set, we can at least issue a warning, however.
max_line_length = function(value)
if value ~= "off" then
global_max_line_length = tonumber(value)
end
set_pre_save(max_line_length, tostring(value ~= "off"))
end,
-- Not supported by vis
-- charset
-- Partial support
-- end_of_line
-- max_line_length
}
-- Compatible with editorconfig-core-lua v0.3.0
function ec_iter(p)
i = 0
props, keys = ec.parse(p)
n = #keys
return function ()
i = i + 1
if i <= n then
return keys[i], props[keys[i]]
end
end
end
function ec_set_values(file)
if file.path then
for name, value in ec_iter(file.path) do
if OPTIONS[name] then
OPTIONS[name](value, file)
end
end
end
end
function ec_parse_cmd() ec_set_values(vis.win.file) end
vis:command_register("econfig_parse", ec_parse_cmd, "(Re)parse an editorconfig file")
vis.events.subscribe(vis.events.FILE_OPEN, function (file)
ec_set_values(file)
end)
vis.events.subscribe(vis.events.FILE_SAVE_POST, function (file, path)
ec_set_values(file)
end)
edconf_hooks_enabled = false
vis:option_register("edconfhooks", "bool", function(value)
edconf_hooks_enabled = value
end, "Enable optional pre-save-hooks for certain editorconfig settings")
|