m2m模型翻译
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.

563 lines
21 KiB

6 months ago
  1. # -*- coding: utf-8 -*-
  2. #*****************************************************************************
  3. # Copyright (C) 2003-2006 Gary Bishop.
  4. # Copyright (C) 2006 Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
  5. #
  6. # Distributed under the terms of the BSD License. The full license is in
  7. # the file COPYING, distributed as part of this software.
  8. #*****************************************************************************
  9. from __future__ import print_function, unicode_literals, absolute_import
  10. import os, re, math, glob, sys, time
  11. from pyreadline.py3k_compat import callable
  12. import pyreadline.logger as logger
  13. from pyreadline.logger import log
  14. from pyreadline.keysyms.common import make_KeyPress_from_keydescr
  15. import pyreadline.lineeditor.lineobj as lineobj
  16. import pyreadline.lineeditor.history as history
  17. import pyreadline.clipboard as clipboard
  18. from pyreadline.error import ReadlineError,GetSetError
  19. from pyreadline.unicode_helper import ensure_str, ensure_unicode
  20. in_ironpython = "IronPython" in sys.version
  21. class BaseMode(object):
  22. mode = "base"
  23. def __init__(self,rlobj):
  24. self.argument=0
  25. self.rlobj=rlobj
  26. self.exit_dispatch = {}
  27. self.key_dispatch = {}
  28. self.argument=1
  29. self.prevargument=None
  30. self.l_buffer=lineobj.ReadLineTextBuffer("")
  31. self._history=history.LineHistory()
  32. self.completer_delims = " \t\n\"\\'`@$><=;|&{("
  33. self.show_all_if_ambiguous = 'on'
  34. self.mark_directories = 'on'
  35. self.complete_filesystem = 'off'
  36. self.completer = None
  37. self.begidx = 0
  38. self.endidx = 0
  39. self.tabstop = 4
  40. self.startup_hook = None
  41. self.pre_input_hook = None
  42. self.first_prompt = True
  43. self.cursor_size=25
  44. self.prompt = ">>> "
  45. #Paste settings
  46. #assumes data on clipboard is path if shorter than 300 characters and doesn't contain \t or \n
  47. #and replace \ with / for easier use in ipython
  48. self.enable_ipython_paste_for_paths=True
  49. #automatically convert tabseparated data to list of lists or array constructors
  50. self.enable_ipython_paste_list_of_lists=True
  51. self.enable_win32_clipboard=True
  52. self.paste_line_buffer=[]
  53. self._sub_modes=[]
  54. def __repr__(self):
  55. return "<BaseMode>"
  56. def _gs(x):
  57. def g(self):
  58. return getattr(self.rlobj,x)
  59. def s(self,q):
  60. setattr(self.rlobj,x,q)
  61. return g,s
  62. def _g(x):
  63. def g(self):
  64. return getattr(self.rlobj,x)
  65. return g
  66. def _argreset(self):
  67. val=self.argument
  68. self.argument=0
  69. if val==0:
  70. val=1
  71. return val
  72. argument_reset=property(_argreset)
  73. #used in readline
  74. ctrl_c_tap_time_interval=property(*_gs("ctrl_c_tap_time_interval"))
  75. allow_ctrl_c=property(*_gs("allow_ctrl_c"))
  76. _print_prompt=property(_g("_print_prompt"))
  77. _update_line=property(_g("_update_line"))
  78. console=property(_g("console"))
  79. prompt_begin_pos=property(_g("prompt_begin_pos"))
  80. prompt_end_pos=property(_g("prompt_end_pos"))
  81. #used in completer _completions
  82. # completer_delims=property(*_gs("completer_delims"))
  83. _bell=property(_g("_bell"))
  84. bell_style=property(_g("bell_style"))
  85. #used in emacs
  86. _clear_after=property(_g("_clear_after"))
  87. _update_prompt_pos=property(_g("_update_prompt_pos"))
  88. #not used in basemode or emacs
  89. def process_keyevent(self, keyinfo):
  90. raise NotImplementedError
  91. def readline_setup(self, prompt=''):
  92. self.l_buffer.selection_mark=-1
  93. if self.first_prompt:
  94. self.first_prompt = False
  95. if self.startup_hook:
  96. try:
  97. self.startup_hook()
  98. except:
  99. print('startup hook failed')
  100. traceback.print_exc()
  101. self.l_buffer.reset_line()
  102. self.prompt = prompt
  103. if self.pre_input_hook:
  104. try:
  105. self.pre_input_hook()
  106. except:
  107. print('pre_input_hook failed')
  108. traceback.print_exc()
  109. self.pre_input_hook = None
  110. ####################################
  111. def finalize(self):
  112. """Every bindable command should call this function for cleanup.
  113. Except those that want to set argument to a non-zero value.
  114. """
  115. self.argument = 0
  116. def add_history(self, text):
  117. self._history.add_history(lineobj.ReadLineTextBuffer(text))
  118. #Create key bindings:
  119. def rl_settings_to_string(self):
  120. out=["%-20s: %s"%("show all if ambigous",self.show_all_if_ambiguous)]
  121. out.append("%-20s: %s"%("mark_directories",self.mark_directories))
  122. out.append("%-20s: %s"%("bell_style",self.bell_style))
  123. out.append("------------- key bindings ------------")
  124. tablepat="%-7s %-7s %-7s %-15s %-15s "
  125. out.append(tablepat%("Control","Meta","Shift","Keycode/char","Function"))
  126. bindings=[(k[0],k[1],k[2],k[3],v.__name__) for k,v in self.key_dispatch.items()]
  127. bindings.sort()
  128. for key in bindings:
  129. out.append(tablepat%(key))
  130. return out
  131. def _bind_key(self, key, func):
  132. """setup the mapping from key to call the function."""
  133. if not callable(func):
  134. print("Trying to bind non method to keystroke:%s,%s"%(key,func))
  135. raise ReadlineError("Trying to bind non method to keystroke:%s,%s,%s,%s"%(key,func,type(func),type(self._bind_key)))
  136. keyinfo = make_KeyPress_from_keydescr(key.lower()).tuple()
  137. log(">>>%s -> %s<<<"%(keyinfo,func.__name__))
  138. self.key_dispatch[keyinfo] = func
  139. def _bind_exit_key(self, key):
  140. """setup the mapping from key to call the function."""
  141. keyinfo = make_KeyPress_from_keydescr(key.lower()).tuple()
  142. self.exit_dispatch[keyinfo] = None
  143. def init_editing_mode(self, e): # (C-e)
  144. """When in vi command mode, this causes a switch to emacs editing
  145. mode."""
  146. raise NotImplementedError
  147. #completion commands
  148. def _get_completions(self):
  149. """Return a list of possible completions for the string ending at the point.
  150. Also set begidx and endidx in the process."""
  151. completions = []
  152. self.begidx = self.l_buffer.point
  153. self.endidx = self.l_buffer.point
  154. buf=self.l_buffer.line_buffer
  155. if self.completer:
  156. # get the string to complete
  157. while self.begidx > 0:
  158. self.begidx -= 1
  159. if buf[self.begidx] in self.completer_delims:
  160. self.begidx += 1
  161. break
  162. text = ensure_str(''.join(buf[self.begidx:self.endidx]))
  163. log('complete text="%s"' % ensure_unicode(text))
  164. i = 0
  165. while 1:
  166. try:
  167. r = self.completer(ensure_unicode(text), i)
  168. except IndexError:
  169. break
  170. i += 1
  171. if r is None:
  172. break
  173. elif r and r not in completions:
  174. completions.append(r)
  175. else:
  176. pass
  177. log('text completions=<%s>' % list(map(ensure_unicode, completions)))
  178. if (self.complete_filesystem == "on") and not completions:
  179. # get the filename to complete
  180. while self.begidx > 0:
  181. self.begidx -= 1
  182. if buf[self.begidx] in ' \t\n':
  183. self.begidx += 1
  184. break
  185. text = ensure_str(''.join(buf[self.begidx:self.endidx]))
  186. log('file complete text="%s"' % ensure_unicode(text))
  187. completions = list(map(ensure_unicode, glob.glob(os.path.expanduser(text) + '*'.encode('ascii'))))
  188. if self.mark_directories == 'on':
  189. mc = []
  190. for f in completions:
  191. if os.path.isdir(f):
  192. mc.append(f + os.sep)
  193. else:
  194. mc.append(f)
  195. completions = mc
  196. log('fnames=<%s>' % list(map(ensure_unicode, completions)))
  197. return completions
  198. def _display_completions(self, completions):
  199. if not completions:
  200. return
  201. self.console.write('\n')
  202. wmax = max(map(len, completions))
  203. w, h = self.console.size()
  204. cols = max(1, int((w-1) / (wmax+1)))
  205. rows = int(math.ceil(float(len(completions)) / cols))
  206. for row in range(rows):
  207. s = ''
  208. for col in range(cols):
  209. i = col*rows + row
  210. if i < len(completions):
  211. self.console.write(completions[i].ljust(wmax+1))
  212. self.console.write('\n')
  213. if in_ironpython:
  214. self.prompt=sys.ps1
  215. self._print_prompt()
  216. def complete(self, e): # (TAB)
  217. """Attempt to perform completion on the text before point. The
  218. actual completion performed is application-specific. The default is
  219. filename completion."""
  220. completions = self._get_completions()
  221. if completions:
  222. cprefix = commonprefix(completions)
  223. if len(cprefix) > 0:
  224. rep = [ c for c in cprefix ]
  225. point=self.l_buffer.point
  226. self.l_buffer[self.begidx:self.endidx] = rep
  227. self.l_buffer.point = point + len(rep) - (self.endidx - self.begidx)
  228. if len(completions) > 1:
  229. if self.show_all_if_ambiguous == 'on':
  230. self._display_completions(completions)
  231. else:
  232. self._bell()
  233. else:
  234. self._bell()
  235. self.finalize()
  236. def possible_completions(self, e): # (M-?)
  237. """List the possible completions of the text before point. """
  238. completions = self._get_completions()
  239. self._display_completions(completions)
  240. self.finalize()
  241. def insert_completions(self, e): # (M-*)
  242. """Insert all completions of the text before point that would have
  243. been generated by possible-completions."""
  244. completions = self._get_completions()
  245. b = self.begidx
  246. e = self.endidx
  247. for comp in completions:
  248. rep = [ c for c in comp ]
  249. rep.append(' ')
  250. self.l_buffer[b:e] = rep
  251. b += len(rep)
  252. e = b
  253. self.line_cursor = b
  254. self.finalize()
  255. def menu_complete(self, e): # ()
  256. """Similar to complete, but replaces the word to be completed with a
  257. single match from the list of possible completions. Repeated
  258. execution of menu-complete steps through the list of possible
  259. completions, inserting each match in turn. At the end of the list of
  260. completions, the bell is rung (subject to the setting of bell-style)
  261. and the original text is restored. An argument of n moves n
  262. positions forward in the list of matches; a negative argument may be
  263. used to move backward through the list. This command is intended to
  264. be bound to TAB, but is unbound by default."""
  265. self.finalize()
  266. ### Methods below here are bindable emacs functions
  267. def insert_text(self, string):
  268. """Insert text into the command line."""
  269. self.l_buffer.insert_text(string, self.argument_reset)
  270. self.finalize()
  271. def beginning_of_line(self, e): # (C-a)
  272. """Move to the start of the current line. """
  273. self.l_buffer.beginning_of_line()
  274. self.finalize()
  275. def end_of_line(self, e): # (C-e)
  276. """Move to the end of the line. """
  277. self.l_buffer.end_of_line()
  278. self.finalize()
  279. def forward_char(self, e): # (C-f)
  280. """Move forward a character. """
  281. self.l_buffer.forward_char(self.argument_reset)
  282. self.finalize()
  283. def backward_char(self, e): # (C-b)
  284. """Move back a character. """
  285. self.l_buffer.backward_char(self.argument_reset)
  286. self.finalize()
  287. def forward_word(self, e): # (M-f)
  288. """Move forward to the end of the next word. Words are composed of
  289. letters and digits."""
  290. self.l_buffer.forward_word(self.argument_reset)
  291. self.finalize()
  292. def backward_word(self, e): # (M-b)
  293. """Move back to the start of the current or previous word. Words are
  294. composed of letters and digits."""
  295. self.l_buffer.backward_word(self.argument_reset)
  296. self.finalize()
  297. def forward_word_end(self, e): # ()
  298. """Move forward to the end of the next word. Words are composed of
  299. letters and digits."""
  300. self.l_buffer.forward_word_end(self.argument_reset)
  301. self.finalize()
  302. def backward_word_end(self, e): # ()
  303. """Move forward to the end of the next word. Words are composed of
  304. letters and digits."""
  305. self.l_buffer.backward_word_end(self.argument_reset)
  306. self.finalize()
  307. ### Movement with extend selection
  308. def beginning_of_line_extend_selection(self, e): #
  309. """Move to the start of the current line. """
  310. self.l_buffer.beginning_of_line_extend_selection()
  311. self.finalize()
  312. def end_of_line_extend_selection(self, e): #
  313. """Move to the end of the line. """
  314. self.l_buffer.end_of_line_extend_selection()
  315. self.finalize()
  316. def forward_char_extend_selection(self, e): #
  317. """Move forward a character. """
  318. self.l_buffer.forward_char_extend_selection(self.argument_reset)
  319. self.finalize()
  320. def backward_char_extend_selection(self, e): #
  321. """Move back a character. """
  322. self.l_buffer.backward_char_extend_selection(self.argument_reset)
  323. self.finalize()
  324. def forward_word_extend_selection(self, e): #
  325. """Move forward to the end of the next word. Words are composed of
  326. letters and digits."""
  327. self.l_buffer.forward_word_extend_selection(self.argument_reset)
  328. self.finalize()
  329. def backward_word_extend_selection(self, e): #
  330. """Move back to the start of the current or previous word. Words are
  331. composed of letters and digits."""
  332. self.l_buffer.backward_word_extend_selection(self.argument_reset)
  333. self.finalize()
  334. def forward_word_end_extend_selection(self, e): #
  335. """Move forward to the end of the next word. Words are composed of
  336. letters and digits."""
  337. self.l_buffer.forward_word_end_extend_selection(self.argument_reset)
  338. self.finalize()
  339. def backward_word_end_extend_selection(self, e): #
  340. """Move forward to the end of the next word. Words are composed of
  341. letters and digits."""
  342. self.l_buffer.forward_word_end_extend_selection(self.argument_reset)
  343. self.finalize()
  344. ######## Change case
  345. def upcase_word(self, e): # (M-u)
  346. """Uppercase the current (or following) word. With a negative
  347. argument, uppercase the previous word, but do not move the cursor."""
  348. self.l_buffer.upcase_word()
  349. self.finalize()
  350. def downcase_word(self, e): # (M-l)
  351. """Lowercase the current (or following) word. With a negative
  352. argument, lowercase the previous word, but do not move the cursor."""
  353. self.l_buffer.downcase_word()
  354. self.finalize()
  355. def capitalize_word(self, e): # (M-c)
  356. """Capitalize the current (or following) word. With a negative
  357. argument, capitalize the previous word, but do not move the cursor."""
  358. self.l_buffer.capitalize_word()
  359. self.finalize()
  360. ########
  361. def clear_screen(self, e): # (C-l)
  362. """Clear the screen and redraw the current line, leaving the current
  363. line at the top of the screen."""
  364. self.console.page()
  365. self.finalize()
  366. def redraw_current_line(self, e): # ()
  367. """Refresh the current line. By default, this is unbound."""
  368. self.finalize()
  369. def accept_line(self, e): # (Newline or Return)
  370. """Accept the line regardless of where the cursor is. If this line
  371. is non-empty, it may be added to the history list for future recall
  372. with add_history(). If this line is a modified history line, the
  373. history line is restored to its original state."""
  374. self.finalize()
  375. return True
  376. def delete_char(self, e): # (C-d)
  377. """Delete the character at point. If point is at the beginning of
  378. the line, there are no characters in the line, and the last
  379. character typed was not bound to delete-char, then return EOF."""
  380. self.l_buffer.delete_char(self.argument_reset)
  381. self.finalize()
  382. def backward_delete_char(self, e): # (Rubout)
  383. """Delete the character behind the cursor. A numeric argument means
  384. to kill the characters instead of deleting them."""
  385. self.l_buffer.backward_delete_char(self.argument_reset)
  386. self.finalize()
  387. def backward_delete_word(self, e): # (Control-Rubout)
  388. """Delete the character behind the cursor. A numeric argument means
  389. to kill the characters instead of deleting them."""
  390. self.l_buffer.backward_delete_word(self.argument_reset)
  391. self.finalize()
  392. def forward_delete_word(self, e): # (Control-Delete)
  393. """Delete the character behind the cursor. A numeric argument means
  394. to kill the characters instead of deleting them."""
  395. self.l_buffer.forward_delete_word(self.argument_reset)
  396. self.finalize()
  397. def delete_horizontal_space(self, e): # ()
  398. """Delete all spaces and tabs around point. By default, this is unbound. """
  399. self.l_buffer.delete_horizontal_space()
  400. self.finalize()
  401. def self_insert(self, e): # (a, b, A, 1, !, ...)
  402. """Insert yourself. """
  403. if e.char and ord(e.char)!=0: #don't insert null character in buffer, can happen with dead keys.
  404. self.insert_text(e.char)
  405. self.finalize()
  406. # Paste from clipboard
  407. def paste(self,e):
  408. """Paste windows clipboard.
  409. Assume single line strip other lines and end of line markers and trailing spaces""" #(Control-v)
  410. if self.enable_win32_clipboard:
  411. txt=clipboard.get_clipboard_text_and_convert(False)
  412. txt=txt.split("\n")[0].strip("\r").strip("\n")
  413. log("paste: >%s<"%list(map(ord,txt)))
  414. self.insert_text(txt)
  415. self.finalize()
  416. def paste_mulitline_code(self,e):
  417. """Paste windows clipboard as multiline code.
  418. Removes any empty lines in the code"""
  419. reg=re.compile("\r?\n")
  420. if self.enable_win32_clipboard:
  421. txt=clipboard.get_clipboard_text_and_convert(False)
  422. t=reg.split(txt)
  423. t=[row for row in t if row.strip()!=""] #remove empty lines
  424. if t!=[""]:
  425. self.insert_text(t[0])
  426. self.add_history(self.l_buffer.copy())
  427. self.paste_line_buffer=t[1:]
  428. log("multi: >%s<"%self.paste_line_buffer)
  429. return True
  430. else:
  431. return False
  432. self.finalize()
  433. def ipython_paste(self,e):
  434. """Paste windows clipboard. If enable_ipython_paste_list_of_lists is
  435. True then try to convert tabseparated data to repr of list of lists or
  436. repr of array.
  437. If enable_ipython_paste_for_paths==True then change \\ to / and spaces to \space"""
  438. if self.enable_win32_clipboard:
  439. txt=clipboard.get_clipboard_text_and_convert(
  440. self.enable_ipython_paste_list_of_lists)
  441. if self.enable_ipython_paste_for_paths:
  442. if len(txt)<300 and ("\t" not in txt) and ("\n" not in txt):
  443. txt=txt.replace("\\","/").replace(" ",r"\ ")
  444. self.insert_text(txt)
  445. self.finalize()
  446. def copy_region_to_clipboard(self, e): # ()
  447. """Copy the text in the region to the windows clipboard."""
  448. self.l_buffer.copy_region_to_clipboard()
  449. self.finalize()
  450. def copy_selection_to_clipboard(self, e): # ()
  451. """Copy the text in the region to the windows clipboard."""
  452. self.l_buffer.copy_selection_to_clipboard()
  453. self.finalize()
  454. def cut_selection_to_clipboard(self, e): # ()
  455. """Copy the text in the region to the windows clipboard."""
  456. self.l_buffer.cut_selection_to_clipboard()
  457. self.finalize()
  458. def dump_functions(self, e): # ()
  459. """Print all of the functions and their key bindings to the Readline
  460. output stream. If a numeric argument is supplied, the output is
  461. formatted in such a way that it can be made part of an inputrc
  462. file. This command is unbound by default."""
  463. print()
  464. txt="\n".join(self.rl_settings_to_string())
  465. print(txt)
  466. self._print_prompt()
  467. self.finalize()
  468. def commonprefix(m):
  469. "Given a list of pathnames, returns the longest common leading component"
  470. if not m: return ''
  471. prefix = m[0]
  472. for item in m:
  473. for i in range(len(prefix)):
  474. if prefix[:i+1].lower() != item[:i+1].lower():
  475. prefix = prefix[:i]
  476. if i == 0: return ''
  477. break
  478. return prefix