commit f374506215371cd375b43f54135cbf46dc202ea0
parent fe57971b9192d5ee093df12b288d5d2d9fd119c0
Author: emmett1 <me@emmett1.my>
Date: Sat, 11 Apr 2026 08:51:01 +0800
update
Diffstat:
| M | sfm | | | 80 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
1 file changed, 46 insertions(+), 34 deletions(-)
diff --git a/sfm b/sfm
@@ -244,40 +244,42 @@ apply_filter() {
if [ -z "$FILTER" ]; then
ENTRIES="$ALL_ENTRIES"
COUNT="$ALL_COUNT"
- return
- fi
- ENTRIES=""
- COUNT=0
- printf '%s\n' "$ALL_ENTRIES" | while IFS= read -r line; do
- case "$line" in
- *"$FILTER"*) printf '%s\n' "$line" ;;
- esac
- done | {
- while IFS= read -r line; do
- ENTRIES="$ENTRIES
-$line"
- COUNT=$((COUNT + 1))
- done
- # write back via temp — subshell can't modify parent vars directly
- printf '%s\n' "$COUNT" > /tmp/_fm_count
- printf '%s' "$ENTRIES" > /tmp/_fm_entries
- }
- COUNT=$(cat /tmp/_fm_count 2>/dev/null || echo 0)
- ENTRIES=$(cat /tmp/_fm_entries 2>/dev/null || echo "")
- ENTRIES="${ENTRIES#
+ else
+ ENTRIES=""
+ COUNT=0
+ _rest="$ALL_ENTRIES"
+ while [ -n "$_rest" ]; do
+ _line="${_rest%%
+*}"; _next="${_rest#*
}"
+ [ "$_next" = "$_rest" ] && _next=""
+ _rest="$_next"
+ [ -z "$_line" ] && continue
+ case "$_line" in
+ *"$FILTER"*)
+ if [ -z "$ENTRIES" ]; then ENTRIES="$_line"
+ else ENTRIES="$ENTRIES
+$_line"; fi
+ COUNT=$((COUNT + 1)) ;;
+ esac
+ done
+ fi
+ # write to tmp file for O(1) line access in get_entry
+ printf '%s\n' "$ENTRIES" > /tmp/_sfm_list
}
get_entry() {
- printf '%s\n' "$ENTRIES" | awk -v n="$(($1 + 1))" 'NR==n{print; exit}'
+ sed -n "$(($1 + 1))p" /tmp/_sfm_list
}
# find index of entry by name (0-based), returns -1 if not found
find_entry() {
- printf '%s\n' "$ENTRIES" | awk -v name="$1" '
- { if ($0 == name) { print NR-1; found=1; exit } }
- END { if (!found) print -1 }
- '
+ _fe_n=$(grep -n "^${1}$" /tmp/_sfm_list 2>/dev/null | head -1 | cut -d: -f1)
+ if [ -n "$_fe_n" ]; then
+ printf '%d' $((_fe_n - 1))
+ else
+ printf '%d' -1
+ fi
}
# is entry name in SELECTED list?
@@ -344,13 +346,19 @@ render_row() {
*/) colour="${BLUE}${BOLD}" ;;
*@)
_name="${entry%@}"
- # broken symlink if target doesn't exist
if [ -e "${CWD}/${_name}" ]; then
colour="${CYAN}${BOLD}"
else
colour="${RED}${BOLD}"
fi ;;
- *) colour=$(file_colour "$entry") ;;
+ *)
+ _fc="${CWD}/${entry}"
+ if [ -x "$_fc" ]; then colour="${GREEN}${BOLD}"
+ elif [ -c "$_fc" ]; then colour="${MAGENTA}${BOLD}"
+ elif [ -b "$_fc" ]; then colour="${MAGENTA}${BOLD}"
+ elif [ ! -r "$_fc" ] || [ ! -w "$_fc" ]; then colour="${RED}${BOLD}"
+ else colour="${WHITE}"
+ fi ;;
esac
# multi-select marker
@@ -382,17 +390,21 @@ render_row() {
if [ "$SHOW_DETAILS" = "1" ]; then
_path="${CWD}/${entry%/}"; _path="${_path%@}"
_info=$(ls -ldh "$_path" 2>/dev/null)
- _sz=$(printf '%s' "$_info" | awk '{print $5}')
- _dt=$(printf '%s' "$_info" | awk '{print $6, $7}')
- # fixed width: size=6, date=6 → total detail = 14 chars
+ # parse ls output with parameter expansion — no awk fork
+ set -- $_info
+ _sz=$5; _dt="$6 $7"
_detail=$(printf ' %6s %-6s' "$_sz" "$_dt")
+ set --
fi
# layout: marker(1) + name + spaces + detail
_dlen=${#_detail}
- maxw=$((_cols - 1 - _dlen - 1))
+ maxw=$((_cols - 2 - _dlen))
if [ "${#display}" -gt "$maxw" ]; then
- display=$(printf '%s' "$display" | cut -c1-$((_cols - _dlen - 4)))
+ _trunc=$((maxw - 3))
+ while [ "${#display}" -gt "$_trunc" ]; do
+ display="${display%?}"
+ done
display="${display}..."
fi
_namew=$((${#display} + 1)) # 1 for marker
@@ -1633,7 +1645,7 @@ do_paste() {
}
# --- main ---
-trap 'restore_term; show_cursor; printf "\033[2J\033[H"; exit 0' INT TERM EXIT
+trap 'restore_term; show_cursor; printf "\033[2J\033[H"; rm -f /tmp/_sfm_list /tmp/_sfm_find; exit 0' INT TERM EXIT
setup_term
hide_cursor