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

read() add string into read before writing

Started by TechnicalCoding, 28 June 2016 - 11:43 PM
TechnicalCoding #1
Posted 29 June 2016 - 01:43 AM
I am creating something to an operating system, I also want some kind of "memory" to it, and thats good, but what I am having problems to understand is how I can assign text/string to read() before anyone starts writing to it?

EXAMPLE
—————————
I have an username variable which use read, they get 3 attempts trying to figure out right details but I want that after first attempt I want the same username to appear to second so no one needs to rewrite the username.


Any ideas? Thanks
KingofGamesYami #2
Posted 29 June 2016 - 02:02 AM
So basically like a text field that has a description in it before you start typing? It's not exactly easy, but you *can* do it.
TechnicalCoding #3
Posted 29 June 2016 - 03:48 AM
So basically like a text field that has a description in it before you start typing? It's not exactly easy, but you *can* do it.

Not exactly an description, but I want it to contain itself, basicly I am using a while loop to make it go over and over again, and for each time it has to repeat I want it to contain the string it had before the it kind of overlap itself, so basicly just using itself (or duplicate it) to make it just contain itself again..
eniallator #4
Posted 29 June 2016 - 10:45 AM
So basically like a text field that has a description in it before you start typing? It's not exactly easy, but you *can* do it.

Not exactly an description, but I want it to contain itself, basicly I am using a while loop to make it go over and over again, and for each time it has to repeat I want it to contain the string it had before the it kind of overlap itself, so basicly just using itself (or duplicate it) to make it just contain itself again..

what about you have an option before you get to the login screen where you can quickly login from. for example like a button that has the username that will show an input field where you put in your password instead of both the username and the password.
LBPHacker #5
Posted 29 June 2016 - 05:51 PM
EDIT: Do check out the answer below this one first. It's way more crafty and simple.

Re-implementing read in a way that it accepts a 4th parameter which defaults to an empty string if not passed is an option. You'd probably end up with more code than sense, though. For example, the history code is completely useless here.

local function read( _sReplaceChar, _tHistory, _fnComplete, initial_sLine ) -- note the new parameter initial_sLine
	term.setCursorBlink( true )

	local sLine = initial_sLine or "" -- empty string used if initial_sLine is not passed (or it's nil/false)

	... -- the rest of read() as seen in bios.lua
end

read(nil, nil, nil, "initial text") -- you'd call it like this

Full code, in case you have never seen bios.lua before
local function read( _sReplaceChar, _tHistory, _fnComplete, initial_sLine ) -- not the new parameter initial_sLine
	term.setCursorBlink( true )

	local sLine = initial_sLine or "" -- empty string used if initial_sLine is not passed (or it nil/false)

	local nHistoryPos
	local nPos = 0
	if _sReplaceChar then
		_sReplaceChar = string.sub( _sReplaceChar, 1, 1 )
	end

	local tCompletions
	local nCompletion
	local function recomplete()
		if _fnComplete and nPos == string.len(sLine) then
			tCompletions = _fnComplete( sLine )
			if tCompletions and #tCompletions > 0 then
				nCompletion = 1
			else
				nCompletion = nil
			end
		else
			tCompletions = nil
			nCompletion = nil
		end
	end

	local function uncomplete()
		tCompletions = nil
		nCompletion = nil
	end

	local w = term.getSize()
	local sx = term.getCursorPos()

	local function redraw( _bClear )
		local nScroll = 0
		if sx + nPos >= w then
			nScroll = (sx + nPos) - w
		end

		local cx,cy = term.getCursorPos()
		term.setCursorPos( sx, cy )
		local sReplace = (_bClear and " ") or _sReplaceChar
		if sReplace then
			term.write( string.rep( sReplace, math.max( string.len(sLine) - nScroll, 0 ) ) )
		else
			term.write( string.sub( sLine, nScroll + 1 ) )
		end

		if nCompletion then
			local sCompletion = tCompletions[ nCompletion ]
			local oldText, oldBg
			if not _bClear then
				oldText = term.getTextColor()
				oldBg = term.getBackgroundColor()
				term.setTextColor( colors.white )
				term.setBackgroundColor( colors.gray )
			end
			if sReplace then
				term.write( string.rep( sReplace, string.len( sCompletion ) ) )
			else
				term.write( sCompletion )
			end
			if not _bClear then
				term.setTextColor( oldText )
				term.setBackgroundColor( oldBg )
			end
		end

		term.setCursorPos( sx + nPos - nScroll, cy )
	end

	local function clear()
		redraw( true )
	end

	recomplete()
	redraw()

	local function acceptCompletion()
		if nCompletion then
			-- Clear
			clear()

			-- Find the common prefix of all the other suggestions which start with the same letter as the current one
			local sCompletion = tCompletions[ nCompletion ]
			sLine = sLine .. sCompletion
			nPos = string.len( sLine )

			-- Redraw
			recomplete()
			redraw()
		end
	end
	while true do
		local sEvent, param = os.pullEvent()
		if sEvent == "char" then
			-- Typed key
			clear()
			sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
			nPos = nPos + 1
			recomplete()
			redraw()

		elseif sEvent == "paste" then
			-- Pasted text
			clear()
			sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
			nPos = nPos + string.len( param )
			recomplete()
			redraw()

		elseif sEvent == "key" then
			if param == keys.enter then
				-- Enter
				if nCompletion then
					clear()
					uncomplete()
					redraw()
				end
				break

			elseif param == keys.left then
				-- Left
				if nPos > 0 then
					clear()
					nPos = nPos - 1
					recomplete()
					redraw()
				end

			elseif param == keys.right then
				-- Right				
				if nPos < string.len(sLine) then
					-- Move right
					clear()
					nPos = nPos + 1
					recomplete()
					redraw()
				else
					-- Accept autocomplete
					acceptCompletion()
				end

			elseif param == keys.up or param == keys.down then
				-- Up or down
				if nCompletion then
					-- Cycle completions
					clear()
					if param == keys.up then
						nCompletion = nCompletion - 1
						if nCompletion < 1 then
							nCompletion = #tCompletions
						end
					elseif param == keys.down then
						nCompletion = nCompletion + 1
						if nCompletion > #tCompletions then
							nCompletion = 1
						end
					end
					redraw()

				elseif _tHistory then
					-- Cycle history
					clear()
					if param == keys.up then
						-- Up
						if nHistoryPos == nil then
							if #_tHistory > 0 then
								nHistoryPos = #_tHistory
							end
						elseif nHistoryPos > 1 then
							nHistoryPos = nHistoryPos - 1
						end
					else
						-- Down
						if nHistoryPos == #_tHistory then
							nHistoryPos = nil
						elseif nHistoryPos ~= nil then
							nHistoryPos = nHistoryPos + 1
						end						
					end
					if nHistoryPos then
						sLine = _tHistory[nHistoryPos]
						nPos = string.len( sLine )
					else
						sLine = ""
						nPos = 0
					end
					uncomplete()
					redraw()

				end

			elseif param == keys.backspace then
				-- Backspace
				if nPos > 0 then
					clear()
					sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 )
					nPos = nPos - 1
					recomplete()
					redraw()
				end

			elseif param == keys.home then
				-- Home
				if nPos > 0 then
					clear()
					nPos = 0
					recomplete()
					redraw()
				end

			elseif param == keys.delete then
				-- Delete
				if nPos < string.len(sLine) then
					clear()
					sLine = string.sub( sLine, 1, nPos ) .. string.sub( sLine, nPos + 2 )				
					recomplete()
					redraw()
				end

			elseif param == keys["end"] then
				-- End
				if nPos < string.len(sLine ) then
					clear()
					nPos = string.len(sLine)
					recomplete()
					redraw()
				end

			elseif param == keys.tab then
				-- Tab (accept autocomplete)
				acceptCompletion()

			end

		elseif sEvent == "term_resize" then
			-- Terminal resized
			w = term.getSize()
			redraw()

		end
	end

	local cx, cy = term.getCursorPos()
	term.setCursorBlink( false )
	term.setCursorPos( w + 1, cy )
	print()

	return sLine
end

EDIT: You can just call it with the last result it returned if you want it to remember the input.

local last
while ... -- some loop
	last = read(nil, nil, nil, last)
end
Edited on 29 June 2016 - 05:39 PM
Anavrins #6
Posted 29 June 2016 - 06:58 PM
A simple way to achieve this is queueing every characters as a char event before read()

local init = "hello world"
for c in init:gmatch(".") do os.queueEvent("char", c) end
read() #-- Will start with "hello world" already written
Or in a format similar to your function

local function newread(sReplaceChar, tHistory, fnComplete, initial_sLine)
  for c in (initial_sLine or ""):gmatch(".") do os.queueEvent("char", c) end
  return read(sReplaceChar, tHistory, fnComplete)
end
Edited on 29 June 2016 - 05:18 PM
Bomb Bloke #7
Posted 30 June 2016 - 03:56 AM
You could alternatively use the "history" feature already built into the read function.

http://www.computercraft.info/wiki/Read

Eg:

read(nil, {"Tom", "Dick", "Harry"})

The user can then use up/down to go through these entries. This is how CraftOS and the Lua console let you get at previously typed commands.