Abstracted dir list handling from browser.c into dirlist.c
This optimizes a few actions (though not all), and makes the code easier to understand and expand. The behaviour of the browser has changed a bit with regards to multi-page listings. Personally I don't like this change much, so I'd probably fix that later on.
Этот коммит содержится в:
родитель
fe21608e98
Коммит
5db9c2aea1
@ -1,5 +1,5 @@
|
|||||||
bin_PROGRAMS = ncdu
|
bin_PROGRAMS = ncdu
|
||||||
|
|
||||||
ncdu_SOURCES = browser.c calc.c delete.c exclude.c help.c main.c path.c util.c
|
ncdu_SOURCES = browser.c calc.c delete.c dirlist.c exclude.c help.c main.c path.c util.c
|
||||||
|
|
||||||
noinst_HEADERS = browser.h calc.h delete.h exclude.h global.h help.h path.h util.h
|
noinst_HEADERS = browser.h calc.h delete.h dirlist.h exclude.h global.h help.h path.h util.h
|
||||||
|
376
src/browser.c
376
src/browser.c
@ -30,103 +30,12 @@
|
|||||||
#include <ncurses.h>
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
|
||||||
#define BF_NAME 0x01
|
int graph = 0,
|
||||||
#define BF_SIZE 0x02
|
show_as = 0,
|
||||||
#define BF_NDIRF 0x04 /* Normally, dirs before files, setting this disables it */
|
info_show = 0,
|
||||||
#define BF_DESC 0x08
|
info_page = 0,
|
||||||
#define BF_HIDE 0x10 /* don't show hidden files... */
|
info_start = 0;
|
||||||
#define BF_AS 0x40 /* show apparent sizes instead of disk usage */
|
|
||||||
#define BF_INFO 0x80 /* show file information window */
|
|
||||||
|
|
||||||
struct dir *browse_dir = NULL;
|
|
||||||
unsigned char graph = 0,
|
|
||||||
flags = BF_SIZE | BF_DESC,
|
|
||||||
info_page = 0, info_start = 0;
|
|
||||||
|
|
||||||
|
|
||||||
#define ishidden(x) (flags & BF_HIDE && (\
|
|
||||||
(x->next != browse_dir && (x->name[0] == '.' || x->name[strlen(x->name)-1] == '~'))\
|
|
||||||
|| x->flags & FF_EXL))
|
|
||||||
|
|
||||||
|
|
||||||
int browse_cmp(struct dir *x, struct dir *y) {
|
|
||||||
struct dir *a, *b;
|
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
if(flags & BF_DESC) {
|
|
||||||
a = y; b = x;
|
|
||||||
} else {
|
|
||||||
b = y; a = x;
|
|
||||||
}
|
|
||||||
if(!(flags & BF_NDIRF) && y->flags & FF_DIR && !(x->flags & FF_DIR))
|
|
||||||
return(1);
|
|
||||||
if(!(flags & BF_NDIRF) && !(y->flags & FF_DIR) && x->flags & FF_DIR)
|
|
||||||
return(-1);
|
|
||||||
|
|
||||||
if(flags & BF_NAME)
|
|
||||||
r = strcmp(a->name, b->name);
|
|
||||||
if(flags & BF_AS) {
|
|
||||||
if(r == 0)
|
|
||||||
r = a->asize > b->asize ? 1 : (a->asize == b->asize ? 0 : -1);
|
|
||||||
if(r == 0)
|
|
||||||
r = a->size > b->size ? 1 : (a->size == b->size ? 0 : -1);
|
|
||||||
} else {
|
|
||||||
if(r == 0)
|
|
||||||
r = a->size > b->size ? 1 : (a->size == b->size ? 0 : -1);
|
|
||||||
if(r == 0)
|
|
||||||
r = a->asize > b->asize ? 1 : (a->asize == b->asize ? 0 : -1);
|
|
||||||
}
|
|
||||||
if(r == 0)
|
|
||||||
r = strcmp(x->name, y->name);
|
|
||||||
return(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct dir *browse_sort(struct dir *list) {
|
|
||||||
struct dir *p, *q, *e, *tail;
|
|
||||||
int insize, nmerges, psize, qsize, i;
|
|
||||||
|
|
||||||
insize = 1;
|
|
||||||
while(1) {
|
|
||||||
p = list;
|
|
||||||
list = NULL;
|
|
||||||
tail = NULL;
|
|
||||||
nmerges = 0;
|
|
||||||
while(p) {
|
|
||||||
nmerges++;
|
|
||||||
q = p;
|
|
||||||
psize = 0;
|
|
||||||
for(i=0; i<insize; i++) {
|
|
||||||
psize++;
|
|
||||||
q = q->next;
|
|
||||||
if(!q) break;
|
|
||||||
}
|
|
||||||
qsize = insize;
|
|
||||||
while(psize > 0 || (qsize > 0 && q)) {
|
|
||||||
if(psize == 0) {
|
|
||||||
e = q; q = q->next; qsize--;
|
|
||||||
} else if(qsize == 0 || !q) {
|
|
||||||
e = p; p = p->next; psize--;
|
|
||||||
} else if(browse_cmp(p,q) <= 0) {
|
|
||||||
e = p; p = p->next; psize--;
|
|
||||||
} else {
|
|
||||||
e = q; q = q->next; qsize--;
|
|
||||||
}
|
|
||||||
if(tail) tail->next = e;
|
|
||||||
else list = e;
|
|
||||||
tail = e;
|
|
||||||
}
|
|
||||||
p = q;
|
|
||||||
}
|
|
||||||
tail->next = NULL;
|
|
||||||
if(nmerges <= 1) {
|
|
||||||
if(list->parent)
|
|
||||||
list->parent->sub = list;
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
insize *= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void browse_draw_info(struct dir *dr) {
|
void browse_draw_info(struct dir *dr) {
|
||||||
@ -181,7 +90,7 @@ void browse_draw_info(struct dir *dr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void browse_draw_item(struct dir *n, int row, off_t max, int ispar) {
|
void browse_draw_item(struct dir *n, int row) {
|
||||||
char *line, ct, dt, *size, gr[11];
|
char *line, ct, dt, *size, gr[11];
|
||||||
int i, o;
|
int i, o;
|
||||||
float pc;
|
float pc;
|
||||||
@ -190,7 +99,7 @@ void browse_draw_item(struct dir *n, int row, off_t max, int ispar) {
|
|||||||
attron(A_REVERSE);
|
attron(A_REVERSE);
|
||||||
|
|
||||||
/* reference to parent dir has a different format */
|
/* reference to parent dir has a different format */
|
||||||
if(ispar) {
|
if(n == dirlist_parent) {
|
||||||
mvhline(row, 0, ' ', wincols);
|
mvhline(row, 0, ' ', wincols);
|
||||||
o = graph == 0 ? 12 :
|
o = graph == 0 ? 12 :
|
||||||
graph == 1 ? 24 :
|
graph == 1 ? 24 :
|
||||||
@ -214,18 +123,22 @@ void browse_draw_item(struct dir *n, int row, off_t max, int ispar) {
|
|||||||
&& n->sub == NULL ? 'e' :
|
&& n->sub == NULL ? 'e' :
|
||||||
' ' ;
|
' ' ;
|
||||||
dt = n->flags & FF_DIR ? '/' : ' ';
|
dt = n->flags & FF_DIR ? '/' : ' ';
|
||||||
size = formatsize(flags & BF_AS ? n->asize : n->size);
|
size = formatsize(show_as ? n->asize : n->size);
|
||||||
|
|
||||||
/* create graph (if necessary) */
|
/* create graph (if necessary) */
|
||||||
if((pc = (float)(flags & BF_AS ? n->parent->asize : n->parent->size)) < 1)
|
if(graph) {
|
||||||
|
/* percentage */
|
||||||
|
if((pc = (float)(show_as ? n->parent->asize : n->parent->size)) < 1)
|
||||||
pc = 1.0f;
|
pc = 1.0f;
|
||||||
pc = ((float)(flags & BF_AS ? n->asize : n->size) / pc) * 100.0f;
|
pc = ((float)(show_as ? n->asize : n->size) / pc) * 100.0f;
|
||||||
|
/* graph */
|
||||||
if(graph == 1 || graph == 3) {
|
if(graph == 1 || graph == 3) {
|
||||||
o = (int)(10.0f*(float)(flags & BF_AS ? n->asize : n->size) / (float)max);
|
o = (int)(10.0f*(float)(show_as ? n->asize : n->size) / (float)(show_as ? dirlist_maxa : dirlist_maxs));
|
||||||
for(i=0; i<10; i++)
|
for(i=0; i<10; i++)
|
||||||
gr[i] = i < o ? '#' : ' ';
|
gr[i] = i < o ? '#' : ' ';
|
||||||
gr[10] = '\0';
|
gr[10] = '\0';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* format and add item to the list */
|
/* format and add item to the list */
|
||||||
line = malloc(winrows+1);
|
line = malloc(winrows+1);
|
||||||
@ -254,134 +167,74 @@ void browse_draw_item(struct dir *n, int row, off_t max, int ispar) {
|
|||||||
|
|
||||||
|
|
||||||
void browse_draw() {
|
void browse_draw() {
|
||||||
struct dir *n, ref, *cur, *sel = NULL;
|
struct dir *t;
|
||||||
char *line, *tmp;
|
char fmtsize[9], *tmp;
|
||||||
int selected, i;
|
int selected, i;
|
||||||
off_t max = 1;
|
|
||||||
|
|
||||||
erase();
|
erase();
|
||||||
cur = browse_dir;
|
t = dirlist_get(0);
|
||||||
|
|
||||||
/* create header and status bar */
|
/* top line - basic info */
|
||||||
attron(A_REVERSE);
|
attron(A_REVERSE);
|
||||||
mvhline(0, 0, ' ', wincols);
|
mvhline(0, 0, ' ', wincols);
|
||||||
mvhline(winrows-1, 0, ' ', wincols);
|
mvhline(winrows-1, 0, ' ', wincols);
|
||||||
mvprintw(0,0,"%s %s ~ Use the arrow keys to navigate, press ? for help", PACKAGE_NAME, PACKAGE_VERSION);
|
mvprintw(0,0,"%s %s ~ Use the arrow keys to navigate, press ? for help", PACKAGE_NAME, PACKAGE_VERSION);
|
||||||
|
|
||||||
if(cur) {
|
|
||||||
line = malloc(winrows+1);
|
|
||||||
strcpy(line, formatsize(cur->parent->size));
|
|
||||||
mvprintw(winrows-1, 0, " Total disk usage: %s Apparent size: %s Items: %d",
|
|
||||||
line, formatsize(cur->parent->asize), cur->parent->items);
|
|
||||||
free(line);
|
|
||||||
} else
|
|
||||||
mvaddstr(winrows-1, 0, " No items to display.");
|
|
||||||
attroff(A_REVERSE);
|
attroff(A_REVERSE);
|
||||||
|
|
||||||
|
/* second line - the path */
|
||||||
mvhline(1, 0, '-', wincols);
|
mvhline(1, 0, '-', wincols);
|
||||||
if(cur) {
|
if(t) {
|
||||||
mvaddch(1, 3, ' ');
|
mvaddch(1, 3, ' ');
|
||||||
tmp = getpath(cur->parent);
|
tmp = getpath(t->parent);
|
||||||
mvaddstr(1, 4, cropstr(tmp, wincols-8));
|
mvaddstr(1, 4, cropstr(tmp, wincols-8));
|
||||||
mvaddch(1, 4+((int)strlen(tmp) > wincols-8 ? wincols-8 : (int)strlen(tmp)), ' ');
|
mvaddch(1, 4+((int)strlen(tmp) > wincols-8 ? wincols-8 : (int)strlen(tmp)), ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!cur)
|
/* bottom line - stats */
|
||||||
|
attron(A_REVERSE);
|
||||||
|
if(t) {
|
||||||
|
strcpy(fmtsize, formatsize(t->parent->size));
|
||||||
|
mvprintw(winrows-1, 0, " Total disk usage: %s Apparent size: %s Items: %d",
|
||||||
|
fmtsize, formatsize(t->parent->asize), t->parent->items);
|
||||||
|
} else
|
||||||
|
mvaddstr(winrows-1, 0, " No items to display.");
|
||||||
|
attroff(A_REVERSE);
|
||||||
|
|
||||||
|
/* nothing to display? stop here. */
|
||||||
|
if(!t)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* add reference to parent dir */
|
/* get start position */
|
||||||
memset(&ref, 0, sizeof(struct dir));
|
t = dirlist_get(-1*((winrows)/2));
|
||||||
if(cur->parent->parent) {
|
if(t == dirlist_next(NULL))
|
||||||
ref.name = "..";
|
t = NULL;
|
||||||
ref.next = cur;
|
|
||||||
ref.parent = cur->parent;
|
|
||||||
cur = &ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get maximum size and selected item */
|
|
||||||
for(n=cur, selected=-1, i=0; n!=NULL; n=n->next) {
|
|
||||||
if(ishidden(n))
|
|
||||||
continue;
|
|
||||||
if(n->flags & FF_BSEL) {
|
|
||||||
selected = i;
|
|
||||||
sel = n;
|
|
||||||
}
|
|
||||||
if((flags & BF_AS ? n->asize : n->size) > max)
|
|
||||||
max = flags & BF_AS ? n->asize : n->size;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if(selected < 0)
|
|
||||||
cur->flags |= FF_BSEL;
|
|
||||||
|
|
||||||
/* determine start position */
|
|
||||||
for(n=cur,i=0; n!=NULL; n=n->next) {
|
|
||||||
if(ishidden(n))
|
|
||||||
continue;
|
|
||||||
if(i == (selected / (winrows-3)) * (winrows-3))
|
|
||||||
break;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
selected -= i;
|
|
||||||
|
|
||||||
/* print the list to the screen */
|
/* print the list to the screen */
|
||||||
for(i=0; n!=NULL && i<winrows-3; n=n->next) {
|
for(i=0; (t=dirlist_next(t)) && i<winrows-3; i++) {
|
||||||
if(ishidden(n))
|
browse_draw_item(t, 2+i);
|
||||||
continue;
|
/* save the selected row number for later */
|
||||||
browse_draw_item(n, 2+i++, max, n == &ref);
|
if(t->flags & FF_BSEL)
|
||||||
|
selected = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* draw information window */
|
/* draw information window */
|
||||||
if(sel && (flags & BF_INFO) && sel != &ref)
|
t = dirlist_get(0);
|
||||||
browse_draw_info(sel);
|
if(info_show && t != dirlist_parent)
|
||||||
|
browse_draw_info(t);
|
||||||
|
|
||||||
/* move cursor to selected row for accessibility */
|
/* move cursor to selected row for accessibility */
|
||||||
move(selected+2, 0);
|
move(selected+2, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void browse_key_sel(int change) {
|
|
||||||
struct dir *n, *cur, par;
|
|
||||||
int i, max;
|
|
||||||
|
|
||||||
if((cur = browse_dir) == NULL)
|
|
||||||
return;
|
|
||||||
par.next = cur;
|
|
||||||
par.flags = 0;
|
|
||||||
if(cur->parent->parent)
|
|
||||||
cur = ∥
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
max = -1;
|
|
||||||
for(n=cur; n!=NULL; n=n->next) {
|
|
||||||
if(!ishidden(n)) {
|
|
||||||
max++;
|
|
||||||
if(n->flags & FF_BSEL)
|
|
||||||
i = max;
|
|
||||||
}
|
|
||||||
n->flags &= ~FF_BSEL;
|
|
||||||
}
|
|
||||||
i += change;
|
|
||||||
i = i<0 ? 0 : i>max ? max : i;
|
|
||||||
|
|
||||||
for(n=cur; n!=NULL; n=n->next)
|
|
||||||
if(!ishidden(n) && !i--)
|
|
||||||
n->flags |= FF_BSEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define toggle(x,y) if(x & y) x -=y; else x |= y
|
|
||||||
|
|
||||||
int browse_key(int ch) {
|
int browse_key(int ch) {
|
||||||
char sort = 0, nonfo = 0, catch = 0;
|
struct dir *t, *sel;
|
||||||
struct dir *r, *sel;
|
int i, catch = 0;
|
||||||
int i;
|
|
||||||
|
|
||||||
for(sel=browse_dir; sel!=NULL; sel=sel->next)
|
sel = dirlist_get(0);
|
||||||
if(sel->flags & FF_BSEL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* info window overwrites a few keys */
|
/* info window overwrites a few keys */
|
||||||
if(flags & BF_INFO && sel)
|
if(info_show && sel)
|
||||||
switch(ch) {
|
switch(ch) {
|
||||||
case '1':
|
case '1':
|
||||||
info_page = 0;
|
info_page = 0;
|
||||||
@ -416,7 +269,7 @@ int browse_key(int ch) {
|
|||||||
case 'j':
|
case 'j':
|
||||||
case ' ':
|
case ' ':
|
||||||
if(sel->hlnk && info_page == 1) {
|
if(sel->hlnk && info_page == 1) {
|
||||||
for(i=0,r=sel->hlnk; r!=sel; r=r->hlnk)
|
for(i=0,t=sel->hlnk; t!=sel; t=t->hlnk)
|
||||||
i++;
|
i++;
|
||||||
if(i > info_start+6)
|
if(i > info_start+6)
|
||||||
info_start++;
|
info_start++;
|
||||||
@ -430,155 +283,120 @@ int browse_key(int ch) {
|
|||||||
/* selecting items */
|
/* selecting items */
|
||||||
case KEY_UP:
|
case KEY_UP:
|
||||||
case 'k':
|
case 'k':
|
||||||
browse_key_sel(-1);
|
dirlist_select(dirlist_get(-1));
|
||||||
info_start = 0;
|
info_start = 0;
|
||||||
break;
|
break;
|
||||||
case KEY_DOWN:
|
case KEY_DOWN:
|
||||||
case 'j':
|
case 'j':
|
||||||
browse_key_sel(1);
|
dirlist_select(dirlist_get(1));
|
||||||
info_start = 0;
|
info_start = 0;
|
||||||
break;
|
break;
|
||||||
case KEY_HOME:
|
case KEY_HOME:
|
||||||
browse_key_sel(-1*(1<<30));
|
dirlist_select(dirlist_next(NULL));
|
||||||
info_start = 0;
|
info_start = 0;
|
||||||
break;
|
break;
|
||||||
case KEY_LL:
|
case KEY_LL:
|
||||||
case KEY_END:
|
case KEY_END:
|
||||||
browse_key_sel(1<<30);
|
dirlist_select(dirlist_get(1<<30));
|
||||||
info_start = 0;
|
info_start = 0;
|
||||||
break;
|
break;
|
||||||
case KEY_PPAGE:
|
case KEY_PPAGE:
|
||||||
browse_key_sel(-1*(winrows-3));
|
dirlist_select(dirlist_get(-1*(winrows-3)));
|
||||||
info_start = 0;
|
info_start = 0;
|
||||||
break;
|
break;
|
||||||
case KEY_NPAGE:
|
case KEY_NPAGE:
|
||||||
browse_key_sel(winrows-3);
|
dirlist_select(dirlist_get(winrows-3));
|
||||||
info_start = 0;
|
info_start = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* sorting items */
|
/* sorting items */
|
||||||
case 'n':
|
case 'n':
|
||||||
if(flags & BF_NAME)
|
dirlist_set_sort(DL_COL_NAME, dirlist_sort_col == DL_COL_NAME ? !dirlist_sort_desc : DL_NOCHANGE, DL_NOCHANGE);
|
||||||
toggle(flags, BF_DESC);
|
info_show = 0;
|
||||||
else
|
|
||||||
flags = (flags & BF_HIDE) + (flags & BF_NDIRF) + BF_NAME;
|
|
||||||
sort++;
|
|
||||||
nonfo++;
|
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
if(flags & BF_SIZE)
|
i = show_as ? DL_COL_ASIZE : DL_COL_SIZE;
|
||||||
toggle(flags, BF_DESC);
|
dirlist_set_sort(i, dirlist_sort_col == i ? !dirlist_sort_desc : DL_NOCHANGE, DL_NOCHANGE);
|
||||||
else
|
info_show = 0;
|
||||||
flags = (flags & BF_HIDE) + (flags & BF_NDIRF) + BF_SIZE + BF_DESC;
|
|
||||||
sort++;
|
|
||||||
nonfo++;
|
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
toggle(flags, BF_HIDE);
|
dirlist_set_hidden(!dirlist_hidden);
|
||||||
browse_key_sel(0);
|
info_show = 0;
|
||||||
nonfo++;
|
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
toggle(flags, BF_NDIRF);
|
dirlist_set_sort(DL_NOCHANGE, DL_NOCHANGE, dirlist_sort_df);
|
||||||
sort++;
|
info_show = 0;
|
||||||
nonfo++;
|
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
toggle(flags, BF_AS);
|
show_as = !show_as;
|
||||||
nonfo++;
|
if(dirlist_sort_col == DL_COL_ASIZE || dirlist_sort_col == DL_COL_SIZE)
|
||||||
|
dirlist_set_sort(show_as ? DL_COL_ASIZE : DL_COL_SIZE, DL_NOCHANGE, DL_NOCHANGE);
|
||||||
|
info_show = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* browsing */
|
/* browsing */
|
||||||
case 10:
|
case 10:
|
||||||
case KEY_RIGHT:
|
case KEY_RIGHT:
|
||||||
case 'l':
|
case 'l':
|
||||||
if(sel != NULL && sel->sub != NULL) {
|
if(sel != NULL && sel->sub != NULL)
|
||||||
browse_dir = sel->sub;
|
dirlist_open(sel->sub);
|
||||||
sort++;
|
info_show = 0;
|
||||||
}
|
|
||||||
if(sel == NULL && browse_dir != NULL && browse_dir->parent->parent) {
|
|
||||||
browse_dir = browse_dir->parent->parent->sub;
|
|
||||||
sort++;
|
|
||||||
}
|
|
||||||
browse_key_sel(0);
|
|
||||||
nonfo++;
|
|
||||||
break;
|
break;
|
||||||
case KEY_LEFT:
|
case KEY_LEFT:
|
||||||
case 'h':
|
case 'h':
|
||||||
case '<':
|
case '<':
|
||||||
if(browse_dir != NULL && browse_dir->parent->parent != NULL) {
|
if(sel != NULL && sel->parent->parent != NULL)
|
||||||
browse_dir = browse_dir->parent->parent->sub;
|
dirlist_open(sel->parent);
|
||||||
sort++;
|
info_show = 0;
|
||||||
}
|
|
||||||
browse_key_sel(0);
|
|
||||||
nonfo++;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* and other stuff */
|
/* and other stuff */
|
||||||
case 'r':
|
case 'r':
|
||||||
if(browse_dir != NULL)
|
if(sel != NULL)
|
||||||
calc_init(getpath(browse_dir->parent), browse_dir->parent);
|
calc_init(getpath(sel->parent), sel->parent);
|
||||||
nonfo++;
|
info_show = 0;
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
if(flags & BF_INFO)
|
if(info_show)
|
||||||
nonfo++;
|
info_show = 0;
|
||||||
else
|
else
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
if(++graph > 3)
|
if(++graph > 3)
|
||||||
graph = 0;
|
graph = 0;
|
||||||
nonfo++;
|
info_show = 0;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
toggle(flags, BF_INFO);
|
info_show = !info_show;
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
help_init();
|
help_init();
|
||||||
nonfo++;
|
info_show = 0;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
if(sel == NULL)
|
if(sel == NULL || sel == dirlist_parent)
|
||||||
break;
|
break;
|
||||||
nonfo++;
|
info_show = 0;
|
||||||
/* quirky method of getting the next selected dir without actually selecting it */
|
if((t = dirlist_get(1)) == sel)
|
||||||
browse_key_sel(sel->next ? 1 : -1);
|
t = dirlist_get(-1);
|
||||||
for(r=browse_dir; r!=NULL; r=r->next)
|
delete_init(sel, t);
|
||||||
if(r->flags & FF_BSEL)
|
|
||||||
break;
|
|
||||||
browse_key_sel(sel->next ? -1 : 1);
|
|
||||||
delete_init(sel, r);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sort && browse_dir != NULL)
|
/* make sure the info_* options are correct */
|
||||||
browse_dir = browse_sort(browse_dir);
|
sel = dirlist_get(0);
|
||||||
if(nonfo) {
|
if(!info_show || sel == dirlist_parent)
|
||||||
flags &= ~BF_INFO;
|
info_show = info_page = info_start = 0;
|
||||||
info_start = 0;
|
else if(sel && !sel->hlnk)
|
||||||
}
|
info_page = info_start = 0;
|
||||||
if(flags & BF_INFO) {
|
|
||||||
for(sel=browse_dir; sel!=NULL; sel=sel->next)
|
|
||||||
if(sel->flags & FF_BSEL)
|
|
||||||
break;
|
|
||||||
if(sel && !sel->hlnk)
|
|
||||||
info_page = 0;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void browse_init(struct dir *cur) {
|
void browse_init(struct dir *cur) {
|
||||||
pstate = ST_BROWSE;
|
pstate = ST_BROWSE;
|
||||||
if(cur != NULL && cur->parent == NULL)
|
dirlist_open(cur);
|
||||||
browse_dir = cur->sub;
|
|
||||||
else
|
|
||||||
browse_dir = cur;
|
|
||||||
if(browse_dir != NULL && browse_dir->parent->sub != browse_dir)
|
|
||||||
browse_dir = cur->parent->sub;
|
|
||||||
if(browse_dir != NULL)
|
|
||||||
browse_dir = browse_sort(browse_dir);
|
|
||||||
browse_key_sel(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
293
src/dirlist.c
Обычный файл
293
src/dirlist.c
Обычный файл
@ -0,0 +1,293 @@
|
|||||||
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
|
Copyright (c) 2007-2010 Yoran Heling
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* public variables */
|
||||||
|
struct dir *dirlist_parent = NULL;
|
||||||
|
off_t dirlist_maxs = 0,
|
||||||
|
dirlist_maxa = 0;
|
||||||
|
|
||||||
|
int dirlist_sort_desc = 1,
|
||||||
|
dirlist_sort_col = DL_COL_SIZE,
|
||||||
|
dirlist_sort_df = 0,
|
||||||
|
dirlist_hidden = 0;
|
||||||
|
|
||||||
|
/* private state vars */
|
||||||
|
struct dir dirlist_parent_alloc;
|
||||||
|
struct dir *head, *head_real, *selected;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define ISHIDDEN(d) (dirlist_hidden && (d) != dirlist_parent && (\
|
||||||
|
(d)->flags & FF_EXL || (d)->name[0] == '.' || (d)->name[strlen((d)->name)-1] == '~'\
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int dirlist_cmp(struct dir *x, struct dir *y) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* dirs are always before files when that option is set */
|
||||||
|
if(dirlist_sort_df) {
|
||||||
|
if(y->flags & FF_DIR && !(x->flags & FF_DIR))
|
||||||
|
return 1;
|
||||||
|
else if(!(y->flags & FF_DIR) && x->flags & FF_DIR)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sort columns:
|
||||||
|
* 1 -> 2 -> 3
|
||||||
|
* NAME: name -> size -> asize
|
||||||
|
* SIZE: size -> asize -> name
|
||||||
|
* ASIZE: asize -> size -> name
|
||||||
|
*
|
||||||
|
* Note that the method used below is supposed to be fast, not readable :-)
|
||||||
|
*/
|
||||||
|
#define CMP_NAME strcmp(x->name, y->name)
|
||||||
|
#define CMP_SIZE (x->size > y->size ? 1 : (x->size == y->size ? 0 : -1))
|
||||||
|
#define CMP_ASIZE (x->asize > y->asize ? 1 : (x->asize == y->asize ? 0 : -1))
|
||||||
|
|
||||||
|
/* try 1 */
|
||||||
|
r = dirlist_sort_col == DL_COL_NAME ? CMP_NAME : dirlist_sort_col == DL_COL_SIZE ? CMP_SIZE : CMP_ASIZE;
|
||||||
|
/* try 2 */
|
||||||
|
if(!r)
|
||||||
|
r = dirlist_sort_col == DL_COL_SIZE ? CMP_ASIZE : CMP_SIZE;
|
||||||
|
/* try 3 */
|
||||||
|
if(!r)
|
||||||
|
r = dirlist_sort_col == DL_COL_NAME ? CMP_ASIZE : CMP_NAME;
|
||||||
|
|
||||||
|
/* reverse when sorting in descending order */
|
||||||
|
if(dirlist_sort_desc && r != 0)
|
||||||
|
r = r < 0 ? 1 : -1;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct dir *dirlist_sort(struct dir *list) {
|
||||||
|
struct dir *p, *q, *e, *tail;
|
||||||
|
int insize, nmerges, psize, qsize, i;
|
||||||
|
|
||||||
|
insize = 1;
|
||||||
|
while(1) {
|
||||||
|
p = list;
|
||||||
|
list = NULL;
|
||||||
|
tail = NULL;
|
||||||
|
nmerges = 0;
|
||||||
|
while(p) {
|
||||||
|
nmerges++;
|
||||||
|
q = p;
|
||||||
|
psize = 0;
|
||||||
|
for(i=0; i<insize; i++) {
|
||||||
|
psize++;
|
||||||
|
q = q->next;
|
||||||
|
if(!q) break;
|
||||||
|
}
|
||||||
|
qsize = insize;
|
||||||
|
while(psize > 0 || (qsize > 0 && q)) {
|
||||||
|
if(psize == 0) {
|
||||||
|
e = q; q = q->next; qsize--;
|
||||||
|
} else if(qsize == 0 || !q) {
|
||||||
|
e = p; p = p->next; psize--;
|
||||||
|
} else if(dirlist_cmp(p,q) <= 0) {
|
||||||
|
e = p; p = p->next; psize--;
|
||||||
|
} else {
|
||||||
|
e = q; q = q->next; qsize--;
|
||||||
|
}
|
||||||
|
if(tail) tail->next = e;
|
||||||
|
else list = e;
|
||||||
|
tail = e;
|
||||||
|
}
|
||||||
|
p = q;
|
||||||
|
}
|
||||||
|
tail->next = NULL;
|
||||||
|
if(nmerges <= 1) {
|
||||||
|
if(list->parent)
|
||||||
|
list->parent->sub = list;
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
insize *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* passes through the dir listing once and:
|
||||||
|
* - makes sure one, and only one, visible item is selected
|
||||||
|
* - updates the dirlist_(maxs|maxa) values
|
||||||
|
* - makes sure that the FF_BSEL bits are correct */
|
||||||
|
void dirlist_fixup() {
|
||||||
|
struct dir *t;
|
||||||
|
|
||||||
|
/* we're going to determine the selected items from the list itself, so reset this one */
|
||||||
|
selected = NULL;
|
||||||
|
|
||||||
|
for(t=head; t; t=t->next) {
|
||||||
|
/* not visible? not selected! */
|
||||||
|
if(ISHIDDEN(t))
|
||||||
|
t->flags &= ~FF_BSEL;
|
||||||
|
else {
|
||||||
|
/* visible and selected? make sure only one item is selected */
|
||||||
|
if(t->flags & FF_BSEL) {
|
||||||
|
if(!selected)
|
||||||
|
selected = t;
|
||||||
|
else
|
||||||
|
t->flags &= ~FF_BSEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update dirlist_(maxs|maxa) */
|
||||||
|
if(t->size > dirlist_maxs)
|
||||||
|
dirlist_maxs = t->size;
|
||||||
|
if(t->asize > dirlist_maxa)
|
||||||
|
dirlist_maxa = t->asize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no selected items found after one pass? select the first visible item */
|
||||||
|
if(!selected) {
|
||||||
|
selected = dirlist_next(NULL);
|
||||||
|
selected->flags |= FF_BSEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dirlist_open(struct dir *d) {
|
||||||
|
/* set the head of the list */
|
||||||
|
head_real = head = d == NULL ? NULL : d->parent == NULL ? d->sub : d->parent->sub;
|
||||||
|
|
||||||
|
/* reset internal status */
|
||||||
|
dirlist_maxs = dirlist_maxa = 0;
|
||||||
|
|
||||||
|
/* stop if this is not a directory list we can work with */
|
||||||
|
if(head == NULL) {
|
||||||
|
dirlist_parent = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sort the dir listing */
|
||||||
|
head_real = head = dirlist_sort(head);
|
||||||
|
|
||||||
|
/* set the reference to the parent dir */
|
||||||
|
if(head->parent->parent) {
|
||||||
|
dirlist_parent = &dirlist_parent_alloc;
|
||||||
|
dirlist_parent->name = "..";
|
||||||
|
dirlist_parent->next = head;
|
||||||
|
dirlist_parent->parent = head->parent;
|
||||||
|
dirlist_parent->sub = head->parent;
|
||||||
|
head = dirlist_parent;
|
||||||
|
} else
|
||||||
|
dirlist_parent = NULL;
|
||||||
|
|
||||||
|
dirlist_fixup();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct dir *dirlist_next(struct dir *d) {
|
||||||
|
if(!head)
|
||||||
|
return NULL;
|
||||||
|
if(!d) {
|
||||||
|
if(!ISHIDDEN(head))
|
||||||
|
return head;
|
||||||
|
else
|
||||||
|
d = head;
|
||||||
|
}
|
||||||
|
while((d = d->next)) {
|
||||||
|
if(!ISHIDDEN(d))
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* this function assumes that 'selected' is valid and points to a visible item */
|
||||||
|
struct dir *dirlist_get(int i) {
|
||||||
|
struct dir *t = selected, *d;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
if(!head)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* i == 0? return the selected item */
|
||||||
|
if(!i)
|
||||||
|
return selected;
|
||||||
|
|
||||||
|
/* positive number? simply move forward */
|
||||||
|
while(i > 0) {
|
||||||
|
d = dirlist_next(t);
|
||||||
|
if(!d)
|
||||||
|
return t;
|
||||||
|
t = d;
|
||||||
|
if(!--i)
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* negative number? start from beginning to get the index of the selected
|
||||||
|
* item, and then start all over to get the requested item before that.
|
||||||
|
* XXX: This can obviously be optimized by using a doubly linked list. */
|
||||||
|
for(j=0,t=NULL; (t=dirlist_next(t)); j++)
|
||||||
|
if(t == selected)
|
||||||
|
break;
|
||||||
|
for(t=NULL,j+=i; (t=dirlist_next(t))&&j>0; j--)
|
||||||
|
;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dirlist_select(struct dir *d) {
|
||||||
|
if(!head || ISHIDDEN(d) || d->parent != head->parent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selected->flags &= ~FF_BSEL;
|
||||||
|
selected = d;
|
||||||
|
selected->flags |= FF_BSEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dirlist_set_sort(int col, int desc, int df) {
|
||||||
|
/* update config */
|
||||||
|
if(col != DL_NOCHANGE)
|
||||||
|
dirlist_sort_col = col;
|
||||||
|
if(desc != DL_NOCHANGE)
|
||||||
|
dirlist_sort_desc = desc;
|
||||||
|
if(df != DL_NOCHANGE)
|
||||||
|
dirlist_sort_df = df;
|
||||||
|
|
||||||
|
/* sort the list (excluding the parent, which is always on top) */
|
||||||
|
head_real = dirlist_sort(head_real);
|
||||||
|
if(dirlist_parent)
|
||||||
|
dirlist_parent->next = head_real;
|
||||||
|
else
|
||||||
|
head = head_real;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dirlist_set_hidden(int hidden) {
|
||||||
|
dirlist_hidden = hidden;
|
||||||
|
dirlist_fixup();
|
||||||
|
}
|
||||||
|
|
78
src/dirlist.h
Обычный файл
78
src/dirlist.h
Обычный файл
@ -0,0 +1,78 @@
|
|||||||
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
|
Copyright (c) 2007-2010 Yoran Heling
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Note: all functions below include a 'reference to parent dir' node at the
|
||||||
|
* top of the list. */
|
||||||
|
|
||||||
|
#ifndef _dirlist_h
|
||||||
|
#define _dirlist_h
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define DL_NOCHANGE -1
|
||||||
|
#define DL_COL_NAME 0
|
||||||
|
#define DL_COL_SIZE 1
|
||||||
|
#define DL_COL_ASIZE 2
|
||||||
|
|
||||||
|
|
||||||
|
void dirlist_open(struct dir *);
|
||||||
|
|
||||||
|
/* Get the next non-hidden item,
|
||||||
|
* NULL = get first non-hidden item */
|
||||||
|
struct dir *dirlist_next(struct dir *);
|
||||||
|
|
||||||
|
/* Get the struct dir item relative to the selected item, or the item nearest to the requested item
|
||||||
|
* i = 0 get selected item
|
||||||
|
* hidden items aren't considered */
|
||||||
|
struct dir *dirlist_get(int i);
|
||||||
|
|
||||||
|
/* Set selected dir (must be in the currently opened directory, obviously) */
|
||||||
|
void dirlist_select(struct dir *);
|
||||||
|
|
||||||
|
/* Change sort column (arguments should have a NO_CHANGE option) */
|
||||||
|
void dirlist_set_sort(int column, int desc, int df);
|
||||||
|
|
||||||
|
/* Set the hidden thingy */
|
||||||
|
void dirlist_set_hidden(int hidden);
|
||||||
|
|
||||||
|
|
||||||
|
/* DO NOT WRITE TO ANY OF THE BELOW VARIABLES FROM OUTSIDE OF dirlist.c! */
|
||||||
|
|
||||||
|
/* The 'reference to parent dir' */
|
||||||
|
extern struct dir *dirlist_parent;
|
||||||
|
|
||||||
|
/* current sorting configuration (set with dirlist_set_sort()) */
|
||||||
|
extern int dirlist_sort_desc, dirlist_sort_col, dirlist_sort_df;
|
||||||
|
|
||||||
|
/* set with dirlist_set_hidden() */
|
||||||
|
extern int dirlist_hidden;
|
||||||
|
|
||||||
|
/* maximum size of an item in the opened dir */
|
||||||
|
extern off_t dirlist_maxs, dirlist_maxa;
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -78,5 +78,6 @@ int input_handle(int);
|
|||||||
#include "browser.h"
|
#include "browser.h"
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
|
#include "dirlist.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user