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