summaryrefslogtreecommitdiffstatshomepage
path: root/plugins/console/init.lua
blob: c27e55164bcce836d1c738b0d052839ec102883c (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
-- license:BSD-3-Clause
-- copyright-holders:Carl
local exports = {}
exports.name = "console"
exports.version = "0.0.1"
exports.description = "Console plugin"
exports.license = "The BSD 3-Clause License"
exports.author = { name = "Carl" }

local console = exports

function console.startplugin()
	local conth = emu.thread()
	local started = false
	local ln = require("linenoise")
	local preload = false
	print("    _/      _/    _/_/    _/      _/  _/_/_/_/");
	print("   _/_/  _/_/  _/    _/  _/_/  _/_/  _/       ");
	print("  _/  _/  _/  _/_/_/_/  _/  _/  _/  _/_/_/    ");
	print(" _/      _/  _/    _/  _/      _/  _/         ");
	print("_/      _/  _/    _/  _/      _/  _/_/_/_/    \n");
	print(emu.app_name() .. " " .. emu.app_version(), "\nCopyright (C) Nicola Salmoria and the MAME team\n");
	print(_VERSION, "\nCopyright (C) Lua.org, PUC-Rio\n");
	-- linenoise isn't thread safe but that means history can handled here
	-- that also means that bad things will happen if anything outside lua tries to use it
	-- especially the completion callback
	ln.historysetmaxlen(10)
	local scr = [[
local ln = require('linenoise')
ln.setcompletion(function(c, str)
	status = str
	yield()
	status:gsub('[^,]*', function(s) if s ~= '' then ln.addcompletion(c, s) end end)
end)
return ln.linenoise('\x1b[1;36m[MAME]\x1b[0m> ')
]]

	local function find_unmatch(str, openpar, pair)
		local done = false
		if not str:match(openpar) then
			return str
		end
		local tmp = str:gsub(pair, "")
		if not tmp:match(openpar) then
			return str
		end
		repeat
			str = str:gsub(".-" .. openpar .. "(.*)", function (s)
				tmp = s:gsub(pair, "")
				if not tmp:match(openpar) then
					done = true
				end
				return s
			end)
		until done or str == ""
		return str
	end

	local function get_completions(str)
		local comps = ","
		local rest, dot, last = str:match("(.-)([.:]?)([^.:]*)$")
		str = find_unmatch(str, "%(", "%b()")
		str = find_unmatch(str, "%[", "%b[]")
		local table = str:match("([%w_%.:%(%)%[%]]-)[:.][%w_]*$")
		local err
		if rest == "" or not table then
			if dot == "" then
				table = "_G"
			else
				return comps
			end
		end
		err, tablef = pcall(load("return " .. table))
		if (not err) or (not tablef) then
			return comps
		end
		rest = rest .. dot
		if type(tablef) == 'table' then
			for k, v in pairs(tablef) do
				if k:match("^" .. last) then
					comps = comps .. "," .. rest .. k
				end
			end
		end
		if type(tablef) == "userdata" then
			local tablef = getmetatable(tablef)
			for k, v in pairs(tablef) do
				if k:match("^" .. last) then
					comps = comps .. "," .. rest .. k
				end
			end
		end
		return comps
	end

	emu.register_periodic(function()
		if conth.yield then
			conth:continue(get_completions(conth.result))
			return
		elseif conth.busy then
			return
		elseif started then
			local cmd = conth.result
			preload = false
			local func, err = load(cmd)
			if not func then
				if err:match("<eof>") then
					print("incomplete command")
					ln.preload(cmd)
					preload = true
				else
					print("error: ", err)
				end
			else
				local status
				status, err = pcall(func)
				if not status then
					print("error: ", err)
				end
			end
			if not preload then
				ln.historyadd(cmd)
			end
		end
		conth:start(scr)
		started = true
	end)
end

return exports