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

Problem with read function modification.

Started by cyanisaac, 15 August 2015 - 08:42 PM
cyanisaac #1
Posted 15 August 2015 - 10:42 PM
I am trying to add in a modified read function for use in a shell.

Expected result: If the user enters "? " it will switch the complete function to textutils.complete otherwise it will use shell.complete

Achieved result: No autocompletions.

Here's the code:
Modded Read Function

function specShellRead( _sReplaceChar, _tHistory)
local _fnComplete = shell.complete
local readCharactersInput = {}
local ignoreInputTable = false
    term.setCursorBlink( true )
    local sLine = ""
    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 ]
		    local sFirstLetter = string.sub( sCompletion, 1, 1 )
		    local sCommonPrefix = sCompletion
		    for n=1,#tCompletions do
			    local sResult = tCompletions[n]
			    if n ~= nCompletion and string.find( sResult, sFirstLetter, 1, true ) == 1 then
				    while #sCommonPrefix > 1 do
					    if string.find( sResult, sCommonPrefix, 1, true ) == 1 then
						    break
					    else
						    sCommonPrefix = string.sub( sCommonPrefix, 1, #sCommonPrefix - 1 )
					    end
				    end
			    end
		    end
		    -- Append this string
		    sLine = sLine .. sCommonPrefix
		    nPos = string.len( sLine )
	    end
	    recomplete()
	    redraw()
    end
    while true do
	    local sEvent, param = os.pullEvent()
	    if sEvent == "char" then
		 if not ignoreInputTable then
		  table.insert(readCharactersInput, param)
		  local check = coreTools.mergeTableIntoString(readCharactersInput)
		  if #check == 2 then
		   if check == "? " then
		    _fnComplete = textutils.complete
		   else
		    ignoreInputTable = true
		   end
		  end
		 end
		    -- 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

If anyone has a fix for this that would be greatly appreciated :D/>
HPWebcamAble #2
Posted 16 August 2015 - 02:26 AM

if sEvent == "char" then
				 if not ignoreInputTable then
				  table.insert(readCharactersInput, param)

				  local check = coreTools.mergeTableIntoString(readCharactersInput) --# This line

				  if #check == 2 then
				   if check == "? " then
					_fnComplete = textutils.complete
				   else
					ignoreInputTable = true
				   end
				  end
				 end
					-- Typed key
					clear()
					sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
					nPos = nPos + 1
					recomplete()
					redraw()
			elseif sEvent == "paste" then

What on earth is 'coreTools'?
Can you link a pastebin?

If you are just turning a table into a string, you can use this:

table.concat( tableInQuestion , " " ) --# " ", a space, tells it to put a space between each element

Speaking of pastebin, this code is a little long. You put it into a spoiler, which is good, but code this long (> 100 lines) definitely needs line numbers.
Next time, put it on pastebin, and link it in your post.
Edited on 16 August 2015 - 12:28 AM