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
|
VERSION = "1.0.0"
local buffer = import("micro/buffer")
local config = import("micro/config")
local micro = import("micro")
-- local posix = import("posix")
-- Returns Loc-tuple w/ current marked text or whole line (begin, end)
function getTextLoc(c)
local v = micro.CurPane()
local a, b = nil, nil
if c:HasSelection() then
if c.CurSelection[1]:GreaterThan(-c.CurSelection[2]) then
a, b = c.CurSelection[2], c.CurSelection[1]
else
a, b = c.CurSelection[1], c.CurSelection[2]
end
else
local eol = string.len(v.Buf:Line(c.Loc.Y))
a, b = c.Loc, buffer.Loc(eol, c.Y)
end
return buffer.Loc(a.X, a.Y), buffer.Loc(b.X, b.Y)
end
-- Returns the current marked text or whole line
function getText(a, b)
local txt, buf = {}, micro.CurPane().Buf
-- Editing a single line?
if a.Y == b.Y then return buf:Line(a.Y):sub(a.X + 1, b.X) end
-- Add first part of text selection (a.X+1 as Lua is 1-indexed)
table.insert(txt, buf:Line(a.Y):sub(a.X + 1))
-- Stuff in the middle
for lineNo = a.Y + 1, b.Y - 1 do
table.insert(txt, buf:Line(lineNo))
end
-- Insert last part of selection
table.insert(txt, buf:Line(b.Y):sub(1, b.X))
return table.concat(txt, "\n")
end
-- Calls 'manipulator'-function on text matching 'regex'
function manipulate(regex, manipulator, num)
local num = math.inf or num
local v = micro.CurPane()
-- perform the replacement for each cursor
local cs = v.Buf:GetCursors()
for i = 1, #cs do
local c = cs[i]
local a, b = getTextLoc(c)
local oldTxt = getText(a, b)
local newTxt = string.gsub(oldTxt, regex, manipulator, num)
local sel = nil
if c:HasSelection() then
-- copied from comment plugin
sel = -c.CurSelection
end
v.Buf:Replace(a, b, newTxt)
-- Fix selection, if transformation changes text length (e.g. base64)
local d = string.len(newTxt) - string.len(oldTxt)
if sel ~= nil then
-- copied from comment plugin
c.CurSelection[1].Y = sel[1].Y
c.CurSelection[2].Y = sel[2].Y
c.CurSelection[1].X = sel[1].X
c.CurSelection[2].X = sel[2].X
if c.CurSelection[1]:GreaterThan(-c.CurSelection[2]) then
c.CurSelection[1].X = sel[1].X + d
else
c.CurSelection[2].X = sel[2].X + d
end
end
c:Relocate()
c.LastVisualX = c:GetVisualX() -- called with false
end
end
-- https://stackoverflow.com/questions/1242572/how-do-you-construct-a-read-write-pipe-with-lua
function os_pipe(input, cmd)
os.setenv("LUA_X",input)
local f = assert(io.popen('printf "%s" "$LUA_X" | ' .. cmd, 'r'))
local s = assert(f:read('*a'))
f:close()
return s
end
function sort()
manipulate("(.*)", function(lines)
return os_pipe(lines, 'sort')
end)
end
function sortu()
manipulate("(.*)", function(lines)
return os_pipe(lines, 'sort -u')
end)
end
function jq()
manipulate("(.*)", function(lines)
return os_pipe(lines, 'jq')
end)
end
function pipe(bp, args)
manipulate("(.*)", function(lines)
return os_pipe(lines, table.concat(args, " "))
end)
end
function init()
config.MakeCommand("sort", sort, config.NoComplete)
config.MakeCommand("sortu", sortu, config.NoComplete)
config.MakeCommand("jq", jq, config.NoComplete)
config.MakeCommand("pipe", pipe, config.NoComplete)
end
|