##// END OF EJS Templates
Merge pull request #4542 from ivanov/history-clear...
Min RK -
r13694:24e10561 merge
parent child Browse files
Show More
@@ -0,0 +1,1 b''
1 * bash completion updated with support for all ipython subcommands and flags, including nbconvert
@@ -0,0 +1,4 b''
1 * ``ipython history trim``: added ``--keep=<N>`` as an alias for the more verbose
2 ``--HistoryTrim.keep=<N>``
3 * new ``ipython history clear`` subcommand, which is the same as the newly supported
4 ``ipython history trim --keep=0``
@@ -1,119 +1,159 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An application for managing IPython history.
3 An application for managing IPython history.
4
4
5 To be invoked as the `ipython history` subcommand.
5 To be invoked as the `ipython history` subcommand.
6 """
6 """
7 from __future__ import print_function
7 from __future__ import print_function
8
8
9 import os
9 import os
10 import sqlite3
10 import sqlite3
11
11
12 from IPython.config.application import Application
12 from IPython.config.application import Application
13 from IPython.core.application import BaseIPythonApplication
13 from IPython.core.application import BaseIPythonApplication
14 from IPython.utils.traitlets import Bool, Int, Dict
14 from IPython.utils.traitlets import Bool, Int, Dict
15 from IPython.utils.io import ask_yes_no
15
16
16 trim_hist_help = """Trim the IPython history database to the last 1000 entries.
17 trim_hist_help = """Trim the IPython history database to the last 1000 entries.
17
18
18 This actually copies the last 1000 entries to a new database, and then replaces
19 This actually copies the last 1000 entries to a new database, and then replaces
19 the old file with the new.
20 the old file with the new. Use the `--keep=` argument to specify a number
21 other than 1000.
20 """
22 """
21
23
24 clear_hist_help = """Clear the IPython history database, deleting all entries.
25
26 Because this is a destructive operation, IPython will prompt the user if they
27 really want to do this. Passing a `-f` flag will force clearing without a
28 prompt.
29
30 This is an handy alias to `ipython history trim --keep=0`
31 """
32
33
22 class HistoryTrim(BaseIPythonApplication):
34 class HistoryTrim(BaseIPythonApplication):
23 description = trim_hist_help
35 description = trim_hist_help
24
36
25 backup = Bool(False, config=True,
37 backup = Bool(False, config=True,
26 help="Keep the old history file as history.sqlite.<N>")
38 help="Keep the old history file as history.sqlite.<N>")
27
39
28 keep = Int(1000, config=True,
40 keep = Int(1000, config=True,
29 help="Number of recent lines to keep in the database.")
41 help="Number of recent lines to keep in the database.")
30
42
31 flags = Dict(dict(
43 flags = Dict(dict(
32 backup = ({'HistoryTrim' : {'backup' : True}},
44 backup = ({'HistoryTrim' : {'backup' : True}},
33 "Set Application.log_level to 0, maximizing log output."
45 backup.get_metadata('help')
34 )
46 )
35 ))
47 ))
48
49 aliases=Dict(dict(
50 keep = 'HistoryTrim.keep'
51 ))
36
52
37 def start(self):
53 def start(self):
38 profile_dir = self.profile_dir.location
54 profile_dir = self.profile_dir.location
39 hist_file = os.path.join(profile_dir, 'history.sqlite')
55 hist_file = os.path.join(profile_dir, 'history.sqlite')
40 con = sqlite3.connect(hist_file)
56 con = sqlite3.connect(hist_file)
41
57
42 # Grab the recent history from the current database.
58 # Grab the recent history from the current database.
43 inputs = list(con.execute('SELECT session, line, source, source_raw FROM '
59 inputs = list(con.execute('SELECT session, line, source, source_raw FROM '
44 'history ORDER BY session DESC, line DESC LIMIT ?', (self.keep+1,)))
60 'history ORDER BY session DESC, line DESC LIMIT ?', (self.keep+1,)))
45 if len(inputs) <= self.keep:
61 if len(inputs) <= self.keep:
46 print("There are already at most %d entries in the history database." % self.keep)
62 print("There are already at most %d entries in the history database." % self.keep)
47 print("Not doing anything.")
63 print("Not doing anything. Use --keep= argument to keep fewer entries")
48 return
64 return
49
65
50 print("Trimming history to the most recent %d entries." % self.keep)
66 print("Trimming history to the most recent %d entries." % self.keep)
51
67
52 inputs.pop() # Remove the extra element we got to check the length.
68 inputs.pop() # Remove the extra element we got to check the length.
53 inputs.reverse()
69 inputs.reverse()
54 first_session = inputs[0][0]
70 if inputs:
55 outputs = list(con.execute('SELECT session, line, output FROM '
71 first_session = inputs[0][0]
56 'output_history WHERE session >= ?', (first_session,)))
72 outputs = list(con.execute('SELECT session, line, output FROM '
57 sessions = list(con.execute('SELECT session, start, end, num_cmds, remark FROM '
73 'output_history WHERE session >= ?', (first_session,)))
58 'sessions WHERE session >= ?', (first_session,)))
74 sessions = list(con.execute('SELECT session, start, end, num_cmds, remark FROM '
75 'sessions WHERE session >= ?', (first_session,)))
59 con.close()
76 con.close()
60
77
61 # Create the new history database.
78 # Create the new history database.
62 new_hist_file = os.path.join(profile_dir, 'history.sqlite.new')
79 new_hist_file = os.path.join(profile_dir, 'history.sqlite.new')
63 i = 0
80 i = 0
64 while os.path.exists(new_hist_file):
81 while os.path.exists(new_hist_file):
65 # Make sure we don't interfere with an existing file.
82 # Make sure we don't interfere with an existing file.
66 i += 1
83 i += 1
67 new_hist_file = os.path.join(profile_dir, 'history.sqlite.new'+str(i))
84 new_hist_file = os.path.join(profile_dir, 'history.sqlite.new'+str(i))
68 new_db = sqlite3.connect(new_hist_file)
85 new_db = sqlite3.connect(new_hist_file)
69 new_db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
86 new_db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
70 primary key autoincrement, start timestamp,
87 primary key autoincrement, start timestamp,
71 end timestamp, num_cmds integer, remark text)""")
88 end timestamp, num_cmds integer, remark text)""")
72 new_db.execute("""CREATE TABLE IF NOT EXISTS history
89 new_db.execute("""CREATE TABLE IF NOT EXISTS history
73 (session integer, line integer, source text, source_raw text,
90 (session integer, line integer, source text, source_raw text,
74 PRIMARY KEY (session, line))""")
91 PRIMARY KEY (session, line))""")
75 new_db.execute("""CREATE TABLE IF NOT EXISTS output_history
92 new_db.execute("""CREATE TABLE IF NOT EXISTS output_history
76 (session integer, line integer, output text,
93 (session integer, line integer, output text,
77 PRIMARY KEY (session, line))""")
94 PRIMARY KEY (session, line))""")
78 new_db.commit()
95 new_db.commit()
79
96
80
97
81 with new_db:
98 if inputs:
82 # Add the recent history into the new database.
99 with new_db:
83 new_db.executemany('insert into sessions values (?,?,?,?,?)', sessions)
100 # Add the recent history into the new database.
84 new_db.executemany('insert into history values (?,?,?,?)', inputs)
101 new_db.executemany('insert into sessions values (?,?,?,?,?)', sessions)
85 new_db.executemany('insert into output_history values (?,?,?)', outputs)
102 new_db.executemany('insert into history values (?,?,?,?)', inputs)
103 new_db.executemany('insert into output_history values (?,?,?)', outputs)
86 new_db.close()
104 new_db.close()
87
105
88 if self.backup:
106 if self.backup:
89 i = 1
107 i = 1
90 backup_hist_file = os.path.join(profile_dir, 'history.sqlite.old.%d' % i)
108 backup_hist_file = os.path.join(profile_dir, 'history.sqlite.old.%d' % i)
91 while os.path.exists(backup_hist_file):
109 while os.path.exists(backup_hist_file):
92 i += 1
110 i += 1
93 backup_hist_file = os.path.join(profile_dir, 'history.sqlite.old.%d' % i)
111 backup_hist_file = os.path.join(profile_dir, 'history.sqlite.old.%d' % i)
94 os.rename(hist_file, backup_hist_file)
112 os.rename(hist_file, backup_hist_file)
95 print("Backed up longer history file to", backup_hist_file)
113 print("Backed up longer history file to", backup_hist_file)
96 else:
114 else:
97 os.remove(hist_file)
115 os.remove(hist_file)
98
116
99 os.rename(new_hist_file, hist_file)
117 os.rename(new_hist_file, hist_file)
100
118
119 class HistoryClear(HistoryTrim):
120 description = clear_hist_help
121 keep = Int(0, config=False,
122 help="Number of recent lines to keep in the database.")
123
124 force = Bool(False, config=True,
125 help="Don't prompt user for confirmation")
126
127 flags = Dict(dict(
128 force = ({'HistoryClear' : {'force' : True}},
129 force.get_metadata('help')),
130 f = ({'HistoryTrim' : {'force' : True}},
131 force.get_metadata('help')
132 )
133 ))
134 aliases = Dict()
135
136 def start(self):
137 if self.force or ask_yes_no("Really delete all ipython history? ",
138 default="no", interrupt="no"):
139 HistoryTrim.start(self)
101
140
102 class HistoryApp(Application):
141 class HistoryApp(Application):
103 name = u'ipython-history'
142 name = u'ipython-history'
104 description = "Manage the IPython history database."
143 description = "Manage the IPython history database."
105
144
106 subcommands = Dict(dict(
145 subcommands = Dict(dict(
107 trim = (HistoryTrim, HistoryTrim.description.splitlines()[0]),
146 trim = (HistoryTrim, HistoryTrim.description.splitlines()[0]),
147 clear = (HistoryClear, HistoryClear.description.splitlines()[0]),
108 ))
148 ))
109
149
110 def start(self):
150 def start(self):
111 if self.subapp is None:
151 if self.subapp is None:
112 print("No subcommand specified. Must specify one of: %s" % \
152 print("No subcommand specified. Must specify one of: %s" % \
113 (self.subcommands.keys()))
153 (self.subcommands.keys()))
114 print()
154 print()
115 self.print_description()
155 self.print_description()
116 self.print_subcommands()
156 self.print_subcommands()
117 self.exit(1)
157 self.exit(1)
118 else:
158 else:
119 return self.subapp.start()
159 return self.subapp.start()
@@ -1,229 +1,232 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 IO related utilities.
3 IO related utilities.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 from __future__ import print_function
12 from __future__ import print_function
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 import os
17 import os
18 import sys
18 import sys
19 import tempfile
19 import tempfile
20 from .capture import CapturedIO, capture_output
20 from .capture import CapturedIO, capture_output
21 from .py3compat import string_types, input
21 from .py3compat import string_types, input
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Code
24 # Code
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27
27
28 class IOStream:
28 class IOStream:
29
29
30 def __init__(self,stream, fallback=None):
30 def __init__(self,stream, fallback=None):
31 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
31 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
32 if fallback is not None:
32 if fallback is not None:
33 stream = fallback
33 stream = fallback
34 else:
34 else:
35 raise ValueError("fallback required, but not specified")
35 raise ValueError("fallback required, but not specified")
36 self.stream = stream
36 self.stream = stream
37 self._swrite = stream.write
37 self._swrite = stream.write
38
38
39 # clone all methods not overridden:
39 # clone all methods not overridden:
40 def clone(meth):
40 def clone(meth):
41 return not hasattr(self, meth) and not meth.startswith('_')
41 return not hasattr(self, meth) and not meth.startswith('_')
42 for meth in filter(clone, dir(stream)):
42 for meth in filter(clone, dir(stream)):
43 setattr(self, meth, getattr(stream, meth))
43 setattr(self, meth, getattr(stream, meth))
44
44
45 def write(self,data):
45 def write(self,data):
46 try:
46 try:
47 self._swrite(data)
47 self._swrite(data)
48 except:
48 except:
49 try:
49 try:
50 # print handles some unicode issues which may trip a plain
50 # print handles some unicode issues which may trip a plain
51 # write() call. Emulate write() by using an empty end
51 # write() call. Emulate write() by using an empty end
52 # argument.
52 # argument.
53 print(data, end='', file=self.stream)
53 print(data, end='', file=self.stream)
54 except:
54 except:
55 # if we get here, something is seriously broken.
55 # if we get here, something is seriously broken.
56 print('ERROR - failed to write data to stream:', self.stream,
56 print('ERROR - failed to write data to stream:', self.stream,
57 file=sys.stderr)
57 file=sys.stderr)
58
58
59 def writelines(self, lines):
59 def writelines(self, lines):
60 if isinstance(lines, string_types):
60 if isinstance(lines, string_types):
61 lines = [lines]
61 lines = [lines]
62 for line in lines:
62 for line in lines:
63 self.write(line)
63 self.write(line)
64
64
65 # This class used to have a writeln method, but regular files and streams
65 # This class used to have a writeln method, but regular files and streams
66 # in Python don't have this method. We need to keep this completely
66 # in Python don't have this method. We need to keep this completely
67 # compatible so we removed it.
67 # compatible so we removed it.
68
68
69 @property
69 @property
70 def closed(self):
70 def closed(self):
71 return self.stream.closed
71 return self.stream.closed
72
72
73 def close(self):
73 def close(self):
74 pass
74 pass
75
75
76 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
76 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
77 devnull = open(os.devnull, 'a')
77 devnull = open(os.devnull, 'a')
78 stdin = IOStream(sys.stdin, fallback=devnull)
78 stdin = IOStream(sys.stdin, fallback=devnull)
79 stdout = IOStream(sys.stdout, fallback=devnull)
79 stdout = IOStream(sys.stdout, fallback=devnull)
80 stderr = IOStream(sys.stderr, fallback=devnull)
80 stderr = IOStream(sys.stderr, fallback=devnull)
81
81
82 class IOTerm:
82 class IOTerm:
83 """ Term holds the file or file-like objects for handling I/O operations.
83 """ Term holds the file or file-like objects for handling I/O operations.
84
84
85 These are normally just sys.stdin, sys.stdout and sys.stderr but for
85 These are normally just sys.stdin, sys.stdout and sys.stderr but for
86 Windows they can can replaced to allow editing the strings before they are
86 Windows they can can replaced to allow editing the strings before they are
87 displayed."""
87 displayed."""
88
88
89 # In the future, having IPython channel all its I/O operations through
89 # In the future, having IPython channel all its I/O operations through
90 # this class will make it easier to embed it into other environments which
90 # this class will make it easier to embed it into other environments which
91 # are not a normal terminal (such as a GUI-based shell)
91 # are not a normal terminal (such as a GUI-based shell)
92 def __init__(self, stdin=None, stdout=None, stderr=None):
92 def __init__(self, stdin=None, stdout=None, stderr=None):
93 mymodule = sys.modules[__name__]
93 mymodule = sys.modules[__name__]
94 self.stdin = IOStream(stdin, mymodule.stdin)
94 self.stdin = IOStream(stdin, mymodule.stdin)
95 self.stdout = IOStream(stdout, mymodule.stdout)
95 self.stdout = IOStream(stdout, mymodule.stdout)
96 self.stderr = IOStream(stderr, mymodule.stderr)
96 self.stderr = IOStream(stderr, mymodule.stderr)
97
97
98
98
99 class Tee(object):
99 class Tee(object):
100 """A class to duplicate an output stream to stdout/err.
100 """A class to duplicate an output stream to stdout/err.
101
101
102 This works in a manner very similar to the Unix 'tee' command.
102 This works in a manner very similar to the Unix 'tee' command.
103
103
104 When the object is closed or deleted, it closes the original file given to
104 When the object is closed or deleted, it closes the original file given to
105 it for duplication.
105 it for duplication.
106 """
106 """
107 # Inspired by:
107 # Inspired by:
108 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
108 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
109
109
110 def __init__(self, file_or_name, mode="w", channel='stdout'):
110 def __init__(self, file_or_name, mode="w", channel='stdout'):
111 """Construct a new Tee object.
111 """Construct a new Tee object.
112
112
113 Parameters
113 Parameters
114 ----------
114 ----------
115 file_or_name : filename or open filehandle (writable)
115 file_or_name : filename or open filehandle (writable)
116 File that will be duplicated
116 File that will be duplicated
117
117
118 mode : optional, valid mode for open().
118 mode : optional, valid mode for open().
119 If a filename was give, open with this mode.
119 If a filename was give, open with this mode.
120
120
121 channel : str, one of ['stdout', 'stderr']
121 channel : str, one of ['stdout', 'stderr']
122 """
122 """
123 if channel not in ['stdout', 'stderr']:
123 if channel not in ['stdout', 'stderr']:
124 raise ValueError('Invalid channel spec %s' % channel)
124 raise ValueError('Invalid channel spec %s' % channel)
125
125
126 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
126 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
127 self.file = file_or_name
127 self.file = file_or_name
128 else:
128 else:
129 self.file = open(file_or_name, mode)
129 self.file = open(file_or_name, mode)
130 self.channel = channel
130 self.channel = channel
131 self.ostream = getattr(sys, channel)
131 self.ostream = getattr(sys, channel)
132 setattr(sys, channel, self)
132 setattr(sys, channel, self)
133 self._closed = False
133 self._closed = False
134
134
135 def close(self):
135 def close(self):
136 """Close the file and restore the channel."""
136 """Close the file and restore the channel."""
137 self.flush()
137 self.flush()
138 setattr(sys, self.channel, self.ostream)
138 setattr(sys, self.channel, self.ostream)
139 self.file.close()
139 self.file.close()
140 self._closed = True
140 self._closed = True
141
141
142 def write(self, data):
142 def write(self, data):
143 """Write data to both channels."""
143 """Write data to both channels."""
144 self.file.write(data)
144 self.file.write(data)
145 self.ostream.write(data)
145 self.ostream.write(data)
146 self.ostream.flush()
146 self.ostream.flush()
147
147
148 def flush(self):
148 def flush(self):
149 """Flush both channels."""
149 """Flush both channels."""
150 self.file.flush()
150 self.file.flush()
151 self.ostream.flush()
151 self.ostream.flush()
152
152
153 def __del__(self):
153 def __del__(self):
154 if not self._closed:
154 if not self._closed:
155 self.close()
155 self.close()
156
156
157
157
158 def ask_yes_no(prompt,default=None):
158 def ask_yes_no(prompt, default=None, interrupt=None):
159 """Asks a question and returns a boolean (y/n) answer.
159 """Asks a question and returns a boolean (y/n) answer.
160
160
161 If default is given (one of 'y','n'), it is used if the user input is
161 If default is given (one of 'y','n'), it is used if the user input is
162 empty. Otherwise the question is repeated until an answer is given.
162 empty. If interrupt is given (one of 'y','n'), it is used if the user
163 presses Ctrl-C. Otherwise the question is repeated until an answer is
164 given.
163
165
164 An EOF is treated as the default answer. If there is no default, an
166 An EOF is treated as the default answer. If there is no default, an
165 exception is raised to prevent infinite loops.
167 exception is raised to prevent infinite loops.
166
168
167 Valid answers are: y/yes/n/no (match is not case sensitive)."""
169 Valid answers are: y/yes/n/no (match is not case sensitive)."""
168
170
169 answers = {'y':True,'n':False,'yes':True,'no':False}
171 answers = {'y':True,'n':False,'yes':True,'no':False}
170 ans = None
172 ans = None
171 while ans not in answers.keys():
173 while ans not in answers.keys():
172 try:
174 try:
173 ans = input(prompt+' ').lower()
175 ans = input(prompt+' ').lower()
174 if not ans: # response was an empty string
176 if not ans: # response was an empty string
175 ans = default
177 ans = default
176 except KeyboardInterrupt:
178 except KeyboardInterrupt:
177 pass
179 if interrupt:
180 ans = interrupt
178 except EOFError:
181 except EOFError:
179 if default in answers.keys():
182 if default in answers.keys():
180 ans = default
183 ans = default
181 print()
184 print()
182 else:
185 else:
183 raise
186 raise
184
187
185 return answers[ans]
188 return answers[ans]
186
189
187
190
188 def temp_pyfile(src, ext='.py'):
191 def temp_pyfile(src, ext='.py'):
189 """Make a temporary python file, return filename and filehandle.
192 """Make a temporary python file, return filename and filehandle.
190
193
191 Parameters
194 Parameters
192 ----------
195 ----------
193 src : string or list of strings (no need for ending newlines if list)
196 src : string or list of strings (no need for ending newlines if list)
194 Source code to be written to the file.
197 Source code to be written to the file.
195
198
196 ext : optional, string
199 ext : optional, string
197 Extension for the generated file.
200 Extension for the generated file.
198
201
199 Returns
202 Returns
200 -------
203 -------
201 (filename, open filehandle)
204 (filename, open filehandle)
202 It is the caller's responsibility to close the open file and unlink it.
205 It is the caller's responsibility to close the open file and unlink it.
203 """
206 """
204 fname = tempfile.mkstemp(ext)[1]
207 fname = tempfile.mkstemp(ext)[1]
205 f = open(fname,'w')
208 f = open(fname,'w')
206 f.write(src)
209 f.write(src)
207 f.flush()
210 f.flush()
208 return fname, f
211 return fname, f
209
212
210
213
211 def raw_print(*args, **kw):
214 def raw_print(*args, **kw):
212 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
215 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
213
216
214 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
217 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
215 file=sys.__stdout__)
218 file=sys.__stdout__)
216 sys.__stdout__.flush()
219 sys.__stdout__.flush()
217
220
218
221
219 def raw_print_err(*args, **kw):
222 def raw_print_err(*args, **kw):
220 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
223 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
221
224
222 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
225 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
223 file=sys.__stderr__)
226 file=sys.__stderr__)
224 sys.__stderr__.flush()
227 sys.__stderr__.flush()
225
228
226
229
227 # Short aliases for quick debugging, do NOT use these in production code.
230 # Short aliases for quick debugging, do NOT use these in production code.
228 rprint = raw_print
231 rprint = raw_print
229 rprinte = raw_print_err
232 rprinte = raw_print_err
@@ -1,115 +1,131 b''
1 # load with: . ipython-completion.bash
1 # load with: . ipython-completion.bash
2
2
3 if [[ -n ${ZSH_VERSION-} ]]; then
3 if [[ -n ${ZSH_VERSION-} ]]; then
4 autoload -Uz bashcompinit && bashcompinit
4 autoload -Uz bashcompinit && bashcompinit
5 fi
5 fi
6
6
7 _ipython_get_flags()
7 _ipython_get_flags()
8 {
8 {
9 local url=$1
9 local url=$1
10 local var=$2
10 local var=$2
11 local dash=$3
11 local dash=$3
12 if [[ "$url $var" == $__ipython_complete_last ]]; then
12 if [[ "$url $var" == $__ipython_complete_last ]]; then
13 opts=$__ipython_complete_last_res
13 opts=$__ipython_complete_last_res
14 return
14 return
15 fi
15 fi
16 # pylab and profile don't need the = and the
16 # pylab and profile don't need the = and the
17 # version without simplifies the special cased completion
17 # version without simplifies the special cased completion
18 opts=$(ipython ${url} --help-all | grep -E "^-{1,2}[^-]" | sed -e "s/<.*//" -e "s/[^=]$/& /" -e "s/^--pylab=$//" -e "s/^--profile=$/--profile /")
18 opts=$(ipython ${url} --help-all | grep -E "^-{1,2}[^-]" | sed -e "s/<.*//" -e "s/[^=]$/& /" -e "s/^--pylab=$//" -e "s/^--profile=$/--profile /")
19 __ipython_complete_last="$url $var"
19 __ipython_complete_last="$url $var"
20 __ipython_complete_last_res="$opts"
20 __ipython_complete_last_res="$opts"
21 }
21 }
22
22
23 _ipython()
23 _ipython()
24 {
24 {
25 local cur=${COMP_WORDS[COMP_CWORD]}
25 local cur=${COMP_WORDS[COMP_CWORD]}
26 local prev=${COMP_WORDS[COMP_CWORD - 1]}
26 local prev=${COMP_WORDS[COMP_CWORD - 1]}
27 local subcommands="notebook qtconsole console kernel profile locate history nbconvert"
27 local subcommands="notebook qtconsole console kernel profile locate history nbconvert "
28 local opts=""
28 local opts=""
29 if [ -z "$__ipython_complete_baseopts" ]; then
29 if [ -z "$__ipython_complete_baseopts" ]; then
30 _ipython_get_flags baseopts
30 _ipython_get_flags baseopts
31 __ipython_complete_baseopts="${opts}"
31 __ipython_complete_baseopts="${opts}"
32 fi
32 fi
33 local baseopts="$__ipython_complete_baseopts"
33 local baseopts="$__ipython_complete_baseopts"
34 local mode=""
34 local mode=""
35 for i in "${COMP_WORDS[@]}"; do
35 for i in "${COMP_WORDS[@]}"; do
36 [ "$cur" = "$i" ] && break
36 [ "$cur" = "$i" ] && break
37 if [[ ${subcommands} == *${i}* ]]; then
37 if [[ ${subcommands} == *${i}* ]]; then
38 mode="$i"
38 mode="$i"
39 break
39 break
40 elif [[ ${i} == "--"* ]]; then
40 elif [[ ${i} == "--"* ]]; then
41 mode="nosubcommand"
41 mode="nosubcommand"
42 break
42 break
43 fi
43 fi
44 done
44 done
45
45
46
46
47 if [[ ${cur} == -* ]]; then
47 if [[ ${cur} == -* ]]; then
48 case $mode in
48 case $mode in
49 "notebook" | "qtconsole" | "console" | "kernel")
49 "notebook" | "qtconsole" | "console" | "kernel" | "nbconvert")
50 _ipython_get_flags $mode
50 _ipython_get_flags $mode
51 opts=$"${opts} ${baseopts}"
51 opts=$"${opts} ${baseopts}"
52 ;;
52 ;;
53 "locate" | "history" | "profile")
53 "locate" | "profile")
54 _ipython_get_flags $mode
54 _ipython_get_flags $mode
55 ;;
56 "history")
57 if [[ $COMP_CWORD -ge 3 ]]; then
58 # 'history trim' and 'history clear' covered by next line
59 _ipython_get_flags history\ "${COMP_WORDS[2]}"
60 else
61 _ipython_get_flags $mode
62
63 fi
55 opts=$"${opts}"
64 opts=$"${opts}"
56 ;;
65 ;;
57 *)
66 *)
58 opts=$baseopts
67 opts=$baseopts
59 esac
68 esac
60 # don't drop the trailing space
69 # don't drop the trailing space
61 local IFS=$'\t\n'
70 local IFS=$'\t\n'
62 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
71 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
63 return 0
72 return 0
64 elif [[ $mode == "profile" ]]; then
73 elif [[ $mode == "profile" ]]; then
65 opts="list create locate"
74 opts="list create locate "
75 local IFS=$'\t\n'
66 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
76 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
67 elif [[ $mode == "history" ]]; then
77 elif [[ $mode == "history" ]]; then
68 opts="trim"
78 if [[ $COMP_CWORD -ge 3 ]]; then
79 # drop into flags
80 opts="--"
81 else
82 opts="trim clear "
83 fi
84 local IFS=$'\t\n'
69 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
85 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
70 elif [[ $mode == "locate" ]]; then
86 elif [[ $mode == "locate" ]]; then
71 opts="profile"
87 opts="profile"
72 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
88 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
73 elif [[ ${prev} == "--pylab"* ]] || [[ ${prev} == "--gui"* ]]; then
89 elif [[ ${prev} == "--pylab"* ]] || [[ ${prev} == "--gui"* ]]; then
74 if [ -z "$__ipython_complete_pylab" ]; then
90 if [ -z "$__ipython_complete_pylab" ]; then
75 __ipython_complete_pylab=`cat <<EOF | python -
91 __ipython_complete_pylab=`cat <<EOF | python -
76 try:
92 try:
77 import IPython.core.shellapp as mod;
93 import IPython.core.shellapp as mod;
78 for k in mod.InteractiveShellApp.pylab.values:
94 for k in mod.InteractiveShellApp.pylab.values:
79 print "%s " % k
95 print "%s " % k
80 except:
96 except:
81 pass
97 pass
82 EOF
98 EOF
83 `
99 `
84 fi
100 fi
85 local IFS=$'\t\n'
101 local IFS=$'\t\n'
86 COMPREPLY=( $(compgen -W "${__ipython_complete_pylab}" -- ${cur}) )
102 COMPREPLY=( $(compgen -W "${__ipython_complete_pylab}" -- ${cur}) )
87 elif [[ ${prev} == "--profile"* ]]; then
103 elif [[ ${prev} == "--profile"* ]]; then
88 if [ -z "$__ipython_complete_profiles" ]; then
104 if [ -z "$__ipython_complete_profiles" ]; then
89 __ipython_complete_profiles=`cat <<EOF | python -
105 __ipython_complete_profiles=`cat <<EOF | python -
90 try:
106 try:
91 import IPython.core.profileapp
107 import IPython.core.profileapp
92 for k in IPython.core.profileapp.list_bundled_profiles():
108 for k in IPython.core.profileapp.list_bundled_profiles():
93 print "%s " % k
109 print "%s " % k
94 p = IPython.core.profileapp.ProfileList()
110 p = IPython.core.profileapp.ProfileList()
95 for k in IPython.core.profileapp.list_profiles_in(p.ipython_dir):
111 for k in IPython.core.profileapp.list_profiles_in(p.ipython_dir):
96 print "%s " % k
112 print "%s " % k
97 except:
113 except:
98 pass
114 pass
99 EOF
115 EOF
100 `
116 `
101 fi
117 fi
102 local IFS=$'\t\n'
118 local IFS=$'\t\n'
103 COMPREPLY=( $(compgen -W "${__ipython_complete_profiles}" -- ${cur}) )
119 COMPREPLY=( $(compgen -W "${__ipython_complete_profiles}" -- ${cur}) )
104 else
120 else
105 if [ "$COMP_CWORD" == 1 ]; then
121 if [ "$COMP_CWORD" == 1 ]; then
106 local IFS=$'\t\n'
122 local IFS=$'\t\n'
107 local sub=$(echo $subcommands | sed -e "s/ / \t/g")
123 local sub=$(echo $subcommands | sed -e "s/ / \t/g")
108 COMPREPLY=( $(compgen -W "${sub}" -- ${cur}) )
124 COMPREPLY=( $(compgen -W "${sub}" -- ${cur}) )
109 else
125 else
110 COMPREPLY=( $(compgen -f -- ${cur}) )
126 COMPREPLY=( $(compgen -f -- ${cur}) )
111 fi
127 fi
112 fi
128 fi
113
129
114 }
130 }
115 complete -o default -o nospace -F _ipython ipython
131 complete -o default -o nospace -F _ipython ipython
General Comments 0
You need to be logged in to leave comments. Login now