| 
						 
						
						
						
						 
					 | 
					 | 
					@@ -1,7 +1,7 @@
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					//
 | 
					 | 
					 | 
					 | 
					//
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					// sdn: simple directory navigator
 | 
					 | 
					 | 
					 | 
					// sdn: simple directory navigator
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					//
 | 
					 | 
					 | 
					 | 
					//
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					// Copyright (c) 2017 - 2021, Přemysl Eric Janouch <p@janouch.name>
 | 
					 | 
					 | 
					 | 
					// Copyright (c) 2017 - 2024, Přemysl Eric Janouch <p@janouch.name>
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					//
 | 
					 | 
					 | 
					 | 
					//
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					// Permission to use, copy, modify, and/or distribute this software for any
 | 
					 | 
					 | 
					 | 
					// Permission to use, copy, modify, and/or distribute this software for any
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					// purpose with or without fee is hereby granted.
 | 
					 | 
					 | 
					 | 
					// purpose with or without fee is hereby granted.
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -18,42 +18,53 @@
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					// May be required for ncursesw and we generally want it all anyway
 | 
					 | 
					 | 
					 | 
					// May be required for ncursesw and we generally want it all anyway
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#define _XOPEN_SOURCE_EXTENDED
 | 
					 | 
					 | 
					 | 
					#define _XOPEN_SOURCE_EXTENDED
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <string>
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <vector>
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <locale>
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <iostream>
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <algorithm>
 | 
					 | 
					 | 
					 | 
					#include <algorithm>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <cwchar>
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <climits>
 | 
					 | 
					 | 
					 | 
					#include <climits>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <cstdlib>
 | 
					 | 
					 | 
					 | 
					#include <cstdlib>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <cstring>
 | 
					 | 
					 | 
					 | 
					#include <cstring>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#include <cwchar>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <fstream>
 | 
					 | 
					 | 
					 | 
					#include <fstream>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#include <iostream>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#include <locale>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <map>
 | 
					 | 
					 | 
					 | 
					#include <map>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <tuple>
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <memory>
 | 
					 | 
					 | 
					 | 
					#include <memory>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#include <string>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#include <tuple>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#include <vector>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <unistd.h>
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <dirent.h>
 | 
					 | 
					 | 
					 | 
					#include <dirent.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <sys/stat.h>
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <sys/types.h>
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <sys/acl.h>
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <fcntl.h>
 | 
					 | 
					 | 
					 | 
					#include <fcntl.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <pwd.h>
 | 
					 | 
					 | 
					 | 
					#include <fnmatch.h>
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <grp.h>
 | 
					 | 
					 | 
					 | 
					#include <grp.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <libgen.h>
 | 
					 | 
					 | 
					 | 
					#include <libgen.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <time.h>
 | 
					 | 
					 | 
					 | 
					#include <pwd.h>
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <signal.h>
 | 
					 | 
					 | 
					 | 
					#include <signal.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					#include <sys/stat.h>
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <sys/inotify.h>
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <sys/xattr.h>
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <sys/types.h>
 | 
					 | 
					 | 
					 | 
					#include <sys/types.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <sys/wait.h>
 | 
					 | 
					 | 
					 | 
					#include <sys/wait.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#include <time.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#include <unistd.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#ifdef __linux__
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#include <sys/inotify.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					// ACL information is not important enough to be ported
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <acl/libacl.h>
 | 
					 | 
					 | 
					 | 
					#include <acl/libacl.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#include <sys/acl.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#include <sys/xattr.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#else
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#include <sys/event.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#endif
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#include <ncurses.h>
 | 
					 | 
					 | 
					 | 
					#include <ncurses.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					// Unicode is complex enough already and we might make assumptions
 | 
					 | 
					 | 
					 | 
					// To implement cbreak() with disabled ^S that gets reënabled on endwin()
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#define NCURSES_INTERNALS
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#include <term.h>
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#undef CTRL  // term.h -> termios.h -> sys/ttydefaults.h, too simplistic
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#ifndef __STDC_ISO_10646__
 | 
					 | 
					 | 
					 | 
					#ifndef __STDC_ISO_10646__
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#error Unicode required for wchar_t
 | 
					 | 
					 | 
					 | 
					// Unicode is complex enough already and we might make assumptions,
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					// though macOS doesn't define this despite using UCS-4,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					// and we won't build on Windows that seems to be the only one to use UTF-16.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#endif
 | 
					 | 
					 | 
					 | 
					#endif
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					// Trailing return types make C++ syntax suck considerably less
 | 
					 | 
					 | 
					 | 
					// Trailing return types make C++ syntax suck considerably less
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -93,8 +104,8 @@ fun to_mb (const wstring &wide) -> string {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						return mb;
 | 
					 | 
					 | 
					 | 
						return mb;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun prefix_length (const wstring &in, const wstring &of) -> int {
 | 
					 | 
					 | 
					 | 
					fun prefix_length (const wstring &in, const wstring &of) -> size_t {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						int score = 0;
 | 
					 | 
					 | 
					 | 
						size_t score = 0;
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						for (size_t i = 0; i < of.size () && in.size () >= i && in[i] == of[i]; i++)
 | 
					 | 
					 | 
					 | 
						for (size_t i = 0; i < of.size () && in.size () >= i && in[i] == of[i]; i++)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							score++;
 | 
					 | 
					 | 
					 | 
							score++;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						return score;
 | 
					 | 
					 | 
					 | 
						return score;
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -159,9 +170,9 @@ fun shell_escape (const string &v) -> string {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun parse_line (istream &is, vector<string> &out) -> bool {
 | 
					 | 
					 | 
					 | 
					fun parse_line (istream &is, vector<string> &out) -> bool {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						enum {STA, DEF, COM, ESC, WOR, QUO, STATES};
 | 
					 | 
					 | 
					 | 
						enum { STA, DEF, COM, ESC, WOR, QUO, STATES };
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						enum {TAKE = 1 << 3, PUSH = 1 << 4, STOP = 1 << 5, ERROR = 1 << 6};
 | 
					 | 
					 | 
					 | 
						enum { TAKE = 1 << 3, PUSH = 1 << 4, STOP = 1 << 5, ERROR = 1 << 6 };
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						enum {TWOR = TAKE | WOR};
 | 
					 | 
					 | 
					 | 
						enum { TWOR = TAKE | WOR };
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						// We never transition back to the start state, so it can stay as a no-op
 | 
					 | 
					 | 
					 | 
						// We never transition back to the start state, so it can stay as a no-op
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						static char table[STATES][7] = {
 | 
					 | 
					 | 
					 | 
						static char table[STATES][7] = {
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -246,7 +257,7 @@ fun capitalize (const string &s) -> string {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					/// Underlining for teletypes (also called overstriking),
 | 
					 | 
					 | 
					 | 
					/// Underlining for teletypes (also called overstriking),
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					/// also imitated in more(1) and less(1)
 | 
					 | 
					 | 
					 | 
					/// also imitated in more(1) and less(1)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun underline (const string& s) -> string {
 | 
					 | 
					 | 
					 | 
					fun underline (const string &s) -> string {
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						string result;
 | 
					 | 
					 | 
					 | 
						string result;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						for (auto c : s)
 | 
					 | 
					 | 
					 | 
						for (auto c : s)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							result.append ({c, 8, '_'});
 | 
					 | 
					 | 
					 | 
							result.append ({c, 8, '_'});
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -268,7 +279,7 @@ fun xdg_config_home () -> string {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun xdg_config_find (const string &suffix) -> unique_ptr<ifstream> {
 | 
					 | 
					 | 
					 | 
					fun xdg_config_find (const string &suffix) -> unique_ptr<ifstream> {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						vector<string> dirs {xdg_config_home ()};
 | 
					 | 
					 | 
					 | 
						vector<string> dirs {xdg_config_home ()};
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						const char *system_dirs = getenv ("XDG_CONFIG_DIRS");
 | 
					 | 
					 | 
					 | 
						const char *system_dirs = getenv ("XDG_CONFIG_DIRS");
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						split (system_dirs ? system_dirs : "/etc/xdg", ":", dirs);
 | 
					 | 
					 | 
					 | 
						split ((system_dirs && *system_dirs) ? system_dirs : "/etc/xdg", ":", dirs);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						for (const auto &dir : dirs) {
 | 
					 | 
					 | 
					 | 
						for (const auto &dir : dirs) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if (dir[0] != '/')
 | 
					 | 
					 | 
					 | 
							if (dir[0] != '/')
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								continue;
 | 
					 | 
					 | 
					 | 
								continue;
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -297,7 +308,21 @@ fun xdg_config_write (const string &suffix) -> unique_ptr<fstream> {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
					 | 
					 | 
					 | 
					// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					using ncstring = basic_string<cchar_t>;
 | 
					 | 
					 | 
					 | 
					// This should be basic_string, however that crashes on macOS
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					using ncstring = vector<cchar_t>;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					fun operator+ (const ncstring &lhs, const ncstring &rhs) -> ncstring {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						ncstring result;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						result.reserve (lhs.size () + rhs.size ());
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						result.insert (result.end (), lhs.begin (), lhs.end ());
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						result.insert (result.end (), rhs.begin (), rhs.end ());
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						return result;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					fun operator+= (ncstring &lhs, const ncstring &rhs) -> ncstring & {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						lhs.insert (lhs.end (), rhs.begin (), rhs.end ());
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						return lhs;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun cchar (chtype attrs, wchar_t c) -> cchar_t {
 | 
					 | 
					 | 
					 | 
					fun cchar (chtype attrs, wchar_t c) -> cchar_t {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						cchar_t ch {}; wchar_t ws[] = {c, 0};
 | 
					 | 
					 | 
					 | 
						cchar_t ch {}; wchar_t ws[] = {c, 0};
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -318,9 +343,9 @@ fun invert (cchar_t &ch) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun apply_attrs (const wstring &w, attr_t attrs) -> ncstring {
 | 
					 | 
					 | 
					 | 
					fun apply_attrs (const wstring &w, attr_t attrs) -> ncstring {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						ncstring res;
 | 
					 | 
					 | 
					 | 
						ncstring res (w.size (), cchar_t {});
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						for (auto c : w)
 | 
					 | 
					 | 
					 | 
						for (size_t i = 0; i < w.size (); i++)
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							res += cchar (attrs, c);
 | 
					 | 
					 | 
					 | 
							res[i] = cchar (attrs, w[i]);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						return res;
 | 
					 | 
					 | 
					 | 
						return res;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -405,12 +430,13 @@ enum { ALT = 1 << 24, SYM = 1 << 25 };  // Outside the range of Unicode
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#define ACTIONS(XX) XX(NONE) XX(HELP) XX(QUIT) XX(QUIT_NO_CHDIR) \
 | 
					 | 
					 | 
					 | 
					#define ACTIONS(XX) XX(NONE) XX(HELP) XX(QUIT) XX(QUIT_NO_CHDIR) \
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						XX(CHOOSE) XX(CHOOSE_FULL) XX(VIEW) XX(EDIT) XX(SORT_LEFT) XX(SORT_RIGHT) \
 | 
					 | 
					 | 
					 | 
						XX(CHOOSE) XX(CHOOSE_FULL) XX(VIEW) XX(EDIT) XX(SORT_LEFT) XX(SORT_RIGHT) \
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						XX(UP) XX(DOWN) XX(TOP) XX(BOTTOM) XX(HIGH) XX(MIDDLE) XX(LOW) \
 | 
					 | 
					 | 
					 | 
						XX(UP) XX(DOWN) XX(TOP) XX(BOTTOM) XX(HIGH) XX(MIDDLE) XX(LOW) \
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						XX(PAGE_PREVIOUS) XX(PAGE_NEXT) XX(SCROLL_UP) XX(SCROLL_DOWN) \
 | 
					 | 
					 | 
					 | 
						XX(PAGE_PREVIOUS) XX(PAGE_NEXT) XX(SCROLL_UP) XX(SCROLL_DOWN) XX(CENTER) \
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						XX(CHDIR) XX(PARENT) XX(GO_START) XX(GO_HOME) \
 | 
					 | 
					 | 
					 | 
						XX(CHDIR) XX(PARENT) XX(GO_START) XX(GO_HOME) \
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						XX(SEARCH) XX(RENAME) XX(RENAME_PREFILL) \
 | 
					 | 
					 | 
					 | 
						XX(SEARCH) XX(RENAME) XX(RENAME_PREFILL) XX(MKDIR) \
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						XX(TOGGLE_FULL) XX(REVERSE_SORT) XX(SHOW_HIDDEN) XX(REDRAW) XX(RELOAD) \
 | 
					 | 
					 | 
					 | 
						XX(TOGGLE_FULL) XX(REVERSE_SORT) XX(SHOW_HIDDEN) XX(REDRAW) XX(RELOAD) \
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						XX(INPUT_ABORT) XX(INPUT_CONFIRM) XX(INPUT_B_DELETE) XX(INPUT_DELETE) \
 | 
					 | 
					 | 
					 | 
						XX(INPUT_ABORT) XX(INPUT_CONFIRM) XX(INPUT_B_DELETE) XX(INPUT_DELETE) \
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						XX(INPUT_B_KILL_LINE) XX(INPUT_KILL_LINE) XX(INPUT_QUOTED_INSERT) \
 | 
					 | 
					 | 
					 | 
						XX(INPUT_B_KILL_WORD) XX(INPUT_B_KILL_LINE) XX(INPUT_KILL_LINE) \
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						XX(INPUT_QUOTED_INSERT) \
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						XX(INPUT_BACKWARD) XX(INPUT_FORWARD) XX(INPUT_BEGINNING) XX(INPUT_END)
 | 
					 | 
					 | 
					 | 
						XX(INPUT_BACKWARD) XX(INPUT_FORWARD) XX(INPUT_BEGINNING) XX(INPUT_END)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#define XX(name) ACTION_ ## name,
 | 
					 | 
					 | 
					 | 
					#define XX(name) ACTION_ ## name,
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -437,10 +463,12 @@ static map<wint_t, action> g_normal_actions {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{'H', ACTION_HIGH}, {'M', ACTION_MIDDLE}, {'L', ACTION_LOW},
 | 
					 | 
					 | 
					 | 
						{'H', ACTION_HIGH}, {'M', ACTION_MIDDLE}, {'L', ACTION_LOW},
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{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},
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						{'z', ACTION_CENTER},
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{'c', ACTION_CHDIR}, {ALT | KEY (UP), ACTION_PARENT},
 | 
					 | 
					 | 
					 | 
						{'c', ACTION_CHDIR}, {ALT | KEY (UP), ACTION_PARENT},
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{'&', ACTION_GO_START}, {'~', ACTION_GO_HOME},
 | 
					 | 
					 | 
					 | 
						{'&', ACTION_GO_START}, {'~', ACTION_GO_HOME},
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{'/', ACTION_SEARCH},  {'s', ACTION_SEARCH},
 | 
					 | 
					 | 
					 | 
						{'/', ACTION_SEARCH}, {'s', ACTION_SEARCH}, {CTRL ('S'), ACTION_SEARCH},
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{ALT | 'e', ACTION_RENAME_PREFILL}, {'e', ACTION_RENAME},
 | 
					 | 
					 | 
					 | 
						{ALT | 'e', ACTION_RENAME_PREFILL}, {'e', ACTION_RENAME},
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						{KEY (F (6)), ACTION_RENAME_PREFILL}, {KEY (F (7)), ACTION_MKDIR},
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{'t', ACTION_TOGGLE_FULL}, {ALT | 't', ACTION_TOGGLE_FULL},
 | 
					 | 
					 | 
					 | 
						{'t', ACTION_TOGGLE_FULL}, {ALT | 't', ACTION_TOGGLE_FULL},
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{'R', ACTION_REVERSE_SORT}, {ALT | '.', ACTION_SHOW_HIDDEN},
 | 
					 | 
					 | 
					 | 
						{'R', ACTION_REVERSE_SORT}, {ALT | '.', ACTION_SHOW_HIDDEN},
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{CTRL ('L'), ACTION_REDRAW}, {'r', ACTION_RELOAD},
 | 
					 | 
					 | 
					 | 
						{CTRL ('L'), ACTION_REDRAW}, {'r', ACTION_RELOAD},
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -451,7 +479,8 @@ static map<wint_t, action> g_input_actions {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						// Sometimes terminfo is wrong, we need to accept both of these
 | 
					 | 
					 | 
					 | 
						// Sometimes terminfo is wrong, we need to accept both of these
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{L'\b', ACTION_INPUT_B_DELETE}, {CTRL ('?'), ACTION_INPUT_B_DELETE},
 | 
					 | 
					 | 
					 | 
						{L'\b', ACTION_INPUT_B_DELETE}, {CTRL ('?'), ACTION_INPUT_B_DELETE},
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{KEY (BACKSPACE), ACTION_INPUT_B_DELETE}, {KEY (DC), ACTION_INPUT_DELETE},
 | 
					 | 
					 | 
					 | 
						{KEY (BACKSPACE), ACTION_INPUT_B_DELETE}, {KEY (DC), ACTION_INPUT_DELETE},
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{CTRL ('D'), ACTION_INPUT_DELETE}, {CTRL ('U'), ACTION_INPUT_B_KILL_LINE},
 | 
					 | 
					 | 
					 | 
						{CTRL ('W'), ACTION_INPUT_B_KILL_WORD}, {CTRL ('D'), ACTION_INPUT_DELETE},
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						{CTRL ('U'), ACTION_INPUT_B_KILL_LINE},
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{CTRL ('K'), ACTION_INPUT_KILL_LINE},
 | 
					 | 
					 | 
					 | 
						{CTRL ('K'), ACTION_INPUT_KILL_LINE},
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{CTRL ('V'), ACTION_INPUT_QUOTED_INSERT},
 | 
					 | 
					 | 
					 | 
						{CTRL ('V'), ACTION_INPUT_QUOTED_INSERT},
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						{CTRL ('B'), ACTION_INPUT_BACKWARD}, {KEY (LEFT), ACTION_INPUT_BACKWARD},
 | 
					 | 
					 | 
					 | 
						{CTRL ('B'), ACTION_INPUT_BACKWARD}, {KEY (LEFT), ACTION_INPUT_BACKWARD},
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -485,7 +514,7 @@ static const char *g_ls_colors[] = {LS(XX)};
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					struct stringcaseless {
 | 
					 | 
					 | 
					 | 
					struct stringcaseless {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						bool operator () (const string &a, const string &b) const {
 | 
					 | 
					 | 
					 | 
						bool operator () (const string &a, const string &b) const {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							const auto &c = locale::classic();
 | 
					 | 
					 | 
					 | 
							const auto &c = locale::classic ();
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							return lexicographical_compare (begin (a), end (a), begin (b), end (b),
 | 
					 | 
					 | 
					 | 
							return lexicographical_compare (begin (a), end (a), begin (b), end (b),
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								[&](char m, char n) { return tolower (m, c) < tolower (n, c); });
 | 
					 | 
					 | 
					 | 
								[&](char m, char n) { return tolower (m, c) < tolower (n, c); });
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -528,7 +557,7 @@ static struct {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						bool no_chdir;                      ///< Do not tell the shell to chdir
 | 
					 | 
					 | 
					 | 
						bool no_chdir;                      ///< Do not tell the shell to chdir
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						bool quitting;                      ///< Whether we should quit already
 | 
					 | 
					 | 
					 | 
						bool quitting;                      ///< Whether we should quit already
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						int inotify_fd, inotify_wd = -1;    ///< File watch
 | 
					 | 
					 | 
					 | 
						int watch_fd, watch_wd = -1;        ///< File watch (inotify/kqueue)
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						bool out_of_date;                   ///< Entries may be out of date
 | 
					 | 
					 | 
					 | 
						bool out_of_date;                   ///< Entries may be out of date
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						const wchar_t *editor;              ///< Prompt string for editing
 | 
					 | 
					 | 
					 | 
						const wchar_t *editor;              ///< Prompt string for editing
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -537,7 +566,6 @@ static struct {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						int editor_cursor = 0;              ///< Cursor position
 | 
					 | 
					 | 
					 | 
						int editor_cursor = 0;              ///< Cursor position
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						bool editor_inserting;              ///< Inserting a literal character
 | 
					 | 
					 | 
					 | 
						bool editor_inserting;              ///< Inserting a literal character
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						void (*editor_on_change) ();        ///< Callback on editor change
 | 
					 | 
					 | 
					 | 
						void (*editor_on_change) ();        ///< Callback on editor change
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						void (*editor_on_confirm) ();       ///< Callback on editor confirmation
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						map<action, void (*) ()> editor_on; ///< Handlers for custom actions
 | 
					 | 
					 | 
					 | 
						map<action, void (*) ()> editor_on; ///< Handlers for custom actions
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						enum { AT_CURSOR, AT_BAR, AT_CWD, AT_INPUT, AT_INFO, AT_CMDLINE, AT_COUNT };
 | 
					 | 
					 | 
					 | 
						enum { AT_CURSOR, AT_BAR, AT_CWD, AT_INPUT, AT_INFO, AT_CMDLINE, AT_COUNT };
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -556,8 +584,8 @@ static struct {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						// Refreshed by reload():
 | 
					 | 
					 | 
					 | 
						// Refreshed by reload():
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						map<uid_t, string> unames;          ///< User names by UID
 | 
					 | 
					 | 
					 | 
						map<uid_t, wstring> unames;         ///< User names by UID
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						map<gid_t, string> gnames;          ///< Group names by GID
 | 
					 | 
					 | 
					 | 
						map<gid_t, wstring> gnames;         ///< Group names by GID
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						struct tm now;                      ///< Current local time for display
 | 
					 | 
					 | 
					 | 
						struct tm now;                      ///< Current local time for display
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					} g;
 | 
					 | 
					 | 
					 | 
					} g;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -588,8 +616,10 @@ fun ls_format (const entry &e, bool for_target) -> chtype {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								set (LS_MULTIHARDLINK);
 | 
					 | 
					 | 
					 | 
								set (LS_MULTIHARDLINK);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if ((info.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
 | 
					 | 
					 | 
					 | 
							if ((info.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								set (LS_EXECUTABLE);
 | 
					 | 
					 | 
					 | 
								set (LS_EXECUTABLE);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#ifdef __linux__
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if (lgetxattr (name.c_str (), "security.capability", NULL, 0) >= 0)
 | 
					 | 
					 | 
					 | 
							if (lgetxattr (name.c_str (), "security.capability", NULL, 0) >= 0)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								set (LS_CAPABILITY);
 | 
					 | 
					 | 
					 | 
								set (LS_CAPABILITY);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#endif
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if ((info.st_mode & S_ISGID))
 | 
					 | 
					 | 
					 | 
							if ((info.st_mode & S_ISGID))
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								set (LS_SETGID);
 | 
					 | 
					 | 
					 | 
								set (LS_SETGID);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if ((info.st_mode & S_ISUID))
 | 
					 | 
					 | 
					 | 
							if ((info.st_mode & S_ISUID))
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -604,8 +634,8 @@ fun ls_format (const entry &e, bool for_target) -> chtype {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								set (LS_STICKY_OTHER_WRITABLE);
 | 
					 | 
					 | 
					 | 
								set (LS_STICKY_OTHER_WRITABLE);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						} else if (S_ISLNK (info.st_mode)) {
 | 
					 | 
					 | 
					 | 
						} else if (S_ISLNK (info.st_mode)) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							type = LS_SYMLINK;
 | 
					 | 
					 | 
					 | 
							type = LS_SYMLINK;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if (!e.target_info.st_mode
 | 
					 | 
					 | 
					 | 
							if (!e.target_info.st_mode &&
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							 && (ls_is_colored (LS_ORPHAN) || g.ls_symlink_as_target))
 | 
					 | 
					 | 
					 | 
								(ls_is_colored (LS_ORPHAN) || g.ls_symlink_as_target))
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								type = LS_ORPHAN;
 | 
					 | 
					 | 
					 | 
								type = LS_ORPHAN;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						} else if (S_ISFIFO (info.st_mode)) {
 | 
					 | 
					 | 
					 | 
						} else if (S_ISFIFO (info.st_mode)) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							type = LS_FIFO;
 | 
					 | 
					 | 
					 | 
							type = LS_FIFO;
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -631,15 +661,33 @@ fun ls_format (const entry &e, bool for_target) -> chtype {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						return format;
 | 
					 | 
					 | 
					 | 
						return format;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					fun suffixize (off_t size, unsigned shift, wchar_t suffix, std::wstring &out)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						-> bool {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						// Prevent implementation-defined and undefined behaviour
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						if (size < 0 || shift >= sizeof size * 8)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							return false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						off_t divided = size >> shift;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						if (divided >= 10) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							out.assign (std::to_wstring (divided)).append (1, suffix);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							return true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						} else if (divided > 0) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							unsigned times_ten = size / double (off_t (1) << shift) * 10.0;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							out.assign ({L'0' + wchar_t (times_ten / 10), L'.',
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								L'0' + wchar_t (times_ten % 10), suffix});
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							return true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						return false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun make_entry (const struct dirent *f) -> entry {
 | 
					 | 
					 | 
					 | 
					fun make_entry (const struct dirent *f) -> entry {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						entry e;
 | 
					 | 
					 | 
					 | 
						entry e;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						e.filename = f->d_name;
 | 
					 | 
					 | 
					 | 
						e.filename = f->d_name;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						e.info.st_mode = DTTOIF (f->d_type);
 | 
					 | 
					 | 
					 | 
						e.info.st_mode = DTTOIF (f->d_type);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						auto &info = e.info;
 | 
					 | 
					 | 
					 | 
						auto &info = e.info;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						// TODO: benchmark just readdir() vs. lstat(), also on dead mounts;
 | 
					 | 
					 | 
					 | 
						// io_uring is only at most about 50% faster, though it might help with
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						//   it might make sense to stat asynchronously in threads
 | 
					 | 
					 | 
					 | 
						// slowly statting devices, at a major complexity cost.
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						//   http://lkml.iu.edu/hypermail//linux/kernel/0804.3/1616.html
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (lstat (f->d_name, &info)) {
 | 
					 | 
					 | 
					 | 
						if (lstat (f->d_name, &info)) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							e.cols[entry::MODES] = apply_attrs ({ decode_type (info.st_mode),
 | 
					 | 
					 | 
					 | 
							e.cols[entry::MODES] = apply_attrs ({ decode_type (info.st_mode),
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								L'?', L'?', L'?', L'?', L'?', L'?', L'?', L'?', L'?' }, 0);
 | 
					 | 
					 | 
					 | 
								L'?', L'?', L'?', L'?', L'?', L'?', L'?', L'?', L'?' }, 0);
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -665,39 +713,44 @@ fun make_entry (const struct dirent *f) -> entry {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						auto mode = decode_mode (info.st_mode);
 | 
					 | 
					 | 
					 | 
						auto mode = decode_mode (info.st_mode);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						// This is a Linux-only extension
 | 
					 | 
					 | 
					 | 
					#ifdef __linux__
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						// We're using a laughably small subset of libacl: this translates to
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						// two lgetxattr() calls, the results of which are compared with
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						// specific architecture-dependent constants.  Linux-only.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (acl_extended_file_nofollow (f->d_name) > 0)
 | 
					 | 
					 | 
					 | 
						if (acl_extended_file_nofollow (f->d_name) > 0)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							mode += L"+";
 | 
					 | 
					 | 
					 | 
							mode += L"+";
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#endif
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						e.cols[entry::MODES] = apply_attrs (mode, 0);
 | 
					 | 
					 | 
					 | 
						e.cols[entry::MODES] = apply_attrs (mode, 0);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						auto usr = g.unames.find (info.st_uid);
 | 
					 | 
					 | 
					 | 
						auto usr = g.unames.find (info.st_uid);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						e.cols[entry::USER] = (usr != g.unames.end ())
 | 
					 | 
					 | 
					 | 
						e.cols[entry::USER] = (usr != g.unames.end ())
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							? apply_attrs (to_wide (usr->second), 0)
 | 
					 | 
					 | 
					 | 
							? apply_attrs (usr->second, 0)
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							: apply_attrs (to_wstring (info.st_uid), 0);
 | 
					 | 
					 | 
					 | 
							: apply_attrs (to_wstring (info.st_uid), 0);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						auto grp = g.gnames.find (info.st_gid);
 | 
					 | 
					 | 
					 | 
						auto grp = g.gnames.find (info.st_gid);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						e.cols[entry::GROUP] = (grp != g.gnames.end ())
 | 
					 | 
					 | 
					 | 
						e.cols[entry::GROUP] = (grp != g.gnames.end ())
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							? apply_attrs (to_wide (grp->second), 0)
 | 
					 | 
					 | 
					 | 
							? apply_attrs (grp->second, 0)
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							: apply_attrs (to_wstring (info.st_gid), 0);
 | 
					 | 
					 | 
					 | 
							: apply_attrs (to_wstring (info.st_gid), 0);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						auto size = to_wstring (info.st_size);
 | 
					 | 
					 | 
					 | 
						std::wstring size;
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if      (info.st_size >> 40) size = to_wstring (info.st_size >> 40) + L"T";
 | 
					 | 
					 | 
					 | 
						if (!suffixize (info.st_size, 40, L'T', size) &&
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						else if (info.st_size >> 30) size = to_wstring (info.st_size >> 30) + L"G";
 | 
					 | 
					 | 
					 | 
							!suffixize (info.st_size, 30, L'G', size) &&
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						else if (info.st_size >> 20) size = to_wstring (info.st_size >> 20) + L"M";
 | 
					 | 
					 | 
					 | 
							!suffixize (info.st_size, 20, L'M', size) &&
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						else if (info.st_size >> 10) size = to_wstring (info.st_size >> 10) + L"K";
 | 
					 | 
					 | 
					 | 
							!suffixize (info.st_size, 10, L'K', size))
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							size = to_wstring (info.st_size);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						e.cols[entry::SIZE] = apply_attrs (size, 0);
 | 
					 | 
					 | 
					 | 
						e.cols[entry::SIZE] = apply_attrs (size, 0);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						char buf[32] = "";
 | 
					 | 
					 | 
					 | 
						wchar_t buf[32] = L"";
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						auto tm = localtime (&info.st_mtime);
 | 
					 | 
					 | 
					 | 
						auto tm = localtime (&info.st_mtime);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						strftime (buf, sizeof buf,
 | 
					 | 
					 | 
					 | 
						wcsftime (buf, sizeof buf / sizeof *buf,
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							(tm->tm_year == g.now.tm_year) ? "%b %e %H:%M" : "%b %e  %Y", tm);
 | 
					 | 
					 | 
					 | 
							(tm->tm_year == g.now.tm_year) ? L"%b %e %H:%M" : L"%b %e  %Y", tm);
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						e.cols[entry::MTIME] = apply_attrs (to_wide (buf), 0);
 | 
					 | 
					 | 
					 | 
						e.cols[entry::MTIME] = apply_attrs (buf, 0);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						auto &fn = e.cols[entry::FILENAME] =
 | 
					 | 
					 | 
					 | 
						auto &fn = e.cols[entry::FILENAME] =
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							apply_attrs (to_wide (e.filename), ls_format (e, false));
 | 
					 | 
					 | 
					 | 
							apply_attrs (to_wide (e.filename), ls_format (e, false));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (!e.target_path.empty ()) {
 | 
					 | 
					 | 
					 | 
						if (!e.target_path.empty ()) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							fn.append (apply_attrs (to_wide (" -> "), 0));
 | 
					 | 
					 | 
					 | 
							fn += apply_attrs (L" -> ", 0);
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							fn.append (apply_attrs (to_wide (e.target_path), ls_format (e, true)));
 | 
					 | 
					 | 
					 | 
							fn += apply_attrs (to_wide (e.target_path), ls_format (e, true));
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						return e;
 | 
					 | 
					 | 
					 | 
						return e;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -706,7 +759,7 @@ fun inline visible_lines () -> int { return max (0, LINES - 2); }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun update () {
 | 
					 | 
					 | 
					 | 
					fun update () {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						int start_column = g.full_view ? 0 : entry::FILENAME;
 | 
					 | 
					 | 
					 | 
						int start_column = g.full_view ? 0 : entry::FILENAME;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						static int alignment[entry::COLUMNS] = { -1, -1, -1, 1, 1, -1 };
 | 
					 | 
					 | 
					 | 
						static int alignment[entry::COLUMNS] = {-1, -1, -1, 1, 1, -1};
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						erase ();
 | 
					 | 
					 | 
					 | 
						erase ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						int available = visible_lines ();
 | 
					 | 
					 | 
					 | 
						int available = visible_lines ();
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -767,8 +820,8 @@ fun update () {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								print (info, info_width);
 | 
					 | 
					 | 
					 | 
								print (info, info_width);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							}
 | 
					 | 
					 | 
					 | 
							}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							auto start = sanitize (prompt + line.substr (0, g.editor_cursor));
 | 
					 | 
					 | 
					 | 
							line.resize (g.editor_cursor);
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							move (LINES - 1, compute_width (start));
 | 
					 | 
					 | 
					 | 
							move (LINES - 1, compute_width (sanitize (prompt + line)));
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							curs_set (1);
 | 
					 | 
					 | 
					 | 
							curs_set (1);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						} else if (!g.message.empty ()) {
 | 
					 | 
					 | 
					 | 
						} else if (!g.message.empty ()) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							move (LINES - 1, 0);
 | 
					 | 
					 | 
					 | 
							move (LINES - 1, 0);
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -782,9 +835,10 @@ fun update () {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun operator< (const entry &e1, const entry &e2) -> bool {
 | 
					 | 
					 | 
					 | 
					fun operator< (const entry &e1, const entry &e2) -> bool {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						auto t1 = make_tuple (e1.filename != "..",
 | 
					 | 
					 | 
					 | 
						static string dotdot {".."};
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						auto t1 = make_tuple (e1.filename != dotdot,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							!S_ISDIR (e1.info.st_mode) && !S_ISDIR (e1.target_info.st_mode));
 | 
					 | 
					 | 
					 | 
							!S_ISDIR (e1.info.st_mode) && !S_ISDIR (e1.target_info.st_mode));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						auto t2 = make_tuple (e2.filename != "..",
 | 
					 | 
					 | 
					 | 
						auto t2 = make_tuple (e2.filename != dotdot,
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							!S_ISDIR (e2.info.st_mode) && !S_ISDIR (e2.target_info.st_mode));
 | 
					 | 
					 | 
					 | 
							!S_ISDIR (e2.info.st_mode) && !S_ISDIR (e2.target_info.st_mode));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (t1 != t2)
 | 
					 | 
					 | 
					 | 
						if (t1 != t2)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							return t1 < t2;
 | 
					 | 
					 | 
					 | 
							return t1 < t2;
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -821,16 +875,34 @@ fun at_cursor () -> const entry & {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						return g.cursor >= int (g.entries.size ()) ? invalid : g.entries[g.cursor];
 | 
					 | 
					 | 
					 | 
						return g.cursor >= int (g.entries.size ()) ? invalid : g.entries[g.cursor];
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun reload (bool keep_anchor) {
 | 
					 | 
					 | 
					 | 
					fun focus (const string &anchor) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						g.unames.clear();
 | 
					 | 
					 | 
					 | 
						if (!anchor.empty ()) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						while (auto *ent = getpwent ())
 | 
					 | 
					 | 
					 | 
							for (size_t i = 0; i < g.entries.size (); i++)
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.unames.emplace (ent->pw_uid, ent->pw_name);
 | 
					 | 
					 | 
					 | 
								if (g.entries[i].filename == anchor)
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						endpwent();
 | 
					 | 
					 | 
					 | 
									g.cursor = i;
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						g.gnames.clear();
 | 
					 | 
					 | 
					 | 
					fun resort (const string anchor = at_cursor ().filename) {
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						sort (begin (g.entries), end (g.entries));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						focus (anchor);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					fun show_message (const string &message, int ttl = 30) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						g.message = to_wide (message);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						g.message_ttl = ttl;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					fun reload (bool keep_anchor) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						g.unames.clear ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						while (auto *ent = getpwent ())
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							g.unames.emplace (ent->pw_uid, to_wide (ent->pw_name));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						endpwent ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						g.gnames.clear ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						while (auto *ent = getgrent ())
 | 
					 | 
					 | 
					 | 
						while (auto *ent = getgrent ())
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.gnames.emplace (ent->gr_gid, ent->gr_name);
 | 
					 | 
					 | 
					 | 
							g.gnames.emplace (ent->gr_gid, to_wide (ent->gr_name));
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						endgrent();
 | 
					 | 
					 | 
					 | 
						endgrent ();
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						string anchor;
 | 
					 | 
					 | 
					 | 
						string anchor;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (keep_anchor)
 | 
					 | 
					 | 
					 | 
						if (keep_anchor)
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -839,6 +911,16 @@ fun reload (bool keep_anchor) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						auto now = time (NULL); g.now = *localtime (&now);
 | 
					 | 
					 | 
					 | 
						auto now = time (NULL); g.now = *localtime (&now);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						auto dir = opendir (".");
 | 
					 | 
					 | 
					 | 
						auto dir = opendir (".");
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						g.entries.clear ();
 | 
					 | 
					 | 
					 | 
						g.entries.clear ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						if (!dir) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							show_message (strerror (errno));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							if (g.cwd != "/") {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								struct dirent f = {};
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								strncpy (f.d_name, "..", sizeof f.d_name);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								f.d_type = DT_DIR;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								g.entries.push_back (make_entry (&f));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							goto readfail;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						while (auto f = readdir (dir)) {
 | 
					 | 
					 | 
					 | 
						while (auto f = readdir (dir)) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							string name = f->d_name;
 | 
					 | 
					 | 
					 | 
							string name = f->d_name;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							// Two dots are for navigation but this ain't as useful
 | 
					 | 
					 | 
					 | 
							// Two dots are for navigation but this ain't as useful
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -848,45 +930,52 @@ fun reload (bool keep_anchor) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								g.entries.push_back (make_entry (f));
 | 
					 | 
					 | 
					 | 
								g.entries.push_back (make_entry (f));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						closedir (dir);
 | 
					 | 
					 | 
					 | 
						closedir (dir);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						sort (begin (g.entries), end (g.entries));
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						g.out_of_date = false;
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (!anchor.empty ()) {
 | 
					 | 
					 | 
					 | 
					readfail:
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							for (size_t i = 0; i < g.entries.size (); i++)
 | 
					 | 
					 | 
					 | 
						g.out_of_date = false;
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (g.entries[i].filename == anchor)
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									g.cursor = i;
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						for (int col = 0; col < entry::COLUMNS; col++) {
 | 
					 | 
					 | 
					 | 
						for (int col = 0; col < entry::COLUMNS; col++) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							auto &longest = g.max_widths[col] = 0;
 | 
					 | 
					 | 
					 | 
							auto &longest = g.max_widths[col] = 0;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							for (const auto &entry : g.entries)
 | 
					 | 
					 | 
					 | 
							for (const auto &entry : g.entries)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								longest = max (longest, compute_width (entry.cols[col]));
 | 
					 | 
					 | 
					 | 
								longest = max (longest, compute_width (entry.cols[col]));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						resort (anchor);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						g.cursor = max (0, min (g.cursor, int (g.entries.size ()) - 1));
 | 
					 | 
					 | 
					 | 
						g.cursor = max (0, min (g.cursor, int (g.entries.size ()) - 1));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						g.offset = max (0, min (g.offset, int (g.entries.size ()) - 1));
 | 
					 | 
					 | 
					 | 
						g.offset = max (0, min (g.offset, int (g.entries.size ()) - 1));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (g.inotify_wd != -1)
 | 
					 | 
					 | 
					 | 
					#ifdef __linux__
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							inotify_rm_watch (g.inotify_fd, g.inotify_wd);
 | 
					 | 
					 | 
					 | 
						if (g.watch_wd != -1)
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							inotify_rm_watch (g.watch_fd, g.watch_wd);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						// We don't show atime, so access and open are merely spam
 | 
					 | 
					 | 
					 | 
						// We don't show atime, so access and open are merely spam
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						g.inotify_wd = inotify_add_watch (g.inotify_fd, ".",
 | 
					 | 
					 | 
					 | 
						g.watch_wd = inotify_add_watch (g.watch_fd, ".",
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							(IN_ALL_EVENTS | IN_ONLYDIR | IN_EXCL_UNLINK) & ~(IN_ACCESS | IN_OPEN));
 | 
					 | 
					 | 
					 | 
							(IN_ALL_EVENTS | IN_ONLYDIR | IN_EXCL_UNLINK) & ~(IN_ACCESS | IN_OPEN));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#else
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						if (g.watch_wd != -1)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							close (g.watch_wd);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						if ((g.watch_wd = open (".", O_RDONLY | O_DIRECTORY | O_CLOEXEC)) >= 0) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							// At least the macOS kqueue doesn't report anything too specific
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							struct kevent ev {};
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							EV_SET (&ev, g.watch_wd, EVFILT_VNODE, EV_ADD | EV_CLEAR,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								NOTE_WRITE | NOTE_LINK, 0, nullptr);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							(void) kevent (g.watch_fd, &ev, 1, nullptr, 0, nullptr);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#endif
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun show_message (const string &message, int ttl = 30) {
 | 
					 | 
					 | 
					 | 
					fun run_program (initializer_list<const char *> list, const string &filename) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						g.message = to_wide (message);
 | 
					 | 
					 | 
					 | 
						auto args = (!filename.empty() && filename.front() == '-' ? " -- " : " ")
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						g.message_ttl = ttl;
 | 
					 | 
					 | 
					 | 
							+ shell_escape (filename);
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun run_program (initializer_list<const char*> list, const string &filename) {
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (g.ext_helpers) {
 | 
					 | 
					 | 
					 | 
						if (g.ext_helpers) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							// XXX: this doesn't try them all out, though it shouldn't make any
 | 
					 | 
					 | 
					 | 
							// XXX: this doesn't try them all out,
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							// noticeable difference
 | 
					 | 
					 | 
					 | 
							// though it shouldn't make any noticeable difference
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							const char *found = nullptr;
 | 
					 | 
					 | 
					 | 
							const char *found = nullptr;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							for (auto program : list)
 | 
					 | 
					 | 
					 | 
							for (auto program : list)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if ((found = program))
 | 
					 | 
					 | 
					 | 
								if ((found = program))
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									break;
 | 
					 | 
					 | 
					 | 
									break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.ext_helper = found + (" " + shell_escape (filename));
 | 
					 | 
					 | 
					 | 
							g.ext_helper.assign (found).append (args);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.quitting = true;
 | 
					 | 
					 | 
					 | 
							g.quitting = true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							return;
 | 
					 | 
					 | 
					 | 
							return;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -902,8 +991,8 @@ fun run_program (initializer_list<const char*> list, const string &filename) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							tcsetpgrp (STDOUT_FILENO, getpgid (0));
 | 
					 | 
					 | 
					 | 
							tcsetpgrp (STDOUT_FILENO, getpgid (0));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							for (auto program : list)
 | 
					 | 
					 | 
					 | 
							for (auto program : list)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (program) execl ("/bin/sh", "/bin/sh", "-c", (string (program)
 | 
					 | 
					 | 
					 | 
								if (program) execl ("/bin/sh", "/bin/sh", "-c",
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									+ " " + shell_escape (filename)).c_str (), NULL);
 | 
					 | 
					 | 
					 | 
									(program + args).c_str (), NULL);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							_exit (EXIT_FAILURE);
 | 
					 | 
					 | 
					 | 
							_exit (EXIT_FAILURE);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						default:
 | 
					 | 
					 | 
					 | 
						default:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							// ...and make sure of it in the parent as well
 | 
					 | 
					 | 
					 | 
							// ...and make sure of it in the parent as well
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1003,24 +1092,23 @@ fun show_help () {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						fclose (contents);
 | 
					 | 
					 | 
					 | 
						fclose (contents);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					/// Stays on the current match when there are no better ones, unless it's pushed
 | 
					 | 
					 | 
					 | 
					fun match (const wstring &needle, int push) -> int {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun search (const wstring &needle, int push) -> int {
 | 
					 | 
					 | 
					 | 
						string pattern = to_mb (needle) + "*";
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						int best = g.cursor, best_n = 0, matches = 0, step = push != 0 ? push : 1;
 | 
					 | 
					 | 
					 | 
						bool jump_to_first = push || fnmatch (pattern.c_str (),
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							g.entries[g.cursor].filename.c_str (), 0) == FNM_NOMATCH;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						int best = g.cursor, matches = 0, step = push + !push;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						for (int i = 0, count = g.entries.size (); i < count; i++) {
 | 
					 | 
					 | 
					 | 
						for (int i = 0, count = g.entries.size (); i < count; i++) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							auto o = (g.cursor + (count + i * step) + (count + push)) % count;
 | 
					 | 
					 | 
					 | 
							int o = (g.cursor + (count + i * step) + (count + push)) % count;
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							int n = prefix_length (to_wide (g.entries[o].filename), needle);
 | 
					 | 
					 | 
					 | 
							if (!fnmatch (pattern.c_str (), g.entries[o].filename.c_str (), 0)
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							matches += n == needle.size ();
 | 
					 | 
					 | 
					 | 
							 && !matches++ && jump_to_first)
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if (n > best_n) {
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								best = o;
 | 
					 | 
					 | 
					 | 
								best = o;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								best_n = n;
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							}
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						g.cursor = best;
 | 
					 | 
					 | 
					 | 
						g.cursor = best;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						return matches;
 | 
					 | 
					 | 
					 | 
						return matches;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun search_interactive (int push) {
 | 
					 | 
					 | 
					 | 
					fun match_interactive (int push) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						int matches = search (g.editor_line, push);
 | 
					 | 
					 | 
					 | 
						int matches = match (g.editor_line, push);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (g.editor_line.empty ())
 | 
					 | 
					 | 
					 | 
						if (g.editor_line.empty ())
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_info.clear ();
 | 
					 | 
					 | 
					 | 
							g.editor_info.clear ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						else if (matches == 0)
 | 
					 | 
					 | 
					 | 
						else if (matches == 0)
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1031,6 +1119,21 @@ fun search_interactive (int push) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_info = L"(" + to_wstring (matches) + L" matches)";
 | 
					 | 
					 | 
					 | 
							g.editor_info = L"(" + to_wstring (matches) + L" matches)";
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					/// Stays on the current item unless there are better matches
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					fun lookup (const wstring &needle) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						int best = g.cursor;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						size_t best_n = 0;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						for (int i = 0, count = g.entries.size (); i < count; i++) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							int o = (g.cursor + i) % count;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							size_t n = prefix_length (to_wide (g.entries[o].filename), needle);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							if (n > best_n) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								best = o;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								best_n = n;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						g.cursor = best;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun fix_cursor_and_offset () {
 | 
					 | 
					 | 
					 | 
					fun fix_cursor_and_offset () {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						g.cursor = min (g.cursor, int (g.entries.size ()) - 1);
 | 
					 | 
					 | 
					 | 
						g.cursor = min (g.cursor, int (g.entries.size ()) - 1);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						g.cursor = max (g.cursor, 0);
 | 
					 | 
					 | 
					 | 
						g.cursor = max (g.cursor, 0);
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1067,7 +1170,7 @@ fun relativize (string current, const string &path) -> string {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						return path;
 | 
					 | 
					 | 
					 | 
						return path;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun pop_levels (const string& old_cwd) {
 | 
					 | 
					 | 
					 | 
					fun pop_levels (const string &old_cwd) {
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						string anchor; auto i = g.levels.rbegin ();
 | 
					 | 
					 | 
					 | 
						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) {
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1087,7 +1190,7 @@ fun pop_levels (const string& old_cwd) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						fix_cursor_and_offset ();
 | 
					 | 
					 | 
					 | 
						fix_cursor_and_offset ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (!anchor.empty () && at_cursor ().filename != anchor)
 | 
					 | 
					 | 
					 | 
						if (!anchor.empty () && at_cursor ().filename != anchor)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							search (to_wide (anchor), 0);
 | 
					 | 
					 | 
					 | 
							lookup (to_wide (anchor));
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun explode_path (const string &path, vector<string> &out) {
 | 
					 | 
					 | 
					 | 
					fun explode_path (const string &path, vector<string> &out) {
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1145,7 +1248,7 @@ fun change_dir (const string &path) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									beep ();
 | 
					 | 
					 | 
					 | 
									beep ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									return;
 | 
					 | 
					 | 
					 | 
									return;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								}
 | 
					 | 
					 | 
					 | 
								}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (!out.back().empty ())
 | 
					 | 
					 | 
					 | 
								if (!out.back ().empty ())
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									out.pop_back ();
 | 
					 | 
					 | 
					 | 
									out.pop_back ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							} else if (in[i] != "." && (!in[i].empty () || i < startempty)) {
 | 
					 | 
					 | 
					 | 
							} else if (in[i] != "." && (!in[i].empty () || i < startempty)) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								out.push_back (in[i]);
 | 
					 | 
					 | 
					 | 
								out.push_back (in[i]);
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1212,9 +1315,9 @@ fun choose (const entry &entry) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					// Move the cursor in `diff` direction and look for non-combining characters
 | 
					 | 
					 | 
					 | 
					// Move the cursor in `diff` direction and look for non-combining characters
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun move_towards_spacing (int diff) -> bool {
 | 
					 | 
					 | 
					 | 
					fun move_towards_spacing (int diff) -> bool {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						g.editor_cursor += diff;
 | 
					 | 
					 | 
					 | 
						g.editor_cursor += diff;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						return g.editor_cursor <= 0
 | 
					 | 
					 | 
					 | 
						return g.editor_cursor <= 0 ||
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							|| g.editor_cursor >= int (g.editor_line.length ())
 | 
					 | 
					 | 
					 | 
							g.editor_cursor >= int (g.editor_line.length ()) ||
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							|| wcwidth (g.editor_line.at (g.editor_cursor));
 | 
					 | 
					 | 
					 | 
							wcwidth (g.editor_line.at (g.editor_cursor));
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun handle_editor (wint_t c) {
 | 
					 | 
					 | 
					 | 
					fun handle_editor (wint_t c) {
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1228,16 +1331,16 @@ fun handle_editor (wint_t c) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								action = i->second;
 | 
					 | 
					 | 
					 | 
								action = i->second;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							auto m = g_binding_contexts.find (to_mb (g.editor));
 | 
					 | 
					 | 
					 | 
							auto m = g_binding_contexts.find (to_mb (g.editor));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if (m != g_binding_contexts.end ()
 | 
					 | 
					 | 
					 | 
							if (m != g_binding_contexts.end () &&
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							 && (i = m->second->find (c)) != m->second->end ())
 | 
					 | 
					 | 
					 | 
								(i = m->second->find (c)) != m->second->end ())
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								action = i->second;
 | 
					 | 
					 | 
					 | 
								action = i->second;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						auto original = g.editor_line;
 | 
					 | 
					 | 
					 | 
						auto original = g.editor_line;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						switch (action) {
 | 
					 | 
					 | 
					 | 
						switch (action) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_INPUT_CONFIRM:
 | 
					 | 
					 | 
					 | 
						case ACTION_INPUT_CONFIRM:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if (g.editor_on_confirm)
 | 
					 | 
					 | 
					 | 
							if (auto handler = g.editor_on[action])
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								g.editor_on_confirm ();
 | 
					 | 
					 | 
					 | 
								handler ();
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							// Fall-through
 | 
					 | 
					 | 
					 | 
							// Fall-through
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_INPUT_ABORT:
 | 
					 | 
					 | 
					 | 
						case ACTION_INPUT_ABORT:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor = 0;
 | 
					 | 
					 | 
					 | 
							g.editor = 0;
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1246,7 +1349,6 @@ fun handle_editor (wint_t c) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_cursor = 0;
 | 
					 | 
					 | 
					 | 
							g.editor_cursor = 0;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_inserting = false;
 | 
					 | 
					 | 
					 | 
							g.editor_inserting = false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_on_change = nullptr;
 | 
					 | 
					 | 
					 | 
							g.editor_on_change = nullptr;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_on_confirm = nullptr;
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_on.clear ();
 | 
					 | 
					 | 
					 | 
							g.editor_on.clear ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							return;
 | 
					 | 
					 | 
					 | 
							return;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_INPUT_BEGINNING:
 | 
					 | 
					 | 
					 | 
						case ACTION_INPUT_BEGINNING:
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1256,13 +1358,13 @@ fun handle_editor (wint_t c) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_cursor = g.editor_line.length ();
 | 
					 | 
					 | 
					 | 
							g.editor_cursor = g.editor_line.length ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							break;
 | 
					 | 
					 | 
					 | 
							break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_INPUT_BACKWARD:
 | 
					 | 
					 | 
					 | 
						case ACTION_INPUT_BACKWARD:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							while (g.editor_cursor > 0
 | 
					 | 
					 | 
					 | 
							while (g.editor_cursor > 0 &&
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								&& !move_towards_spacing (-1))
 | 
					 | 
					 | 
					 | 
								!move_towards_spacing (-1))
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								;
 | 
					 | 
					 | 
					 | 
								;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							break;
 | 
					 | 
					 | 
					 | 
							break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_INPUT_FORWARD:
 | 
					 | 
					 | 
					 | 
						case ACTION_INPUT_FORWARD:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							while (g.editor_cursor < int (g.editor_line.length ())
 | 
					 | 
					 | 
					 | 
							while (g.editor_cursor < int (g.editor_line.length ()) &&
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								&& !move_towards_spacing (+1))
 | 
					 | 
					 | 
					 | 
								!move_towards_spacing (+1))
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								;
 | 
					 | 
					 | 
					 | 
								;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							break;
 | 
					 | 
					 | 
					 | 
							break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_INPUT_B_DELETE:
 | 
					 | 
					 | 
					 | 
						case ACTION_INPUT_B_DELETE:
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1280,6 +1382,17 @@ fun handle_editor (wint_t c) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									break;
 | 
					 | 
					 | 
					 | 
									break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							}
 | 
					 | 
					 | 
					 | 
							}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							break;
 | 
					 | 
					 | 
					 | 
							break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						case ACTION_INPUT_B_KILL_WORD:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						{
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							int i = g.editor_cursor;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							while (i && g.editor_line[--i] == L' ');
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							while (i-- && g.editor_line[i] != L' ');
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							i++;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							g.editor_line.erase (i, g.editor_cursor - i);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							g.editor_cursor = i;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_INPUT_B_KILL_LINE:
 | 
					 | 
					 | 
					 | 
						case ACTION_INPUT_B_KILL_LINE:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_line.erase (0, g.editor_cursor);
 | 
					 | 
					 | 
					 | 
							g.editor_line.erase (0, g.editor_cursor);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_cursor = 0;
 | 
					 | 
					 | 
					 | 
							g.editor_cursor = 0;
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1295,7 +1408,8 @@ fun handle_editor (wint_t c) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if (auto handler = g.editor_on[action]) {
 | 
					 | 
					 | 
					 | 
							if (auto handler = g.editor_on[action]) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								handler ();
 | 
					 | 
					 | 
					 | 
								handler ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							} else if (c & (ALT | SYM)) {
 | 
					 | 
					 | 
					 | 
							} else if (c & (ALT | SYM)) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								beep ();
 | 
					 | 
					 | 
					 | 
								if (c != KEY (RESIZE))
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
									beep ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							} else {
 | 
					 | 
					 | 
					 | 
							} else {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								g.editor_line.insert (g.editor_cursor, 1, c);
 | 
					 | 
					 | 
					 | 
								g.editor_line.insert (g.editor_cursor, 1, c);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								g.editor_cursor++;
 | 
					 | 
					 | 
					 | 
								g.editor_cursor++;
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1351,12 +1465,12 @@ fun handle (wint_t c) -> bool {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_SORT_LEFT:
 | 
					 | 
					 | 
					 | 
						case ACTION_SORT_LEFT:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.sort_column = (g.sort_column + entry::COLUMNS - 1) % entry::COLUMNS;
 | 
					 | 
					 | 
					 | 
							g.sort_column = (g.sort_column + entry::COLUMNS - 1) % entry::COLUMNS;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.sort_flash_ttl = 2;
 | 
					 | 
					 | 
					 | 
							g.sort_flash_ttl = 2;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							reload (true);
 | 
					 | 
					 | 
					 | 
							resort ();
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							break;
 | 
					 | 
					 | 
					 | 
							break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_SORT_RIGHT:
 | 
					 | 
					 | 
					 | 
						case ACTION_SORT_RIGHT:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.sort_column = (g.sort_column + entry::COLUMNS + 1) % entry::COLUMNS;
 | 
					 | 
					 | 
					 | 
							g.sort_column = (g.sort_column + entry::COLUMNS + 1) % entry::COLUMNS;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.sort_flash_ttl = 2;
 | 
					 | 
					 | 
					 | 
							g.sort_flash_ttl = 2;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							reload (true);
 | 
					 | 
					 | 
					 | 
							resort ();
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							break;
 | 
					 | 
					 | 
					 | 
							break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_UP:
 | 
					 | 
					 | 
					 | 
						case ACTION_UP:
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1395,10 +1509,13 @@ fun handle (wint_t c) -> bool {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_SCROLL_UP:
 | 
					 | 
					 | 
					 | 
						case ACTION_SCROLL_UP:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.offset--;
 | 
					 | 
					 | 
					 | 
							g.offset--;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							break;
 | 
					 | 
					 | 
					 | 
							break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						case ACTION_CENTER:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							g.offset = g.cursor - (visible_lines () - 1) / 2;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_CHDIR:
 | 
					 | 
					 | 
					 | 
						case ACTION_CHDIR:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor = L"chdir";
 | 
					 | 
					 | 
					 | 
							g.editor = L"chdir";
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_on_confirm = [] {
 | 
					 | 
					 | 
					 | 
							g.editor_on[ACTION_INPUT_CONFIRM] = [] {
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								change_dir (untilde (to_mb (g.editor_line)));
 | 
					 | 
					 | 
					 | 
								change_dir (untilde (to_mb (g.editor_line)));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							};
 | 
					 | 
					 | 
					 | 
							};
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							break;
 | 
					 | 
					 | 
					 | 
							break;
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1414,10 +1531,10 @@ fun handle (wint_t c) -> bool {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_SEARCH:
 | 
					 | 
					 | 
					 | 
						case ACTION_SEARCH:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor = L"search";
 | 
					 | 
					 | 
					 | 
							g.editor = L"search";
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_on_change       = [] { search_interactive (0); };
 | 
					 | 
					 | 
					 | 
							g.editor_on_change                = [] { match_interactive (0); };
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_on[ACTION_UP]   = [] { search_interactive (-1); };
 | 
					 | 
					 | 
					 | 
							g.editor_on[ACTION_UP]            = [] { match_interactive (-1); };
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_on[ACTION_DOWN] = [] { search_interactive (+1); };
 | 
					 | 
					 | 
					 | 
							g.editor_on[ACTION_DOWN]          = [] { match_interactive (+1); };
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_on_confirm      = [] { choose (at_cursor ()); };
 | 
					 | 
					 | 
					 | 
							g.editor_on[ACTION_INPUT_CONFIRM] = [] { choose (at_cursor ()); };
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							break;
 | 
					 | 
					 | 
					 | 
							break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_RENAME_PREFILL:
 | 
					 | 
					 | 
					 | 
						case ACTION_RENAME_PREFILL:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_line = to_wide (current.filename);
 | 
					 | 
					 | 
					 | 
							g.editor_line = to_wide (current.filename);
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1425,19 +1542,30 @@ fun handle (wint_t c) -> bool {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							// Fall-through
 | 
					 | 
					 | 
					 | 
							// Fall-through
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_RENAME:
 | 
					 | 
					 | 
					 | 
						case ACTION_RENAME:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor = L"rename";
 | 
					 | 
					 | 
					 | 
							g.editor = L"rename";
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.editor_on_confirm = [] {
 | 
					 | 
					 | 
					 | 
							g.editor_on[ACTION_INPUT_CONFIRM] = [] {
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								auto mb = to_mb (g.editor_line);
 | 
					 | 
					 | 
					 | 
								auto mb = to_mb (g.editor_line);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								rename (at_cursor ().filename.c_str (), mb.c_str ());
 | 
					 | 
					 | 
					 | 
								if (rename (at_cursor ().filename.c_str (), mb.c_str ()))
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
									show_message (strerror (errno));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								reload (true);
 | 
					 | 
					 | 
					 | 
								reload (true);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							};
 | 
					 | 
					 | 
					 | 
							};
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							break;
 | 
					 | 
					 | 
					 | 
							break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						case ACTION_MKDIR:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							g.editor = L"mkdir";
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							g.editor_on[ACTION_INPUT_CONFIRM] = [] {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								auto mb = to_mb (g.editor_line);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								if (mkdir (mb.c_str (), 0777))
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
									show_message (strerror (errno));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								reload (true);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
								focus (mb);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							};
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_TOGGLE_FULL:
 | 
					 | 
					 | 
					 | 
						case ACTION_TOGGLE_FULL:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.full_view = !g.full_view;
 | 
					 | 
					 | 
					 | 
							g.full_view = !g.full_view;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							break;
 | 
					 | 
					 | 
					 | 
							break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_REVERSE_SORT:
 | 
					 | 
					 | 
					 | 
						case ACTION_REVERSE_SORT:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.reverse_sort = !g.reverse_sort;
 | 
					 | 
					 | 
					 | 
							g.reverse_sort = !g.reverse_sort;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							reload (true);
 | 
					 | 
					 | 
					 | 
							resort ();
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							break;
 | 
					 | 
					 | 
					 | 
							break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						case ACTION_SHOW_HIDDEN:
 | 
					 | 
					 | 
					 | 
						case ACTION_SHOW_HIDDEN:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							g.show_hidden = !g.show_hidden;
 | 
					 | 
					 | 
					 | 
							g.show_hidden = !g.show_hidden;
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1458,19 +1586,27 @@ fun handle (wint_t c) -> bool {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						return !g.quitting;
 | 
					 | 
					 | 
					 | 
						return !g.quitting;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fun inotify_check () {
 | 
					 | 
					 | 
					 | 
					fun watch_check () {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						// Only provide simple indication that contents might have changed
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						char buf[4096]; ssize_t len;
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						bool changed = false;
 | 
					 | 
					 | 
					 | 
						bool changed = false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						while ((len = read (g.inotify_fd, buf, sizeof buf)) > 0) {
 | 
					 | 
					 | 
					 | 
						// Only provide simple indication that contents might have changed,
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						// if only because kqueue can't do any better
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#ifdef __linux__
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						char buf[4096]; ssize_t len;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						while ((len = read (g.watch_fd, buf, sizeof buf)) > 0) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							const inotify_event *e;
 | 
					 | 
					 | 
					 | 
							const inotify_event *e;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							for (char *ptr = buf; ptr < buf + len; ptr += sizeof *e + e->len) {
 | 
					 | 
					 | 
					 | 
							for (char *ptr = buf; ptr < buf + len; ptr += sizeof *e + e->len) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								e = (const inotify_event *) buf;
 | 
					 | 
					 | 
					 | 
								e = (const inotify_event *) buf;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (e->wd == g.inotify_wd)
 | 
					 | 
					 | 
					 | 
								if (e->wd == g.watch_wd)
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
									changed = g.out_of_date = true;
 | 
					 | 
					 | 
					 | 
									changed = true;
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							}
 | 
					 | 
					 | 
					 | 
							}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (changed)
 | 
					 | 
					 | 
					 | 
					#else
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						struct kevent ev {};
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						struct timespec timeout {};
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						if (kevent (g.watch_fd, nullptr, 0, &ev, 1, &timeout) > 0)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							changed = ev.filter == EVFILT_VNODE && (ev.fflags & NOTE_WRITE);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#endif
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						if ((g.out_of_date = changed))
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							update ();
 | 
					 | 
					 | 
					 | 
							update ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1534,8 +1670,8 @@ fun load_ls_colors (vector<string> colors) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if (equal == string::npos)
 | 
					 | 
					 | 
					 | 
							if (equal == string::npos)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								continue;
 | 
					 | 
					 | 
					 | 
								continue;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							auto key = pair.substr (0, equal), value = pair.substr (equal + 1);
 | 
					 | 
					 | 
					 | 
							auto key = pair.substr (0, equal), value = pair.substr (equal + 1);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if (key != g_ls_colors[LS_SYMLINK]
 | 
					 | 
					 | 
					 | 
							if (key != g_ls_colors[LS_SYMLINK] ||
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							 || !(g.ls_symlink_as_target = value == "target"))
 | 
					 | 
					 | 
					 | 
								!(g.ls_symlink_as_target = value == "target"))
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								attrs[key] = decode_ansi_sgr (split (value, ";"));
 | 
					 | 
					 | 
					 | 
								attrs[key] = decode_ansi_sgr (split (value, ";"));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						for (int i = 0; i < LS_COUNT; i++) {
 | 
					 | 
					 | 
					 | 
						for (int i = 0; i < LS_COUNT; i++) {
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1792,10 +1928,17 @@ int main (int argc, char *argv[]) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						// So that the neither us nor our children stop on tcsetpgrp()
 | 
					 | 
					 | 
					 | 
						// So that the neither us nor our children stop on tcsetpgrp()
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						signal (SIGTTOU, SIG_IGN);
 | 
					 | 
					 | 
					 | 
						signal (SIGTTOU, SIG_IGN);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if ((g.inotify_fd = inotify_init1 (IN_NONBLOCK)) < 0) {
 | 
					 | 
					 | 
					 | 
					#ifdef __linux__
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						if ((g.watch_fd = inotify_init1 (IN_NONBLOCK)) < 0) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							cerr << "cannot initialize inotify" << endl;
 | 
					 | 
					 | 
					 | 
							cerr << "cannot initialize inotify" << endl;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							return 1;
 | 
					 | 
					 | 
					 | 
							return 1;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#else
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						if ((g.watch_fd = kqueue ()) < 0) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							cerr << "cannot initialize kqueue" << endl;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							return 1;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#endif
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						locale::global (locale (""));
 | 
					 | 
					 | 
					 | 
						locale::global (locale (""));
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						load_bindings ();
 | 
					 | 
					 | 
					 | 
						load_bindings ();
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1815,6 +1958,13 @@ int main (int argc, char *argv[]) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						pop_levels (g.cwd);
 | 
					 | 
					 | 
					 | 
						pop_levels (g.cwd);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						update ();
 | 
					 | 
					 | 
					 | 
						update ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						// Cunt, now I need to reïmplement all signal handling
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#if NCURSES_VERSION_PATCH < 20210821
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						// This gets applied along with the following halfdelay()
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						cur_term->Nttyb.c_cc[VSTOP] =
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							cur_term->Nttyb.c_cc[VSTART] = _POSIX_VDISABLE;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#endif
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						// Invoking keypad() earlier would make ncurses flush its output buffer,
 | 
					 | 
					 | 
					 | 
						// Invoking keypad() earlier would make ncurses flush its output buffer,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						// which would worsen start-up flickering
 | 
					 | 
					 | 
					 | 
						// which would worsen start-up flickering
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (halfdelay (1) == ERR || keypad (stdscr, TRUE) == ERR) {
 | 
					 | 
					 | 
					 | 
						if (halfdelay (1) == ERR || keypad (stdscr, TRUE) == ERR) {
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					@@ -1825,7 +1975,7 @@ 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 ();
 | 
					 | 
					 | 
					 | 
							watch_check ();
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if (g.sort_flash_ttl && !--g.sort_flash_ttl)
 | 
					 | 
					 | 
					 | 
							if (g.sort_flash_ttl && !--g.sort_flash_ttl)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								update ();
 | 
					 | 
					 | 
					 | 
								update ();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if (g.message_ttl && !--g.message_ttl) {
 | 
					 | 
					 | 
					 | 
							if (g.message_ttl && !--g.message_ttl) {
 | 
				
			
			
		
	
	
		
		
			
				
					
					| 
						
					 | 
					 | 
					 
 |