Skip to content
This repository

Run PyOs_InputHook in pager to keep plot windows interactive. #741

Closed
wants to merge 3 commits into from

1 participant

Eric Firing
Eric Firing

This is implemented here only for posix platforms, but probably
could be generalized.

It has only one minor ill effect that I am aware of: upon exiting the pager, one must hit CR to get a prompt back. I have been unable to figure out why that is, or how to fix it, but it is a consequence of running the PyOs_InputHook, not of the change from popen to subprocess.Popen.

added some commits August 27, 2011
Eric Firing Run PyOs_InputHook in pager to keep plot windows interactive.
This is implemented here only for posix platforms, but probably
could be generalized.
1932aff
Eric Firing page.page: use io.flush() to get the prompt back after running the pager 05fddd8
Eric Firing page.page: code cleaned up, commented regarding remaining problem.
There are still major problems and puzzles regarding getting back
to the prompt, and a hangup with Tk.
6d483c8
Eric Firing

My second commit turned out to be no help at all; I was not testing it under the right circumstances, which is with an InputHook in place.
I'm closing the request now because although the need to hit CR to get back to the prompt is perhaps tolerable, the method is failing completely with Tk. I'm stumped.

Eric Firing efiring closed this September 05, 2011
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 3 unique commits by 1 author.

Aug 27, 2011
Eric Firing Run PyOs_InputHook in pager to keep plot windows interactive.
This is implemented here only for posix platforms, but probably
could be generalized.
1932aff
Sep 05, 2011
Eric Firing page.page: use io.flush() to get the prompt back after running the pager 05fddd8
Eric Firing page.page: code cleaned up, commented regarding remaining problem.
There are still major problems and puzzles regarding getting back
to the prompt, and a hangup with Tk.
6d483c8
This page is out of date. Refresh to see the latest.

Showing 1 changed file with 68 additions and 40 deletions. Show diff stats Hide diff stats

  1. 108  IPython/core/page.py
108  IPython/core/page.py
@@ -30,6 +30,8 @@
30 30
 import re
31 31
 import sys
32 32
 import tempfile
  33
+import subprocess
  34
+import time
33 35
 
34 36
 from IPython.core import ipapi
35 37
 from IPython.core.error import TryNext
@@ -38,7 +40,7 @@
38 40
 from IPython.utils import io
39 41
 from IPython.utils.process import system
40 42
 from IPython.utils.terminal import get_terminal_size
41  
-
  43
+from IPython.lib.inputhook import InputHookManager
42 44
 
43 45
 #-----------------------------------------------------------------------------
44 46
 # Classes and functions
@@ -46,6 +48,8 @@
46 48
 
47 49
 esc_re = re.compile(r"(\x1b[^m]+m)")
48 50
 
  51
+_input_hook_manager = InputHookManager()
  52
+
49 53
 def page_dumb(strng, start=0, screen_lines=25):
