├── LICENSE
├── README.md
├── conf.lua
├── loveconsole
├── config.lua
└── init.lua
└── main.lua
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Catlinman 2015
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # LOVEConsole #
3 |
4 | This is an in-application debugging and command console created for the [LÖVE2D game framework](https://love2d.org/). The console allows for rapid game testing by allowing the execution of user defined commands as well as native Lua functions. It also displays a useful overlay indicating a count of warnings and errors printed to the console to notify the user of any events that occur during execution.
5 |
6 | ## Installation and use ##
7 |
8 | Getting LOVEConsole to run is a fairly simple and straightforward task. All that needs to be done is to put the *loveconsole* folder somewhere in you LÖVE2D project and to then *require* the folder from your *main.lua*. It is suggested that you do it from there since LOVEConsole requires you to hook some of LÖVE's main functions to it. This way it can receive information such as key presses and also draw at the end of the main draw loop.
9 |
10 | An example of how this can be seen in this repository's [*main.lua*](https://github.com/catlinman/loveconsole/blob/master/main.lua) file or somewhat abstracted in the code below.
11 |
12 | ```lua
13 | -- Require the console script and assign it to a variable.
14 | local console = require("loveconsole")
15 |
16 | function love.draw()
17 | -- [Do main drawing operations before drawing the console.]
18 | love.graphics.pop() -- [Do this if you pushed any previous graphic translations.]
19 | console.draw()
20 | end
21 |
22 | function love.keypressed(key)
23 | -- [Handle key presses and then pass these on to the console.]
24 | console.keypressed(key)
25 | end
26 |
27 | function love.textinput(t)
28 | -- [Receive text input and pass it on to the console.]
29 | console.textinput(t)
30 | end
31 |
32 | function love.resize(w, h)
33 | -- [Resize the console if the window is resized.]
34 | console.resize(w, h)
35 | end
36 | ```
37 |
38 | From there on you can run your application as your normally would. At this point while your application is running you can hit *F10* to bring up the console. This can be done assuming you are using the default key bindings and have not made any changes to the configuration file as explained in the next section. If you've gotten this far your console is pretty much ready to be used. If you want to take it even further you should check out the next section.
39 |
40 | ## Configuring the console ##
41 |
42 | Inside your *loveconsole* folder you will also find a file called *config.lua*. This is where LOVEConsole gets it's configuration from and it is crucial that the configuration file contains all of it's default values as specified in this repositories config file. If this is not the case the console will not be able to run and simply deactivate itself on load.
43 |
44 | You can open the configuration file with your favorite text editing program and modify it to your liking. I've done my best to comment each configuration variable's use so it should be easy to edit and obtain your own personalized console. I also suggest that you define your custom console commands at the end of this file. You will find a sample command at the bottom of the file to see how commands can be created with ease. The benefit of using already defined commands comes with the fact that you have a lot more control over what they do and they are faster to type and perform over a native lua command which can be executed using the *run* built-in console command (further on that in the next section).
45 |
46 | In the configuration file you will also find some variables which define the keys used to perform actions within the console window. You can find their default assignments in the table below.
47 |
48 |
49 |
50 | Key
51 | | Action
52 | |
53 |
54 | F10
55 | | Toggle the console interface.
56 | |
57 |
58 | Page Up
59 | | Scroll up the console log.
60 | |
61 |
62 | Page Down
63 | | Scroll down the console log.
64 | |
65 |
66 | Home
67 | | Move to the very beginning of the console log.
68 | |
69 |
70 | End
71 | | Move to the newest message in the console log.
72 | |
73 |
74 | Up Arrow
75 | | Move up through the stack of previously entered commands.
76 | |
77 |
78 | Down Arrow
79 | | Move down through the stack of previously entered commands.
80 | |
81 |
82 | Left Arrow
83 | | Move the input cursor to the left.
84 | |
85 |
86 | Right Arrow
87 | | Move the input cursor to the right.
88 | |
89 |
90 |
91 | ## Built-in commands ##
92 |
93 | LOVEConsole comes with a set of predefined commands which are declared towards the end of the *init.lua* file. Some of these are just to show what the console is capable of while others allow you to interface with native code. You can find a full listing of these commands in the table below.
94 |
95 |
96 |
97 | Command
98 | | Description
99 | |
100 |
101 | help
102 | | Outputs the names and descriptions of all available console commands or just a single one - Arguments: [command to fetch information on]
103 | |
104 |
105 | clear
106 | | Clears the entire console.
107 | |
108 |
109 | quit
110 | | Attempts to close the application.
111 | |
112 |
113 | print
114 | | Prints trailing command arguments as a formatted string - Arguments: [string to print]
115 | |
116 |
117 | alias
118 | | Creates a new command list entry mimicking another command. Arguments: [command to alias] [alias name]
119 | |
120 |
121 | run
122 | | Executes the supplied lua function - Arguments: [lua command to execute]
123 | |
124 |
125 | set
126 | | Sets a supplied variable - Arguments: [lua assignment to execute]
127 | |
128 |
129 |
130 | ## License ##
131 |
132 | This repository is released under the MIT license. For more information please refer to [LICENSE](https://github.com/catlinman/loveconsole/blob/master/LICENSE)
133 |
--------------------------------------------------------------------------------
/conf.lua:
--------------------------------------------------------------------------------
1 |
2 | function love.conf(t)
3 | t.identity = nil
4 | t.version = "0.10.0"
5 | t.console = false
6 | t.accelerometerjoystick = true
7 | t.gammacorrect = false
8 |
9 | t.window.title = "LOVEConsole"
10 | t.window.icon = nil
11 | t.window.width = 800
12 | t.window.height = 600
13 | t.window.borderless = false
14 | t.window.resizable = false
15 | t.window.minwidth = 1
16 | t.window.minheight = 1
17 | t.window.fullscreen = false
18 | t.window.fullscreentype = "desktop"
19 | t.window.vsync = true
20 | t.window.msaa = 0
21 | t.window.display = 1
22 | t.window.highdpi = false
23 | t.window.x = nil
24 | t.window.y = nil
25 |
26 | t.modules.audio = true
27 | t.modules.event = true
28 | t.modules.graphics = true
29 | t.modules.image = true
30 | t.modules.joystick = true
31 | t.modules.keyboard = true
32 | t.modules.math = true
33 | t.modules.mouse = true
34 | t.modules.physics = true
35 | t.modules.sound = true
36 | t.modules.system = true
37 | t.modules.timer = true
38 | t.modules.window = true
39 | t.modules.thread = true
40 | t.modules.video = true
41 | t.modules.touch = true
42 | end
43 |
--------------------------------------------------------------------------------
/loveconsole/config.lua:
--------------------------------------------------------------------------------
1 |
2 | -- User configuration file for LOVEConsole
3 | -- We keep this file separate since it mainly consists of defining variables.
4 |
5 | local config = {} -- Table containing the settings returned to the main system.
6 |
7 | config.keys = {} -- Table containing the user defined keys.
8 | config.colors = {} -- Table containing the console style colors.
9 |
10 | config.enabled = true -- If true the user is able to show/hide the console.
11 | config.alert = true -- If true the console will display a widget on warnings and errors.
12 |
13 | config.echoLine = true -- print entered line to console
14 | config.inputChar = ">" -- Characters displayed at the start of the input line.
15 | config.scrollChar = "..." -- Scroll handle characters.
16 | config.cursorSpeed = 1.5 -- Speed at which the cursor blinks.
17 | config.fontName = "" -- Filename of the font to be used. Leave it blank to use the default font.
18 | config.fontSize = 10 -- Size of the console font.
19 | config.consoleMarginEdge = 5 -- Left border margin of the console text.
20 | config.consoleMarginTop = 0 -- Top border margin of the console text.
21 | config.lineSpacing = 4 -- Space between individual lines.
22 | config.outlineSize = 1 -- Outline height at the bottom of the console.
23 | config.ignoreToggleKey = false -- If true, the toggle key will not be inputted to the console's input field.
24 | config.displayPrint = false -- If true the default print function will print to the console.
25 |
26 | config.stackMax = 100 -- Maximum number of lines stored in the console stack before old lines are removed.
27 | config.sizeMin = 5 -- Minimum lines the console should display before extending to the max size.
28 | config.sizeMax = 10 -- Maximum number of entries to print at a time.
29 | config.shiftAmount = 1 -- Amount of lines to move over while scrolling up and down.
30 |
31 | config.keys.toggle = "f10" -- Key used to toggle the console during runtime.
32 | config.keys.scrollUp = "pageup" -- Key used to scroll up within the console's message stack.
33 | config.keys.scrollDown = "pagedown" -- Key used to scroll down within the console's message stack.
34 | config.keys.scrollTop = "home" -- Key used to move to the top of the stack.
35 | config.keys.scrollBottom = "end" -- Key used to move to the bottom of the stack.
36 | config.keys.inputUp = "up" -- Cycle up through the stack of last used commands.
37 | config.keys.inputDown = "down" -- Cycle down through the stack of last used commands.
38 | config.keys.cursorLeft = "left" -- Move the input cursor to the left.
39 | config.keys.cursorRight = "right" -- Move the input cursor to the right.
40 |
41 | -- Color tables used by the console. Change these to style the console to your liking.
42 | -- Background color of the console window.
43 | config.colors["background"] = {
44 | r = 0,
45 | g = 43,
46 | b = 54,
47 | a = 255
48 | }
49 |
50 | -- Color of the console outline.
51 | config.colors["outline"] = {
52 | r = 88,
53 | g = 110,
54 | b = 117,
55 | a = 255
56 | }
57 |
58 | -- Default console basic text color.
59 | config.colors["text"] = {
60 | r = 238,
61 | g = 232,
62 | b = 213,
63 | a = 255
64 | }
65 |
66 | -- Color of warning messages.
67 | config.colors["warning"] = {
68 | r = 231,
69 | g = 207,
70 | b = 0,
71 | a = 255
72 | }
73 |
74 | -- Color of error messages.
75 | config.colors["error"] = {
76 | r = 255,
77 | g = 75,
78 | b = 75,
79 | a = 255
80 | }
81 |
82 | -- Color of error messages.
83 | config.colors["success"] = {
84 | r = 143,
85 | g = 253,
86 | b = 0,
87 | a = 255
88 | }
89 |
90 | -- Color of the console's input field.
91 | config.colors["input"] = {
92 | r = 253,
93 | g = 246,
94 | b = 227,
95 | a = 255
96 | }
97 |
98 | return config
99 |
--------------------------------------------------------------------------------
/loveconsole/init.lua:
--------------------------------------------------------------------------------
1 |
2 | --[[
3 |
4 | LOVEConsole was created by Catlinman and can be forked on GitHub
5 |
6 | -> https://github.com/catlinman/loveconsole
7 |
8 | This file allows for in-application executing and handling of function and variables allowing for more flexibility while debugging.
9 |
10 | Feel free to modify the file to your liking as long as I am credited for the original work.
11 | For more information please refer to the following link:
12 |
13 | -> https://github.com/catlinman/loveconsole/blob/master/LICENSE
14 |
15 | The configuration file (config.lua) contains all the necessary settings for the console to work correctly.
16 | At the moment this means that if a variable within the configuration is not set the actual console will cause errors and not work.
17 |
18 | --]]
19 |
20 | local console = {} -- Base table containing all console variables and methods.
21 | local config = {} -- Table containing console settings.
22 |
23 | local baseFont = love.graphics.getFont() -- Store the default font.
24 | local consoleFont = baseFont -- Temporarily store the default font which will be overwritten later on.
25 |
26 | local consoleCommands = {} -- Table containing command callbacks.
27 | local consoleInput = "" -- String containing a user entered string command.
28 | local consoleActive = false -- If true the console will be shown.
29 | local consoleStatus = "" -- Variable holding the last fatal error message.
30 | local consoleCursorIndex = 0 -- Index of the input movement cursor.
31 |
32 | local consoleStack = {} -- Table containing the console printed lines.
33 | local consoleStackCount = 0 -- Current number of lines the console should accommodate for.
34 | local consoleStackShift = 0 -- Amount of lines to shift the output stack by.
35 |
36 | local consoleInputStack = {} -- Table containing the last user inputs. Has the same size as the main stack.
37 | local consoleInputStackCount = 0 -- Number of input lines in the stack.
38 | local consoleInputStackShift = 0 -- Amount of lines to shift the input stack by.
39 |
40 | local warningCount, errorCount = 0, 0 -- Track the number of unchecked errors and warnings.
41 |
42 | local screenWidth, screenHeight = love.graphics.getDimensions() -- Store the screen size.
43 |
44 | local defaultPrint = print
45 |
46 | -- Returns the current lua local path to this script.
47 | local function scriptPath()
48 | local str = debug.getinfo(2, "S").source:sub(2)
49 | return str:match("(.*/)") or ""
50 | end
51 |
52 | -- String splitting function.
53 | function string.split(str, delim)
54 | if string.find(str, delim) == nil then
55 | return {str}
56 | end
57 |
58 | local result = {}
59 | local pat = "(.-)" .. delim .. "()"
60 | local nb = 0
61 | local lastPos
62 |
63 | for part, pos in string.gfind(str, pat) do
64 | nb = nb + 1
65 | result[nb] = part
66 | lastPos = pos
67 | end
68 |
69 | result[nb + 1] = string.sub(str, lastPos)
70 |
71 | return result
72 | end
73 |
74 | -- Insert a string into another string.
75 | function string.insert(s1, s2, pos)
76 | return string.sub(s1, 1, pos) ..s2 ..string.sub(s1, pos + 1, #s1)
77 | end
78 |
79 | -- Drop a character at a specified position.
80 | function string.pop(str, pos)
81 | return string.sub(str, 1, pos) ..string.sub(str, pos + 2, #str)
82 | end
83 |
84 | -- Remove all UTF8 characters from a string.
85 | function string.stripUTF8(str)
86 | return str:gsub('[%z\1-\127\194-\244][\128-\191]*', function(c) return #c > 1 and "" end)
87 | end
88 |
89 | -- Range iterator function.
90 | local function range(a, b, step)
91 | if not b then
92 | b = a
93 | a = 1
94 | end
95 |
96 | step = step or 1
97 |
98 | local f = step > 0 and
99 | function(_, lastvalue)
100 | local nextvalue = lastvalue + step
101 | if nextvalue <= b then return nextvalue end
102 | end or
103 | step < 0 and
104 | function(_, lastvalue)
105 | local nextvalue = lastvalue + step
106 | if nextvalue >= b then return nextvalue end
107 | end or
108 | function(_, lastvalue) return lastvalue end
109 | return f, nil, a - step
110 | end
111 |
112 | -- Pass a message to the console stack.
113 | local function stackpush(message, color)
114 | if message ~= nil then
115 | if #consoleStack > config.stackMax then
116 | table.remove(consoleStack, 1)
117 | end
118 |
119 | consoleStack[#consoleStack + 1] = {
120 | ["message"] = message,
121 | ["color"] = color
122 | }
123 |
124 | consoleStackCount = #consoleStack
125 | end
126 | end
127 |
128 | -- Inserts line breaks into a string.
129 | local function linify(message)
130 | local editedmessage = message
131 | local averagelength = consoleFont:getWidth(message) / #tostring(message)
132 | local segementlength = math.floor((screenWidth - config.consoleMarginEdge * 2) / averagelength)
133 | local numsplits = math.floor(#tostring(message) / segementlength)
134 |
135 | if numsplits > 0 then
136 | for i = 1, numsplits, 1 do
137 | editedmessage = string.insert(editedmessage, '\n', segementlength * i + (2 * (i - 1)))
138 | end
139 | end
140 |
141 | return string.split(tostring(editedmessage), '\n')
142 | end
143 |
144 | -- Console functions that can be called outside of console.lua
145 | -- Toggle the console.
146 | function console.toggle(state)
147 | if config.enabled then
148 | if state ~= true and state ~= false then
149 | consoleActive = not consoleActive
150 |
151 | elseif state or state == false then
152 | -- The console state was specified. Set the console to the desired state.
153 | consoleActive = state
154 | end
155 |
156 | if consoleActive then
157 | -- The console was opened and the errors were seen. Remove the outside widget.
158 | warningCount, errorCount = 0, 0
159 | end
160 | end
161 | end
162 |
163 | -- Print a string to the console. The optional color table must be defined as {r = v, g = v, b = v, a = v}.
164 | function console.print(message, color)
165 | if config.enabled then
166 | if message ~= nil then
167 |
168 | lines = linify(message)
169 |
170 | for i, m in pairs(lines) do
171 | if not color then
172 | stackpush(m, "default")
173 | else
174 | stackpush(m, color)
175 | end
176 | end
177 | else
178 | stackpush("Please supply a value before printing to the console.", "warning")
179 | end
180 | end
181 | end
182 |
183 | -- Print a string to the console with warning styling and add to the warning count.
184 | function console.warning(message)
185 | if config.enabled then
186 | if message ~= nil then
187 | lines = linify(message)
188 |
189 | for i, m in pairs(lines) do
190 | stackpush("Warning: " .. m, "warning")
191 | end
192 |
193 | warningCount = warningCount + 1
194 | else
195 | stackpush("Please supply a value before sending a warning message to the console.", "warning")
196 | end
197 | end
198 | end
199 |
200 | -- Print a string to the console with success styling.
201 | function console.success(message)
202 | if config.enabled then
203 | if message ~= nil then
204 | lines = linify(message)
205 |
206 | for i, m in pairs(lines) do
207 | stackpush("Success: " .. m, "success")
208 | end
209 | else
210 | stackpush("Please supply a value before sending a warning message to the console.", "warning")
211 | end
212 | end
213 | end
214 |
215 | -- Print a string to the console with error styling and add to the error count.
216 | function console.error(message)
217 | if config.enabled then
218 | if message ~= nil then
219 | lines = linify(message)
220 |
221 | for i, m in pairs(lines) do
222 | stackpush("Error: " .. m, "error")
223 | end
224 |
225 | errorCount = errorCount + 1
226 | else
227 | stackpush("Please supply a value before sending an error message to the console.", "warning")
228 | end
229 | end
230 | end
231 |
232 | -- Print a string to the console using the default print function.
233 | function print(...)
234 | defaultPrint(...)
235 |
236 | if config.displayPrint then
237 | console.print(table.concat({...}, " "))
238 | end
239 | end
240 |
241 | -- Add a command to the command table. Callback is the function executed when the command is run.
242 | function console.addCommand(name, callback, description)
243 | if not consoleCommands[name] then
244 | consoleCommands[name] = {["callback"] = callback, ["description"] = description or ""}
245 | else
246 | print("[Console] The command with the name of " .. name .. " already exists in the command table.")
247 | end
248 | end
249 |
250 | -- Remove a command from the command table.
251 | function console.removeCommand(name)
252 | if consoleCommands[name] then
253 | consoleCommands[name] = nil
254 | collectgarbage()
255 | else
256 | print("[Console] Unable to find the command with the name of " .. name .. " in the command table.")
257 | end
258 | end
259 |
260 | -- Tell the console to perform a command from a string argument.
261 | function console.perform(line)
262 | local arguments = string.split(line, " ")
263 | local command = arguments[1]
264 |
265 | -- Remove the command argument from the argument table
266 | table.remove(arguments, 1)
267 |
268 | if consoleCommands[command] then
269 | local status, err
270 |
271 | if arguments[1] then
272 | status, err = pcall(
273 | function()
274 | consoleCommands[command].callback(arguments)
275 | end
276 | )
277 | else
278 | status, err = pcall(
279 | function()
280 | consoleCommands[command].callback()
281 | end
282 | )
283 | end
284 |
285 | if err then
286 | console.print(string.format("Executing %s returned the following error: %s", command, tostring(err)))
287 | end
288 | elseif console.parseLine then
289 | console.parseLine(line)
290 | else
291 | console.print(string.format("Unknown command '%s'", command))
292 | end
293 | end
294 |
295 | -- Clear the console.
296 | function console.clear()
297 | consoleStack = {}
298 | consoleStackCount = 0
299 | warningCount, errorCount = 0, 0
300 | end
301 |
302 | -- These functions need to be called from main.lua
303 | -- Draw the console and it's contents.
304 | function console.draw()
305 | if config.enabled and consoleActive then
306 | love.graphics.setFont(consoleFont) -- Prepare the console font.
307 |
308 | -- Draw the console background.
309 | love.graphics.setColor(config.colors["background"].r, config.colors["background"].g, config.colors["background"].b, config.colors["background"].a)
310 | love.graphics.rectangle(
311 | "fill",
312 | 0,
313 | 0,
314 | screenWidth,
315 | config.consoleMarginTop + config.fontSize * 2 + config.lineSpacing * math.max(math.min(consoleStackCount, config.sizeMax) + 1, config.sizeMin) +
316 | (math.max(math.min(consoleStackCount, config.sizeMax), config.sizeMin - 1) * config.fontSize)
317 | )
318 |
319 | -- Draw the console outline.
320 | love.graphics.setColor(config.colors["outline"].r, config.colors["outline"].g, config.colors["outline"].b, config.colors["outline"].a)
321 | love.graphics.rectangle(
322 | "fill",
323 | 0,
324 | config.consoleMarginTop + config.fontSize * 2 + config.lineSpacing * math.max(math.min(consoleStackCount, config.sizeMax) + 1, config.sizeMin) +
325 | (math.max(math.min(consoleStackCount, config.sizeMax), config.sizeMin - 1) * config.fontSize),
326 | screenWidth,
327 | config.outlineSize
328 | )
329 |
330 | -- Draw the scroll indicators.
331 | if #consoleStack > config.sizeMax then
332 | love.graphics.setColor(config.colors["text"].r, config.colors["text"].g, config.colors["text"].b, config.colors["text"].a)
333 |
334 | -- Show scroll arrows if there are more lines to display.
335 | if consoleStackShift ~= math.min(#consoleStack - config.sizeMax, config.stackMax) then
336 | love.graphics.printf(config.scrollChar, 0, config.consoleMarginTop, screenWidth - config.consoleMarginEdge, "right")
337 | end
338 |
339 | if consoleStackShift ~= 0 then
340 | love.graphics.printf(config.scrollChar, 0, config.consoleMarginTop + (config.lineSpacing * config.sizeMax) + (config.sizeMax * config.fontSize), screenWidth - config.consoleMarginEdge, "right")
341 | end
342 | end
343 |
344 | -- Draw the message stack with the message coloring.
345 | for i in range(math.min(config.sizeMax, #consoleStack)) do
346 | local entry = consoleStack[math.max(1, (#consoleStack - math.min(config.sizeMax, #consoleStack) + i - consoleStackShift))]
347 |
348 | if type(entry.color) == "string" then
349 | if config.colors[entry.color] then
350 | local c = config.colors[entry.color]
351 | love.graphics.setColor(c.r, c.g, c.b, c.a)
352 | else
353 | love.graphics.setColor(config.colors["text"].r, config.colors["text"].g, config.colors["text"].b, config.colors["text"].a)
354 | end
355 |
356 | elseif type(entry.color) == "table" then
357 | local r, g, b, a = entry.color.r or 255, entry.color.g or 255, entry.color.b or 255, entry.color.a or 255
358 | love.graphics.setColor(r, g, b, a)
359 | else
360 | love.graphics.setColor(config.colors["text"].r, config.colors["text"].g, config.colors["text"].b, config.colors["text"].a)
361 | end
362 |
363 | love.graphics.print(tostring(entry.message), config.consoleMarginEdge, config.consoleMarginTop + (config.lineSpacing * i) + ((i - 1) * config.fontSize))
364 | end
365 |
366 | -- Draw the input line.
367 | local consoleInputEdited = consoleInput
368 | if math.ceil(os.clock() * config.cursorSpeed) % 2 == 0 then
369 | consoleInputEdited = string.insert(consoleInput, "|", consoleCursorIndex)
370 | else
371 | consoleInputEdited = string.insert(consoleInput, " ", consoleCursorIndex)
372 | end
373 |
374 | love.graphics.setColor(config.colors["input"].r, config.colors["input"].g, config.colors["input"].b, config.colors["input"].a)
375 | love.graphics.print(string.format("%s%s", config.inputChar, consoleInputEdited), config.consoleMarginEdge,config.consoleMarginTop +
376 | (config.lineSpacing * math.max(math.min(consoleStackCount, config.sizeMax) + 1, 1)) +
377 | (math.min(consoleStackCount, config.sizeMax) * config.fontSize)
378 | )
379 |
380 | -- Reset the color and font in case someone decides to do drawing after the console (which doesn't make sense but who cares).
381 | love.graphics.setColor(255, 255, 255, 255)
382 | love.graphics.setFont(baseFont)
383 |
384 | elseif config.enabled and config.alert and consoleActive == false then
385 | love.graphics.setFont(consoleFont) -- Prepare the console font.
386 |
387 | -- Draw the information widgets if the console is hidden and there are warnings and or errors.
388 | if warningCount > 0 or errorCount > 0 then
389 | local width = 6 * config.fontSize
390 | local height = config.fontSize * 1.5
391 |
392 | -- Draw the box outline border.
393 | love.graphics.setColor(config.colors["outline"].r, config.colors["outline"].g, config.colors["outline"].b, config.colors["outline"].a)
394 | love.graphics.rectangle("fill", 0, 0, width + config.outlineSize * 2, height + config.outlineSize * 2)
395 |
396 | -- Draw the box background.
397 | love.graphics.setColor(config.colors["background"].r, config.colors["background"].g, config.colors["background"].b, config.colors["background"].a)
398 | love.graphics.rectangle("fill", config.outlineSize, config.outlineSize, width, height)
399 |
400 | -- Draw the warning count.
401 | love.graphics.setColor(config.colors["warning"].r, config.colors["warning"].g, config.colors["warning"].b, config.colors["warning"].a)
402 | love.graphics.printf(math.min(9999, warningCount), math.ceil(config.outlineSize - config.fontSize / 2), math.ceil(config.outlineSize + (config.fontSize / 6)), config.fontSize * 4, "center")
403 |
404 | -- Draw the error count.
405 | love.graphics.setColor(config.colors["error"].r, config.colors["error"].g, config.colors["error"].b, config.colors["error"].a)
406 | love.graphics.printf(math.min(9999, errorCount), math.ceil(config.outlineSize + config.fontSize * 2.5), math.ceil(config.outlineSize + (config.fontSize / 6)), config.fontSize * 4, "center")
407 |
408 | -- Reset color.
409 | love.graphics.setColor(255, 255, 255, 255)
410 | love.graphics.setFont(baseFont)
411 | end
412 | end
413 | end
414 |
415 | -- Tell LÖVE2D to allow repeating key presses. Comment this line if you don't want the given functionality.
416 | love.keyboard.setKeyRepeat(true)
417 |
418 | -- Receive pressed keys and interpret them.
419 | function console.keypressed(key)
420 | if config.enabled then
421 | if key == config.keys.toggle then
422 | -- Update the screen size and display the console.
423 | screenWidth, screenHeight = love.graphics.getDimensions()
424 | console.toggle()
425 |
426 | elseif consoleActive then
427 | if key == "return" or key == "kpenter" then
428 | if consoleInput == "" then
429 | consoleInput = lastConsoleInput or ""
430 | end
431 |
432 | if consoleInput ~= "" then
433 | lastConsoleInput = consoleInput
434 | if consoleInput:match("%S") then
435 | -- Store the line in the stack.
436 | if #consoleInputStack > config.stackMax then
437 | table.remove(consoleInputStack, 1)
438 | end
439 |
440 | consoleInputStack[#consoleInputStack + 1] = consoleInput
441 | consoleInputStackCount = #consoleInputStack
442 |
443 | -- echo line if enabled
444 | if config.echoLine then
445 | console.print(string.format("%s%s", config.inputChar, consoleInput))
446 | end
447 |
448 | -- Execute the given string command and reset the input field.
449 | console.perform(consoleInput)
450 | consoleInput = ""
451 |
452 | -- Also reset the stack shift.
453 | consoleStackShift = 0
454 | consoleInputStackShift = 0
455 |
456 | -- Reset the cursor index
457 | consoleCursorIndex = 0
458 | else
459 | consoleInput = ""
460 | end
461 | end
462 |
463 | elseif key == "backspace" then
464 | if consoleCursorIndex ~= 0 then
465 | consoleInput = string.pop(consoleInput, consoleCursorIndex - 1)
466 | consoleCursorIndex = math.max(consoleCursorIndex - 1, 0)
467 | end
468 |
469 | elseif key == "delete" then
470 | consoleInput = string.pop(consoleInput, consoleCursorIndex)
471 |
472 | elseif love.keyboard.isDown("lctrl", "rctrl") and love.keyboard.isDown("v") then
473 | consoleInput = string.insert(consoleInput, love.system.getClipboardText(), consoleCursorIndex)
474 | consoleCursorIndex = consoleCursorIndex + string.len(love.system.getClipboardText())
475 |
476 | elseif key == config.keys.scrollUp then
477 | if #consoleStack > config.sizeMax then
478 | -- Move the stack up.
479 | consoleStackShift = math.min(math.min(#consoleStack - config.sizeMax, config.stackMax), consoleStackShift + 1)
480 | end
481 |
482 | elseif key == config.keys.scrollDown then
483 | -- Move the stack down.
484 | consoleStackShift = math.max(consoleStackShift - 1, 0)
485 |
486 | elseif key == config.keys.scrollTop then
487 | -- Make sure that we can actually scroll and if so, move the stack shift to show the top most line.
488 | if #consoleStack > config.sizeMax then
489 | consoleStackShift = math.min(#consoleStack - config.sizeMax, config.stackMax)
490 | end
491 |
492 | elseif key == config.keys.scrollBottom then
493 | -- Set the shift amount to zero so the newest line is the last.
494 | consoleStackShift = 0
495 |
496 | elseif key == config.keys.scrollUp then
497 | if #consoleStack > config.sizeMax then
498 | -- Move the stack up.
499 | consoleStackShift = math.min(math.min(#consoleStack - config.sizeMax, config.stackMax), consoleStackShift + 1)
500 | end
501 |
502 | elseif key == config.keys.cursorLeft then
503 | consoleCursorIndex = math.max(consoleCursorIndex - 1, 0)
504 |
505 | elseif key == config.keys.cursorRight then
506 | consoleCursorIndex = math.min(consoleCursorIndex + 1, #consoleInput)
507 |
508 | elseif key == config.keys.inputUp then
509 | consoleInputStackShift = math.min(consoleInputStackShift + 1, #consoleInputStack)
510 |
511 | local entry = consoleInputStack[#consoleInputStack - consoleInputStackShift + 1]
512 | if entry then
513 | consoleInput = entry
514 | end
515 |
516 | consoleCursorIndex = #consoleInput
517 |
518 | elseif key == config.keys.inputDown then
519 | consoleInputStackShift = math.max(consoleInputStackShift - 1, 0)
520 |
521 | local entry = consoleInputStack[#consoleInputStack - consoleInputStackShift + 1]
522 | if consoleInputStackShift ~= 0 then
523 | consoleInput = entry
524 | consoleCursorIndex = #consoleInput
525 | else
526 | consoleInput = ""
527 | consoleCursorIndex = 0
528 | end
529 | end
530 | end
531 | end
532 | end
533 |
534 | -- Send text input to the console input field.
535 | function console.textinput(s)
536 | -- If the key is the toggle key and the ignoreToggleKey option is enabled, clear the input.
537 | if config.ignoreToggleKey and s == config.keys.toggle then
538 | s = ""
539 | end
540 |
541 | if config.enabled and consoleActive and s ~= "" then
542 | -- Insert the character and clean out all UTF8 characters since they break everything otherwise.
543 | consoleInput = string.insert(consoleInput, string.stripUTF8(s), consoleCursorIndex)
544 | consoleCursorIndex = math.min(#consoleInput, consoleCursorIndex + 1)
545 | end
546 | end
547 |
548 | -- If the window is resized whilst the console is open, resize the console.
549 | function console.resize(w, h)
550 | screenWidth, screenHeight = w, h
551 | end
552 |
553 | -- Execute the configuration file and initialize user consoleCommands.
554 | local loaded, data
555 | loaded, data = pcall(love.filesystem.load, scriptPath() .."config.lua")
556 |
557 | if not loaded then
558 | print("[Console] Failed to load the configuration file due to the following error: " .. tostring(data))
559 | config.enabled, consoleActive, consoleStatus = false, false, data
560 | else
561 | loaded, data = pcall(data)
562 |
563 | if not loaded then
564 | print("[Console] Executing the configuration file returned the following error: " .. tostring(data))
565 | config.enabled, consoleActive, consoleStatus = false, false, data
566 | else
567 | config = data
568 |
569 | -- Load font data.
570 | local fontstatus, data = pcall(
571 | function()
572 | if config.fontName ~= "" then
573 | return love.graphics.newFont(config.fontName, config.fontSize)
574 | else
575 | return love.graphics.newFont(config.fontSize)
576 | end
577 | end
578 | )
579 | if not fontstatus then
580 | print("[Console] Loading the custom defined console font returned the following error: " .. tostring(data) .." - reverting to the default font instead.")
581 | else
582 | consoleFont = data
583 | end
584 | end
585 | end
586 |
587 | -- Some base functions to make life just a little easier.
588 |
589 | -- We wrap functions in a custom callback.
590 | console.addCommand("clear", function() console.clear() end, "Clears the entire console.")
591 | console.addCommand("quit", function() love.event.quit() end, "Attempts to close the application.")
592 |
593 | -- Command callbacks can also receive a table of string arguments.
594 | console.addCommand("print", function(args)
595 | if args then
596 | console.print(table.concat(args, " "))
597 | else
598 | -- Error is returned to the console. In case of console.execute, error is returned to the "out" variable.
599 | console.print("Missing required arguments")
600 | end
601 | end, "Prints trailing command arguments as a formatted string - Arguments: [string to print]")
602 |
603 | -- Executes a lua command and prints it's return value to the console.
604 | console.addCommand("run", function(args)
605 | if args then
606 | local value = assert(loadstring(string.format("return %s", table.concat(args, " "))))()
607 |
608 | if value then
609 | console.print(string.format("Returned %s", tostring(value)))
610 | else
611 | console.print(string.format("Executing %s returned nil", table.concat(args, " ")))
612 | end
613 | else
614 | console.print("Missing the argument lua code to execute")
615 | end
616 | end, "Executes the supplied lua function - Arguments: [lua command to execute] - Example: 'console.print(\"Do the fishstick!\")'")
617 |
618 | -- Same as run with the difference of not returning a value and so avoiding errors while assigning new values to variables.
619 | console.addCommand("set", function(args)
620 | if args then
621 | assert(loadstring(string.format('%s', table.concat(args, " "))))()
622 | console.print("Variable entry set")
623 | else
624 | console.print("Missing the argument lua code to set")
625 | end
626 | end, "Sets a supplied variable - Arguments: [lua assignment to execute] - Example: 'console.enabled = false'")
627 |
628 | -- Amazing help command of doom. It helps people.
629 | console.addCommand("help", function(args)
630 | if not args then
631 | console.print("Available commands are:")
632 | for k, v in pairs(consoleCommands) do
633 | if v.description ~= "" then
634 | console.print(string.format("%s - %s", k, v.description), config.colors.success)
635 | else
636 | console.print(k, config.colors.success)
637 | end
638 | end
639 | else
640 | local name = table.concat(args, " ")
641 |
642 | if consoleCommands[name] then
643 | if consoleCommands[name].description then
644 | console.print(string.format("%s - %s", name, consoleCommands[name].description), {r = 0, g = 255, b = 0})
645 | else
646 | console.print(string.format("The command with the name of '%s' does not have a description.", name))
647 | end
648 | else
649 | console.print(string.format("The command with the name of '%s' was not found in the command table.", name))
650 | end
651 | end
652 | end, "Outputs the names and descriptions of all available console commands or just a single one - Arguments: [command to fetch information on]")
653 |
654 | -- Creates a new command entry that points to another command.
655 | console.addCommand("alias", function(args)
656 | if args then
657 | if args[1] and args[2] then
658 | if consoleCommands[args[1]] then
659 | console.addCommand(args[2], consoleCommands[args[1]].callback, consoleCommands[args[1]].description)
660 | console.print(string.format("Successfully assigned the alias of '%s' to the command of '%s'.", args[2], args[1]))
661 | end
662 | else
663 | console.print("Missing command arguments. Requires two.")
664 | end
665 | else
666 | console.print("Missing command arguments. Requires two.")
667 | end
668 | end, "Creates a new command list entry mimicking another command. Arguments: [command to alias] [alias name]")
669 |
670 | return console
671 |
--------------------------------------------------------------------------------
/main.lua:
--------------------------------------------------------------------------------
1 |
2 | -- Example main file to show the console functionality.
3 |
4 | local console = require("loveconsole") -- Require the console script.
5 |
6 | function love.load()
7 | -- Example of printing to the console with custom colors.
8 | console.print("You are running LOVEConsole by Catlinman", {r = 0, g = 150, b = 255, a = 255})
9 | console.warning("Wow what a warning. Something is about to break.")
10 | console.error("Many error very scare.")
11 | console.success("User is spooked.")
12 |
13 | -- We define custom commands using the addCommand method.
14 | -- A simple "Hello user" example command can be seen below.
15 | console.addCommand("hello", function(args)
16 | if args then
17 | console.print(string.format("Greetings %s!", args[1]))
18 | else
19 | console.print("Hey there!")
20 | end
21 | end, "Greets you in a non rude way - Arguments: [person to say hello to]")
22 |
23 | end
24 |
25 | function love.draw()
26 | love.graphics.setBackgroundColor(10, 25, 50) -- Set a lame background.
27 |
28 | -- Keep in mind to call love.graphics.pop() if you performed any translation changes using love.graphics.push()
29 | console.draw() -- Draw the console at the end of the draw loop.
30 | end
31 |
32 | function love.keypressed(key)
33 | console.keypressed(key) -- Pass pressed keys to the console.
34 | end
35 |
36 | function love.textinput(t)
37 | console.textinput(t) -- Send text input to the console.
38 | end
39 |
40 | function love.resize(w, h)
41 | console.resize(w, h) -- Resize the console if the window is resized.
42 | end
43 |
--------------------------------------------------------------------------------