From 4de89faf7e0649f1f805cbeabbf682390bf820de Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Fri, 2 Nov 2018 14:32:24 +0100
Subject: Store runtime and configuration to a file
Added a toggle for gravity, now turned off by default.
---
sdn.cpp | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 92 insertions(+), 18 deletions(-)
diff --git a/sdn.cpp b/sdn.cpp
index b56d458..0cca9b9 100644
--- a/sdn.cpp
+++ b/sdn.cpp
@@ -175,6 +175,14 @@ fun parse_line (istream &is, vector &out) -> bool {
}
}
+fun write_line (ostream &os, const vector &in) {
+ if (!in.empty ())
+ os << shell_escape (in.at (0));
+ for (size_t i = 1; i < in.size (); i++)
+ os << " " << shell_escape (in.at (i));
+ os << endl;
+}
+
fun decode_type (mode_t m) -> wchar_t {
if (S_ISDIR (m)) return L'd'; if (S_ISBLK (m)) return L'b';
if (S_ISCHR (m)) return L'c'; if (S_ISLNK (m)) return L'l';
@@ -235,12 +243,23 @@ fun xdg_config_find (const string &suffix) -> unique_ptr {
for (const auto &dir : dirs) {
if (dir[0] != '/')
continue;
- if (ifstream ifs {dir + suffix})
+ if (ifstream ifs {dir + "/" PROJECT_NAME "/" + suffix})
return make_unique (move (ifs));
}
return nullptr;
}
+fun xdg_config_write (const string &suffix) -> unique_ptr {
+ auto dir = xdg_config_home ();
+ if (dir[0] == '/') {
+ // TODO: try to create the end directory
+ if (fstream fs {dir + "/" PROJECT_NAME "/" + suffix,
+ fstream::in | fstream::out | fstream::trunc})
+ return make_unique (move (fs));
+ }
+ return nullptr;
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
using ncstring = basic_string;
@@ -439,6 +458,7 @@ static struct {
vector levels; ///< Upper directory levels
int offset, cursor; ///< Scroll offset and cursor position
bool full_view; ///< Show extended information
+ bool gravity; ///< Entries are shoved to the bottom
int max_widths[entry::COLUMNS]; ///< Column widths
string chosen; ///< Chosen item for the command line
@@ -625,7 +645,7 @@ fun update () {
auto index = g.offset + i;
bool selected = index == g.cursor;
attrset (selected ? g.attrs[g.AT_CURSOR] : 0);
- move (available - used + i, 0);
+ move (g.gravity ? (available - used + i) : i, 0);
auto used = 0;
for (int col = start_column; col < entry::COLUMNS; col++) {
@@ -782,6 +802,23 @@ fun is_ancestor_dir (const string &ancestor, const string &of) -> bool {
return of[ancestor.length ()] == '/' || (ancestor == "/" && ancestor != of);
}
+fun pop_levels () {
+ string anchor;
+ auto i = g.levels.rbegin ();
+ while (i != g.levels.rend () && !is_ancestor_dir (i->path, g.cwd)) {
+ if (i->path == g.cwd) {
+ g.offset = i->offset;
+ g.cursor = i->cursor;
+ anchor = i->filename;
+ }
+ i++;
+ g.levels.pop_back ();
+ }
+ if (!anchor.empty () && (g.cursor >= g.entries.size ()
+ || g.entries[g.cursor].filename != anchor))
+ search (to_wide (anchor));
+}
+
fun change_dir (const string &path) {
if (chdir (path.c_str ())) {
beep ();
@@ -795,20 +832,7 @@ fun change_dir (const string &path) {
g.levels.push_back (last);
g.offset = g.cursor = 0;
} else {
- string anchor;
- auto i = g.levels.rbegin ();
- while (i != g.levels.rend () && !is_ancestor_dir (i->path, g.cwd)) {
- if (i->path == g.cwd) {
- g.offset = i->offset;
- g.cursor = i->cursor;
- anchor = i->filename;
- }
- i++;
- g.levels.pop_back ();
- }
- if (!anchor.empty () && (g.cursor >= g.entries.size ()
- || g.entries[g.cursor].filename != anchor))
- search (to_wide (anchor));
+ pop_levels ();
}
}
@@ -1046,7 +1070,7 @@ fun load_colors () {
if (const char *colors = getenv ("LS_COLORS"))
load_ls_colors (split (colors, ":"));
- auto config = xdg_config_find ("/" PROJECT_NAME "/look");
+ auto config = xdg_config_find ("look");
if (!config)
return;
@@ -1133,7 +1157,7 @@ fun load_bindings () {
learn_named_key (filtered, SYM | kc);
}
- auto config = xdg_config_find ("/" PROJECT_NAME "/bindings");
+ auto config = xdg_config_find ("bindings");
if (!config)
return;
@@ -1175,6 +1199,53 @@ fun load_bindings () {
}
}
+fun load_history_level (const vector &v) {
+ if (v.size () != 6)
+ return;
+ // Not checking the hostname and parent PID right now since we can't merge
+ g.levels.push_back ({stoi (v.at (4)), stoi (v.at (5)), v.at (3), v.at (6)});
+}
+
+fun load_config () {
+ auto config = xdg_config_find ("config");
+ if (!config)
+ return;
+
+ vector tokens;
+ while (parse_line (*config, tokens)) {
+ if (tokens.empty ())
+ continue;
+
+ if (tokens.front () == "full-view")
+ g.full_view = tokens.size () > 1 && tokens.at (1) == "1";
+ else if (tokens.front () == "gravity")
+ g.gravity = tokens.size () > 1 && tokens.at (1) == "1";
+ else if (tokens.front () == "history")
+ load_history_level (tokens);
+ }
+}
+
+fun save_config () {
+ auto config = xdg_config_write ("config");
+ if (!config)
+ return;
+
+ write_line (*config, {"full-view", g.full_view ? "1" : "0"});
+ write_line (*config, {"gravity", g.gravity ? "1" : "0"});
+
+ char hostname[256];
+ if (gethostname (hostname, sizeof hostname))
+ *hostname = 0;
+
+ auto ppid = std::to_string (getppid ());
+ for (auto i = g.levels.begin (); i != g.levels.end (); i++)
+ write_line (*config, {"history", hostname, ppid, i->path,
+ to_string (i->offset), to_string (i->cursor), i->filename});
+ write_line (*config, {"history", hostname, ppid, g.cwd,
+ to_string (g.offset), to_string (g.cursor),
+ g.entries[g.cursor].filename});
+}
+
int main (int argc, char *argv[]) {
(void) argc;
(void) argv;
@@ -1200,6 +1271,7 @@ int main (int argc, char *argv[]) {
locale::global (locale (""));
load_bindings ();
+ load_config ();
if (!initscr () || cbreak () == ERR || noecho () == ERR || nonl () == ERR) {
cerr << "cannot initialize screen" << endl;
@@ -1209,6 +1281,7 @@ int main (int argc, char *argv[]) {
load_colors ();
reload ();
g.start_dir = g.cwd;
+ pop_levels ();
update ();
// Invoking keypad() earlier would make ncurses flush its output buffer,
@@ -1223,6 +1296,7 @@ int main (int argc, char *argv[]) {
while (!read_key (c) || handle (c))
inotify_check ();
endwin ();
+ save_config ();
// Presumably it is going to end up as an argument, so quote it
if (!g.chosen.empty ())
--
cgit v1.2.3-70-g09d2