aboutsummaryrefslogtreecommitdiffstats
path: root/init.lua
blob: 4411c375750155e912d27fdd0027f6b3afc814fb (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
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
205
206
207
require("vis")

local M = {}

M.par_prg = "par"
M.par_tw = 72
M.ex_args = function () return "RET4bhgqw" .. M.par_tw end
M.debug = false
-- ex_args = "RET4bhgqB=.,?_A_aQ=_s>|w" .. par_tw
-- export PARINIT='Tbp2hgqR B=.,?_A_a Q=_s>|'

function print(...)
    if M.debug then
        _print_ = _print_ or io.open("/tmp/visprint", "w")
        _print_:write(..., "\n")
    end
end

--- Dump value of a variable in a formatted string
--
--- @param o    table       Dumpable object
--- @param tbs  string|nil  Tabulation string, '  ' by default
--- @param tb   number|nil  Initial tabulation level, 0 by default
--- @return     string
local function dump(o, tbs, tb)
    tb = tb or 0
    tbs = tbs or "  "
    if type(o) == "table" then
        local s = "{"
        if (next(o)) then
            s = s .. "\n"
        else
            return s .. "}"
        end
        tb = tb + 1
        for k, v in pairs(o) do
            if type(k) ~= "number" then
                k = '"' .. k .. '"'
            end
            s = s .. tbs:rep(tb) .. "[" .. k .. "] = " .. dump(v, tbs, tb)
            s = s .. ",\n"
        end
        tb = tb - 1
        return s .. tbs:rep(tb) .. "}"
    else
        return tostring(o)
    end
end

local supress_stdout = " >/dev/null"
local supress_stderr = " 2>/dev/null"
local supress_output = supress_stdout .. supress_stderr

-- Return nil or a string of formatted text from a specific file range or text
-- by calling the formatter command.
-- If given a range we will use vis:pipe to get the output from the formatter.
-- If a string was passed we call the formatter ourself and redirect its stdout
-- to a temporary file. See http://lua-users.org/lists/lua-l/2007-10/msg00189.html.
local function run_shell_cmd(cmd, params, inp)
    local out
    print("cmd = " .. cmd .. ", params = " .. params .. ", inp = " .. inp .. ", (" .. type(inp) .. ")")

    if type(inp) == "string" then
        local full_cmd = cmd .. " '" .. params .. "'"
        local tmp_name = os.tmpname()
        print("tmp_name = " .. tmp_name)
        full_cmd = full_cmd  .. " > " .. tmp_name
        print("full_cmd = " .. full_cmd)
        local proc = assert(io.popen(full_cmd, "w"))
        print("proc = " .. type(proc))
        proc:write(inp)
        -- this error detection may need lua5.2
        proc:flush()
        local exit_code = proc:close()
        print("exit_code = " .. tostring(exit_code))
        
        local tmp_file = assert(io.open(tmp_name, "r"))
        out = tmp_file:read("*a")
        tmp_file:close()
        -- print("out = " .. out)
        os.remove(tmp_name)

        if not exit_code then
            print("calling " .. full_cmd .. " failed (" .. out .. ")")
            return nil
        end
    else
        local range = inp
        local ret, so, _ = vis:pipe(vis.win.file, range, cmd)

        if ret ~= 0 then
            print("calling " .. cmd .. " failed (" .. ret .. ")")
            return nil
        end
        out = so
    end

    return out
end

function lines(str)
    local t = {}
    local function helper(line)
        table.insert(t, line)
        return ""
    end
    helper((str:gsub("(.-)\r?\n", helper)))
    return t
end

getmetatable(_VERSION).__index.lines = lines

function hanging_symbol(line, nspc)
    local beg, fin = 0, 0
    -- itemized list
    beg, fin = line:find("^[-+*] ", nspc)
    if beg then
        print("item beg = " .. beg .. ", fin = " .. fin)
        return fin
    end

    local beg, fin = line:find("^%d+%. ", nspc)
    if beg then
        print("enum beg = " .. beg .. ", fin = " .. fin)
        return fin
    end

    return nspc -- no hanging idennt
end

function new_segment(segment, p_arg)
    if next(segment) then
        print("M.par_prg = " .. M.par_prg .. ", M.ex_args = " .. M.ex_args() .. ", p_arg = " .. p_arg)
        local new_text = run_shell_cmd(M.par_prg, M.ex_args() .. "p" .. p_arg,
                                       table.concat(segment, "\n"))
        print("new_text = " .. new_text)
        return new_text, {}, 0 -- add-to-out, segment, p_arg
    else
        return "", {}, 0 -- add-to-out, segment, p_arg
    end
end

vis:operator_new(
    "gq",
    function(file, range, pos)
        local out = ""
        local hang_sym = ""
        local segment = {}
        local p_arg = 0
        local range_lines = file:content(range):lines()

        for _, line in ipairs(range_lines) do
            local beg, beg_spc_len = line:find("^%s*")
            assert(beg == 1, "There is no way this would not be 1.")
            local non_spc_idx = line:len() >= beg_spc_len + 1 and beg_spc_len + 1 or 0
            print("non_spc_idx = " .. non_spc_idx)

            hang_sym = hanging_symbol(line, non_spc_idx)
            print("hang_sym = " .. hang_sym .. ", non_spc_idx = " .. non_spc_idx)

            if non_spc_idx ~= 0 then -- non-empty line
                -- item: start new segment
                if hang_sym ~= non_spc_idx then
                    seg_pared, segment, p_arg = new_segment(segment, p_arg)
                    if seg_pared then
                        out = out .. seg_pared
                        p_arg = hang_sym
                    end
                    table.insert(segment, line)
                else
                    -- continuous line in a segment, just collect it
                    table.insert(segment, line)
                end
            else -- this is an empty line
                seg_pared, segment, p_arg = new_segment(segment, p_arg)
                if seg_pared then
                    out = out .. seg_pared
                end
            end
        end

        if out:len() == 0 then
            print("Cannot process paragraph.")
        else
            file:delete(range)
            file:insert(range.start, out)
        end
        return range.start -- new cursor location
    end,
    "Formating operator, filter range through formatting filter"
)

vis:option_register(
    "autoformat",
    "bool",
    function(value, toogle)
        if not vis.win then
            return false
        end
        vis.win.autoformat = toogle and not vis.win.autoformat or value
        print("Option autoformat = " .. tostring(vis.win.autoformat))
        return true
    end,
    "Automatically format current paragraph."
)

return M