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

Different terminals and print

Started by Noiro, 15 June 2015 - 09:51 PM
Noiro #1
Posted 15 June 2015 - 11:51 PM
So, I guess my first question is, which api does print() belong to exactly? Is it just default lua? If you are in a terminal and use print and the text you pass in is greater than the width of that terminal (let's assume you have two windows side by side and the 'terminal' is the left window), will print wrap to the next line of the window or will it run over into the window beside it?

My second question is regarding terminals themselves. Since they can be different objects, is there a way I can tell the difference between say a window object, a native terminal object, and a monitor? I would assume that type(term.current()) would return table instead of "window" or "monitor". If they do return "window" or "monitor", how would I make code that'd let me give custom objects I create their own names for when returning a type() as well?
Edited on 15 June 2015 - 09:56 PM
valithor #2
Posted 16 June 2015 - 12:26 AM
Print is actually defined in the bios so it does not really belong to a API. It makes use of term.write.

It would wrap to the next line of the window.

You could check if term.current() is equal to term.native (if true it is just the default terminal window) or if term.current is equal to peripheral.wrap(side of monitor) (if true it's just the default monitor window).

All a window is, is a table of functions which determine how things such as term.write behave. So yes type(term.current()) is a table.

Wrote of my phone sorry if it's hard to read.
Edited on 15 June 2015 - 10:28 PM
Noiro #3
Posted 16 June 2015 - 01:24 AM
Print is actually defined in the bios so it does not really belong to a API. It makes use of term.write.

It would wrap to the next line of the window.

You could check if term.current() is equal to term.native (if true it is just the default terminal window) or if term.current is equal to peripheral.wrap(side of monitor) (if true it's just the default monitor window).

All a window is, is a table of functions which determine how things such as term.write behave. So yes type(term.current()) is a table.

Wrote of my phone sorry if it's hard to read.
While that makes sense and thank you for the if term.native() == term.current(), but my thing is that I may not be able to check the peripheral.wrap(side). Well, the goal is that I'm wanting to make an API that includes buttons and input and it'd be nice to know if I'm working with a computer or a monitor so though my code that'd be pasting visuals to the monitor wouldn't matter much, how I accept input would. I guess worst case, I can loop through all the sides of a computer (up, down, left, right, top, back) right? and check a) if it's a periph and B)/> if it matches, but that still wouldn't answer if it's a monitor or not. What if it's an openblocks setup for glasses? Or would I have to loop around, look at each periph, and compare to what I'm looking at and if true, handle each case accordingly? That…is going to be annoying. Can you wrap a monitor in FRONT of the computer? And if the search was performed by a turtle, would peripheral.getType("front") throw any areas? If I recall, there are sides turtles can't wrap that computers can.
Edited on 15 June 2015 - 11:27 PM
Lyqyd #4
Posted 16 June 2015 - 01:26 AM
The terminal glasses do not present as a terminal object, they have their own set of functions. Comparing term.current() against a new peripheral.wrap result will always be false, as peripheral.wrap will generate a new table each time it's called. Your API may want to accept a side name so that it can wrap the peripheral internally as well as watch the monitor_touch event side parameters to check if it's got the right monitor. You might find it valuable to see how Touchpoint does this.
Noiro #5
Posted 16 June 2015 - 01:34 AM
The terminal glasses do not present as a terminal object, they have their own set of functions. Comparing term.current() against a new peripheral.wrap result will always be false, as peripheral.wrap will generate a new table each time it's called. Your API may want to accept a side name so that it can wrap the peripheral internally as well as watch the monitor_touch event side parameters to check if it's got the right monitor. You might find it valuable to see how Touchpoint does this.

So it's fair to assume if someone performs a peripheral.wrap() and starts using it as a terminal, it WILL be a monitor of some kind under all circumstances? My goal with the API is not to bind to a specific side so one computer can run across however many monitors/terminals they want. Do displays have some kind of identifier like functions do? does the pointer to the monitor return an id of some kind I can use as an index in a table and store a value telling me how to deal with it?

I was considering hijacking the peripheral.wrap() function, adding a "Add this to my own table", then continueing on with its normal operation, though I'm sure that's probably the more hacky way to do it.

Edit: Ok, I went through Touchpoint line by line and I see how you did it. Blargh. You did it with the OOP route by just assigning the pointer of the side via each screen or buttonscreen object. I was hoping my API would let them bounce between different terminals of their own accord and if they said they wanted a button there, I'd put a button there, but now I can sorta see how that'd be difficult to manage if I was going to give them that much freedom but the API would still be expected to manage input from them.

My question on touchpoint though, line 99 and line 108, it looks like run 'runs' handleEvent though you seem to want users using your api to call button:run(), it looks like handleEvent is the one actually returning all the variables and I don't see run returning anything that handleEvent unpacks and returns. Where is it going and how is run returning the values? (better yet, I'm not exactly sure WHAT values it's returning though you gave p1-p5) as possible returns.
Edited on 16 June 2015 - 12:17 AM
Bomb Bloke #6
Posted 16 June 2015 - 02:08 AM
Yes, any display obtained via peripheral.wrap() will be a monitor.

Comparing term.current() against a new peripheral.wrap result will always be false, as peripheral.wrap will generate a new table each time it's called.

Well, unless you record the result of wrapping the monitor in a variable, then redirect to that and later compare against it. Certainly the technique will fail as written.

Likewise, comparing term.current() to term.native() runs into trouble on advanced computers, as multishell starts you off with full-screen window as your "default" terminal - not with term.native().

In any case, it's worth noting that term.current() is never the same as term. The former returns the actual pointer to whatever it is you're redirected to. term returns, well, the current terminal table, which is an altered version of whatever it is you're redirected to.

Windows and monitors have access to functions that the native display of your computer never has. These functions never appear in the current terminal table, either, even if you redirect to a window or monitor. But since term.current() returns a pointer to the actual terminal object you're redirecting to (keeping in mind that all "terminal objects" are simply tables filled with functions for dealing with a given display), you can check if the table that returns has the relevant functions of a monitor/window in order to determine what sort of display it points to.

Eg:

if term.current().setTextScale then
  -- You're currently redirected to a monitor.
elseif term.current().setVisible then
  -- You're currently redirected to a window.
elseif term.current() == term.native() then
  -- You're currently directly using the computer's own display.
end

If you have a wrapped monitor, you can't determine what "side" it belongs to unless you wrapped it and saved that information at the time. Well, unless the computer only has one external monitor available, or all the attached displays have different dimensions, or different colour-capabilities, in which case you could probe them for that information and figure it out - but they might all be the same, so this might not be possible!. I like to use peripheral.find() to embed it as a "side" key in the wrapped monitor's table:

local mon = peripheral.find("monitor", function(name, object) object.side = name return true end)  -- Or "return object.isColour()", if you only want colour displays.
print(mon.side)  -- Prints whatever side was wrapped.

I'm not sure what you're saying you want your script to do, but you might find this code snippet useful:

-- Populate this "displays" table with as many terminal objects as you want:
local displays = {term.current(), peripheral.find("monitor")}  -- This example gets the current terminal plus all attached monitors.

local multiTerm = {}
for funcName,_ in pairs(displays[1]) do  -- For each function that exists in the first object in "displays",
	multiTerm[funcName] = function(...)  -- ... generate a new function of the same name in the multiterm table...
		for i=2,#displays do displays[i][funcName](unpack(arg)) end  -- ... that calls the same function in all the OTHER objects...
		return displays[1][funcName](unpack(arg))  -- ... and returns the output from the function in the first.
	end
end

-- "multiterm" is now a single terminal object filled with functions that affect all of the terminal objects in the "displays" table.
term.redirect(multiTerm)
Lyqyd #7
Posted 16 June 2015 - 06:46 AM
My question on touchpoint though, line 99 and line 108, it looks like run 'runs' handleEvent though you seem to want users using your api to call button:run(), it looks like handleEvent is the one actually returning all the variables and I don't see run returning anything that handleEvent unpacks and returns. Where is it going and how is run returning the values? (better yet, I'm not exactly sure WHAT values it's returning though you gave p1-p5) as possible returns.

Users of the API are welcome to use either handleEvents() or run() as fits their use case. The run function is good for simple systems that only need functions assigned to each button, whereas the handleEvents function allows the user greater control by creating "button_click" events whenever the API detects that one of its buttons has been pressed. The user is then welcome to use these events as they see fit in their program. The handleEvents function is meant to transform events as they pass through it, and so is normally used like:


local event = {t:handleEvents(os.pullEvent())}

The run function, in contrast, is intended to replace the main loop of a program, and so does not return at all (hence being intended for simpler programs).

Hope that clears things up! :)/>