Show More
@@ -257,6 +257,14 b' def _lenlastline(s):' | |||||
257 | return len(s.splitlines()[-1]) |
|
257 | return len(s.splitlines()[-1]) | |
258 |
|
258 | |||
259 |
|
259 | |||
|
260 | invisible_chars_re = re.compile('\001[^\001\002]*\002') | |||
|
261 | def _invisible_characters(s): | |||
|
262 | """ | |||
|
263 | Get the number of invisible ANSI characters in s. Invisible characters | |||
|
264 | must be delimited by \001 and \002. | |||
|
265 | """ | |||
|
266 | return _lenlastline(s) - _lenlastline(invisible_chars_re.sub('', s)) | |||
|
267 | ||||
260 | class UserNSFormatter(Formatter): |
|
268 | class UserNSFormatter(Formatter): | |
261 | """A Formatter that falls back on a shell's user_ns and __builtins__ for name resolution""" |
|
269 | """A Formatter that falls back on a shell's user_ns and __builtins__ for name resolution""" | |
262 | def __init__(self, shell): |
|
270 | def __init__(self, shell): | |
@@ -350,8 +358,7 b' class PromptManager(Configurable):' | |||||
350 | self.templates[name] = multiple_replace(prompt_abbreviations, new_template) |
|
358 | self.templates[name] = multiple_replace(prompt_abbreviations, new_template) | |
351 | # We count invisible characters (colour escapes) on the last line of the |
|
359 | # We count invisible characters (colour escapes) on the last line of the | |
352 | # prompt, to calculate the width for lining up subsequent prompts. |
|
360 | # prompt, to calculate the width for lining up subsequent prompts. | |
353 |
invis_chars = _ |
|
361 | invis_chars = _invisible_characters(self._render(name, color=True)) | |
354 | _lenlastline(self._render(name, color=False)) |
|
|||
355 | self.invisible_chars[name] = invis_chars |
|
362 | self.invisible_chars[name] = invis_chars | |
356 |
|
363 | |||
357 | def _update_prompt_trait(self, traitname, new_template): |
|
364 | def _update_prompt_trait(self, traitname, new_template): |
@@ -6,7 +6,7 b' import unittest' | |||||
6 | import os |
|
6 | import os | |
7 |
|
7 | |||
8 | from IPython.testing import tools as tt, decorators as dec |
|
8 | from IPython.testing import tools as tt, decorators as dec | |
9 | from IPython.core.prompts import PromptManager, LazyEvaluate |
|
9 | from IPython.core.prompts import PromptManager, LazyEvaluate, _invisible_characters | |
10 | from IPython.testing.globalipapp import get_ipython |
|
10 | from IPython.testing.globalipapp import get_ipython | |
11 | from IPython.utils.tempdir import TemporaryWorkingDirectory |
|
11 | from IPython.utils.tempdir import TemporaryWorkingDirectory | |
12 | from IPython.utils import py3compat |
|
12 | from IPython.utils import py3compat | |
@@ -107,3 +107,23 b' class PromptTests(unittest.TestCase):' | |||||
107 | finally: |
|
107 | finally: | |
108 | os.chdir(save) |
|
108 | os.chdir(save) | |
109 |
|
109 | |||
|
110 | def test_invisible_chars(self): | |||
|
111 | self.assertEqual(_invisible_characters('abc'), 0) | |||
|
112 | self.assertEqual(_invisible_characters('\001\033[1;37m\002'), 9) | |||
|
113 | # Sequences must be between \001 and \002 to be counted | |||
|
114 | self.assertEqual(_invisible_characters('\033[1;37m'), 0) | |||
|
115 | # Test custom escape sequences | |||
|
116 | self.assertEqual(_invisible_characters('\001\033]133;A\a\002'), 10) | |||
|
117 | ||||
|
118 | def test_width(self): | |||
|
119 | default_in = '\x01\x1b]133;A\x07\x02In [\\#]: \x01\x1b]133;B\x07\x02' | |||
|
120 | self.pm.in_template = default_in | |||
|
121 | self.pm.render('in') | |||
|
122 | self.assertEqual(self.pm.width, 8) | |||
|
123 | self.assertEqual(self.pm.txtwidth, 8) | |||
|
124 | ||||
|
125 | # Test custom escape sequences | |||
|
126 | self.pm.in_template = '\001\033]133;A\a\002' + default_in + '\001\033]133;B\a\002' | |||
|
127 | self.pm.render('in') | |||
|
128 | self.assertEqual(self.pm.width, 8) | |||
|
129 | self.assertEqual(self.pm.txtwidth, 8) |
General Comments 0
You need to be logged in to leave comments.
Login now