~ubuntu-branches/ubuntu/oneiric/lfm/oneiric

« back to all changes in this revision

Viewing changes to lfm/actions.py

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Echeverry
  • Date: 2011-05-21 12:03:10 UTC
  • mfrom: (2.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20110521120310-i6ifehdicskf7skp
Tags: 2.3-1
* New Upstream release.
* debian/control
  + Bumped standard versions 3.9.2 (no changes)
  + Now require python 2.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
9
9
import os, os.path
10
10
import sys
11
11
from glob import glob
 
12
from time import tzname, ctime
 
13
import datetime
 
14
import difflib
12
15
import curses
13
16
 
14
17
from __init__ import *
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
51
 
        
 
54
 
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
95
 
    
 
97
    0x19: 'select_history',    # Ctrl-Y
 
98
 
96
99
    # panels
97
100
    ord('\t'): 'toggle_active_pane',  # tab
98
101
    ord('.'): 'toggle_panes',
126
129
    ord('l'): 'create_link',
127
130
    ord('L'): 'edit_link',
128
131
    0x0F: 'open_shell',         # Ctrl-O
 
132
    0x18: 'show_cli',           # Ctrl-X
129
133
 
130
134
    # main functions
131
135
    curses.KEY_F2: 'rename',
146
150
 
147
151
    # terminal resize:
148
152
    curses.KEY_RESIZE: 'resize_window',
149
 
    0x12: 'refresh_screen',          # Ctrl-R
 
153
    0x12: 'refresh_screen',     # Ctrl-R
150
154
 
151
155
    # quit & exit
152
156
    ord('q'): 'quit',
153
157
    ord('Q'): 'quit',
154
158
    curses.KEY_F10: 'quit',
155
 
    0x11: 'exit'                     # Ctrl-Q
 
159
    0x11: 'exit'                # Ctrl-Q
156
160
}
157
161
 
158
162
 
221
225
    delta = int(tab.pane.dims[0]/4)
222
226
    tab.file_i += delta
223
227
    tab.fix_limits()
224
 
    return RET_HALF_UPDATE  
 
228
    return RET_HALF_UPDATE
225
229
 
226
230
# movement other pane
227
231
def cursor_up_otherpane(tab):
284
288
    else:
285
289
        return RET_NO_UPDATE
286
290
 
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
293
297
    else:
294
298
        return RET_NO_UPDATE
295
299
 
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
321
325
        return RET_HALF_UPDATE_OTHER
322
326
    else:
323
327
        return RET_NO_UPDATE
324
 
    
 
328
 
325
329
# change dir
326
330
def cursor_left(tab):
327
331
    tab.exit_dir()
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'):
338
342
        vfstype = None
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)))
 
348
        else:
 
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:
350
357
        return
351
358
 
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')
354
361
    if todir:
355
362
        app.display()
356
363
        todir = os.path.join(tab.path, todir)
359
366
        tab.init(todir)
360
367
 
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')
363
370
    if tofile:
364
371
        thefiles = tab.sorted[tab.file_i:]
365
372
        for f in thefiles:
373
380
def tree(tab):
374
381
    if tab.vfs:
375
382
        return
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)
379
 
    ans = t.run()
380
 
    del t
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
382
387
    if ans != -1:
383
388
        tab.init(ans)
384
389
 
421
426
 
422
427
def set_bookmark(tab):
423
428
    if tab.vfs:
424
 
        messages.error('Set bookmark', 'Can\'t bookmark inside vfs')
 
429
        messages.error('Cannot set bookmark inside vfs')
425
430
        return
426
431
    while True:
427
432
        ch = messages.get_a_key('Set bookmark',
433
438
            break
434
439
 
435
440
 
436
 
def select_historic(tab):
437
 
    items = tab.historic[::-1]
 
441
def select_history(tab):
 
442
    items = tab.history[::-1]
438
443
    if not items:
439
 
        messages.error('Select from history', 'No previous directories')
 
444
        messages.error('Cannot select directory from history\nNo entries yet')
440
445
        return
441
446
    ret = messages.MenuWin('Return to', items).run()
442
447
    if ret != -1:
485
490
 
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')
489
494
    else:
490
495
        return RET_TAB_NEW
491
496
 
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')
495
500
    else:
496
501
        if tab.vfs:
497
502
            vfs.exit(tab)
524
529
    tab.fix_limits()
525
530
 
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')
528
533
    if pattern:
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)
533
538
 
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')
536
541
    if pattern:
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 \
545
550
                          f != os.pardir]
