Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --- read_number, by fatboychummy
- --- You have full permission to use this in any way you see fit, as long as you don't claim it as your own.
- --- Do note this comes without liability, and I am not responsible for any damages caused by this code.
- --- This is a function that allows the user to input a number, and enforces that the input is a number.
- --- It also allows you to specify a minimum and maximum value for the number.
- --- Usage is at the bottom of the file.
- --- Please note that this function has some slight amount of jank to it, and it's not perfect.
- --- In order to enter a negative value, for example, it is recommended you type
- --- in the positive version of the number you wish to enter *then* hit the negative sign.
- --- This is because the negative sign is used to negate the current number, and
- --- if you try to enter a negative sign before any numbers, it will drop in -0.
- --- If you try to get rid of the 0, it will also remove the negative sign.
- -- ########################################################################
- -- # IF YOU WANT TO USE THIS FUNCTION IN YOUR OWN PROGRAM, COPY FROM HERE #
- -- ########################################################################
- --- Like read(), but this will only allow the user to input an integer.
- ---@param min integer? The minimum value allowed.
- ---@param max integer? The maximum value allowed.
- ---@return integer value The number the user entered.
- local function read_number(min, max)
- local input = {}
- local len = 0
- local position = 0
- min = min or -math.huge
- max = max or math.huge
- local function clamp(val)
- if val > max then return max end
- if val < min then return min end
- return val
- end
- local function get_number()
- return tonumber(table.concat(input)) or 0
- end
- local x, y = term.getCursorPos()
- local last_len = #input
- --- Redraw the input line.
- local function redraw()
- term.setCursorPos(x, y) -- move the cursor to the start of the line.
- term.write((' '):rep(last_len)) -- clear the line
- term.setCursorPos(x, y) -- move the cursor back to the start of the line.
- term.write(table.concat(input) or "") -- write the input string.
- term.setCursorPos(x + position, y) -- move the cursor to the correct position.
- end
- -- Enable blinking to show the cursor to the user.
- term.setCursorBlink(true)
- while true do
- redraw()
- last_len = #input
- local event, key_char = os.pullEvent()
- if event == "key" then
- -- Handle backspace, enter, arrow keys.
- if key_char == keys.backspace then
- -- Remove the current character - 1 from the input string
- if position > 0 then
- table.remove(input, position) -- we use table.remove here so the table is compacted.
- position = position - 1
- if len > 0 then len = len - 1 end
- if position < 0 then position = 0 end
- -- if backspace removed the negative sign, then we need to negate the number.
- if input[1] == '-' then
- local clipped = clamp(get_number())
- input = {}
- for char in tostring(clipped):gmatch(".") do
- table.insert(input, char)
- end
- len = #input
- position = 0
- end
- end
- elseif key_char == keys.delete then
- -- Remove the current character + 1 from the input string
- if position < len then
- table.remove(input, position + 1)
- if len > 0 then len = len - 1 end
- if position > len then position = len end
- end
- elseif key_char == keys.left then
- -- Move the cursor left
- position = position - 1
- if position < 0 then position = 0 end
- elseif key_char == keys.right then
- -- Move the cursor right
- position = position + 1
- if position > len then position = len end
- elseif key_char == keys.enter then
- -- due to the fact that we enforce numbers only, we can assume that the input is always valid.
- -- however, we should enforce it being in range.
- local n = get_number()
- if n < min or n > max then
- -- if the number is out of range, then we should redraw the input line with the number in red.
- local old = term.getTextColor()
- term.setTextColor(colors.red)
- redraw()
- term.setTextColor(old)
- sleep(0.25)
- else
- -- if the number is in range, then we can return it.
- term.setCursorBlink(false)
- print()
- return n
- end
- end
- elseif event == "char" then
- -- Handle actual numbers, 0-9 (and the minus sign if min < 0)
- if key_char:match("%d") then
- -- Insert the number at the current position
- local _position = position
- if input[position + 1] == '-' then
- -- handle attempting to insert in front of the negative sign.
- _position = position + 1
- end
- table.insert(input, _position + 1, key_char)
- position = _position + 1
- len = len + 1
- elseif key_char == '-' then
- if min < 0 then
- -- Negate the current number, clipping the value to the "maximum" for whatever side of the number line we're on.
- -- 1. Negate
- if input[1] == '-' then
- table.remove(input, 1)
- else
- table.insert(input, 1, '-')
- end
- -- 2. Clip
- local clipped = clamp(get_number())
- input = {}
- for char in tostring(clipped):gmatch(".") do
- table.insert(input, char)
- end
- len = #input
- position = len
- end
- end
- elseif event == "paste" then
- -- Handle pasted text, we need to enforce that this is a valid number.
- -- Use a very basic pattern to check if the pasted text is a valid number.
- if key_char:match("^%-?%d+$") then
- -- Clear the input and insert the pasted text.
- input = {}
- for char in key_char:gmatch(".") do
- table.insert(input, char)
- end
- len = #input
- position = len
- end
- end
- end
- end
- -- ######################################################################
- -- # IF YOU WANT TO USE THIS FUNCTION IN YOUR OWN PROGRAM, COPY TO HERE #
- -- ######################################################################
- -- tests
- write("Read number, no min/max: ")
- print(read_number())
- write("Read number, min 0: ")
- print(read_number(0))
- write("Read number, min 0, max 10: ")
- print(read_number(0, 10))
- write("Read number, min -10, max 10: ")
- print(read_number(-10, 10))
- write("Read number, min -10, max -5: ")
- print(read_number(-10, -5))
- write("Read number, no min, max -5: ")
- print(read_number(nil, -5))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement