PageRenderTime 77ms CodeModel.GetById 42ms RepoModel.GetById 0ms app.codeStats 1ms

/python-libs/Pymacs.py

http://github.com/gabrielelanaro/emacs-for-python
Python | 969 lines | 899 code | 38 blank | 32 comment | 8 complexity | a377275437569fe1f76484a5c4131cb6 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # Copyright © 2001, 2002, 2003, 2012 Progiciels Bourbeau-Pinard inc.
  4. # François Pinard <pinard@iro.umontreal.ca>, 2001.
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2, or (at your option)
  8. # any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software Foundation,
  17. # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  18. """\
  19. Interface between Emacs Lisp and Python - Python part.
  20. Emacs may launch this module as a stand-alone program, in which case it
  21. acts as a server of Python facilities for that Emacs session, reading
  22. requests from standard input and writing replies on standard output.
  23. When used in this way, the program is called "the Pymacs helper".
  24. This module may also be usefully imported by other Python modules.
  25. See the Pymacs documentation (check `README') for more information.
  26. """
  27. # Identification of version.
  28. package = 'Pymacs'
  29. version = '0.25'
  30. import os
  31. import sys
  32. __metaclass__ = type
  33. def fixup_icanon():
  34. # Otherwise sys.stdin.read hangs for large inputs in emacs 24.
  35. # See comment in emacs source code sysdep.c.
  36. import termios
  37. a = termios.tcgetattr(1)
  38. a[3] &= ~termios.ICANON
  39. termios.tcsetattr(1, termios.TCSANOW, a)
  40. try:
  41. import signal
  42. except ImportError:
  43. # Jython does not have signal.
  44. signal = None
  45. ## Python services for Emacs applications.
  46. class Main:
  47. debug_file = None
  48. signal_file = None
  49. def main(self, *arguments):
  50. """\
  51. Execute Python services for Emacs, and Emacs services for Python.
  52. This program is meant to be called from Emacs, using `pymacs.el'.
  53. Debugging options:
  54. -d FILE Debug the protocol to FILE.
  55. -s FILE Trace received signals to FILE.
  56. Arguments are added to the search path for Python modules.
  57. """
  58. # Decode options.
  59. arguments = (os.environ.get('PYMACS_OPTIONS', '').split()
  60. + list(arguments))
  61. import getopt
  62. options, arguments = getopt.getopt(arguments, 'fd:s:')
  63. for option, value in options:
  64. if option == '-d':
  65. self.debug_file = value
  66. elif option == '-s':
  67. self.signal_file = value
  68. elif option == '-f':
  69. try:
  70. fixup_icanon()
  71. except:
  72. pass
  73. arguments.reverse()
  74. for argument in arguments:
  75. if os.path.isdir(argument):
  76. sys.path.insert(0, argument)
  77. # Inhibit signals. The Interrupt signal is temporary enabled, however,
  78. # while executing any Python code received from the Lisp side.
  79. if signal is not None:
  80. # See the comment for IO_ERRORS_WITH_SIGNALS in ppppconfig.py.
  81. self.original_handler = signal.signal(
  82. signal.SIGINT, self.interrupt_handler)
  83. self.inhibit_quit = True
  84. # Re-open standard input and output in binary mode.
  85. sys.stdin = os.fdopen(sys.stdin.fileno(), 'rb')
  86. sys.stdout = os.fdopen(sys.stdout.fileno(), 'wb')
  87. # Start protocol and services.
  88. lisp._protocol.send('version', '"%s"' % version)
  89. lisp._protocol.loop()
  90. def generic_handler(self, number, frame):
  91. if self.signal_file:
  92. handle = open(self.signal_file, 'a')
  93. handle.write('%d\n' % number)
  94. handle.close()
  95. def interrupt_handler(self, number, frame):
  96. if self.signal_file:
  97. star = (' *', '')[self.inhibit_quit]
  98. handle = open(self.signal_file, 'a')
  99. handle.write('%d%s\n' % (number, star))
  100. handle.close()
  101. if not self.inhibit_quit:
  102. self.original_handler(number, frame)
  103. run = Main()
  104. main = run.main
  105. class error(Exception):
  106. pass
  107. class ProtocolError(error):
  108. pass
  109. class ZombieError(error):
  110. pass
  111. class Protocol:
  112. # All exec's and eval's triggered from the Emacs side are all executed
  113. # within the "loop" method below, so all user context is kept as
  114. # local variables within this single routine. Different instances
  115. # of this Protocol class would yield independant evaluation contexts.
  116. # But in the usual case, there is only one such instance kept within a
  117. # Lisp_Interface instance, and the "lisp" global variable within this
  118. # module holds such a Lisp_Interface instance.
  119. def __init__(self):
  120. self.freed = []
  121. def loop(self):
  122. # The server loop repeatedly receives a request from Emacs and
  123. # returns a response, which is either the value of the received
  124. # Python expression, or the Python traceback if an error occurs
  125. # while evaluating the expression.
  126. # The server loop may also be executed, as a recursive invocation,
  127. # in the context of Emacs serving a Python request. In which
  128. # case, we might also receive a notification from Emacs telling
  129. # that the reply has been transmitted, or that an error occurred.
  130. # A reply notification from Emacs interrupts the loop: the result
  131. # of this function is then the value returned from Emacs.
  132. done = False
  133. while not done:
  134. try:
  135. action, text = self.receive()
  136. if action == 'eval':
  137. action = 'return'
  138. try:
  139. run.inhibit_quit = False
  140. value = eval(text)
  141. finally:
  142. run.inhibit_quit = True
  143. elif action == 'exec':
  144. action = 'return'
  145. value = None
  146. try:
  147. run.inhibit_quit = False
  148. exec(text)
  149. finally:
  150. run.inhibit_quit = True
  151. elif action == 'return':
  152. done = True
  153. try:
  154. run.inhibit_quit = False
  155. value = eval(text)
  156. finally:
  157. run.inhibit_quit = True
  158. elif action == 'raise':
  159. action = 'raise'
  160. value = 'Emacs: ' + text
  161. else:
  162. raise ProtocolError("Unknown action %r" % action)
  163. except KeyboardInterrupt:
  164. if done:
  165. raise
  166. action = 'raise'
  167. value = '*Interrupted*'
  168. except ProtocolError, exception:
  169. sys.exit("Protocol error: %s\n" % exception)
  170. except:
  171. import traceback
  172. action = 'raise'
  173. if lisp.debug_on_error.value() is None:
  174. value = traceback.format_exception_only(
  175. sys.exc_type, sys.exc_value)
  176. value = ''.join(value).rstrip()
  177. else:
  178. value = traceback.format_exc()
  179. if not done:
  180. fragments = []
  181. print_lisp(value, fragments.append, True)
  182. self.send(action, ''.join(fragments))
  183. return value
  184. def receive(self):
  185. # Receive a Python expression from Emacs, return (ACTION, TEXT).
  186. prefix = sys.stdin.read(3)
  187. if not prefix or prefix[0] != '>':
  188. raise ProtocolError("`>' expected.")
  189. while prefix[-1] != '\t':
  190. character = sys.stdin.read(1)
  191. if not character:
  192. raise ProtocolError("Empty stdin read.")
  193. prefix += character
  194. text = sys.stdin.read(int(prefix[1:-1]))
  195. if run.debug_file is not None:
  196. handle = open(run.debug_file, 'a')
  197. handle.write(prefix + text)
  198. handle.close()
  199. return text.split(None, 1)
  200. def send(self, action, text):
  201. # Send ACTION and its TEXT argument to Emacs.
  202. if self.freed:
  203. # All delayed Lisp cleanup is piggied back on the transmission.
  204. text = ('(free (%s) %s %s)\n'
  205. % (' '.join(map(str, self.freed)), action, text))
  206. self.freed = []
  207. else:
  208. text = '(%s %s)\n' % (action, text)
  209. prefix = '<%d\t' % len(text)
  210. if run.debug_file is not None:
  211. handle = open(run.debug_file, 'a')
  212. handle.write(prefix + text)
  213. handle.close()
  214. sys.stdout.write(prefix + text)
  215. sys.stdout.flush()
  216. def pymacs_load_helper(file_without_extension, prefix, noerror=None):
  217. # This function imports a Python module, then returns a Lisp expression
  218. # which, when later evaluated, will install trampoline definitions
  219. # in Emacs for accessing the Python module facilities. Module, given
  220. # through FILE_WITHOUT_EXTENSION, may be a full path, yet without the
  221. # `.py' or `.pyc' suffix, in which case the directory is temporarily
  222. # added to the Python search path for the sole duration of that import.
  223. # All defined symbols on the Lisp side have have PREFIX prepended,
  224. # and have Python underlines in Python turned into dashes. If PREFIX
  225. # is None, it then defaults to the base name of MODULE with underlines
  226. # turned to dashes, followed by a dash.
  227. directory, module_name = os.path.split(file_without_extension)
  228. module_components = module_name.split('.')
  229. if prefix is None:
  230. prefix = module_components[-1].replace('_', '-') + '-'
  231. try:
  232. module = sys.modules.get(module_name)
  233. if module:
  234. reload(module)
  235. else:
  236. try:
  237. if directory:
  238. sys.path.insert(0, directory)
  239. module = __import__(module_name)
  240. finally:
  241. if directory:
  242. del sys.path[0]
  243. # Whenever MODULE_NAME is of the form [PACKAGE.]...MODULE,
  244. # __import__ returns the outer PACKAGE, not the module.
  245. for component in module_components[1:]:
  246. module = getattr(module, component)
  247. except ImportError:
  248. if noerror:
  249. return None
  250. else:
  251. raise
  252. load_hook = module.__dict__.get('pymacs_load_hook')
  253. if load_hook:
  254. load_hook()
  255. interactions = module.__dict__.get('interactions', {})
  256. if not isinstance(interactions, dict):
  257. interactions = {}
  258. arguments = []
  259. for name, value in module.__dict__.items():
  260. if callable(value) and value is not lisp:
  261. arguments.append(allocate_python(value))
  262. arguments.append(lisp[prefix + name.replace('_', '-')])
  263. try:
  264. interaction = value.interaction
  265. except AttributeError:
  266. interaction = interactions.get(value)
  267. if callable(interaction):
  268. arguments.append(allocate_python(interaction))
  269. else:
  270. arguments.append(interaction)
  271. if arguments:
  272. return [lisp.progn,
  273. [lisp.pymacs_defuns, [lisp.quote, arguments]],
  274. module]
  275. return [lisp.quote, module]
  276. def doc_string(function):
  277. import inspect
  278. return inspect.getdoc(function)
  279. ## Garbage collection matters.
  280. # Many Python types do not have direct Lisp equivalents, and may not be
  281. # directly returned to Lisp for this reason. They are rather allocated in
  282. # a list of handles, below, and a handle index is used for communication
  283. # instead of the Python value. Whenever such a handle is freed from the
  284. # Lisp side, its index is added of a freed list for later reuse.
  285. python = []
  286. freed_list = []
  287. def allocate_python(value):
  288. assert not isinstance(value, str), (type(value), repr(value))
  289. # Allocate some handle to hold VALUE, return its index.
  290. if freed_list:
  291. index = freed_list[-1]
  292. del freed_list[-1]
  293. python[index] = value
  294. else:
  295. index = len(python)
  296. python.append(value)
  297. return index
  298. def free_python(indices):
  299. # Return many handles to the pool.
  300. for index in indices:
  301. python[index] = None
  302. freed_list.append(index)
  303. def zombie_python(indices):
  304. # Ensure that some handles are _not_ in the pool.
  305. for index in indices:
  306. while index >= len(python):
  307. freed_list.append(len(python))
  308. python.append(None)
  309. python[index] = zombie
  310. freed_list.remove(index)
  311. # Merely to make `*Pymacs*' a bit more readable.
  312. freed_list.sort()
  313. def zombie(*arguments):
  314. # This catch-all function is set as the value for any function which
  315. # disappeared with a previous Pymacs helper process, so calling
  316. # such a function from Emacs will trigger a decipherable diagnostic.
  317. diagnostic = "Object vanished when the Pymacs helper was killed"
  318. if lisp.pymacs_dreadful_zombies.value():
  319. raise ZombieError(diagnostic)
  320. lisp.message(diagnostic)
  321. ## Emacs services for Python applications.
  322. class Let:
  323. def __init__(self, **keywords):
  324. # The stack holds (METHOD, DATA) pairs, where METHOD is the expected
  325. # unbound pop_* method, and DATA holds information to be restored.
  326. # METHOD may not be bound to the instance, as this would induce
  327. # reference cycles, and then, __del__ would not be called timely.
  328. self.stack = []
  329. if keywords:
  330. self.push(**keywords)
  331. def __del__(self):
  332. self.pops()
  333. def __nonzero__(self):
  334. # So stylistic `if let:' executes faster.
  335. return True
  336. def pops(self):
  337. while self.stack:
  338. self.stack[-1][0](self)
  339. def push(self, **keywords):
  340. data = []
  341. for name, value in keywords.items():
  342. data.append((name, getattr(lisp, name).value()))
  343. setattr(lisp, name, value)
  344. self.stack.append((Let.pop, data))
  345. return self
  346. def pop(self):
  347. method, data = self.stack.pop()
  348. assert method == Let.pop, (method, data)
  349. for name, value in data:
  350. setattr(lisp, name, value)
  351. def push_excursion(self):
  352. self.stack.append((Let.pop_excursion, (lisp.current_buffer(),
  353. lisp.point_marker(),
  354. lisp.mark_marker())))
  355. return self
  356. def pop_excursion(self):
  357. method, data = self.stack.pop()
  358. assert method == Let.pop_excursion, (method, data)
  359. buffer, point_marker, mark_marker = data
  360. lisp.set_buffer(buffer)
  361. lisp.goto_char(point_marker)
  362. lisp.set_mark(mark_marker)
  363. lisp.set_marker(point_marker, None)
  364. lisp.set_marker(mark_marker, None)
  365. def push_match_data(self):
  366. self.stack.append((Let.pop_match_data, lisp.match_data()))
  367. return self
  368. def pop_match_data(self):
  369. method, data = self.stack.pop()
  370. assert method == Let.pop_match_data, (method, data)
  371. lisp.set_match_data(data)
  372. def push_restriction(self):
  373. self.stack.append((Let.pop_restriction, (lisp.point_min_marker(),
  374. lisp.point_max_marker())))
  375. return self
  376. def pop_restriction(self):
  377. method, data = self.stack.pop()
  378. assert method == Let.pop_restriction, (method, data)
  379. point_min_marker, point_max_marker = data
  380. lisp.narrow_to_region(point_min_marker, point_max_marker)
  381. lisp.set_marker(point_min_marker, None)
  382. lisp.set_marker(point_max_marker, None)
  383. def push_selected_window(self):
  384. self.stack.append((Let.pop_selected_window, lisp.selected_window()))
  385. return self
  386. def pop_selected_window(self):
  387. method, data = self.stack.pop()
  388. assert method == Let.pop_selected_window, (method, data)
  389. lisp.select_window(data)
  390. def push_window_excursion(self):
  391. self.stack.append((Let.pop_window_excursion,
  392. lisp.current_window_configuration()))
  393. return self
  394. def pop_window_excursion(self):
  395. method, data = self.stack.pop()
  396. assert method == Let.pop_window_excursion, (method, data)
  397. lisp.set_window_configuration(data)
  398. class Symbol:
  399. def __init__(self, text):
  400. self.text = text
  401. def __repr__(self):
  402. return 'lisp[%s]' % repr(self.text)
  403. def __str__(self):
  404. return '\'' + self.text
  405. def value(self):
  406. return lisp._eval(self.text)
  407. def copy(self):
  408. return lisp._expand(self.text)
  409. def set(self, value):
  410. if value is None:
  411. lisp._eval('(setq %s nil)' % self.text)
  412. else:
  413. fragments = []
  414. write = fragments.append
  415. write('(progn (setq %s ' % self.text)
  416. print_lisp(value, write, True)
  417. write(') nil)')
  418. lisp._eval(''.join(fragments))
  419. def __call__(self, *arguments):
  420. fragments = []
  421. write = fragments.append
  422. write('(%s' % self.text)
  423. for argument in arguments:
  424. write(' ')
  425. print_lisp(argument, write, True)
  426. write(')')
  427. return lisp._eval(''.join(fragments))
  428. class Lisp:
  429. def __init__(self, index):
  430. self.index = index
  431. def __del__(self):
  432. lisp._protocol.freed.append(self.index)
  433. def __repr__(self):
  434. return ('lisp(%s)' % repr(lisp('(prin1-to-string %s)' % self)))
  435. def __str__(self):
  436. return '(aref pymacs-lisp %d)' % self.index
  437. def value(self):
  438. return self
  439. def copy(self):
  440. return lisp._expand(str(self))
  441. class Buffer(Lisp):
  442. pass
  443. #def write(text):
  444. # # So you could do things like
  445. # # print >>lisp.current_buffer(), "Hello World"
  446. # lisp.insert(text, self)
  447. #def point(self):
  448. # return lisp.point(self)
  449. class List(Lisp):
  450. def __call__(self, *arguments):
  451. fragments = []
  452. write = fragments.append
  453. write('(%s' % self)
  454. for argument in arguments:
  455. write(' ')
  456. print_lisp(argument, write, True)
  457. write(')')
  458. return lisp._eval(''.join(fragments))
  459. def __len__(self):
  460. return lisp._eval('(length %s)' % self)
  461. def __getitem__(self, key):
  462. value = lisp._eval('(nth %d %s)' % (key, self))
  463. if value is None and key >= len(self):
  464. raise IndexError(key)
  465. return value
  466. def __setitem__(self, key, value):
  467. fragments = []
  468. write = fragments.append
  469. write('(setcar (nthcdr %d %s) ' % (key, self))
  470. print_lisp(value, write, True)
  471. write(')')
  472. lisp._eval(''.join(fragments))
  473. class Table(Lisp):
  474. def __getitem__(self, key):
  475. fragments = []
  476. write = fragments.append
  477. write('(gethash ')
  478. print_lisp(key, write, True)
  479. write(' %s)' % self)
  480. return lisp._eval(''.join(fragments))
  481. def __setitem__(self, key, value):
  482. fragments = []
  483. write = fragments.append
  484. write('(puthash ')
  485. print_lisp(key, write, True)
  486. write(' ')
  487. print_lisp(value, write, True)
  488. write(' %s)' % self)
  489. lisp._eval(''.join(fragments))
  490. class Vector(Lisp):
  491. def __len__(self):
  492. return lisp._eval('(length %s)' % self)
  493. def __getitem__(self, key):
  494. return lisp._eval('(aref %s %d)' % (self, key))
  495. def __setitem__(self, key, value):
  496. fragments = []
  497. write = fragments.append
  498. write('(aset %s %d ' % (self, key))
  499. print_lisp(value, write, True)
  500. write(')')
  501. lisp._eval(''.join(fragments))
  502. class Lisp_Interface:
  503. def __init__(self):
  504. self.__dict__['_cache'] = {'nil': None}
  505. self.__dict__['_protocol'] = Protocol()
  506. def __call__(self, text):
  507. return self._eval('(progn %s)' % text)
  508. def _eval(self, text):
  509. self._protocol.send('eval', text)
  510. return self._protocol.loop()
  511. def _expand(self, text):
  512. self._protocol.send('expand', text)
  513. return self._protocol.loop()
  514. def __getattr__(self, name):
  515. if name[0] == '_':
  516. raise AttributeError(name)
  517. return self[name.replace('_', '-')]
  518. def __setattr__(self, name, value):
  519. if name[0] == '_':
  520. raise AttributeError(name)
  521. self[name.replace('_', '-')] = value
  522. def __getitem__(self, name):
  523. try:
  524. return self._cache[name]
  525. except KeyError:
  526. symbol = self._cache[name] = Symbol(name)
  527. return symbol
  528. def __setitem__(self, name, value):
  529. try:
  530. symbol = self._cache[name]
  531. except KeyError:
  532. symbol = self._cache[name] = Symbol(name)
  533. symbol.set(value)
  534. lisp = Lisp_Interface()
  535. print_lisp_quoted_specials = {
  536. '"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f',
  537. '\n': '\\n', '\r': '\\r', '\t': '\\t'}
  538. def print_lisp(value, write, quoted):
  539. if value is None:
  540. write('nil')
  541. elif isinstance(bool, type) and isinstance(value, bool):
  542. write(('nil', 't')[value])
  543. elif isinstance(value, int):
  544. write(repr(value))
  545. elif isinstance(value, float):
  546. write(repr(value))
  547. elif isinstance(value, basestring):
  548. multibyte = False
  549. if isinstance(value, unicode):
  550. try:
  551. value = value.encode('ASCII')
  552. except UnicodeError:
  553. value = value.encode('UTF-8')
  554. multibyte = True
  555. if multibyte:
  556. write('(decode-coding-string ')
  557. write('"')
  558. for character in value:
  559. special = print_lisp_quoted_specials.get(character)
  560. if special is not None:
  561. write(special)
  562. elif 32 <= ord(character) < 127:
  563. write(character)
  564. else:
  565. write('\\%.3o' % ord(character))
  566. write('"')
  567. if multibyte:
  568. write(' \'utf-8)')
  569. elif isinstance(value, list):
  570. if quoted:
  571. write("'")
  572. if len(value) == 0:
  573. write('nil')
  574. elif len(value) == 2 and value[0] == lisp.quote:
  575. write("'")
  576. print_lisp(value[1], write, False)
  577. else:
  578. write('(')
  579. print_lisp(value[0], write, False)
  580. for sub_value in value[1:]:
  581. write(' ')
  582. print_lisp(sub_value, write, False)
  583. write(')')
  584. elif isinstance(value, tuple):
  585. write('[')
  586. if len(value) > 0:
  587. print_lisp(value[0], write, False)
  588. for sub_value in value[1:]:
  589. write(' ')
  590. print_lisp(sub_value, write, False)
  591. write(']')
  592. elif isinstance(value, Lisp):
  593. write(str(value))
  594. elif isinstance(value, Symbol):
  595. if quoted:
  596. write("'")
  597. write(value.text)
  598. elif callable(value):
  599. write('(pymacs-defun %d nil)' % allocate_python(value))
  600. else:
  601. write('(pymacs-python %d)' % allocate_python(value))
  602. if __name__ == '__main__':
  603. main(*sys.argv[1:])