aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2017-06-30 08:22:38 +0200
committerPřemysl Janouch <p.janouch@gmail.com>2017-06-30 08:25:47 +0200
commitc90fa0a060a6f51262afafd90278a438e7e7aa3f (patch)
tree96fdf3551904f6af6a6f6910952dcc2ef1150f3b
parentbe77f6fa461edc0378d2dcef6adccba0394fb9ac (diff)
downloadsdn-c90fa0a060a6f51262afafd90278a438e7e7aa3f.tar.gz
sdn-c90fa0a060a6f51262afafd90278a438e7e7aa3f.tar.xz
sdn-c90fa0a060a6f51262afafd90278a438e7e7aa3f.zip
Properly align all columns
-rw-r--r--sdn.cpp61
1 files changed, 42 insertions, 19 deletions
diff --git a/sdn.cpp b/sdn.cpp
index 408ba12..aeca397 100644
--- a/sdn.cpp
+++ b/sdn.cpp
@@ -157,12 +157,35 @@ fun print (const ncstring &nc, int limit) -> int {
return total_width;
}
+fun compute_width (const ncstring &nc) -> int {
+ int total = 0;
+ for (const auto &c : nc)
+ total += wcwidth (c.chars[0]);
+ return total;
+}
+
+// TODO: maybe we need formatting for the padding passed in?
+fun align (const ncstring &nc, int target) -> ncstring {
+ auto current = compute_width (nc);
+ auto missing = abs (target) - current;
+ if (missing <= 0)
+ return nc;
+ return target < 0
+ ? nc + apply_attrs (wstring (missing, L' '), 0)
+ : apply_attrs (wstring (missing, L' '), 0) + nc;
+}
+
// --- Application -------------------------------------------------------------
#define CTRL 31 &
+struct row {
+ enum { MODES, USER, GROUP, SIZE, MTIME, FILENAME, COLUMNS };
+ ncstring cols[COLUMNS];
+};
+
struct entry {
- string filename; struct stat info;
+ string filename; struct stat info; row row;
auto operator< (const entry &other) -> bool {
auto a = S_ISDIR (info.st_mode);
auto b = S_ISDIR (other.info.st_mode);
@@ -175,6 +198,7 @@ static struct {
vector<entry> entries; // Current directory entries
int offset, cursor; // Scroll offset and cursor position
bool full_view; // Whether to show extended information
+ int max_widths[row::COLUMNS]; // Column widths
string chosen; // Chosen item for the command line
bool chosen_full; // Use the full path
@@ -186,15 +210,8 @@ static struct {
wstring editor_line; // Current user input
} g;
-// TODO: this should probably be cached within `struct entry`
-struct row {
- enum { MODES, USER, GROUP, SIZE, MTIME, FILENAME, COLUMNS };
- ncstring cols[COLUMNS];
-};
-
-fun make_row (const entry &entry) -> row {
+fun make_row (const string &filename, const struct stat &info) -> row {
row r;
- const auto &info = entry.info;
r.cols[row::MODES] = apply_attrs (decode_mode (info.st_mode), 0);
auto user = to_wstring (info.st_uid);
@@ -224,32 +241,32 @@ fun make_row (const entry &entry) -> row {
r.cols[row::MTIME] = apply_attrs (to_wide (buf), 0);
// TODO: symlink target and whatever formatting
- r.cols[row::FILENAME] = apply_attrs (to_wide (entry.filename), 0);
+ r.cols[row::FILENAME] = apply_attrs (to_wide (filename), 0);
return r;
}
fun inline visible_lines () -> int { return max (0, LINES - 2); }
fun update () {
+ int start_column = g.full_view ? 0 : row::FILENAME;
+ static int alignment[row::COLUMNS] = { -1, -1, -1, 1, -1, -1 };
erase ();
int available = visible_lines ();
int used = min (available, int (g.entries.size ()) - g.offset);
for (int i = 0; i < used; i++) {
attrset (0);
+ move (available - used + i, 0);
+
int index = g.offset + i;
if (index == g.cursor)
attron (A_REVERSE);
- // TODO: use g.full_view, align properly (different columns differently)
- // XXX: maybe this should return a struct instead
- auto row = make_row (g.entries[index]);
-
- move (available - used + i, 0);
auto limit = COLS, used = 0;
- for (auto &i : row.cols) {
- used += print (i, limit - used);
- used += print (apply_attrs (L" ", 0), limit - used);
+ for (int col = start_column; col < row::COLUMNS; col++) {
+ const auto &field = g.entries[index].row.cols[col];
+ auto aligned = align (field, alignment[col] * g.max_widths[col]);
+ used += print (aligned + apply_attrs (L" ", 0), limit - used);
}
hline (' ', limit - used);
}
@@ -284,12 +301,18 @@ fun reload () {
struct stat sb = {};
lstat (f->d_name, &sb);
- g.entries.push_back ({ f->d_name, sb });
+ g.entries.push_back ({ f->d_name, sb, make_row (f->d_name, sb) });
}
closedir (dir);
sort (begin (g.entries), end (g.entries));
g.out_of_date = false;
+ for (int col = 0; col < row::COLUMNS; col++) {
+ auto &longest = g.max_widths[col] = 0;
+ for (const auto &entry : g.entries)
+ longest = max (longest, compute_width (entry.row.cols[col]));
+ }
+
g.cursor = min (g.cursor, int (g.entries.size ()) - 1);
g.offset = min (g.offset, int (g.entries.size ()) - 1);
update ();