50 54
     """Very dumb 'pager' in Python, for when nothing else works.
51 55
 
@@ -151,7 +155,7 @@ def page(strng, start=0, screen_lines=0, pager_cmd=None):
151 155
             # http://bugs.python.org/issue10144
152 156
             NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
153 157
             os.environ['NCURSES_NO_SETBUF'] = ''
154  
-            
  158
+
155 159
             # Proceed with curses initialization
156 160
             scr = curses.initscr()
157 161
             screen_lines_real,screen_cols = scr.getmaxyx()
@@ -162,7 +166,7 @@ def page(strng, start=0, screen_lines=0, pager_cmd=None):
162 166
                 del os.environ['NCURSES_NO_SETBUF']
163 167
             else:
164 168
                 os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
165  
-                
  169
+
166 170
             # Restore terminal state in case endwin() didn't.
167 171
             termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
168 172
             # Now we have what we needed: the screen size in rows/columns
@@ -176,47 +180,71 @@ def page(strng, start=0, screen_lines=0, pager_cmd=None):
176 180
     if numlines <= screen_lines :
177 181
         #print '*** normal print'  # dbg
178 182
         print >>io.stdout, str_toprint
179  
-    else:
180  
-        # Try to open pager and default to internal one if that fails.
181  
-        # All failure modes are tagged as 'retval=1', to match the return
182  
-        # value of a failed system command.  If any intermediate attempt
183  
-        # sets retval to 1, at the end we resort to our own page_dumb() pager.
184  
-        pager_cmd = get_pager_cmd(pager_cmd)
185  
-        pager_cmd += ' ' + get_pager_start(pager_cmd,start)
186  
-        if os.name == 'nt':
187  
-            if pager_cmd.startswith('type'):
188  
-                # The default WinXP 'type' command is failing on complex strings.
  183
+        return
  184
+
  185
+    # Try to open pager and default to internal one if that fails.
  186
+    # All failure modes are tagged as 'retval=1', to match the return
  187
+    # value of a failed system command.  If any intermediate attempt
  188
+    # sets retval to 1, at the end we resort to our own page_dumb() pager.
  189
+    pager_cmd = get_pager_cmd(pager_cmd)
  190
+    pager_cmd += ' ' + get_pager_start(pager_cmd,start)
  191
+    if os.name == 'nt':
  192
+        if pager_cmd.startswith('type'):
  193
+            # The default WinXP 'type' command is failing on complex strings.
  194
+            retval = 1
  195
+        else:
  196
+            tmpname = tempfile.mktemp('.txt')
  197
+            tmpfile = file(tmpname,'wt')
  198
+            tmpfile.write(strng)
  199
+            tmpfile.close()
  200
+            cmd = "%s < %s" % (pager_cmd,tmpname)
  201
+            if os.system(cmd):
189 202
                 retval = 1
190 203
             else:
191  
-                tmpname = tempfile.mktemp('.txt')
192  
-                tmpfile = file(tmpname,'wt')
193  
-                tmpfile.write(strng)
194  
-                tmpfile.close()
195  
-                cmd = "%s < %s" % (pager_cmd,tmpname)
196  
-                if os.system(cmd):
197  
-                  retval = 1
198  
-                else:
199  
-                  retval = None
200  
-                os.remove(tmpname)
201  
-        else:
202  
-            try:
203 204
                 retval = None
204  
-                # if I use popen4, things hang. No idea why.
205  
-                #pager,shell_out = os.popen4(pager_cmd)
206  
-                pager = os.popen(pager_cmd,'w')
207  
-                pager.write(strng)
208  
-                pager.close()
209  
-                retval = pager.close()  # success returns None
210  
-            except IOError,msg:  # broken pipe when user quits
211  
-                if msg.args == (32,'Broken pipe'):
212  
-                    retval = None
213  
-                else:
214  
-                    retval = 1
215  
-            except OSError:
216  
-                # Other strange problems, sometimes seen in Win2k/cygwin
  205
+            os.remove(tmpname)
  206
+    else:
  207
+        try:
  208
+            # Block keyboard interrupts; otherwise the terminal
  209
+            # may be left in a bizarre state.
  210
+            import signal
  211
+            oldint = signal.signal(signal.SIGINT, signal.SIG_IGN)
  212
+            def hook():
  213
+                time.sleep(0.1)
  214
+            if _input_hook_manager.get_pyos_inputhook():
  215
+                hook = _input_hook_manager.get_pyos_inputhook_as_func()
  216
+            pager = subprocess.Popen(pager_cmd, shell=True,
  217
+                                        stdin=subprocess.PIPE)
  218
+            pager.stdin.write(strng)
  219
+            pager.stdin.close()
  220
+            while pager.poll() is None: # sets and returns pager.returncode
  221
+                hook()
  222
+                # The PyOS_InputHook provided by qt4 and gtk
  223
+                # blocks until the pager process ends; I don't know
  224
+                # how this notification occurs.
  225
+                # Usually, the user has to hit CR to get the prompt
  226
+                # displayed, although even if it isn't, the input
  227
+                # line is processed.
  228
+                # Tk is not setting the input hook, and doesn't work
  229
+                # with this code; if there is plot displayed, the
  230
+                # terminal hangs upon returning from the pager.
  231
+
  232
+            if pager.returncode <=0:  # normally 0; negative for signal;
  233
+                                      # pager ran, so we have finished.
  234
+                retval = None
  235
+            else:
217 236
                 retval = 1
218  
-        if retval is not None:
219  
-            page_dumb(strng,screen_lines=screen_lines)
  237
+
  238
+        except OSError:
  239
+            # Other strange problems, sometimes seen in Win2k/cygwin
  240
+            retval = 1
  241
+        finally:
  242
+            signal.signal(signal.SIGINT, oldint)
  243
+
  244
+    if retval is not None:
  245
+        page_dumb(strng,screen_lines=screen_lines)
  246
+
  247
+
220 248
 
221 249
 
222 250
 def page_file(fname, start=0, pager_cmd=None):
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.