diff options
| author | jacqueline <me@jacqueline.id.au> | 2023-12-13 16:10:08 +1100 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2023-12-13 16:10:08 +1100 |
| commit | 64b106c13e18c33be0f2b0de532054e0ed3f731d (patch) | |
| tree | b54b1c90d941bc456b4d51e864970720bdf2d648 /lib/lua-repl/repl/plugins | |
| parent | 5a2f0b08e0e3f20cda977b510b680d5843ae7283 (diff) | |
| download | tangara-fw-64b106c13e18c33be0f2b0de532054e0ed3f731d.tar.gz | |
add a cool lua repl
Diffstat (limited to 'lib/lua-repl/repl/plugins')
| -rw-r--r-- | lib/lua-repl/repl/plugins/autoreturn.lua | 29 | ||||
| -rw-r--r-- | lib/lua-repl/repl/plugins/completion.lua | 192 | ||||
| -rw-r--r-- | lib/lua-repl/repl/plugins/example.lua | 41 | ||||
| -rw-r--r-- | lib/lua-repl/repl/plugins/filename_completion.lua | 63 | ||||
| -rw-r--r-- | lib/lua-repl/repl/plugins/history.lua | 60 | ||||
| -rw-r--r-- | lib/lua-repl/repl/plugins/keep_last_eval.lua | 43 | ||||
| -rw-r--r-- | lib/lua-repl/repl/plugins/linenoise.lua | 59 | ||||
| -rw-r--r-- | lib/lua-repl/repl/plugins/pretty_print.lua | 262 | ||||
| -rw-r--r-- | lib/lua-repl/repl/plugins/rcfile.lua | 54 | ||||
| -rw-r--r-- | lib/lua-repl/repl/plugins/rlwrap.lua | 41 | ||||
| -rw-r--r-- | lib/lua-repl/repl/plugins/semicolon_suppress_output.lua | 36 |
11 files changed, 880 insertions, 0 deletions
diff --git a/lib/lua-repl/repl/plugins/autoreturn.lua b/lib/lua-repl/repl/plugins/autoreturn.lua new file mode 100644 index 00000000..a0e15eab --- /dev/null +++ b/lib/lua-repl/repl/plugins/autoreturn.lua @@ -0,0 +1,29 @@ +-- Copyright (c) 2011-2015 Rob Hoelz <rob@hoelz.ro> +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +-- the Software, and to permit persons to whom the Software is furnished to do so, +-- subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +-- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +-- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +-- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +-- A plugin that causes the REPL to automatically return evaluation results + +function around:compilechunk(orig, chunk) + local f, err = orig(self, 'return ' .. chunk) + + if not f then + f, err = orig(self, chunk) + end + + return f, err +end diff --git a/lib/lua-repl/repl/plugins/completion.lua b/lib/lua-repl/repl/plugins/completion.lua new file mode 100644 index 00000000..938c7439 --- /dev/null +++ b/lib/lua-repl/repl/plugins/completion.lua @@ -0,0 +1,192 @@ +-- Copyright (c) 2011-2015 Rob Hoelz <rob@hoelz.ro> +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +-- the Software, and to permit persons to whom the Software is furnished to do so, +-- subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +-- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +-- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +-- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +local utils = require 'repl.utils' +local getmetatable = getmetatable +local pairs = pairs +local sfind = string.find +local sgmatch = string.gmatch +local smatch = string.match +local ssub = string.sub +local tconcat = table.concat +local tsort = table.sort +local type = type + +local function isindexable(value) + if type(value) == 'table' then + return true + end + + local mt = getmetatable(value) + + return mt and mt.__index +end + +local function getcompletions(t) + local union = {} + + while isindexable(t) do + if type(t) == 'table' then + -- XXX what about the pairs metamethod in 5.2? + -- either we don't care, we implement a __pairs-friendly + -- pairs for 5.1, or implement a 'rawpairs' for 5.2 + for k, v in pairs(t) do + if union[k] == nil then + union[k] = v + end + end + end + + local mt = getmetatable(t) + t = mt and mt.__index or nil + end + + return pairs(union) +end + +local function split_ns(expr) + if expr == '' then + return { '' } + end + + local pieces = {} + + -- XXX method calls too (option?) + for m in sgmatch(expr, '[^.]+') do + pieces[#pieces + 1] = m + end + + -- logic for determining whether to pad the matches with the empty + -- string (ugly) + if ssub(expr, -1) == '.' then + pieces[#pieces + 1] = '' + end + + return pieces +end + +local function determine_ns(expr) + local ns = _G -- XXX what if the REPL lives in a special context? (option?) + local pieces = split_ns(expr) + + for index = 1, #pieces - 1 do + local key = pieces[index] + -- XXX rawget? or regular access? (option?) + ns = ns[key] + + if not isindexable(ns) then + return {}, '', '' + end + end + + expr = pieces[#pieces] + + local prefix = '' + + if #pieces > 1 then + prefix = tconcat(pieces, '.', 1, #pieces - 1) .. '.' + end + + local last_piece = pieces[#pieces] + + local before, after = smatch(last_piece, '(.*):(.*)') + + if before then + ns = ns[before] -- XXX rawget + prefix = prefix .. before .. ':' + expr = after + end + + return ns, prefix, expr +end + +local isidentifierchar + +do + local ident_chars_set = {} + -- XXX I think this can be done with isalpha in C... + local ident_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.:_0123456789' + + for i = 1, #ident_chars do + local char = ssub(ident_chars, i, i) + ident_chars_set[char] = true + end + + function isidentifierchar(char) + return ident_chars_set[char] + end +end + +local function extract_innermost_expr(expr) + local index = #expr + + while index > 0 do + local char = ssub(expr, index, index) + if isidentifierchar(char) then + index = index - 1 + else + break + end + end + + index = index + 1 + + return ssub(expr, 1, index - 1), ssub(expr, index) +end + +-- XXX is this logic (namely, returning the entire line) too specific to +-- linenoise? +function repl:complete(expr, callback) + if utils.ends_in_unfinished_string(expr) then + return + end + + local ns, prefix, path + + prefix, expr = extract_innermost_expr(expr) + + ns, path, expr = determine_ns(expr) + + prefix = prefix .. path + + local completions = {} + + for k, v in getcompletions(ns) do + if sfind(k, expr, 1, true) == 1 then + local suffix = '' + local type = type(v) + + -- XXX this should be optional + if type == 'function' then + suffix = '(' + elseif type == 'table' then + suffix = '.' + end + + completions[#completions + 1] = prefix .. k .. suffix + end + end + + tsort(completions) + + for _, completion in ipairs(completions) do + callback(completion) + end +end + +features = 'completion' diff --git a/lib/lua-repl/repl/plugins/example.lua b/lib/lua-repl/repl/plugins/example.lua new file mode 100644 index 00000000..d55fd076 --- /dev/null +++ b/lib/lua-repl/repl/plugins/example.lua @@ -0,0 +1,41 @@ +-- Example plugin that demonstrates the objects available to a +-- plugin, as well as the methods that a plugin should make use +-- of + +-- Adding methods and properties to the repl object adds them to +-- the REPL object loading the plugin. If such a method or property +-- already exists, the current plugin will fail to load. +function repl:newmethod(...) +end + +-- Adding methods to the before object causes them to be called +-- before the actual method itself. If the method being added +-- (in this case displayresults) does not exist on the REPL object +-- loading this plugin, the current plugin will fail to load. +function before:displayresults(results) +end + +-- Adding methods to the after object causes them to be called +-- after the actual method itself. If the method being added +-- (in this case displayresults) does not exist on the REPL object +-- loading this plugin, the current plugin will fail to load. +function after:displayresults(results) +end + +-- Adding methods to the around object causes them to be called +-- instead of the original method of the same name. The new +-- method receives all of the arguments that the original would, +-- except it also receives the original method as the first argument. +-- This way, the new method may invoke the original as it pleases. +-- If the method being added (in this case displayresults) does not exist on +-- the REPL object loading this plugin, the current plugin will fail to load. +function around:evalute(orig, chunk) +end + +-- Adding methods to the override object causes them to be called +-- instead of the original method of the same name. If the method being added +-- (in this case displayresults) does not exist on the REPL object loading this +-- plugin, the current plugin will fail to load. +function override:name() + return 'Plugin!' +end diff --git a/lib/lua-repl/repl/plugins/filename_completion.lua b/lib/lua-repl/repl/plugins/filename_completion.lua new file mode 100644 index 00000000..c16729f3 --- /dev/null +++ b/lib/lua-repl/repl/plugins/filename_completion.lua @@ -0,0 +1,63 @@ +local utils = require 'repl.utils' +local lfs = require 'lfs' + +repl:requirefeature 'completion' + +local function guess_directory_separator(file_name) + return file_name:match('/') or + file_name:match('\\') or + '/' +end + +local function split_parent_directory(file_name) + local parent_directory, directory_entry = + file_name:match('^(.+)[\\/](.+)$') + if not parent_directory then + parent_directory = '.' + directory_entry = file_name + end + return parent_directory, directory_entry +end + +local function is_ignored_directory_entry(entry) + return entry == '.' or + entry == '..' +end + +local function replace_end_of_string(str, suffix, replacement) + assert(str:sub(-#suffix) == suffix) + return str:sub(1, -(#suffix+1)) .. replacement +end + +local function complete_file_name(file_name, expr, callback) + local directory, partial_entry = split_parent_directory(file_name) + for entry in lfs.dir(directory) do + if not is_ignored_directory_entry(entry) and + entry:find(partial_entry, 1, true) == 1 then + callback(replace_end_of_string(expr, partial_entry, entry)) + end + end +end + +local function complete_directory(directory, expr, callback) + for entry in lfs.dir(directory) do + if not is_ignored_directory_entry(entry) then + callback(expr..entry) + end + end +end + +function after:complete(expr, callback) + if utils.ends_in_unfinished_string(expr) then + local file_name = expr:match('[%w@/\\.-_+#$%%{}[%]!~ ]+$') + if file_name then + if file_name:find('[/\\]$') then + complete_directory(file_name, expr, callback) + else + complete_file_name(file_name, expr, callback) + end + else + complete_directory('.', expr, callback) + end + end +end diff --git a/lib/lua-repl/repl/plugins/history.lua b/lib/lua-repl/repl/plugins/history.lua new file mode 100644 index 00000000..6330dbd2 --- /dev/null +++ b/lib/lua-repl/repl/plugins/history.lua @@ -0,0 +1,60 @@ +-- Copyright (c) 2011-2015 Rob Hoelz <rob@hoelz.ro> +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +-- the Software, and to permit persons to whom the Software is furnished to do so, +-- subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +-- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +-- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +-- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +local history_file + +local function invokecallback(self, name, ...) + if not self._history_callbacks then + return + end + + local impl = self._history_callbacks[name] + return impl(...) +end + +local function init() + if os.getenv 'HOME' then + history_file = os.getenv('HOME') .. '/.rep.lua.history' + end +end + +-- XXX I don't know if this callback setup way +-- is the best way to go about this (in fact +-- I'm pretty sure it isn't), but I just need +-- something that works right now. +function repl:setuphistorycallbacks(callbacks) + self._history_callbacks = callbacks + + if history_file then + invokecallback(self, 'load', history_file) + end +end + +function after:handleline(line) + invokecallback(self, 'addline', line) +end + +function before:shutdown() + if history_file then + invokecallback(self, 'save', history_file) + end +end + +features = 'history' + +init() diff --git a/lib/lua-repl/repl/plugins/keep_last_eval.lua b/lib/lua-repl/repl/plugins/keep_last_eval.lua new file mode 100644 index 00000000..01a77946 --- /dev/null +++ b/lib/lua-repl/repl/plugins/keep_last_eval.lua @@ -0,0 +1,43 @@ +-- Copyright (c) 2011-2015 Rob Hoelz <rob@hoelz.ro> +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +-- the Software, and to permit persons to whom the Software is furnished to do so, +-- subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +-- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +-- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +-- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +-- A plugin that stores the results of the last evaluation in _G._ + +local tostring = tostring + +function before:displayresults(results) + local context = self:getcontext() + + if self._keep_eval_lastn then + context._ = nil + + for i = 1, self._keep_eval_lastn do + context['_' .. tostring(i)] = nil + end + end + + if results.n > 0 then + context._ = results[1] + + for i = 1, results.n do + context['_' .. tostring(i)] = results[i] + end + + self._keep_eval_lastn = results.n + end +end diff --git a/lib/lua-repl/repl/plugins/linenoise.lua b/lib/lua-repl/repl/plugins/linenoise.lua new file mode 100644 index 00000000..4407c535 --- /dev/null +++ b/lib/lua-repl/repl/plugins/linenoise.lua @@ -0,0 +1,59 @@ +-- Copyright (c) 2011-2015 Rob Hoelz <rob@hoelz.ro> +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +-- the Software, and to permit persons to whom the Software is furnished to do so, +-- subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +-- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +-- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +-- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +-- A plugin that uses linenoise (https://github.com/hoelzro/lua-linenoise) for prompting + +local ln = require 'linenoise' + +repl:requirefeature 'console' + +function override:showprompt(prompt) + self._prompt = prompt -- XXX how do we make sure other plugins don't step on this? +end + +function override:lines() + return function() + return ln.linenoise(self._prompt .. ' ') + end +end + +repl:iffeature('completion', function() + ln.setcompletion(function(completions, line) + repl:complete(line, function(completion) + ln.addcompletion(completions, completion) + end) + end) +end) + +repl:ifplugin('history', function() + repl:setuphistorycallbacks { + load = function(filename) + ln.historyload(filename) + end, + + addline = function(line) + ln.historyadd(line) + end, + + save = function(filename) + ln.historysave(filename) + end, + } +end) + +features = 'input' diff --git a/lib/lua-repl/repl/plugins/pretty_print.lua b/lib/lua-repl/repl/plugins/pretty_print.lua new file mode 100644 index 00000000..2318f444 --- /dev/null +++ b/lib/lua-repl/repl/plugins/pretty_print.lua @@ -0,0 +1,262 @@ +-- Copyright (c) 2011-2015 Rob Hoelz <rob@hoelz.ro> +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +-- the Software, and to permit persons to whom the Software is furnished to do so, +-- subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +-- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +-- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +-- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +-- Pretty prints expression results (console only) + +local format = string.format +local tconcat = table.concat +local tsort = table.sort +local tostring = tostring +local type = type +local floor = math.floor +local pairs = pairs +local ipairs = ipairs +local error = error +local stderr = io.stderr + +pcall(require, 'luarocks.require') +local ok, term = pcall(require, 'term') +if not ok then + term = nil +end + +local keywords = { + ['and'] = true, + ['break'] = true, + ['do'] = true, + ['else'] = true, + ['elseif'] = true, + ['end'] = true, + ['false'] = true, + ['for'] = true, + ['function'] = true, + ['if'] = true, + ['in'] = true, + ['local'] = true, + ['nil'] = true, + ['not'] = true, + ['or'] = true, + ['repeat'] = true, + ['return'] = true, + ['then'] = true, + ['true'] = true, + ['until'] = true, + ['while'] = true, +} + +local function compose(f, g) + return function(...) + return f(g(...)) + end +end + +local emptycolormap = setmetatable({}, { __index = function() + return function(s) + return s + end +end}) + +local colormap = emptycolormap + +if term then + colormap = { + ['nil'] = term.colors.blue, + string = term.colors.yellow, + punctuation = compose(term.colors.green, term.colors.bright), + ident = term.colors.red, + boolean = term.colors.green, + number = term.colors.cyan, + path = term.colors.white, + misc = term.colors.magenta, + } +end + +local function isinteger(n) + return type(n) == 'number' and floor(n) == n +end + +local function isident(s) + return type(s) == 'string' and not keywords[s] and s:match('^[a-zA-Z_][a-zA-Z0-9_]*$') +end + +-- most of these are arbitrary, I *do* want numbers first, though +local type_order = { + number = 0, + string = 1, + userdata = 2, + table = 3, + thread = 4, + boolean = 5, + ['function'] = 6, + cdata = 7, +} + +local function cross_type_order(a, b) + local pos_a = type_order[ type(a) ] + local pos_b = type_order[ type(b) ] + + if pos_a == pos_b then + return a < b + else + return pos_a < pos_b + end +end + +local function sortedpairs(t) + local keys = {} + + local seen_non_string + + for k in pairs(t) do + keys[#keys + 1] = k + + if not seen_non_string and type(k) ~= 'string' then + seen_non_string = true + end + end + + local sort_func = seen_non_string and cross_type_order or nil + tsort(keys, sort_func) + + local index = 1 + return function() + if keys[index] == nil then + return nil + else + local key = keys[index] + local value = t[key] + index = index + 1 + + return key, value + end + end, keys +end + +local function find_longstring_nest_level(s) + local level = 0 + + while s:find(']' .. string.rep('=', level) .. ']', 1, true) do + level = level + 1 + end + + return level +end + +local function dump(params) + local pieces = params.pieces + local seen = params.seen + local path = params.path + local v = params.value + local indent = params.indent + + local t = type(v) + + if t == 'nil' or t == 'boolean' or t == 'number' then + pieces[#pieces + 1] = colormap[t](tostring(v)) + elseif t == 'string' then + if v:match '\n' then + local level = find_longstring_nest_level(v) + pieces[#pieces + 1] = colormap.string('[' .. string.rep('=', level) .. '[' .. v .. ']' .. string.rep('=', level) .. ']') + else + pieces[#pieces + 1] = colormap.string(format('%q', v)) + end + elseif t == 'table' then + if seen[v] then + pieces[#pieces + 1] = colormap.path(seen[v]) + return + end + + seen[v] = path + + local lastintkey = 0 + + pieces[#pieces + 1] = colormap.punctuation '{\n' + for i, v in ipairs(v) do + for j = 1, indent do + pieces[#pieces + 1] = ' ' + end + dump { + pieces = pieces, + seen = seen, + path = path .. '[' .. tostring(i) .. ']', + value = v, + indent = indent + 1, + } + pieces[#pieces + 1] = colormap.punctuation ',\n' + lastintkey = i + end + + for k, v in sortedpairs(v) do + if not (isinteger(k) and k <= lastintkey and k > 0) then + for j = 1, indent do + pieces[#pieces + 1] = ' ' + end + + if isident(k) then + pieces[#pieces + 1] = colormap.ident(k) + else + pieces[#pieces + 1] = colormap.punctuation '[' + dump { + pieces = pieces, + seen = seen, + path = path .. '.' .. tostring(k), + value = k, + indent = indent + 1, + } + pieces[#pieces + 1] = colormap.punctuation ']' + end + pieces[#pieces + 1] = colormap.punctuation ' = ' + dump { + pieces = pieces, + seen = seen, + path = path .. '.' .. tostring(k), + value = v, + indent = indent + 1, + } + pieces[#pieces + 1] = colormap.punctuation ',\n' + end + end + + for j = 1, indent - 1 do + pieces[#pieces + 1] = ' ' + end + + pieces[#pieces + 1] = colormap.punctuation '}' + else + pieces[#pieces + 1] = colormap.misc(tostring(v)) + end +end + +repl:requirefeature 'console' + +function override:displayresults(results) + local pieces = {} + + for i = 1, results.n do + dump { + pieces = pieces, + seen = {}, + path = '<topvalue>', + value = results[i], + indent = 1, + } + pieces[#pieces + 1] = '\n' + end + + stderr:write(tconcat(pieces, '')) +end diff --git a/lib/lua-repl/repl/plugins/rcfile.lua b/lib/lua-repl/repl/plugins/rcfile.lua new file mode 100644 index 00000000..a74e81ac --- /dev/null +++ b/lib/lua-repl/repl/plugins/rcfile.lua @@ -0,0 +1,54 @@ +-- Copyright (c) 2011-2015 Rob Hoelz <rob@hoelz.ro> +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +-- the Software, and to permit persons to whom the Software is furnished to do so, +-- subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +-- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +-- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +-- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +-- A plugin that runs code in $HOME/.rep.lua before the REPL starts + +local setfenv = require('repl.utils').setfenv + +local function readable(filename) + local f = io.open(filename, 'r') + if not f then + return false + end + f:close() + return true +end + +local function init() + local home = os.getenv 'HOME' + + if not home then + return + end + + local rcfile = home .. '/.rep.lua' + + if not readable(rcfile) then + return + end + + local chunk = assert(loadfile(rcfile)) + local env = setmetatable({ repl = repl }, { __index = _G, __newindex = _G }) + + setfenv(chunk, env) + + chunk() + return true +end + +return init() diff --git a/lib/lua-repl/repl/plugins/rlwrap.lua b/lib/lua-repl/repl/plugins/rlwrap.lua new file mode 100644 index 00000000..9f195a3f --- /dev/null +++ b/lib/lua-repl/repl/plugins/rlwrap.lua @@ -0,0 +1,41 @@ +-- Copyright (c) 2011-2015 Rob Hoelz <rob@hoelz.ro> +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +-- the Software, and to permit persons to whom the Software is furnished to do so, +-- subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +-- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +-- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +-- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +if os.getenv 'LUA_REPL_RLWRAP' then + features = 'input' +else + -- XXX check that we're not receiving input from a non-tty + local has_rlwrap = os.execute('which rlwrap >/dev/null 2>/dev/null') + + if type(has_rlwrap) ~= 'boolean' then + has_rlwrap = has_rlwrap == 0 + end + + if not has_rlwrap then + error 'Please install rlwrap in order to use the rlwrap plugin' + end + + local lowest_index = -1 + + while arg[lowest_index] ~= nil do + lowest_index = lowest_index - 1 + end + lowest_index = lowest_index + 1 + os.execute(string.format('LUA_REPL_RLWRAP=1 rlwrap %q %q', arg[lowest_index], arg[0])) + os.exit(0) +end diff --git a/lib/lua-repl/repl/plugins/semicolon_suppress_output.lua b/lib/lua-repl/repl/plugins/semicolon_suppress_output.lua new file mode 100644 index 00000000..4adaecb6 --- /dev/null +++ b/lib/lua-repl/repl/plugins/semicolon_suppress_output.lua @@ -0,0 +1,36 @@ +-- Copyright (c) 2011-2015 Rob Hoelz <rob@hoelz.ro> +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +-- the Software, and to permit persons to whom the Software is furnished to do so, +-- subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +-- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +-- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +-- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +local smatch = string.match + +-- XXX will this affect any other plugins? +function around:compilechunk(orig, chunk) + local f, err = orig(self, chunk) + + if not f then + return f, err + end + + if smatch(chunk, ';%s*$') then + return function() + f() + end + end + + return f +end |
