aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/generators/gen_ex_cmds.lua
blob: 0c1051b04e3c882b2238b8de754ebc3ba740d080 (plain) (blame)
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
local nvimsrcdir = arg[1]
local includedir = arg[2]
local autodir = arg[3]

if nvimsrcdir == '--help' then
  print ([[
Usage:
  lua genex_cmds.lua src/nvim build/include build/src/nvim/auto

Will generate files build/include/ex_cmds_enum.generated.h with cmdidx_T
enum and build/src/nvim/auto/ex_cmds_defs.generated.h with main Ex commands
definitions.
]])
  os.exit(0)
end

package.path = nvimsrcdir .. '/?.lua;' .. package.path

local enumfname = includedir .. '/ex_cmds_enum.generated.h'
local defsfname = autodir .. '/ex_cmds_defs.generated.h'

local enumfile = io.open(enumfname, 'w')
local defsfile = io.open(defsfname, 'w')

local bit = require 'bit'
local ex_cmds = require('ex_cmds')
local defs = ex_cmds.cmds
local flags = ex_cmds.flags

local byte_a = string.byte('a')
local byte_z = string.byte('z')
local a_to_z = byte_z - byte_a + 1

-- Table giving the index of the first command in cmdnames[] to lookup
-- based on the first letter of a command.
local cmdidxs1_out = string.format([[
static const uint16_t cmdidxs1[%u] = {
]], a_to_z)
-- Table giving the index of the first command in cmdnames[] to lookup
-- based on the first 2 letters of a command.
-- Values in cmdidxs2[c1][c2] are relative to cmdidxs1[c1] so that they
-- fit in a byte.
local cmdidxs2_out = string.format([[
static const char_u cmdidxs2[%u][%u] = {
  /*           a   b   c   d   e   f   g   h   i   j   k   l   m   n   o   p   q   r   s   t   u   v   w   x   y   z */
]], a_to_z, a_to_z)

enumfile:write([[
typedef enum CMD_index {
]])
defsfile:write(string.format([[
#include "nvim/arglist.h"
#include "nvim/autocmd.h"
#include "nvim/buffer.h"
#include "nvim/cmdhist.h"
#include "nvim/debugger.h"
#include "nvim/diff.h"
#include "nvim/digraph.h"
#include "nvim/eval.h"
#include "nvim/eval/userfunc.h"
#include "nvim/eval/vars.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_session.h"
#include "nvim/help.h"
#include "nvim/indent.h"
#include "nvim/locale.h"
#include "nvim/lua/executor.h"
#include "nvim/mapping.h"
#include "nvim/mark.h"
#include "nvim/match.h"
#include "nvim/menu.h"
#include "nvim/message.h"
#include "nvim/ops.h"
#include "nvim/option.h"
#include "nvim/profile.h"
#include "nvim/quickfix.h"
#include "nvim/runtime.h"
#include "nvim/sign.h"
#include "nvim/spell.h"
#include "nvim/spellfile.h"
#include "nvim/syntax.h"
#include "nvim/undo.h"
#include "nvim/usercmd.h"
#include "nvim/version.h"

static const int command_count = %u;
static CommandDefinition cmdnames[%u] = {
]], #defs, #defs))
local cmds, cmdidxs1, cmdidxs2 = {}, {}, {}
for _, cmd in ipairs(defs) do
  if bit.band(cmd.flags, flags.RANGE) == flags.RANGE then
    assert(cmd.addr_type ~= 'ADDR_NONE',
           string.format('ex_cmds.lua:%s: Using RANGE with ADDR_NONE\n', cmd.command))
  else
    assert(cmd.addr_type == 'ADDR_NONE',
           string.format('ex_cmds.lua:%s: Missing ADDR_NONE\n', cmd.command))
  end
  if bit.band(cmd.flags, flags.DFLALL) == flags.DFLALL then
    assert(cmd.addr_type ~= 'ADDR_OTHER' and cmd.addr_type ~= 'ADDR_NONE',
           string.format('ex_cmds.lua:%s: Missing misplaced DFLALL\n', cmd.command))
  end
  if bit.band(cmd.flags, flags.PREVIEW) == flags.PREVIEW then
    assert(cmd.preview_func ~= nil,
           string.format('ex_cmds.lua:%s: Missing preview_func\n', cmd.command))
  end
  local enumname = cmd.enum or ('CMD_' .. cmd.command)
  local byte_cmd = cmd.command:sub(1, 1):byte()
  if byte_a <= byte_cmd and byte_cmd <= byte_z then
    table.insert(cmds, cmd.command)
  end
  local preview_func
  if cmd.preview_func then
    preview_func = string.format("(ex_preview_func_T)&%s", cmd.preview_func)
  else
    preview_func = "NULL"
  end
  enumfile:write('  ' .. enumname .. ',\n')
  defsfile:write(string.format([[
  [%s] = {
    .cmd_name = "%s",
    .cmd_func = (ex_func_T)&%s,
    .cmd_preview_func = %s,
    .cmd_argt = %uL,
    .cmd_addr_type = %s
  },
]], enumname, cmd.command, cmd.func, preview_func, cmd.flags, cmd.addr_type))
end
for i = #cmds, 1, -1 do
  local cmd = cmds[i]
  -- First and second characters of the command
  local c1 = cmd:sub(1, 1)
  cmdidxs1[c1] = i - 1
  if cmd:len() >= 2 then
    local c2 = cmd:sub(2, 2)
    local byte_c2 = string.byte(c2)
    if byte_a <= byte_c2 and byte_c2 <= byte_z then
      if not cmdidxs2[c1] then
        cmdidxs2[c1] = {}
      end
      cmdidxs2[c1][c2] = i - 1
    end
  end
end
for i = byte_a, byte_z do
  local c1 = string.char(i)
  cmdidxs1_out = cmdidxs1_out .. '  /*  ' .. c1 .. '  */ ' .. cmdidxs1[c1] .. ',\n'
  cmdidxs2_out = cmdidxs2_out .. '  /*  ' .. c1 .. '  */ {'
  for j = byte_a, byte_z do
    local c2 = string.char(j)
    cmdidxs2_out = cmdidxs2_out ..
      ((cmdidxs2[c1] and cmdidxs2[c1][c2])
        and string.format('%3d', cmdidxs2[c1][c2] - cmdidxs1[c1])
        or '  0') .. ','
  end
  cmdidxs2_out = cmdidxs2_out .. ' },\n'
end
enumfile:write([[
  CMD_SIZE,
  CMD_USER = -1,
  CMD_USER_BUF = -2
} cmdidx_T;
]])
defsfile:write(string.format([[
};
%s};
%s};
]], cmdidxs1_out, cmdidxs2_out))