From 5d9246a38ad178bdeb409f2b8c1c0d1a8aa9f551 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Fri, 30 Jun 2017 01:39:49 +0200
Subject: Show more file information
Yet to be properly aligned.
---
sdn.cpp | 160 +++++++++++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 119 insertions(+), 41 deletions(-)
diff --git a/sdn.cpp b/sdn.cpp
index 1afa865..adafc54 100644
--- a/sdn.cpp
+++ b/sdn.cpp
@@ -30,18 +30,22 @@
#include
#include
#include
+#include
+#include
// Unicode is complex enough already and we might make assumptions
#ifndef __STDC_ISO_10646__
#error Unicode required for wchar_t
#endif
+// Trailing return types make C++ syntax suck considerably less
+#define fun static auto
+
using namespace std;
// For some reason handling of encoding in C and C++ is extremely annoying
// and C++17 ironically obsoletes C++11 additions that made it less painful
-static wstring
-to_wide (const string &multi) {
+fun to_wide (const string &multi) -> wstring {
wstring wide; wchar_t w; mbstate_t mb {};
size_t n = 0, len = multi.length () + 1;
while (auto res = mbrtowc (&w, multi.c_str () + n, len - n, &mb)) {
@@ -54,8 +58,7 @@ to_wide (const string &multi) {
return wide;
}
-static string
-to_mb (const wstring &wide) {
+fun to_mb (const wstring &wide) -> string {
string mb; char buf[MB_LEN_MAX + 1]; mbstate_t mbs {};
for (size_t n = 0; n <= wide.length (); n++) {
auto res = wcrtomb (buf, wide.c_str ()[n], &mbs);
@@ -68,8 +71,7 @@ to_mb (const wstring &wide) {
return mb;
}
-static int
-print (const wstring &wide, int limit) {
+fun print (const wstring &wide, int limit) -> int {
int total_width = 0;
for (wchar_t w : wide) {
// TODO: controls as ^X, show in inverse
@@ -88,16 +90,14 @@ print (const wstring &wide, int limit) {
return total_width;
}
-static int
-prefix (const wstring &in, const wstring &of) {
+fun prefix (const wstring &in, const wstring &of) -> int {
int score = 0;
for (size_t i = 0; i < of.size () && in.size () >= i && in[i] == of[i]; i++)
score++;
return score;
}
-static string
-shell_escape (const string &v) {
+fun shell_escape (const string &v) -> string {
string result;
for (auto c : v)
if (c == '\'')
@@ -107,6 +107,35 @@ shell_escape (const string &v) {
return "'" + result + "'";
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+using ncstring = basic_string;
+
+fun apply_attrs (const wstring &w, attr_t attrs) -> ncstring {
+ ncstring res;
+ for (auto c : w)
+ res.push_back ({attrs, {c}});
+ return res;
+}
+
+fun print_nc (const ncstring &nc, int limit) -> int {
+ int total_width = 0;
+ for (cchar_t c : nc) {
+ // TODO: controls as ^X, show in inverse
+ auto &w = c.chars[0];
+ if (!isprint (w))
+ w = L'?';
+
+ int width = wcwidth (w);
+ if (total_width + width > limit)
+ break;
+
+ add_wch (&c);
+ total_width += width;
+ }
+ return total_width;
+}
+
// --- Application -------------------------------------------------------------
#define CTRL 31 &
@@ -131,14 +160,71 @@ static struct {
int inotify_fd, inotify_wd = -1;
bool out_of_date;
+ bool full_view;
+
wchar_t editor;
wstring editor_line;
} g;
-static inline int visible_lines () { return max (0, LINES - 2); }
+fun inline visible_lines () -> int { return max (0, LINES - 2); }
+
+fun make_mode (mode_t m) -> wstring {
+ auto type = L'-';
+ if (S_ISDIR (m)) type = L'd';
+ if (S_ISBLK (m)) type = L'b';
+ if (S_ISCHR (m)) type = L'c';
+ if (S_ISLNK (m)) type = L'l';
+ if (S_ISFIFO (m)) type = L'p';
+ if (S_ISSOCK (m)) type = L's';
+
+ wstring mode = {type};
+ mode += L"r-"[!(m & S_IRUSR)];
+ mode += L"w-"[!(m & S_IWUSR)];
+ mode += ((m & S_ISUID) ? L"sS" : L"x-")[!(m & S_IXUSR)];
+ mode += L"r-"[!(m & S_IRGRP)];
+ mode += L"w-"[!(m & S_IWGRP)];
+ mode += ((m & S_ISGID) ? L"sS" : L"x-")[!(m & S_IXGRP)];
+ mode += L"r-"[!(m & S_IROTH)];
+ mode += L"w-"[!(m & S_IWOTH)];
+ mode += ((m & S_ISVTX) ? L"tT" : L"x-")[!(m & S_IXOTH)];
+ return mode;
+}
+
+fun make_row (const entry &entry) -> vector {
+ vector result;
+ const auto &info = entry.info;
+ result.push_back (apply_attrs (make_mode (info.st_mode), 0));
+
+ if (auto u = getpwuid (info.st_uid)) {
+ result.push_back (apply_attrs (to_wide (u->pw_name), 0));
+ } else {
+ result.push_back (apply_attrs (to_wstring (info.st_uid), 0));
+ }
+
+ if (auto g = getgrgid (info.st_gid)) {
+ result.push_back (apply_attrs (to_wide (g->gr_name), 0));
+ } else {
+ result.push_back (apply_attrs (to_wstring (info.st_gid), 0));
+ }
+
+ // TODO: human-readable
+ result.push_back (apply_attrs (to_wstring (info.st_size), 0));
+
+ auto now = time (NULL);
+ auto now_year = localtime (&now)->tm_year;
+
+ char buf[32] = "";
+ auto tm = localtime (&info.st_mtime);
+ strftime (buf, sizeof buf,
+ (tm->tm_year == now_year) ? "%b %e %H:%M" : "%b %e %Y", tm);
+ result.push_back (apply_attrs (to_wide (buf), 0));
+
+ // TODO: symlink target and whatever formatting
+ result.push_back (apply_attrs (to_wide (entry.filename), 0));
+ return result;
+}
-static void
-update () {
+fun update () {
erase ();
int available = visible_lines ();
@@ -149,23 +235,17 @@ update () {
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 &entry = g.entries[index];
-
- // TODO display more information from "info"
- char modes[] = "- ";
- const auto &stat = entry.info;
- if (S_ISDIR (stat.st_mode)) modes[0] = 'd';
- if (S_ISBLK (stat.st_mode)) modes[0] = 'b';
- if (S_ISCHR (stat.st_mode)) modes[0] = 'c';
- if (S_ISLNK (stat.st_mode)) modes[0] = 'l';
- if (S_ISFIFO (stat.st_mode)) modes[0] = 'p';
- if (S_ISSOCK (stat.st_mode)) modes[0] = 's';
- addstr (modes);
-
- // TODO show symbolic link target
- auto width = COLS - 2;
- hline (' ', width - print (to_wide (entry.filename), width));
+ auto limit = COLS, used = 0;
+ for (auto &i : row) {
+ used += print_nc (i, limit - used);
+ used += print (L" ", limit - used);
+ }
+ hline (' ', limit - used);
}
attrset (A_BOLD);
@@ -186,8 +266,7 @@ update () {
refresh ();
}
-static void
-reload () {
+fun reload () {
char buf[4096];
g.cwd = getcwd (buf, sizeof buf);
@@ -217,8 +296,7 @@ reload () {
IN_ALL_EVENTS | IN_ONLYDIR);
}
-static void
-search (const wstring &needle) {
+fun search (const wstring &needle) {
int best = g.cursor, best_n = 0;
for (int i = 0; i < int (g.entries.size ()); i++) {
auto o = (i + g.cursor) % g.entries.size ();
@@ -231,8 +309,7 @@ search (const wstring &needle) {
g.cursor = best;
}
-static void
-handle_editor (wint_t c, bool is_char) {
+fun handle_editor (wint_t c, bool is_char) {
if (c == 27 || c == (CTRL L'g')) {
g.editor_line.clear ();
g.editor = 0;
@@ -256,8 +333,7 @@ handle_editor (wint_t c, bool is_char) {
beep ();
}
-static bool
-handle (wint_t c, bool is_char) {
+fun handle (wint_t c, bool is_char) -> bool {
// If an editor is active, let it handle the key instead and eat it
if (g.editor) {
handle_editor (c, is_char);
@@ -329,6 +405,10 @@ handle (wint_t c, bool is_char) {
case CTRL L'e': g.offset++; break;
case CTRL L'y': g.offset--; break;
+ case ALT | L't':
+ g.full_view = !g.full_view;
+ break;
+
case ALT | L'e':
g.editor_line = to_wide (current.filename);
// Fall-through
@@ -368,8 +448,7 @@ handle (wint_t c, bool is_char) {
return true;
}
-static void
-inotify_check () {
+fun inotify_check () {
// Only provide simple indication that contents might have changed
char buf[4096]; ssize_t len;
bool changed = false;
@@ -385,8 +464,7 @@ inotify_check () {
update ();
}
-int
-main (int argc, char *argv[]) {
+int main (int argc, char *argv[]) {
(void) argc;
(void) argv;
--
cgit v1.2.3-70-g09d2