Compare commits
11 Commits
4d6999c415
...
v1.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
272ee62ad8
|
|||
|
a85426541a
|
|||
|
c9b003735d
|
|||
|
52a28f01c8
|
|||
|
3607757554
|
|||
|
6eb216a40a
|
|||
|
9ce6f47716
|
|||
|
c9662f1a7b
|
|||
|
9ddeb03652
|
|||
|
acb187c6b1
|
|||
|
9427df62e7
|
@@ -1,25 +1,24 @@
|
|||||||
# target_compile_features has been introduced in that version
|
# target_compile_features has been introduced in that version
|
||||||
cmake_minimum_required (VERSION 3.1)
|
cmake_minimum_required (VERSION 3.1...3.27)
|
||||||
project (sdn VERSION 0.1 LANGUAGES CXX)
|
project (sdn VERSION 1.0 LANGUAGES CXX)
|
||||||
|
|
||||||
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
|
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
|
||||||
set (CMAKE_CXX_FLAGS
|
set (CMAKE_CXX_FLAGS
|
||||||
"${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-misleading-indentation -pedantic")
|
"${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-misleading-indentation -pedantic")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# Since we use a language with slow compilers, let's at least use a fast linker
|
|
||||||
execute_process (COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=gold -Wl,--version
|
|
||||||
ERROR_QUIET OUTPUT_VARIABLE ld_version)
|
|
||||||
if ("${ld_version}" MATCHES "GNU gold")
|
|
||||||
set (CMAKE_EXE_LINKER_FLAGS "-fuse-ld=gold ${CMAKE_EXE_LINKER_FLAGS}")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
find_package (PkgConfig REQUIRED)
|
find_package (PkgConfig REQUIRED)
|
||||||
pkg_check_modules (NCURSESW QUIET ncursesw)
|
pkg_check_modules (ACL libacl)
|
||||||
|
pkg_check_modules (NCURSESW ncursesw)
|
||||||
|
if (NOT NCURSESW_FOUND)
|
||||||
|
find_library (NCURSESW_LIBRARIES NAMES ncursesw)
|
||||||
|
find_path (NCURSESW_INCLUDE_DIRS ncurses.h PATH_SUFFIXES ncurses)
|
||||||
|
endif ()
|
||||||
|
|
||||||
add_executable (${PROJECT_NAME} ${PROJECT_NAME}.cpp)
|
add_executable (${PROJECT_NAME} ${PROJECT_NAME}.cpp)
|
||||||
target_include_directories (${PROJECT_NAME} PUBLIC ${NCURSESW_INCLUDE_DIRS})
|
target_include_directories (${PROJECT_NAME} PUBLIC ${NCURSESW_INCLUDE_DIRS})
|
||||||
target_link_libraries (${PROJECT_NAME} PUBLIC ${NCURSESW_LIBRARIES} acl)
|
target_link_libraries (${PROJECT_NAME}
|
||||||
|
PUBLIC ${NCURSESW_LIBRARIES} ${ACL_LIBRARIES})
|
||||||
target_compile_features (${PROJECT_NAME} PUBLIC cxx_std_14)
|
target_compile_features (${PROJECT_NAME} PUBLIC cxx_std_14)
|
||||||
target_compile_definitions (${PROJECT_NAME} PUBLIC
|
target_compile_definitions (${PROJECT_NAME} PUBLIC
|
||||||
-DPROJECT_NAME=\"${PROJECT_NAME}\" -DPROJECT_VERSION=\"${PROJECT_VERSION}\")
|
-DPROJECT_NAME=\"${PROJECT_NAME}\" -DPROJECT_VERSION=\"${PROJECT_VERSION}\")
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2017 - 2022, 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.
|
||||||
|
|||||||
12
README.adoc
12
README.adoc
@@ -11,20 +11,22 @@ commands. It enables you to:
|
|||||||
can be simply forwarded if it is to be edited. What's more, it will always
|
can be simply forwarded if it is to be edited. What's more, it will always
|
||||||
be obvious whether the navigator is running.
|
be obvious whether the navigator is running.
|
||||||
|
|
||||||
The only supported platform is Linux. I wanted to try a different, simpler
|
'sdn' runs on Linux and all BSD derivatives. I wanted to try a different,
|
||||||
approach here, and the end result is very friendly to tinkering.
|
simpler approach here, and the end result is very friendly to tinkering.
|
||||||
|
|
||||||
image::sdn.png[align="center"]
|
image::sdn.png[align="center"]
|
||||||
|
|
||||||
Packages
|
Packages
|
||||||
--------
|
--------
|
||||||
Regular releases are sporadic. git master should be stable enough. You can get
|
Regular releases are sporadic. git master should be stable enough.
|
||||||
a package with the latest development version from Archlinux's AUR.
|
You can get a package with the latest development version using Arch Linux's
|
||||||
|
https://aur.archlinux.org/packages/sdn-git[AUR],
|
||||||
|
or as a https://git.janouch.name/p/nixexprs[Nix derivation].
|
||||||
|
|
||||||
Building
|
Building
|
||||||
--------
|
--------
|
||||||
Build dependencies: CMake and/or make, a C++14 compiler, pkg-config +
|
Build dependencies: CMake and/or make, a C++14 compiler, pkg-config +
|
||||||
Runtime dependencies: ncursesw, libacl
|
Runtime dependencies: ncursesw, libacl (on Linux)
|
||||||
|
|
||||||
// Working around libasciidoc's missing support for escaping it like \++
|
// Working around libasciidoc's missing support for escaping it like \++
|
||||||
Unfortunately most LLVM libc{plus}{plus} versions have a bug that crashes 'sdn'
|
Unfortunately most LLVM libc{plus}{plus} versions have a bug that crashes 'sdn'
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ done
|
|||||||
|
|
||||||
# Figure out the shell to integrate with
|
# Figure out the shell to integrate with
|
||||||
login=$(basename "$SHELL")
|
login=$(basename "$SHELL")
|
||||||
actual=$(ps -p $$ -o ppid= | xargs ps -o comm= -p)
|
actual=$(ps -p $$ -o ppid= | xargs ps -o comm= -p | sed 's/^-//')
|
||||||
if [ -z "$shell" ]
|
if [ -z "$shell" ]
|
||||||
then
|
then
|
||||||
if [ "$login" != "$actual" ]
|
if [ "$login" != "$actual" ]
|
||||||
|
|||||||
145
sdn.cpp
145
sdn.cpp
@@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// sdn: simple directory navigator
|
// sdn: simple directory navigator
|
||||||
//
|
//
|
||||||
// Copyright (c) 2017 - 2022, 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.
|
||||||
@@ -39,27 +39,32 @@
|
|||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/acl.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <acl/libacl.h>
|
#ifdef __linux__
|
||||||
#include <ncurses.h>
|
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
#include <sys/types.h>
|
// ACL information is not important enough to be ported
|
||||||
#include <sys/wait.h>
|
#include <acl/libacl.h>
|
||||||
|
#include <sys/acl.h>
|
||||||
#include <sys/xattr.h>
|
#include <sys/xattr.h>
|
||||||
|
#else
|
||||||
|
#include <sys/event.h>
|
||||||
|
#endif
|
||||||
|
#include <ncurses.h>
|
||||||
|
|
||||||
// To implement cbreak() with disabled ^S that gets reënabled on endwin()
|
// To implement cbreak() with disabled ^S that gets reënabled on endwin()
|
||||||
#define NCURSES_INTERNALS
|
#define NCURSES_INTERNALS
|
||||||
#include <term.h>
|
#include <term.h>
|
||||||
#undef CTRL // term.h -> termios.h -> sys/ttydefaults.h, too simplistic
|
#undef CTRL // term.h -> termios.h -> sys/ttydefaults.h, too simplistic
|
||||||
|
|
||||||
// Unicode is complex enough already and we might make assumptions
|
|
||||||
#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
|
||||||
@@ -303,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};
|
||||||
@@ -538,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
|
||||||
@@ -597,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))
|
||||||
@@ -640,6 +661,25 @@ 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;
|
||||||
@@ -673,11 +713,13 @@ fun make_entry (const struct dirent *f) -> entry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto mode = decode_mode (info.st_mode);
|
auto mode = decode_mode (info.st_mode);
|
||||||
|
#ifdef __linux__
|
||||||
// We're using a laughably small subset of libacl: this translates to
|
// We're using a laughably small subset of libacl: this translates to
|
||||||
// two lgetxattr() calls, the results of which are compared with
|
// two lgetxattr() calls, the results of which are compared with
|
||||||
// specific architecture-dependent constants. Linux-only.
|
// 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);
|
||||||
@@ -690,11 +732,12 @@ fun make_entry (const struct dirent *f) -> entry {
|
|||||||
? apply_attrs (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);
|
||||||
|
|
||||||
wchar_t buf[32] = L"";
|
wchar_t buf[32] = L"";
|
||||||
@@ -706,8 +749,8 @@ fun make_entry (const struct dirent *f) -> entry {
|
|||||||
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 (L" -> ", 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;
|
||||||
}
|
}
|
||||||
@@ -777,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);
|
||||||
@@ -901,23 +944,38 @@ readfail:
|
|||||||
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 run_program (initializer_list<const char *> list, const string &filename) {
|
fun run_program (initializer_list<const char *> list, const string &filename) {
|
||||||
|
auto args = (!filename.empty() && filename.front() == '-' ? " -- " : " ")
|
||||||
|
+ shell_escape (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;
|
||||||
}
|
}
|
||||||
@@ -933,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
|
||||||
@@ -1528,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 ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1862,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 ();
|
||||||
@@ -1902,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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user