lk.Patch

:findCode (url)

local lib = {type='lk.Patch'} lib.__index = lib lk.Patch = lib local private = {}

Lubyk.mimas_quit_on_close = false

-- PRIVATE local ALLOWED_KEYS = { nodes = true, x = true, y = true, w = true, h = true, hue = true, name = true, }

-- PUBLIC

setmetatable(lib, { -- new method __call = function(lib, name) local self = { name = name, nodes = {}, pending_nodes = {}, on_notify = setmetatable({}, {__mode = 'k'}), } sched.patch = name setmetatable(self, lib)

return self end})

-- When we load from morph, we must set file loader to be the -- remote morph server. (find code) self.is_process = true

-- Create processes watch before loading code (to resolve remote -- processes). -- --- Watch for other processes on the network and create -- lk.RemoteProcess proxies when needed. self.process_watch = lk.ProcessWatch():addDelegate(self) end

--print(string.format("================================= lk.Patch %s\n%s", self.name, yaml.dump(definitions))) --print("================================= lk.Patch ]") for k, v in pairs(definitions) do if k == 'nodes' then private.setNodes(self, v) elseif ALLOWED_KEYS[k] then self[k] = v end end if self.need_cleanup then self.need_cleanup = nil collectgarbage('collect') collectgarbage('collect') end end

--- Create a pending inlet from an url relative to this process (nearly the same -- as editor.Process.pendingInlet). local inlet_url = lk.absToRel(inlet_abs_url, self:url()) -- inlet_url example: -- node/in/slot local parts = lk.split(inlet_url, '/') local node_name, inlet_name if parts == 3 and parts[2] == 'in' then node_name, inlet_name = parts[1], parts[3] else return nil, string.format("Invalid pendingInlet url '%s'.") end

local node = self.nodes[node_name] local inlet = nil if node then -- inlet not created yet inlet = lk.Inlet(inlet_abs_url, inlet_name) node.pending_inlets[inlet_name] = inlet else -- node not created yet local pending_node = self.pending_nodes[node_name] if not pending_node then pending_node = {} self.pending_nodes[node_name] = pending_node end inlet = pending_node[inlet_name] if not inlet then -- We pass absolute url so that the inlet can answer 'url()' requests. inlet = lk.Inlet(inlet_abs_url, inlet_name) pending_node[inlet_name] = inlet end end return inlet end

-- Find an element from an url. An url -- is something like -- /process name/[parent node name]/node name/in/inlet name -- or /process name/[parent node name]/node name -- or [parent node name]/node name -- -- ALSO USED BY editor.Process -- TODO: cache result by full url ? -- not greedy regexp local process_name, path = string.match(url, '^/([^/])/(.*)$')

local process if process_name then process = self:findProcess(process_name) else process = self path = url end

local res = process:findByPath(path) local res_mt = getmetatable(res) if res and mt and mt ~= res_mt then local msg = '' if mt.type and res_mt.type then msg = string.format('expected %s, found %s', mt.type, res_mt.type) elseif res.__tostring then msg = string.format('found %s', res:to__string()) elseif not res then msg = 'found nil' else msg = 'found ?' end return false, string.format("Invalid object at '%s' (%s).", url, msg) else return res end end

-- ALSO USED BY editor.Process local parts = lk.split(path, '/') -- current object local c = self local c_next = 'node'

for i, name in ipairs(parts) do if c_next == 'node' then -- Find node if name == 'in' then c, c_next = c.inlets, 'slot' elseif name == 'out' then c, c_next = c.outlets, 'slot' else -- sub-node 'a/b' lives in nodes.a.nodes.b c = c.nodes[name] end elseif c_next == 'slot' then -- slot list c, c_type = c[name], nil else -- error c = nil end if c == nil then return nil, string.format("Cannot find '%s' while resolving '%s'.", name, path) end end return c end

--- Serialize current patch as a lua table. If a -- data table is provided, only dump parts that contain -- keys in the table. local res = {nodes = {}} for k, _ in pairs(ALLOWED_KEYS) do if k == 'nodes' then local nodes = {} res.nodes = nodes for k, node in pairs(self.nodes) do nodes[k] = node:dump() end else local v = self[k] if v then res[k] = v end end end return res end

--- Serialize part of the current patch as a lua table by only returning -- data for parts that contain keys in the given table. local res = {} local nodes = self.nodes for k, v in pairs(data) do if k == 'nodes' then res.nodes = {} local res_nodes = res.nodes for k, node_data in pairs(v) do local node = nodes[k] if node then res_nodes[k] = node:partialDump(node_data) else res_nodes[k] = false end end elseif ALLOWED_KEYS[k] then res[k] = self[k] end end return res end

--- Find source code for the node at the given url (patch_name/[parent_node/]node_name). --[[

Path organization (local filesystem or remote on Mnémosyne server):

... <== base project directory. This is the current dir for the process
.../A              <== Everything for process with role "A"
.../A/_patch.yml   <== Patch for process with role "A"
.../B              <== Everything for process with role "B"
.../B/_patch.yml   <== Patch for process with role "B"
.../B/foo.lua or
...[node:url()].lua <== Code for node 'foo' in process 'B'
.../lib             <== searched for required code

TODO make async

:findClass (class_name)

TODO MISSING DOCUMENTATION

TODO make async ?

:callback (url, ...)

TODO MISSING DOCUMENTATION

FIXME This is an ugly hack related to post-linking. We notify only

:error (...)

TODO MISSING DOCUMENTATION

TODO notify error

:notify (...)

TODO MISSING DOCUMENTATION

:onNotify (key, callback)

TODO MISSING DOCUMENTATION

:setParam (lubyk, p, param_name, value)

Set a single parameter

:control (url, value)

Set a parameter from a relative url like "metro/@tempo".

FIXME Is this used ?

:findProcess (name)

TODO MISSING DOCUMENTATION

TODO better error handling

:url ()

nodes.

:setMorph (process)

TODO MISSING DOCUMENTATION

:sync ()

TODO MISSING DOCUMENTATION

:processConnected (remote_process)

Callback on found process in ProcessWatch. Not used for the moment.

:processDisconnected (remote_process)

Callback on removed process in ProcessWatch. Not used for the moment.

TODO

#findCodeTODO make async

#findClassTODO MISSING DOCUMENTATION

#findClassTODO make async ?

#callbackTODO MISSING DOCUMENTATION

#errorTODO MISSING DOCUMENTATION

#errorTODO notify error

#notifyTODO MISSING DOCUMENTATION

#onNotifyTODO MISSING DOCUMENTATION

#findProcessTODO MISSING DOCUMENTATION

#findProcessTODO better error handling

#setMorphTODO MISSING DOCUMENTATION

#syncTODO MISSING DOCUMENTATION

FIXME

#callbackFIXME This is an ugly hack related to post-linking. We notify only

#controlFIXME Is this used ?