##// END OF EJS Templates
added comment on reason for seperate ls_alias for OpenBSD/NetBSD
bsvh -
Show More
@@ -1,252 +1,253 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 System command aliases.
3 System command aliases.
4
4
5 Authors:
5 Authors:
6
6
7 * Fernando Perez
7 * Fernando Perez
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License.
14 # Distributed under the terms of the BSD License.
15 #
15 #
16 # The full license is in the file COPYING.txt, distributed with this software.
16 # The full license is in the file COPYING.txt, distributed with this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import os
23 import os
24 import re
24 import re
25 import sys
25 import sys
26
26
27 from IPython.config.configurable import Configurable
27 from IPython.config.configurable import Configurable
28 from IPython.core.error import UsageError
28 from IPython.core.error import UsageError
29
29
30 from IPython.utils.py3compat import string_types
30 from IPython.utils.py3compat import string_types
31 from IPython.utils.traitlets import List, Instance
31 from IPython.utils.traitlets import List, Instance
32 from IPython.utils.warn import error
32 from IPython.utils.warn import error
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Utilities
35 # Utilities
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38 # This is used as the pattern for calls to split_user_input.
38 # This is used as the pattern for calls to split_user_input.
39 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
39 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
40
40
41 def default_aliases():
41 def default_aliases():
42 """Return list of shell aliases to auto-define.
42 """Return list of shell aliases to auto-define.
43 """
43 """
44 # Note: the aliases defined here should be safe to use on a kernel
44 # Note: the aliases defined here should be safe to use on a kernel
45 # regardless of what frontend it is attached to. Frontends that use a
45 # regardless of what frontend it is attached to. Frontends that use a
46 # kernel in-process can define additional aliases that will only work in
46 # kernel in-process can define additional aliases that will only work in
47 # their case. For example, things like 'less' or 'clear' that manipulate
47 # their case. For example, things like 'less' or 'clear' that manipulate
48 # the terminal should NOT be declared here, as they will only work if the
48 # the terminal should NOT be declared here, as they will only work if the
49 # kernel is running inside a true terminal, and not over the network.
49 # kernel is running inside a true terminal, and not over the network.
50
50
51 if os.name == 'posix':
51 if os.name == 'posix':
52 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
52 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
53 ('mv', 'mv'), ('rm', 'rm'), ('cp', 'cp'),
53 ('mv', 'mv'), ('rm', 'rm'), ('cp', 'cp'),
54 ('cat', 'cat'),
54 ('cat', 'cat'),
55 ]
55 ]
56 # Useful set of ls aliases. The GNU and BSD options are a little
56 # Useful set of ls aliases. The GNU and BSD options are a little
57 # different, so we make aliases that provide as similar as possible
57 # different, so we make aliases that provide as similar as possible
58 # behavior in ipython, by passing the right flags for each platform
58 # behavior in ipython, by passing the right flags for each platform
59 if sys.platform.startswith('linux'):
59 if sys.platform.startswith('linux'):
60 ls_aliases = [('ls', 'ls -F --color'),
60 ls_aliases = [('ls', 'ls -F --color'),
61 # long ls
61 # long ls
62 ('ll', 'ls -F -o --color'),
62 ('ll', 'ls -F -o --color'),
63 # ls normal files only
63 # ls normal files only
64 ('lf', 'ls -F -o --color %l | grep ^-'),
64 ('lf', 'ls -F -o --color %l | grep ^-'),
65 # ls symbolic links
65 # ls symbolic links
66 ('lk', 'ls -F -o --color %l | grep ^l'),
66 ('lk', 'ls -F -o --color %l | grep ^l'),
67 # directories or links to directories,
67 # directories or links to directories,
68 ('ldir', 'ls -F -o --color %l | grep /$'),
68 ('ldir', 'ls -F -o --color %l | grep /$'),
69 # things which are executable
69 # things which are executable
70 ('lx', 'ls -F -o --color %l | grep ^-..x'),
70 ('lx', 'ls -F -o --color %l | grep ^-..x'),
71 ]
71 ]
72 elif sys.platform.startswith('openbsd') or sys.platform.startswith('netbsd'):
72 elif sys.platform.startswith('openbsd') or sys.platform.startswith('netbsd'):
73 # OpenBSD, NetBSD
73 # OpenBSD, NetBSD. The ls implementation on these platforms do not support
74 # the -G switch and lack the ability to use colorized output.
74 ls_aliases = [('ls', 'ls -F'),
75 ls_aliases = [('ls', 'ls -F'),
75 # long ls
76 # long ls
76 ('ll', 'ls -F -l'),
77 ('ll', 'ls -F -l'),
77 # ls normal files only
78 # ls normal files only
78 ('lf', 'ls -F -l %l | grep ^-'),
79 ('lf', 'ls -F -l %l | grep ^-'),
79 # ls symbolic links
80 # ls symbolic links
80 ('lk', 'ls -F -l %l | grep ^l'),
81 ('lk', 'ls -F -l %l | grep ^l'),
81 # directories or links to directories,
82 # directories or links to directories,
82 ('ldir', 'ls -F -l %l | grep /$'),
83 ('ldir', 'ls -F -l %l | grep /$'),
83 # things which are executable
84 # things which are executable
84 ('lx', 'ls -F -l %l | grep ^-..x'),
85 ('lx', 'ls -F -l %l | grep ^-..x'),
85 ]
86 ]
86 else:
87 else:
87 # BSD, OSX, etc.
88 # BSD, OSX, etc.
88 ls_aliases = [('ls', 'ls -F -G'),
89 ls_aliases = [('ls', 'ls -F -G'),
89 # long ls
90 # long ls
90 ('ll', 'ls -F -l -G'),
91 ('ll', 'ls -F -l -G'),
91 # ls normal files only
92 # ls normal files only
92 ('lf', 'ls -F -l -G %l | grep ^-'),
93 ('lf', 'ls -F -l -G %l | grep ^-'),
93 # ls symbolic links
94 # ls symbolic links
94 ('lk', 'ls -F -l -G %l | grep ^l'),
95 ('lk', 'ls -F -l -G %l | grep ^l'),
95 # directories or links to directories,
96 # directories or links to directories,
96 ('ldir', 'ls -F -G -l %l | grep /$'),
97 ('ldir', 'ls -F -G -l %l | grep /$'),
97 # things which are executable
98 # things which are executable
98 ('lx', 'ls -F -l -G %l | grep ^-..x'),
99 ('lx', 'ls -F -l -G %l | grep ^-..x'),
99 ]
100 ]
100 default_aliases = default_aliases + ls_aliases
101 default_aliases = default_aliases + ls_aliases
101 elif os.name in ['nt', 'dos']:
102 elif os.name in ['nt', 'dos']:
102 default_aliases = [('ls', 'dir /on'),
103 default_aliases = [('ls', 'dir /on'),
103 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
104 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
104 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
105 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
105 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
106 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
106 ]
107 ]
107 else:
108 else:
108 default_aliases = []
109 default_aliases = []
109
110
110 return default_aliases
111 return default_aliases
111
112
112
113
113 class AliasError(Exception):
114 class AliasError(Exception):
114 pass
115 pass
115
116
116
117
117 class InvalidAliasError(AliasError):
118 class InvalidAliasError(AliasError):
118 pass
119 pass
119
120
120 class Alias(object):
121 class Alias(object):
121 """Callable object storing the details of one alias.
122 """Callable object storing the details of one alias.
122
123
123 Instances are registered as magic functions to allow use of aliases.
124 Instances are registered as magic functions to allow use of aliases.
124 """
125 """
125
126
126 # Prepare blacklist
127 # Prepare blacklist
127 blacklist = {'cd','popd','pushd','dhist','alias','unalias'}
128 blacklist = {'cd','popd','pushd','dhist','alias','unalias'}
128
129
129 def __init__(self, shell, name, cmd):
130 def __init__(self, shell, name, cmd):
130 self.shell = shell
131 self.shell = shell
131 self.name = name
132 self.name = name
132 self.cmd = cmd
133 self.cmd = cmd
133 self.nargs = self.validate()
134 self.nargs = self.validate()
134
135
135 def validate(self):
136 def validate(self):
136 """Validate the alias, and return the number of arguments."""
137 """Validate the alias, and return the number of arguments."""
137 if self.name in self.blacklist:
138 if self.name in self.blacklist:
138 raise InvalidAliasError("The name %s can't be aliased "
139 raise InvalidAliasError("The name %s can't be aliased "
139 "because it is a keyword or builtin." % self.name)
140 "because it is a keyword or builtin." % self.name)
140 try:
141 try:
141 caller = self.shell.magics_manager.magics['line'][self.name]
142 caller = self.shell.magics_manager.magics['line'][self.name]
142 except KeyError:
143 except KeyError:
143 pass
144 pass
144 else:
145 else:
145 if not isinstance(caller, Alias):
146 if not isinstance(caller, Alias):
146 raise InvalidAliasError("The name %s can't be aliased "
147 raise InvalidAliasError("The name %s can't be aliased "
147 "because it is another magic command." % self.name)
148 "because it is another magic command." % self.name)
148
149
149 if not (isinstance(self.cmd, string_types)):
150 if not (isinstance(self.cmd, string_types)):
150 raise InvalidAliasError("An alias command must be a string, "
151 raise InvalidAliasError("An alias command must be a string, "
151 "got: %r" % self.cmd)
152 "got: %r" % self.cmd)
152
153
153 nargs = self.cmd.count('%s')
154 nargs = self.cmd.count('%s')
154
155
155 if (nargs > 0) and (self.cmd.find('%l') >= 0):
156 if (nargs > 0) and (self.cmd.find('%l') >= 0):
156 raise InvalidAliasError('The %s and %l specifiers are mutually '
157 raise InvalidAliasError('The %s and %l specifiers are mutually '
157 'exclusive in alias definitions.')
158 'exclusive in alias definitions.')
158
159
159 return nargs
160 return nargs
160
161
161 def __repr__(self):
162 def __repr__(self):
162 return "<alias {} for {!r}>".format(self.name, self.cmd)
163 return "<alias {} for {!r}>".format(self.name, self.cmd)
163
164
164 def __call__(self, rest=''):
165 def __call__(self, rest=''):
165 cmd = self.cmd
166 cmd = self.cmd
166 nargs = self.nargs
167 nargs = self.nargs
167 # Expand the %l special to be the user's input line
168 # Expand the %l special to be the user's input line
168 if cmd.find('%l') >= 0:
169 if cmd.find('%l') >= 0:
169 cmd = cmd.replace('%l', rest)
170 cmd = cmd.replace('%l', rest)
170 rest = ''
171 rest = ''
171 if nargs==0:
172 if nargs==0:
172 # Simple, argument-less aliases
173 # Simple, argument-less aliases
173 cmd = '%s %s' % (cmd, rest)
174 cmd = '%s %s' % (cmd, rest)
174 else:
175 else:
175 # Handle aliases with positional arguments
176 # Handle aliases with positional arguments
176 args = rest.split(None, nargs)
177 args = rest.split(None, nargs)
177 if len(args) < nargs:
178 if len(args) < nargs:
178 raise UsageError('Alias <%s> requires %s arguments, %s given.' %
179 raise UsageError('Alias <%s> requires %s arguments, %s given.' %
179 (self.name, nargs, len(args)))
180 (self.name, nargs, len(args)))
180 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
181 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
181
182
182 self.shell.system(cmd)
183 self.shell.system(cmd)
183
184
184 #-----------------------------------------------------------------------------
185 #-----------------------------------------------------------------------------
185 # Main AliasManager class
186 # Main AliasManager class
186 #-----------------------------------------------------------------------------
187 #-----------------------------------------------------------------------------
187
188
188 class AliasManager(Configurable):
189 class AliasManager(Configurable):
189
190
190 default_aliases = List(default_aliases(), config=True)
191 default_aliases = List(default_aliases(), config=True)
191 user_aliases = List(default_value=[], config=True)
192 user_aliases = List(default_value=[], config=True)
192 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
193 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
193
194
194 def __init__(self, shell=None, **kwargs):
195 def __init__(self, shell=None, **kwargs):
195 super(AliasManager, self).__init__(shell=shell, **kwargs)
196 super(AliasManager, self).__init__(shell=shell, **kwargs)
196 # For convenient access
197 # For convenient access
197 self.linemagics = self.shell.magics_manager.magics['line']
198 self.linemagics = self.shell.magics_manager.magics['line']
198 self.init_aliases()
199 self.init_aliases()
199
200
200 def init_aliases(self):
201 def init_aliases(self):
201 # Load default & user aliases
202 # Load default & user aliases
202 for name, cmd in self.default_aliases + self.user_aliases:
203 for name, cmd in self.default_aliases + self.user_aliases:
203 self.soft_define_alias(name, cmd)
204 self.soft_define_alias(name, cmd)
204
205
205 @property
206 @property
206 def aliases(self):
207 def aliases(self):
207 return [(n, func.cmd) for (n, func) in self.linemagics.items()
208 return [(n, func.cmd) for (n, func) in self.linemagics.items()
208 if isinstance(func, Alias)]
209 if isinstance(func, Alias)]
209
210
210 def soft_define_alias(self, name, cmd):
211 def soft_define_alias(self, name, cmd):
211 """Define an alias, but don't raise on an AliasError."""
212 """Define an alias, but don't raise on an AliasError."""
212 try:
213 try:
213 self.define_alias(name, cmd)
214 self.define_alias(name, cmd)
214 except AliasError as e:
215 except AliasError as e:
215 error("Invalid alias: %s" % e)
216 error("Invalid alias: %s" % e)
216
217
217 def define_alias(self, name, cmd):
218 def define_alias(self, name, cmd):
218 """Define a new alias after validating it.
219 """Define a new alias after validating it.
219
220
220 This will raise an :exc:`AliasError` if there are validation
221 This will raise an :exc:`AliasError` if there are validation
221 problems.
222 problems.
222 """
223 """
223 caller = Alias(shell=self.shell, name=name, cmd=cmd)
224 caller = Alias(shell=self.shell, name=name, cmd=cmd)
224 self.shell.magics_manager.register_function(caller, magic_kind='line',
225 self.shell.magics_manager.register_function(caller, magic_kind='line',
225 magic_name=name)
226 magic_name=name)
226
227
227 def get_alias(self, name):
228 def get_alias(self, name):
228 """Return an alias, or None if no alias by that name exists."""
229 """Return an alias, or None if no alias by that name exists."""
229 aname = self.linemagics.get(name, None)
230 aname = self.linemagics.get(name, None)
230 return aname if isinstance(aname, Alias) else None
231 return aname if isinstance(aname, Alias) else None
231
232
232 def is_alias(self, name):
233 def is_alias(self, name):
233 """Return whether or not a given name has been defined as an alias"""
234 """Return whether or not a given name has been defined as an alias"""
234 return self.get_alias(name) is not None
235 return self.get_alias(name) is not None
235
236
236 def undefine_alias(self, name):
237 def undefine_alias(self, name):
237 if self.is_alias(name):
238 if self.is_alias(name):
238 del self.linemagics[name]
239 del self.linemagics[name]
239 else:
240 else:
240 raise ValueError('%s is not an alias' % name)
241 raise ValueError('%s is not an alias' % name)
241
242
242 def clear_aliases(self):
243 def clear_aliases(self):
243 for name, cmd in self.aliases:
244 for name, cmd in self.aliases:
244 self.undefine_alias(name)
245 self.undefine_alias(name)
245
246
246 def retrieve_alias(self, name):
247 def retrieve_alias(self, name):
247 """Retrieve the command to which an alias expands."""
248 """Retrieve the command to which an alias expands."""
248 caller = self.get_alias(name)
249 caller = self.get_alias(name)
249 if caller:
250 if caller:
250 return caller.cmd
251 return caller.cmd
251 else:
252 else:
252 raise ValueError('%s is not an alias' % name)
253 raise ValueError('%s is not an alias' % name)
General Comments 0
You need to be logged in to leave comments. Login now