Store runtime and configuration to a file
Added a toggle for gravity, now turned off by default.
This commit is contained in:
parent
beee2e2683
commit
4de89faf7e
110
sdn.cpp
110
sdn.cpp
|
@ -175,6 +175,14 @@ fun parse_line (istream &is, vector<string> &out) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun write_line (ostream &os, const vector<string> &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 {
|
fun decode_type (mode_t m) -> wchar_t {
|
||||||
if (S_ISDIR (m)) return L'd'; if (S_ISBLK (m)) return L'b';
|
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';
|
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<ifstream> {
|
||||||
for (const auto &dir : dirs) {
|
for (const auto &dir : dirs) {
|
||||||
if (dir[0] != '/')
|
if (dir[0] != '/')
|
||||||
continue;
|
continue;
|
||||||
if (ifstream ifs {dir + suffix})
|
if (ifstream ifs {dir + "/" PROJECT_NAME "/" + suffix})
|
||||||
return make_unique<ifstream> (move (ifs));
|
return make_unique<ifstream> (move (ifs));
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun xdg_config_write (const string &suffix) -> unique_ptr<fstream> {
|
||||||
|
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<fstream> (move (fs));
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
using ncstring = basic_string<cchar_t>;
|
using ncstring = basic_string<cchar_t>;
|
||||||
|
@ -439,6 +458,7 @@ static struct {
|
||||||
vector<level> levels; ///< Upper directory levels
|
vector<level> levels; ///< Upper directory levels
|
||||||
int offset, cursor; ///< Scroll offset and cursor position
|
int offset, cursor; ///< Scroll offset and cursor position
|
||||||
bool full_view; ///< Show extended information
|
bool full_view; ///< Show extended information
|
||||||
|
bool gravity; ///< Entries are shoved to the bottom
|
||||||
int max_widths[entry::COLUMNS]; ///< Column widths
|
int max_widths[entry::COLUMNS]; ///< Column widths
|
||||||
|
|
||||||
string chosen; ///< Chosen item for the command line
|
string chosen; ///< Chosen item for the command line
|
||||||
|
@ -625,7 +645,7 @@ fun update () {
|
||||||
auto index = g.offset + i;
|
auto index = g.offset + i;
|
||||||
bool selected = index == g.cursor;
|
bool selected = index == g.cursor;
|
||||||
attrset (selected ? g.attrs[g.AT_CURSOR] : 0);
|
attrset (selected ? g.attrs[g.AT_CURSOR] : 0);
|
||||||
move (available - used + i, 0);
|
move (g.gravity ? (available - used + i) : i, 0);
|
||||||
|
|
||||||
auto used = 0;
|
auto used = 0;
|
||||||
for (int col = start_column; col < entry::COLUMNS; col++) {
|
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);
|
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) {
|
fun change_dir (const string &path) {
|
||||||
if (chdir (path.c_str ())) {
|
if (chdir (path.c_str ())) {
|
||||||
beep ();
|
beep ();
|
||||||
|
@ -795,20 +832,7 @@ fun change_dir (const string &path) {
|
||||||
g.levels.push_back (last);
|
g.levels.push_back (last);
|
||||||
g.offset = g.cursor = 0;
|
g.offset = g.cursor = 0;
|
||||||
} else {
|
} else {
|
||||||
string anchor;
|
pop_levels ();
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1046,7 +1070,7 @@ fun load_colors () {
|
||||||
if (const char *colors = getenv ("LS_COLORS"))
|
if (const char *colors = getenv ("LS_COLORS"))
|
||||||
load_ls_colors (split (colors, ":"));
|
load_ls_colors (split (colors, ":"));
|
||||||
|
|
||||||
auto config = xdg_config_find ("/" PROJECT_NAME "/look");
|
auto config = xdg_config_find ("look");
|
||||||
if (!config)
|
if (!config)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1133,7 +1157,7 @@ fun load_bindings () {
|
||||||
learn_named_key (filtered, SYM | kc);
|
learn_named_key (filtered, SYM | kc);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto config = xdg_config_find ("/" PROJECT_NAME "/bindings");
|
auto config = xdg_config_find ("bindings");
|
||||||
if (!config)
|
if (!config)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1175,6 +1199,53 @@ fun load_bindings () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun load_history_level (const vector<string> &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<string> 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[]) {
|
int main (int argc, char *argv[]) {
|
||||||
(void) argc;
|
(void) argc;
|
||||||
(void) argv;
|
(void) argv;
|
||||||
|
@ -1200,6 +1271,7 @@ int main (int argc, char *argv[]) {
|
||||||
|
|
||||||
locale::global (locale (""));
|
locale::global (locale (""));
|
||||||
load_bindings ();
|
load_bindings ();
|
||||||
|
load_config ();
|
||||||
|
|
||||||
if (!initscr () || cbreak () == ERR || noecho () == ERR || nonl () == ERR) {
|
if (!initscr () || cbreak () == ERR || noecho () == ERR || nonl () == ERR) {
|
||||||
cerr << "cannot initialize screen" << endl;
|
cerr << "cannot initialize screen" << endl;
|
||||||
|
@ -1209,6 +1281,7 @@ int main (int argc, char *argv[]) {
|
||||||
load_colors ();
|
load_colors ();
|
||||||
reload ();
|
reload ();
|
||||||
g.start_dir = g.cwd;
|
g.start_dir = g.cwd;
|
||||||
|
pop_levels ();
|
||||||
update ();
|
update ();
|
||||||
|
|
||||||
// Invoking keypad() earlier would make ncurses flush its output buffer,
|
// 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))
|
while (!read_key (c) || handle (c))
|
||||||
inotify_check ();
|
inotify_check ();
|
||||||
endwin ();
|
endwin ();
|
||||||
|
save_config ();
|
||||||
|
|
||||||
// Presumably it is going to end up as an argument, so quote it
|
// Presumably it is going to end up as an argument, so quote it
|
||||||
if (!g.chosen.empty ())
|
if (!g.chosen.empty ())
|
||||||
|
|
Loading…
Reference in New Issue