546
551
 
 
552
 
547
553
# misc
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
552
 
    else:
553
 
        app.prefs.options['show_dotfiles'] = 0
 
555
    app.prefs.options['show_dotfiles'] = 1 if app.prefs.options['show_dotfiles']==0 else 0
554
556
    app.regenerate()
555
557
 
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
560
 
    else:
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
563
561
 
564
562
def show_size(tab):
581
579
    findgrep(tab)
582
580
 
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')
585
583
    if not newfile:
586
584
        return
587
585
    fullfilename = os.path.join(tab.path, newfile)
590
588
    if err:
591
589
        err = err.split(':')[-1:][0].strip()
592
590
        app.display()
593
 
        messages.error('Touch file', '%s: %s' % (newfile, err))
 
591
        messages.error('Cannot touch file\n%s: %s' % (newfile, err))
594
592
    else:
595
593
        curses.curs_set(0)
596
594
        app.regenerate()
602
600
    else:
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')
606
605
    app.display()
607
 
    if not newlink:
608
 
        messages.error('Create link', 'You must type new link name')
609
 
        return
610
 
    if not pointto:
611
 
        messages.error('Create link', 'You must type pointed file')
 
606
    if newlink is None or pointto is None:
 
607
        return
 
608
    if newlink == '':
 
609
        messages.error('Cannot create link\nYou must specify the name for the new link')
 
610
        return
 
611
    if pointto == '':
 
612
        messages.error('Cannot create link\nYou must specify the file to link')
612
613
        return
613
614
    fullfilename = os.path.join(tab.path, newlink)
614
615
    ans = files.create_link(pointto, fullfilename)
615
616
    if ans:
616
 
        messages.error('Create link', '%s (%s)' % (ans, tab.get_file()))
 
617
        messages.error('Cannot create link\n%s (%s)' % (ans, tab.get_file()))
617
618
    else:
618
619
        app.regenerate()
619
620
 
622
623
    if not os.path.islink(fullfilename):
623
624
        return
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')
626
627
    app.display()
627
 
    if not pointto:
628
 
        messages.error('Create link', 'You must type pointed file')
 
628
    if pointto is None:
 
629
        return
 
630
    elif pointto == '':
 
631
        messages.error('Cannot edit link\nYou must specify the file to link')
629
632
        return
630
633
    if pointto != os.readlink(fullfilename):
631
634
        ans = files.modify_link(pointto, fullfilename)
632
635
        if ans:
633
 
            messages.error('Edit link', '%s (%s)' % (ans, tab.getfile()))
 
636
            messages.error('Cannot edit link\n%s (%s)' % (ans, tab.getfile()))
634
637
    app.regenerate()
635
638
 
636
639
def open_shell(tab):
637
640
    curses.endwin()
638
 
    os.system('cd "%s"; %s' % (get_escaped_filename(tab.path),
639
 
                               app.prefs.progs['shell']))
640
 
    curses.curs_set(0)
641
 
    tab.refresh()
 
641
    os.system('cd "%s" && %s' % (get_escaped_filename(tab.path),
 
642
                                 app.prefs.progs['shell']))
 
643
    curses.curs_set(0)
 
644
    tab.refresh()
 
645
 
 
646
def show_cli(tab):
 
647
    app.cli.display()
 
648
    curses.curs_set(0)
 
649
    tab.refresh()
 
650
    app.regenerate()
642
651
 
643
652
 
644
653
# main functions
654
663
 
655
664
def rename(tab):
656
665
    fs = __rename_backup_helper(tab)
 
666
    if fs is None:
 
667
        return
657
668
    res = ProcessLoopRename('Rename files', files.do_rename, fs, tab.path).run()
658
669
    tab.selections = []
659
670
    tab.refresh()
661
672
 
662
673
def backup_file(tab):
663
674
    fs = __rename_backup_helper(tab)
 
675
    if fs is None:
 
676
        return
664
677
    try:
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')
669
682
        return
670
683
    res = ProcessLoopBackup('Backup files', files.do_backup, fs, tab.path,
671
684
                            app.prefs.misc['backup_extension']).run()
673
686
    tab.refresh()
674
687
    app.regenerate()
675
688
 
 
689
def diff_file(tab):
 
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)])
 
696
    else:
 
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')
 
701
        return
 
702
    if not os.path.exists(file_new):
 
