This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
distantcam's profile picture

Terminal Buffers

Started by distantcam, 14 November 2013 - 11:52 PM
distantcam #1
Posted 15 November 2013 - 12:52 AM
Adding a buffer (or more accurately a way to access the internal buffer) of the terminal would allow programs to create overlays easily. Currently the only way to do this is with a terminal redirection, which can interfere with other terminal redirects, and is overall a very complex solution to a simple problem.

If terminals could provide a buffer swap then functions like double-buffering would be available too.

Ideally buffering should be handled in the terminal itself (to simulate hardware buffering), but alternatively if Lua could read the state of the screen then our programs could handle buffering that way.
Lyqyd #2
Posted 15 November 2013 - 01:32 AM
Easily done with software freely available on the forums with few downsides. Handled properly, terminal redirection does not interfere with other redirects and is a very simple concept to implement with basic Lua knowledge. This would fall under "Enhancements" in the Suggestions Not to Make list.
distantcam #3
Posted 15 November 2013 - 01:42 AM
I'd disagree. "few downsides" does not mean no downsides.

Terminal redirects to not stack, so for example LyqydOS does not run properly through my Billboard program because you're using your own redirects to handle frame buffering.

*edit* To head off any argument that it's my program at fault, LyqydOS also does not work with the Monitor program, which uses the same technique.

And given the terminals are already keeping an internal buffer all I'm asking for is that be exposed to the Lua side.
Edited on 15 November 2013 - 12:51 AM
theoriginalbit #4
Posted 15 November 2013 - 07:48 AM
Having multiple active redirects is a bad idea, just the same as allowing programs direct access to the screen buffer…

The reason that this is a bad idea is that, while yes it would be good in a few circumstances, for the most part it would cause massive conflicts. Imagine two programs, running, attempting to control their rendering. You could have one application rendering over part of others etc and just create bad, unusable programs.

This is definitely implementable, and easily at that, as Lyqyd stated. And it is definitely yours and the other "Monitor" program at fault here, use a better technique and it will be fine. Just because another program uses the same technique you do, doesn't make it the best, nor does it make it the only technique.

One technique would be to override term.redirect and term.native.redirect making sure that the other program doesn't take control away from you, but so that it "thinks" it does have control. Then of course you get to know what its doing and do what you wish with it.

