ls: Add colors to output
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
c524dc8d58
commit
39ba4c9087
66
apps/ls.cpp
66
apps/ls.cpp
@ -8,6 +8,7 @@
|
||||
#include <os/FileSystem.h>
|
||||
#include <os/Mode.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void find_user_and_group(struct stat& st, StringView& owner, StringView& group)
|
||||
{
|
||||
@ -47,18 +48,46 @@ int sort_reverse(const os::Directory::Entry* a, const os::Directory::Entry* b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Result<String> entry_join(const Vector<os::Directory::Entry>& vec, StringView delim)
|
||||
#define RESET_COLORS "\x1b[m"
|
||||
#define SYMLINK_COLOR "\x1b[36m"
|
||||
#define FILE_COLOR "\x1b[1;32m"
|
||||
#define DIR_COLOR "\x1b[1;34m"
|
||||
#define SOCKET_COLOR "\x1b[33m"
|
||||
#define SPECIAL_COLOR "\x1b[35m"
|
||||
#define STICKY_COLOR "\x1b[30;1;42m"
|
||||
#define SETUID_COLOR "\x1b[30;1;41m"
|
||||
#define EXEC_COLOR "\x1b[1;31m"
|
||||
|
||||
static const char* file_type_color(const os::Directory::Entry& entry)
|
||||
{
|
||||
if (entry.mode & S_ISVTX) return STICKY_COLOR;
|
||||
if (entry.mode & S_ISUID || entry.mode & S_ISGID) return SETUID_COLOR;
|
||||
|
||||
switch (entry.mode & S_IFMT)
|
||||
{
|
||||
case S_IFREG: return entry.mode & S_IXUSR ? EXEC_COLOR : FILE_COLOR;
|
||||
case S_IFDIR: return DIR_COLOR;
|
||||
case S_IFLNK: return SYMLINK_COLOR;
|
||||
case S_IFSOCK: return SOCKET_COLOR;
|
||||
default: return SPECIAL_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
static Result<String> entry_join(const Vector<os::Directory::Entry>& vec, StringView delim, bool colors)
|
||||
{
|
||||
if (vec.size() == 0) return String {};
|
||||
if (vec.size() == 1) return vec[0].name.clone();
|
||||
|
||||
StringBuilder sb;
|
||||
if (colors) TRY(sb.add(StringView { file_type_color(vec[0]) }));
|
||||
TRY(sb.add(vec[0].name));
|
||||
if (colors) TRY(sb.add(StringView { RESET_COLORS }));
|
||||
|
||||
for (usize i = 1; i < vec.size(); i++)
|
||||
{
|
||||
TRY(sb.add(delim));
|
||||
if (colors) TRY(sb.add(StringView { file_type_color(vec[i]) }));
|
||||
TRY(sb.add(vec[i].name));
|
||||
if (colors) TRY(sb.add(StringView { RESET_COLORS }));
|
||||
}
|
||||
|
||||
return sb.string();
|
||||
@ -75,6 +104,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
bool follow_symlink_args { false };
|
||||
bool one_per_line { false };
|
||||
bool list_directories { false };
|
||||
bool no_colors { false };
|
||||
|
||||
StringView sort_type { "name" };
|
||||
|
||||
@ -98,6 +128,8 @@ Result<int> luna_main(int argc, char** argv)
|
||||
parser.add_switch_argument(list_directories, 'd', "directory"_sv, "list directories instead of their contents"_sv);
|
||||
parser.add_value_argument(sort_type, ' ', "sort"_sv, "sort by name, size or time"_sv);
|
||||
parser.add_switch_argument(reverse_sort, 'r', "reverse"_sv, "reverse order while sorting"_sv);
|
||||
parser.add_switch_argument(no_colors, ' ', "no-colors"_sv,
|
||||
"disable coloring of output (defaults to true when not in a TTY)"_sv);
|
||||
parser.parse(argc, argv);
|
||||
|
||||
Vector<os::Directory::Entry> files;
|
||||
@ -154,11 +186,13 @@ Result<int> luna_main(int argc, char** argv)
|
||||
|
||||
if (!long_list)
|
||||
{
|
||||
auto list = TRY(entry_join(files, one_per_line ? "\n"_sv : " "_sv));
|
||||
auto list = TRY(entry_join(files, one_per_line ? "\n"_sv : " "_sv, !no_colors && isatty(STDIN_FILENO)));
|
||||
if (!list.is_empty()) os::println("%s", list.chars());
|
||||
}
|
||||
else
|
||||
{
|
||||
bool colors = !no_colors && isatty(STDIN_FILENO);
|
||||
|
||||
for (const auto& file : files)
|
||||
{
|
||||
struct stat st;
|
||||
@ -176,14 +210,32 @@ Result<int> luna_main(int argc, char** argv)
|
||||
|
||||
if (!human_readable && !si)
|
||||
{
|
||||
os::println("%s %u %4s %4s %10lu %s%s%s", formatted_mode, st.st_nlink, owner.chars(), group.chars(),
|
||||
st.st_size, file.name.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
||||
if (colors)
|
||||
{
|
||||
os::println("%s %u %4s %4s %10lu %s%s" RESET_COLORS "%s" SYMLINK_COLOR "%s" RESET_COLORS,
|
||||
formatted_mode, st.st_nlink, owner.chars(), group.chars(), st.st_size,
|
||||
file_type_color(file), file.name.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
||||
}
|
||||
else
|
||||
{
|
||||
os::println("%s %u %4s %4s %10lu %s%s%s", formatted_mode, st.st_nlink, owner.chars(), group.chars(),
|
||||
st.st_size, file.name.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto size = TRY(to_dynamic_unit(st.st_size, 10, false, si ? Unit::SI : Unit::Binary, false));
|
||||
os::println("%s %u %4s %4s %6s %s%s%s", formatted_mode, st.st_nlink, owner.chars(), group.chars(),
|
||||
size.chars(), file.name.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
||||
if (colors)
|
||||
{
|
||||
os::println("%s %u %4s %4s %6s %s%s" RESET_COLORS "%s" SYMLINK_COLOR "%s" RESET_COLORS,
|
||||
formatted_mode, st.st_nlink, owner.chars(), group.chars(), size.chars(),
|
||||
file_type_color(file), file.name.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
||||
}
|
||||
else
|
||||
{
|
||||
os::println("%s %u %4s %4s %6s %s%s%s", formatted_mode, st.st_nlink, owner.chars(), group.chars(),
|
||||
size.chars(), file.name.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user