-
Notifications
You must be signed in to change notification settings - Fork 148
/
redbean.lua
140 lines (133 loc) · 5.28 KB
/
redbean.lua
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
-- Copyright 2022 Paul Kulchenko, ZeroBrane LLC; All rights reserved
local pathcache
local win = ide and ide.osname == "Windows"
local interpreter = {
name = "Redbean",
description = "Redbean Lua debugger",
api = {"baselib"},
frun = function(self,wfilename,rundebug)
local projdir = self:fworkdir(wfilename)
local redbean = ide.config.path.redbean or pathcache and pathcache[projdir]
if redbean and not wx.wxFileExists(redbean) then
ide:Print(("Can't find configured redbean executable: '%s'."):format(redbean))
redbean = nil
end
if not redbean then
local sep = win and ';' or ':'
local default = win and GenerateProgramFilesPath('', sep)..sep or ''
local path = default
..(os.getenv('PATH') or '')..sep
..projdir..sep
..(os.getenv('HOME') and GetPathWithSep(os.getenv('HOME'))..'bin' or '')
local paths = {}
for p in path:gmatch("[^"..sep.."]+") do
redbean = redbean or GetFullPathIfExists(p, 'redbean.com')
table.insert(paths, p)
end
if not redbean then
ide:Print("Can't find redbean executable in any of the following folders: "
..table.concat(paths, ", "))
return
end
end
local filepath = wfilename:GetFullPath()
if rundebug then
ide:GetDebugger():SetOptions({ runstart = ide.config.debugger.runonstart ~= false })
local mdb = MergeFullPath(GetPathWithSep(ide.editorFilename), "lualibs/mobdebug/")
rundebug = ([[-e "package.path=[=[%s]=] package.loaded['socket']=require'redbean'"]])
:format(ide:GetPackage("redbean"):GetFilePath())
.." "..([[-e "package.path=[=[%s]=]
MDB=require('mobdebug')
MDB.start()
function OnServerStart()
local OHR=OnHttpRequest
if OHR then
OnHttpRequest=function(...) MDB.on() return OHR(...) end
end
end"]]):format(MergeFullPath(GetPathWithSep(ide.editorFilename), "lualibs/mobdebug/?.lua"))
:gsub("\r?\n%s*"," ")
else
-- if running on Windows and can't open the file, this may mean that
-- the file path includes unicode characters that need special handling
local fh = io.open(filepath, "r")
if fh then fh:close() end
if ide.osname == 'Windows' and pcall(require, "winapi")
and wfilename:FileExists() and not fh then
winapi.set_encoding(winapi.CP_UTF8)
filepath = winapi.short_path(filepath)
end
end
local params = ide.config.arg.any or ide.config.arg.redbean
local code = rundebug or ""
local cmd = '"'..redbean..'" '..code..(params and " "..params or "")
-- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
return CommandLineRun(cmd,self:fworkdir(wfilename),true,false,nil,nil)
end,
hasdebugger = true,
skipcompile = true,
unhideanywindow = true,
takeparameters = true,
}
local name = 'redbean'
return {
name = "Redbean",
description = "Implements integration with Redbean server.",
author = "Paul Kulchenko",
version = 0.12,
dependencies = "1.60",
onRegister = function(self)
ide:AddInterpreter(name, interpreter)
end,
onUnRegister = function(self)
ide:RemoveInterpreter(name)
end,
-- socket.lua mock to allow redbean.lua to be required from the app when debugged
-- since it needs to be loaded form the IDE, which may be running a Lua version
-- that doesn't include bit-wise operators, load the fragment at run-time.
tcp = function()
return load[[return {
_ = assert(unix.socket()),
buf = "",
settimeout = function(self, t) self._timeout = t and t*1000 or nil end,
connect = function(self, ip, port)
return assert(unix.connect(self._, assert(ResolveIp(ip)), port))
end,
close = function(self) return assert(unix.close(self._)) end,
send = function(self, data)
local CANWRITE = unix.POLLOUT | unix.POLLWRNORM
local events = assert(unix.poll({[self._] = unix.POLLOUT}, self._timeout))
if not events[self._] then return nil, "timeout" end
if events[self._] & CANWRITE == 0 then return nil, "close" end
local sent, err = unix.send(self._, data)
if not sent and err:name() == "EAGAIN" then return nil, "timeout" end
return sent, err
end,
receive = function(self, pattern)
local CANREAD = unix.POLLIN | unix.POLLRDNORM | unix.POLLRDBAND
local size = tonumber(pattern)
if size then
if #self.buf < size then
local events = assert(unix.poll({[self._] = unix.POLLIN}, self._timeout))
if not events[self._] then return nil, "timeout" end
if events[self._] & CANREAD == 0 then return nil, "close" end
self.buf = self.buf .. assert(unix.recv(self._, size-#self.buf))
end
local res = self.buf:sub(1, size)
self.buf = self.buf:sub(size+1)
return res
end
while not self.buf:find("\n") do
self.buf = self.buf .. assert(unix.recv(self._, 4096))
end
local pos = self.buf:find("\n")
local res = self.buf:sub(1, pos-1):gsub("\r","")
self.buf = self.buf:sub(pos+1)
return res
end,
}]]()
end,
}
--[[ configuration example:
-- if `redbean` executable is not in the project folder or PATH, set the path to it manually
path.redbean = "/full/path/redbean.com"
--]]