CC: Tweaked

CC: Tweaked

42M Downloads

Skip "Press any key to continue" prompt from shell.openTab

BlackAsLight opened this issue ยท 5 comments

commented

Useful information to include:

  • Explanation of how the feature/change should work.
  • Some rationale/use case for a feature. My general approach to designing new features is to ask yourself "what issue are we trying to solve" and then "is this the best way to solve this issue?".

When starting a command with shell.openTab('program path') it opens a new shell as expected, but once that program is finished it prompts with "Press any key to continue". I'd like the ability to disable this prompt and it just exit and closes the tab automatically. My use case is that the main shell will open new tabs to process messages it receives over rednet so it doesn't risk missing a message while processing another.

commented

After a bit of testing I don't think it would work. The documentation for this API could be improved though. It lacks what they return and what those values indicate.

parallel.waitForAny() Returns the number, corresponding to their argument position, that finished.
parallel.waitForAll() Returns the number, corresponding to their argument position, that took the longest to finish.

Also. parallel.waitForAny() doesn't seem to ever go back to the one that took longer. So I can't see a way I could always be listening for an incoming message while processing another message happens. Not without calling parellel.waitForAll() in one of the two functions passed in, and I don't know if that will create a scope issue after x amount of requests.

commented

Ahh, this is because coroutines themselves don't know anything about events: you've got pass in the next event in the queue with coroutine.resume. In your case, this'd look something like this:

local threads = {}

-- Create a new coroutine and run it it pulls an event for the first time.
local function add_thread(func)
  local co = coroutine.create(func)

  local ok, result = coroutine.resume(co)
  if not ok then error(result, 0) end

  table.insert(threads, { co = co, filter = result })
end

-- Add your main worker
add_thread(function()
  while true do
    print('Listening...')
    local id, payload = rednet.receive(protocol)
    -- As before...
  end
end)

-- Run all threads
while #threads > 0 do
  -- Pull the next event
  local event = table.pack(os.pullEventRaw())

  -- Then resume all threads with this event.
  for i = #threads, 1, -1 do
    local thread = threads[i]
    if thread.filter == nil or thread.filter == event[1] or event[1] == "terminate" then
      local ok, result = coroutine.resume(thread.co, table.unpack(event, 1, event.n))
      if not ok then error(result, 0) end

      if coroutine.status(thread.co) == "dead" then
        table.remove(threads, i)
      else
        thread.filter = result
      end
    end
  end
end

I should probably add a library to make this easier into CC itself.

commented

I tried making something like this so I'd have some concurrency, but rednet.receive never seems to receive it at all. Removing the sleep in the last while loop seems to make it throw an error.

require('utils')

local protocol = 'DocCrafts'
local hostname = 'DocCrafts.com'

if not OpenRednet() then
	os.exit(64)
end
rednet.host(protocol, hostname)

local function handle(id, payload)
	sleep(1)
	print(id, payload)
end

local i = 1
local max = 1

Threads = {
	[1] = coroutine.create(function()
		while true do
			print('Listening...')
			local id, payload = rednet.receive(protocol)
			print(id, payload)
			local thread = coroutine.create(handle)
			table.insert(Threads, thread)
			max = max + 1
			coroutine.resume(Threads[max], id, payload)
		end
	end)
}

while i <= max do
	print(i, coroutine.resume(Threads[i]))
	if coroutine.status(Threads[i]) == 'dead' then
		table.remove(Threads, i)
	else
		i = i + 1
		if i > max then
			i = i % max + 1
		end
	end
	sleep(1 / 20)
end
commented

Could you use the parallel API to receive and process messages in parallel, rather than starting a new multishell tab?

commented

Thanks. I ended up with this and it seems to work great.

local threads = {}
local function addThread(func, args)
	args = args or table.pack()
	local thread = coroutine.create(func)
	local ok, result = coroutine.resume(thread, table.unpack(args, 1, args.n))
	if not ok then
		error(result, 0)
	end
	table.insert(threads, { thread = thread, filter = result })
end

local function handle(id, payload)
	sleep(1)
	print(id, payload)
end

addThread(function()
	print('Listening...')
	while true do
		local id, payload = rednet.receive(protocol)
		print('Received: ' .. id)
		addThread(handle, table.pack(id, payload))
	end
end)

while #threads > 0 do
	local events = table.pack(os.pullEventRaw())

	for i = #threads, 1, -1 do
		if threads[i].filter == nil or threads[i].filter == events[1] or events[1] == 'terminate' then
			local ok, result = coroutine.resume(threads[i].thread, table.unpack(events, 1, events.n))
			if not ok then
				error(result, 0)
			end
			if coroutine.status(threads[i].thread) == 'dead' then
				table.remove(threads, i)
			else
				threads[i].filter = result
			end
		end
	end
end