├── LICENSE ├── README.md ├── conf.lua ├── console.lua ├── inconsolata ├── Inconsolata.otf └── OFL.txt ├── main.lua └── shot.png /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Maciej Lopacinski 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # love-console 2 | 3 | Simple Counter-Strike-like console for LÖVE games 4 | 5 | ## What is it? 6 | 7 | Tap `` ` `` to toggle console visibility: 8 | 9 | ![In action](https://raw.githubusercontent.com/hamsterready/love-console/master/shot.png) 10 | 11 | When console is visible it can consume ``love.keypressed`` and ``love.mousepressed`` callbacks (if you wish it to). If you do not want to pass events to console callbacks then you can always open console by calling ``console.visible = true``. 12 | 13 | Useful for simple debugging and changing game parameters in runtime. 14 | 15 | ## How to use it? 16 | 17 | Check [main.lua](https://github.com/hamsterready/love-console/blob/master/main.lua) for complete example. 18 | 19 | Minimum working example: 20 | 21 | ```lua 22 | 23 | -- load and initialize console with defaults 24 | local console = require 'console' 25 | 26 | function love.draw() 27 | -- draw console, should be last statement in love.draw function, 28 | -- otherwsie other elements may be drawn on top of it 29 | console.draw() 30 | end 31 | 32 | function love.keypressed(key) 33 | -- let console consume keypress events, if only it is visible 34 | -- should be first code block in love.keypressed function 35 | if console.keypressed(key) then 36 | return 37 | end 38 | end 39 | 40 | function love.resize( w, h ) 41 | -- if your application window is resizable, 42 | -- then update console with new width and height 43 | console.resize(w, h) 44 | end 45 | 46 | 47 | function love.mousepressed(x, y, button) 48 | -- let the console consume wheel up and down mosuepress events 49 | -- (only when console is visible) 50 | -- should be first code block in love.mousepressed function 51 | if console.mousepressed(x, y, button) then 52 | return 53 | end 54 | end 55 | 56 | ``` 57 | 58 | ## API 59 | 60 | - `` console.load(keyCode, fontSize, keyRepeat, inputCallback) `` - initializes console 61 | - ``keyCode`` - KeyConstant, default `` ` ``, it is used to toggle console visibility 62 | - ``fontSize`` - number, default 20 63 | - ``keyRepeat`` - boolean, default false 64 | - ``inputCallback`` - function, if ``nil`` is being passed then default implementation is being used, see ``console.lua`` file for details 65 | 66 | - `` console.draw() `` - draws console, 67 | 68 | console position and size ``x, y, w, h = 0, 0, windowWidth, windowHeight/5``; please remember to call ``console.resize()`` so that ``w, h`` can be recomputed 69 | 70 | - `` console.update(dt) `` - updates console state with ``dt`` time, not required, but strongly recommended 71 | - ``dt`` - delta time 72 | 73 | - `` console.resize(w, h) `` - call when window is resized, not required but recommended when your application window is resizable 74 | - ``w`` - new window width 75 | - ``h`` - new window height 76 | 77 | - `` console.keypressed(key) `` - handles keypress events 78 | - ``key`` - KeyConstant 79 | 80 | shall be invoked as first block in ``love.keypressed(key)``; returns true if key was consumed by console, false otherwise 81 | 82 | this one is rather required, it allows to toggle console visibility without pain and you do not have to deal with visibility state, however you can always use ``console.visible = true or false`` to show/hide the console 83 | 84 | - `` console.mousepressed(x, y, button) `` - handles mousepress events 85 | - ``x`` - mouse position 86 | - ``y`` - mouse position 87 | - ``button`` - mouse button being pressed 88 | 89 | calling this method allows console to support scrolling through messages (if only console is visible ) 90 | 91 | shall be invoked as first block in ``love.mousepressed(x, y, button)``; returns true if button was consumed by console, false otherwise 92 | 93 | - `` console.d(t), console.i(t), console.e(t) `` - append ``debug``, ``info`` or ``error`` message to the console 94 | - `` t `` - string, message content 95 | 96 | - `console.defineCommand(name, description, implementation)` - Define a command like `/help`. 97 | - `name` - The name of the command which must include the forward-slash (if desired). 98 | - `description` - An explanation of the command shown by `/help`. 99 | - `implementation` - A function providing the logic for the command. It receives no arguments and the package ignores any return values. 100 | -------------------------------------------------------------------------------- /conf.lua: -------------------------------------------------------------------------------- 1 | function love.conf( t ) 2 | t.window.title = "Console example" 3 | t.window.width = 1920 4 | t.window.height = 1080 5 | t.window.resizable = true 6 | end 7 | -------------------------------------------------------------------------------- /console.lua: -------------------------------------------------------------------------------- 1 | local console = { 2 | _VERSION = 'love-console v0.1.0', 3 | _DESCRIPTION = 'Simple love2d console overlay', 4 | _URL = 'https://github.com/hamsterready/love-console', 5 | _LICENSE = [[ 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2014 Maciej Lopacinski 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | ]], 28 | -- hm, should it be stored in console or as module locals? 29 | -- need to read more http://kiki.to/blog/2014/03/31/rule-2-return-a-local-table/ 30 | 31 | _KEY_TOGGLE = "`",--"f2",-- 32 | _KEY_SUBMIT = "return", 33 | _KEY_CLEAR = "escape", 34 | _KEY_DELETE = "backspace", 35 | _KEY_UP = "up", 36 | _KEY_DOWN = "down", 37 | _KEY_LEFT = "left", 38 | _KEY_RIGHT = "right", 39 | _KEY_PAGEDOWN = "pagedown", 40 | _KEY_PAGEUP = "pageup", 41 | 42 | cursor = 0, 43 | cursorlife = 1, 44 | visible = false, 45 | delta = 0, 46 | logs = {}, 47 | history = {}, 48 | historyPosition = 0, 49 | linesPerConsole = 0, 50 | fontSize = 20, 51 | font = nil, 52 | firstLine = 0, 53 | lastLine = 0, 54 | input = "", 55 | ps = "> ", 56 | mode = "none", --Options are "none", "wrap", "scissors" or "bind" 57 | motd = 'Welcome user!\nType "help" for an index of available commands.', 58 | 59 | -- This table has as its keys the names of commands as 60 | -- strings, which the user must type to run the command. The 61 | -- values are themselves tables with two properties: 62 | -- 63 | -- 1. 'description' A string of information to show via the 64 | -- help command. 65 | -- 66 | -- 2. 'implementation' A function implementing the command. 67 | -- 68 | -- See the function defineCommand() for examples of adding 69 | -- entries to this table. 70 | commands = {} 71 | } 72 | -- Dynamic polygons used to draw the arrows 73 | local up = function (x, y, w) 74 | w = w * .7 75 | local h = w * .7 76 | return { 77 | x, y + h; 78 | x + w, y + h; 79 | x + w/2, y 80 | } 81 | end 82 | 83 | local down = function (x, y, w) 84 | w = w * .7 85 | local h = w * .7 86 | return { 87 | x, y; 88 | x + w, y; 89 | x + w/2, y + h 90 | } 91 | end 92 | --When you use wrap or bind, the total number of lines depends 93 | --on the number of lines used by each entry. 94 | local totalLines = function () 95 | if console.mode == "wrap" or console.mode == "bind" then 96 | local a, b = 1, 1 97 | local width = console.w - console.margin * 2 98 | for i,t in ipairs(console.logs) do 99 | b = a 100 | local _,u = console.font:getWrap(t.msg, width) 101 | a = a + u 102 | end 103 | return a 104 | else 105 | return #console.logs 106 | end 107 | end 108 | 109 | local function toboolean(v) 110 | return (type(v) == "string" and v == "true") or (type(v) == "string" and v == "1") or (type(v) == "number" and v ~= 0) or (type(v) == "boolean" and v) 111 | end 112 | 113 | -- http://lua-users.org/wiki/StringTrim trim2 114 | local function trim(s) 115 | s = s or "" 116 | return s:match "^%s*(.-)%s*$" 117 | end 118 | 119 | -- http://wiki.interfaceware.com/534.html 120 | local function string_split(s, d) 121 | local t = {} 122 | local i = 0 123 | local f 124 | local match = '(.-)' .. d .. '()' 125 | 126 | if string.find(s, d) == nil then 127 | return {s} 128 | end 129 | 130 | for sub, j in string.gmatch(s, match) do 131 | i = i + 1 132 | t[i] = sub 133 | f = j 134 | end 135 | 136 | if i ~= 0 then 137 | t[i+1] = string.sub(s, f) 138 | end 139 | 140 | return t 141 | end 142 | 143 | local function merge_quoted(t) 144 | local ret = {} 145 | local merging = false 146 | local buf = "" 147 | for k, v in ipairs(t) do 148 | local f, l = v:sub(1,1), v:sub(v:len()) 149 | if f == '"' and l ~= '"' then 150 | merging = true 151 | buf = v 152 | else 153 | if merging then 154 | buf = buf .. " " .. v 155 | if l == '"' then 156 | merging = false 157 | table.insert(ret, buf:sub(2,-2)) 158 | end 159 | else 160 | if f == "\"" and l == f then 161 | table.insert(ret, v:sub(2, -2)) 162 | else 163 | table.insert(ret, v) 164 | end 165 | end 166 | end 167 | end 168 | return ret 169 | end 170 | 171 | function console.load(font, keyRepeat, inputCallback, mode, levels) 172 | 173 | if mode == "none" or mode == "wrap" or mode == "scissors" or mode == "bind" then 174 | console.mode = mode 175 | end 176 | 177 | love.keyboard.setKeyRepeat(keyRepeat or false) 178 | 179 | console.font = font or love.graphics.newFont(console.fontSize) 180 | console.fontSize = font and font:getHeight() or console.fontSize 181 | console.margin = console.fontSize 182 | console.lineSpacing = 1.25 183 | console.lineHeight = console.fontSize * console.lineSpacing 184 | console.x, console.y = 0, 0 185 | 186 | console.colors = {} 187 | console.colors["I"] = {r = 251/255, g = 241/255, b = 213/255, a = 255/255} 188 | console.colors["D"] = {r = 235/255, g = 197/255, b = 50/255, a = 255/255} 189 | console.colors["E"] = {r = 222/255, g = 69/255, b = 61/255, a = 255/255} 190 | 191 | console.colors["background"] = {r = 23/255, g = 55/255, b = 86/255, a = 190/255} 192 | console.colors["input"] = {r = 23/255, g = 55/255, b = 86/255, a = 255/255} 193 | console.colors["default"] = {r = 215/255, g = 213/255, b = 174/255, a = 255/255} 194 | 195 | console.levels = levels or {info = true, debug=true, error=true} 196 | console.inputCallback = inputCallback or console.defaultInputCallback 197 | 198 | console.resize(love.graphics.getWidth(), love.graphics.getHeight()) 199 | end 200 | 201 | function console.newHotkeys(toggle, submit, clear, delete) 202 | console._KEY_TOGGLE = toggle or console._KEY_TOGGLE 203 | console._KEY_SUBMIT = submit or console._KEY_SUBMIT 204 | console._KEY_CLEAR = clear or console._KEY_CLEAR 205 | console._KEY_DELETE = delete or console._KEY_DELETE 206 | end 207 | 208 | function console.setMotd(message) 209 | console.motd = message 210 | end 211 | 212 | function console.resize( w, h ) 213 | console.w, console.h = w, h / 3 214 | console.y = console.lineHeight - console.lineHeight * console.lineSpacing 215 | 216 | console.linesPerConsole = math.floor((console.h - console.margin * 2) / console.lineHeight) 217 | 218 | console.h = math.floor(console.linesPerConsole * console.lineHeight + console.margin * 2) 219 | 220 | console.firstLine = console.lastLine - console.linesPerConsole 221 | console.lastLine = console.firstLine + console.linesPerConsole 222 | end 223 | 224 | function console.textinput(t) 225 | if t ~= console._KEY_TOGGLE and console.visible then 226 | console.cursor = console.cursor + 1 227 | local x = string.sub(console.input, 0, console.cursor) .. t 228 | if console.cursor < #console.input then 229 | x = x .. string.sub(console.input, console.cursor+1) 230 | end 231 | console.input = x 232 | 233 | 234 | --console.input = console.input .. t 235 | return true 236 | end 237 | end 238 | 239 | function console.keypressed(key) 240 | local function push_history(input) 241 | local trimmed = trim(console.input) 242 | local valid = trimmed ~= "" 243 | if valid then 244 | table.insert(console.history, trimmed) 245 | console.historyPosition = #console.history + 1 246 | end 247 | console.input = "" 248 | console.cursor = 0 249 | return valid 250 | end 251 | if key ~= console._KEY_TOGGLE and console.visible then 252 | if key == console._KEY_SUBMIT then 253 | local msg = console.input 254 | if push_history() then 255 | console.inputCallback(msg) 256 | end 257 | elseif key == console._KEY_CLEAR then 258 | console.input = "" 259 | elseif key == console._KEY_DELETE then 260 | if console.cursor >= 0 then 261 | local t = string.sub(console.input, 0, console.cursor) 262 | if console.cursor < #console.input then 263 | t = t .. string.sub(console.input, console.cursor+2) 264 | end 265 | console.input = t 266 | console.cursor = console.cursor - 1 267 | end 268 | elseif key == console._KEY_LEFT and console.cursor > 0 then 269 | console.cursor = console.cursor - 1 270 | elseif key == console._KEY_RIGHT and console.cursor < #console.input then 271 | console.cursor = console.cursor + 1 272 | end 273 | 274 | -- history traversal 275 | if #console.history > 0 then 276 | if key == console._KEY_UP then 277 | console.historyPosition = math.min(math.max(console.historyPosition - 1, 1), #console.history) 278 | console.input = console.history[console.historyPosition] 279 | elseif key == console._KEY_DOWN then 280 | local pushing = console.historyPosition + 1 > #console.history + 1 281 | console.historyPosition = math.min(console.historyPosition + 1, #console.history + 1) 282 | console.input = console.history[console.historyPosition] or "" 283 | if pushing then 284 | console.input = "" 285 | end 286 | end 287 | end 288 | 289 | if key == console._KEY_PAGEUP then 290 | console.firstLine = math.max(0, console.firstLine - console.linesPerConsole) 291 | console.lastLine = console.firstLine + console.linesPerConsole 292 | elseif key == console._KEY_PAGEDOWN then 293 | console.firstLine = math.min(console.firstLine + console.linesPerConsole, #console.logs - console.linesPerConsole) 294 | console.lastLine = console.firstLine + console.linesPerConsole 295 | end 296 | 297 | return true 298 | elseif key == console._KEY_TOGGLE then 299 | console.visible = not console.visible 300 | return true 301 | else 302 | 303 | end 304 | return false 305 | end 306 | 307 | function console.update( dt ) 308 | console.delta = console.delta + dt 309 | console.cursorlife = console.cursorlife - 1*dt 310 | if console.cursorlife < 0 then console.cursorlife = 1 end 311 | end 312 | 313 | function console.draw() 314 | if not console.visible then 315 | return 316 | end 317 | 318 | -- backup 319 | love.graphics.push() 320 | local r, g, b, a = love.graphics.getColor() 321 | local font = love.graphics.getFont() 322 | local blend = love.graphics.getBlendMode() 323 | local cr, cg, cb, ca = love.graphics.getColorMask() 324 | local sx, sy, sw, sh = love.graphics.getScissor() 325 | local canvas = love.graphics.getCanvas() 326 | 327 | --set everything to default 328 | love.graphics.origin() 329 | love.graphics.setBlendMode("alpha") 330 | love.graphics.setColorMask(true,true,true,true) 331 | love.graphics.setCanvas() 332 | 333 | if console.mode == "scissors" or console.mode == "bind" then 334 | love.graphics.setScissor(console.x, console.y, console.w, console.h + console.lineHeight) 335 | else 336 | love.graphics.setScissor() 337 | end 338 | 339 | -- draw console 340 | local color = console.colors.background 341 | love.graphics.setColor(color.r, color.g, color.b, color.a) 342 | love.graphics.rectangle("fill", console.x, console.y, console.w, console.h) 343 | color = console.colors.input 344 | love.graphics.setColor(color.r, color.g, color.b, color.a) 345 | love.graphics.rectangle("fill", console.x, console.y + console.h, console.w, console.lineHeight) 346 | color = console.colors.default 347 | love.graphics.setColor(color.r, color.g, color.b, color.a) 348 | love.graphics.setFont(console.font) 349 | love.graphics.print(console.ps .. " " .. console.input, console.x + console.margin, console.y + console.h + (console.lineHeight - console.fontSize) / 2 -1 ) 350 | 351 | if console.firstLine > 0 then 352 | love.graphics.polygon("fill", up(console.x + console.w - console.margin, console.y + console.margin, console.margin)) 353 | end 354 | 355 | if console.lastLine < #console.logs then 356 | love.graphics.polygon("fill", down(console.x + console.w - console.margin, console.y + console.h - console.margin * 2, console.margin)) 357 | end 358 | 359 | --Wrap and Bind are more complex than the normal mode so they are separated 360 | if console.mode == "wrap" or console.mode == "bind" then 361 | local x, width = console.x + console.margin, console.w - console.margin * 2 362 | local k, j = 1,1 363 | local lines = totalLines() 364 | love.graphics.setScissor(x, console.y, width, (console.linesPerConsole + 1) * console.lineHeight) 365 | for i, t in ipairs(console.logs) do 366 | local _,u = console.font:getWrap(t.msg, width) 367 | j = k + u 368 | if j > console.firstLine and k <= console.lastLine then 369 | local color = console.colors[t.level] 370 | love.graphics.setColor(color.r, color.g, color.b, color.a) 371 | 372 | local y = console.y + (k - console.firstLine)*console.lineHeight 373 | 374 | love.graphics.printf(t.msg, x, y, width) 375 | end 376 | k = j 377 | end 378 | else 379 | --This is the normal section 380 | for i, t in ipairs(console.logs) do 381 | if i > console.firstLine and i <= console.lastLine then 382 | local color = console.colors[t.level] 383 | love.graphics.setColor(color.r, color.g, color.b, color.a) 384 | love.graphics.print(t.msg, console.x + console.margin, console.y + (i - console.firstLine)*console.lineHeight) 385 | end 386 | end 387 | end 388 | 389 | -- cursor 390 | 391 | if console.cursorlife < 0.5 then 392 | local str = tostring(console.input) 393 | local offset = 1 394 | while console.font:getWidth(str) > console.w - (console.fontSize / 4) do 395 | str = str:sub(2) 396 | offset = offset + 1 397 | end 398 | 399 | local cursorx = ((console.x + (console.margin*2) + (console.fontSize/4)) + console.font:getWidth(str:sub(1, console.cursor + offset))) 400 | love.graphics.setColor(255, 255, 255) 401 | love.graphics.line(cursorx, console.y + console.h + console.lineHeight -5, cursorx, console.y + console.h +5) 402 | end 403 | 404 | 405 | -- rollback 406 | love.graphics.setCanvas(canvas) 407 | love.graphics.pop() 408 | love.graphics.setFont(font) 409 | love.graphics.setColor(r, g, b, a) 410 | love.graphics.setBlendMode(blend) 411 | love.graphics.setColorMask(cr, cg, cb, ca) 412 | love.graphics.setScissor(sx, sy, sw, sh) 413 | end 414 | 415 | function console.mousepressed( x, y, button ) 416 | if not console.visible then 417 | return false 418 | end 419 | 420 | if not (x >= console.x and x <= (console.x + console.w)) then 421 | return false 422 | end 423 | 424 | if not (y >= console.y and y <= (console.y + console.h + console.lineHeight)) then 425 | return false 426 | end 427 | 428 | local consumed = false 429 | 430 | if button == "wu" then 431 | console.firstLine = math.max(0, console.firstLine - 1) 432 | consumed = true 433 | end 434 | 435 | if button == "wd" then 436 | console.firstLine = math.min(#console.logs - console.linesPerConsole, console.firstLine + 1) 437 | consumed = true 438 | end 439 | console.lastLine = console.firstLine + console.linesPerConsole 440 | 441 | return consumed 442 | end 443 | 444 | function console.d(str) 445 | if console.levels.debug then 446 | a(str, 'D') 447 | end 448 | end 449 | 450 | function console.i(str) 451 | if console.levels.info then 452 | a(str, 'I') 453 | end 454 | end 455 | 456 | function console.e(str) 457 | if console.levels.error then 458 | a(str, 'E') 459 | end 460 | end 461 | 462 | function console.clearCommand(name) 463 | console.commands[name] = nil 464 | end 465 | 466 | function console.defineCommand(name, description, implementation, hidden) 467 | console.commands[name] = { 468 | description = description, 469 | implementation = implementation, 470 | hidden = hidden or false 471 | } 472 | end 473 | 474 | -- private stuff 475 | 476 | console.defineCommand( 477 | "help", 478 | "Shows information on all commands.", 479 | function () 480 | console.i("Available commands are:") 481 | for name,data in pairs(console.commands) do 482 | if not data.hidden then 483 | console.i(string.format(" %s - %s", name, data.description)) 484 | end 485 | end 486 | end 487 | ) 488 | 489 | console.defineCommand( 490 | "quit", 491 | "Quits your application.", 492 | function () love.event.quit() end 493 | ) 494 | 495 | console.defineCommand( 496 | "clear", 497 | "Clears the console.", 498 | function () 499 | console.firstLine = 0 500 | console.lastLine = 0 501 | console.logs = {} 502 | end 503 | ) 504 | --THIS IS A REALLY DANGEROUS FUNCTION, REMOVE IT IF YOU DONT NEED IT 505 | console.defineCommand( 506 | "lua", 507 | "Lets you run lua code from the terminal", 508 | function(...) 509 | local cmd = "" 510 | for i = 1, select("#", ...) do 511 | cmd = cmd .. tostring(select(i, ...)) .. " " 512 | end 513 | if cmd == "" then 514 | console.i("This command lets you run lua code from the terminal.") 515 | console.i("It's a really dangerous command. Don't use it!") 516 | return 517 | end 518 | xpcall(loadstring(cmd), console.e) 519 | end, 520 | true 521 | ) 522 | 523 | console.defineCommand( 524 | "motd", 525 | "Shows/sets the intro message.", 526 | function(motd) 527 | if motd then 528 | console.motd = motd 529 | console.i("Motd updated.") 530 | else 531 | console.i(console.motd) 532 | end 533 | end 534 | ) 535 | 536 | console.defineCommand( 537 | "flush", 538 | "Flush console history to disk", 539 | function(file) 540 | if file then 541 | local t = love.timer.getTime() 542 | 543 | love.filesystem.write(file, "") 544 | local buffer = "" 545 | local lines = 0 546 | for _, v in ipairs(console.logs) do 547 | buffer = buffer .. v.msg .. "\n" 548 | lines = lines + 1 549 | if lines >= 2048 then 550 | love.filesystem.append(file, buffer) 551 | lines = 0 552 | buffer = "" 553 | end 554 | end 555 | love.filesystem.append(file, buffer) 556 | 557 | t = love.timer.getTime() - t 558 | console.i(string.format("Successfully flushed console logs to \"%s\" in %fs.", love.filesystem.getSaveDirectory() .. "/" .. file, t)) 559 | else 560 | console.e("Usage: flush ") 561 | end 562 | end 563 | ) 564 | 565 | function console.invokeCommand(name, ...) 566 | local args = {...} 567 | if console.commands[name] ~= nil then 568 | local status, error = pcall(function() 569 | console.commands[name].implementation(unpack(args)) 570 | end) 571 | if not status then 572 | console.e(error) 573 | console.e(debug.traceback()) 574 | end 575 | else 576 | console.e("Command \"" .. name .. "\" not supported, type help for help.") 577 | end 578 | end 579 | 580 | function console.defaultInputCallback(input) 581 | local commands = string_split(input, ";") 582 | 583 | for _, line in ipairs(commands) do 584 | local args = merge_quoted(string_split(trim(line), " ")) 585 | local name = args[1] 586 | table.remove(args, 1) 587 | console.invokeCommand(name, unpack(merge_quoted(args))) 588 | end 589 | end 590 | 591 | function a(str, level) 592 | str = tostring(str) 593 | for _, str in ipairs(string_split(str, "\n")) do 594 | table.insert(console.logs, #console.logs + 1, {level = level, msg = string.format("%07.02f [".. level .. "] %s", console.delta, str)}) 595 | console.lastLine = totalLines() 596 | console.firstLine = console.lastLine - console.linesPerConsole 597 | -- print(console.logs[console.lastLine].msg) 598 | end 599 | end 600 | 601 | -- auto-initialize so that console.load() is optional 602 | console.load() 603 | console.i(console.motd) 604 | 605 | return console 606 | -------------------------------------------------------------------------------- /inconsolata/Inconsolata.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamsterready/love-console/3eb23bf2c932f6ec199dd54ad89c4ab142243209/inconsolata/Inconsolata.otf -------------------------------------------------------------------------------- /inconsolata/OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Raph Levien (firstname.lastname@gmail.com), Copyright (c) 2012, Cyreal (cyreal.org) 2 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 3 | This license is copied below, and is also available with a FAQ at: 4 | http://scripts.sil.org/OFL 5 | 6 | 7 | ----------------------------------------------------------- 8 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 9 | ----------------------------------------------------------- 10 | 11 | PREAMBLE 12 | The goals of the Open Font License (OFL) are to stimulate worldwide 13 | development of collaborative font projects, to support the font creation 14 | efforts of academic and linguistic communities, and to provide a free and 15 | open framework in which fonts may be shared and improved in partnership 16 | with others. 17 | 18 | The OFL allows the licensed fonts to be used, studied, modified and 19 | redistributed freely as long as they are not sold by themselves. The 20 | fonts, including any derivative works, can be bundled, embedded, 21 | redistributed and/or sold with any software provided that any reserved 22 | names are not used by derivative works. The fonts and derivatives, 23 | however, cannot be released under any other type of license. The 24 | requirement for fonts to remain under this license does not apply 25 | to any document created using the fonts or their derivatives. 26 | 27 | DEFINITIONS 28 | "Font Software" refers to the set of files released by the Copyright 29 | Holder(s) under this license and clearly marked as such. This may 30 | include source files, build scripts and documentation. 31 | 32 | "Reserved Font Name" refers to any names specified as such after the 33 | copyright statement(s). 34 | 35 | "Original Version" refers to the collection of Font Software components as 36 | distributed by the Copyright Holder(s). 37 | 38 | "Modified Version" refers to any derivative made by adding to, deleting, 39 | or substituting -- in part or in whole -- any of the components of the 40 | Original Version, by changing formats or by porting the Font Software to a 41 | new environment. 42 | 43 | "Author" refers to any designer, engineer, programmer, technical 44 | writer or other person who contributed to the Font Software. 45 | 46 | PERMISSION & CONDITIONS 47 | Permission is hereby granted, free of charge, to any person obtaining 48 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 49 | redistribute, and sell modified and unmodified copies of the Font 50 | Software, subject to the following conditions: 51 | 52 | 1) Neither the Font Software nor any of its individual components, 53 | in Original or Modified Versions, may be sold by itself. 54 | 55 | 2) Original or Modified Versions of the Font Software may be bundled, 56 | redistributed and/or sold with any software, provided that each copy 57 | contains the above copyright notice and this license. These can be 58 | included either as stand-alone text files, human-readable headers or 59 | in the appropriate machine-readable metadata fields within text or 60 | binary files as long as those fields can be easily viewed by the user. 61 | 62 | 3) No Modified Version of the Font Software may use the Reserved Font 63 | Name(s) unless explicit written permission is granted by the corresponding 64 | Copyright Holder. This restriction only applies to the primary font name as 65 | presented to the users. 66 | 67 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 68 | Software shall not be used to promote, endorse or advertise any 69 | Modified Version, except to acknowledge the contribution(s) of the 70 | Copyright Holder(s) and the Author(s) or with their explicit written 71 | permission. 72 | 73 | 5) The Font Software, modified or unmodified, in part or in whole, 74 | must be distributed entirely under this license, and must not be 75 | distributed under any other license. The requirement for fonts to 76 | remain under this license does not apply to any document created 77 | using the Font Software. 78 | 79 | TERMINATION 80 | This license becomes null and void if any of the above conditions are 81 | not met. 82 | 83 | DISCLAIMER 84 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 85 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 86 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 87 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 88 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 89 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 90 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 91 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 92 | OTHER DEALINGS IN THE FONT SOFTWARE. 93 | -------------------------------------------------------------------------------- /main.lua: -------------------------------------------------------------------------------- 1 | local console = require 'console' 2 | 3 | function love.load() 4 | -- Step 1: load console, parameters are optional, defaults enumerated below 5 | -- The key to open/close console == ` 6 | -- font size == 14 7 | -- false = no key repeat by default, pressing (and not releasing backspace) will act in a strange way 8 | -- nil == function called when user press return, see console.lua and defaultInputCallback function 9 | 10 | -- It is fine not to run console.load() 11 | console.load(love.graphics.newFont("inconsolata/Inconsolata.otf", 16)) 12 | 13 | console.defineCommand( -- How to create a custom command 14 | "hello", 15 | "Print 'Hello World'.", 16 | function() 17 | console.i("Hello World!!!") 18 | end 19 | ) 20 | 21 | console.defineCommand( -- Custom command tree 22 | "test", 23 | "test arguements", 24 | function(...) 25 | local cmd = {} 26 | for i = 1, select("#", ...) do 27 | cmd[i] = tostring(select(i, ...)) 28 | end 29 | 30 | if cmd[1] == "help" then 31 | console.i("* How to use multiple custom args.") 32 | console.i("* Commands:") 33 | console.i("test one") 34 | console.i("test two") 35 | console.i("test three alpha") 36 | console.i("test three bravo [msg]") 37 | return 38 | 39 | elseif cmd[1] == "one" then 40 | console.d("one") 41 | return 42 | 43 | elseif cmd[1] == "two" then 44 | console.d("two") 45 | return 46 | 47 | elseif cmd[1] == "three" then 48 | if cmd[2] == "alpha" then 49 | console.d("three alpha") 50 | elseif cmd[2] == "bravo" then 51 | if cmd[3] then 52 | console.d("three bravo " .. cmd[3]) 53 | else 54 | console.e("Wrong Syntax!") 55 | end 56 | else 57 | console.e("Wrong Syntax!") 58 | end 59 | return 60 | else 61 | console.e("Wrong Syntax!") 62 | end 63 | end, 64 | true 65 | ) 66 | end 67 | 68 | function love.update( dt ) 69 | -- Step 2: Make sure that you update console with dt 70 | console.update(dt) 71 | 72 | -- Use it console.i(msg), console.d(msg), console.e(msg) 73 | -- if somethingHappend then 74 | -- console.i("Something ...") 75 | -- end 76 | end 77 | 78 | function love.draw() 79 | drawGrid() 80 | 81 | -- Step 3: draw console last inside the 'love.draw' function 82 | console.draw() 83 | end 84 | 85 | function love.keypressed(key) 86 | -- Step 4: let console consume keys so that it can open and close (default `) and consume user input while open 87 | if console.keypressed(key) then 88 | return 89 | end 90 | 91 | if key == "escape" then 92 | love.event.quit() 93 | end 94 | end 95 | 96 | function love.textinput(t) 97 | console.textinput(t) 98 | end 99 | 100 | function love.resize( w, h ) 101 | -- Step 5: If your application allows a resize-able window, then call console.resize on love.resize 102 | console.resize(w, h) 103 | end 104 | 105 | 106 | function love.mousepressed(x, y, button) 107 | -- Step 6: When the console is open, the mouse scrolls the console text 108 | if console.mousepressed(x, y, button) then 109 | return 110 | end 111 | 112 | end 113 | 114 | 115 | function drawGrid( ) 116 | for i =0, math.floor(1920/100) do 117 | for j=0, math.floor(1080/100) do 118 | if (i + j) % 2 == 0 then 119 | love.graphics.setColor(255/255, 255/255, 255/255, 200/255) 120 | else 121 | love.graphics.setColor(255/255, 255/255, 255/255, 220/255) 122 | end 123 | love.graphics.rectangle("fill", i*100, j*100, 100, 100) 124 | end 125 | end 126 | end 127 | -------------------------------------------------------------------------------- /shot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamsterready/love-console/3eb23bf2c932f6ec199dd54ad89c4ab142243209/shot.png --------------------------------------------------------------------------------