Last active 1755161877

anduin's Avatar anduin revised this gist 1755161877. Go to revision

1 file changed, 59 insertions, 39 deletions

glance.bash

@@ -1,20 +1,21 @@
1 - # 函数:glance - 快速概览目录内容
1 + # glance - Provides a quick and intelligent overview of a directory's contents.
2 2 #
3 - # 作者: Gemini & anduin
4 - # 功能:
5 - # - 自动检测 Git 仓库,智能选择文件列表模式。
6 - # - 动态计算并调整 tree 的显示深度。
7 - # - 文件内容输出严格遵循 tree 的显示深度。
8 - # - 限制单个文件的最大输出行数。
9 - # - 支持按文件名模式筛选文件。
3 + # Authors: anduin
10 4 #
11 - # 用法:
12 - # glance [目录] [选项...]
5 + # Features:
6 + # - Auto-detects Git repositories to intelligently list files.
7 + # - Dynamically calculates and adjusts the `tree` view depth to prevent clutter.
8 + # - File content display strictly adheres to the calculated tree depth.
9 + # - Limits the maximum lines printed per file to avoid long scrolls.
10 + # - Supports powerful filtering by file glob patterns.
13 11 #
14 - # 选项:
15 - # --max-files-preview <数量> : tree 显示的最大条目数 (默认: 100)
16 - # --max-file-lines <数量> : 单个文件的最大显示行数 (默认: 150)
17 - # --filter <模式> : 按扩展名筛选,逗号分隔 (例: '*.md,*.cs')
12 + # Usage:
13 + # glance [DIRECTORY] [OPTIONS...]
14 + #
15 + # Options:
16 + # --max-files-preview <count> : Max items (files+dirs) in tree view. (Default: 100)
17 + # --max-file-lines <count> : Max lines to print per file. (Default: 150)
18 + # --filter <patterns> : Comma-separated glob patterns to filter files (e.g., '*.md,*.cs')
18 19 #
19 20 glance() {
20 21 local target_dir="."
@@ -23,12 +24,16 @@ glance() {
23 24 local filter_patterns=""
24 25 local positional_args=()
25 26
26 - # --- 内部辅助函数:处理单个文件的打印 (无改动) ---
27 + # --- Internal helper function to process and print a single file ---
27 28 _glance_process_file() {
28 29 local file="$1"
29 30 if [ ! -f "$file" ]; then return; fi
31 +
32 + # Check if it's a text file
30 33 if file -b --mime-type "$file" | grep -q '^text/'; then
31 - local total_lines; total_lines=$(wc -l < "$file")
34 + local total_lines
35 + total_lines=$(wc -l < "$file") # More efficient line count
36 +
32 37 local extension="${file##*.}"; local lang=""
33 38 case "$extension" in
34 39 js) lang="javascript" ;; py) lang="python" ;; rb) lang="ruby" ;;
@@ -37,74 +42,86 @@ glance() {
37 42 java) lang="java" ;; c) lang="c" ;; cpp) lang="cpp" ;; go) lang="go" ;;
38 43 *) lang="" ;;
39 44 esac
40 - echo; echo "Content of file \"$file\":"; echo "\`\`\`$lang"
45 +
46 + echo
47 + echo "Content of file \"$file\":"
48 + echo "\`\`\`$lang"
49 +
41 50 if [ "$total_lines" -gt "$max_file_lines" ]; then
42 - head -n "$max_file_lines" "$file"; echo; echo "... (Only shown top $max_file_lines lines of $total_lines) ..."
51 + head -n "$max_file_lines" "$file"
52 + echo
53 + echo "... (Only shown top $max_file_lines lines of $total_lines) ..."
43 54 else
44 55 cat "$file"
45 56 fi
46 - echo; echo "\`\`\`"; echo "----------------------------------------------------------"
57 +
58 + echo
59 + echo "\`\`\`"
60 + echo "----------------------------------------------------------"
47 61 else
48 - echo; echo "--> 已跳过二进制文件: \"$file\""; echo "----------------------------------------------------------"
62 + echo
63 + echo "--> Skipped binary file: \"$file\""
64 + echo "----------------------------------------------------------"
49 65 fi
50 66 }
51 67
52 - # --- 步骤 1: 解析参数 ---
68 + # --- Step 1: Parse arguments ---
53 69 while [[ $# -gt 0 ]]; do
54 70 case "$1" in
55 71 --max-files-preview)
56 72 if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then max_items_preview="$2"; shift 2;
57 - else echo "错误: '--max-files-preview' 需要一个正整数参数。" >&2; return 1; fi ;;
73 + else echo "Error: '--max-files-preview' requires a positive integer argument." >&2; return 1; fi ;;
58 74 --max-file-lines)
59 75 if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then max_file_lines="$2"; shift 2;
60 - else echo "错误: '--max-file-lines' 需要一个正整数参数。" >&2; return 1; fi ;;
76 + else echo "Error: '--max-file-lines' requires a positive integer argument." >&2; return 1; fi ;;
61 77 --filter)
62 78 if [[ -n "$2" && "$2" != -* ]]; then filter_patterns="$2"; shift 2;
63 - else echo "错误: '--filter' 需要一个模式字符串参数。" >&2; return 1; fi ;;
64 - -*) echo "错误: 未知选项 '$1'" >&2; return 1 ;;
79 + else echo "Error: '--filter' requires a pattern string argument." >&2; return 1; fi ;;
80 + -*) echo "Error: Unknown option '$1'" >&2; return 1 ;;
65 81 *) positional_args+=("$1"); shift ;;
66 82 esac
67 83 done
68 84 [[ ${#positional_args[@]} -gt 0 ]] && target_dir="${positional_args[0]}"
69 85
70 - # --- 步骤 2: 依赖和目录检查 ---
71 - if ! command -v tree &>/dev/null; then echo "错误: 'tree' 命令未找到。" >&2; return 1; fi
72 - if [ ! -d "$target_dir" ]; then echo "错误: 目录 '$target_dir' 不存在。" >&2; return 1; fi
86 + # --- Step 2: Check dependencies and directory validity ---
87 + if ! command -v tree &>/dev/null; then echo "Error: 'tree' command not found. Please install it first." >&2; return 1; fi
88 + if [ ! -d "$target_dir" ]; then echo "Error: Directory '$target_dir' does not exist." >&2; return 1; fi
73 89
74 90 echo "=========================================================="
75 - echo "🔎 概览目录: $(realpath "$target_dir")"
91 + echo "🔎 Overview for directory: $(realpath "$target_dir")"
76 92 echo "=========================================================="
77 93 echo
78 94
79 - # --- 步骤 3: 动态计算 tree 的最佳深度 (基于未筛选的完整目录) ---
80 - echo "🌳 目录结构:"
95 + # --- Step 3: Dynamically calculate the optimal tree depth (based on the full, unfiltered directory) ---
96 + echo "🌳 Directory Structure:"
81 97 local best_depth=1; local max_depth_to_check=6; local prev_item_count=-1
82 98 for depth in $(seq 1 $max_depth_to_check); do
83 99 local current_item_count; current_item_count=$(tree -L "$depth" -a --noreport "$target_dir" | wc -l)
84 100 if [ "$depth" -gt 1 ] && [ "$current_item_count" -gt "$max_items_preview" ]; then
85 101 best_depth=$((depth - 1)); break;
86 102 fi
103 + # If item count stops increasing, we've reached the maximum effective depth
87 104 if [ "$depth" -gt 1 ] && [ "$current_item_count" -eq "$prev_item_count" ]; then
88 105 best_depth=$depth; break;
89 106 fi
90 107 best_depth=$depth; prev_item_count=$current_item_count
91 108 done
92 109
93 - # --- 步骤 3.5: 应用筛选并打印 tree ---
110 + # --- Step 3.5: Apply filter and print the tree ---
94 111 local tree_args=(-L "$best_depth")
95 112 if [ -n "$filter_patterns" ]; then
96 113 local tree_pattern; tree_pattern=$(echo "$filter_patterns" | tr ',' '|')
97 114 tree_args+=(-P "$tree_pattern")
98 - echo "(筛选模式: ${filter_patterns})"
115 + echo "(Filter active: ${filter_patterns})"
99 116 fi
100 - echo "(动态调整深度至 L${best_depth} 以适应预览数限制: ${max_items_preview})"
117 + echo "(Dynamic depth set to L${best_depth} to fit item limit: ${max_items_preview})"
101 118 tree "${tree_args[@]}" "$target_dir"
102 119 echo
103 120
104 - # --- 步骤 4: 遍历并打印文件内容 (应用筛选和深度限制) ---
121 + # --- Step 4: Iterate and print file contents (applying filters and depth limits) ---
105 122 local header_suffix=""
106 - if [ -n "$filter_patterns" ]; then header_suffix=" (筛选: ${filter_patterns})"; fi
107 - echo "📄 文件内容详情 (深度 L${best_depth} 以内, 单文件最多 ${max_file_lines} 行${header_suffix}):"
123 + if [ -n "$filter_patterns" ]; then header_suffix=" (filter: ${filter_patterns})"; fi
124 + echo "📄 File Content Details (within depth L${best_depth}, max ${max_file_lines} lines per file${header_suffix}):"
108 125 (
109 126 cd "$target_dir" || exit 1
110 127 echo "----------------------------------------------------------"
@@ -113,18 +130,19 @@ glance() {
113 130 [ -n "$filter_patterns" ] && IFS=',' read -ra filter_array <<< "$filter_patterns"
114 131
115 132 if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
116 - # Git 模式
133 + # Git mode
117 134 local git_files
118 135 if [ ${#filter_array[@]} -gt 0 ]; then
119 136 git_files=$(git ls-files -- "${filter_array[@]}")
120 137 else
121 138 git_files=$(git ls-files)
122 139 fi
140 + # Use awk to filter paths by slash count to simulate depth limit
123 141 echo "$git_files" | awk -F'/' -v depth="$best_depth" 'NF <= depth' | while read -r file; do
124 142 _glance_process_file "$file"
125 143 done
126 144 else
127 - # 普通模式
145 + # Normal mode
128 146 local find_args=(-maxdepth "$best_depth" -type f)
129 147 if [ ${#filter_array[@]} -gt 0 ]; then
130 148 find_args+=("(")
@@ -134,7 +152,9 @@ glance() {
134 152 done
135 153 find_args+=(")")
136 154 fi
155 + # Use find's -maxdepth parameter and name patterns
137 156 find . "${find_args[@]}" | while read -r file; do
157 + # Remove leading './' from file path for cleaner output
138 158 _glance_process_file "${file#./}"
139 159 done
140 160 fi

anduin's Avatar anduin revised this gist 1755161727. Go to revision

No changes

anduin's Avatar anduin revised this gist 1755161709. Go to revision

1 file changed, 142 insertions

glance.bash(file created)

@@ -0,0 +1,142 @@
1 + # 函数:glance - 快速概览目录内容
2 + #
3 + # 作者: Gemini & anduin
4 + # 功能:
5 + # - 自动检测 Git 仓库,智能选择文件列表模式。
6 + # - 动态计算并调整 tree 的显示深度。
7 + # - 文件内容输出严格遵循 tree 的显示深度。
8 + # - 限制单个文件的最大输出行数。
9 + # - 支持按文件名模式筛选文件。
10 + #
11 + # 用法:
12 + # glance [目录] [选项...]
13 + #
14 + # 选项:
15 + # --max-files-preview <数量> : tree 显示的最大条目数 (默认: 100)
16 + # --max-file-lines <数量> : 单个文件的最大显示行数 (默认: 150)
17 + # --filter <模式> : 按扩展名筛选,逗号分隔 (例: '*.md,*.cs')
18 + #
19 + glance() {
20 + local target_dir="."
21 + local max_items_preview=100
22 + local max_file_lines=150
23 + local filter_patterns=""
24 + local positional_args=()
25 +
26 + # --- 内部辅助函数:处理单个文件的打印 (无改动) ---
27 + _glance_process_file() {
28 + local file="$1"
29 + if [ ! -f "$file" ]; then return; fi
30 + if file -b --mime-type "$file" | grep -q '^text/'; then
31 + local total_lines; total_lines=$(wc -l < "$file")
32 + local extension="${file##*.}"; local lang=""
33 + case "$extension" in
34 + js) lang="javascript" ;; py) lang="python" ;; rb) lang="ruby" ;;
35 + sh) lang="bash" ;; css) lang="css" ;; html) lang="html" ;;
36 + json) lang="json" ;; md) lang="markdown" ;; yml|yaml) lang="yaml" ;;
37 + java) lang="java" ;; c) lang="c" ;; cpp) lang="cpp" ;; go) lang="go" ;;
38 + *) lang="" ;;
39 + esac
40 + echo; echo "Content of file \"$file\":"; echo "\`\`\`$lang"
41 + if [ "$total_lines" -gt "$max_file_lines" ]; then
42 + head -n "$max_file_lines" "$file"; echo; echo "... (Only shown top $max_file_lines lines of $total_lines) ..."
43 + else
44 + cat "$file"
45 + fi
46 + echo; echo "\`\`\`"; echo "----------------------------------------------------------"
47 + else
48 + echo; echo "--> 已跳过二进制文件: \"$file\""; echo "----------------------------------------------------------"
49 + fi
50 + }
51 +
52 + # --- 步骤 1: 解析参数 ---
53 + while [[ $# -gt 0 ]]; do
54 + case "$1" in
55 + --max-files-preview)
56 + if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then max_items_preview="$2"; shift 2;
57 + else echo "错误: '--max-files-preview' 需要一个正整数参数。" >&2; return 1; fi ;;
58 + --max-file-lines)
59 + if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then max_file_lines="$2"; shift 2;
60 + else echo "错误: '--max-file-lines' 需要一个正整数参数。" >&2; return 1; fi ;;
61 + --filter)
62 + if [[ -n "$2" && "$2" != -* ]]; then filter_patterns="$2"; shift 2;
63 + else echo "错误: '--filter' 需要一个模式字符串参数。" >&2; return 1; fi ;;
64 + -*) echo "错误: 未知选项 '$1'" >&2; return 1 ;;
65 + *) positional_args+=("$1"); shift ;;
66 + esac
67 + done
68 + [[ ${#positional_args[@]} -gt 0 ]] && target_dir="${positional_args[0]}"
69 +
70 + # --- 步骤 2: 依赖和目录检查 ---
71 + if ! command -v tree &>/dev/null; then echo "错误: 'tree' 命令未找到。" >&2; return 1; fi
72 + if [ ! -d "$target_dir" ]; then echo "错误: 目录 '$target_dir' 不存在。" >&2; return 1; fi
73 +
74 + echo "=========================================================="
75 + echo "🔎 概览目录: $(realpath "$target_dir")"
76 + echo "=========================================================="
77 + echo
78 +
79 + # --- 步骤 3: 动态计算 tree 的最佳深度 (基于未筛选的完整目录) ---
80 + echo "🌳 目录结构:"
81 + local best_depth=1; local max_depth_to_check=6; local prev_item_count=-1
82 + for depth in $(seq 1 $max_depth_to_check); do
83 + local current_item_count; current_item_count=$(tree -L "$depth" -a --noreport "$target_dir" | wc -l)
84 + if [ "$depth" -gt 1 ] && [ "$current_item_count" -gt "$max_items_preview" ]; then
85 + best_depth=$((depth - 1)); break;
86 + fi
87 + if [ "$depth" -gt 1 ] && [ "$current_item_count" -eq "$prev_item_count" ]; then
88 + best_depth=$depth; break;
89 + fi
90 + best_depth=$depth; prev_item_count=$current_item_count
91 + done
92 +
93 + # --- 步骤 3.5: 应用筛选并打印 tree ---
94 + local tree_args=(-L "$best_depth")
95 + if [ -n "$filter_patterns" ]; then
96 + local tree_pattern; tree_pattern=$(echo "$filter_patterns" | tr ',' '|')
97 + tree_args+=(-P "$tree_pattern")
98 + echo "(筛选模式: ${filter_patterns})"
99 + fi
100 + echo "(动态调整深度至 L${best_depth} 以适应预览数限制: ${max_items_preview})"
101 + tree "${tree_args[@]}" "$target_dir"
102 + echo
103 +
104 + # --- 步骤 4: 遍历并打印文件内容 (应用筛选和深度限制) ---
105 + local header_suffix=""
106 + if [ -n "$filter_patterns" ]; then header_suffix=" (筛选: ${filter_patterns})"; fi
107 + echo "📄 文件内容详情 (深度 L${best_depth} 以内, 单文件最多 ${max_file_lines} 行${header_suffix}):"
108 + (
109 + cd "$target_dir" || exit 1
110 + echo "----------------------------------------------------------"
111 +
112 + local filter_array=()
113 + [ -n "$filter_patterns" ] && IFS=',' read -ra filter_array <<< "$filter_patterns"
114 +
115 + if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
116 + # Git 模式
117 + local git_files
118 + if [ ${#filter_array[@]} -gt 0 ]; then
119 + git_files=$(git ls-files -- "${filter_array[@]}")
120 + else
121 + git_files=$(git ls-files)
122 + fi
123 + echo "$git_files" | awk -F'/' -v depth="$best_depth" 'NF <= depth' | while read -r file; do
124 + _glance_process_file "$file"
125 + done
126 + else
127 + # 普通模式
128 + local find_args=(-maxdepth "$best_depth" -type f)
129 + if [ ${#filter_array[@]} -gt 0 ]; then
130 + find_args+=("(")
131 + for i in "${!filter_array[@]}"; do
132 + [ "$i" -ne 0 ] && find_args+=("-o")
133 + find_args+=(-name "${filter_array[$i]}")
134 + done
135 + find_args+=(")")
136 + fi
137 + find . "${find_args[@]}" | while read -r file; do
138 + _glance_process_file "${file#./}"
139 + done
140 + fi
141 + )
142 + }
Newer Older