703
        messages.error('Cannot diff file\nOnly backup file exists')
 
704
        return
 
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')
 
707
        return
 
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)
 
720
    diff = list(diff)
 
721
    if diff == []:
 
722
        messages.error('Files are identical')
 
723
        return
 
724
    tmpfile = os.path.join(files.mkdtemp(), os.path.basename(file_old) + \
 
725
                           ' DIFF ' + os.path.basename(file_new))
 
726
    f = open(tmpfile, 'w')
 
727
    f.writelines(diff)
 
728
    f.close()
 
729
    curses.endwin()
 
730
    os.system('%s \"%s\"' % (app.prefs.progs['pager'], tmpfile))
 
731
    curses.curs_set(0)
 
732
    files.delete_bulk(os.path.dirname(tmpfile), True)
 
733
 
676
734
def view_file(tab):
677
735
    do_view_file(tab)
678
736
 
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
692
750
    for f in fs:
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
699
757
    for f in fs:
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):
710
768
        for f in fs:
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
719
775
 
720
776
def copy(tab):
721
777
    destdir = app.noact_pane.act_tab.path + os.sep
728
784
            return
729
785
        buf = 'Copy \'%s\' to' % filename
730
786
        fs = [filename]
731
 
    destdir = doEntry(tab.path, 'Copy', buf, destdir)
 
787
    destdir = doEntry(tab.path, 'Copy', buf, destdir, with_history='path')
732
788
    if destdir:
733
789
        st, destdir, rename_dir = __copymove_helper(destdir, tab.path, fs)
734
790
        if st == -1:
737
793
            pc = files.PathContents(fs, tab.path)
738
794
        except UnicodeError:
739
795
            app.display()
740
 
            messages.error('Copy files', 'Files with invalid encoding, convert first')
 
796
            messages.error('Cannot copy files\nFiles with invalid encoding, convert first')
741
797
            return
742
798
        res = ProcessLoopCopy('Copy files', files.do_copy, pc,
743
799
                              destdir, rename_dir).run()
744
800
        tab.selections = []
745
801
        app.regenerate()
746
 
        
 
802
 
747
803
def move(tab):
748
804
    destdir = app.noact_pane.act_tab.path + os.sep
749
805
    if tab.selections:
755
811
            return
756
812
        buf = 'Move \'%s\' to' % filename
757
813
        fs = [filename]
758
 
    destdir = doEntry(tab.path, 'Move', buf, destdir)
 
814
    destdir = doEntry(tab.path, 'Move', buf, destdir, with_history='path')
759
815
    if destdir:
760
816
        st, destdir, rename_dir = __copymove_helper(destdir, tab.path, fs)
761
817
        if st == -1:
764
820
            pc = files.PathContents(fs, tab.path)
765
821
        except UnicodeError:
766
822
            app.display()
767
 
            messages.error('Move files', 'Files with invalid encoding, convert first')
 
823
            messages.error('Cannot move files\nFiles with invalid encoding, convert first')
768
824
            return
769
825
        res = ProcessLoopCopy('Move files', files.do_copy, pc,
770
826
                              destdir, rename_dir).run()
779
835
        tab.refresh()
780
836
 
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')
783
839
    if newdir:
784
840
        ans = files.mkdir(tab.path, newdir)
785
841
        if ans:
786
842
            app.display()
787
 
            messages.error('Make directory',
788
 
                           '%s (%s)' % ans)
 
843
            messages.error('Cannot make directory\n' +
 
844
                           newdir + ': %s (%s)' % ans)
789
845
        else:
790
846
            app.regenerate()
791
847
 
800
856
    try:
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')
804
860
        return
805
861
    res = ProcessLoopDelete('Delete files', files.do_delete, pc).run()
806
862
    tab.selections = []
831
887
             'i    File info',
832
888
             'p    Change file permissions, owner, group',
833
889
             'a    Backup file',
834
 
             'g    Gzip/gunzip file(s)',
835
 
             'b    Bzip2/bunzip2 file(s)',
836
 
             'h    Xz/unxz 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()
846
896
    if cmd == -1:
847
897
        return
855
905
        do_change_perms(tab)
856
906
    elif cmd == 'a':
857
907
        backup_file(tab)
858
 
    elif cmd == 'g':
859
 
        compress_uncompress_file(tab, 'gz')
860
 
    elif cmd == 'b':
861
 
        compress_uncompress_file(tab, 'bz2')
