added preview function

This commit is contained in:
emmett1
2026-03-16 00:36:44 +08:00
parent 02a8adadc4
commit fbc3227515
+138 -38
View File
@@ -83,6 +83,7 @@ INFO_MSG="" # ephemeral message shown in botbar
SHOW_HIDDEN=0 # 1 = show dotfiles SHOW_HIDDEN=0 # 1 = show dotfiles
SORT_MODE="name" # name | size | date SORT_MODE="name" # name | size | date
SHOW_DETAILS=0 # 1 = show size+date column SHOW_DETAILS=0 # 1 = show size+date column
SHOW_PREVIEW=0 # 1 = show preview pane on right
TRASH_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/sfm-trash" TRASH_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/sfm-trash"
mkdir -p "$TRASH_DIR" mkdir -p "$TRASH_DIR"
PREV_CWD="" # last visited directory, for jumping back PREV_CWD="" # last visited directory, for jumping back
@@ -432,6 +433,85 @@ render_row() {
fi fi
} }
draw_preview() {
_rows=$1; _cols=$2; _px=$3; _pw=$4
entry=$(get_entry "$SEL")
# clear preview area first
_r=2
while [ "$_r" -le $((_rows - 1)) ]; do
goto "$_r" "$_px"
printf '\033[K'
_r=$((_r + 1))
done
[ -z "$entry" ] && return
_path=$(joinpath "${entry%/}"); _path="${_path%@}"
# draw vertical divider
_r=2
while [ "$_r" -le $((_rows - 1)) ]; do
goto "$_r" $((_px - 1))
printf '%s|%s' "${CYAN}" "${RESET}"
_r=$((_r + 1))
done
case "$entry" in
*/)
# directory: show entry count
_dc=$(ls -1 "$_path" 2>/dev/null | wc -l | tr -d '[:space:]')
goto 2 "$_px"
printf '%s[dir] %s items%s' "${CYAN}" "${_dc}" "${RESET}"
;;
*@)
# symlink
_tgt=$(readlink "$_path" 2>/dev/null || echo "?")
goto 2 "$_px"
printf '%s[symlink]%s' "${MAGENTA}${BOLD}" "${RESET}"
goto 3 "$_px"
printf '%s-> %s%s' "${WHITE}" "${_tgt}" "${RESET}"
;;
*)
# detect if text via extension or mime
_ext="${entry##*.}"
_ext=$(printf '%s' "$_ext" | tr '[:upper:]' '[:lower:]')
_is_text=0
case "$_ext" in
txt|md|markdown|rst|log|conf|cfg|ini|toml|yaml|yml|\
sh|bash|zsh|py|rb|pl|lua|js|ts|json|xml|html|htm|\
css|c|h|cpp|rs|go|java|php|r|sql|vim|env|gitignore|\
diff|patch|csv|tsv|lock|mod|sum) _is_text=1 ;;
esac
if [ "$_is_text" = "0" ] && command -v file >/dev/null 2>&1; then
case "$(file --mime-type -b "$_path" 2>/dev/null)" in
text/*) _is_text=1 ;;
esac
fi
if [ "$_is_text" = "1" ]; then
_max_lines=$((_rows - 3))
_line_n=0
while IFS= read -r _line && [ "$_line_n" -lt "$_max_lines" ]; do
# truncate to preview width
if [ "${#_line}" -gt "$((_pw - 1))" ]; then
_line=$(printf '%s' "$_line" | cut -c1-$((_pw - 2)))
_line="${_line}~"
fi
goto "$((_line_n + 2))" "$_px"
printf '%s%s%s' "${WHITE}" "$_line" "${RESET}"
_line_n=$((_line_n + 1))
done < "$_path"
if [ "$_line_n" -eq 0 ]; then
goto 2 "$_px"
printf '%s(empty file)%s' "${WHITE}" "${RESET}"
fi
else
# binary / unknown
goto 2 "$_px"
_sz=$(ls -lh "$_path" 2>/dev/null | awk '{print $5}')
printf '%s[binary] %s%s' "${YELLOW}" "${_sz}" "${RESET}"
fi
;;
esac
}
draw_topbar() { draw_topbar() {
_cols=$1 _cols=$1
spaces=$(printf '%*s' "$_cols" '') spaces=$(printf '%*s' "$_cols" '')
@@ -494,6 +574,15 @@ draw() {
COLS=$(term_cols) COLS=$(term_cols)
LIST_ROWS=$((ROWS - 2)) # row 1 = topbar, row ROWS = botbar LIST_ROWS=$((ROWS - 2)) # row 1 = topbar, row ROWS = botbar
# split layout when preview enabled
if [ "$SHOW_PREVIEW" = "1" ]; then
LIST_COLS=$((COLS / 2))
PREV_COL=$((LIST_COLS + 2))
PREV_WIDTH=$((COLS - LIST_COLS - 2))
else
LIST_COLS=$COLS
fi
# clamp selection # clamp selection
[ "$SEL" -lt 0 ] && SEL=0 [ "$SEL" -lt 0 ] && SEL=0
[ "$COUNT" -gt 0 ] && [ "$SEL" -ge "$COUNT" ] && SEL=$((COUNT - 1)) [ "$COUNT" -gt 0 ] && [ "$SEL" -ge "$COUNT" ] && SEL=$((COUNT - 1))
@@ -509,7 +598,6 @@ draw() {
[ "$OFFSET" != "$PREV_OFFSET" ] && NEED_FULL_REDRAW=1 [ "$OFFSET" != "$PREV_OFFSET" ] && NEED_FULL_REDRAW=1
if [ "$NEED_FULL_REDRAW" = "1" ]; then if [ "$NEED_FULL_REDRAW" = "1" ]; then
# --- full repaint: move to top without erasing, overwrite every row ---
printf '\033[H' printf '\033[H'
draw_topbar "$COLS" draw_topbar "$COLS"
@@ -517,7 +605,7 @@ draw() {
idx=$OFFSET idx=$OFFSET
while [ "$row" -le $((LIST_ROWS + 1)) ] && [ "$idx" -lt "$COUNT" ]; do while [ "$row" -le $((LIST_ROWS + 1)) ] && [ "$idx" -lt "$COUNT" ]; do
sel=0; [ "$idx" -eq "$SEL" ] && sel=1 sel=0; [ "$idx" -eq "$SEL" ] && sel=1
render_row "$row" "$idx" "$sel" "$COLS" render_row "$row" "$idx" "$sel" "$LIST_COLS"
row=$((row + 1)) row=$((row + 1))
idx=$((idx + 1)) idx=$((idx + 1))
done done
@@ -527,18 +615,19 @@ draw() {
printf '%s (empty)%s%s' "${WHITE}" "${ERASE_LINE}" "${RESET}" printf '%s (empty)%s%s' "${WHITE}" "${ERASE_LINE}" "${RESET}"
row=3 row=3
fi fi
# blank leftover rows (e.g. after entering a smaller directory) # blank leftover rows
while [ "$row" -le $((LIST_ROWS + 1)) ]; do while [ "$row" -le $((LIST_ROWS + 1)) ]; do
goto "$row" 1 goto "$row" 1
printf '%s' "${ERASE_LINE}" printf '%s' "${ERASE_LINE}"
row=$((row + 1)) row=$((row + 1))
done done
[ "$SHOW_PREVIEW" = "1" ] && draw_preview "$ROWS" "$COLS" "$PREV_COL" "$PREV_WIDTH"
draw_botbar "$ROWS" "$COLS" draw_botbar "$ROWS" "$COLS"
NEED_FULL_REDRAW=0 NEED_FULL_REDRAW=0
else else
# --- fast path: only touch the two rows whose highlight state changed --- # --- fast path ---
# if nothing moved, skip entirely — no flicker at boundaries
if [ "$SEL" = "$PREV_SEL" ] && [ "$OFFSET" = "$PREV_OFFSET" ]; then if [ "$SEL" = "$PREV_SEL" ] && [ "$OFFSET" = "$PREV_OFFSET" ]; then
return 2>/dev/null || true return 2>/dev/null || true
fi fi
@@ -546,12 +635,14 @@ draw() {
new_row=$(( (SEL - OFFSET) + 2 )) new_row=$(( (SEL - OFFSET) + 2 ))
if [ "$prev_row" -ge 2 ] && [ "$prev_row" -le $((LIST_ROWS + 1)) ]; then if [ "$prev_row" -ge 2 ] && [ "$prev_row" -le $((LIST_ROWS + 1)) ]; then
render_row "$prev_row" "$PREV_SEL" 0 "$COLS" render_row "$prev_row" "$PREV_SEL" 0 "$LIST_COLS"
fi fi
if [ "$new_row" -ge 2 ] && [ "$new_row" -le $((LIST_ROWS + 1)) ]; then if [ "$new_row" -ge 2 ] && [ "$new_row" -le $((LIST_ROWS + 1)) ]; then
render_row "$new_row" "$SEL" 1 "$COLS" render_row "$new_row" "$SEL" 1 "$LIST_COLS"
fi fi
[ "$SHOW_PREVIEW" = "1" ] && draw_preview "$ROWS" "$COLS" "$PREV_COL" "$PREV_WIDTH"
draw_botbar "$ROWS" "$COLS" draw_botbar "$ROWS" "$COLS"
fi fi
@@ -765,7 +856,7 @@ do_help() {
bw=$((COLS - 4)) bw=$((COLS - 4))
[ "$bw" -gt 52 ] && bw=52 [ "$bw" -gt 52 ] && bw=52
[ "$bw" -lt 36 ] && bw=36 [ "$bw" -lt 36 ] && bw=36
bh=41 bh=42
_help_bx=$(( (COLS - bw) / 2 )); [ "$_help_bx" -lt 1 ] && _help_bx=1 _help_bx=$(( (COLS - bw) / 2 )); [ "$_help_bx" -lt 1 ] && _help_bx=1
_help_by=$(( (ROWS - bh) / 2 )); [ "$_help_by" -lt 1 ] && _help_by=1 _help_by=$(( (ROWS - bh) / 2 )); [ "$_help_by" -lt 1 ] && _help_by=1
_help_iw=$((bw - 2)) _help_iw=$((bw - 2))
@@ -787,32 +878,33 @@ do_help() {
help_row 11 " i file info in status bar" help_row 11 " i file info in status bar"
help_row 12 " s cycle sort: name/size/date" help_row 12 " s cycle sort: name/size/date"
help_row 13 " T toggle size/date details" help_row 13 " T toggle size/date details"
help_sep 14 help_row 14 " P toggle preview pane"
help_row 15 " space toggle multi-select" help_sep 15
help_row 16 " a select all / deselect all" help_row 16 " space toggle multi-select"
help_row 17 " y yank/copy (works on selection)" help_row 17 " a select all / deselect all"
help_row 18 " x cut (works on selection)" help_row 18 " y yank/copy (works on selection)"
help_row 19 " p paste" help_row 19 " x cut (works on selection)"
help_row 20 " d delete (works on selection)" help_row 20 " p paste"
help_sep 21 help_row 21 " d delete (works on selection)"
help_row 22 " r rename R refresh" help_sep 22
help_row 23 " m make directory" help_row 23 " r rename R refresh"
help_row 24 " n new file" help_row 24 " m make directory"
help_row 25 " u trash file (safe delete)" help_row 25 " n new file"
help_row 26 " U open trash directory" help_row 26 " u trash file (safe delete)"
help_row 27 " ! drop to shell in CWD" help_row 27 " U open trash directory"
help_row 28 " o open with custom program" help_row 28 " ! drop to shell in CWD"
help_sep 29 help_row 29 " o open with custom program"
help_row 30 " b bookmark current dir" help_sep 30
help_row 31 " B open bookmark picker" help_row 31 " b bookmark current dir"
help_row 32 " c copy path to clipboard" help_row 32 " B open bookmark picker"
help_row 33 " ~ go to home directory" help_row 33 " c copy path to clipboard"
help_row 34 " \` jump to previous directory" help_row 34 " ~ go to home directory"
help_sep 35 help_row 35 " \` jump to previous directory"
help_row 36 " q quit" help_sep 36
help_row 37 " ? this help" help_row 37 " q quit"
help_row 38 "" help_row 38 " ? this help"
help_row 39 " press any key to close..." help_row 39 ""
help_row 40 " press any key to close..."
goto "$(( _help_by + bh ))" "$_help_bx" goto "$(( _help_by + bh ))" "$_help_bx"
printf '%s+%s+%s' "${BOLD}${CYAN}" "$_help_hl" "${RESET}" printf '%s+%s+%s' "${BOLD}${CYAN}" "$_help_hl" "${RESET}"
@@ -877,11 +969,18 @@ do_toggle_hidden() {
do_toggle_details() { do_toggle_details() {
if [ "$SHOW_DETAILS" = "0" ]; then if [ "$SHOW_DETAILS" = "0" ]; then
SHOW_DETAILS=1 SHOW_DETAILS=1; INFO_MSG="details on"
INFO_MSG="details on"
else else
SHOW_DETAILS=0 SHOW_DETAILS=0; INFO_MSG="details off"
INFO_MSG="details off" fi
NEED_FULL_REDRAW=1
}
do_toggle_preview() {
if [ "$SHOW_PREVIEW" = "0" ]; then
SHOW_PREVIEW=1; INFO_MSG="preview on"
else
SHOW_PREVIEW=0; INFO_MSG="preview off"
fi fi
NEED_FULL_REDRAW=1 NEED_FULL_REDRAW=1
} }
@@ -1385,6 +1484,7 @@ while true; do
/) do_search ;; /) do_search ;;
'.') do_toggle_hidden ;; '.') do_toggle_hidden ;;
T) do_toggle_details ;; T) do_toggle_details ;;
P) do_toggle_preview ;;
i) do_info ;; i) do_info ;;
'!') do_shell ;; '!') do_shell ;;
o) do_open_with ;; o) do_open_with ;;