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 | 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 | 98 | class TerminalInteractiveShell(InteractiveShell): |
|
91 | 99 | space_for_menu = Integer(6, help='Number of line at the bottom of the screen ' |
|
92 | 100 | 'to reserve for the completion menu' |
@@ -120,6 +128,11 b' class TerminalInteractiveShell(InteractiveShell):' | |||
|
120 | 128 | help="Shortcut style to use at the prompt. 'vi' or 'emacs'.", |
|
121 | 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 | 136 | mouse_support = Bool(False, |
|
124 | 137 | help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)" |
|
125 | 138 | ).tag(config=True) |
@@ -150,6 +163,16 b' class TerminalInteractiveShell(InteractiveShell):' | |||
|
150 | 163 | if self.pt_app: |
|
151 | 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 | 176 | @observe('highlighting_style') |
|
154 | 177 | @observe('colors') |
|
155 | 178 | def _highlighting_style_changed(self, change): |
@@ -44,6 +44,15 b' def create_ipython_shortcuts(shell):' | |||
|
44 | 44 | & insert_mode |
|
45 | 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 | 56 | kb.add('c-\\')(force_exit) |
|
48 | 57 | |
|
49 | 58 | kb.add('c-p', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER)) |
@@ -86,7 +95,17 b' def create_ipython_shortcuts(shell):' | |||
|
86 | 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 | 107 | def newline_or_execute_outer(shell): |
|
108 | ||
|
90 | 109 | def newline_or_execute(event): |
|
91 | 110 | """When the user presses return, insert a newline or execute the code.""" |
|
92 | 111 | b = event.current_buffer |
@@ -107,7 +126,12 b' def newline_or_execute_outer(shell):' | |||
|
107 | 126 | else: |
|
108 | 127 | check_text = d.text[:d.cursor_position] |
|
109 | 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 | 135 | if not (d.on_last_line or |
|
112 | 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 | 142 | return |
|
119 | 143 | |
|
120 | 144 | if (status != 'incomplete') and b.accept_handler: |
|
145 | reformat_text_before_cursor(b, d, shell) | |
|
121 | 146 | b.validate_and_handle() |
|
122 | 147 | else: |
|
123 | 148 | if shell.autoindent: |
General Comments 0
You need to be logged in to leave comments.
Login now