PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/lib_pypy/pyrepl/commands.py

https://bitbucket.org/dac_io/pypy
Python | 384 lines | 308 code | 43 blank | 33 comment | 54 complexity | 15b4b5c8a923c618e6b48fa9b5adcb2a MD5 | raw file
  1. # Copyright 2000-2010 Michael Hudson-Doyle <micahel@gmail.com>
  2. # Antonio Cuni
  3. # Armin Rigo
  4. #
  5. # All Rights Reserved
  6. #
  7. #
  8. # Permission to use, copy, modify, and distribute this software and
  9. # its documentation for any purpose is hereby granted without fee,
  10. # provided that the above copyright notice appear in all copies and
  11. # that both that copyright notice and this permission notice appear in
  12. # supporting documentation.
  13. #
  14. # THE AUTHOR MICHAEL HUDSON DISCLAIMS ALL WARRANTIES WITH REGARD TO
  15. # THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  16. # AND FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
  17. # INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  18. # RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
  19. # CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  20. # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21. import sys, os
  22. # Catgories of actions:
  23. # killing
  24. # yanking
  25. # motion
  26. # editing
  27. # history
  28. # finishing
  29. # [completion]
  30. class Command(object):
  31. finish = 0
  32. kills_digit_arg = 1
  33. def __init__(self, reader, cmd):
  34. self.reader = reader
  35. self.event_name, self.event = cmd
  36. def do(self):
  37. pass
  38. class KillCommand(Command):
  39. def kill_range(self, start, end):
  40. if start == end:
  41. return
  42. r = self.reader
  43. b = r.buffer
  44. text = b[start:end]
  45. del b[start:end]
  46. if is_kill(r.last_command):
  47. if start < r.pos:
  48. r.kill_ring[-1] = text + r.kill_ring[-1]
  49. else:
  50. r.kill_ring[-1] = r.kill_ring[-1] + text
  51. else:
  52. r.kill_ring.append(text)
  53. r.pos = start
  54. r.dirty = 1
  55. class YankCommand(Command):
  56. pass
  57. class MotionCommand(Command):
  58. pass
  59. class EditCommand(Command):
  60. pass
  61. class FinishCommand(Command):
  62. finish = 1
  63. pass
  64. def is_kill(command):
  65. return command and issubclass(command, KillCommand)
  66. def is_yank(command):
  67. return command and issubclass(command, YankCommand)
  68. # etc
  69. class digit_arg(Command):
  70. kills_digit_arg = 0
  71. def do(self):
  72. r = self.reader
  73. c = self.event[-1]
  74. if c == "-":
  75. if r.arg is not None:
  76. r.arg = -r.arg
  77. else:
  78. r.arg = -1
  79. else:
  80. d = int(c)
  81. if r.arg is None:
  82. r.arg = d
  83. else:
  84. if r.arg < 0:
  85. r.arg = 10*r.arg - d
  86. else:
  87. r.arg = 10*r.arg + d
  88. r.dirty = 1
  89. class clear_screen(Command):
  90. def do(self):
  91. r = self.reader
  92. r.console.clear()
  93. r.dirty = 1
  94. class refresh(Command):
  95. def do(self):
  96. self.reader.dirty = 1
  97. class repaint(Command):
  98. def do(self):
  99. self.reader.dirty = 1
  100. self.reader.console.repaint_prep()
  101. class kill_line(KillCommand):
  102. def do(self):
  103. r = self.reader
  104. b = r.buffer
  105. eol = r.eol()
  106. for c in b[r.pos:eol]:
  107. if not c.isspace():
  108. self.kill_range(r.pos, eol)
  109. return
  110. else:
  111. self.kill_range(r.pos, eol+1)
  112. class unix_line_discard(KillCommand):
  113. def do(self):
  114. r = self.reader
  115. self.kill_range(r.bol(), r.pos)
  116. # XXX unix_word_rubout and backward_kill_word should actually
  117. # do different things...
  118. class unix_word_rubout(KillCommand):
  119. def do(self):
  120. r = self.reader
  121. for i in range(r.get_arg()):
  122. self.kill_range(r.bow(), r.pos)
  123. class kill_word(KillCommand):
  124. def do(self):
  125. r = self.reader
  126. for i in range(r.get_arg()):
  127. self.kill_range(r.pos, r.eow())
  128. class backward_kill_word(KillCommand):
  129. def do(self):
  130. r = self.reader
  131. for i in range(r.get_arg()):
  132. self.kill_range(r.bow(), r.pos)
  133. class yank(YankCommand):
  134. def do(self):
  135. r = self.reader
  136. if not r.kill_ring:
  137. r.error("nothing to yank")
  138. return
  139. r.insert(r.kill_ring[-1])
  140. class yank_pop(YankCommand):
  141. def do(self):
  142. r = self.reader
  143. b = r.buffer
  144. if not r.kill_ring:
  145. r.error("nothing to yank")
  146. return
  147. if not is_yank(r.last_command):
  148. r.error("previous command was not a yank")
  149. return
  150. repl = len(r.kill_ring[-1])
  151. r.kill_ring.insert(0, r.kill_ring.pop())
  152. t = r.kill_ring[-1]
  153. b[r.pos - repl:r.pos] = t
  154. r.pos = r.pos - repl + len(t)
  155. r.dirty = 1
  156. class interrupt(FinishCommand):
  157. def do(self):
  158. import signal
  159. self.reader.console.finish()
  160. os.kill(os.getpid(), signal.SIGINT)
  161. class suspend(Command):
  162. def do(self):
  163. import signal
  164. r = self.reader
  165. p = r.pos
  166. r.console.finish()
  167. os.kill(os.getpid(), signal.SIGSTOP)
  168. ## this should probably be done
  169. ## in a handler for SIGCONT?
  170. r.console.prepare()
  171. r.pos = p
  172. r.posxy = 0, 0
  173. r.dirty = 1
  174. r.console.screen = []
  175. class up(MotionCommand):
  176. def do(self):
  177. r = self.reader
  178. for i in range(r.get_arg()):
  179. bol1 = r.bol()
  180. if bol1 == 0:
  181. if r.historyi > 0:
  182. r.select_item(r.historyi - 1)
  183. return
  184. r.pos = 0
  185. r.error("start of buffer")
  186. return
  187. bol2 = r.bol(bol1-1)
  188. line_pos = r.pos - bol1
  189. if line_pos > bol1 - bol2 - 1:
  190. r.sticky_y = line_pos
  191. r.pos = bol1 - 1
  192. else:
  193. r.pos = bol2 + line_pos
  194. class down(MotionCommand):
  195. def do(self):
  196. r = self.reader
  197. b = r.buffer
  198. for i in range(r.get_arg()):
  199. bol1 = r.bol()
  200. eol1 = r.eol()
  201. if eol1 == len(b):
  202. if r.historyi < len(r.history):
  203. r.select_item(r.historyi + 1)
  204. r.pos = r.eol(0)
  205. return
  206. r.pos = len(b)
  207. r.error("end of buffer")
  208. return
  209. eol2 = r.eol(eol1+1)
  210. if r.pos - bol1 > eol2 - eol1 - 1:
  211. r.pos = eol2
  212. else:
  213. r.pos = eol1 + (r.pos - bol1) + 1
  214. class left(MotionCommand):
  215. def do(self):
  216. r = self.reader
  217. for i in range(r.get_arg()):
  218. p = r.pos - 1
  219. if p >= 0:
  220. r.pos = p
  221. else:
  222. self.reader.error("start of buffer")
  223. class right(MotionCommand):
  224. def do(self):
  225. r = self.reader
  226. b = r.buffer
  227. for i in range(r.get_arg()):
  228. p = r.pos + 1
  229. if p <= len(b):
  230. r.pos = p
  231. else:
  232. self.reader.error("end of buffer")
  233. class beginning_of_line(MotionCommand):
  234. def do(self):
  235. self.reader.pos = self.reader.bol()
  236. class end_of_line(MotionCommand):
  237. def do(self):
  238. r = self.reader
  239. self.reader.pos = self.reader.eol()
  240. class home(MotionCommand):
  241. def do(self):
  242. self.reader.pos = 0
  243. class end(MotionCommand):
  244. def do(self):
  245. self.reader.pos = len(self.reader.buffer)
  246. class forward_word(MotionCommand):
  247. def do(self):
  248. r = self.reader
  249. for i in range(r.get_arg()):
  250. r.pos = r.eow()
  251. class backward_word(MotionCommand):
  252. def do(self):
  253. r = self.reader
  254. for i in range(r.get_arg()):
  255. r.pos = r.bow()
  256. class self_insert(EditCommand):
  257. def do(self):
  258. r = self.reader
  259. r.insert(self.event * r.get_arg())
  260. class insert_nl(EditCommand):
  261. def do(self):
  262. r = self.reader
  263. r.insert("\n" * r.get_arg())
  264. class transpose_characters(EditCommand):
  265. def do(self):
  266. r = self.reader
  267. b = r.buffer
  268. s = r.pos - 1
  269. if s < 0:
  270. r.error("cannot transpose at start of buffer")
  271. else:
  272. if s == len(b):
  273. s -= 1
  274. t = min(s + r.get_arg(), len(b) - 1)
  275. c = b[s]
  276. del b[s]
  277. b.insert(t, c)
  278. r.pos = t
  279. r.dirty = 1
  280. class backspace(EditCommand):
  281. def do(self):
  282. r = self.reader
  283. b = r.buffer
  284. for i in range(r.get_arg()):
  285. if r.pos > 0:
  286. r.pos -= 1
  287. del b[r.pos]
  288. r.dirty = 1
  289. else:
  290. self.reader.error("can't backspace at start")
  291. class delete(EditCommand):
  292. def do(self):
  293. r = self.reader
  294. b = r.buffer
  295. if ( r.pos == 0 and len(b) == 0 # this is something of a hack
  296. and self.event[-1] == "\004"):
  297. r.update_screen()
  298. r.console.finish()
  299. raise EOFError
  300. for i in range(r.get_arg()):
  301. if r.pos != len(b):
  302. del b[r.pos]
  303. r.dirty = 1
  304. else:
  305. self.reader.error("end of buffer")
  306. class accept(FinishCommand):
  307. def do(self):
  308. pass
  309. class help(Command):
  310. def do(self):
  311. self.reader.msg = self.reader.help_text
  312. self.reader.dirty = 1
  313. class invalid_key(Command):
  314. def do(self):
  315. pending = self.reader.console.getpending()
  316. s = ''.join(self.event) + pending.data
  317. self.reader.error("`%r' not bound"%s)
  318. class invalid_command(Command):
  319. def do(self):
  320. s = self.event_name
  321. self.reader.error("command `%s' not known"%s)
  322. class qIHelp(Command):
  323. def do(self):
  324. r = self.reader
  325. r.insert((self.event + r.console.getpending().data) * r.get_arg())
  326. r.pop_input_trans()
  327. from pyrepl import input
  328. class QITrans(object):
  329. def push(self, evt):
  330. self.evt = evt
  331. def get(self):
  332. return ('qIHelp', self.evt.raw)
  333. class quoted_insert(Command):
  334. kills_digit_arg = 0
  335. def do(self):
  336. self.reader.push_input_trans(QITrans())