Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fix for prompts containing newlines. #1105

Merged
merged 2 commits into from

4 participants

@takluyver
Owner

@rkern, I've tried this with the config example you supplied, and it seems to be working OK.

Specifically, we now only justify prompts based on the last line of the preceding prompt, and we don't attempt to justify multiline prompts at all.

Closes gh-1104

@rkern

Works for me.

@takluyver
Owner

Great, thanks. I'll give the others a day or two to make any comments, then merge it.

@minrk
Owner

works fine for me, thanks.

@fperez
Owner

Glad to hear the fixes work correctly. I thought for a bit about what kind of automated test we could add to ensure this doesn't return to bite us later, but I can't quite seem to see a quick way to make one. I figured we could do one involving creating an irunner with custom prompts, running a session through it and validating back the output, but it sounds like a fair amount of hassle and I'm not sure the effort/payoff is worth it.

If you can think of a way to test this that isn't too painful to implement, go ahead and do it, otherwise merge as-is.

@takluyver
Owner
@fperez
Owner

Sure :) We've made good progress on the other PRs today, so we can sit on this one for a few days before the 0.12 rc.

@takluyver
Owner

I've added a few simple tests, and checked that they're passing.

@minrk
Owner

nice, looks good to me.

@takluyver
Owner

Great. I'll merge it later today unless anyone objects.

@minrk
Owner

please do, thanks!

@takluyver takluyver merged commit 96e8539 into from
@takluyver
Owner

Rebased to avoid a merge, and pushed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 8, 2011
  1. @takluyver
  2. @takluyver
This page is out of date. Refresh to see the latest.
Showing with 59 additions and 6 deletions.
  1. +16 −6 IPython/core/prompts.py
  2. +43 −0 IPython/core/tests/test_prompts.py
View
22 IPython/core/prompts.py
@@ -232,7 +232,14 @@ def cwd_filt2(depth):
[LazyEvaluate(cwd_filt, x) for x in range(1,6)],
'cwd_y': [LazyEvaluate(cwd_filt2, x) for x in range(6)]
}
-
+
+def _lenlastline(s):
+ """Get the length of the last line. More intelligent than
+ len(s.splitlines()[-1]).
+ """
+ if not s or s.endswith(('\n', '\r')):
+ return 0
+ return len(s.splitlines()[-1])
class PromptManager(Configurable):
"""This is the primary interface for producing IPython's prompts."""
@@ -305,8 +312,10 @@ def update_prompt(self, name, new_template=None):
"""
if new_template is not None:
self.templates[name] = multiple_replace(prompt_abbreviations, new_template)
- invis_chars = len(self._render(name, color=True)) - \
- len(self._render(name, color=False))
+ # We count invisible characters (colour escapes) on the last line of the
+ # prompt, to calculate the width for lining up subsequent prompts.
+ invis_chars = _lenlastline(self._render(name, color=True)) - \
+ _lenlastline(self._render(name, color=False))
self.invisible_chars[name] = invis_chars
def _update_prompt_trait(self, traitname, new_template):
@@ -388,9 +397,10 @@ def render(self, name, color=True, just=None, **kwargs):
# Handle justification of prompt
invis_chars = self.invisible_chars[name] if color else 0
- self.txtwidth = len(res) - invis_chars
+ self.txtwidth = _lenlastline(res) - invis_chars
just = self.justify if (just is None) else just
- if just:
+ # If the prompt spans more than one line, don't try to justify it:
+ if just and ('\n' not in res) and ('\r' not in res):
res = res.rjust(self.width + invis_chars)
- self.width = len(res) - invis_chars
+ self.width = _lenlastline(res) - invis_chars
return res
View
43 IPython/core/tests/test_prompts.py
@@ -0,0 +1,43 @@
+"""Tests for prompt generation."""
+
+import unittest
+
+import nose.tools as nt
+
+from IPython.testing import tools as tt, decorators as dec
+from IPython.core.prompts import PromptManager
+from IPython.testing.globalipapp import get_ipython
+
+ip = get_ipython()
+
+
+class PromptTests(unittest.TestCase):
+ def setUp(self):
+ self.pm = PromptManager(shell=ip, config=ip.config)
+
+ def test_multiline_prompt(self):
+ self.pm.in_template = "[In]\n>>>"
+ self.pm.render('in')
+ self.assertEqual(self.pm.width, 3)
+ self.assertEqual(self.pm.txtwidth, 3)
+
+ self.pm.in_template = '[In]\n'
+ self.pm.render('in')
+ self.assertEqual(self.pm.width, 0)
+ self.assertEqual(self.pm.txtwidth, 0)
+
+ def test_translate_abbreviations(self):
+ def do_translate(template):
+ self.pm.in_template = template
+ return self.pm.templates['in']
+
+ pairs = [(r'%n>', '{color.number}{count}{color.prompt}>'),
+ (r'\T', '{time}'),
+ (r'\n', '\n')
+ ]
+
+ tt.check_pairs(do_translate, pairs)
+
+ def test_render(self):
+ self.pm.in_template = r'\#>'
+ self.assertEqual(self.pm.render('in',color=False), '%d>' % ip.execution_count)
Something went wrong with that request. Please try again.