git subrepo clone https://gitlab.com/technomancy/jeejah.git vendor/jeejah
subrepo: subdir: "vendor/jeejah" merged: "3ed9eb1" upstream: origin: "https://gitlab.com/technomancy/jeejah.git" branch: "master" commit: "3ed9eb1" git-subrepo: version: "0.4.2" origin: "https://github.com/ingydotnet/git-subrepo" commit: "65fde50"
This commit is contained in:
parent
3d52b70bbc
commit
c843deea3d
12
vendor/jeejah/.gitrepo
vendored
Normal file
12
vendor/jeejah/.gitrepo
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
; DO NOT EDIT (unless you know what you are doing)
|
||||||
|
;
|
||||||
|
; This subdirectory is a git "subrepo", and this file is maintained by the
|
||||||
|
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
|
||||||
|
;
|
||||||
|
[subrepo]
|
||||||
|
remote = https://gitlab.com/technomancy/jeejah.git
|
||||||
|
branch = master
|
||||||
|
commit = 3ed9eb1f368c825e33e73dec0bcc9c553c33cf82
|
||||||
|
parent = 3d52b70bbcc475d8ef69accd990c367f1a72bbba
|
||||||
|
method = merge
|
||||||
|
cmdver = 0.4.2
|
31
vendor/jeejah/Changelog.md
vendored
Normal file
31
vendor/jeejah/Changelog.md
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# Jeejah changelog: history of user-visible changes
|
||||||
|
|
||||||
|
## 0.3.1 / 2020-04-24
|
||||||
|
|
||||||
|
* Fix compatibility for Lua 5.1 and 5.2.
|
||||||
|
* Improve error reporting.
|
||||||
|
* Move Fennel support to special handler instead of middleware.
|
||||||
|
|
||||||
|
## 0.3.0 / 2019-08-01
|
||||||
|
|
||||||
|
* Fix a bug with socket timeout.
|
||||||
|
* Add foreground mode.
|
||||||
|
* Avoid burning CPU when there's nothing to do.
|
||||||
|
|
||||||
|
## 0.2.1 / 2019-05-21
|
||||||
|
|
||||||
|
* Add support for launching a Fennel server using middleware.
|
||||||
|
* Add support for middleware.
|
||||||
|
* Support Luas newer than 5.1.
|
||||||
|
|
||||||
|
## 0.2.0 / 2016-06-20
|
||||||
|
|
||||||
|
* Support requesting a read from stdin.
|
||||||
|
* Support stopping the server.
|
||||||
|
* Change module API to return a table, not a function.
|
||||||
|
* Support multiple sessions.
|
||||||
|
|
||||||
|
## 0.1.0 / 2016-06-09
|
||||||
|
|
||||||
|
* Initial release!
|
||||||
|
|
19
vendor/jeejah/LICENSE
vendored
Normal file
19
vendor/jeejah/LICENSE
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright © 2016-2019 Phil Hagelberg and contributors
|
||||||
|
|
||||||
|
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.
|
1
vendor/jeejah/Makefile
vendored
Normal file
1
vendor/jeejah/Makefile
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
check: ; luacheck --std max jeejah.lua bencode.lua
|
94
vendor/jeejah/Readme.md
vendored
Normal file
94
vendor/jeejah/Readme.md
vendored
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
# JeeJah
|
||||||
|
|
||||||
|
An nREPL server for [Fennel](https://fennel-lang.org) and [Lua](https://lua.org).
|
||||||
|
|
||||||
|
## A what now?
|
||||||
|
|
||||||
|
The [nREPL protocol](https://nrepl.org/nrepl/index.html#_why_nrepl)
|
||||||
|
allows developers to embed a server in their programs to which
|
||||||
|
external programs can connect for development, debugging, etc.
|
||||||
|
|
||||||
|
The original implementation of the protocol was written in Clojure,
|
||||||
|
and many clients assume they will connect to a Clojure server; however
|
||||||
|
the protocol is quite agnostic about what language is being
|
||||||
|
evaluated. It supports evaluating snippets of code or whole files with
|
||||||
|
`print` and `io.write` redirected back to the connected client.
|
||||||
|
|
||||||
|
This library was originally written to add Emacs support to
|
||||||
|
[Bussard](https://gitlab.com/technomancy/bussard), a spaceflight
|
||||||
|
programming game.
|
||||||
|
|
||||||
|
Currently mainly tested with
|
||||||
|
[monroe](https://github.com/sanel/monroe/) and
|
||||||
|
[shevek](https://git.sr.ht/~technomancy/shevek/) as
|
||||||
|
clients. [grenchman](https://leiningen.org/grench.html) version 0.3.0+
|
||||||
|
works. Other clients exist for Vim, Eclipse, and Atom, as well as
|
||||||
|
several independent command-line clients; however these may require
|
||||||
|
some adaptation to work with Jeejah. If you try your favorite client
|
||||||
|
and find that it makes Clojure-specific assumptions, please report a
|
||||||
|
bug with it so that it can gracefully degrade when those assumptions
|
||||||
|
don't hold.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
The pure-Lua dependencies are included (`bencode`, `serpent`, and
|
||||||
|
`fennel`) but you will need to install `luasocket` yourself. If your
|
||||||
|
operating system does not provide it, you can install it using LuaRocks:
|
||||||
|
|
||||||
|
$ luarocks install --local luasocket
|
||||||
|
|
||||||
|
Note that [LÖVE](https://love2d.org) ships with its own copy of
|
||||||
|
luasocket, so there is no need to install it there.
|
||||||
|
|
||||||
|
You can symlink `bin/jeejah` to your `$PATH` or something.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
You can launch a standalone nREPL server:
|
||||||
|
|
||||||
|
$ bin/jeejah
|
||||||
|
|
||||||
|
Pass in a `--fennel` flag to start a server for evaluating Fennel code
|
||||||
|
instead of Lua. Accepts a `--port` argument and a `--debug` flag.
|
||||||
|
|
||||||
|
You can use it as a library too, of course:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local jeejah = require("jeejah")
|
||||||
|
local coro = jeejah.start(port, {debug=true, sandbox={x=12}})
|
||||||
|
```
|
||||||
|
|
||||||
|
The function returns a coroutine which you'll need to repeatedly
|
||||||
|
resume in order to handle requests. Each accepted connection is stored
|
||||||
|
in a coroutine internal to that function; these are each repeatedly
|
||||||
|
resumed by the main coroutine. If all you're doing is starting an
|
||||||
|
nrepl server, you can pass `foreground=true` in the options table to
|
||||||
|
leave the server running in the foreground and skip the step of
|
||||||
|
resuming the coroutine.
|
||||||
|
|
||||||
|
Note that the sandbox feature is not well-tested or audited and should
|
||||||
|
not be trusted to provide robust security. It currently only works
|
||||||
|
with Lua 5.1 and LuaJIT.
|
||||||
|
|
||||||
|
You can also pass in a `handlers` table where the keys are custom
|
||||||
|
[nREPL ops](https://nrepl.org/nrepl/ops.html)
|
||||||
|
you want to handle yourself.
|
||||||
|
|
||||||
|
## Completion
|
||||||
|
|
||||||
|
The included `monroe-lua-complete.el` file adds support for completion
|
||||||
|
to the Monroe client by querying the connected nREPL server for
|
||||||
|
possibilities. Simply invoke `completion-at-point` (bound to `C-M-i`
|
||||||
|
by default) when connected.
|
||||||
|
|
||||||
|
## Caveats
|
||||||
|
|
||||||
|
PUC Lua 5.1 does not allow yielding coroutines from inside protected
|
||||||
|
calls, which means you cannot use `io.read`, though LuaJIT and
|
||||||
|
Lua 5.2+ allow it.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Copyright © 2016-2020 Phil Hagelberg and contributors
|
||||||
|
|
||||||
|
Distributed under the MIT license; see file LICENSE
|
78
vendor/jeejah/bencode.lua
vendored
Normal file
78
vendor/jeejah/bencode.lua
vendored
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
local encode, decode
|
||||||
|
|
||||||
|
local function decode_list(str, t, total_len)
|
||||||
|
-- print("list", str, lume.serialize(t))
|
||||||
|
if(str:sub(1,1) == "e") then return t, total_len + 1 end
|
||||||
|
local value, v_len = decode(str)
|
||||||
|
table.insert(t, value)
|
||||||
|
total_len = total_len + v_len
|
||||||
|
return decode_list(str:sub(v_len + 1), t, total_len)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function decode_table(str, t, total_len)
|
||||||
|
-- print("table", str, lume.serialize(t))
|
||||||
|
if(str:sub(1,1) == "e") then return t, total_len + 1 end
|
||||||
|
local key, k_len = decode(str)
|
||||||
|
local value, v_len = decode(str:sub(k_len+1))
|
||||||
|
local end_pos = 1 + k_len + v_len
|
||||||
|
t[key] = value
|
||||||
|
total_len = total_len + k_len + v_len
|
||||||
|
return decode_table(str:sub(end_pos), t, total_len)
|
||||||
|
end
|
||||||
|
|
||||||
|
function decode(str)
|
||||||
|
-- print("decoding", str)
|
||||||
|
if(str:sub(1,1) == "l") then
|
||||||
|
return decode_list(str:sub(2), {}, 1)
|
||||||
|
elseif(str:sub(1,1) == "d") then
|
||||||
|
return decode_table(str:sub(2), {}, 1)
|
||||||
|
elseif(str:sub(1,1) == "i") then
|
||||||
|
return(tonumber(str:sub(2, str:find("e") - 1))), str:find("e")
|
||||||
|
elseif(str:match("[0-9]+")) then
|
||||||
|
local num_str = str:match("[0-9]+")
|
||||||
|
local beginning_of_string = #num_str + 2
|
||||||
|
local str_len = tonumber(num_str)
|
||||||
|
local total_len = beginning_of_string + str_len - 1
|
||||||
|
return str:sub(beginning_of_string, total_len), total_len
|
||||||
|
else
|
||||||
|
error("Could not parse "..str)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function encode_str(s) return #s .. ":" .. s end
|
||||||
|
local function encode_int(n) return "i" .. tostring(n) .. "e" end
|
||||||
|
|
||||||
|
local function encode_table(t)
|
||||||
|
local s = "d"
|
||||||
|
for k,v in pairs(t) do s = s .. encode(k) .. encode(v) end
|
||||||
|
return s .. "e"
|
||||||
|
end
|
||||||
|
|
||||||
|
local function encode_list(l)
|
||||||
|
local s = "l"
|
||||||
|
for _,x in ipairs(l) do s = s .. encode(x) end
|
||||||
|
return s .. "e"
|
||||||
|
end
|
||||||
|
|
||||||
|
local function count(tbl)
|
||||||
|
local i = 0
|
||||||
|
for _ in pairs(tbl) do i = i + 1 end
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
|
||||||
|
function encode(x)
|
||||||
|
local unpack = unpack or table.unpack
|
||||||
|
if(type(x) == "table" and select("#", unpack(x)) == count(x)) then
|
||||||
|
return encode_list(x)
|
||||||
|
elseif(type(x) == "table") then
|
||||||
|
return encode_table(x)
|
||||||
|
elseif(type(x) == "number" and math.floor(x) == x) then
|
||||||
|
return encode_int(x)
|
||||||
|
elseif(type(x) == "string") then
|
||||||
|
return encode_str(x)
|
||||||
|
else
|
||||||
|
error("Could not encode " .. type(x) .. ": " .. tostring(x))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {decode=decode, encode=encode}
|
35
vendor/jeejah/bin/jeejah
vendored
Executable file
35
vendor/jeejah/bin/jeejah
vendored
Executable file
|
@ -0,0 +1,35 @@
|
||||||
|
#!/usr/bin/env lua
|
||||||
|
|
||||||
|
require "luarocks.loader"
|
||||||
|
|
||||||
|
local opts, port = {foreground = true}
|
||||||
|
|
||||||
|
for n,v in ipairs(arg) do
|
||||||
|
if(v == "--port") then
|
||||||
|
port = arg[n+1]
|
||||||
|
elseif(v == "--fennel") then
|
||||||
|
opts.fennel = true
|
||||||
|
elseif(v == "--debug") then
|
||||||
|
opts.debug = true
|
||||||
|
elseif(v == "--empty-sandbox") then
|
||||||
|
opts.sandbox = {}
|
||||||
|
elseif(v == "--version" or v == "--help") then
|
||||||
|
print("jeejah 0.2.0\n")
|
||||||
|
print("Options:")
|
||||||
|
print(" --fennel Start a Fennel server instead of Lua")
|
||||||
|
print(" --port Port on which to listen")
|
||||||
|
print(" --debug Print verbose debugging information")
|
||||||
|
os.exit(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local root_dir = debug.getinfo(1).source:sub(2, -(1+#"bin/jeejah"))
|
||||||
|
local search_parent = string.format("%s?.lua;%s", root_dir, package.path)
|
||||||
|
if(package.searchpath) then
|
||||||
|
local jeejah = dofile(package.searchpath("jeejah", search_parent))
|
||||||
|
jeejah.start(port, opts)
|
||||||
|
else -- 5.1
|
||||||
|
if root_dir == "" then root_dir = "." end
|
||||||
|
local jeejah = dofile(root_dir .. "/jeejah.lua")
|
||||||
|
jeejah.start(port, opts)
|
||||||
|
end
|
2229
vendor/jeejah/fennel.lua
vendored
Normal file
2229
vendor/jeejah/fennel.lua
vendored
Normal file
File diff suppressed because it is too large
Load diff
156
vendor/jeejah/fennelview.fnl
vendored
Normal file
156
vendor/jeejah/fennelview.fnl
vendored
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
;; A pretty-printer that outputs tables in Fennel syntax.
|
||||||
|
;; Loosely based on inspect.lua: http://github.com/kikito/inspect.lua
|
||||||
|
|
||||||
|
(local view-quote (fn [str] (.. '"' (: str :gsub '"' '\\"') '"')))
|
||||||
|
|
||||||
|
(local short-control-char-escapes
|
||||||
|
{"\a" "\\a" "\b" "\\b" "\f" "\\f" "\n" "\\n"
|
||||||
|
"\r" "\\r" "\t" "\\t" "\v" "\\v"})
|
||||||
|
|
||||||
|
(local long-control-char-esapes
|
||||||
|
(let [long {}]
|
||||||
|
(for [i 0 31]
|
||||||
|
(let [ch (string.char i)]
|
||||||
|
(when (not (. short-control-char-escapes ch))
|
||||||
|
(tset short-control-char-escapes ch (.. "\\" i))
|
||||||
|
(tset long ch (: "\\%03d" :format i)))))
|
||||||
|
long))
|
||||||
|
|
||||||
|
(fn escape [str]
|
||||||
|
(let [str (: str :gsub "\\" "\\\\")
|
||||||
|
str (: str :gsub "(%c)%f[0-9]" long-control-char-esapes)]
|
||||||
|
(: str :gsub "%c" short-control-char-escapes)))
|
||||||
|
|
||||||
|
(fn sequence-key? [k len]
|
||||||
|
(and (= (type k) "number")
|
||||||
|
(<= 1 k)
|
||||||
|
(<= k len)
|
||||||
|
(= (math.floor k) k)))
|
||||||
|
|
||||||
|
(local type-order {:number 1 :boolean 2 :string 3 :table 4
|
||||||
|
:function 5 :userdata 6 :thread 7})
|
||||||
|
|
||||||
|
(fn sort-keys [a b]
|
||||||
|
(let [ta (type a) tb (type b)]
|
||||||
|
(if (and (= ta tb) (~= ta "boolean")
|
||||||
|
(or (= ta "string") (= ta "number")))
|
||||||
|
(< a b)
|
||||||
|
(let [dta (. type-order a)
|
||||||
|
dtb (. type-order b)]
|
||||||
|
(if (and dta dtb)
|
||||||
|
(< dta dtb)
|
||||||
|
dta true
|
||||||
|
dtb false
|
||||||
|
:else (< ta tb))))))
|
||||||
|
|
||||||
|
(fn get-sequence-length [t]
|
||||||
|
(var len 1)
|
||||||
|
(each [i (ipairs t)] (set len i))
|
||||||
|
len)
|
||||||
|
|
||||||
|
(fn get-nonsequential-keys [t]
|
||||||
|
(let [keys {}
|
||||||
|
sequence-length (get-sequence-length t)]
|
||||||
|
(each [k (pairs t)]
|
||||||
|
(when (not (sequence-key? k sequence-length))
|
||||||
|
(table.insert keys k)))
|
||||||
|
(table.sort keys sort-keys)
|
||||||
|
(values keys sequence-length)))
|
||||||
|
|
||||||
|
(fn count-table-appearances [t appearances]
|
||||||
|
(if (= (type t) "table")
|
||||||
|
(when (not (. appearances t))
|
||||||
|
(tset appearances t 1)
|
||||||
|
(each [k v (pairs t)]
|
||||||
|
(count-table-appearances k appearances)
|
||||||
|
(count-table-appearances v appearances)))
|
||||||
|
(when (and t (= t t)) ; no nans please
|
||||||
|
(tset appearances t (+ (or (. appearances t) 0) 1))))
|
||||||
|
appearances)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(var put-value nil) ; mutual recursion going on; defined below
|
||||||
|
|
||||||
|
(fn puts [self ...]
|
||||||
|
(each [_ v (ipairs [...])]
|
||||||
|
(table.insert self.buffer v)))
|
||||||
|
|
||||||
|
(fn tabify [self] (puts self "\n" (: self.indent :rep self.level)))
|
||||||
|
|
||||||
|
(fn already-visited? [self v] (~= (. self.ids v) nil))
|
||||||
|
|
||||||
|
(fn get-id [self v]
|
||||||
|
(var id (. self.ids v))
|
||||||
|
(when (not id)
|
||||||
|
(let [tv (type v)]
|
||||||
|
(set id (+ (or (. self.max-ids tv) 0) 1))
|
||||||
|
(tset self.max-ids tv id)
|
||||||
|
(tset self.ids v id)))
|
||||||
|
(tostring id))
|
||||||
|
|
||||||
|
(fn put-sequential-table [self t length]
|
||||||
|
(puts self "[")
|
||||||
|
(set self.level (+ self.level 1))
|
||||||
|
(for [i 1 length]
|
||||||
|
(puts self " ")
|
||||||
|
(put-value self (. t i)))
|
||||||
|
(set self.level (- self.level 1))
|
||||||
|
(puts self " ]"))
|
||||||
|
|
||||||
|
(fn put-key [self k]
|
||||||
|
(if (and (= (type k) "string")
|
||||||
|
(: k :find "^[-%w?\\^_`!#$%&*+./@~:|<=>]+$"))
|
||||||
|
(puts self ":" k)
|
||||||
|
(put-value self k)))
|
||||||
|
|
||||||
|
(fn put-kv-table [self t]
|
||||||
|
(puts self "{")
|
||||||
|
(set self.level (+ self.level 1))
|
||||||
|
(each [k v (pairs t)]
|
||||||
|
(tabify self)
|
||||||
|
(put-key self k)
|
||||||
|
(puts self " ")
|
||||||
|
(put-value self v))
|
||||||
|
(set self.level (- self.level 1))
|
||||||
|
(tabify self)
|
||||||
|
(puts self "}"))
|
||||||
|
|
||||||
|
(fn put-table [self t]
|
||||||
|
(if (already-visited? self t)
|
||||||
|
(puts self "#<table " (get-id self t) ">")
|
||||||
|
(>= self.level self.depth)
|
||||||
|
(puts self "{...}")
|
||||||
|
:else
|
||||||
|
(let [(non-seq-keys length) (get-nonsequential-keys t)
|
||||||
|
id (get-id self t)]
|
||||||
|
(if (> (. self.appearances t) 1)
|
||||||
|
(puts self "#<" id ">")
|
||||||
|
(and (= (# non-seq-keys) 0) (= (# t) 0))
|
||||||
|
(puts self "{}")
|
||||||
|
(= (# non-seq-keys) 0)
|
||||||
|
(put-sequential-table self t length)
|
||||||
|
:else
|
||||||
|
(put-kv-table self t)))))
|
||||||
|
|
||||||
|
(set put-value (fn [self v]
|
||||||
|
(let [tv (type v)]
|
||||||
|
(if (= tv "string")
|
||||||
|
(puts self (view-quote (escape v)))
|
||||||
|
(or (= tv "number") (= tv "boolean") (= tv "nil"))
|
||||||
|
(puts self (tostring v))
|
||||||
|
(= tv "table")
|
||||||
|
(put-table self v)
|
||||||
|
:else
|
||||||
|
(puts self "#<" (tostring v) ">")))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(fn fennelview [root options]
|
||||||
|
(let [options (or options {})
|
||||||
|
inspector {:appearances (count-table-appearances root {})
|
||||||
|
:depth (or options.depth 128)
|
||||||
|
:level 0 :buffer {} :ids {} :max-ids {}
|
||||||
|
:indent (or options.indent " ")}]
|
||||||
|
(put-value inspector root)
|
||||||
|
(table.concat inspector.buffer)))
|
357
vendor/jeejah/jeejah.lua
vendored
Normal file
357
vendor/jeejah/jeejah.lua
vendored
Normal file
|
@ -0,0 +1,357 @@
|
||||||
|
local socket = require "socket"
|
||||||
|
local serpent = require "serpent"
|
||||||
|
local bencode = require "bencode"
|
||||||
|
|
||||||
|
local load = loadstring or load
|
||||||
|
|
||||||
|
local timeout = 0.001
|
||||||
|
|
||||||
|
local d = os.getenv("DEBUG") and print or function(_) end
|
||||||
|
local serpent_pp = function(p) return function(x)
|
||||||
|
local serpent_opts = {maxlevel=8,maxnum=64,nocode=true}
|
||||||
|
p(serpent.block(x, serpent_opts)) end
|
||||||
|
end
|
||||||
|
local sessions = {}
|
||||||
|
|
||||||
|
local response_for = function(old_msg, msg)
|
||||||
|
-- certain implementations break when the ns field is empty; see
|
||||||
|
-- https://gitlab.com/technomancy/jeejah/issues/5
|
||||||
|
msg.session, msg.id, msg.ns = old_msg.session, old_msg.id, ">"
|
||||||
|
return msg
|
||||||
|
end
|
||||||
|
|
||||||
|
local send = function(conn, msg)
|
||||||
|
d("Sending", bencode.encode(msg))
|
||||||
|
conn:send(bencode.encode(msg))
|
||||||
|
end
|
||||||
|
|
||||||
|
local write_for = function(conn, msg)
|
||||||
|
return function(...)
|
||||||
|
send(conn, response_for(msg, {out=table.concat({...}, "\t")}))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local print_for = function(write)
|
||||||
|
return function(...)
|
||||||
|
local args = {...}
|
||||||
|
for i,x in ipairs(args) do args[i] = tostring(x) end
|
||||||
|
table.insert(args, "\n")
|
||||||
|
write(table.concat(args, " "))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local read_for = function(conn, msg)
|
||||||
|
return function()
|
||||||
|
send(conn, response_for(msg, {status={"need-input"}}))
|
||||||
|
while(not sessions[msg.session].input) do
|
||||||
|
coroutine.yield()
|
||||||
|
d("yielded")
|
||||||
|
end
|
||||||
|
local input = sessions[msg.session].input
|
||||||
|
sessions[msg.session].input = nil
|
||||||
|
return input
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local sandbox_for = function(write, provided_sandbox)
|
||||||
|
local sandbox = { io = { write = write },
|
||||||
|
print = print_for(write), }
|
||||||
|
for k,v in pairs(provided_sandbox) do
|
||||||
|
sandbox[k] = v
|
||||||
|
end
|
||||||
|
return sandbox
|
||||||
|
end
|
||||||
|
|
||||||
|
-- for stuff that's shared between eval and load_file
|
||||||
|
local execute_chunk = function(session, chunk, pp)
|
||||||
|
local old_write, old_print, old_read = io.write, print, io.read
|
||||||
|
if(session.sandbox) then
|
||||||
|
setfenv(chunk, session.sandbox)
|
||||||
|
pp = pp or serpent_pp(session.sandbox.print)
|
||||||
|
else
|
||||||
|
_G.print = print_for(session.write)
|
||||||
|
_G.io.write, _G.io.read = session.write, session.read
|
||||||
|
pp = pp or serpent_pp(_G.print)
|
||||||
|
end
|
||||||
|
|
||||||
|
local trace, err
|
||||||
|
local result = {xpcall(chunk, function(e)
|
||||||
|
trace = debug.traceback()
|
||||||
|
err = e end)}
|
||||||
|
|
||||||
|
_G.print, _G.io.write, _G.io.read = old_print, old_write, old_read
|
||||||
|
|
||||||
|
if(result[1]) then
|
||||||
|
local res, i = pp(result[2]), 3
|
||||||
|
while i <= #result do
|
||||||
|
res = res .. ', ' .. pp(result[i])
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
return res
|
||||||
|
else
|
||||||
|
return nil, (err or "Unknown error") .. "\n" .. trace
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local eval = function(session, code, pp)
|
||||||
|
local chunk, err = load("return " .. code, "*socket*")
|
||||||
|
if(err and not chunk) then -- statement, not expression
|
||||||
|
chunk, err = load(code, "*socket*")
|
||||||
|
if(not chunk) then
|
||||||
|
return nil, "Compilation error: " .. (err or "unknown")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return execute_chunk(session, chunk, pp)
|
||||||
|
end
|
||||||
|
|
||||||
|
local load_file = function(session, file, loader)
|
||||||
|
local chunk, err = (loader or loadfile)(file)
|
||||||
|
if(not chunk) then
|
||||||
|
return nil, "Compilation error in " .. file ": ".. (err or "unknown")
|
||||||
|
end
|
||||||
|
return execute_chunk(session, chunk)
|
||||||
|
end
|
||||||
|
|
||||||
|
local register_session = function(conn, msg, provided_sandbox)
|
||||||
|
local id = tostring(math.random(999999999))
|
||||||
|
local write = write_for(conn, msg)
|
||||||
|
local sandbox = provided_sandbox and sandbox_for(write, provided_sandbox)
|
||||||
|
sessions[id] = { conn = conn, write = write, print = print_for(write),
|
||||||
|
sandbox = sandbox, coros = {}, id = id}
|
||||||
|
return response_for(msg, {["new-session"]=id, status={"done"}})
|
||||||
|
end
|
||||||
|
|
||||||
|
local unregister_session = function(msg)
|
||||||
|
sessions[msg.session] = nil
|
||||||
|
return response_for(msg, {status={"done"}})
|
||||||
|
end
|
||||||
|
|
||||||
|
local describe = function(msg, handlers)
|
||||||
|
local ops = { "clone", "close", "describe", "eval", "load-file",
|
||||||
|
"ls-sessions", "complete", "stdin", "interrupt" }
|
||||||
|
for op in handlers do table.insert(ops, op) end
|
||||||
|
return response_for(msg, {ops=ops, status={"done"}})
|
||||||
|
end
|
||||||
|
|
||||||
|
local session_for = function(conn, msg, sandbox)
|
||||||
|
local s = sessions[msg.session] or register_session(conn, msg, sandbox)
|
||||||
|
s.write = write_for(conn, msg)
|
||||||
|
s.read = read_for(conn, msg)
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
local complete = function(msg, sandbox)
|
||||||
|
local clone = function(t)
|
||||||
|
local n = {} for k,v in pairs(t) do n[k] = v end return n
|
||||||
|
end
|
||||||
|
local top_ctx = clone(sandbox or _G)
|
||||||
|
for k,v in pairs(msg.libs or {}) do
|
||||||
|
top_ctx[k] = require(v:sub(2,-2))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function cpl_for(input_parts, ctx)
|
||||||
|
if type(ctx) ~= "table" then return {} end
|
||||||
|
if #input_parts == 0 and ctx ~= top_ctx then
|
||||||
|
return ctx
|
||||||
|
elseif #input_parts == 1 then
|
||||||
|
local matches = {}
|
||||||
|
for k in pairs(ctx) do
|
||||||
|
if k:find('^' .. input_parts[1]) then
|
||||||
|
table.insert(matches, k)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return matches
|
||||||
|
else
|
||||||
|
local token1 = table.remove(input_parts, 1)
|
||||||
|
return cpl_for(input_parts, ctx[token1])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local input_parts = {}
|
||||||
|
for i in string.gmatch(msg.input, "([^.%s]+)") do
|
||||||
|
table.insert(input_parts, i)
|
||||||
|
end
|
||||||
|
return response_for(msg, {completions = cpl_for(input_parts, top_ctx)})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- see https://github.com/clojure/tools.nrepl/blob/master/doc/ops.md
|
||||||
|
local handle = function(conn, handlers, sandbox, msg)
|
||||||
|
if(handlers and handlers[msg.op]) then
|
||||||
|
d("Custom op:", msg.op)
|
||||||
|
handlers[msg.op](conn, msg, session_for(conn, msg, sandbox),
|
||||||
|
send, response_for)
|
||||||
|
elseif(msg.op == "clone") then
|
||||||
|
d("New session.")
|
||||||
|
send(conn, register_session(conn, msg, sandbox))
|
||||||
|
elseif(msg.op == "describe") then
|
||||||
|
d("Describe.")
|
||||||
|
send(conn, describe(msg, handlers))
|
||||||
|
elseif(msg.op == "eval") then
|
||||||
|
d("Evaluating", msg.code)
|
||||||
|
local value, err = eval(session_for(conn, msg, sandbox), msg.code, msg.pp)
|
||||||
|
d("Got", value, err)
|
||||||
|
-- monroe bug means you have to send done status separately
|
||||||
|
send(conn, response_for(msg, {value=value, ex=err}))
|
||||||
|
send(conn, response_for(msg, {status={"done"}}))
|
||||||
|
elseif(msg.op == "load-file") then
|
||||||
|
d("Loading file", msg.file)
|
||||||
|
local value, err = load_file(session_for(conn, msg, sandbox),
|
||||||
|
msg.file, msg.loader)
|
||||||
|
d("Got", value, err)
|
||||||
|
send(conn, response_for(msg, {value=value, ex=err, status={"done"}}))
|
||||||
|
elseif(msg.op == "ls-sessions") then
|
||||||
|
d("List sessions")
|
||||||
|
local session_ids = {}
|
||||||
|
for id in pairs(sessions) do table.insert(session_ids, id) end
|
||||||
|
send(conn, response_for(msg, {sessions=session_ids, status={"done"}}))
|
||||||
|
elseif(msg.op == "complete") then
|
||||||
|
d("Complete", msg.input)
|
||||||
|
local session_sandbox = session_for(conn, msg, sandbox).sandbox
|
||||||
|
send(conn, complete(msg, session_sandbox))
|
||||||
|
elseif(msg.op == "stdin") then
|
||||||
|
d("Stdin", serpent.block(msg))
|
||||||
|
sessions[msg.session].input = msg.stdin
|
||||||
|
send(conn, response_for(msg, {status={"done"}}))
|
||||||
|
return
|
||||||
|
elseif(msg.op ~= "interrupt") then -- silently ignore interrupt
|
||||||
|
send(conn, response_for(msg, {status={"unknown-op"}}))
|
||||||
|
print(" | Unknown op", serpent.block(msg))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local handler_coros = {}
|
||||||
|
|
||||||
|
local function receive(conn, partial)
|
||||||
|
local s, err = conn:receive(1) -- wow this is primitive
|
||||||
|
-- iterate backwards so we can safely remove
|
||||||
|
for i=#handler_coros, 1, -1 do
|
||||||
|
local ok, err2 = coroutine.resume(handler_coros[i])
|
||||||
|
if(coroutine.status(handler_coros[i]) ~= "suspended") then
|
||||||
|
if(not ok) then print(" | Handler error", err2) end
|
||||||
|
table.remove(handler_coros, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if(s) then
|
||||||
|
return receive(conn, (partial or "") .. s)
|
||||||
|
elseif(err == "timeout" and partial == nil) then
|
||||||
|
coroutine.yield()
|
||||||
|
return receive(conn)
|
||||||
|
elseif(err == "timeout") then
|
||||||
|
return partial
|
||||||
|
else
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function client_loop(conn, sandbox, handlers, middleware, partial)
|
||||||
|
local input, r_err = receive(conn, partial)
|
||||||
|
if(input) then
|
||||||
|
local decoded, d_err = bencode.decode(input)
|
||||||
|
if decoded and d_err < #input then
|
||||||
|
partial = input:sub(d_err + 1)
|
||||||
|
else
|
||||||
|
partial = nil
|
||||||
|
end
|
||||||
|
coroutine.yield()
|
||||||
|
if(decoded and decoded.op == "close") then
|
||||||
|
d("End session.")
|
||||||
|
return send(conn, unregister_session(decoded))
|
||||||
|
elseif(decoded and decoded.op ~= "close") then
|
||||||
|
-- If we don't spin up a coroutine here, we can't io.read, because
|
||||||
|
-- that requires waiting for a response from the client. But most
|
||||||
|
-- messages don't need to stick around.
|
||||||
|
local coro = coroutine.create(handle)
|
||||||
|
if(middleware) then
|
||||||
|
middleware(function(msg)
|
||||||
|
local ok, err = coroutine.resume(coro, conn, handlers,
|
||||||
|
sandbox, msg)
|
||||||
|
if(not ok) then print(" | Handler error", err) end
|
||||||
|
end, decoded)
|
||||||
|
else
|
||||||
|
local ok, err = coroutine.resume(coro, conn, handlers,
|
||||||
|
sandbox, decoded)
|
||||||
|
if(not ok) then print(" | Handler error", err) end
|
||||||
|
end
|
||||||
|
if(coroutine.status(coro) == "suspended") then
|
||||||
|
table.insert(handler_coros, coro)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
print(" | Decoding error:", d_err)
|
||||||
|
end
|
||||||
|
return client_loop(conn, sandbox, handlers, middleware, partial)
|
||||||
|
else
|
||||||
|
return r_err
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local connections = {}
|
||||||
|
|
||||||
|
local function loop(server, sandbox, handlers, middleware, foreground)
|
||||||
|
socket.sleep(timeout)
|
||||||
|
local conn, err = server:accept()
|
||||||
|
local stop = (not foreground) and (coroutine.yield() == "stop")
|
||||||
|
if(conn) then
|
||||||
|
conn:settimeout(timeout)
|
||||||
|
d("Connected.")
|
||||||
|
local coro = coroutine.create(function()
|
||||||
|
local _, h_err = pcall(client_loop, conn, sandbox, handlers, middleware)
|
||||||
|
if(h_err ~= "closed") then print("Connection closed: " .. h_err) end
|
||||||
|
end)
|
||||||
|
table.insert(connections, coro)
|
||||||
|
return loop(server, sandbox, handlers, middleware, foreground)
|
||||||
|
else
|
||||||
|
if(err ~= "timeout") then print(" | Socket error: " .. err) end
|
||||||
|
for _,c in ipairs(connections) do coroutine.resume(c) end
|
||||||
|
if(stop or err == "closed") then
|
||||||
|
server:close()
|
||||||
|
print("Server stopped.")
|
||||||
|
else
|
||||||
|
return loop(server, sandbox, handlers, middleware, foreground)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
-- Start an nrepl socket server on the given port. For opts you can pass a
|
||||||
|
-- table with foreground=true to run in the foreground, debug=true for
|
||||||
|
-- verbose logging, and sandbox={...} to evaluate all code in a sandbox. You
|
||||||
|
-- can also give an opts.handlers table keying ops to handler functions which
|
||||||
|
-- take the socket, the decoded message, and the optional sandbox table.
|
||||||
|
start = function(port, opts)
|
||||||
|
port = port or 7888
|
||||||
|
opts = opts or {}
|
||||||
|
opts.handlers = opts.handlers or {}
|
||||||
|
-- host should always be localhost on a PC, but not always on a micro
|
||||||
|
local server = assert(socket.bind(opts.host or "localhost", port))
|
||||||
|
if(opts.debug) then d = print end
|
||||||
|
if(opts.timeout) then timeout = tonumber(opts.timeout) end
|
||||||
|
if(opts.fennel) then
|
||||||
|
local fenneleval = require("jeejah.fenneleval")
|
||||||
|
opts.handlers.eval = fenneleval
|
||||||
|
opts.handlers.stdin = fenneleval
|
||||||
|
end
|
||||||
|
assert(not opts.sandbox or setfenv, "Can't use sandbox on 5.2+")
|
||||||
|
|
||||||
|
server:settimeout(timeout)
|
||||||
|
print("Server started on port " .. port .. "...")
|
||||||
|
if opts.foreground then
|
||||||
|
return loop(server, opts.sandbox, opts.handlers,
|
||||||
|
opts.middleware, opts.foreground)
|
||||||
|
else
|
||||||
|
return coroutine.create(function()
|
||||||
|
loop(server, opts.sandbox, opts.handlers, opts.middleware)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- Pass in the coroutine from jeejah.start to this function to stop it.
|
||||||
|
stop = function(coro)
|
||||||
|
coroutine.resume(coro, "stop")
|
||||||
|
end,
|
||||||
|
|
||||||
|
broadcast = function(msg)
|
||||||
|
for _,session in pairs(sessions) do
|
||||||
|
send(session.conn, msg)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
}
|
77
vendor/jeejah/jeejah/fenneleval.lua
vendored
Normal file
77
vendor/jeejah/jeejah/fenneleval.lua
vendored
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
local fennel = require("fennel")
|
||||||
|
local fennelview_ok, fennelview = pcall(require, "fennelview")
|
||||||
|
if not fennelview_ok then fennelview = fennel.dofile("fennelview.fnl") end
|
||||||
|
|
||||||
|
local d = os.getenv("DEBUG") and print or function(_) end
|
||||||
|
|
||||||
|
local repls = {}
|
||||||
|
|
||||||
|
local print_for = function(write)
|
||||||
|
return function(...)
|
||||||
|
local args = {...}
|
||||||
|
for i,x in ipairs(args) do args[i] = tostring(x) end
|
||||||
|
table.insert(args, "\n")
|
||||||
|
write(table.concat(args, " "))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local make_repl = function(session, repls)
|
||||||
|
local on_values = function(xs)
|
||||||
|
session.values(xs)
|
||||||
|
session.done({status={"done"}})
|
||||||
|
end
|
||||||
|
local read = function()
|
||||||
|
-- If we skip empty input, it confuses the client.
|
||||||
|
local input = coroutine.yield()
|
||||||
|
if(input:find("^%s*$")) then return "nil\n" else return input end
|
||||||
|
end
|
||||||
|
local err = function(errtype, msg)
|
||||||
|
session.write(table.concat({errtype, msg}, ": ")) session.done()
|
||||||
|
end
|
||||||
|
|
||||||
|
local env = session.sandbox
|
||||||
|
if not env then
|
||||||
|
env = {}
|
||||||
|
for k, v in pairs(_G) do env[k] = v end
|
||||||
|
env.io = {}
|
||||||
|
end
|
||||||
|
env.print = print_for(session.write)
|
||||||
|
env.io.write = session.write
|
||||||
|
env.io.read = function()
|
||||||
|
session.needinput()
|
||||||
|
local input, done = coroutine.yield()
|
||||||
|
done()
|
||||||
|
return input
|
||||||
|
end
|
||||||
|
|
||||||
|
local f = function()
|
||||||
|
return fennel.repl({readChunk = read,
|
||||||
|
onValues = on_values,
|
||||||
|
onError = err,
|
||||||
|
env = env,
|
||||||
|
pp = fennelview})
|
||||||
|
end
|
||||||
|
repls[session.id] = coroutine.wrap(f)
|
||||||
|
repls[session.id]()
|
||||||
|
return repls[session.id]
|
||||||
|
end
|
||||||
|
|
||||||
|
return function(conn, msg, session, send, response_for)
|
||||||
|
d("Evaluating", msg.code)
|
||||||
|
local repl = repls[session.id] or make_repl(session, repls)
|
||||||
|
if msg.op == "eval" then
|
||||||
|
session.values = function(xs)
|
||||||
|
send(conn, response_for(msg, {value=table.concat(xs, "\n") .. "\n"}))
|
||||||
|
end
|
||||||
|
session.done = function()
|
||||||
|
send(conn, response_for(msg, {status={"done"}}))
|
||||||
|
end
|
||||||
|
session.needinput = function()
|
||||||
|
send(conn, response_for(msg, {status={"need-input"}}))
|
||||||
|
end
|
||||||
|
repl(msg.code .. "\n")
|
||||||
|
elseif msg.op == "stdin" then
|
||||||
|
repl(msg.stdin,
|
||||||
|
function() send(conn, response_for(msg, {status={"done"}})) end)
|
||||||
|
end
|
||||||
|
end
|
89
vendor/jeejah/monroe-lua-complete.el
vendored
Normal file
89
vendor/jeejah/monroe-lua-complete.el
vendored
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
;;; monroe-lua-complete.el --- Completion for Lua over Monroe connection
|
||||||
|
|
||||||
|
;; Copyright © 2016 Phil Hagelberg
|
||||||
|
;;
|
||||||
|
;; Author: Phil Hagelberg
|
||||||
|
;; URL: https://gitlab.com/technomancy/jeejah
|
||||||
|
;; Version: 0.1.0
|
||||||
|
;; Keywords: languages, nrepl, lua
|
||||||
|
|
||||||
|
;; This program is free software: you can redistribute it and/or modify
|
||||||
|
;; it under the terms of the GNU General Public License as published by
|
||||||
|
;; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
;; (at your option) any later version.
|
||||||
|
|
||||||
|
;; This program is distributed in the hope that it will be useful,
|
||||||
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
;; GNU General Public License for more details.
|
||||||
|
|
||||||
|
;; You should have received a copy of the GNU General Public License
|
||||||
|
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
;; This file is not part of GNU Emacs.
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; Provides live completion results for Lua by querying a Lua process
|
||||||
|
;; over an nREPL connection. Uses `completion-at-point' but can be
|
||||||
|
;; adapted for other completion methods.
|
||||||
|
|
||||||
|
;;; Installation:
|
||||||
|
|
||||||
|
;; Copy it to your load-path and (require 'monroe-lua-complete)
|
||||||
|
|
||||||
|
;;; Usage:
|
||||||
|
|
||||||
|
;; * Launch an nREPL server using jeejah.
|
||||||
|
;; * Connect to it with M-x monroe.
|
||||||
|
;; * Complete the expression at point with M-x completion-at-point
|
||||||
|
;; also bound to M-tab or C-M-i.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(require 'lua-mode) ; requires a newer lua-mode that has lua-start-of-expr
|
||||||
|
(require 'monroe)
|
||||||
|
|
||||||
|
(defvar monroe-completion-candidates nil)
|
||||||
|
|
||||||
|
(defun monroe-completion-handler (response)
|
||||||
|
"Set `monroe-completion-candidates' based on response from Lua server.
|
||||||
|
|
||||||
|
Since monroe doesn't have any synchronous communication available, we
|
||||||
|
have to `sit-for' and hope a response has been returned and handled."
|
||||||
|
(monroe-dbind-response response (id completions status output)
|
||||||
|
(let ((process (get-buffer-process monroe-repl-buffer)))
|
||||||
|
(comint-output-filter process output)
|
||||||
|
(when completions
|
||||||
|
(setq monroe-completion-candidates completions))
|
||||||
|
(when status
|
||||||
|
(when (member "done" status)
|
||||||
|
(remhash id monroe-requests))))))
|
||||||
|
|
||||||
|
(defun monroe-lua-complete-function ()
|
||||||
|
"Completion function for `completion-at-point-functions'.
|
||||||
|
|
||||||
|
Queries over current lua connection for possible completions."
|
||||||
|
(let ((expr (buffer-substring-no-properties (lua-start-of-expr) (point))))
|
||||||
|
(monroe-send-request `("op" "complete"
|
||||||
|
"input" ,expr
|
||||||
|
;; TODO: at this time, monroe cannot bencode
|
||||||
|
;; nested values, only string->string dicts
|
||||||
|
;; "libs" ,(lua-local-libs)
|
||||||
|
"session" ,(monroe-current-session))
|
||||||
|
'monroe-completion-handler))
|
||||||
|
(sit-for 0.1)
|
||||||
|
(list (save-excursion (when (symbol-at-point) (backward-sexp)) (point))
|
||||||
|
(point)
|
||||||
|
monroe-completion-candidates))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun monroe-lua-hook ()
|
||||||
|
(make-local-variable 'completion-at-point-functions)
|
||||||
|
(add-to-list 'completion-at-point-functions 'monroe-lua-complete-function))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(eval-after-load 'lua-mode
|
||||||
|
'(add-to-list 'lua-mode-hook 'monroe-lua-hook))
|
||||||
|
|
||||||
|
;;; monroe-lua-complete.el ends here
|
28
vendor/jeejah/rockspecs/jeejah-0.1.0-1.rockspec
vendored
Normal file
28
vendor/jeejah/rockspecs/jeejah-0.1.0-1.rockspec
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
-- -*- lua -*-
|
||||||
|
|
||||||
|
package = "jeejah"
|
||||||
|
version = "0.1.0-1"
|
||||||
|
source = {
|
||||||
|
url = "https://gitlab.com/technomancy/jeejah.git",
|
||||||
|
tag = "0.1.0",
|
||||||
|
}
|
||||||
|
description = {
|
||||||
|
summary = "An nREPL server",
|
||||||
|
detailed = [[
|
||||||
|
Implements a server that speaks the nREPL protocol and allows
|
||||||
|
clients to connect and evaluate code over a network connection.
|
||||||
|
]],
|
||||||
|
homepage = "https://gitlab.com/technomancy/jeejah.git",
|
||||||
|
license = "MIT/X11",
|
||||||
|
}
|
||||||
|
dependencies = {
|
||||||
|
"lua ~> 5.1",
|
||||||
|
"luasocket = 3.0rc1-2",
|
||||||
|
"serpent = 0.28-1",
|
||||||
|
"bencode = 2.2.0-1",
|
||||||
|
}
|
||||||
|
build = {
|
||||||
|
type = "builtin",
|
||||||
|
modules = { jeejah = "jeejah.lua", },
|
||||||
|
install = { bin = { "bin/jeejah" } },
|
||||||
|
}
|
28
vendor/jeejah/rockspecs/jeejah-0.2.1-1.rockspec
vendored
Normal file
28
vendor/jeejah/rockspecs/jeejah-0.2.1-1.rockspec
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
-- -*- lua -*-
|
||||||
|
|
||||||
|
package = "jeejah"
|
||||||
|
version = "0.2.1-1"
|
||||||
|
source = {
|
||||||
|
url = "git+https://gitlab.com/technomancy/jeejah.git",
|
||||||
|
tag = "0.2.1",
|
||||||
|
}
|
||||||
|
description = {
|
||||||
|
summary = "An nREPL server",
|
||||||
|
detailed = [[
|
||||||
|
Implements a server that speaks the nREPL protocol and allows
|
||||||
|
clients to connect and evaluate code over a network connection.
|
||||||
|
]],
|
||||||
|
homepage = "https://gitlab.com/technomancy/jeejah",
|
||||||
|
license = "MIT/X11",
|
||||||
|
}
|
||||||
|
dependencies = {
|
||||||
|
"lua >= 5.1",
|
||||||
|
"luasocket = 3.0rc1-2",
|
||||||
|
"serpent = 0.28-1",
|
||||||
|
"bencode = 2.2.0-1",
|
||||||
|
}
|
||||||
|
build = {
|
||||||
|
type = "builtin",
|
||||||
|
modules = { jeejah = "jeejah.lua", },
|
||||||
|
install = { bin = { "bin/jeejah" } },
|
||||||
|
}
|
28
vendor/jeejah/rockspecs/jeejah-0.2.1-4.rockspec
vendored
Normal file
28
vendor/jeejah/rockspecs/jeejah-0.2.1-4.rockspec
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
-- -*- lua -*-
|
||||||
|
|
||||||
|
package = "jeejah"
|
||||||
|
version = "0.2.1-4"
|
||||||
|
source = {
|
||||||
|
url = "git+https://gitlab.com/technomancy/jeejah.git",
|
||||||
|
tag = "0.2.4",
|
||||||
|
}
|
||||||
|
description = {
|
||||||
|
summary = "An nREPL server",
|
||||||
|
detailed = [[
|
||||||
|
Implements a server that speaks the nREPL protocol and allows
|
||||||
|
clients to connect and evaluate code over a network connection.
|
||||||
|
]],
|
||||||
|
homepage = "https://gitlab.com/technomancy/jeejah",
|
||||||
|
license = "MIT/X11",
|
||||||
|
}
|
||||||
|
dependencies = {
|
||||||
|
"lua >= 5.1",
|
||||||
|
"luasocket = 3.0rc1-2",
|
||||||
|
"serpent = 0.28-1",
|
||||||
|
"bencode = 2.2.0-1",
|
||||||
|
}
|
||||||
|
build = {
|
||||||
|
type = "builtin",
|
||||||
|
modules = { jeejah = "jeejah.lua", },
|
||||||
|
install = { bin = { "bin/jeejah" } },
|
||||||
|
}
|
28
vendor/jeejah/rockspecs/jeejah-0.3.0-1.rockspec
vendored
Normal file
28
vendor/jeejah/rockspecs/jeejah-0.3.0-1.rockspec
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
-- -*- lua -*-
|
||||||
|
|
||||||
|
package = "jeejah"
|
||||||
|
version = "0.3.0-1"
|
||||||
|
source = {
|
||||||
|
url = "git+https://gitlab.com/technomancy/jeejah.git",
|
||||||
|
tag = "0.3.0",
|
||||||
|
}
|
||||||
|
description = {
|
||||||
|
summary = "An nREPL server",
|
||||||
|
detailed = [[
|
||||||
|
Implements a server that speaks the nREPL protocol and allows
|
||||||
|
clients to connect and evaluate code over a network connection.
|
||||||
|
]],
|
||||||
|
homepage = "https://gitlab.com/technomancy/jeejah",
|
||||||
|
license = "MIT/X11",
|
||||||
|
}
|
||||||
|
dependencies = {
|
||||||
|
"lua >= 5.1",
|
||||||
|
"luasocket = 3.0rc1-2",
|
||||||
|
"serpent = 0.28-1",
|
||||||
|
"bencode = 2.2.0-1",
|
||||||
|
}
|
||||||
|
build = {
|
||||||
|
type = "builtin",
|
||||||
|
modules = { jeejah = "jeejah.lua", },
|
||||||
|
install = { bin = { "bin/jeejah" } },
|
||||||
|
}
|
28
vendor/jeejah/rockspecs/jeejah-0.3.1-1.rockspec
vendored
Normal file
28
vendor/jeejah/rockspecs/jeejah-0.3.1-1.rockspec
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
-- -*- lua -*-
|
||||||
|
|
||||||
|
package = "jeejah"
|
||||||
|
version = "0.3.1-1"
|
||||||
|
source = {
|
||||||
|
url = "git+https://gitlab.com/technomancy/jeejah.git",
|
||||||
|
tag = "0.3.1",
|
||||||
|
}
|
||||||
|
description = {
|
||||||
|
summary = "An nREPL server",
|
||||||
|
detailed = [[
|
||||||
|
Implements a server that speaks the nREPL protocol and allows
|
||||||
|
clients to connect and evaluate code over a network connection.
|
||||||
|
]],
|
||||||
|
homepage = "https://gitlab.com/technomancy/jeejah",
|
||||||
|
license = "MIT/X11",
|
||||||
|
}
|
||||||
|
dependencies = {
|
||||||
|
"lua >= 5.1",
|
||||||
|
"luasocket = 3.0rc1-2",
|
||||||
|
"serpent = 0.28-1",
|
||||||
|
"bencode = 2.2.0-1",
|
||||||
|
}
|
||||||
|
build = {
|
||||||
|
type = "builtin",
|
||||||
|
modules = { jeejah = "jeejah.lua", },
|
||||||
|
install = { bin = { "bin/jeejah" } },
|
||||||
|
}
|
29
vendor/jeejah/rockspecs/jeejah-0.3.1-2.rockspec
vendored
Normal file
29
vendor/jeejah/rockspecs/jeejah-0.3.1-2.rockspec
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
-- -*- lua -*-
|
||||||
|
|
||||||
|
package = "jeejah"
|
||||||
|
version = "0.3.1-2"
|
||||||
|
source = {
|
||||||
|
url = "git+https://gitlab.com/technomancy/jeejah.git",
|
||||||
|
tag = "0.3.1",
|
||||||
|
}
|
||||||
|
description = {
|
||||||
|
summary = "An nREPL server",
|
||||||
|
detailed = [[
|
||||||
|
Implements a server that speaks the nREPL protocol and allows
|
||||||
|
clients to connect and evaluate code over a network connection.
|
||||||
|
]],
|
||||||
|
homepage = "https://gitlab.com/technomancy/jeejah",
|
||||||
|
license = "MIT/X11",
|
||||||
|
}
|
||||||
|
dependencies = {
|
||||||
|
"lua >= 5.1",
|
||||||
|
"luasocket = 3.0rc1-2",
|
||||||
|
"serpent = 0.28-1",
|
||||||
|
"bencode = 2.2.0-1",
|
||||||
|
}
|
||||||
|
build = {
|
||||||
|
type = "builtin",
|
||||||
|
modules = { jeejah = "jeejah.lua",
|
||||||
|
["jeejah.fenneleval"] = "jeejah/fenneleval.lua" },
|
||||||
|
install = { bin = { "bin/jeejah" } },
|
||||||
|
}
|
30
vendor/jeejah/rockspecs/jeejah-0.3.1-4.rockspec
vendored
Normal file
30
vendor/jeejah/rockspecs/jeejah-0.3.1-4.rockspec
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
-- -*- lua -*-
|
||||||
|
|
||||||
|
package = "jeejah"
|
||||||
|
version = "0.3.1-4"
|
||||||
|
source = {
|
||||||
|
url = "git+https://gitlab.com/technomancy/jeejah.git",
|
||||||
|
tag = "0.3.1",
|
||||||
|
}
|
||||||
|
description = {
|
||||||
|
summary = "An nREPL server",
|
||||||
|
detailed = [[
|
||||||
|
Implements a server that speaks the nREPL protocol and allows
|
||||||
|
clients to connect and evaluate code over a network connection.
|
||||||
|
]],
|
||||||
|
homepage = "https://gitlab.com/technomancy/jeejah",
|
||||||
|
license = "MIT/X11",
|
||||||
|
}
|
||||||
|
dependencies = {
|
||||||
|
"lua >= 5.1",
|
||||||
|
"luasocket = 3.0rc1-2",
|
||||||
|
"serpent = 0.28-1",
|
||||||
|
}
|
||||||
|
build = {
|
||||||
|
type = "builtin",
|
||||||
|
modules = { jeejah = "jeejah.lua",
|
||||||
|
["jeejah.fenneleval"] = "jeejah/fenneleval.lua",
|
||||||
|
bencode = "bencode.lua",
|
||||||
|
},
|
||||||
|
install = { bin = { "bin/jeejah" } },
|
||||||
|
}
|
125
vendor/jeejah/serpent.lua
vendored
Normal file
125
vendor/jeejah/serpent.lua
vendored
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
local n, v = "serpent", 0.28 -- (C) 2012-15 Paul Kulchenko; MIT License
|
||||||
|
local c, d = "Paul Kulchenko", "Lua serializer and pretty printer"
|
||||||
|
local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'}
|
||||||
|
local badtype = {thread = true, userdata = true, cdata = true}
|
||||||
|
local keyword, globals, G = {}, {}, (_G or _ENV)
|
||||||
|
for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false',
|
||||||
|
'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat',
|
||||||
|
'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end
|
||||||
|
for k,v in pairs(G) do globals[v] = k end -- build func to name mapping
|
||||||
|
for _,g in ipairs({'coroutine', 'debug', 'io', 'math', 'string', 'table', 'os'}) do
|
||||||
|
for k,v in pairs(G[g] or {}) do globals[v] = g..'.'..k end end
|
||||||
|
|
||||||
|
local function s(t, opts)
|
||||||
|
local name, indent, fatal, maxnum = opts.name, opts.indent, opts.fatal, opts.maxnum
|
||||||
|
local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge
|
||||||
|
local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge)
|
||||||
|
local iname, comm = '_'..(name or ''), opts.comment and (tonumber(opts.comment) or math.huge)
|
||||||
|
local seen, sref, syms, symn = {}, {'local '..iname..'={}'}, {}, 0
|
||||||
|
local function gensym(val) return '_'..(tostring(tostring(val)):gsub("[^%w]",""):gsub("(%d%w+)",
|
||||||
|
-- tostring(val) is needed because __tostring may return a non-string value
|
||||||
|
function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return tostring(syms[s]) end)) end
|
||||||
|
local function safestr(s) return type(s) == "number" and tostring(huge and snum[tostring(s)] or s)
|
||||||
|
or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026
|
||||||
|
or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end
|
||||||
|
local function comment(s,l) return comm and (l or 0) < comm and ' --[['..tostring(s)..']]' or '' end
|
||||||
|
local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal
|
||||||
|
and safestr(select(2, pcall(tostring, s))) or error("Can't serialize "..tostring(s)) end
|
||||||
|
local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r']
|
||||||
|
local n = name == nil and '' or name
|
||||||
|
local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n]
|
||||||
|
local safe = plain and n or '['..safestr(n)..']'
|
||||||
|
return (path or '')..(plain and path and '.' or '')..safe, safe end
|
||||||
|
local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(k, o, n) -- k=keys, o=originaltable, n=padding
|
||||||
|
local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'}
|
||||||
|
local function padnum(d) return ("%0"..tostring(maxn).."d"):format(tonumber(d)) end
|
||||||
|
table.sort(k, function(a,b)
|
||||||
|
-- sort numeric keys first: k[key] is not nil for numerical keys
|
||||||
|
return (k[a] ~= nil and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum))
|
||||||
|
< (k[b] ~= nil and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end
|
||||||
|
local function val2str(t, name, indent, insref, path, plainindex, level)
|
||||||
|
local ttype, level, mt = type(t), (level or 0), getmetatable(t)
|
||||||
|
local spath, sname = safename(path, name)
|
||||||
|
local tag = plainindex and
|
||||||
|
((type(name) == "number") and '' or name..space..'='..space) or
|
||||||
|
(name ~= nil and sname..space..'='..space or '')
|
||||||
|
if seen[t] then -- already seen this element
|
||||||
|
sref[#sref+1] = spath..space..'='..space..seen[t]
|
||||||
|
return tag..'nil'..comment('ref', level) end
|
||||||
|
if type(mt) == 'table' and (mt.__serialize or mt.__tostring) then -- knows how to serialize itself
|
||||||
|
seen[t] = insref or spath
|
||||||
|
if mt.__serialize then t = mt.__serialize(t) else t = tostring(t) end
|
||||||
|
ttype = type(t) end -- new value falls through to be serialized
|
||||||
|
if ttype == "table" then
|
||||||
|
if level >= maxl then return tag..'{}'..comment('max', level) end
|
||||||
|
seen[t] = insref or spath
|
||||||
|
-- PNH: this breaks with our metatable monkeypatch to support iterators
|
||||||
|
-- if next(t) == nil then return tag..'{}'..comment(t, level) end -- table empty
|
||||||
|
local maxn, o, out = math.min(#t, maxnum or #t), {}, {}
|
||||||
|
for key = 1, maxn do o[key] = key end
|
||||||
|
if not maxnum or #o < maxnum then
|
||||||
|
local n = #o -- n = n + 1; o[n] is much faster than o[#o+1] on large tables
|
||||||
|
for key in pairs(t) do if o[key] ~= key then n = n + 1; o[n] = key end end end
|
||||||
|
if maxnum and #o > maxnum then o[maxnum+1] = nil end
|
||||||
|
if opts.sortkeys and #o > maxn then alphanumsort(o, t, opts.sortkeys) end
|
||||||
|
local sparse = sparse and #o > maxn -- disable sparsness if only numeric keys (shorter output)
|
||||||
|
for n, key in ipairs(o) do
|
||||||
|
local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse
|
||||||
|
if opts.valignore and opts.valignore[value] -- skip ignored values; do nothing
|
||||||
|
or opts.keyallow and not opts.keyallow[key]
|
||||||
|
or opts.valtypeignore and opts.valtypeignore[type(value)] -- skipping ignored value types
|
||||||
|
or sparse and value == nil then -- skipping nils; do nothing
|
||||||
|
elseif ktype == 'table' or ktype == 'function' or badtype[ktype] then
|
||||||
|
if not seen[key] and not globals[key] then
|
||||||
|
sref[#sref+1] = 'placeholder'
|
||||||
|
local sname = safename(iname, gensym(key)) -- iname is table for local variables
|
||||||
|
sref[#sref] = val2str(key,sname,indent,sname,iname,true) end
|
||||||
|
sref[#sref+1] = 'placeholder'
|
||||||
|
local path = seen[t]..'['..tostring(seen[key] or globals[key] or gensym(key))..']'
|
||||||
|
sref[#sref] = path..space..'='..space..tostring(seen[value] or val2str(value,nil,indent,path))
|
||||||
|
else
|
||||||
|
out[#out+1] = val2str(value,key,indent,insref,seen[t],plainindex,level+1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local prefix = string.rep(indent or '', level)
|
||||||
|
local head = indent and '{\n'..prefix..indent or '{'
|
||||||
|
local body = table.concat(out, ','..(indent and '\n'..prefix..indent or space))
|
||||||
|
local tail = indent and "\n"..prefix..'}' or '}'
|
||||||
|
return (custom and custom(tag,head,body,tail) or tag..head..body..tail)..comment(t, level)
|
||||||
|
elseif badtype[ttype] then
|
||||||
|
seen[t] = insref or spath
|
||||||
|
return tag..globerr(t, level)
|
||||||
|
elseif ttype == 'function' then
|
||||||
|
seen[t] = insref or spath
|
||||||
|
local ok, res = pcall(string.dump, t)
|
||||||
|
local func = ok and ((opts.nocode and "function() --[[..skipped..]] end" or
|
||||||
|
"((loadstring or load)("..safestr(res)..",'@serialized'))")..comment(t, level))
|
||||||
|
return tag..(func or globerr(t, level))
|
||||||
|
else return tag..safestr(t) end -- handle all other types
|
||||||
|
end
|
||||||
|
local sepr = indent and "\n" or ";"..space
|
||||||
|
local body = val2str(t, name, indent) -- this call also populates sref
|
||||||
|
local tail = #sref>1 and table.concat(sref, sepr)..sepr or ''
|
||||||
|
local warn = opts.comment and #sref>1 and space.."--[[incomplete output with shared/self-references skipped]]" or ''
|
||||||
|
return not name and body..warn or "do local "..body..sepr..tail.."return "..name..sepr.."end"
|
||||||
|
end
|
||||||
|
|
||||||
|
local function deserialize(data, opts)
|
||||||
|
local env = (opts and opts.safe == false) and G
|
||||||
|
or setmetatable({}, {
|
||||||
|
__index = function(t,k) return t end,
|
||||||
|
__call = function(t,...) error("cannot call functions") end
|
||||||
|
})
|
||||||
|
local f, res = (loadstring or load)('return '..data, nil, nil, env)
|
||||||
|
if not f then f, res = (loadstring or load)(data, nil, nil, env) end
|
||||||
|
if not f then return f, res end
|
||||||
|
if setfenv then setfenv(f, env) end
|
||||||
|
return pcall(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end
|
||||||
|
return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s,
|
||||||
|
load = deserialize,
|
||||||
|
dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end,
|
||||||
|
line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end,
|
||||||
|
block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = true}, opts)) end }
|
Loading…
Reference in a new issue