@@ -18,80 +18,104 @@ const EXCLUDED_DIRECTORIES = [
1818] ; // 排除目录
1919
2020/**
21- * 解析 ignore 文件内容并返回匹配模式数组
22- * @param filePath ignore 文件路径
23- * @returns 过滤模式数组
21+ * 解析 .gitignore 文件,返回正向模式和反向模式
22+ * @param filePath .gitignore 文件路径
23+ * @returns { ignorePatterns: string[], includePatterns: string[] }
2424 */
25- function parseIgnoreFile ( filePath : string ) : string [ ] {
25+ function parseGitignore ( filePath : string ) : { ignorePatterns : string [ ] , includePatterns : string [ ] } {
2626 try {
2727 const content = fs . readFileSync ( filePath , 'utf8' ) ;
28- return content
29- . split ( '\n' )
30- . map ( line => line . trim ( ) )
31- . filter ( line =>
32- line && // 非空行
33- ! line . startsWith ( '#' ) && // 不是注释
34- ! line . startsWith ( '!' ) // 不是反向模式
35- )
36- . map ( pattern => {
37- // 转换 gitignore 风格的模式为 glob 模式
38- if ( pattern . endsWith ( '/' ) ) {
39- return `**/${ pattern } **` ;
40- }
41- return `**/${ pattern } ` ;
42- } ) ;
28+ const lines = content . split ( '\n' ) . map ( line => line . trim ( ) ) . filter ( line => line && ! line . startsWith ( '#' ) ) ;
29+ const ignorePatterns : string [ ] = [ ] ;
30+ const includePatterns : string [ ] = [ ] ;
31+ lines . forEach ( line => {
32+ if ( line . startsWith ( '!' ) ) {
33+ includePatterns . push ( line . slice ( 1 ) ) ; // 去掉 '!',作为强制包含模式
34+ } else {
35+ ignorePatterns . push ( line ) ;
36+ }
37+ } ) ;
38+ return { ignorePatterns, includePatterns } ;
4339 } catch ( error ) {
44- return [ ] ;
40+ return { ignorePatterns : [ ] , includePatterns : [ ] } ;
4541 }
4642}
4743
44+ /**
45+ * 检查文件是否匹配某个模式(简单的手动匹配)
46+ * @param filePath 文件路径
47+ * @param pattern 模式
48+ * @returns 是否匹配
49+ */
50+ function matchesPattern ( filePath : string , pattern : string ) : boolean {
51+ const basename = path . basename ( filePath ) ;
52+ if ( pattern . startsWith ( '*' ) && pattern . includes ( ',' ) ) {
53+ const exactExtension = pattern . slice ( 1 ) ; // 去掉前面的 *,保留 .py,cover
54+ return basename . endsWith ( exactExtension ) ;
55+ }
56+ // 其他简单模式(可以扩展支持更多规则)
57+ return basename === pattern || filePath . includes ( pattern ) ;
58+ }
59+
4860/**
4961 * 显示文件选择器,并返回用户选择的文件列表
5062 * @returns 用户选择的文件路径数组
5163 */
5264export async function selectFiles ( ) : Promise < string [ ] > {
53- // 检查是否打开了工作区
5465 const workspaceFolders = vscode . workspace . workspaceFolders ;
5566 if ( ! workspaceFolders ) {
5667 vscode . window . showErrorMessage ( 'No workspace folder found.' ) ;
5768 return [ ] ;
5869 }
5970
6071 const rootPath = workspaceFolders [ 0 ] . uri . fsPath ;
61-
62- // 构建默认排除模式数组
63- const defaultExcludePatterns = EXCLUDED_DIRECTORIES . map ( dir => `**/${ dir } /**` ) ;
64-
65- // 获取 ignore 文件的模式
66- let ignorePatterns : string [ ] = [ ] ;
6772 const gitignorePath = path . join ( rootPath , '.gitignore' ) ;
68-
69- if ( fs . existsSync ( gitignorePath ) ) {
70- ignorePatterns = ignorePatterns . concat ( parseIgnoreFile ( gitignorePath ) ) ;
71- }
73+ const { ignorePatterns, includePatterns } = fs . existsSync ( gitignorePath ) ? parseGitignore ( gitignorePath ) : { ignorePatterns : [ ] , includePatterns : [ ] } ;
7274
73- // 合并所有排除模式并确保是扁平结构
74- const allExcludePatterns = [ ...defaultExcludePatterns , ...ignorePatterns ] ;
75- const excludePattern = allExcludePatterns . length > 0
76- ? `{${ allExcludePatterns . join ( ',' ) } }`
77- : undefined ;
78-
79- // 1. 匹配白名单文件名
75+ // 获取所有符合扩展名和文件名的文件
8076 const filenamePattern = `**/{${ ALLOWED_FILENAMES . join ( ',' ) } }` ;
81- const filenameFiles = await vscode . workspace . findFiles ( filenamePattern , excludePattern ) ;
82-
83- // 2. 匹配扩展名文件
8477 const extensionPattern = `**/*.{${ INCLUDED_EXTENSIONS . join ( ',' ) } }` ;
85- const extensionFiles = await vscode . workspace . findFiles ( extensionPattern , excludePattern ) ;
78+ const filenameFiles = await vscode . workspace . findFiles ( filenamePattern ) ;
79+ const extensionFiles = await vscode . workspace . findFiles ( extensionPattern ) ;
8680
87- // 3. 合并结果并去重
81+ // 合并并去重
8882 const allFiles = [ ...filenameFiles , ...extensionFiles ] ;
8983 const uniqueFiles = Array . from ( new Set ( allFiles . map ( file => file . fsPath ) ) ) ;
9084
91- // 4. 显示文件选择面板
92- const selectedItems = await vscode . window . showQuickPick ( uniqueFiles , {
85+ // 手动过滤
86+ const filteredFiles = uniqueFiles . filter ( filePath => {
87+ const relativePath = path . relative ( rootPath , filePath ) ;
88+
89+ // 检查排除目录
90+ for ( const dir of EXCLUDED_DIRECTORIES ) {
91+ if ( relativePath . startsWith ( dir + path . sep ) ) {
92+ return false ;
93+ }
94+ }
95+
96+ // 检查 .gitignore 模式
97+ let shouldIgnore = false ;
98+ for ( const pattern of ignorePatterns ) {
99+ if ( matchesPattern ( filePath , pattern ) ) {
100+ shouldIgnore = true ;
101+ break ;
102+ }
103+ }
104+ // 检查反向模式(强制包含)
105+ for ( const pattern of includePatterns ) {
106+ if ( matchesPattern ( filePath , pattern ) ) {
107+ shouldIgnore = false ; // 强制包含
108+ break ;
109+ }
110+ }
111+
112+ return ! shouldIgnore ;
113+ } ) ;
114+
115+ // 显示选择面板
116+ const selectedItems = await vscode . window . showQuickPick ( filteredFiles , {
93117 placeHolder : 'Select files to include in the refactoring' ,
94- canPickMany : true , // 允许多选
118+ canPickMany : true ,
95119 } ) ;
96120
97121 // 返回用户选择的文件
0 commit comments