pmacs3/mode/dir.py

262 lines
10 KiB
Python

import subprocess, 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) = subprocess.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) = subprocess.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