2 # -*- coding: utf-8 -*-
4 # Copyright (C) 2001-7 Iñigo Serna
5 # Time-stamp: <2007-09-02 21:25:16 inigo>
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 u
"""lfm v2.0 - (C) 2001-7, by Iñigo Serna <inigoserna@telefonica.net>
23 'Last File Manager' is a file manager for UNIX console which born with
24 midnight commander as model. Released under GNU Public License, read
25 COPYING file for more details.
27 Usage:\tlfm <options> [path1 [path2]]
30 path1 Directory to show in left pane
31 path2 Directory to show in right pane
34 -1 Start in 1-pane mode
35 -2 Start in 2-panes mode (default)
36 -d, --debug Create debug file
41 __author__
= u
'Iñigo Serna'
52 from __init__
import *
53 from config
import Config
, colors
62 ######################################################################
63 ##### Global variables
64 LOG_FILE
= os
.path
.join(os
.getcwd(), 'lfm.log')
67 ######################################################################
70 """Main application class"""
72 def __init__(self
, win
, prefs
):
73 self
.win
= win
# root window, needed for resizing
74 self
.prefs
= prefs
# preferences
76 self
.statusbar
= StatusBar(self
.maxh
, self
) # statusbar
77 self
.lpane
= Pane(PANE_MODE_LEFT
, self
) # left pane
78 self
.rpane
= Pane(PANE_MODE_RIGHT
, self
) # right pane
79 self
.act_pane
, self
.noact_pane
= self
.lpane
, self
.rpane
80 if self
.prefs
.options
['num_panes'] == 1:
81 self
.lpane
.mode
= PANE_MODE_FULL
83 self
.rpane
.mode
= PANE_MODE_HIDDEN
85 actions
.app
= messages
.app
= utils
.app
= vfs
.app
= pyview
.app
= self
88 def load_paths(self
, paths1
, paths2
):
89 self
.lpane
.load_tabs_with_paths(paths1
)
90 self
.rpane
.load_tabs_with_paths(paths2
)
94 """initialize curses stuff: windows, colors..."""
96 self
.maxh
, self
.maxw
= self
.win
.getmaxyx()
99 messages
.cursor_hide()
102 if curses
.has_colors():
103 prefs_colors
= self
.prefs
.colors
104 # Translation table: color name -> curses color name
106 'black': curses
.COLOR_BLACK
,
107 'blue': curses
.COLOR_BLUE
,
108 'cyan': curses
.COLOR_CYAN
,
109 'green': curses
.COLOR_GREEN
,
110 'magenta': curses
.COLOR_MAGENTA
,
111 'red': curses
.COLOR_RED
,
112 'white': curses
.COLOR_WHITE
,
113 'yellow': curses
.COLOR_YELLOW
}
114 # Initialize every color pair with user colors or with the defaults
115 color_items
= ['title', 'files', 'current_file', 'messages', 'help',
116 'file_info', 'error_messages1', 'error_messages2',
117 'buttons', 'selected_file', 'current_selected_file',
118 'tabs', 'temp_files', 'document_files', 'media_files',
119 'archive_files', 'source_files', 'graphics_files',
121 for i
, color_name
in enumerate(color_items
):
122 curses
.init_pair(i
+1,
123 self
.__set
_color
(prefs_colors
[color_name
][0],
124 self
.coltbl
[colors
[color_name
][0]]),
125 self
.__set
_color
(prefs_colors
[color_name
][1],
126 self
.coltbl
[colors
[color_name
][1]]))
129 def __set_color(self
, col
, defcol
):
130 """return curses color value if exists, otherwise return default"""
132 if self
.coltbl
.has_key(col
):
133 return self
.coltbl
[col
]
141 h
, w
= self
.win
.getmaxyx()
142 self
.maxh
, self
.maxw
= h
, w
145 self
.win
.resize(h
, w
)
146 self
.lpane
.do_resize(h
, w
)
147 self
.rpane
.do_resize(h
, w
)
148 self
.statusbar
.do_resize(h
, w
)
154 """show files pane and status bar"""
158 self
.statusbar
.display()
161 def regenerate(self
):
162 """Rebuild panes' directories"""
164 self
.lpane
.regenerate()
165 self
.rpane
.regenerate()
168 def quit_program(self
, icode
):
169 """save settings and prepare to quit"""
171 for tab
in self
.lpane
.tabs
+ self
.rpane
.tabs
:
174 if self
.prefs
.options
['save_conf_at_exit']:
176 if icode
== -1: # change directory
177 return self
.act_pane
.act_tab
.path
178 else: # exit, but don't change directory
183 """run application"""
187 ret
= self
.act_pane
.manage_keys()
189 return self
.quit_program(ret
)
190 elif ret
== TOGGLE_PANE
:
191 if self
.act_pane
== self
.lpane
:
192 self
.act_pane
, self
.noact_pane
= self
.rpane
, self
.lpane
194 self
.act_pane
, self
.noact_pane
= self
.lpane
, self
.rpane
196 tab
= self
.act_pane
.act_tab
198 path
= os
.path
.dirname(tab
.vbase
)
201 idx
= self
.act_pane
.tabs
.index(tab
)
202 newtab
= TabVfs(self
.act_pane
)
204 self
.act_pane
.tabs
.insert(idx
+1, newtab
)
205 self
.act_pane
.act_tab
= newtab
206 elif ret
== TAB_CLOSE
:
207 tab
= self
.act_pane
.act_tab
208 idx
= self
.act_pane
.tabs
.index(tab
)
209 self
.act_pane
.act_tab
= self
.act_pane
.tabs
[idx
-1]
210 self
.act_pane
.tabs
.remove(tab
)
214 ######################################################################
215 ##### StatusBar class
219 def __init__(self
, maxh
, app
):
222 self
.win
= curses
.newwin(1, 0, maxh
-1, 0)
224 print 'Can\'t create StatusBar window'
226 if curses
.has_colors():
227 self
.win
.bkgd(curses
.color_pair(1))
230 def do_resize(self
, h
, w
):
231 self
.win
.resize(1, w
)
232 self
.win
.mvwin(h
-1, 0)
236 """show status bar"""
239 adir
= self
.app
.act_pane
.act_tab
241 if len(adir
.selections
):
244 for f
in adir
.selections
:
245 size
+= adir
.files
[f
][files
.FT_SIZE
]
246 self
.win
.addstr(' %s bytes in %d files' % \
247 (num2str(size
), len(adir
.selections
)))
250 self
.win
.addstr('File: %4d of %-4d' % \
251 (adir
.file_i
+ 1, adir
.nfiles
))
252 filename
= adir
.sorted[adir
.file_i
]
254 realpath
= os
.path
.join(vfs
.join(self
.app
.act_pane
.act_tab
),
257 realpath
= files
.get_realpath(adir
.path
, filename
,
258 adir
.files
[filename
][files
.FT_TYPE
])
259 realpath
= utils
.decode(realpath
)
260 if len(realpath
) > maxw
- 35:
261 path
= '~' + realpath
[-(maxw
-37):]
264 path
= utils
.encode(path
)
265 self
.win
.addstr(0, 20, 'Path: ' + path
)
268 self
.win
.addstr(0, maxw
-8, 'F1=Help')
274 ######################################################################
277 """The Pane class is like a notebook containing TabVfs"""
279 def __init__(self
, mode
, app
):
282 self
.dims
= [0, 0, 0, 0] # h, w, y0, x0
283 self
.maxh
, self
.maxw
= app
.maxh
, app
.maxw
288 def load_tabs_with_paths(self
, paths
):
293 tab
.init(os
.path
.abspath('.'))
294 self
.tabs
.append(tab
)
295 self
.act_tab
= self
.tabs
[0]
299 self
.dims
= self
.__calculate
_dims
()
301 self
.win
= curses
.newwin(*self
.dims
)
303 print 'Can\'t create Pane window'
306 if curses
.has_colors():
307 self
.win
.bkgd(curses
.color_pair(2))
308 self
.__calculate
_columns
()
311 def __calculate_dims(self
):
312 if self
.mode
== PANE_MODE_HIDDEN
:
313 return (self
.maxh
-2, self
.maxw
, 0, 0) # h, w, y0, x0
314 elif self
.mode
== PANE_MODE_LEFT
:
315 return (self
.maxh
-2, int(self
.maxw
/2), 1, 0)
316 elif self
.mode
== PANE_MODE_RIGHT
:
317 return (self
.maxh
-2, self
.maxw
-int(self
.maxw
/2), 1, int(self
.maxw
/2))
318 elif self
.mode
== PANE_MODE_FULL
:
319 return (self
.maxh
-2, self
.maxw
, 1, 0) # h, w, y0, x0
321 messages
.error('Initialize Panes Error',
322 'Incorrect pane number.\nLook for bugs if you can see this.')
323 return (self
.maxh
-2, int(self
.maxw
/2), 1, int(self
.maxw
/2))
326 def __calculate_columns(self
):
327 self
.pos_col2
= self
.dims
[1] - 14 # sep between size and date
328 self
.pos_col1
= self
.pos_col2
- 8 # sep between filename and size
331 def do_resize(self
, h
, w
):
332 self
.maxh
, self
.maxw
= h
, w
333 self
.dims
= self
.__calculate
_dims
()
334 self
.win
.resize(self
.dims
[0], self
.dims
[1])
335 self
.win
.mvwin(self
.dims
[2], self
.dims
[3])
336 self
.__calculate
_columns
()
337 for tab
in self
.tabs
:
344 if self
.mode
== PANE_MODE_HIDDEN
:
350 self
.display_cursorbar()
353 def display_tabs(self
):
354 tabs
= curses
.newpad(1, self
.dims
[1]+1)
355 tabs
.bkgd(curses
.color_pair(12))
360 tabs
.addstr(('[' + ' '*(w
-2) + ']') * len(self
.tabs
))
361 for i
, tab
in enumerate(self
.tabs
):
363 path
= '[ %d ]' % (i
+1, )
366 path
= os
.path
.basename(tab
.vbase
.split('#')[0])
368 path
= os
.path
.basename(tab
.path
)
370 path
= os
.path
.dirname(tab
.path
)
371 path
= utils
.decode(path
)
372 if len(path
) > w
- 2:
373 path
= '[%s~]' % path
[:w
-3]
375 path
= '[' + path
+ ' ' * (w
-2-len(path
)) + ']'
376 path
= utils
.encode(path
)
377 if tab
== self
.act_tab
:
378 attr
= curses
.color_pair(10) #| curses.A_BOLD
380 attr
= curses
.color_pair(1)
381 tabs
.addstr(0, i
*w
, path
, attr
)
382 tabs
.refresh(0, 0, 0, self
.dims
[3], 1, self
.dims
[3]+self
.dims
[1]-1)
385 def get_filetypecolorpair(self
, f
, typ
):
386 if typ
== files
.FTYPE_DIR
:
387 return curses
.color_pair(5)
388 elif typ
== files
.FTYPE_EXE
:
389 return curses
.color_pair(6) | curses
.A_BOLD
390 ext
= os
.path
.splitext(f
)[1].lower()
391 files_ext
= self
.app
.prefs
.files_ext
392 if ext
in files_ext
['temp_files']:
393 return curses
.color_pair(13)
394 elif ext
in files_ext
['document_files']:
395 return curses
.color_pair(14)
396 elif ext
in files_ext
['media_files']:
397 return curses
.color_pair(15)
398 elif ext
in files_ext
['archive_files']:
399 return curses
.color_pair(16)
400 elif ext
in files_ext
['source_files']:
401 return curses
.color_pair(17)
402 elif ext
in files_ext
['graphics_files']:
403 return curses
.color_pair(18)
404 elif ext
in files_ext
['data_files']:
405 return curses
.color_pair(19)
407 return curses
.color_pair(2)
410 def display_files(self
):
414 # calculate pane width, height and vertical start position
416 if self
.mode
!= PANE_MODE_FULL
:
417 h
, y
= self
.maxh
-5, 2
419 h
, y
= self
.maxh
-2, 0
422 if self
.mode
!= PANE_MODE_FULL
:
423 if self
== self
.app
.act_pane
:
424 self
.win
.attrset(curses
.color_pair(5))
425 attr
= curses
.color_pair(6) | curses
.A_BOLD
427 self
.win
.attrset(curses
.color_pair(2))
428 attr
= curses
.color_pair(2)
433 path
= utils
.decode(path
)
434 if len(path
) > w
- 5:
435 title_path
= '~' + path
[-w
+5:]
438 title_path
= utils
.encode(title_path
)
440 self
.win
.addstr(0, 2, title_path
, attr
)
441 self
.win
.addstr(1, 1,
442 'Name'.center(self
.pos_col1
-2)[:self
.pos_col1
-2],
443 curses
.color_pair(2) | curses
.A_BOLD
)
444 self
.win
.addstr(1, self
.pos_col1
+2, 'Size',
445 curses
.color_pair(2) | curses
.A_BOLD
)
446 self
.win
.addstr(1, self
.pos_col2
+5, 'Date',
447 curses
.color_pair(2) | curses
.A_BOLD
)
450 self
.win
.vline(0, w
-1, curses
.ACS_VLINE
, h
)
453 for i
in xrange(tab
.file_z
- tab
.file_a
+ 1):
454 filename
= tab
.sorted[i
+tab
.file_a
]
456 res
= files
.get_fileinfo_dict(tab
.path
, filename
,
459 if not tab
.selections
.count(filename
):
460 if self
.app
.prefs
.options
['color_files']:
461 attr
= self
.get_filetypecolorpair(filename
, tab
.files
[filename
][files
.FT_TYPE
])
463 attr
= curses
.color_pair(2)
465 attr
= curses
.color_pair(10) | curses
.A_BOLD
468 if self
.mode
== PANE_MODE_FULL
:
469 buf
= tab
.get_fileinfo_str_long(res
, w
)
470 self
.win
.addstr(i
, 0, buf
, attr
)
472 buf
= tab
.get_fileinfo_str_short(res
, w
, self
.pos_col1
)
473 self
.win
.addstr(i
+2, 1, buf
, attr
)
475 # vertical separators
476 if self
.mode
!= PANE_MODE_FULL
:
477 self
.win
.vline(1, self
.pos_col1
, curses
.ACS_VLINE
, self
.dims
[0]-2)
478 self
.win
.vline(1, self
.pos_col2
, curses
.ACS_VLINE
, self
.dims
[0]-2)
480 # vertical scroll bar
481 y0
, n
= self
.__calculate
_scrollbar
_dims
(h
, tab
.nfiles
, tab
.file_i
)
482 self
.win
.vline(y
+y0
, w
-1, curses
.ACS_CKBOARD
, n
)
484 self
.win
.vline(y
, w
-1, '^', 1)
485 if (n
== 1) and (y0
== 0):
486 self
.win
.vline(y
+1, w
-1, curses
.ACS_CKBOARD
, n
)
487 if tab
.nfiles
> tab
.file_a
+ h
:
488 self
.win
.vline(h
+y
-1, w
-1, 'v', 1)
489 if (n
== 1) and (y0
== h
-1):
490 self
.win
.vline(h
+y
-2, w
-1, curses
.ACS_CKBOARD
, n
)
495 def __calculate_scrollbar_dims(self
, h
, nels
, i
):
496 """calculate scrollbar initial position and size"""
499 n
= max(int(h
*h
/nels
), 1)
500 y0
= min(max(int(int(i
/h
)*h
*h
/nels
),0), h
-n
)
506 def display_cursorbar(self
):
507 if self
!= self
.app
.act_pane
:
509 if self
.mode
== PANE_MODE_FULL
:
510 cursorbar
= curses
.newpad(1, self
.maxw
)
512 cursorbar
= curses
.newpad(1, self
.dims
[1]-1)
513 cursorbar
.bkgd(curses
.color_pair(3))
517 filename
= tab
.sorted[tab
.file_i
]
520 tab
.selections
.index(filename
)
522 attr
= curses
.color_pair(3)
524 attr
= curses
.color_pair(11) | curses
.A_BOLD
526 res
= files
.get_fileinfo_dict(tab
.path
, filename
, tab
.files
[filename
])
527 if self
.mode
== PANE_MODE_FULL
:
528 buf
= tab
.get_fileinfo_str_long(res
, self
.maxw
)
529 cursorbar
.addstr(0, 0, buf
, attr
)
530 cursorbar
.refresh(0, 0,
531 tab
.file_i
% self
.dims
[0] + 1, 0,
532 tab
.file_i
% self
.dims
[0] + 1, self
.maxw
-2)
534 buf
= tab
.get_fileinfo_str_short(res
, self
.dims
[1], self
.pos_col1
)
535 cursorbar
.addstr(0, 0, buf
, attr
)
536 cursorbar
.addch(0, self
.pos_col1
-1, curses
.ACS_VLINE
)
537 cursorbar
.addch(0, self
.pos_col2
-1, curses
.ACS_VLINE
)
538 row
= tab
.file_i
% (self
.dims
[0]-3) + 3
539 if self
.mode
== PANE_MODE_LEFT
:
540 cursorbar
.refresh(0, 0,
541 row
, 1, row
, int(self
.maxw
/2)-2)
543 cursorbar
.refresh(0, 0,
544 row
, int(self
.maxw
/2)+1, row
, self
.maxw
-2)
547 def regenerate(self
):
548 """Rebuild tabs' directories, this is needed because panel
551 for tab
in self
.tabs
:
558 def manage_keys(self
):
561 ch
= self
.win
.getch()
562 if ch
== -1: # no key pressed
567 # if ch == 0x1B: # ESC
568 # ch = self.app.win.getch() + 0x100
569 # print 'key: \'%s\' <=> %c <=> 0x%X <=> %d' % \
570 # (curses.keyname(ch), ch & 255, ch, ch)
571 # messages.win('Keyboard hitted:',
572 # 'key: \'%s\' <=> %c <=> 0x%X <=> %d' % \
573 # (curses.keyname(ch), ch & 255, ch, ch))
574 ret
= actions
.do(self
.act_tab
, ch
)
581 ######################################################################
584 """Vfs class contains files information in a directory"""
594 self
.vfs
= '' # vfs? if not -> blank string
595 self
.base
= '' # tempdir basename
596 self
.vbase
= self
.path
# virtual directory basename
599 def init_dir(self
, path
):
602 self
.nfiles
, self
.files
= files
.get_dir(path
, app
.prefs
.options
['show_dotfiles'])
603 sortmode
= app
.prefs
.options
['sort']
604 sort_mix_dirs
= app
.prefs
.options
['sort_mix_dirs']
605 sort_mix_cases
= app
.prefs
.options
['sort_mix_cases']
607 self
.sorted = files
.sort_dir(self
.files
, sortmode
,
608 sort_mix_dirs
, sort_mix_cases
)
609 self
.sort_mode
= sortmode
610 self
.path
= os
.path
.abspath(path
)
612 except (IOError, OSError), (errno
, strerror
):
613 return (strerror
, errno
)
617 self
.vbase
= self
.path
620 def init(self
, path
, old_file
= ''):
621 raise NotImplementedError
624 def enter_dir(self
, filename
):
626 if self
.path
== self
.base
and filename
== os
.pardir
:
628 self
.init(os
.path
.dirname(self
.vbase
),
629 old_file
=os
.path
.basename(self
.vbase
).replace('#vfs', ''))
631 pvfs
, base
, vbase
= self
.vfs
, self
.base
, self
.vbase
632 self
.init(os
.path
.join(self
.path
, filename
))
633 self
.vfs
, self
.base
, self
.vbase
= pvfs
, base
, vbase
635 if filename
== os
.pardir
:
636 self
.init(os
.path
.dirname(self
.path
),
637 old_file
=os
.path
.basename(self
.path
))
639 self
.init(os
.path
.join(self
.path
, filename
),
640 old_file
=self
.sorted[self
.file_i
],
646 if self
.path
== self
.base
:
648 self
.init(os
.path
.dirname(self
.vbase
),
649 old_file
=os
.path
.basename(self
.vbase
).replace('#vfs', ''))
651 pvfs
, base
, vbase
= self
.vfs
, self
.base
, self
.vbase
652 self
.init(os
.path
.dirname(self
.path
),
653 old_file
=os
.path
.basename(self
.path
))
654 self
.vfs
, self
.base
, self
.vbase
= pvfs
, base
, vbase
656 if self
.path
!= os
.sep
:
657 self
.init(os
.path
.dirname(self
.path
),
658 old_file
=os
.path
.basename(self
.path
))
662 self
.old_file
= self
.sorted[self
.file_i
]
663 self
.old_file_i
= self
.file_i
664 self
.old_vfs
= self
.vfs
, self
.base
, self
.vbase
669 self
.file_i
= self
.sorted.index(self
.old_file
)
671 if self
.old_file_i
< len(self
.sorted):
672 self
.file_i
= self
.old_file_i
674 self
.file_i
= len(self
.sorted) - 1
675 self
.vfs
, self
.base
, self
.vbase
= self
.old_vfs
682 def regenerate(self
):
683 """Rebuild tabs' directories"""
686 if path
[-1] == os
.sep
:
688 if path
== '': path
= os
.sep
689 while not os
.path
.exists(path
):
690 path
= os
.path
.dirname(path
)
692 if path
!= self
.path
:
695 pvfs
, base
, vbase
= self
.vfs
, self
.base
, self
.vbase
696 self
.init_dir(self
.path
)
697 self
.vfs
, self
.base
, self
.vbase
= pvfs
, base
, vbase
700 filename_old
= self
.sorted[self
.file_i
]
701 selections_old
= self
.selections
[:]
702 pvfs
, base
, vbase
= self
.vfs
, self
.base
, self
.vbase
703 self
.init_dir(self
.path
)
704 self
.vfs
, self
.base
, self
.vbase
= pvfs
, base
, vbase
706 self
.file_i
= self
.sorted.index(filename_old
)
709 self
.selections
= selections_old
[:]
710 for f
in self
.selections
:
711 if f
not in self
.sorted:
712 self
.selections
.remove(f
)
716 file_i_old
= self
.file_i
717 file_old
= self
.sorted[self
.file_i
]
718 self
.pane
.app
.regenerate()
720 self
.file_i
= self
.sorted.index(file_old
)
722 self
.file_i
= file_i_old
726 def get_fileinfo_str_short(self
, res
, maxw
, pos_col1
):
727 filewidth
= maxw
- 24
728 fname
= utils
.decode(res
['filename'])
729 if len(fname
) > filewidth
:
730 half
= int(filewidth
/2)
731 fname
= fname
[:half
+2] + '~' + fname
[-half
+3:]
732 fname
= fname
.ljust(pos_col1
-2)[:pos_col1
-2]
733 fname
= utils
.encode(fname
)
735 buf
= '%c%s %3d,%3d %12s' % \
736 (res
['type_chr'], fname
,
737 res
['maj_rdev'], res
['min_rdev'],
740 buf
= '%c%s %7s %12s' % \
741 (res
['type_chr'], fname
,
742 res
['size'], res
['mtime2'])
746 def get_fileinfo_str_long(self
, res
, maxw
):
747 filewidth
= maxw
- 57
748 fname
= utils
.decode(res
['filename'])
749 if len(fname
) > filewidth
:
750 half
= int(filewidth
/2)
751 fname
= fname
[:half
+2] + '~' + fname
[-half
+2:]
752 fname
= utils
.encode(fname
)
754 buf
= '%c%9s %-8s %-8s %3d,%3d %16s %s' % \
755 (res
['type_chr'], res
['perms'],
756 res
['owner'][:8], res
['group'][:8],
757 res
['maj_rdev'], res
['min_rdev'],
760 buf
= '%c%9s %-8s %-8s %7s %16s %s' % \
761 (res
['type_chr'], res
['perms'],
762 res
['owner'][:8], res
['group'][:8],
769 """return pointed file"""
770 return self
.sorted[self
.file_i
]
773 def get_fullpathfile(self
):
774 """return full path for pointed file"""
775 return os
.path
.join(self
.path
, self
.sorted[self
.file_i
])
778 ######################################################################
781 """TabVfs class is the UI container for Vfs class"""
783 def __init__(self
, pane
):
788 def init(self
, path
, old_file
= '', check_oldfile
=True):
789 path
= os
.path
.expanduser(path
)
790 path
= os
.path
.expandvars(path
)
791 err
= self
.init_dir(path
)
793 messages
.error('Enter In Directory', '%s (%d)' % err
, path
)
794 if (check_oldfile
and old_file
) or (old_file
and err
):
796 self
.file_i
= self
.sorted.index(old_file
)
805 def fix_limits(self
):
806 self
.file_i
= max(0, min(self
.file_i
, self
.nfiles
-1))
807 if self
.pane
.mode
== PANE_MODE_HIDDEN
or \
808 self
.pane
.mode
== PANE_MODE_FULL
:
809 height
= self
.pane
.dims
[0]
811 height
= self
.pane
.dims
[0] - 3
812 self
.file_a
= int(self
.file_i
/height
) * height
813 self
.file_z
= min(self
.file_a
+height
-1, self
.nfiles
-1)
816 ######################################################################
820 # return (len(num) < 4) and num or (num2str(num[:-3]) + "." + num[-3:])
822 while num
/ 1000.0 >= 0.001:
823 num_list
.append('%.3d' % (num
% 1000))
827 if len(num_list
) != 0:
829 num_str
= ','.join(num_list
)
830 while num_str
[0] == '0':
831 num_str
= num_str
[1:]
835 ######################################################################
839 print 'lfm:\tERROR: %s\n' % msg
843 def lfm_exit(ret_code
, ret_path
='.'):
844 f
= open('/tmp/lfm-%s.path' % (os
.getppid()), 'w')
850 def main(win
, prefs
, paths1
, paths2
):
851 app
= Lfm(win
, prefs
)
852 app
.load_paths(paths1
, paths2
)
859 def lfm_start(sysargs
):
860 # get configuration & preferences
862 paths1
, paths2
= [], []
866 print 'Config file does not exist, we\'ll use default values'
870 print 'Config file seems corrupted, we\'ll use default values'
875 # hack, 'lfm' shell function returns a string, not a list,
876 # so we have to build a list
877 if len(sysargs
) <= 2:
881 sysargs
.extend(lst
[1].split())
883 opts
, args
= getopt
.getopt(sysargs
[1:], '12dh', ['debug', 'help'])
884 except getopt
.GetoptError
:
885 usage('Bad argument(s)')
889 prefs
.options
['num_panes'] = 1
891 prefs
.options
['num_panes'] = 2
892 if o
in ('-d', '--debug'):
894 if o
in ('-h', '--help'):
899 paths1
.append(os
.path
.abspath('.'))
900 paths2
.append(os
.path
.abspath('.'))
902 buf
= os
.path
.abspath(args
[0])
903 if not os
.path
.isdir(buf
):
904 usage('<%s> is not a directory' % args
[0])
907 paths2
.append(os
.path
.abspath('.'))
909 buf
= os
.path
.abspath(args
[0])
910 if not os
.path
.isdir(buf
):
911 usage('<%s> is not a directory' % args
[0])
914 buf
= os
.path
.abspath(args
[1])
915 if not os
.path
.isdir(buf
):
916 usage('<%s> is not a directory' % args
[1])
920 usage('Incorrect number of arguments')
925 log_file
= os
.path
.join(os
.path
.abspath('.'), LOG_FILE
)
926 logging
.basicConfig(level
=logging
.DEBUG
,
927 format
='%(asctime)s %(levelname)s\t%(message)s',
928 datefmt
='%Y-%m-%d %H:%M:%S ',
931 logging
.info('Starting Lfm...')
934 logging
.info('Main application call')
935 path
= curses
.wrapper(main
, prefs
, paths1
, paths2
)
938 # change to directory
945 if __name__
== '__main__':
949 ######################################################################