##// END OF EJS Templates
Merge pull request #11734 from Carreau/autoformat-black...
Matthias Bussonnier -
r25249:17e9ca62 merge
parent child Browse files
Show More
@@ -0,0 +1,24 b''
1 Code autoformatting
2 ===================
3
4 The IPython terminal can now auto format your code just before entering a new
5 line or executing a command. To do so use the
6 ``--TerminalInteractiveShell.autoformatter`` option and set it to ``'black'``;
7 if black is installed IPython will use black to format your code when possible.
8
9 IPython cannot always properly format your code; in particular it will
10 auto formatting with *black* will only work if:
11
12 - Your code does not contains magics or special python syntax.
13
14 - There is no code after your cursor.
15
16 The Black API is also still in motion; so this may not work with all versions of
17 black.
18
19 It should be possible to register custom reformatter, though the API is till in
20 flux.
21
22
23
24
@@ -87,6 +87,14 b' else:'
87
87
88 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
88 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
89
89
90 def black_reformat_handler(text_before_cursor):
91 import black
92 formatted_text = black.format_str(text_before_cursor, mode=black.FileMode())
93 if not text_before_cursor.endswith('\n') and formatted_text.endswith('\n'):
94 formatted_text = formatted_text[:-1]
95 return formatted_text
96
97
90 class TerminalInteractiveShell(InteractiveShell):
98 class TerminalInteractiveShell(InteractiveShell):
91 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
99 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
92 'to reserve for the completion menu'
100 'to reserve for the completion menu'
@@ -120,6 +128,11 b' class TerminalInteractiveShell(InteractiveShell):'
120 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
128 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
121 ).tag(config=True)
129 ).tag(config=True)
122
130
131 autoformatter = Unicode(None,
132 help="Autoformatter to reformat Terminal code. Can be `'black'` or `None`",
133 allow_none=True
134 ).tag(config=True)
135
123 mouse_support = Bool(False,
136 mouse_support = Bool(False,
124 help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)"
137 help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)"
125 ).tag(config=True)
138 ).tag(config=True)
@@ -150,6 +163,16 b' class TerminalInteractiveShell(InteractiveShell):'
150 if self.pt_app:
163 if self.pt_app:
151 self.pt_app.editing_mode = u_mode
164 self.pt_app.editing_mode = u_mode
152
165
166 @observe('autoformatter')
167 def _autoformatter_changed(self, change):
168 formatter = change.new
169 if formatter is None:
170 self.reformat_handler = lambda x:x
171 elif formatter == 'black':
172 self.reformat_handler = black_reformat_handler
173 else:
174 raise ValueError
175
153 @observe('highlighting_style')
176 @observe('highlighting_style')
154 @observe('colors')
177 @observe('colors')
155 def _highlighting_style_changed(self, change):
178 def _highlighting_style_changed(self, change):
@@ -44,6 +44,15 b' def create_ipython_shortcuts(shell):'
44 & insert_mode
44 & insert_mode
45 ))(return_handler)
45 ))(return_handler)
46
46
47 def reformat_and_execute(event):
48 reformat_text_before_cursor(event.current_buffer, event.current_buffer.document, shell)
49 event.current_buffer.validate_and_handle()
50
51 kb.add('escape', 'enter', filter=(has_focus(DEFAULT_BUFFER)
52 & ~has_selection
53 & insert_mode
54 ))(reformat_and_execute)
55
47 kb.add('c-\\')(force_exit)
56 kb.add('c-\\')(force_exit)
48
57
49 kb.add('c-p', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
58 kb.add('c-p', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
@@ -86,7 +95,17 b' def create_ipython_shortcuts(shell):'
86 return kb
95 return kb
87
96
88
97
98 def reformat_text_before_cursor(buffer, document, shell):
99 text = buffer.delete_before_cursor(len(document.text[:document.cursor_position]))
100 try:
101 formatted_text = shell.reformat_handler(text)
102 buffer.insert_text(formatted_text)
103 except Exception as e:
104 buffer.insert_text(text)
105
106
89 def newline_or_execute_outer(shell):
107 def newline_or_execute_outer(shell):
108
90 def newline_or_execute(event):
109 def newline_or_execute(event):
91 """When the user presses return, insert a newline or execute the code."""
110 """When the user presses return, insert a newline or execute the code."""
92 b = event.current_buffer
111 b = event.current_buffer
@@ -107,7 +126,12 b' def newline_or_execute_outer(shell):'
107 else:
126 else:
108 check_text = d.text[:d.cursor_position]
127 check_text = d.text[:d.cursor_position]
109 status, indent = shell.check_complete(check_text)
128 status, indent = shell.check_complete(check_text)
110
129
130 # if all we have after the cursor is whitespace: reformat current text
131 # before cursor
132 after_cursor = d.text[d.cursor_position:]
133 if not after_cursor.strip():
134 reformat_text_before_cursor(b, d, shell)
111 if not (d.on_last_line or
135 if not (d.on_last_line or
112 d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
136 d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
113 ):
137 ):
@@ -118,6 +142,7 b' def newline_or_execute_outer(shell):'
118 return
142 return
119
143
120 if (status != 'incomplete') and b.accept_handler:
144 if (status != 'incomplete') and b.accept_handler:
145 reformat_text_before_cursor(b, d, shell)
121 b.validate_and_handle()
146 b.validate_and_handle()
122 else:
147 else:
123 if shell.autoindent:
148 if shell.autoindent:
General Comments 0
You need to be logged in to leave comments. Login now