From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Thierry Volpiatto Newsgroups: gmane.emacs.help Subject: Re: writing Python in Emacs Date: Sun, 20 Jan 2008 23:35:37 +0100 Message-ID: <878x2km8g6.fsf@thievol.homelinux.org> References: <160ed936-c8c0-432e-81c8-c62b8f164136@s13g2000prd.googlegroups.com> <87r6gc5wr5.fsf@merkury.smsnet.pl> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: ger.gmane.org 1200868254 24153 80.91.229.12 (20 Jan 2008 22:30:54 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sun, 20 Jan 2008 22:30:54 +0000 (UTC) Cc: help-gnu-emacs@gnu.org To: Rob Wolfe Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Sun Jan 20 23:31:12 2008 Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1JGih3-0007jq-Mh for geh-help-gnu-emacs@m.gmane.org; Sun, 20 Jan 2008 23:31:10 +0100 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JGigd-0007zL-Vy for geh-help-gnu-emacs@m.gmane.org; Sun, 20 Jan 2008 17:30:44 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1JGidw-0006v0-5v for help-gnu-emacs@gnu.org; Sun, 20 Jan 2008 17:27:56 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1JGidv-0006tu-9G for help-gnu-emacs@gnu.org; Sun, 20 Jan 2008 17:27:55 -0500 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JGidu-0006tW-S2 for help-gnu-emacs@gnu.org; Sun, 20 Jan 2008 17:27:54 -0500 Original-Received: from fg-out-1718.google.com ([72.14.220.155]) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1JGidu-0007Ns-Bl for help-gnu-emacs@gnu.org; Sun, 20 Jan 2008 17:27:54 -0500 Original-Received: by fg-out-1718.google.com with SMTP id d23so1804475fga.30 for ; Sun, 20 Jan 2008 14:27:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:references:date:in-reply-to:message-id:user-agent:mime-version:content-type; bh=EqaZnJq0vX2qdZT9QlsdJzJhop3A9QpbCKLlT01zZ2g=; b=eWfLEv+ACP6BP1TwmAOuLby6HiiJgTz0d35t5Ec3wG5EOadUvBmngZt36C9XJUWiGjtqu/p/ZVK07CQkmpILyLNbucxbro+VgLCmN3FiH+laG/JAwXi4rmZoUDV9LWoTqjdC+qBvMQ4mpFsN0ZlwLBmbD2NHjGRcnC+qEfb/DNQ= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:references:date:in-reply-to:message-id:user-agent:mime-version:content-type; b=iw4MF01VD1VxD53g6cV2o7H3C46cK2JcS/axwF5z8Qi8SJ7rY6gyAFVVqG2UGaAECgdZsAOz9fjWsDE8WLi1VJRM5+kLFUgN0oGKtL6thMK02Jd8uJqiPwfR9fJ2Bl0KKTfKJs7LOXqxrvp7xfEIaakJqKqzIjZA38CaPKjDsdc= Original-Received: by 10.86.77.5 with SMTP id z5mr5758778fga.41.1200868072618; Sun, 20 Jan 2008 14:27:52 -0800 (PST) Original-Received: from thievol.homelinux.org ( [79.81.53.77]) by mx.google.com with ESMTPS id l19sm10444398fgb.9.2008.01.20.14.27.42 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 20 Jan 2008 14:27:44 -0800 (PST) In-Reply-To: <87r6gc5wr5.fsf@merkury.smsnet.pl> (Rob Wolfe's message of "Sun, 20 Jan 2008 16:42:38 +0100") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.0.60 (gnu/linux) X-detected-kernel: by monty-python.gnu.org: Linux 2.6 (newer, 2) X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:50838 Archived-At: Your code work really well for me, Thank you very much. :) Rob Wolfe writes: > Terry Jones writes: > >>>>>>> "Richard" == Richard Szopa writes: > > I don't see Richard's original post, so I reply to Terry. > >> >> Richard> I am a devoted Emacs user and I write a lot in Python. >> >> Me too. > > The good news is that I managed to configure completion for Python > in Emacs using pymacs, python-mode.el, pycomplete.el and pycomplete.py. > For contents of my pycomplete.el, pycomplete.py and necessary > settings in .emacs see below. > >> >> Richard> I need the following features: >> >> Richard> 1) Tab completion, ideally Slime like. That is, when there's not >> Richard> enough letters to unambiguously complete a symbol, I want it to >> Richard> show a buffer (w/o taking the focus) w/ the possible >> Richard> completions. In an ideal world, it would be able to complete >> Richard> fo.ba to foo.bar. I imagine this would require quite tight >> Richard> Emacs-Python integration. > > Works for me. > > [...] > >> Richard> 2) Sending the toplevel definition (class or function) to the Python >> Richard> buffer. > > That feature is defined in python-mode.el: > "\e\C-x" 'py-execute-def-or-class > "\C-c|" 'py-execute-region > > > [...] > >> Richard> 3) Hints on function/method arguments. IDLE has this done nearly >> Richard> right, but the hints are a bit too intrusive for me. I would like to >> Richard> see them in the minibuffer. > > Works for me, but only for pure python functions > (`inspect.getargspec` constraint). > > [...] > >> Richard> I have tried a couple of times both python-modes (the one shipped w/ >> Richard> Python and the one shipped w/ Emacs), pymacs and stuff like that... >> Richard> And, as I said, never got it right. But, maybe I just cannot find the >> Richard> way to configure it, and some configuration hints will be enough... > > I mixed solutions found around the net and finally got it working: > - hitting TAB complete function/method name > - f1 shows description of object at point > - hitting '(' and ',' shows function parameters > > Copy `pycomplete.py` on your PYTHONPATH (e.g. /usr/lib/python2.5/site-packages) > and `pycomplete.el` on your Emacs load_path (e.g. /usr/share/emacs/site-lisp). > Copy my settings to your `.emacs` file and hopefully it will work. ;) > > My files: > > # .emacs > (require 'pycomplete) > (setq auto-mode-alist (cons '("\\.py$" . python-mode) auto-mode-alist)) > (autoload 'python-mode "python-mode" "Python editing mode." t) > > (autoload 'pymacs-load "pymacs" nil t) > (autoload 'pymacs-eval "pymacs" nil t) > (autoload 'pymacs-apply "pymacs") > (autoload 'pymacs-call "pymacs") > > (setq interpreter-mode-alist(cons '("python" . python-mode) > interpreter-mode-alist)) > (setq python-mode-hook > '(lambda () (progn > (set-variable 'py-python-command "/usr/bin/python2.5") > (set-variable 'py-indent-offset 4) > (set-variable 'py-smart-indentation nil) > (set-variable 'indent-tabs-mode nil)))) > # end of .emacs > > > # pycomplete.el > (require 'pymacs) > (require 'python-mode) > > (pymacs-load "pycomplete") > > > ;;check if prev character is blank-type > (defun char-before-blank () > (save-excursion > (forward-char -1) > (looking-at "[\n\t\r]"))) > > (defun py-complete () > (interactive) > (let ((pymacs-forget-mutability t)) > (if (and > (and (eolp) (not (bolp)) > (not (char-before-blank)))) > (insert (pycomplete-pycomplete (py-symbol-near-point) (py-find-global-imports))) > (indent-for-tab-command)))) > > (defun py-find-global-imports () > (save-excursion > (let ((imports nil)) > (goto-char (point-min)) > (while (re-search-forward > "\\(import \\|from \\([A-Za-z_][A-Za-z_0-9\\.]*\\) import \\).*" > nil t) > (setq imports > (append imports (list (buffer-substring > (match-beginning 0) > (match-end 0)))))) > imports))) > > > (defun py-complete-python-dotexpr-begin nil > (interactive) > (re-search-backward "[^a-zA-Z_0-9\\.]") > (forward-char)) > > > (defun py-complete-python-dotexpr-end nil > (interactive) > (re-search-forward "[a-zA-Z_0-9\\.]*")) > > (put 'python-dotexpr 'beginning-op 'py-complete-python-dotexpr-begin) > (put 'python-dotexpr 'end-op 'py-complete-python-dotexpr-end) > > > (defun py-complete-show (string) > (display-message-or-buffer string "*PythonHelp*")) > > > (defun py-complete-help (string) > "get help on a python expression" > (let ((help-string > (pycomplete-pyhelp string (py-find-global-imports)))) > (if (and help-string (> (length help-string) 300)) > (with-output-to-temp-buffer "*Python Help*" > (print help-string)) > (py-complete-show help-string)))) > > > (defun py-complete-help-thing-at-point nil > (interactive) > (require 'thingatpt) > (let ((sym (thing-at-point 'python-dotexpr))) > (if sym > (py-complete-help sym)))) > > > (set 'py-complete-current-signature nil) > > (defun py-complete-signature (function) > "get signature of a python function or method" > (interactive) > (set 'py-complete-current-signature > (pycomplete-pysignature function))) > > > (defun py-complete-signature-show nil > (interactive) > (require 'thingatpt) > (let ((sym (thing-at-point 'python-dotexpr))) > (if sym > (progn > (py-complete-show (py-complete-signature sym)))))) > > > (defun py-complete-signature-expr nil > (interactive) > (require 'thingatpt) > (let ((dotexpr (read-string "signature on: " > (thing-at-point 'python-dotexpr)))) > (if dotexpr > (py-complete-show > (py-complete-signature dotexpr))))) > > > (defun py-complete-electric-lparen nil > "electricly insert '(', and try to get a signature for the stuff to the left" > (interactive) > (py-complete-signature-show) > (self-insert-command 1)) > > > (defun py-complete-electric-comma nil > "electricly insert ',', and redisplay latest signature" > (interactive) > (self-insert-command 1) > (if py-complete-current-signature > (py-complete-show (format "%s" py-complete-current-signature)))) > > > (define-key py-mode-map "\M-\C-i" 'py-complete) > (define-key py-mode-map "\t" 'py-complete) > (define-key py-mode-map [f1] 'py-complete-help-thing-at-point) > (define-key py-mode-map "(" 'py-complete-electric-lparen) > (define-key py-mode-map "," 'py-complete-electric-comma) > (define-key py-mode-map [f2] 'py-complete-signature-expr) > > (provide 'pycomplete) > # end of pycomplete.el > > > # pycomplete.py > import sys > import inspect > from StringIO import StringIO > import os.path > > try: > x = set > except NameError: > from sets import Set as set > else: > del x > > from Pymacs import lisp > > > sys.path.append('.') > > > def pycomplete(s, imports=None, debug=False): > """Display completion in Emacs window""" > completions = _get_all_completions(s, imports) > dots = s.split(".") > result = os.path.commonprefix([k[len(dots[-1]):] for k in completions]) > > if result == "": > if completions: > if debug: > width = 80 > else: > width = lisp.window_width() - 2 > > column = width / 20 > white = " " * 20 > msg = "" > > counter = 0 > for completion in completions : > if len(completion) < 20 : > msg += completion + white[len(completion):] > counter += 1 > else : > msg += completion + white[len(completion) - 20:] > counter += 2 > > if counter >= column: > counter = 0 > msg += '\n' > > else: > msg = "no completions!" > if debug: > print msg > else: > lisp.message(msg) > return result > > > def pyhelp(s, imports=None): > """Return object description""" > _import_modules(imports, globals(), None) > return _getdoc(s) > > > def pysignature(s): > """Return info about function parameters""" > f = None > try: > f = eval(s) > except Exception, ex: > return "%s" % ex > > if inspect.ismethod(f): > f = f.im_func > if not inspect.isfunction(f): > return '' > (args, varargs, varkw, defaults) = inspect.getargspec(f) > return('%s: %s' > % (f.__name__, inspect.formatargspec(args,varargs,varkw,defaults))) > > > def _getdoc(s): > """Return string printed by `help` function""" > obj = None > try: > obj = eval(s) > except Exception, ex: > return "%s" % ex > out = StringIO() > old = sys.stdout > sys.stdout = out > help(obj) > sys.stdout = old > return out.getvalue() > > > def _import_modules(imports, dglobals, dlocals): > """If given, execute import statements""" > > if imports is not None: > for stmt in imports: > try: > exec stmt in dglobals, dlocals > except TypeError: > raise TypeError, 'invalid type: %s' % stmt > except: > continue > > > def _get_all_completions(s, imports=None): > """Return contextual completion of s (string of >= zero chars)""" > > dlocals = {} > _import_modules(imports, globals(), dlocals) > dots = s.split(".") > if not s or len(dots) == 1: > keys = set() > keys.update(dlocals.keys()) > keys.update(globals().keys()) > import __builtin__ > keys.update(dir(__builtin__)) > keys = list(keys) > keys.sort() > if s: > return [k for k in keys if k.startswith(s)] > else: > return keys > > sym = None > for i in range(1, len(dots)): > s = ".".join(dots[:i]) > try: > sym = eval(s, globals(), dlocals) > except NameError: > try: > sym = __import__(s, globals(), dlocals, []) > except ImportError: > return [] > if sym is not None: > s = dots[-1] > return [k for k in dir(sym) if k.startswith(s)] > > > def _test(): > print ' ->', pycomplete('', debug=True) > print 'sys.get ->', pycomplete('sys.get', debug=True) > print 'settr ->', pycomplete('settr', debug=True) > print 'settr (plat in context) ->', > print pycomplete('settr', imports=['from sys import settrace'], debug=True) > print 'foo. ->', pycomplete('foo.', debug=True) > print 'Enc (email * imported) ->', > print pycomplete('Enc', imports=['from email import *'], debug=True) > print 'E (email * imported) ->', > print pycomplete('E', imports=['from email import *'], debug=True) > print 'Enc ->', pycomplete('Enc', debug=True) > print 'E ->', pycomplete('E', debug=True) > > > if __name__ == "__main__": > _test() > # end of pycomplete.py > > > HTH, > Rob > _______________________________________________ > help-gnu-emacs mailing list > help-gnu-emacs@gnu.org > http://lists.gnu.org/mailman/listinfo/help-gnu-emacs > -- A + Thierry Pub key: http://pgp.mit.edu