862
 
    elif cmd == 'h':
863
 
        compress_uncompress_file(tab, 'xz')
 
908
    elif cmd == 'd':
 
909
        diff_file(tab)
 
910
    elif cmd == 'z':
 
911
        compress_fmts = {'g': 'gz', 'b': 'bz2', 'x': 'xz'}
 
912
        while True:
 
913
            ch = messages.get_a_key('Un/Compress file(s)',
 
914
                                    '(g)zip, (b)zip2, (x)z\n\n'
 
915
                                    '   Ctrl-C to quit')
 
916
            if ch == -1: # Ctrl-C
 
917
                break
 
918
            elif chr(ch) in compress_fmts.keys():
 
919
                compress_uncompress_file(tab, compress_fmts[chr(ch)])
 
920
                break
864
921
    elif cmd == 'x':
865
922
        uncompress_dir(tab, tab.path)
866
923
    elif cmd == 'u':
867
924
        uncompress_dir(tab, app.noact_pane.act_tab.path)
868
925
    elif cmd == 'c':
869
 
        compress_dir(tab, 'tgz')
870
 
    elif cmd == 'd':
871
 
        compress_dir(tab, 'tbz2')
872
 
    elif cmd == 'e':
873
 
        compress_dir(tab, 'txz')
874
 
    elif cmd == 'z':
875
 
        compress_dir(tab, 'zip')
876
 
    elif cmd == 'r':
877
 
        compress_dir(tab, 'rar')
878
 
    elif cmd == '7':
879
 
        compress_dir(tab, '7z')
 
926
        if not tab.selections and os.path.basename(tab.sorted[tab.file_i])==os.pardir:
 
927
            return
 
928
        compress_fmts = {'g': 'tgz', 'b': 'tbz2', 'x': 'txz', 't': 'tar',
 
929
                         'z': 'zip', 'r': 'rar', '7': '7z'}
 
930
        while True:
 
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'
 
933
                                    '                    Ctrl-C to quit')
 
934
            if ch == -1: # Ctrl-C
 
935
                break
 
936
            elif chr(ch) in compress_fmts.keys():
 
937
                compress_dir(tab, compress_fmts[chr(ch)])
 
938
                break
880
939
    app.regenerate()
881
940
 
882
941
 
888
947
             'f    Show filesystems info',
889
948
             'o    Open shell',
890
949
             'c    Edit configuration',
891
 
             'r    Regenerate programs' ]
 
950
             'r    Regenerate programs',
 
951
             'h    Delete history' ]
892
952
    cmd = messages.MenuWin('General Menu', menu).run()
893
953
    if cmd == -1:
894
954
        return
915
975
        app.prefs.check_progs()
916
976
        app.prefs.save()
917
977
        app.prefs.load()
918
 
        messages.win('Regenerate programs', '          OK')
 
978
        messages.win('Configuration', 'Regenerating programs... OK')
 
979
    elif cmd == 'h':
 
980
        files.delete_bulk(messages.HISTORY_FILE)
 
981
        messages.history = messages.DEFAULT_HISTORY.copy()
919
982
 
920
983
 
921
984
# window resize
1010
1073
        if ext in exts:
1011
1074
            prog = app.prefs.progs[typ]
1012
1075
            if prog == '':
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)
1016
1079
                break
1036
1099
# do view file
1037
1100
def do_view_file(tab):
1038
1101
    run_on_current_file('pager', tab.get_fullpathfile())
 
1102
    app.regenerate()
1039
1103
 
1040
1104
 
1041
1105
# do edit file
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:
1052
1116
        return
1053
1117
    elif parms == '':
1054
1118
        cmd = get_escaped_filename(filename)
1055
1119
    else:
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()
1060
1124
    if st == -1:
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)
1070
1134
    tab.refresh()
1072
1136
 
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')
1076
1140
    if cmd:
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):
1093
 
        import stat
1094
 
        from time import ctime
1095
 
 
1096
1157
        fullfilename = os.path.join(tab.path, file)
1097
1158
        fd = tab.files[file]
1098
1159
        fde = files.get_fileinfo_extended(fullfilename)
1146
1207
    try:
1147
1208
        ans = files.set_perms(filename, perms, recursive)
1148
1209
        if ans:
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)
1151
1212
        if ans:
1152
 
            messages.error('Chown "%s"' % filename, '%s (%s)' % ans)
 
1213
            messages.error('Cannot chown\n' + filename + ': %s (%s)' % ans)
