46
49
0x0C: 'cursor_center', # Ctrl-L
47
50
0x10: 'cursor_quarter_up', # Ctrl-P
48
51
0x231: 'cursor_quarter_up', # Ctrl-Cursor_up
49
0x0e: 'cursor_quarter_down', # Ctrl-N
52
0x0E: 'cursor_quarter_down', # Ctrl-N
50
53
0x208: 'cursor_quarter_down', # Ctrl-Cursor_down
52
55
# movement other pane
53
56
curses.KEY_SR: 'cursor_up_otherpane', # Shift-up
54
57
0x22f: 'cursor_up_otherpane', # Alt-up, kUP3
91
94
0x04: 'select_bookmark', # Ctrl-D
92
95
0x1C: 'select_bookmark', # Ctrl-\
93
96
ord('b'): 'set_bookmark',
94
0x19: 'select_historic', # Ctrl-Y
97
0x19: 'select_history', # Ctrl-Y
97
100
ord('\t'): 'toggle_active_pane', # tab
98
101
ord('.'): 'toggle_panes',
285
289
return RET_NO_UPDATE
287
def cursor_left_otherpane(tab):
291
def cursor_left_otherpane(tab):
288
292
if app.prefs.options['manage_otherpane'] and \
289
293
tab.pane.mode in (PANE_MODE_LEFT, PANE_MODE_RIGHT):
290
294
othertab = app.noact_pane.act_tab
294
298
return RET_NO_UPDATE
296
def cursor_right_otherpane(tab):
300
def cursor_right_otherpane(tab):
297
301
if app.prefs.options['manage_otherpane'] and \
298
302
tab.pane.mode in (PANE_MODE_LEFT, PANE_MODE_RIGHT):
299
303
othertab = app.noact_pane.act_tab
334
338
filename = tab.get_file()
335
339
vfstype = compress.check_compressed_file_type(filename)
336
340
typ = tab.files[filename][files.FT_TYPE]
337
if vfstype in ('bz2', 'gz'):
341
if vfstype in ('bz2', 'gz', 'xz'):
339
343
if typ == files.FTYPE_DIR:
340
344
tab.enter_dir(filename)
341
345
elif typ == files.FTYPE_LNK2DIR:
342
tab.init(files.get_linkpath(tab.path, filename))
346
if filename == os.pardir:
347
tab.enter_dir(os.path.normpath(os.path.join(tab.path, filename)))
349
tab.init(files.get_linkpath(tab.path, filename))
343
350
elif typ in (files.FTYPE_REG, files.FTYPE_LNK) and vfstype is not None:
344
351
vfs.init(tab, filename, vfstype)
345
352
elif typ == files.FTYPE_EXE and allowexec:
352
359
def goto_dir(tab):
353
todir = doEntry(tab.path, 'Go to directory', 'Type directory name')
360
todir = doEntry(tab.path, 'Go to directory', 'Type directory name', with_history='path')
356
363
todir = os.path.join(tab.path, todir)
361
368
def goto_file(tab):
362
tofile = doEntry(tab.path, 'Go to file', 'Type how file name begins')
369
tofile = doEntry(tab.path, 'Go to file', 'Type how file name begins', with_history='file')
364
371
thefiles = tab.sorted[tab.file_i:]
365
372
for f in thefiles:
376
app.act_pane, app.noact_pane = app.act_pane, app.noact_pane
383
app.act_pane, app.noact_pane = app.noact_pane, app.act_pane
377
384
tab.pane.display()
378
t = Tree(tab.path, tab.pane.mode)
381
app.act_pane, app.noact_pane = app.act_pane, app.noact_pane
385
ans = Tree(tab.path, tab.pane.mode).run()
386
app.act_pane, app.noact_pane = app.noact_pane, app.act_pane
436
def select_historic(tab):
437
items = tab.historic[::-1]
441
def select_history(tab):
442
items = tab.history[::-1]
439
messages.error('Select from history', 'No previous directories')
444
messages.error('Cannot select directory from history\nNo entries yet')
441
446
ret = messages.MenuWin('Return to', items).run()
486
491
def new_tab(tab):
487
492
if len(tab.pane.tabs) >= 4:
488
messages.error('New tab', 'Can\'t create more tabs')
493
messages.error('Cannot create more tabs')
490
495
return RET_TAB_NEW
492
497
def close_tab(tab):
493
498
if len(tab.pane.tabs) == 1:
494
messages.error('Close tab', 'Can\'t close last tab')
499
messages.error('Cannot close last tab')
526
531
def select_group(tab):
527
pattern = doEntry(tab.path, 'Select group', 'Type pattern', '*')
532
pattern = doEntry(tab.path, 'Select group', 'Type pattern', '*', with_history='glob')
529
534
fullpath = os.path.join(tab.path, pattern)
530
535
for f in [os.path.basename(f) for f in glob(fullpath)]:
532
537
tab.selections.append(f)
534
539
def deselect_group(tab):
535
pattern = doEntry(tab.path, 'Deselect group', 'Type pattern', '*')
540
pattern = doEntry(tab.path, 'Deselect group', 'Type pattern', '*', with_history='glob')
537
542
fullpath = os.path.join(tab.path, pattern)
538
543
for f in [os.path.basename(f) for f in glob(fullpath)]:
544
549
tab.selections = [f for f in tab.sorted if f not in selections_old and \
548
554
def toggle_dotfiles(tab):
549
# app.prefs.options['show_dotfiles'] = 1 if app.prefs.options['show_dotfiles'] == 0 else 0
550
if app.prefs.options['show_dotfiles'] == 0:
551
app.prefs.options['show_dotfiles'] = 1
553
app.prefs.options['show_dotfiles'] = 0
555
app.prefs.options['show_dotfiles'] = 1 if app.prefs.options['show_dotfiles']==0 else 0
556
558
def toggle_manage_otherpane(tab):
557
# app.prefs.options['manage_otherpane'] = 1 if app.prefs.options['manage_otherpane'] == 0 else 0
558
if app.prefs.options['manage_otherpane'] == 0:
559
app.prefs.options['manage_otherpane'] = 1
561
app.prefs.options['manage_otherpane'] = 0
559
app.prefs.options['manage_otherpane'] = 1 if app.prefs.options['manage_otherpane'] == 0 else 0
562
560
return RET_HALF_UPDATE_OTHER
564
562
def show_size(tab):
583
581
def touch_file(tab):
584
newfile = doEntry(tab.path, 'Touch file', 'Type file name')
582
newfile = doEntry(tab.path, 'Touch file', 'Type file name', with_history='file')
587
585
fullfilename = os.path.join(tab.path, newfile)
603
601
otherfile = othertab.get_file()
604
602
newlink, pointto = doDoubleEntry(tab.path, 'Create link', 'Link name', '',
605
'Pointing to', otherfile)
603
'Pointing to', otherfile,
604
with_history1='file', with_history2='path')
608
messages.error('Create link', 'You must type new link name')
611
messages.error('Create link', 'You must type pointed file')
606
if newlink is None or pointto is None:
609
messages.error('Cannot create link\nYou must specify the name for the new link')
612
messages.error('Cannot create link\nYou must specify the file to link')
613
614
fullfilename = os.path.join(tab.path, newlink)
614
615
ans = files.create_link(pointto, fullfilename)
616
messages.error('Create link', '%s (%s)' % (ans, tab.get_file()))
617
messages.error('Cannot create link\n%s (%s)' % (ans, tab.get_file()))
622
623
if not os.path.islink(fullfilename):
624
625
pointto = doEntry(tab.path, 'Edit link', 'Link \'%s\' points to' % \
625
tab.get_file(), os.readlink(fullfilename))
626
tab.get_file(), os.readlink(fullfilename), with_history='path')
628
messages.error('Create link', 'You must type pointed file')
631
messages.error('Cannot edit link\nYou must specify the file to link')
630
633
if pointto != os.readlink(fullfilename):
631
634
ans = files.modify_link(pointto, fullfilename)
633
messages.error('Edit link', '%s (%s)' % (ans, tab.getfile()))
636
messages.error('Cannot edit link\n%s (%s)' % (ans, tab.getfile()))
636
639
def open_shell(tab):
638
os.system('cd "%s"; %s' % (get_escaped_filename(tab.path),
639
app.prefs.progs['shell']))
641
os.system('cd "%s" && %s' % (get_escaped_filename(tab.path),
642
app.prefs.progs['shell']))
662
673
def backup_file(tab):
663
674
fs = __rename_backup_helper(tab)
665
678
# pc is not used, just to check files have valid encoding
666
679
pc = files.PathContents(fs, tab.path)
667
680
except UnicodeError:
668
messages.error('Backup files', 'Files with invalid encoding, convert first')
681
messages.error('Cannot backup files\nFiles with invalid encoding, convert first')
670
683
res = ProcessLoopBackup('Backup files', files.do_backup, fs, tab.path,
671
684
app.prefs.misc['backup_extension']).run()
690
orig_ext = app.prefs.misc['backup_extension']
691
diff_type = app.prefs.misc['diff_type']
692
filename = tab.get_file()
693
if filename.endswith(orig_ext):
694
file_old = os.path.join(tab.path, filename)
695
file_new = os.path.join(tab.path, filename[:-len(orig_ext)])
697
file_old = os.path.join(tab.path, filename + orig_ext)
698
file_new = os.path.join(tab.path, filename)
699
if not os.path.exists(file_old):
700
messages.error('Cannot diff file\nBackup file does not exist')
702
if not os.path.exists(file_new):
703
messages.error('Cannot diff file\nOnly backup file exists')
705
if not os.path.isfile(file_old) or not os.path.isfile(file_new):
706
messages.error('Cannot diff file\nWe can only diff regular files')
708
buf0 = open(file_old).readlines()
709
buf1 = open(file_new).readlines()
710
d0 = datetime.datetime.fromtimestamp(os.stat(file_old).st_mtime)
711
date_old = d0.strftime(' %Y-%m-%d %H:%M:%S.%f ') + tzname[0]
712
d1 = datetime.datetime.fromtimestamp(os.stat(file_new).st_mtime)
713
date_new = d1.strftime(' %Y-%m-%d %H:%M:%S.%f ') + tzname[0]
714
if diff_type == 'context':
715
diff = difflib.context_diff(buf0, buf1, file_old, file_new, date_old, date_new, n=3)
716
elif diff_type == 'unified':
717
diff = difflib.unified_diff(buf0, buf1, file_old, file_new, date_old, date_new, n=3)
718
elif diff_type == 'ndiff':
719
diff = difflib.ndiff(buf0, buf1)
722
messages.error('Files are identical')
724
tmpfile = os.path.join(files.mkdtemp(), os.path.basename(file_old) + \
725
' DIFF ' + os.path.basename(file_new))
726
f = open(tmpfile, 'w')
730
os.system('%s \"%s\"' % (app.prefs.progs['pager'], tmpfile))
732
files.delete_bulk(os.path.dirname(tmpfile), True)
676
734
def view_file(tab):
677
735
do_view_file(tab)
686
744
dest_exists = os.path.exists(destdir)
687
745
# special case: no copy/move multiple files or dir over an existing file
688
746
if len(fs) > 1 and (dest_is_file or not dest_exists):
689
messages.error('Copying files \'%s\'' % destdir,
690
'Not a directory (20)')
691
return -1, None, None
747
messages.error('Cannot copy files\n' +
748
'%s: Not a directory (20)' % destdir)
749
return -1, None, None
693
751
if os.path.isdir(os.path.join(path, f)) and dest_is_file:
694
messages.error('Copying files \'%s\'' % destdir,
695
'Not a directory (20)')
696
return -1, None, None
752
messages.error('Cannot copy files\n' +
753
'%s: Not a directory (20)' % destdir)
754
return -1, None, None
697
755
# special case: copy/move a dir to same path with different name
698
756
rename_dir = False
708
766
# not (os.path.isdir(os.path.dirname(destdir)) and not dest_exists):
709
767
if dir_destdir != path and (not os.path.isdir(dir_destdir) or dest_exists):
711
src = os.path.join(path, f)
712
769
dest = os.path.join(destdir, f)
713
770
if not os.path.exists(dest) and not dest_exists:
714
messages.error(dest, destdir)
715
messages.error('Copying files \'%s\'' % destdir,
716
'No such file or directory (2)')
717
return -1, None, None
718
return 0, destdir, rename_dir
771
messages.error('Cannot copy files\n' +
772
'%s: No such file or directory (2)' % destdir)
773
return -1, None, None
774
return 0, destdir, rename_dir
721
777
destdir = app.noact_pane.act_tab.path + os.sep
729
785
buf = 'Copy \'%s\' to' % filename
731
destdir = doEntry(tab.path, 'Copy', buf, destdir)
787
destdir = doEntry(tab.path, 'Copy', buf, destdir, with_history='path')
733
789
st, destdir, rename_dir = __copymove_helper(destdir, tab.path, fs)
737
793
pc = files.PathContents(fs, tab.path)
738
794
except UnicodeError:
740
messages.error('Copy files', 'Files with invalid encoding, convert first')
796
messages.error('Cannot copy files\nFiles with invalid encoding, convert first')
742
798
res = ProcessLoopCopy('Copy files', files.do_copy, pc,
743
799
destdir, rename_dir).run()
744
800
tab.selections = []
748
804
destdir = app.noact_pane.act_tab.path + os.sep
749
805
if tab.selections:
756
812
buf = 'Move \'%s\' to' % filename
758
destdir = doEntry(tab.path, 'Move', buf, destdir)
814
destdir = doEntry(tab.path, 'Move', buf, destdir, with_history='path')
760
816
st, destdir, rename_dir = __copymove_helper(destdir, tab.path, fs)
764
820
pc = files.PathContents(fs, tab.path)
765
821
except UnicodeError:
767
messages.error('Move files', 'Files with invalid encoding, convert first')
823
messages.error('Cannot move files\nFiles with invalid encoding, convert first')
769
825
res = ProcessLoopCopy('Move files', files.do_copy, pc,
770
826
destdir, rename_dir).run()
781
837
def make_dir(tab):
782
newdir = doEntry(tab.path, 'Make directory', 'Type directory name')
838
newdir = doEntry(tab.path, 'Make directory', 'Type directory name', with_history='file')
784
840
ans = files.mkdir(tab.path, newdir)
787
messages.error('Make directory',
843
messages.error('Cannot make directory\n' +
844
newdir + ': %s (%s)' % ans)
801
857
pc = files.PathContents(fs, tab.path)
802
858
except UnicodeError:
803
messages.error('Delete files', 'Files with invalid encoding, convert first')
859
messages.error('Cannot delete files\nFiles with invalid encoding, convert first')
805
861
res = ProcessLoopDelete('Delete files', files.do_delete, pc).run()
806
862
tab.selections = []
832
888
'p Change file permissions, owner, group',
834
'g Gzip/gunzip file(s)',
835
'b Bzip2/bunzip2 file(s)',
837
'x Uncompress .tar.gz, .tar.bz2, .tar.xz, .zip, .rar, .7z',
890
'd Diff file with backup',
891
'z Compress/uncompress file(s)...', # u'\u2026'
892
'x Uncompress .tar.gz, .tar.bz2, .tar.xz, .tar, .zip, .rar, .7z',
838
893
'u Uncompress .tar.gz, etc in other panel',
839
'c Compress directory to .tar.gz',
840
'd Compress directory to .tar.bz2',
841
'e Compress directory to .tar.xz',
842
'z Compress directory to .zip',
843
'r Compress directory to .rar',
844
'7 Compress directory to .7z' ]
894
'c Compress directory to format...' ] # u'\u2026'
845
895
cmd = messages.MenuWin('File Menu', menu).run()
855
905
do_change_perms(tab)
859
compress_uncompress_file(tab, 'gz')
861
compress_uncompress_file(tab, 'bz2')
863
compress_uncompress_file(tab, 'xz')
911
compress_fmts = {'g': 'gz', 'b': 'bz2', 'x': 'xz'}
913
ch = messages.get_a_key('Un/Compress file(s)',
914
'(g)zip, (b)zip2, (x)z\n\n'
916
if ch == -1: # Ctrl-C
918
elif chr(ch) in compress_fmts.keys():
919
compress_uncompress_file(tab, compress_fmts[chr(ch)])
865
922
uncompress_dir(tab, tab.path)
867
924
uncompress_dir(tab, app.noact_pane.act_tab.path)
869
compress_dir(tab, 'tgz')
871
compress_dir(tab, 'tbz2')
873
compress_dir(tab, 'txz')
875
compress_dir(tab, 'zip')
877
compress_dir(tab, 'rar')
879
compress_dir(tab, '7z')
926
if not tab.selections and os.path.basename(tab.sorted[tab.file_i])==os.pardir:
928
compress_fmts = {'g': 'tgz', 'b': 'tbz2', 'x': 'txz', 't': 'tar',
929
'z': 'zip', 'r': 'rar', '7': '7z'}
931
ch = messages.get_a_key('Compress directory to...',
932
'.tar.(g)z, .tar.(b)z2, .tar.(x)z, .(t)ar, .(z)ip, .(r)ar, .(7)z\n\n'
934
if ch == -1: # Ctrl-C
936
elif chr(ch) in compress_fmts.keys():
937
compress_dir(tab, compress_fmts[chr(ch)])
915
975
app.prefs.check_progs()
918
messages.win('Regenerate programs', ' OK')
978
messages.win('Configuration', 'Regenerating programs... OK')
980
files.delete_bulk(messages.HISTORY_FILE)
981
messages.history = messages.DEFAULT_HISTORY.copy()
1010
1073
if ext in exts:
1011
1074
prog = app.prefs.progs[typ]
1013
messages.error('Can\'t run program',
1076
messages.error('Cannot run program\n' +
1014
1077
'Can\'t start %s files, defaulting to view' % typ)
1015
1078
do_view_file(tab)
1047
1111
# do execute file
1048
1112
def do_execute_file(tab):
1049
1113
filename = tab.get_file()
1050
parms = doEntry(tab.path, 'Execute file', 'Enter arguments')
1114
parms = doEntry(tab.path, 'Execute file', 'Enter arguments', with_history='exec')
1051
1115
if parms is None:
1053
1117
elif parms == '':
1054
1118
cmd = get_escaped_filename(filename)
1056
cmd = '%s %s' % (get_escaped_filename(filename), parms)
1120
cmd = '%s %s' % (get_escaped_filename(filename), encode(parms))
1057
1121
curses.endwin()
1058
1122
st, msg = ProcessFunc('Executing file', encode(filename),
1059
1123
run_shell, cmd, encode(tab.path), True).run()
1061
messages.error('Executing file', msg)
1125
messages.error('Cannot execute file\n' + decode(msg))
1062
1126
if st != -100 and msg is not None:
1063
1127
if app.prefs.options['show_output_after_exec']:
1064
1128
curses.curs_set(0)
1065
1129
if messages.confirm('Executing file', 'Show output'):
1066
1130
lst = [(l, 2) for l in msg.split('\n')]
1067
pyview.InternalView('Output of "%s"' % encode(cmd),
1131
pyview.InternalView('Output of "%s"' % cmd,
1068
1132
lst, center=0).run()
1069
1133
curses.curs_set(0)
1073
1137
# do something on file
1074
1138
def do_something_on_file(tab):
1075
cmd = doEntry(tab.path, 'Do something on file(s)', 'Enter command')
1139
cmd = doEntry(tab.path, 'Do something on file(s)', 'Enter command', with_history='exec')
1077
1141
curses.endwin()
1078
1142
if len(tab.selections):
1090
1154
# show file info
1091
1155
def do_show_file_info(tab):
1092
1156
def show_info(tab, file):
1094
from time import ctime
1096
1157
fullfilename = os.path.join(tab.path, file)
1097
1158
fd = tab.files[file]
1098
1159
fde = files.get_fileinfo_extended(fullfilename)
1147
1208
ans = files.set_perms(filename, perms, recursive)
1149
messages.error('Chmod "%s"' % filename, '%s (%s)' % ans)
1210
messages.error('Cannot chmod\n' + filename + ': %s (%s)' % ans)
1150
1211
ans = files.set_owner_group(filename, owner, group, recursive)
1152
messages.error('Chown "%s"' % filename, '%s (%s)' % ans)
1213
messages.error('Cannot chown\n' + filename + ': %s (%s)' % ans)
1153
1214
except UnicodeError:
1155
messages.error('Change permissions',
1216
messages.error('Cannot change permissions\n' +
1156
1217
'Files with invalid encoding, convert first')
1187
1248
# do show filesystems info
1188
1249
def do_show_fs_info():
1190
fs = get_shell_output('df -h')
1251
buf = get_shell_output('df -h')
1191
1252
except (IOError, os.error), (errno, strerror):
1192
messages.error('Show filesystems info', (strerror, errno))
1194
if fs is None or fs == '':
1195
messages.error('Show filesystems info', ('Can\'t run "df" command', 0))
1199
buf.append((fs[0].strip(), 6))
1200
buf.append(('-'*len(fs[0]), 6))
1202
buf.append((l.strip(), 2))
1203
pyview.InternalView('Show filesystems info', buf).run()
1253
messages.error('Cannot show filesystems info\n%s (%s)' % (strerror, errno))
1255
if buf is None or buf == '':
1256
messages.error('Cannot show filesystems info\n%s (%s)' % ('Can\'t run "df" command', 0))
1258
hdr = buf.split('\n')[0].strip()
1259
fs = [l.strip() for l in buf.strip().split('\n')[1:]]
1260
lst = [(hdr, 6), ('-'*len(hdr), 6)]
1263
pyview.InternalView('Show filesystems info', lst).run()
1206
1266
# find and grep
1207
1267
def findgrep(tab):
1209
fs, pat = doDoubleEntry(tab.path, 'Find files', 'Filename', '*',
1210
'Content', '', with_complete2=False)
1269
fs, pat = doDoubleEntry(tab.path, 'Find files', 'Filename', '*',
1270
'Content', '', with_complete2=False,
1271
with_history1='glob', with_history2='grep')
1211
1272
if fs is None or fs == '':
1213
1274
path = os.path.dirname(fs)
1229
1290
else: # some other error
1231
messages.error(search_type, m)
1292
messages.error('Cannot %s\n' % search_type.lower() + m)
1233
1294
if not m or m == []:
1235
messages.error(search_type, 'No files found')
1296
messages.error('Cannot %s\n' % search_type.lower() + 'No files found')
1245
line = int(par.split(':')[0])
1306
line = int(par.split(':')[-1])
1246
1307
except ValueError:
1248
1309
f = os.path.join(path, par)
1250
f = os.path.join(path, par[par.find(':')+1:])
1311
f = os.path.join(path, par[:par.rfind(':')])
1253
1314
f = os.path.join(path, par)
1293
1354
curses.curs_set(0)
1294
1355
app.regenerate()
1296
messages.error('Edit', 'it\'s a directory', todir)
1357
messages.error('Cannot edit file\n' + todir + ': Is a directory')
1297
1358
elif cmd == 4: # do something on file
1298
cmd2 = doEntry(tab.path, 'Do something on file', 'Enter command')
1359
cmd2 = doEntry(tab.path, 'Do something on file', 'Enter command', with_history='exec')
1300
1361
curses.endwin()
1301
1362
os.system(get_escaped_command(cmd2, f))
1309
def doEntry(tabpath, title, help, path = '',
1310
with_historic = True, with_complete = True):
1370
def doEntry(tabpath, title, help, path='', with_history='', with_complete=True):
1312
path = messages.Entry(title, help, path, with_historic, with_complete,
1372
path = messages.Entry(title, help, path, with_history, with_complete,
1314
1374
if isinstance(path, list):
1315
1375
path = path.pop()
1320
1380
def doDoubleEntry(tabpath, title, help1, path1, help2, path2,
1321
with_historic1 = True, with_complete1 = True,
1322
with_historic2 = True, with_complete2 = True):
1381
with_history1='', with_complete1=True,
1382
with_history2='', with_complete2=True):
1323
1383
tabpath1 = tabpath2 = tabpath
1325
1385
path = messages.DoubleEntry(title, help1, path1,
1326
with_historic1, with_complete1, tabpath1,
1386
with_history1, with_complete1, tabpath1,
1328
with_historic2, with_complete2, tabpath2,
1388
with_history2, with_complete2, tabpath2,
1329
1389
active_entry=0).run()
1330
1390
if not isinstance(path, list):