Another (more complicated, and kinda pointless) technique would be to make an override of the term.native table with references to your table/functions, this way when other programs attempt to make a redirect object, and use term (you've redirected) or term.native as what they invoke in their redirects, YOU will get their commands, and YOU have control over how they get passed to the real term/term.native. Just make sure of course that you create a backup of the real term/term.native for you own uses and of course restore it once your program has finished.

Using either of these method, no matter how the other programs create a redirect object, you'll have control. I'm sure that other people can probably think of other techniques too, this is just two techniques that I can think of off the top of my head in the spur of the moment.
Edited on 15 November 2013 - 06:49 AM
Wojbie #5
Posted 15 November 2013 - 10:21 AM
IF you want an example of program that overwrites control over term.redirect (2nd case in theoriginalbit post) you can take a look at my mirror program. It is not perfect or anything like that but it's functional in most of cases. Still a bit derpy. Also its not supposed to take over, only clone data to second point.
Edited on 15 November 2013 - 09:42 AM
Lyqyd #6
Posted 15 November 2013 - 10:27 AM
The real issue is that there's no way to get the current redirection table once you're already redirected. LyqydOS's compositor has to target term.native for this reason. Redirects stack perfectly fine, which LyqydOS demonstrates internally (programs draw to window buffers which draw to the compositor which draws to the screen). You just need to adjust some variables to send it elsewhere rather than redirecting before you start it. I may eventually allow one to pass in a redirect table or give another way of changing the output destination, but until then, you could try changing the value of process.windowCompositor.target, if I recall correctly. It will be ganky unless you do it right away.

theoriginalbit's suggestion about overriding term.native above would probably also work.

Also, you guys should re-read term. There is no term.native.redirect.
distantcam #7
Posted 15 November 2013 - 11:18 AM
Ok, here's a problem. Let's say you have 2 redirects, both redirecting to a peripheral (let's say a monitor and a printer). How would you get those to work together?

For example term.write will write to the monitor, and write to the printer. How would they stack together?

The reason that this is a bad idea is that, while yes it would be good in a few circumstances, for the most part it would cause massive conflicts. Imagine two programs, running, attempting to control their rendering. You could have one application rendering over part of others etc and just create bad, unusable programs.

Well first off how would you run 2 programs? You can't without writing some code to run each program in a coroutine. So how does the current system handle running 2 programs in a coroutine? Not very well. They both fight to move the cursor around, etc.

So ideally if you were to run 2 or more programs concurrently you'd also handle the redraw system. But oh wait you can't force a program to redraw and since there's no built in buffer swap you'd have to implement that too. But then we get back to the fact that term.redirect does not handle this scenario well.

Ok, let me describe what I'm ultimately trying to do, and see if there's another solution.

I want to create a system where the terminate event is rewired to pop up a box to enter a password, and if the password is incorrect the box goes away and whatever program that was running redraws what was under the box.

I was hoping to do this as just a program, not a full OS replacement. The best I could figure was I needed some way to either capture what the program is drawing, or have a screen buffer that I can capture right before displaying the box, and then restore when the box closes.

So, if I were to use a terminal redirect to capture the buffer then any redirects added after the buffer that ignored term and went straight to the peripheral would not be captured.
Lyqyd #8
Posted 15 November 2013 - 01:20 PM
Your use case is pretty simple. Set up a terminal redirect and also watch for term.redirect and term.restore calls. Your suggested addition to ComputerCraft doesn't really accomplish what you're trying to do. You're going to be much better off using a redirect API and handling redirect/restore yourself.
theoriginalbit #9
Posted 15 November 2013 - 07:26 PM
Ok, here's a problem. Let's say you have 2 redirects, both redirecting to a peripheral (let's say a monitor and a printer). How would you get those to work together?

For example term.write will write to the monitor, and write to the printer. How would they stack together?
Easy, heard of peripheral wrapping? Also you wouldn't be able to redirect to a printer, its missing some methods, plus printing a program to a oddly sized paper would look bad, especially when a program doesn't make use of term.getSize.

Ok, let me describe what I'm ultimately trying to do, and see if there's another solution.

I want to create a system where the terminate event is rewired to pop up a box to enter a password, and if the password is incorrect the box goes away and whatever program that was running redraws what was under the box.

I was hoping to do this as just a program, not a full OS replacement. The best I could figure was I needed some way to either capture what the program is drawing, or have a screen buffer that I can capture right before displaying the box, and then restore when the box closes.

So, if I were to use a terminal redirect to capture the buffer then any redirects added after the buffer that ignored term and went straight to the peripheral would not be captured.
This has to be the easiest use case you could have thought about… I've made this several times with my sandboxed/antivirus environments… This is all that I did:
  1. Make your program startup (making sure it only runs once) and run a new shell and your listener function
  2. Make a backup of term and term.native
  3. Override term and term.native with my own functions, not redirect!
  4. Keep a copy of everything that is written to the terminal in a table
  5. When needed to your function takes control and renders the box over it
  6. Once the box disappears redraw only needed areas to the screen from the buffer
  7. The program now continues
  8. ????
  9. profit
You should have realised by reading this, that this is the second method I posted.

Also, you guys should re-read term. There is no term.native.redirect.
Isn't there? Could have sworn there was… In any case, as you stated, the term.native override would fix the case you stated.
Lyqyd #10
Posted 15 November 2013 - 08:49 PM
Nah, there isn't. The term API sets up the redirect stack and wraps the term.native calls, then creates the redirect and restore methods from scratch, so no term.native.redirect or restore methods should exist.
distantcam #11
Posted 15 November 2013 - 09:13 PM
Alright, I'll see if I can do what I want using terminal redirects. I still feel like there's a use case that will break but I can't think of it right now.
theoriginalbit #12
Posted 15 November 2013 - 10:59 PM
Nah, there isn't. The term API sets up the redirect stack and wraps the term.native calls, then creates the redirect and restore methods from scratch, so no term.native.redirect or restore methods should exist.
Yeh makes sense, I just didn't think about it i guess.

Alright, I'll see if I can do what I want using terminal redirects. I still feel like there's a use case that will break but I can't think of it right now.
I can't think of any use cases where a terminal redirect (when of course implementing a solution that's been stated in this thread) where it would not work.
Cloudy #13
Posted 16 November 2013 - 01:41 AM
The CC terminal doesn't really work in a way which would be good for a terminal buffer.