Operating system for OpenComputers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

270 lines
6.7KB

  1. local ed = package.loaded.ed or {}
  2. ed.bfunc = ed.bfunc or {}
  3. ed.ifunc = ed.ifunc or setmetatable({},{__index=ed.bfunc})
  4. ed.buffers = ed.buffers or {}
  5. function ed.bfunc:load(fpath)
  6. local f = io.open(fpath,"rb")
  7. if not f then return false, "unable to open file" end
  8. for line in f:lines() do
  9. self[#self+1] = line
  10. end
  11. f:close()
  12. self.path = fpath
  13. return true, #self
  14. end
  15. function ed.bfunc:save(fpath)
  16. local path = fpath or self.path
  17. if not path then return false, "no path" end
  18. self.path = path
  19. local f = io.open(path,"wb")
  20. if not f then return false, "unable to open file" end
  21. for k,v in ipairs(self) do
  22. f:write(v.."\n")
  23. end
  24. f:close()
  25. self.dirty = false
  26. return true
  27. end
  28. function ed.bfunc:close(discard)
  29. if not discard and self.dirty then
  30. local saved = self:save()
  31. if not saved then return false, "unable to save buffer" end
  32. end
  33. for k,v in pairs(ed.buffers) do
  34. if v == self then
  35. table.remove(ed.buffers,k)
  36. return true
  37. end
  38. end
  39. return false, "unable to find buffer handle"
  40. end
  41. function ed.bfunc:range(start,finish)
  42. start, finish = math.max(1,tonumber(start) or 1), math.min(#self,tonumber(finish) or #self)
  43. local rt = {}
  44. for i = start, finish do
  45. rt[#rt+1] = self[i]
  46. end
  47. return rt
  48. end
  49. function ed.bfunc:checkCursor()
  50. self.y = math.max(self.y,1)
  51. self.y = math.min(self.y,#self)
  52. self.x = math.max(self.x,1)
  53. self.x = math.min(self.x,math.max(self[self.y]:len()+1,1))
  54. end
  55. function ed.ifunc.buffers()
  56. for k,v in pairs(ed.buffers) do
  57. print(string.format("\27[31m%4i\27[0m %s",k,v.path or "?"))
  58. end
  59. end
  60. function ed.ifunc.help()
  61. print("Available commands:")
  62. for k,v in pairs(ed.bfunc) do
  63. print(k)
  64. end
  65. for k,v in pairs(ed.ifunc) do
  66. print(k)
  67. end
  68. end
  69. function ed.ifunc:list(start,finish)
  70. start, finish = math.max(1,tonumber(start) or 1), math.min(#self,tonumber(finish) or #self)
  71. local lt = self:range(start,finish)
  72. for k,v in pairs(lt) do
  73. print(string.format("\27[31m%4d\27[0m %s",k+start-1,v))
  74. end
  75. end
  76. function ed.ifunc:insert(p,o)
  77. ed.ifunc.pointer(self,p)
  78. while true do
  79. io.write(string.format("\27[31m%4d\27[0m ",self.y + (o or 0)))
  80. local line = io.read()
  81. if line == "." then break end
  82. table.insert(self,self.y + (o or 0),line)
  83. self.dirty = true
  84. self.y = self.y + 1
  85. end
  86. end
  87. function ed.ifunc:append(p)
  88. ed.ifunc.insert(self,p,1)
  89. end
  90. function ed.ifunc:pointer(n)
  91. self.y = math.max(1,tonumber(n) or 1)
  92. self.y = math.min(#self,self.y)
  93. print(self.y)
  94. end
  95. function ed.newBuffer()
  96. local nb = setmetatable({},{__index=ed.bfunc})
  97. nb.x,nb.y = 1, 1
  98. ed.buffers[#ed.buffers+1] = nb
  99. return nb
  100. end
  101. function ed.open(buffer)
  102. local bpath = buffer
  103. if ed.buffers[buffer] then
  104. buffer = ed.buffers[buffer]
  105. end
  106. if type(buffer) == "string" then
  107. nb = ed.newBuffer()
  108. nb:load(buffer)
  109. buffer = nb
  110. end
  111. if type(buffer) ~= "table" then buffer = ed.newBuffer() end
  112. buffer[1] = buffer[1] or ""
  113. buffer.path = buffer.path or "/"..((bpath:sub(1,1) == "/" and table.concat(fs.segments(path),"/")) or table.concat(fs.segments(os.getenv("PWD").."/"..bpath),"/"))
  114. return buffer
  115. end
  116. function ed.interactive(buffer)
  117. buffer=ed.open(buffer)
  118. while true do
  119. io.write("\27[34mced:\27[0m ")
  120. local line = io.read()
  121. local words = {}
  122. for word in line:gmatch("[^%s]+") do
  123. words[#words+1] = word
  124. end
  125. local cmd = table.remove(words,1)
  126. if ed.ifunc[cmd] then
  127. print(ed.ifunc[cmd](buffer,table.unpack(words)))
  128. elseif cmd == "quit" then
  129. break
  130. else
  131. print("Unknown command.")
  132. end
  133. if cmd == "close" then
  134. break
  135. end
  136. end
  137. end
  138. function ed.visual(buffer)
  139. buffer=ed.open(buffer)
  140. local mx, my = 40, 13
  141. local cx,cy = math.max(1,buffer.x-mx//2), math.max(1,buffer.y-my//2)
  142. local ox, oy
  143. local mode = "c"
  144. local mult, multstr = 1, ""
  145. local resized = false
  146. io.write("\27[999;999H\27[6n")
  147. local function drawBuffer(force)
  148. if cx ~= ox or cy ~= oy or force then
  149. io.write("\27[2J\27[H")
  150. for i = cy, cy+my do
  151. print(string.format("\27[31m%4i \27[0m%s",i,(buffer[i] or "\27[36m~"):sub(cx,cx+mx-6)))
  152. end
  153. elseif mode == "i" then
  154. print(string.format("\27[2K\27[999D\27[31m%4i \27[0m%s",buffer.y,(buffer[buffer.y] or "\27[36m~"):sub(cx,cx+mx-6)))
  155. end
  156. io.write(string.format("\27[1;%iH\27[0;36;%im\27[2K[%s] ced visual: %i,%i/%i, %iK free %i",my+2,(mode == "c" and 7) or 0, mode, buffer.x, buffer.y, #buffer, computer.freeMemory()//1024,mult))
  157. io.write(string.format("\27[%i;%iH\27[0m",buffer.x+6-cx,buffer.y-cy+1))
  158. end
  159. os.setTimeout(0.0005)
  160. while true do
  161. drawBuffer()
  162. ox, oy = cx, cy
  163. io.write("\27[100;101m")
  164. local c=io.read(1)
  165. if c == "\27" then
  166. local b = ""
  167. repeat
  168. c=io.read(1)
  169. b=b..c
  170. until c:match("%a")
  171. dprint(b)
  172. local nx, ny = b:match("%[(%d+);(%d+)")
  173. if nx and ny then
  174. mx, my = math.max(mx, tonumber(nx)), math.max(my, tonumber(ny)-2)
  175. drawBuffer(true)
  176. end
  177. end
  178. if mode == "c" then
  179. if c == "q" then
  180. io.write("\27[0m\27[2J\27[H")
  181. break
  182. elseif c == "h" then
  183. buffer.x = buffer.x - mult
  184. elseif c == "l" then
  185. buffer.x = buffer.x + mult
  186. elseif c == "j" then
  187. buffer.y = buffer.y + mult
  188. elseif c == "k" then
  189. buffer.y = buffer.y - mult
  190. elseif c == "d" then
  191. for i = 1, mult do
  192. table.remove(buffer,buffer.y)
  193. end
  194. drawBuffer(true)
  195. elseif c == "i" or c == "\t" then
  196. mode = "i"
  197. elseif c == "a" then
  198. buffer.x = buffer.x + 1
  199. mode = "i"
  200. elseif c == ":" then
  201. io.write("\27[1;999H\27[2K")
  202. ed.interactive(buffer)
  203. drawBuffer(true)
  204. elseif c == "w" then
  205. buffer:save()
  206. elseif c:match("%d") then
  207. multstr = multstr .. c
  208. mult = tonumber(multstr)
  209. end
  210. if c:match("%D") then
  211. multstr = ""
  212. mult = 1
  213. end
  214. else
  215. if c == "\t" then
  216. mode = "c"
  217. elseif c == "\8" and buffer.x == 1 and buffer.y > 1 then
  218. local lblen = buffer[buffer.y-1]:len()
  219. buffer[buffer.y-1] = buffer[buffer.y-1] .. table.remove(buffer,buffer.y)
  220. buffer.x, buffer.y = lblen+1, buffer.y - 1
  221. drawBuffer(true)
  222. elseif c == "\8" then
  223. buffer[buffer.y] = buffer[buffer.y]:sub(1,buffer.x - 2)..buffer[buffer.y]:sub(buffer.x)
  224. buffer.x = buffer.x - 1
  225. else
  226. buffer[buffer.y] = buffer[buffer.y]:sub(1,buffer.x-1)..c..buffer[buffer.y]:sub(buffer.x)
  227. buffer.x = buffer.x + 1
  228. local fh,sh = buffer[buffer.y]:match("(.*)\n(.*)")
  229. if fh and sh then
  230. buffer[buffer.y] = fh
  231. table.insert(buffer,buffer.y+1,sh)
  232. buffer.x, buffer.y = 1, buffer.y + 1
  233. drawBuffer(true)
  234. end
  235. end
  236. end
  237. buffer:checkCursor()
  238. local ax, amx = buffer.x + 5, mx - 5
  239. if cy + my < buffer.y + 3 then
  240. cy = math.min(#buffer-my,buffer.y + 6 - my)
  241. end
  242. if cy + 3 > buffer.y then
  243. cy = math.max(1,buffer.y - 6)
  244. end
  245. if buffer.x + 5 > cx + mx - 4 then
  246. cx = math.max(1,(buffer.x + 6) - (mx - 6))
  247. end
  248. if buffer.x < cx + 3 then
  249. cx = math.max(1,buffer.x - 6)
  250. end
  251. end
  252. end
  253. return ed