1153
1214
    except UnicodeError:
1154
1215
        app.display()
1155
 
        messages.error('Change permissions',
 
1216
        messages.error('Cannot change permissions\n' +
1156
1217
                       'Files with invalid encoding, convert first')
1157
1218
 
1158
1219
 
1187
1248
# do show filesystems info
1188
1249
def do_show_fs_info():
1189
1250
    try:
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))
1193
 
        return
1194
 
    if fs is None or fs == '':
1195
 
        messages.error('Show filesystems info', ('Can\'t run "df" command', 0))
1196
 
        return
1197
 
    fs = fs.split('\n')
1198
 
    buf = []
1199
 
    buf.append((fs[0].strip(), 6))
1200
 
    buf.append(('-'*len(fs[0]), 6))
1201
 
    for l in fs[1:]:
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))
 
1254
        return
 
1255
    if buf is None or buf == '':
 
1256
        messages.error('Cannot show filesystems info\n%s (%s)' % ('Can\'t run "df" command', 0))
 
1257
        return
 
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)]
 
1261
    for l in fs:
 
1262
        lst.append((l, 2))
 
1263
    pyview.InternalView('Show filesystems info', lst).run()
1204
1264
 
1205
1265
 
1206
1266
# find and grep
1207
1267
def findgrep(tab):
1208
1268
    # ask data
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 == '':
1212
1273
        return
1213
1274
    path = os.path.dirname(fs)
1228
1289
            return
1229
1290
        else: # some other error
1230
1291
            app.display()
1231
 
            messages.error(search_type, m)
 
1292
            messages.error('Cannot %s\n' % search_type.lower() + m)
1232
1293
            return
1233
1294
    if not m or m == []:
1234
1295
        app.display()
1235
 
        messages.error(search_type, 'No files found')
 
1296
        messages.error('Cannot %s\n' % search_type.lower() + 'No files found')
1236
1297
        return
1237
1298
    # show matches
1238
1299
    find_quit = 0
1242
1303
        if par:
1243
1304
            if pat:
1244
1305
                try:
1245
 
                    line = int(par.split(':')[0])
 
1306
                    line = int(par.split(':')[-1])
1246
1307
                except ValueError:
1247
1308
                    line = 0
1248
1309
                    f = os.path.join(path, par)
1249
1310
                else:
1250
 
                    f = os.path.join(path, par[par.find(':')+1:])
 
1311
                    f = os.path.join(path, par[:par.rfind(':')])
1251
1312
            else:
1252
1313
                line = 0
1253
1314
                f = os.path.join(path, par)
1263
1324
            tab.vfs, tab.base, tab.vbase = pvfs, base, vbase
1264
1325
            if tofile:
1265
1326
                tab.file_i = tab.sorted.index(tofile)
 
1327
                tab.fix_limits()
1266
1328
            find_quit = 1
1267
1329
        elif cmd == 1:           # panelize
1268
1330
            if pat:
1279
1341
                                              line, get_escaped_filename(f)))
1280
1342
                curses.curs_set(0)
1281
1343
            else:
1282
 
                messages.error('View', 'it\'s a directory',
1283
 
                               todir)
 
1344
                messages.error('Cannot view file\n' + todir + ': Is a directory')
1284
1345
        elif cmd == 3:           # edit
1285
1346
            if tofile:
1286
1347
                curses.endwin()
1293
1354
                curses.curs_set(0)
1294
1355
                app.regenerate()
1295
1356
            else:
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')
1299
1360
            if cmd2:
1300
1361
                curses.endwin()
1301
1362
                os.system(get_escaped_command(cmd2, f))
1306
1367
 
1307
1368
 
1308
1369
# entries
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):
1311
1371
    while True:
1312
 
        path = messages.Entry(title, help, path, with_historic, with_complete,
 
1372
        path = messages.Entry(title, help, path, with_history, with_complete,
1313
1373
                              tabpath).run()
1314
1374
        if isinstance(path, list):
1315
1375
            path = path.pop()
1318
1378
 
1319
1379
 
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
1324
1384
    while True:
1325
1385
        path = messages.DoubleEntry(title, help1, path1,
1326
 
                                    with_historic1, with_complete1, tabpath1,
 
1386
                                    with_history1, with_complete1, tabpath1,
1327
1387
                                    help2, path2,
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):
1331
1391
            return path
1672
1732
 
1673
1733
 
1674
1734
######################################################################
 
1735