262 lines
9.9 KiB
Python
262 lines
9.9 KiB
Python
import commands, dirutil, grp, method, mode, os.path, pwd, re
|
|
import util
|
|
import buffer, buffer.fs
|
|
from window import Window
|
|
from lex import Grammar, PatternRule, RegionRule, PatternMatchRule
|
|
from point import Point
|
|
from method import Method, Argument, arg
|
|
|
|
class PermGrammar(Grammar):
|
|
rules = [
|
|
PatternRule('sticky', '[tT]'),
|
|
PatternRule('setid', '[sS]'),
|
|
PatternRule('read', 'r'),
|
|
PatternRule('write', 'w'),
|
|
PatternRule('exec', 'x'),
|
|
]
|
|
|
|
ds = r'([^ ]+)( +)([^ ]+)( +)([^ ]+)( +)([A-Za-z]{3} [ 0-9]{2} [0-9]{2}:[0-9]{2})( +)([^\n]+)'
|
|
class PathGrammar(Grammar):
|
|
rules = [
|
|
RegionRule('perm', '(?<=^.)', PermGrammar, ' '),
|
|
PatternMatchRule('x', ds, 'dir.owner', 'spaces', 'dir.group', 'spaces',
|
|
'dir.size', 'spaces', 'dir.mtime', 'spaces',
|
|
'name', 'spaces'),
|
|
]
|
|
|
|
class DirGrammar(Grammar):
|
|
rules = [
|
|
RegionRule('dir.file', '^-', PathGrammar, r'\n'),
|
|
RegionRule('dir.blk', '^b', PathGrammar, r'\n'),
|
|
RegionRule('dir.chr', '^c', PathGrammar, r'\n'),
|
|
RegionRule('dir.dir', '^d', PathGrammar, r'\n'),
|
|
RegionRule('dir.lnk', '^l', PathGrammar, r'\n'),
|
|
RegionRule('dir.fifo', '^p', PathGrammar, r'\n'),
|
|
RegionRule('dir.sock', '^s', PathGrammar, r'\n'),
|
|
RegionRule('dir.unk', '^\?', PathGrammar, r'\n'),
|
|
]
|
|
|
|
class FsSettingBase(Method):
|
|
msg = 'Settings have changed'
|
|
def _doit(self, w, **vargs): pass
|
|
def _execute(self, w, **vargs):
|
|
self._doit(w, **vargs)
|
|
w.buffer.reload()
|
|
w.goto_beginning()
|
|
w.set_error(self.msg)
|
|
|
|
class HideDotFiles(FsSettingBase):
|
|
msg = "Dotfiles are hidden"
|
|
def _doit(self, w, **vargs): w.buffer.settings['hide-dot'] = True
|
|
class ShowDotFiles(FsSettingBase):
|
|
msg = "Dotfiles are visible"
|
|
def _doit(self, w, **vargs): w.buffer.settings['hide-dot'] = False
|
|
|
|
class SortType(FsSettingBase):
|
|
msg = "Sorting files by type, name"
|
|
def _doit(self, w, **vargs): w.buffer.settings['type-sort'] = True
|
|
class SortName(FsSettingBase):
|
|
msg = "Sorting files by name, type"
|
|
def _doit(self, w, **vargs): w.buffer.settings['type-sort'] = False
|
|
|
|
class OpenArchive(Method):
|
|
args = [arg('path', dt="path", p="Open Archive: ", h="archive to open")]
|
|
def _execute(self, w, **vargs):
|
|
path = vargs['path']
|
|
a = w.application
|
|
b = a.get_buffer_by_path(path)
|
|
if not b:
|
|
name = a.make_name(os.path.basename(path))
|
|
b = buffer.fs.ArchiveBuffer(path, name)
|
|
b.open()
|
|
Window(b, a, height=0, width=0, mode_name='dir')
|
|
a.add_buffer(b)
|
|
|
|
a.methods['switch-buffer'].execute(w, buffername=b.name())
|
|
if b.btype != 'archive': return
|
|
|
|
names = [x for x in b.get_names() if x != '.' and x != '..']
|
|
if len(names) == 1:
|
|
path2 = os.path.join(b.path, names[0])
|
|
if os.path.isdir(path2):
|
|
a.methods['open-file'].execute(w, filename=path2)
|
|
|
|
class DirRefresh(Method):
|
|
def _execute(self, w, **vargs):
|
|
t = None
|
|
try:
|
|
t = dirutil.resolve_token(w)
|
|
s = t.string
|
|
except:
|
|
pass
|
|
w.buffer.reload()
|
|
if t: dirutil.find_name(w, s)
|
|
class DirOpen(Method):
|
|
def _execute(self, w, **vargs):
|
|
path = dirutil.resolve_path(w)
|
|
w.set_error("opening %r" % path)
|
|
w.application.methods['open-file'].execute(w, filename=path)
|
|
class DirGrep(Method):
|
|
args = [Argument('pattern', datatype="str", prompt="Pattern: ")]
|
|
def _execute(self, w, **vargs):
|
|
cmd = 'grep -rEl -- "%s" %r' % (vargs['pattern'], w.buffer.path)
|
|
(status, output) = commands.getstatusoutput(cmd)
|
|
|
|
paths = []
|
|
suffixes = w.application.config['ignore_suffix']
|
|
for path in output.split('\n'):
|
|
if not path or util.should_ignore_path(path, suffixes):
|
|
continue
|
|
paths.append(path)
|
|
|
|
bufname = '*%s*' % self.name.title()
|
|
b = buffer.fs.PathListBuffer(bufname, paths)
|
|
b.modename = 'dir'
|
|
b.open()
|
|
Window(b, w.application, height=0, width=0)
|
|
w.application.add_buffer(b)
|
|
w.application.switch_buffer(b)
|
|
w.set_error("grep exited with %d" % status)
|
|
|
|
class DirCmd(Method):
|
|
def _make_cmd(self, w, path, **vargs):
|
|
return ''
|
|
def _run(self, w, **vargs):
|
|
basename = dirutil.resolve_name(w)
|
|
path = os.path.join(w.buffer.path, basename)
|
|
cmd = self._make_cmd(w, path, **vargs)
|
|
(status, output) = commands.getstatusoutput(cmd)
|
|
if status != 0:
|
|
w.set_error("%s failed (exit %d)" % (self.name, status))
|
|
dirutil.find_name(w, basename)
|
|
|
|
class DirChmod(DirCmd):
|
|
args = [Argument('mode', type=type(''), prompt="New Mode: ")]
|
|
octal_re = re.compile('^[0-7]{1,4}$')
|
|
symbolic_re = re.compile('(?:[ugoa]*(?:[-+=](?:[rwxXst]*|[ugo]))+ *,?)+')
|
|
def _make_cmd(self, w, path, **vargs):
|
|
return 'chmod %r %r' % (vargs['mode'], path)
|
|
def _execute(self, w, **vargs):
|
|
if self.octal_re.match(vargs['mode']):
|
|
pass
|
|
elif self.symbolic_re.match(vargs['mode']):
|
|
pass
|
|
else:
|
|
w.set_error("Not a valid mode: %r" % vargs['mode'])
|
|
self._run(w, **vargs)
|
|
class DirChown(DirCmd):
|
|
args = [Argument('owner', type=type(''), prompt="New Owner: ")]
|
|
def _make_cmd(self, w, path, **vargs):
|
|
return 'chown %r %r' % (vargs['owner'], path)
|
|
def _execute(self, w, **vargs):
|
|
fields = vargs['owner'].split(':')
|
|
if len(fields) == 1:
|
|
(owner, group) = (fields[0], None)
|
|
elif len(fields) == 2:
|
|
(owner, group) = fields
|
|
else:
|
|
w.set_error("Malformed 'owner' argument: %r" % vargs['owner'])
|
|
return
|
|
if not dirutil.valid_owner(owner):
|
|
w.set_error('User %r does not exist' % owner)
|
|
return
|
|
if group is not None and not dirutil.valid_group(group):
|
|
w.set_error('Group %r does not exist' % group)
|
|
return
|
|
self._run(w, **vargs)
|
|
class DirChgrp(DirCmd):
|
|
args = [Argument('group', type=type(''), prompt="New Group: ")]
|
|
def _make_cmd(self, w, path, **vargs):
|
|
return 'chgrp %r %r' % (vargs['group'], path)
|
|
def _execute(self, w, **vargs):
|
|
if not dirutil.valid_group(vargs['group']):
|
|
w.set_error('Group %r does not exist' % group)
|
|
return
|
|
self._run(w, **vargs)
|
|
|
|
class DirTouch(Method):
|
|
args = [Argument('filename', datatype="path", prompt="Touch File: ")]
|
|
def _execute(self, w, **vargs):
|
|
basename = vargs['filename']
|
|
path = os.path.join(w.buffer.path, basename)
|
|
retval = os.system('touch %r' % path)
|
|
w.application.methods['dir-refresh'].execute(w, filename=path)
|
|
dirutil.find_name(w, basename)
|
|
if retval != 0:
|
|
w.set_error("touch %r failed (exit %d)" % (path, retval))
|
|
class DirRemove(Method):
|
|
def _execute(self, w, **vargs):
|
|
self._old_window = w
|
|
self._old_path = dirutil.resolve_path(w)
|
|
basename = os.path.basename(self._old_path)
|
|
self._prompt = "Do you want to delete %r? " % basename
|
|
w.application.open_mini_buffer(self._prompt, self._callback)
|
|
def _callback(self, v):
|
|
a = self._old_window.application
|
|
if v == 'yes':
|
|
self._doit()
|
|
a.close_mini_buffer()
|
|
return
|
|
if v == 'no':
|
|
a.close_mini_buffer()
|
|
return
|
|
a.open_mini_buffer(self._prompt, self._callback)
|
|
a.set_error('Please type "yes" or "no"')
|
|
def _doit(self):
|
|
w = self._old_window
|
|
path = self._old_path
|
|
try:
|
|
w.application.methods['previous-line'].execute(w)
|
|
os.remove(path)
|
|
w.set_error("deleted %r " % path)
|
|
w.application.methods['dir-refresh'].execute(w, filename=path)
|
|
except:
|
|
w.set_error("failed to delete %r" % path)
|
|
|
|
class Dir(mode.Fundamental):
|
|
name = 'Dir'
|
|
grammar = DirGrammar()
|
|
colors = {
|
|
'dir.blk.start': ('cyan', 'default', 'bold'),
|
|
'dir.blk.name': ('cyan', 'default', 'bold'),
|
|
'dir.chr.start': ('yellow', 'default', 'bold'),
|
|
'dir.chr.name': ('yellow', 'default', 'bold'),
|
|
'dir.dir.start': ('blue', 'default', 'bold'),
|
|
'dir.dir.name': ('blue', 'default', 'bold'),
|
|
'dir.lnk.start': ('green', 'default', 'bold'),
|
|
'dir.lnk.name': ('green', 'default', 'bold'),
|
|
'dir.fifo.start': ('red', 'default', 'bold'),
|
|
'dir.fifo.name': ('red', 'default', 'bold'),
|
|
'dir.sock.start': ('red', 'default', 'bold'),
|
|
'dir.sock.name': ('red', 'default', 'bold'),
|
|
'dir.unk.start': ('magenta', 'default', 'bold'),
|
|
'dir.unk.name': ('magenta', 'default', 'bold'),
|
|
|
|
'perm.setid': ('yellow', 'default', 'bold'),
|
|
'perm.sticky': ('yellow', 'default', 'bold'),
|
|
'perm.read': ('magenta', 'default', 'bold'),
|
|
'perm.write': ('magenta', 'default', 'bold'),
|
|
'perm.exec': ('magenta', 'default', 'bold'),
|
|
|
|
'dir.owner': ('cyan', 'default', 'bold'),
|
|
'dir.group': ('cyan', 'default', 'bold'),
|
|
'dir.size': ('yellow', 'default', 'bold'),
|
|
'dir.mtime': ('green', 'default', 'bold'),
|
|
}
|
|
actions = [DirRefresh, DirOpen, DirGrep, DirChmod, DirChown, DirChgrp,
|
|
DirTouch, DirRemove, HideDotFiles, ShowDotFiles, SortName,
|
|
SortType,
|
|
OpenArchive]
|
|
def __init__(self, w):
|
|
mode.Fundamental.__init__(self, w)
|
|
self.add_bindings('dir-refresh', ('C-c r',))
|
|
self.add_bindings('dir-open', ('RETURN',))
|
|
self.add_bindings('dir-grep', ('C-c G',))
|
|
self.add_bindings('dir-chmod', ('C-c m',))
|
|
self.add_bindings('dir-chown', ('C-c o',))
|
|
self.add_bindings('dir-chgrp', ('C-c g',))
|
|
self.add_bindings('dir-touch', ('C-c t',))
|
|
self.add_bindings('dir-remove', ('DELETE', 'BACKSPACE', 'C-d'))
|
|
|
|
install = Dir.install
|