Compare commits
7 Commits
2c595100ae
...
d6846e6327
Author | SHA1 | Date | |
---|---|---|---|
d6846e6327 | |||
314ba114a1 | |||
4de89faf7e | |||
beee2e2683 | |||
4ab0db3c04 | |||
3624636c2f | |||
e80c56e249 |
218
sdn.cpp
218
sdn.cpp
@ -114,7 +114,7 @@ fun needs_shell_quoting (const string &v) -> bool {
|
|||||||
for (auto c : v)
|
for (auto c : v)
|
||||||
if (strchr ("|&;<>()$`\\\"' \t\n" "*?[#˜=%" "!", c))
|
if (strchr ("|&;<>()$`\\\"' \t\n" "*?[#˜=%" "!", c))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return v.empty ();
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shell_escape (const string &v) -> string {
|
fun shell_escape (const string &v) -> string {
|
||||||
@ -130,6 +130,59 @@ fun shell_escape (const string &v) -> string {
|
|||||||
return "'" + result + "'";
|
return "'" + result + "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun parse_line (istream &is, vector<string> &out) -> bool {
|
||||||
|
enum {STA, DEF, COM, ESC, WOR, QUO, STATES};
|
||||||
|
enum {TAKE = 1 << 3, PUSH = 1 << 4, STOP = 1 << 5, ERROR = 1 << 6};
|
||||||
|
enum {TWOR = TAKE | WOR};
|
||||||
|
|
||||||
|
// We never transition back to the start state, so it can stay as a noop
|
||||||
|
static char table[STATES][7] = {
|
||||||
|
// state EOF SP, TAB ' # \ LF default
|
||||||
|
/* STA */ {ERROR, DEF, QUO, COM, ESC, STOP, TWOR},
|
||||||
|
/* DEF */ {STOP, 0, QUO, COM, ESC, STOP, TWOR},
|
||||||
|
/* COM */ {STOP, 0, 0, 0, 0, STOP, 0},
|
||||||
|
/* ESC */ {ERROR, TWOR, TWOR, TWOR, TWOR, TWOR, TWOR},
|
||||||
|
/* WOR */ {STOP | PUSH, DEF | PUSH, QUO, TAKE, ESC, STOP | PUSH, TAKE},
|
||||||
|
/* QUO */ {ERROR, TAKE, WOR, TAKE, TAKE, TAKE, TAKE},
|
||||||
|
};
|
||||||
|
|
||||||
|
out.clear (); string token; int state = STA;
|
||||||
|
constexpr auto eof = istream::traits_type::eof ();
|
||||||
|
while (1) {
|
||||||
|
int ch = is.get (), edge = 0;
|
||||||
|
switch (ch) {
|
||||||
|
case eof: edge = table[state][0]; break;
|
||||||
|
case '\t':
|
||||||
|
case ' ': edge = table[state][1]; break;
|
||||||
|
case '\'': edge = table[state][2]; break;
|
||||||
|
case '#': edge = table[state][3]; break;
|
||||||
|
case '\\': edge = table[state][4]; break;
|
||||||
|
case '\n': edge = table[state][5]; break;
|
||||||
|
default: edge = table[state][6]; break;
|
||||||
|
}
|
||||||
|
if (edge & TAKE)
|
||||||
|
token += ch;
|
||||||
|
if (edge & PUSH) {
|
||||||
|
out.push_back (token);
|
||||||
|
token.clear ();
|
||||||
|
}
|
||||||
|
if (edge & STOP)
|
||||||
|
return true;
|
||||||
|
if (edge & ERROR)
|
||||||
|
return false;
|
||||||
|
if (edge &= 7)
|
||||||
|
state = edge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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';
|
||||||
@ -149,8 +202,7 @@ fun decode_mode (mode_t m) -> wstring {
|
|||||||
((m & S_ISGID) ? L"sS" : L"x-")[!(m & S_IXGRP)],
|
((m & S_ISGID) ? L"sS" : L"x-")[!(m & S_IXGRP)],
|
||||||
L"r-"[!(m & S_IROTH)],
|
L"r-"[!(m & S_IROTH)],
|
||||||
L"w-"[!(m & S_IWOTH)],
|
L"w-"[!(m & S_IWOTH)],
|
||||||
((m & S_ISVTX) ? L"tT" : L"x-")[!(m & S_IXOTH)],
|
((m & S_ISVTX) ? L"tT" : L"x-")[!(m & S_IXOTH)]};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T> fun shift (vector<T> &v) -> T {
|
template<class T> fun shift (vector<T> &v) -> T {
|
||||||
@ -191,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>;
|
||||||
@ -307,7 +370,7 @@ enum { ALT = 1 << 24, SYM = 1 << 25 }; // Outside the range of Unicode
|
|||||||
|
|
||||||
#define ACTIONS(XX) XX(NONE) XX(CHOOSE) XX(CHOOSE_FULL) XX(HELP) XX(QUIT) \
|
#define ACTIONS(XX) XX(NONE) XX(CHOOSE) XX(CHOOSE_FULL) XX(HELP) XX(QUIT) \
|
||||||
XX(UP) XX(DOWN) XX(TOP) XX(BOTTOM) XX(PAGE_PREVIOUS) XX(PAGE_NEXT) \
|
XX(UP) XX(DOWN) XX(TOP) XX(BOTTOM) XX(PAGE_PREVIOUS) XX(PAGE_NEXT) \
|
||||||
XX(SCROLL_UP) XX(SCROLL_DOWN) XX(GO_START) XX(GO_HOME) \
|
XX(SCROLL_UP) XX(SCROLL_DOWN) XX(CHDIR) XX(GO_START) XX(GO_HOME) \
|
||||||
XX(SEARCH) XX(RENAME) XX(RENAME_PREFILL) \
|
XX(SEARCH) XX(RENAME) XX(RENAME_PREFILL) \
|
||||||
XX(TOGGLE_FULL) XX(REDRAW) XX(RELOAD) \
|
XX(TOGGLE_FULL) XX(REDRAW) XX(RELOAD) \
|
||||||
XX(INPUT_ABORT) XX(INPUT_CONFIRM) XX(INPUT_B_DELETE)
|
XX(INPUT_ABORT) XX(INPUT_CONFIRM) XX(INPUT_B_DELETE)
|
||||||
@ -320,7 +383,7 @@ enum action { ACTIONS(XX) ACTION_COUNT };
|
|||||||
static const char *g_action_names[] = {ACTIONS(XX)};
|
static const char *g_action_names[] = {ACTIONS(XX)};
|
||||||
#undef XX
|
#undef XX
|
||||||
|
|
||||||
static map<wint_t, action> g_normal_actions = {
|
static map<wint_t, action> g_normal_actions {
|
||||||
{ALT | '\r', ACTION_CHOOSE_FULL}, {ALT | KEY (ENTER), ACTION_CHOOSE_FULL},
|
{ALT | '\r', ACTION_CHOOSE_FULL}, {ALT | KEY (ENTER), ACTION_CHOOSE_FULL},
|
||||||
{'\r', ACTION_CHOOSE}, {KEY (ENTER), ACTION_CHOOSE}, {'h', ACTION_HELP},
|
{'\r', ACTION_CHOOSE}, {KEY (ENTER), ACTION_CHOOSE}, {'h', ACTION_HELP},
|
||||||
// M-o ought to be the same shortcut the navigator is launched with
|
// M-o ought to be the same shortcut the navigator is launched with
|
||||||
@ -331,18 +394,18 @@ static map<wint_t, action> g_normal_actions = {
|
|||||||
{'G', ACTION_BOTTOM}, {ALT | '>', ACTION_BOTTOM}, {KEY(END), ACTION_BOTTOM},
|
{'G', ACTION_BOTTOM}, {ALT | '>', ACTION_BOTTOM}, {KEY(END), ACTION_BOTTOM},
|
||||||
{KEY (PPAGE), ACTION_PAGE_PREVIOUS}, {KEY (NPAGE), ACTION_PAGE_NEXT},
|
{KEY (PPAGE), ACTION_PAGE_PREVIOUS}, {KEY (NPAGE), ACTION_PAGE_NEXT},
|
||||||
{CTRL 'y', ACTION_SCROLL_UP}, {CTRL 'e', ACTION_SCROLL_DOWN},
|
{CTRL 'y', ACTION_SCROLL_UP}, {CTRL 'e', ACTION_SCROLL_DOWN},
|
||||||
{'&', ACTION_GO_START}, {'~', ACTION_GO_HOME},
|
{'c', ACTION_CHDIR}, {'&', ACTION_GO_START}, {'~', ACTION_GO_HOME},
|
||||||
{'/', ACTION_SEARCH}, {'s', ACTION_SEARCH},
|
{'/', ACTION_SEARCH}, {'s', ACTION_SEARCH},
|
||||||
{ALT | 'e', ACTION_RENAME_PREFILL}, {'e', ACTION_RENAME},
|
{ALT | 'e', ACTION_RENAME_PREFILL}, {'e', ACTION_RENAME},
|
||||||
{'t', ACTION_TOGGLE_FULL}, {ALT | 't', ACTION_TOGGLE_FULL},
|
{'t', ACTION_TOGGLE_FULL}, {ALT | 't', ACTION_TOGGLE_FULL},
|
||||||
{CTRL 'L', ACTION_REDRAW}, {'r', ACTION_RELOAD},
|
{CTRL 'L', ACTION_REDRAW}, {'r', ACTION_RELOAD},
|
||||||
};
|
};
|
||||||
static map<wint_t, action> g_input_actions = {
|
static map<wint_t, action> g_input_actions {
|
||||||
{27, ACTION_INPUT_ABORT}, {CTRL 'g', ACTION_INPUT_ABORT},
|
{27, ACTION_INPUT_ABORT}, {CTRL 'g', ACTION_INPUT_ABORT},
|
||||||
{L'\r', ACTION_INPUT_CONFIRM}, {KEY (ENTER), ACTION_INPUT_CONFIRM},
|
{L'\r', ACTION_INPUT_CONFIRM}, {KEY (ENTER), ACTION_INPUT_CONFIRM},
|
||||||
{KEY (BACKSPACE), ACTION_INPUT_B_DELETE},
|
{KEY (BACKSPACE), ACTION_INPUT_B_DELETE},
|
||||||
};
|
};
|
||||||
static const map<string, map<wint_t, action>*> g_binding_contexts = {
|
static const map<string, map<wint_t, action>*> g_binding_contexts {
|
||||||
{"normal", &g_normal_actions}, {"input", &g_input_actions},
|
{"normal", &g_normal_actions}, {"input", &g_input_actions},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -395,8 +458,12 @@ 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
|
||||||
|
|
||||||
|
wstring message; ///< Message for the user
|
||||||
|
int message_ttl; ///< Time to live for the message
|
||||||
|
|
||||||
string chosen; ///< Chosen item for the command line
|
string chosen; ///< Chosen item for the command line
|
||||||
bool chosen_full; ///< Use the full path
|
bool chosen_full; ///< Use the full path
|
||||||
|
|
||||||
@ -581,7 +648,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++) {
|
||||||
@ -603,13 +670,16 @@ fun update () {
|
|||||||
hline (' ', COLS - print (bar, COLS));
|
hline (' ', COLS - print (bar, COLS));
|
||||||
|
|
||||||
attrset (g.attrs[g.AT_INPUT]);
|
attrset (g.attrs[g.AT_INPUT]);
|
||||||
|
curs_set (0);
|
||||||
if (g.editor) {
|
if (g.editor) {
|
||||||
move (LINES - 1, 0);
|
move (LINES - 1, 0);
|
||||||
auto p = apply_attrs (wstring (g.editor) + L": ", 0);
|
auto p = apply_attrs (wstring (g.editor) + L": ", 0);
|
||||||
move (LINES - 1, print (p + apply_attrs (g.editor_line, 0), COLS - 1));
|
move (LINES - 1, print (p + apply_attrs (g.editor_line, 0), COLS - 1));
|
||||||
curs_set (1);
|
curs_set (1);
|
||||||
} else
|
} else if (!g.message.empty ()) {
|
||||||
curs_set (0);
|
move (LINES - 1, 0);
|
||||||
|
print (apply_attrs (g.message, 0), COLS);
|
||||||
|
}
|
||||||
|
|
||||||
refresh ();
|
refresh ();
|
||||||
}
|
}
|
||||||
@ -654,7 +724,11 @@ fun reload () {
|
|||||||
(IN_ALL_EVENTS | IN_ONLYDIR | IN_EXCL_UNLINK) & ~(IN_ACCESS | IN_OPEN));
|
(IN_ALL_EVENTS | IN_ONLYDIR | IN_EXCL_UNLINK) & ~(IN_ACCESS | IN_OPEN));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we should be able to signal failures to the user
|
fun show_message (const string &message, int ttl = 30) {
|
||||||
|
g.message = to_wide (message);
|
||||||
|
g.message_ttl = ttl;
|
||||||
|
}
|
||||||
|
|
||||||
fun run_pager (FILE *contents) {
|
fun run_pager (FILE *contents) {
|
||||||
// We don't really need to set O_CLOEXEC, so we're not going to
|
// We don't really need to set O_CLOEXEC, so we're not going to
|
||||||
rewind (contents);
|
rewind (contents);
|
||||||
@ -735,25 +809,11 @@ fun search (const wstring &needle) {
|
|||||||
fun is_ancestor_dir (const string &ancestor, const string &of) -> bool {
|
fun is_ancestor_dir (const string &ancestor, const string &of) -> bool {
|
||||||
if (strncmp (ancestor.c_str (), of.c_str (), ancestor.length ()))
|
if (strncmp (ancestor.c_str (), of.c_str (), ancestor.length ()))
|
||||||
return false;
|
return false;
|
||||||
return of.c_str ()[ancestor.length ()] == '/'
|
return of[ancestor.length ()] == '/' || (ancestor == "/" && ancestor != of);
|
||||||
|| (ancestor == "/" && ancestor != of);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun change_dir (const string &path) {
|
fun pop_levels () {
|
||||||
if (chdir (path.c_str ())) {
|
string anchor; auto i = g.levels.rbegin ();
|
||||||
beep ();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
level last {g.offset, g.cursor, g.cwd, g.entries[g.cursor].filename};
|
|
||||||
reload ();
|
|
||||||
|
|
||||||
if (is_ancestor_dir (last.path, g.cwd)) {
|
|
||||||
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)) {
|
while (i != g.levels.rend () && !is_ancestor_dir (i->path, g.cwd)) {
|
||||||
if (i->path == g.cwd) {
|
if (i->path == g.cwd) {
|
||||||
g.offset = i->offset;
|
g.offset = i->offset;
|
||||||
@ -767,6 +827,23 @@ fun change_dir (const string &path) {
|
|||||||
|| g.entries[g.cursor].filename != anchor))
|
|| g.entries[g.cursor].filename != anchor))
|
||||||
search (to_wide (anchor));
|
search (to_wide (anchor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun change_dir (const string &path) {
|
||||||
|
if (chdir (path.c_str ())) {
|
||||||
|
show_message (strerror (errno));
|
||||||
|
beep ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
level last {g.offset, g.cursor, g.cwd, g.entries[g.cursor].filename};
|
||||||
|
reload ();
|
||||||
|
|
||||||
|
if (is_ancestor_dir (last.path, g.cwd)) {
|
||||||
|
g.levels.push_back (last);
|
||||||
|
g.offset = g.cursor = 0;
|
||||||
|
} else {
|
||||||
|
pop_levels ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun choose (const entry &entry) -> bool {
|
fun choose (const entry &entry) -> bool {
|
||||||
@ -858,6 +935,12 @@ fun handle (wint_t c) -> bool {
|
|||||||
g.offset--;
|
g.offset--;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ACTION_CHDIR:
|
||||||
|
g.editor = L"chdir";
|
||||||
|
g.editor_on_confirm = [] {
|
||||||
|
change_dir (to_mb (g.editor_line));
|
||||||
|
};
|
||||||
|
break;
|
||||||
case ACTION_GO_START:
|
case ACTION_GO_START:
|
||||||
change_dir (g.start_dir);
|
change_dir (g.start_dir);
|
||||||
break;
|
break;
|
||||||
@ -1003,14 +1086,13 @@ 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;
|
||||||
|
|
||||||
string line;
|
vector<string> tokens;
|
||||||
while (getline (*config, line)) {
|
while (parse_line (*config, tokens)) {
|
||||||
auto tokens = split (line, " ");
|
if (tokens.empty ())
|
||||||
if (tokens.empty () || line.front () == '#')
|
|
||||||
continue;
|
continue;
|
||||||
auto name = shift (tokens);
|
auto name = shift (tokens);
|
||||||
for (int i = 0; i < g.AT_COUNT; i++)
|
for (int i = 0; i < g.AT_COUNT; i++)
|
||||||
@ -1091,7 +1173,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;
|
||||||
|
|
||||||
@ -1106,10 +1188,9 @@ fun load_bindings () {
|
|||||||
actions[name] = action (a++);
|
actions[name] = action (a++);
|
||||||
}
|
}
|
||||||
|
|
||||||
string line;
|
vector<string> tokens;
|
||||||
while (getline (*config, line)) {
|
while (parse_line (*config, tokens)) {
|
||||||
auto tokens = split (line, " ");
|
if (tokens.empty ())
|
||||||
if (tokens.empty () || line.front () == '#')
|
|
||||||
continue;
|
continue;
|
||||||
if (tokens.size () < 3) {
|
if (tokens.size () < 3) {
|
||||||
cerr << "bindings: expected: context binding action";
|
cerr << "bindings: expected: context binding action";
|
||||||
@ -1134,6 +1215,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;
|
||||||
@ -1159,6 +1287,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;
|
||||||
@ -1168,6 +1297,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,
|
||||||
@ -1179,9 +1309,15 @@ int main (int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wint_t c;
|
wint_t c;
|
||||||
while (!read_key (c) || handle (c))
|
while (!read_key (c) || handle (c)) {
|
||||||
inotify_check ();
|
inotify_check ();
|
||||||
|
if (g.message_ttl && !--g.message_ttl) {
|
||||||
|
g.message.clear ();
|
||||||
|
update ();
|
||||||
|
}
|
||||||
|
}
|
||||||
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…
x
Reference in New Issue
Block a user