added permission error messsage, fix pane line, add root message if running as root

This commit is contained in:
2026-06-20 16:07:40 +08:00
parent 40e5d2815c
commit cd2a4dffb8
+57 -11
View File
@@ -42,6 +42,7 @@ enum {
CP_OVERLAY_TITLE, CP_OVERLAY_TITLE,
CP_BUTTON_YES, CP_BUTTON_YES,
CP_BUTTON_NO, CP_BUTTON_NO,
CP_ROOT_WARN,
}; };
#define ATTR_DIR (COLOR_PAIR(CP_DIR) | A_BOLD) #define ATTR_DIR (COLOR_PAIR(CP_DIR) | A_BOLD)
@@ -54,6 +55,7 @@ enum {
#define ATTR_MARKER COLOR_PAIR(CP_MARKER) #define ATTR_MARKER COLOR_PAIR(CP_MARKER)
#define ATTR_INFO COLOR_PAIR(CP_INFO) #define ATTR_INFO COLOR_PAIR(CP_INFO)
#define ATTR_OVERLAY_BORDER COLOR_PAIR(CP_OVERLAY_BORDER) #define ATTR_OVERLAY_BORDER COLOR_PAIR(CP_OVERLAY_BORDER)
#define ATTR_ROOT_WARN (COLOR_PAIR(CP_ROOT_WARN) | A_BOLD)
// ─── Entry data ───────────────────────────────────────────────────────────── // ─── Entry data ─────────────────────────────────────────────────────────────
enum class EntryType { Directory, File, Symlink }; enum class EntryType { Directory, File, Symlink };
@@ -154,6 +156,7 @@ private:
bool show_details_ = false; bool show_details_ = false;
bool show_preview_ = false; bool show_preview_ = false;
bool searching_ = false; bool searching_ = false;
bool is_root_ = false;
std::string filter_; std::string filter_;
std::string info_msg_; std::string info_msg_;
@@ -321,6 +324,7 @@ void FileManager::init_colors() {
init_pair(CP_OVERLAY_TITLE, COLOR_CYAN, -1); init_pair(CP_OVERLAY_TITLE, COLOR_CYAN, -1);
init_pair(CP_BUTTON_YES, COLOR_GREEN, -1); init_pair(CP_BUTTON_YES, COLOR_GREEN, -1);
init_pair(CP_BUTTON_NO, COLOR_RED, -1); init_pair(CP_BUTTON_NO, COLOR_RED, -1);
init_pair(CP_ROOT_WARN, COLOR_RED, -1);
} }
// ─── directory loading ────────────────────────────────────────────────────── // ─── directory loading ──────────────────────────────────────────────────────
@@ -554,13 +558,22 @@ void FileManager::draw_botbar() {
right = " press ? for help "; right = " press ? for help ";
} }
int total = static_cast<int>(left.size() + right.size()); std::string root_tag = is_root_ ? "[root] " : "";
int total = static_cast<int>(root_tag.size() + left.size() + right.size());
int pad = cols_ - total; int pad = cols_ - total;
if (pad < 0) pad = 0; if (pad < 0) pad = 0;
int x = 0;
if (is_root_) {
attron(ATTR_ROOT_WARN);
mvprintw(rows_ - 1, 0, "%s", root_tag.c_str());
attroff(ATTR_ROOT_WARN);
x = static_cast<int>(root_tag.size());
}
attron(ATTR_TOPBAR); attron(ATTR_TOPBAR);
mvprintw(rows_ - 1, 0, "%s", left.c_str()); mvprintw(rows_ - 1, x, "%s", left.c_str());
for (int i = 0; i < pad; ++i) mvaddch(rows_ - 1, static_cast<int>(left.size()) + i, ' '); for (int i = 0; i < pad; ++i) mvaddch(rows_ - 1, x + static_cast<int>(left.size()) + i, ' ');
attroff(ATTR_TOPBAR); attroff(ATTR_TOPBAR);
attron(ATTR_INFO); attron(ATTR_INFO);
@@ -711,11 +724,10 @@ void FileManager::draw_preview() {
if (!e) return; if (!e) return;
// Draw vertical divider // Draw vertical divider
for (int r = 1; r < rows_ - 1; ++r) {
attron(ATTR_DIVIDER); attron(ATTR_DIVIDER);
mvaddch(r, list_cols_, '|'); for (int r = 1; r < rows_ - 1; ++r)
mvaddch(r, list_cols_, ACS_VLINE);
attroff(ATTR_DIVIDER); attroff(ATTR_DIVIDER);
}
// Clear entire preview area of previous content (stale lines from last preview) // Clear entire preview area of previous content (stale lines from last preview)
for (int r = 1; r < rows_ - 1; ++r) { for (int r = 1; r < rows_ - 1; ++r) {
@@ -1598,6 +1610,12 @@ void FileManager::do_help() {
void FileManager::do_rename() { void FileManager::do_rename() {
const Entry *e = get_sel(); const Entry *e = get_sel();
if (!e) return; if (!e) return;
if (access(cwd_.c_str(), W_OK) != 0) {
flash_msg("permission denied: " + cwd_);
return;
}
// Strip trailing / or @ // Strip trailing / or @
std::string name = e->name; std::string name = e->name;
if (!name.empty() && (name.back() == '/' || name.back() == '@')) if (!name.empty() && (name.back() == '/' || name.back() == '@'))
@@ -1612,11 +1630,16 @@ void FileManager::do_rename() {
if (std::rename(src.c_str(), dst.c_str()) == 0) { if (std::rename(src.c_str(), dst.c_str()) == 0) {
load_entries(); load_entries();
} else { } else {
flash_msg("rename failed"); flash_msg("rename failed: " + std::string(std::strerror(errno)));
} }
} }
void FileManager::do_mkdir() { void FileManager::do_mkdir() {
if (access(cwd_.c_str(), W_OK) != 0) {
flash_msg("permission denied: " + cwd_);
return;
}
std::string name; std::string name;
if (!read_line(name, " Directory name: ")) { need_full_redraw_ = true; return; } if (!read_line(name, " Directory name: ")) { need_full_redraw_ = true; return; }
if (name.empty()) { flash_msg("cancelled"); return; } if (name.empty()) { flash_msg("cancelled"); return; }
@@ -1625,11 +1648,16 @@ void FileManager::do_mkdir() {
if (fs::create_directory(path)) { if (fs::create_directory(path)) {
load_entries(); load_entries();
} else { } else {
flash_msg("mkdir failed"); flash_msg("mkdir failed: " + std::string(std::strerror(errno)));
} }
} }
void FileManager::do_newfile() { void FileManager::do_newfile() {
if (access(cwd_.c_str(), W_OK) != 0) {
flash_msg("permission denied: " + cwd_);
return;
}
std::string name; std::string name;
if (!read_line(name, " File name: ")) { need_full_redraw_ = true; return; } if (!read_line(name, " File name: ")) { need_full_redraw_ = true; return; }
if (name.empty()) { flash_msg("cancelled"); return; } if (name.empty()) { flash_msg("cancelled"); return; }
@@ -1640,11 +1668,16 @@ void FileManager::do_newfile() {
f.close(); f.close();
load_entries(); load_entries();
} else { } else {
flash_msg("cannot create file"); flash_msg("cannot create file: " + std::string(std::strerror(errno)));
} }
} }
void FileManager::do_delete() { void FileManager::do_delete() {
if (access(cwd_.c_str(), W_OK) != 0) {
flash_msg("permission denied: " + cwd_);
return;
}
// Gather items to delete // Gather items to delete
std::vector<std::string> targets; std::vector<std::string> targets;
if (!selected_.empty()) { if (!selected_.empty()) {
@@ -1709,6 +1742,12 @@ void FileManager::do_delete() {
void FileManager::do_trash() { void FileManager::do_trash() {
const Entry *e = get_sel(); const Entry *e = get_sel();
if (!e) return; if (!e) return;
if (access(cwd_.c_str(), W_OK) != 0) {
flash_msg("permission denied: " + cwd_);
return;
}
std::string name = e->name; std::string name = e->name;
if (!name.empty() && name.back() == '/') name.pop_back(); if (!name.empty() && name.back() == '/') name.pop_back();
if (!name.empty() && name.back() == '@') name.pop_back(); if (!name.empty() && name.back() == '@') name.pop_back();
@@ -1743,7 +1782,7 @@ void FileManager::do_trash() {
sel_ = std::max(0, static_cast<int>(entries_.size()) - 2); sel_ = std::max(0, static_cast<int>(entries_.size()) - 2);
load_entries(); load_entries();
} else { } else {
flash_msg("trash failed"); flash_msg("trash failed: " + std::string(std::strerror(errno)));
} }
} }
@@ -1805,7 +1844,7 @@ void FileManager::do_chmod_x(bool set) {
flash_msg(set ? "chmod +x: " + e->name : "chmod -x: " + e->name); flash_msg(set ? "chmod +x: " + e->name : "chmod -x: " + e->name);
load_entries(); load_entries();
} else { } else {
flash_msg("chmod failed"); flash_msg("chmod failed: " + std::string(std::strerror(errno)));
} }
} }
@@ -2021,6 +2060,11 @@ void FileManager::do_paste() {
return; return;
} }
if (access(cwd_.c_str(), W_OK) != 0) {
flash_msg("permission denied: " + cwd_);
return;
}
for (const auto &src : clipboard_paths_) { for (const auto &src : clipboard_paths_) {
std::string name = fs::path(src).filename().string(); std::string name = fs::path(src).filename().string();
std::string dst = join_path(cwd_, name); std::string dst = join_path(cwd_, name);
@@ -2291,6 +2335,8 @@ void FileManager::run() {
if (can_color()) init_colors(); if (can_color()) init_colors();
load_entries(); load_entries();
is_root_ = (geteuid() == 0);
while (true) { while (true) {
draw(); draw();
int key = getch(); int key = getch();