From 2edbec55727ca42b12fe52f968a1210fb5e37c3b 2005-12-28 06:51:01 From: fperez Date: 2005-12-28 06:51:01 Subject: [PATCH] Added support for automatically reopening the editor if the file had a syntax error in it. Thanks to scottt who provided the patch at: http://www.scipy.net/roundup/ipython/issue36 (slightly modified version committed). --- diff --git a/IPython/Magic.py b/IPython/Magic.py index 457be06..bb6dbbc 100644 --- a/IPython/Magic.py +++ b/IPython/Magic.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Magic functions for InteractiveShell. -$Id: Magic.py 958 2005-12-27 23:17:51Z fperez $""" +$Id: Magic.py 960 2005-12-28 06:51:01Z fperez $""" #***************************************************************************** # Copyright (C) 2001 Janko Hauser and @@ -1875,7 +1875,7 @@ Currently the magic system has the following functions:\n""" else: print 'done. Executing edited code...' try: - execfile(filename,self.shell.user_ns) + self.shell.safe_execfile(filename,self.shell.user_ns) except IOError,msg: if msg.filename == filename: warn('File not found. Did you forget to save?') diff --git a/IPython/Prompts.py b/IPython/Prompts.py index 10befc5..99acbd7 100644 --- a/IPython/Prompts.py +++ b/IPython/Prompts.py @@ -2,7 +2,7 @@ """ Classes for handling input/output prompts. -$Id: Prompts.py 958 2005-12-27 23:17:51Z fperez $""" +$Id: Prompts.py 960 2005-12-28 06:51:01Z fperez $""" #***************************************************************************** # Copyright (C) 2001-2004 Fernando Perez @@ -494,7 +494,9 @@ class CachedOutput: if arg is not None: cout_write = Term.cout.write # fast lookup # first handle the cache and counters - self.update(arg) + # but avoid recursive reference when displaying _oh/Out + if arg is not self.user_ns['_oh']: + self.update(arg) # do not print output if input ends in ';' if self.input_hist[self.prompt_count].endswith(';\n'): return diff --git a/IPython/genutils.py b/IPython/genutils.py index f4717c6..e4a38cc 100644 --- a/IPython/genutils.py +++ b/IPython/genutils.py @@ -5,7 +5,7 @@ General purpose utilities. This is a grab-bag of stuff I find useful in most programs I write. Some of these things are also convenient when working at the command line. -$Id: genutils.py 958 2005-12-27 23:17:51Z fperez $""" +$Id: genutils.py 960 2005-12-28 06:51:01Z fperez $""" #***************************************************************************** # Copyright (C) 2001-2004 Fernando Perez. @@ -948,7 +948,7 @@ def ask_yes_no(prompt,default=None): Valid answers are: y/yes/n/no (match is not case sensitive).""" - answers = {'y':1,'n':0,'yes':1,'no':0} + answers = {'y':True,'n':False,'yes':True,'no':False} ans = None eofs, max_eofs = 0, 20 while ans not in answers.keys(): diff --git a/IPython/hooks.py b/IPython/hooks.py index 1c02757..1395fe9 100644 --- a/IPython/hooks.py +++ b/IPython/hooks.py @@ -32,7 +32,7 @@ ip_set_hook('editor',myiphooks.calljed) The ip_set_hook function is put by IPython into the builtin namespace, so it is always available from all running code. -$Id: hooks.py 535 2005-03-02 08:42:25Z fperez $""" +$Id: hooks.py 960 2005-12-28 06:51:01Z fperez $""" #***************************************************************************** # Copyright (C) 2005 Fernando Perez. @@ -48,9 +48,9 @@ __version__ = Release.version import os -# List here all the default hooks. For now it's just the editor, but over -# time we'll move here all the public API for user-accessible things. -__all__ = ['editor'] +# List here all the default hooks. For now it's just the editor functions +# but over time we'll move here all the public API for user-accessible things. +__all__ = ['editor', 'fix_error_editor'] def editor(self,filename, linenum): """Open the default editor at the given filename and linenumber. @@ -70,3 +70,26 @@ def editor(self,filename, linenum): linemark = '+%d' % linenum # Call the actual editor os.system('%s %s %s' % (editor,linemark,filename)) + +import tempfile +def fix_error_editor(self,filename,linenum,column,msg): + """Open the editor at the given filename, linenumber, column and + show an error message. This is used for correcting syntax errors. + The current implementation only has special support for the VIM editor, + and falls back on the 'editor' hook if VIM is not used. + + Call ip_set_hook('fix_error_editor',youfunc) to use your own function, + """ + def vim_quickfix_file(): + t = tempfile.NamedTemporaryFile() + t.write('%s:%d:%d:%s\n' % (filename,linenum,column,msg)) + t.flush() + return t + if os.path.basename(self.rc.editor) != 'vim': + self.hooks.editor(filename,linenum) + return + t = vim_quickfix_file() + try: + os.system('vim --cmd "set errorformat=%f:%l:%c:%m" -q ' + t.name) + finally: + t.close() diff --git a/IPython/iplib.py b/IPython/iplib.py index b536b42..73f57c6 100644 --- a/IPython/iplib.py +++ b/IPython/iplib.py @@ -6,7 +6,7 @@ Requires Python 2.1 or newer. This file contains all the classes and helper functions specific to IPython. -$Id: iplib.py 959 2005-12-28 02:04:41Z fperez $ +$Id: iplib.py 960 2005-12-28 06:51:01Z fperez $ """ #***************************************************************************** @@ -212,6 +212,23 @@ class InputList(list): def __getslice__(self,i,j): return ''.join(list.__getslice__(self,i,j)) +class SyntaxTB(ultraTB.ListTB): + """Extension which holds some state: the last exception value""" + + def __init__(self,color_scheme = 'NoColor'): + ultraTB.ListTB.__init__(self,color_scheme) + self.last_syntax_error = None + + def __call__(self, etype, value, elist): + self.last_syntax_error = value + ultraTB.ListTB.__call__(self,etype,value,elist) + + def clear_err_state(self): + """Return the current error state and clear it""" + e = self.last_syntax_error + self.last_syntax_error = None + return e + #**************************************************************************** # Main IPython class class InteractiveShell(Logger, Magic): @@ -544,10 +561,10 @@ class InteractiveShell(Logger, Magic): # TraceBack handlers: # Need two, one for syntax errors and one for other exceptions. - self.SyntaxTB = ultraTB.ListTB(color_scheme='NoColor') - # This one is initialized with an offset, meaning we always want to - # remove the topmost item in the traceback, which is our own internal - # code. Valid modes: ['Plain','Context','Verbose'] + self.SyntaxTB = SyntaxTB(color_scheme='NoColor') + # The interactive one is initialized with an offset, meaning we always + # want to remove the topmost item in the traceback, which is our own + # internal code. Valid modes: ['Plain','Context','Verbose'] self.InteractiveTB = ultraTB.AutoFormattedTB(mode = 'Plain', color_scheme='NoColor', tb_offset = 1) @@ -1022,6 +1039,44 @@ want to merge them back into the new files.""" % locals() # Configure auto-indent for all platforms self.set_autoindent(self.rc.autoindent) + def _should_recompile(self,e): + """Utility routine for edit_syntax_error""" + + if e.filename in ('','','', + ''): + return False + try: + if not ask_yes_no('Return to editor to correct syntax error? ' + '[Y/n] ','y'): + return False + except EOFError: + return False + self.hooks.fix_error_editor(e.filename,e.lineno,e.offset,e.msg) + return True + + def edit_syntax_error(self): + """The bottom half of the syntax error handler called in the main loop. + + Loop until syntax error is fixed or user cancels. + """ + + while self.SyntaxTB.last_syntax_error: + # copy and clear last_syntax_error + err = self.SyntaxTB.clear_err_state() + if not self._should_recompile(err): + return + try: + # may set last_syntax_error again if a SyntaxError is raised + self.safe_execfile(err.filename,self.shell.user_ns) + except: + self.showtraceback() + else: + f = file(err.filename) + try: + sys.displayhook(f.read()) + finally: + f.close() + def showsyntaxerror(self, filename=None): """Display the syntax error that just occurred. @@ -1221,10 +1276,15 @@ want to merge them back into the new files.""" % locals() self.indent_current_nsp -= 4 else: self.indent_current_nsp = 0 + # indent_current is the actual string to be inserted # by the readline hooks for indentation self.indent_current = ' '* self.indent_current_nsp + if (self.SyntaxTB.last_syntax_error and + self.rc.autoedit_syntax): + self.edit_syntax_error() + except KeyboardInterrupt: self.write("\nKeyboardInterrupt\n") self.resetbuffer() diff --git a/IPython/ipmaker.py b/IPython/ipmaker.py index 80b28ea..4bb12e6 100644 --- a/IPython/ipmaker.py +++ b/IPython/ipmaker.py @@ -6,7 +6,7 @@ Requires Python 2.1 or better. This file contains the main make_IPython() starter function. -$Id: ipmaker.py 958 2005-12-27 23:17:51Z fperez $""" +$Id: ipmaker.py 960 2005-12-28 06:51:01Z fperez $""" #***************************************************************************** # Copyright (C) 2001-2004 Fernando Perez. @@ -161,7 +161,8 @@ object? -> Details about 'object'. ?object also works, ?? prints more. 'rcfile=s separate_in|si=s separate_out|so=s ' 'separate_out2|so2=s xmode=s wildcards_case_sensitive! ' 'magic_docstrings system_verbose! ' - 'multi_line_specials!') + 'multi_line_specials! ' + 'autoedit_syntax!') # Options that can *only* appear at the cmd line (not in rcfiles). @@ -224,6 +225,7 @@ object? -> Details about 'object'. ?object also works, ?? prints more. xmode = 'Verbose', wildcards_case_sensitive = 1, magic_docstrings = 0, # undocumented, for doc generation + autoedit_syntax = 0, ) # Things that will *only* appear in rcfiles (not at the command line). diff --git a/IPython/usage.py b/IPython/usage.py index c324874..dd765e0 100644 --- a/IPython/usage.py +++ b/IPython/usage.py @@ -6,7 +6,7 @@ # the file COPYING, distributed as part of this software. #***************************************************************************** -# $Id: usage.py 926 2005-12-01 18:14:21Z fperez $ +# $Id: usage.py 960 2005-12-28 06:51:01Z fperez $ from IPython import Release __author__ = '%s <%s>' % Release.authors['Fernando'] @@ -154,13 +154,12 @@ REGULAR OPTIONS -[no]automagic Make magic commands automatic (without needing their first char- - acter to be @). Type @magic at the IPython prompt for more + acter to be %). Type %magic at the IPython prompt for more information. - -[no]autoparens - Make IPython automatically call any callable object even if you - didn’t type explicit parentheses. For example, ’str 43’ becomes - ’str(43)’ automatically. + -[no]autoedit_syntax + When a syntax error occurs after editing a file, automatically + open the file to the trouble causing line for convenient fixing. -[no]banner Print the intial information banner (default on). diff --git a/doc/ChangeLog b/doc/ChangeLog index c0b49b8..4dd3558 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -4,6 +4,11 @@ input with emtpy lines. This fixes http://www.scipy.net/roundup/ipython/issue43 and a similar discussion on the user list. + (edit_syntax_error): added support for automatically reopening the + editor if the file had a syntax error in it. Thanks to scottt who + provided the patch at: + http://www.scipy.net/roundup/ipython/issue36 (slightly modified + version committed). WARNING: a behavior change is necessarily introduced to support blank lines: now a single blank line with whitespace does NOT diff --git a/doc/ipython.1 b/doc/ipython.1 index b68cba3..3f2da8a 100644 --- a/doc/ipython.1 +++ b/doc/ipython.1 @@ -124,12 +124,11 @@ Turn automatic indentation on/off. .TP .B \-[no]automagic Make magic commands automatic (without needing their first character -to be @). Type @magic at the IPython prompt for more information. +to be %). Type %magic at the IPython prompt for more information. .TP -.B \-[no]autoparens -Make IPython automatically call any callable object even if you didn't -type explicit parentheses. For example, 'str 43' becomes 'str(43)' -automatically. +.B \-[no]autoedit_syntax +When a syntax error occurs after editing a file, automatically open the file +to the trouble causing line for convenient fixing. .TP .B \-[no]banner Print the intial information banner (default on). diff --git a/doc/manual_base.lyx b/doc/manual_base.lyx index 380a65e..acbe839 100644 --- a/doc/manual_base.lyx +++ b/doc/manual_base.lyx @@ -2707,6 +2707,28 @@ show() \family typewriter \series bold +-[no]autocall: +\family default +\series default + Make IPython automatically call any callable object even if you didn't + type explicit parentheses. + For example, `str 43' becomes `str(43)' automatically. +\layout List +\labelwidthstring 00.00.0000 + + +\family typewriter +\series bold +-[no]autoindent: +\family default +\series default + Turn automatic indentation on/off. +\layout List +\labelwidthstring 00.00.0000 + + +\family typewriter +\series bold -[no]automagic \series default : @@ -2728,6 +2750,18 @@ show() \family typewriter \series bold +-[no]autoedit_syntax: +\family default +\series default + When a syntax error occurs after editing a file, automatically open the + file to the trouble causing line for convenient fixing. + +\layout List +\labelwidthstring 00.00.0000 + + +\family typewriter +\series bold -[no]banner \series default : @@ -9121,4 +9155,14 @@ Smedt \family default Debugger enhancements, so that when pdb is activated from within IPython, coloring, tab completion and other features continue to work seamlessly. +\layout List +\labelwidthstring 00.00.0000 + +Scott (email unknown) Support for automatic editor invocation on syntax + errors (see +\begin_inset LatexCommand \htmlurl{http://www.scipy.net/roundup/ipython/issue36} + +\end_inset + +). \the_end