Revise and optimize icons handling

This pretty much reworks the entire icon system. Some notable changes:

* The extensions are put into a statically generated hash-table instead
  of a sorted array. We use Robin-Hood insertion to reduce the max probe
  length. Currently we need to probe only 2 slots for `O_EMOJI` and only
  3 for `O_NERD`/`O_ICONS`.
* I've opted not to use a perfect-hash since the perfect hashes
  generated by [`gperf`](https://www.gnu.org/software/gperf) used some
  huge lookup table. The hash function also wasn't as minimal as I'd
  like.
* Colors are now using X-Macros. This should speed up startup since we
  don't have to search `icons_ext` linearly to find unique colors.
* The hash-table generator outputs a more space optimized `struct
  icon_pair` using a char array instead of char pointer. This brings
  down the binary size from `145KiB` when using `O_NERD` down to
  `137KiB`.
* Some unnecessary duplication and indirection has been reduced by using
  the `ICON_STR()` macro.
This commit is contained in:
NRK 2022-07-20 15:57:05 +06:00
parent d95755cce1
commit 3b09fd1c75
7 changed files with 565 additions and 1096 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
*.o
*.dSYM
nnn
src/icons-generated.h
src/icons-hash-gen

View File

@ -95,7 +95,7 @@ ifeq ($(strip $(O_CTX8)),1)
endif
ifeq ($(strip $(O_ICONS)),1)
CPPFLAGS += -DICONS
CPPFLAGS += -DICONS_IN_TERM
endif
ifeq ($(strip $(O_NERD)),1)
@ -187,18 +187,18 @@ endif
ifeq ($(strip $(O_DEBUG)),1)
HEADERS += src/dbg.h
endif
ifeq ($(strip $(O_EMOJI)),1)
HEADERS += src/icons.h src/icons-emoji.h
endif
ifeq ($(strip $(O_NERD)),1)
HEADERS += src/icons.h src/icons-nerdfont.h
endif
ifeq ($(strip $(O_ICONS)),1)
HEADERS += src/icons.h src/icons-in-terminal.h
endif
ifeq ($(strip $(O_QSORT)),1)
HEADERS += src/qsort.h
endif
ifeq ($(strip $(O_EMOJI)),1)
HEADERS += src/icons.h src/icons-generated.h
endif
ifeq ($(strip $(O_NERD)),1)
HEADERS += src/icons.h src/icons-generated.h
endif
ifeq ($(strip $(O_ICONS)),1)
HEADERS += src/icons.h src/icons-generated.h src/icons-in-terminal.h
endif
all: $(BIN)
@ -207,6 +207,11 @@ $(BIN): $(SRC) $(HEADERS) Makefile
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(GETTIME_C) $< $(LDLIBS)
@$(MAKE) --silent postpatch
src/icons-generated.h: src/icons-hash-gen
@./$< > $@
src/icons-hash-gen: src/icons-hash.c src/nnn.c src/icons.h src/nnn.h
$(CC) $(CPPFLAGS) -DICONS_GENERATE -o $@ src/icons-hash.c
# targets for backwards compatibility
debug: $(BIN)
norl: $(BIN)
@ -313,7 +318,7 @@ upload-local: sign static musl
--upload-file $(BIN)-musl-static-$(VERSION).x86_64.tar.gz
clean:
$(RM) -f $(BIN) nnn-$(VERSION).tar.gz *.sig $(BIN)-static $(BIN)-static-$(VERSION).x86_64.tar.gz $(BIN)-icons-static $(BIN)-icons-static-$(VERSION).x86_64.tar.gz $(BIN)-nerd-static $(BIN)-nerd-static-$(VERSION).x86_64.tar.gz $(BIN)-emoji-static $(BIN)-emoji-static-$(VERSION).x86_64.tar.gz $(BIN)-musl-static $(BIN)-musl-static-$(VERSION).x86_64.tar.gz
$(RM) -f $(BIN) nnn-$(VERSION).tar.gz *.sig $(BIN)-static $(BIN)-static-$(VERSION).x86_64.tar.gz $(BIN)-icons-static $(BIN)-icons-static-$(VERSION).x86_64.tar.gz $(BIN)-nerd-static $(BIN)-nerd-static-$(VERSION).x86_64.tar.gz $(BIN)-emoji-static $(BIN)-emoji-static-$(VERSION).x86_64.tar.gz $(BIN)-musl-static $(BIN)-musl-static-$(VERSION).x86_64.tar.gz src/icons-hash-gen src/icons-generated.h
checkpatches:
./patches/check-patches.sh

View File

@ -1,68 +0,0 @@
#ifndef ICONS_EMOJI
#define ICONS_EMOJI
// You can find a list of emoji here:
// https://unicode.org/Public/emoji/5.0/emoji-test.txt
// Note: As some emoji are stored as two characters, all of these strings must
// be of width 2. Therefore, right pad single-width emoji with a space.
#define MD_ARROW_UPWARD "⬆"
#define MD_ARROW_FORWARD "➡"
#define MD_ARROW_DOWNWARD "⬇"
#define EMOJI_ARCHIVE "📦"
#define EMOJI_AUDIO "🎧"
#define EMOJI_BINARY "📓"
#define EMOJI_BRIEFCASE "💼"
#define EMOJI_C "🇨 "
#define EMOJI_CHANGELOG "🔺"
#define EMOJI_CONF "🔧"
#define EMOJI_CPP EMOJI_C
#define EMOJI_DATABASE "🗃️ "
#define EMOJI_DESKTOP "🖥️ "
#define EMOJI_DIFF "📋"
#define EMOJI_DISK "💿"
#define EMOJI_DOWNLOAD "📥"
#define EMOJI_ENCRYPTED "🔒"
#define EMOJI_EXEC "⚙️ "
#define EMOJI_FILE "📃"
#define EMOJI_FOLDER "📂"
#define EMOJI_GIT "🌱"
#define EMOJI_IMAGE "🎨"
#define EMOJI_INFO " "
#define EMOJI_JAVA "☕"
#define EMOJI_JAVASCRIPT EMOJI_SCRIPT
#define EMOJI_LICENSE "⚖️ "
#define EMOJI_LINUX "🐧"
#define EMOJI_LOCK "🔒"
#define EMOJI_LUA "🌘"
#define EMOJI_MAKE "🛠 "
#define EMOJI_MANUAL "❓"
#define EMOJI_MOVIE "🎞 "
#define EMOJI_MUSIC EMOJI_AUDIO
#define EMOJI_NOTE "📝"
#define EMOJI_PATCH "🩹"
#define EMOJI_PDF "📕"
#define EMOJI_PHOTO "📸"
#define EMOJI_PICTURE EMOJI_IMAGE
#define EMOJI_PRESENTATION "📊"
#define EMOJI_PUBLIC "👀"
#define EMOJI_PYTHON "🐍"
#define EMOJI_RSS "📡"
#define EMOJI_RUBY "💎"
#define EMOJI_SCRIPT "📜"
#define EMOJI_STATS "📊"
#define EMOJI_STYLESHEET "🦋"
#define EMOJI_SUBTITLES "💬"
#define EMOJI_TABLE "📗"
#define EMOJI_TEMPLATE "📎"
#define EMOJI_TEXT "🗒 "
#define EMOJI_UNI "🏛️ "
#define EMOJI_VECTOR "🗺️ "
#define EMOJI_WEB "🌐"
#define EMOJI_WINDOWS "🪟"
#define EMOJI_WORD "📘"
#define EMOJI_WORK EMOJI_UNI
#endif // ICONS_EMOJI

201
src/icons-hash.c Normal file
View File

@ -0,0 +1,201 @@
/*
* simple program which outputs a hash-table of `icons_ext` with low collusion.
* the hash function is case-insensitive, it also doesn't hash beyond the
* length of the longest extension.
*/
#include <stddef.h>
#include <stdint.h>
#define GOLDEN_RATIO_16 40503u /* golden ratio for 16bits: (2^16) / 1.61803 */
#define ICONS_TABLE_SIZE 8 /* size in bits. 8 = 256 */
#ifdef ICONS_GENERATE
#define ICONS_PROBE_MAX_ALLOWED 6
#define ICONS_MATCH_MAX ((size_t)-1)
#ifdef NDEBUG
#error "NDEBUG"
#endif
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "icons.h"
#define ASSERT(X) assert(X)
#define ARRLEN(X) (sizeof(X) / sizeof((X)[0]))
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define HGEN_ITERARATION (1ul << 14)
#if 0 /* enable for debugging */
#define log(...) fprintf(stderr, "[INFO]: " __VA_ARGS__)
#else
#define log(...) ((void)0)
#endif
static uint16_t icon_ext_hash(const char *s);
/* change ICONS_TABLE_SIZE to increase the size of the table */
static struct icon_pair table[1u << ICONS_TABLE_SIZE];
static uint16_t seen[ARRLEN(table)];
static uint16_t hash_start = 7; /* arbitrarily picked. change if needed. but ensure it's above 1 */
static uint16_t hash_mul = 251; /* same as above ^ */
/*
* use robin-hood insertion to reduce the max probe length
*/
static void
rh_insert(const struct icon_pair item, uint32_t idx, uint32_t n)
{
assert(n != 0);
for (uint32_t tries = 0; tries < ARRLEN(table); ++tries, ++n) {
if (seen[idx] < n) {
struct icon_pair tmp_item = table[idx];
uint32_t tmp_n = seen[idx];
table[idx] = item;
seen[idx] = n;
if (tmp_n != 0) /* the slot we inserted to wasn't empty */
rh_insert(tmp_item, idx, tmp_n);
return;
}
idx = (idx + 1) % ARRLEN(table);
}
assert(0); /* unreachable */
}
static unsigned int
table_populate(void)
{
memset(seen, 0x0, sizeof seen);
memset(table, 0x0, sizeof table);
for (size_t i = 0; i < ARRLEN(icons_ext); ++i) {
if (icons_ext[i].icon[0] == '\0') continue;
uint32_t h = icon_ext_hash(icons_ext[i].match);
rh_insert(icons_ext[i], h, 1);
}
unsigned int max_try = 0;
for (size_t i = 0; i < ARRLEN(seen); ++i) {
if (seen[i] > max_try) max_try = seen[i];
}
return max_try;
}
int
main(void)
{
assert(ARRLEN(icons_ext) <= ARRLEN(table));
assert(ICONS_TABLE_SIZE < 16); /* the hash function only supports upto 16 bits */
assert(1u << ICONS_TABLE_SIZE == ARRLEN(table));
assert((GOLDEN_RATIO_16 & 1) == 1); /* must be odd */
assert(hash_start > 1); assert(hash_mul > 1);
/* ensure power of 2 hashtable size which allows compiler to optimize
* away mod (`%`) operations
*/
assert((ARRLEN(table) & (ARRLEN(table) - 1)) == 0);
unsigned int max_probe = (unsigned)-1;
uint16_t best_hash_start, best_hash_mul;
for (size_t i = 0; i < HGEN_ITERARATION; ++i) {
unsigned z = table_populate();
if (z < max_probe) {
max_probe = z;
best_hash_start = hash_start;
best_hash_mul = hash_mul;
}
hash_start *= GOLDEN_RATIO_16;
hash_mul *= GOLDEN_RATIO_16;
}
assert(max_probe < ICONS_PROBE_MAX_ALLOWED);
hash_start = best_hash_start;
hash_mul = best_hash_mul;
{
unsigned tmp = table_populate();
assert(tmp == max_probe);
}
/* sanity check */
for (size_t i = 0; i < ARRLEN(icons_ext); ++i) {
if (icons_ext[i].icon[0] == 0) continue;
uint16_t found = 0, h = icon_ext_hash(icons_ext[i].match);
for (uint16_t k = 0; k < max_probe; ++k) {
uint16_t z = (h + k) % ARRLEN(table);
if (table[z].match && strcmp(icons_ext[i].match, table[z].match) == 0) {
found = 1;
}
}
assert(found);
}
log("hash_start: %u\n", (unsigned)hash_start);
log("hash_mul : %u\n", (unsigned)hash_mul);
log("max_probe : %u\n", max_probe);
printf("#ifndef INCLUDE_ICONS_GENERATED\n");
printf("#define INCLUDE_ICONS_GENERATED\n\n");
printf("/*\n * NOTE: This file is automatically generated.\n");
printf(" * DO NOT EDIT THIS FILE DIRECTLY.\n");
printf(" * Use `icons.h` to customize icons\n */\n\n");
printf("#define hash_start %uu\n", hash_start);
printf("#define hash_mul %uu\n\n", hash_mul);
size_t match_max = 0, icon_max = 0;
for (size_t i = 0; i < ARRLEN(icons_name); ++i) {
match_max = MAX(match_max, strlen(icons_name[i].match) + 1);
icon_max = MAX(icon_max, strlen(icons_name[i].icon) + 1);
}
for (size_t i = 0; i < ARRLEN(icons_ext); ++i) {
match_max = MAX(match_max, strlen(icons_ext[i].match) + 1);
icon_max = MAX(icon_max, strlen(icons_ext[i].icon) + 1);
}
icon_max = MAX(icon_max, strlen(dir_icon.icon) + 1);
icon_max = MAX(icon_max, strlen(exec_icon.icon) + 1);
icon_max = MAX(icon_max, strlen(file_icon.icon) + 1);
printf("#define ICONS_PROBE_MAX %u\n", max_probe);
printf("#define ICONS_MATCH_MAX %zuu\n\n", match_max);
printf("struct icon_pair { const char match[%zu]; const char icon[%zu]; unsigned char color; };\n\n",
match_max, icon_max);
printf("static const struct icon_pair icons_ext[%zu] = {\n", ARRLEN(table));
for (size_t i = 0; i < ARRLEN(table); ++i) {
if (table[i].icon == NULL || table[i].icon[0] == '\0') /* skip empty entries */
continue;
printf("\t[%u] = {\"%s\", \"%s\", %d },\n",
(unsigned)i, table[i].match, table[i].icon,
(unsigned)table[i].color);
}
printf("};\n\n");
printf("#endif /* INCLUDE_ICONS_GENERATED */\n");
}
#else
#define ASSERT(X) ((void)0)
#endif /* ICONS_GENERATE */
#ifndef TOUPPER
#define TOUPPER(ch) (((ch) >= 'a' && (ch) <= 'z') ? ((ch) - 'a' + 'A') : (ch))
#endif
static uint16_t
icon_ext_hash(const char *str)
{
const unsigned int z = 16 - ICONS_TABLE_SIZE; /* 16 == size of `hash` in bits */
uint16_t hash = hash_start;
for (size_t i = 0; i < ICONS_MATCH_MAX && str[i] != '\0'; ++i) {
hash ^= TOUPPER((unsigned char)str[i]) + (i << 3);
hash *= hash_mul;
}
hash = (hash >> z) ^ hash;
hash *= GOLDEN_RATIO_16;
hash >>= z;
ASSERT(hash < ARRLEN(table));
return hash;
}

View File

@ -1,276 +0,0 @@
#ifndef ICONS_NERDFONT
#define ICONS_NERDFONT
// You can find hex codes for nerd fonts here
// https://www.nerdfonts.com/cheat-sheet
// Arrows
#define MD_ARROW_UPWARD "\uf55c"
#define MD_ARROW_FORWARD "\uf553"
#define MD_ARROW_DOWNWARD "\uf544"
// Generics
#define ICON_DIRECTORY "\ue5ff"
#define ICON_FILE "\uf713"
#define ICON_EXEC "\uf144"
#define ICON_MANUAL "\uf5bd"
// Top level and common icons
#define ICON_ARCHIVE "\uf53b"
#define ICON_BRIEFCASE "\uf5d5"
#define ICON_C "\ue61e"
#define ICON_CHANGELOG "\uf7d9"
#define ICON_CHESS "\uf639"
#define ICON_CLOJURE "\ue76a"
#define ICON_CONFIGURE "\uf423"
#define ICON_CPLUSPLUS "\ue61d"
#define ICON_DATABASE "\uf6b7"
#define ICON_DESKTOP "\ufcbe"
#define ICON_DOCUMENT "\uf718"
#define ICON_DOWNLOADS "\uf5d7"
#define ICON_ENCRYPT "\uf805"
#define ICON_FSHARP "\ue7a7"
#define ICON_GIT "\ue5fb"
#define ICON_HASKELL "\ue777"
#define ICON_HTML "\uf72d"
#define ICON_JAVA "\ue738"
#define ICON_JAVASCRIPT "\uf81d"
#define ICON_LICENSE "\uf718"
#define ICON_LINUX "\uf83c"
#define ICON_MAKEFILE "\uf68c"
#define ICON_MUSIC "\uf832"
#define ICON_MUSICFILE "\uf886"
#define ICON_OPTICALDISK "\ue271"
#define ICON_PICTUREFILE "\uf71e"
#define ICON_PICTURES "\uf753"
#define ICON_PLAYLIST "\uf910"
#define ICON_PUBLIC "\ue5ff"
#define ICON_PYTHON "\ue235"
#define ICON_REACT "\ue625"
#define ICON_RUBY "\ue23e"
#define ICON_SCRIPT "\ue795"
#define ICON_TEMPLATES "\ufac6"
#define ICON_TEX "\ufb68"
#define ICON_VIDEOFILE "\uf72a"
#define ICON_VIDEOS "\uf72f"
#define ICON_WORDDOC "\uf72b"
/* Numbers */
#define ICON_EXT_1 ICON_MANUAL
#define ICON_EXT_7Z ICON_ARCHIVE
/* A */
#define ICON_EXT_A ICON_MANUAL
#define ICON_EXT_APK ICON_ARCHIVE
#define ICON_EXT_ASM ICON_FILE
#define ICON_EXT_AUP ICON_MUSICFILE
#define ICON_EXT_AVI ICON_VIDEOFILE
/* B */
#define ICON_EXT_BAT ICON_SCRIPT
#define ICON_EXT_BIB ICON_TEX
#define ICON_EXT_BIN "\uf471"
#define ICON_EXT_BMP ICON_PICTUREFILE
#define ICON_EXT_BZ2 ICON_ARCHIVE
/* C */
#define ICON_EXT_C ICON_C
#define ICON_EXT_CPLUSPLUS ICON_CPLUSPLUS
#define ICON_EXT_CAB ICON_ARCHIVE
#define ICON_EXT_CABAL ICON_HASKELL
#define ICON_EXT_CBR ICON_ARCHIVE
#define ICON_EXT_CBZ ICON_ARCHIVE
#define ICON_EXT_CC ICON_CPLUSPLUS
#define ICON_EXT_CLASS ICON_JAVA
#define ICON_EXT_CLJ ICON_CLOJURE
#define ICON_EXT_CLJC ICON_CLOJURE
#define ICON_EXT_CLJS ICON_CLOJURE
#define ICON_EXT_CLS ICON_TEX
#define ICON_EXT_CMAKE ICON_MAKEFILE
#define ICON_EXT_COFFEE "\ue751"
#define ICON_EXT_CONF ICON_CONFIGURE
#define ICON_EXT_CPIO ICON_ARCHIVE
#define ICON_EXT_CPP ICON_CPLUSPLUS
#define ICON_EXT_CSS "\ue749"
#define ICON_EXT_CUE ICON_PLAYLIST
#define ICON_EXT_CVS ICON_CONFIGURE
#define ICON_EXT_CXX ICON_CPLUSPLUS
/* D */
#define ICON_EXT_DB ICON_DATABASE
#define ICON_EXT_DEB "\ue77d"
#define ICON_EXT_DIFF "\uf440"
#define ICON_EXT_DLL ICON_SCRIPT
#define ICON_EXT_DOC ICON_WORDDOC
#define ICON_EXT_DOCX ICON_WORDDOC
/* E */
#define ICON_EXT_EJS ICON_JAVASCRIPT
#define ICON_EXT_ELF ICON_LINUX
#define ICON_EXT_EPUB ICON_MANUAL
#define ICON_EXT_EXE ICON_EXEC
/* F */
#define ICON_EXT_FEN ICON_CHESS
#define ICON_EXT_FSHARP ICON_FSHARP
#define ICON_EXT_FLAC ICON_MUSICFILE
#define ICON_EXT_FLV ICON_VIDEOFILE
#define ICON_EXT_FS ICON_FSHARP
#define ICON_EXT_FSI ICON_FSHARP
#define ICON_EXT_FSSCRIPT ICON_FSHARP
#define ICON_EXT_FSX ICON_FSHARP
/* G */
#define ICON_EXT_GEM ICON_RUBY
#define ICON_EXT_GIF ICON_PICTUREFILE
#define ICON_EXT_GO "\ufcd1"
#define ICON_EXT_GPG ICON_ENCRYPT
#define ICON_EXT_GZ ICON_ARCHIVE
#define ICON_EXT_GZIP ICON_ARCHIVE
/* H */
#define ICON_EXT_H ICON_C
#define ICON_EXT_HH ICON_CPLUSPLUS
#define ICON_EXT_HPP ICON_CPLUSPLUS
#define ICON_EXT_HS ICON_HASKELL
#define ICON_EXT_HTACCESS ICON_CONFIGURE
#define ICON_EXT_HTPASSWD ICON_CONFIGURE
#define ICON_EXT_HTM ICON_HTML
#define ICON_EXT_HTML ICON_HTML
#define ICON_EXT_HXX ICON_CPLUSPLUS
/* I */
#define ICON_EXT_ICO ICON_PICTUREFILE
#define ICON_EXT_IMG ICON_OPTICALDISK
#define ICON_EXT_INI ICON_CONFIGURE
#define ICON_EXT_ISO ICON_OPTICALDISK
/* J */
#define ICON_EXT_JAR ICON_JAVA
#define ICON_EXT_JAVA ICON_JAVA
#define ICON_EXT_JL ICON_CONFIGURE
#define ICON_EXT_JPEG ICON_PICTUREFILE
#define ICON_EXT_JPG ICON_PICTUREFILE
#define ICON_EXT_JS ICON_JAVASCRIPT
#define ICON_EXT_JSON "\ufb25"
#define ICON_EXT_JSX ICON_REACT
/* K */
/* L */
#define ICON_EXT_LHA ICON_ARCHIVE
#define ICON_EXT_LHS ICON_HASKELL
#define ICON_EXT_LOG ICON_DOCUMENT
#define ICON_EXT_LUA "\ue620"
#define ICON_EXT_LZH ICON_ARCHIVE
#define ICON_EXT_LZMA ICON_ARCHIVE
/* M */
#define ICON_EXT_M4A ICON_MUSICFILE
#define ICON_EXT_M4V ICON_VIDEOFILE
#define ICON_EXT_M "\ufd1c"
#define ICON_EXT_MAT "\uf0ce"
#define ICON_EXT_MD "\ue609"
#define ICON_EXT_MK ICON_MAKEFILE
#define ICON_EXT_MKV ICON_VIDEOFILE
#define ICON_EXT_MOV ICON_VIDEOFILE
#define ICON_EXT_MP3 ICON_MUSICFILE
#define ICON_EXT_MP4 ICON_VIDEOFILE
#define ICON_EXT_MPEG ICON_VIDEOFILE
#define ICON_EXT_MPG ICON_VIDEOFILE
#define ICON_EXT_MSI "\uf871"
/* N */
#define ICON_EXT_NIX "\uf313"
/* O */
#define ICON_EXT_O ICON_MANUAL
#define ICON_EXT_OGG ICON_MUSICFILE
#define ICON_EXT_OPUS ICON_MUSICFILE
#define ICON_EXT_ODOWNLOAD ICON_DOWNLOADS
#define ICON_EXT_OUT ICON_LINUX
/* P */
#define ICON_EXT_PART ICON_DOWNLOADS
#define ICON_EXT_PATCH "\uf440"
#define ICON_EXT_PDF "\uf724"
#define ICON_EXT_PGN ICON_CHESS
#define ICON_EXT_PHP "\ue73d"
#define ICON_EXT_PNG ICON_PICTUREFILE
#define ICON_EXT_PPT "\uf726"
#define ICON_EXT_PPTX "\uf726"
#define ICON_EXT_PSB "\ue7b8"
#define ICON_EXT_PSD "\ue7b8"
#define ICON_EXT_PY ICON_PYTHON
#define ICON_EXT_PYC ICON_PYTHON
#define ICON_EXT_PYD ICON_PYTHON
#define ICON_EXT_PYO ICON_PYTHON
/* Q */
/* R */
#define ICON_EXT_RAR ICON_ARCHIVE
#define ICON_EXT_RC ICON_CONFIGURE
#define ICON_EXT_ROM "\uf795"
#define ICON_EXT_RPM ICON_ARCHIVE
#define ICON_EXT_RSS "\uf96b"
#define ICON_EXT_RTF "\uf724"
#define ICON_EXT_RB ICON_RUBY
/* S */
#define ICON_EXT_SASS "\ue603"
#define ICON_EXT_SCSS "\ue603"
#define ICON_EXT_SO ICON_MANUAL
#define ICON_EXT_SCALA "\ue737"
#define ICON_EXT_SH ICON_SCRIPT
#define ICON_EXT_SLIM ICON_SCRIPT
#define ICON_EXT_SLN "\ue70c"
#define ICON_EXT_SQL ICON_DATABASE
#define ICON_EXT_SRT "\uf679"
#define ICON_EXT_STY ICON_TEX
#define ICON_EXT_SUB "\uf679"
#define ICON_EXT_SVG ICON_PICTUREFILE
/* T */
#define ICON_EXT_TAR ICON_ARCHIVE
#define ICON_EXT_TEX ICON_TEX
#define ICON_EXT_TGZ ICON_ARCHIVE
#define ICON_EXT_TS "\ue628"
#define ICON_EXT_TSX ICON_REACT
#define ICON_EXT_TXT ICON_DOCUMENT
#define ICON_EXT_TXZ ICON_ARCHIVE
/* U */
/* V */
#define ICON_EXT_VID ICON_VIDEOFILE
#define ICON_EXT_VIM "\ue62b"
#define ICON_EXT_VIMRC "\ue62b"
/* W */
#define ICON_EXT_WAV ICON_MUSICFILE
#define ICON_EXT_WEBM ICON_VIDEOFILE
#define ICON_EXT_WEBP ICON_PICTUREFILE
#define ICON_EXT_WMA ICON_VIDEOFILE
#define ICON_EXT_WMV ICON_VIDEOFILE
/* X */
#define ICON_EXT_XBPS ICON_ARCHIVE
#define ICON_EXT_XCF ICON_PICTUREFILE
#define ICON_EXT_XHTML ICON_HTML
#define ICON_EXT_XLS "\uf71a"
#define ICON_EXT_XLSX "\uf71a"
#define ICON_EXT_XML ICON_HTML
#define ICON_EXT_XZ ICON_ARCHIVE
/* Y */
#define ICON_EXT_YAML ICON_CONFIGURE
#define ICON_EXT_YML ICON_CONFIGURE
/* Z */
#define ICON_EXT_ZIP ICON_ARCHIVE
#define ICON_EXT_ZSH ICON_SCRIPT
#define ICON_EXT_ZST ICON_ARCHIVE
#endif // ICONS_NERDFONT

File diff suppressed because it is too large Load Diff

View File

@ -123,9 +123,11 @@
#include "nnn.h"
#include "dbg.h"
#if defined(ICONS) || defined(NERD) || defined(EMOJI)
#include "icons.h"
#if defined(ICONS_IN_TERM) || defined(NERD) || defined(EMOJI)
#define ICONS_ENABLED
#include "icons-generated.h"
#include "icons-hash.c"
#include "icons.h"
#endif
#ifdef TOURBIN_QSORT
@ -771,11 +773,6 @@ static const char * const patterns[] = {
#define C_SOC (C_PIP + 1) /* Socket: MediumOrchid1 */
#define C_UND (C_SOC + 1) /* Unknown OR 0B regular/exe file: Red1 */
#ifdef ICONS_ENABLED
/* 0-9, A-Z, OTHER = 36. */
static ushort_t icon_positions[37];
#endif
static char gcolors[] = "c1e2272e006033f7c6d6abc4";
static uint_t fcolors[C_UND + 1] = {0};
@ -2164,30 +2161,10 @@ static bool initcurses(void *oldmask)
init_pair(i + 1, *pcode, -1);
}
}
#ifdef ICONS_ENABLED
if (!g_state.oldcolor) {
uchar_t icolors[COLOR_256] = {0};
char c;
memset(icon_positions, 0x7f, sizeof(icon_positions));
for (uint_t i = 0; i < ELEMENTS(icons_ext); ++i) {
c = TOUPPER(icons_ext[i].match[0]);
if (c >= 'A' && c <= 'Z') {
if (icon_positions[c - 'A' + 10] == 0x7f7f)
icon_positions[c - 'A' + 10] = i;
} else if (c >= '0' && c <= '9') {
if (icon_positions[c - '0'] == 0x7f7f)
icon_positions[c - '0'] = i;
} else if (icon_positions[36] == 0x7f7f)
icon_positions[36] = i;
if (icons_ext[i].color && !icolors[icons_ext[i].color]) {
init_pair(C_UND + 1 + icons_ext[i].color, icons_ext[i].color, -1);
icolors[icons_ext[i].color] = 1;
}
}
for (uint_t i = 0; i < ELEMENTS(init_colors); ++i)
init_pair(C_UND + 1 + init_colors[i], init_colors[i], -1);
}
#endif
@ -3997,28 +3974,15 @@ static const struct icon_pair *get_icon(const struct entry *ent)
char *tmp = xextension(ent->name, ent->nlen);
if (!tmp) {
if (ent->mode & 0100)
return &exec_icon;
return &file_icon;
if (tmp) {
uint16_t z, k, h = icon_ext_hash(++tmp); /* ++tmp to skip '.' */
for (k = 0; k < ICONS_PROBE_MAX; ++k) {
z = (h + k) % ELEMENTS(icons_ext);
if (strcasecmp(tmp, icons_ext[z].match) == 0)
return &icons_ext[z];
}
}
/* Skip the . */
++tmp;
if (*tmp >= '0' && *tmp <= '9')
i = *tmp - '0'; /* NUMBER 0-9 */
else if (TOUPPER(*tmp) >= 'A' && TOUPPER(*tmp) <= 'Z')
i = TOUPPER(*tmp) - 'A' + 10; /* LETTER A-Z */
else
i = 36; /* OTHER */
for (ushort_t j = icon_positions[i]; j < ELEMENTS(icons_ext) &&
icons_ext[j].match[0] == icons_ext[icon_positions[i]].match[0]; ++j)
if (strcasecmp(tmp, icons_ext[j].match) == 0)
return &icons_ext[j];
/* If there's no match and the file is executable, icon that */
if (ent->mode & 0100)
return &exec_icon;
@ -6509,7 +6473,7 @@ static void redraw(char *path)
if (curscroll > 0) {
move(1, 0);
#ifdef ICONS_ENABLED
addstr(MD_ARROW_UPWARD);
addstr(ICON_ARROW_UP);
#else
addch('^');
#endif
@ -6546,7 +6510,7 @@ static void redraw(char *path)
if (onscreen < ndents) {
move(xlines - 2, 0);
#ifdef ICONS_ENABLED
addstr(MD_ARROW_DOWNWARD);
addstr(ICON_ARROW_DOWN);
#else
addch('v');
#endif