terminal.lua 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. local lume = require("libraries.lume")
  2. local Terminal = {}
  3. Terminal.blinktime = 0.5
  4. Terminal.blinktimer = 0
  5. Terminal.blinkstate = false
  6. Terminal.textbuffer = {}
  7. Terminal.textcolors = {}
  8. Terminal.linesLimit = 14
  9. Terminal.lengthLimit = 43
  10. Terminal.currentLine = 1
  11. Terminal.cacheCommand = {}
  12. Terminal.cacheIndex = 0
  13. Terminal.cacheIndexIt = 0
  14. Terminal.rootDir = "/"
  15. function Terminal:wrap_string(str,ml)
  16. local ml = ml or (Terminal.lengthLimit-5)-(self.rootDir:len()+1)
  17. local lt = api.floor(str:len()/ml+0.99)
  18. if lt <= 1 then return {str} end
  19. local t = {}
  20. for i = 1, lt+1 do
  21. table.insert(t,str:sub(0,ml-1))
  22. str=str:sub(ml,-1)
  23. end
  24. return t
  25. end
  26. function Terminal:tout(text,col,skipnl,pathLen)
  27. local text = text or ""
  28. local length = pathLen and (Terminal.lengthLimit-5)-(self.rootDir:len()+1) or Terminal.lengthLimit
  29. for _,line in ipairs(lume.split(text, "\n")) do
  30. for _,wrapped_line in ipairs(self:wrap_string(line,length)) do
  31. self:tout_line(wrapped_line,col,skipnl)
  32. end
  33. end
  34. end
  35. function Terminal:tout_line(text,col,skipnl)
  36. self.textcolors[self.currentLine] = col or self.textcolors[self.currentLine]
  37. if skipnl then
  38. self.textbuffer[self.currentLine] = self.textbuffer[self.currentLine]..(text or "")
  39. if self.textbuffer[self.currentLine]:len() >= self.lengthLimit then self.textbuffer[self.currentLine] = self.textbuffer[self.currentLine]:sub(0,self.lengthLimit) end
  40. else
  41. self.textbuffer[self.currentLine] = self.textbuffer[self.currentLine]..(text or "")
  42. if self.textbuffer[self.currentLine]:len() >= self.lengthLimit then self.textbuffer[self.currentLine] = self.textbuffer[self.currentLine]:sub(0,self.lengthLimit) end
  43. if self.currentLine == self.linesLimit then
  44. for i=2,self.linesLimit do self.textbuffer[i-1] = self.textbuffer[i] end --Shiftup all the text
  45. for i=2,self.linesLimit do self.textcolors[i-1] = self.textcolors[i] end
  46. self.textbuffer[self.currentLine] = "" --Add a new line
  47. else
  48. self.currentLine = self.currentLine + 1
  49. end
  50. end
  51. self:_redraw()
  52. end
  53. function Terminal:setLine(l) self.currentLine = api.floor(l or 1) if self.currentLine > 20 then self.currentLine = 20 elseif self.currentLine < 1 then self.currentLine = 1 end end
  54. function Terminal:splitCommand(str)
  55. local t = {}
  56. for val in str:gmatch("%S+") do
  57. if not t[0] then t[0] = val else table.insert(t, val) end
  58. end
  59. return t
  60. end
  61. function Terminal:_init()
  62. for i=1,self.linesLimit do table.insert(self.textbuffer,"") end --Clean the framebuffer
  63. for i=1,self.linesLimit do table.insert(self.textcolors,8) end
  64. api.keyrepeat(true)
  65. self:tout("-[[liko12]]-")
  66. self:tout(_LK12VER,_LK12VERC)
  67. self:tout()
  68. self:tout("A PICO-8 CLONE WITH EXTRA ABILITIES",7)
  69. self:tout("TYPE HELP FOR HELP",10)
  70. self:tout(self.rootDir.."> ",8,true)
  71. end
  72. function Terminal:_update(dt)
  73. api.setCursor("point")
  74. self.blinktimer = self.blinktimer+dt if self.blinktimer > self.blinktime then self.blinktimer = self.blinktimer - self.blinktime self.blinkstate = not self.blinkstate end
  75. local curlen = self.textbuffer[self.currentLine]:len()
  76. api.color(self.blinkstate and 5 or 1)
  77. api.rect(curlen > 0 and ((curlen)*4+8+3) or 10,(self.currentLine)*8+2,4,5)
  78. end
  79. function Terminal:_redraw()
  80. api.clear(1)
  81. for line,text in ipairs(self.textbuffer) do
  82. api.color(self.textcolors[line])
  83. if text == "-[[liko12]]-" then --THE SECRET PHASE
  84. api.SpriteGroup(49,9,line*8,6,1,1,1,api.EditorSheet)
  85. else
  86. api.print_grid(text,2,line+1)
  87. end
  88. end
  89. end
  90. function Terminal:_kpress(k,sc,ir)
  91. if k == "return" then
  92. self:tout()
  93. local splitted = self:splitCommand(self.textbuffer[self.currentLine-1])
  94. local CMDFunc = require("terminal_commands")[string.lower(splitted[1] or "")]
  95. if CMDFunc then
  96. CMDFunc(unpack(splitted))
  97. elseif splitted[1] then
  98. self:tout("UNKNOWN COMMAND '"..splitted[1].."' !",15)
  99. end
  100. --Save the command in the command cache
  101. if splitted[1] ~= nil then --Only when it have something to save
  102. self.cacheIndex = self.cacheIndex + 1
  103. self.cacheCommand[self.cacheIndex] = splitted[1]
  104. self.cacheIndexIt = self.cacheIndex
  105. end
  106. self:tout(self.rootDir.."> ",8,true,true)
  107. end
  108. if k == "backspace" and self.textbuffer[self.currentLine]:len() > self.rootDir:len()+2 then self.textbuffer[self.currentLine] = self.textbuffer[self.currentLine]:sub(0,-2) self:_redraw() end
  109. if k == "up" then --Use the command cache
  110. self.textbuffer[self.currentLine] = self.rootDir.."> "
  111. self:_tinput(self.cacheCommand[self.cacheIndexIt])
  112. if self.cacheIndexIt > 1 then
  113. self.cacheIndexIt = self.cacheIndexIt - 1
  114. else
  115. self.cacheIndexIt = self.cacheIndex
  116. end
  117. end
  118. end
  119. function Terminal:_krelease(k,sc)
  120. --Try to autocomplete with files in the current folder
  121. if k == "tab" then
  122. local splitted = self:splitCommand(self.textbuffer[self.currentLine])
  123. local path = path or ""
  124. local curpath = path:sub(0,1) == "/" and path.."/" or self.rootDir..path.."/"
  125. local files = api.fs.dirItems(curpath)
  126. local exit = 0
  127. for fileKey,fileValue in ipairs(files) do
  128. self.textbuffer[self.currentLine] = self.rootDir.."> "
  129. for splittedKey,splittedValue in ipairs(splitted) do
  130. if string.find(fileValue, splittedValue) then
  131. self:_tinput(string.gsub(fileValue, ".lk12", ""))
  132. exit = 1
  133. break
  134. end
  135. if exit == 1 then break end
  136. self:_tinput(splittedValue)
  137. self:_tinput(" ")
  138. end
  139. if exit == 1 then break end
  140. end
  141. end
  142. end
  143. function Terminal:_tinput(t)
  144. if t == "\\" then return end --This thing is so bad, so GO AWAY
  145. if self.textbuffer[self.currentLine]:len() < self.lengthLimit then self:tout(t,8,true) end
  146. end
  147. function Terminal:_tpress()
  148. --This means the user is using a touch device
  149. self.linesLimit = 7
  150. api.showkeyboard(true)
  151. end
  152. function Terminal:setRoot(path)
  153. self.rootDir = path or "/"
  154. end
  155. return Terminal