|  |  |  | @ -8,6 +8,10 @@ const FLAVORS = [ | 
			
		
	
		
			
				
					|  |  |  |  |   'cn', | 
			
		
	
		
			
				
					|  |  |  |  | ]; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | const BLACK_FILE_EXT = [ | 
			
		
	
		
			
				
					|  |  |  |  |   'md', | 
			
		
	
		
			
				
					|  |  |  |  | ]; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | final _ctx = { | 
			
		
	
		
			
				
					|  |  |  |  |   'debug': 'debug', | 
			
		
	
		
			
				
					|  |  |  |  |   'release': 'release', | 
			
		
	
	
		
			
				
					|  |  |  | @ -18,12 +22,14 @@ final _ctx = { | 
			
		
	
		
			
				
					|  |  |  |  | String? exp; | 
			
		
	
		
			
				
					|  |  |  |  | late String mode; | 
			
		
	
		
			
				
					|  |  |  |  | late String flavor; | 
			
		
	
		
			
				
					|  |  |  |  | late bool isReplace; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | enum STATE { | 
			
		
	
		
			
				
					|  |  |  |  |   none, | 
			
		
	
		
			
				
					|  |  |  |  |   notMatch, | 
			
		
	
		
			
				
					|  |  |  |  |   caching, | 
			
		
	
		
			
				
					|  |  |  |  |   replace, | 
			
		
	
		
			
				
					|  |  |  |  |   inDefault, | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | void main(List<String> arguments) { | 
			
		
	
	
		
			
				
					|  |  |  | @ -31,6 +37,7 @@ void main(List<String> arguments) { | 
			
		
	
		
			
				
					|  |  |  |  |   var args = parse(arguments); | 
			
		
	
		
			
				
					|  |  |  |  |   mode = args.mode; | 
			
		
	
		
			
				
					|  |  |  |  |   flavor = args.flavor; | 
			
		
	
		
			
				
					|  |  |  |  |   isReplace = args.isReplaceMode; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   _ctx.addEntries(FLAVORS.map((e) => MapEntry(e, e))); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -54,39 +61,83 @@ bool modified = false; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | const evaluator = const ExpressionEvaluator(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | // vars for replace mode | 
			
		
	
		
			
				
					|  |  |  |  | int currentLineIndex = 0; | 
			
		
	
		
			
				
					|  |  |  |  | List<ReplaceOperation> operations = []; | 
			
		
	
		
			
				
					|  |  |  |  | List<ReplaceOperation> tempOperations = []; | 
			
		
	
		
			
				
					|  |  |  |  | List<ReplaceOperation> currentTempOperations = []; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | final _commentReg = RegExp(' +\/\/'); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | var lastIndent = -1; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | void walkPath(FileSystemEntity path) { | 
			
		
	
		
			
				
					|  |  |  |  |   var stat = path.statSync(); | 
			
		
	
		
			
				
					|  |  |  |  |   if (stat.type == FileSystemEntityType.directory) { | 
			
		
	
		
			
				
					|  |  |  |  |     Directory(path.path).listSync().forEach(walkPath); | 
			
		
	
		
			
				
					|  |  |  |  |   } else if (stat.type == FileSystemEntityType.file) { | 
			
		
	
		
			
				
					|  |  |  |  |   } else if (stat.type == FileSystemEntityType.file && | 
			
		
	
		
			
				
					|  |  |  |  |       BLACK_FILE_EXT.indexWhere((ele) => path.path.endsWith(ele)) < 0) { | 
			
		
	
		
			
				
					|  |  |  |  |     file = File(path.path); | 
			
		
	
		
			
				
					|  |  |  |  |     sb.clear(); | 
			
		
	
		
			
				
					|  |  |  |  |     modified = false; | 
			
		
	
		
			
				
					|  |  |  |  |     if (isReplace) { | 
			
		
	
		
			
				
					|  |  |  |  |       currentLineIndex = 0; | 
			
		
	
		
			
				
					|  |  |  |  |       operations.clear(); | 
			
		
	
		
			
				
					|  |  |  |  |       tempOperations.clear(); | 
			
		
	
		
			
				
					|  |  |  |  |       currentTempOperations.clear(); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  |     try { | 
			
		
	
		
			
				
					|  |  |  |  |       file!.readAsLinesSync().forEach((line) { | 
			
		
	
		
			
				
					|  |  |  |  |         currentLineIndex++; | 
			
		
	
		
			
				
					|  |  |  |  |         ma = re.firstMatch(line); | 
			
		
	
		
			
				
					|  |  |  |  |         if (ma != null) { | 
			
		
	
		
			
				
					|  |  |  |  |           lastIndent = line.indexOf('// #{{'); | 
			
		
	
		
			
				
					|  |  |  |  |           modified = true; | 
			
		
	
		
			
				
					|  |  |  |  |           exp = ma!.group(1); | 
			
		
	
		
			
				
					|  |  |  |  |           if (exp == "default") { | 
			
		
	
		
			
				
					|  |  |  |  |             if (isReplace) { | 
			
		
	
		
			
				
					|  |  |  |  |               tempOperations.addAll(currentTempOperations); | 
			
		
	
		
			
				
					|  |  |  |  |               currentTempOperations.clear(); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             // 默认代码块开始 | 
			
		
	
		
			
				
					|  |  |  |  |             if (tmp.isNotEmpty) { | 
			
		
	
		
			
				
					|  |  |  |  |               sb.write(tmp); | 
			
		
	
		
			
				
					|  |  |  |  |               print([ | 
			
		
	
		
			
				
					|  |  |  |  |                 "${file!.path} modified", | 
			
		
	
		
			
				
					|  |  |  |  |                 "-" * 80, | 
			
		
	
		
			
				
					|  |  |  |  |                 "${file!.path} modified" + '\n', | 
			
		
	
		
			
				
					|  |  |  |  |                 "-" * 80 + '\n', | 
			
		
	
		
			
				
					|  |  |  |  |                 tmp.toString(), | 
			
		
	
		
			
				
					|  |  |  |  |                 "-" * 80, | 
			
		
	
		
			
				
					|  |  |  |  |               ].join("\n")); | 
			
		
	
		
			
				
					|  |  |  |  |                 "-" * 80 + '\n', | 
			
		
	
		
			
				
					|  |  |  |  |               ].join()); | 
			
		
	
		
			
				
					|  |  |  |  |               state = STATE.replace; | 
			
		
	
		
			
				
					|  |  |  |  |             } else { | 
			
		
	
		
			
				
					|  |  |  |  |               state = STATE.none; | 
			
		
	
		
			
				
					|  |  |  |  |               state = STATE.inDefault; | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |           } else if (exp == "end") { | 
			
		
	
		
			
				
					|  |  |  |  |             // 默认代码块结束 | 
			
		
	
		
			
				
					|  |  |  |  |             state = STATE.none; | 
			
		
	
		
			
				
					|  |  |  |  |             if (isReplace) { | 
			
		
	
		
			
				
					|  |  |  |  |               if (tmp.isEmpty) { | 
			
		
	
		
			
				
					|  |  |  |  |                 // 说明匹配到了默认代码块,应该将之前的代码全注释掉 | 
			
		
	
		
			
				
					|  |  |  |  |                 tempOperations.forEach((ele) => ele.commented = true); | 
			
		
	
		
			
				
					|  |  |  |  |               } else { | 
			
		
	
		
			
				
					|  |  |  |  |                 // 之前有匹配到的代码块,应该将默认代码块注释掉 | 
			
		
	
		
			
				
					|  |  |  |  |                 currentTempOperations.forEach((ele) => ele.commented = true); | 
			
		
	
		
			
				
					|  |  |  |  |               } | 
			
		
	
		
			
				
					|  |  |  |  |               tempOperations.addAll(currentTempOperations); | 
			
		
	
		
			
				
					|  |  |  |  |               operations.addAll(tempOperations); | 
			
		
	
		
			
				
					|  |  |  |  |               tempOperations.clear(); | 
			
		
	
		
			
				
					|  |  |  |  |               currentTempOperations.clear(); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |             tmp.clear(); | 
			
		
	
		
			
				
					|  |  |  |  |           } else { | 
			
		
	
		
			
				
					|  |  |  |  |             if (isReplace) { | 
			
		
	
		
			
				
					|  |  |  |  |               if (currentTempOperations.isNotEmpty && | 
			
		
	
		
			
				
					|  |  |  |  |                   !currentTempOperations.first.commented) | 
			
		
	
		
			
				
					|  |  |  |  |                 tempOperations.forEach((ele) => ele.commented = true); | 
			
		
	
		
			
				
					|  |  |  |  |               tempOperations.addAll(currentTempOperations); | 
			
		
	
		
			
				
					|  |  |  |  |               currentTempOperations.clear(); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |             if (evaluator.eval(Expression.parse(exp!), _ctx)) { | 
			
		
	
		
			
				
					|  |  |  |  |               // 匹配到 | 
			
		
	
		
			
				
					|  |  |  |  |               tmp.clear(); | 
			
		
	
	
		
			
				
					|  |  |  | @ -97,19 +148,47 @@ void walkPath(FileSystemEntity path) { | 
			
		
	
		
			
				
					|  |  |  |  |           } | 
			
		
	
		
			
				
					|  |  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |  |           // none状态时直接将line写入sb | 
			
		
	
		
			
				
					|  |  |  |  |           if (state == STATE.none) { | 
			
		
	
		
			
				
					|  |  |  |  |           if ([STATE.none, STATE.inDefault].contains(state)) { | 
			
		
	
		
			
				
					|  |  |  |  |             sb.writeln(line); | 
			
		
	
		
			
				
					|  |  |  |  |           } | 
			
		
	
		
			
				
					|  |  |  |  |           // 缓存中状态,将用于替换的内容移除注释后写入缓存 | 
			
		
	
		
			
				
					|  |  |  |  |           else if (state == STATE.caching) | 
			
		
	
		
			
				
					|  |  |  |  |             tmp.writeln(line.replaceFirst('// ', '')); | 
			
		
	
		
			
				
					|  |  |  |  |           // 这样就跳过了没有匹配上的替换代码块和默认内容 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |           if (isReplace && | 
			
		
	
		
			
				
					|  |  |  |  |               [STATE.notMatch, STATE.caching, STATE.replace, STATE.inDefault] | 
			
		
	
		
			
				
					|  |  |  |  |                   .contains(state)) { | 
			
		
	
		
			
				
					|  |  |  |  |             currentTempOperations.add(ReplaceOperation( | 
			
		
	
		
			
				
					|  |  |  |  |                 currentLineIndex, lastIndent, state == STATE.notMatch)); | 
			
		
	
		
			
				
					|  |  |  |  |           } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |       }); | 
			
		
	
		
			
				
					|  |  |  |  |       if (modified) { | 
			
		
	
		
			
				
					|  |  |  |  |         if (isReplace) { | 
			
		
	
		
			
				
					|  |  |  |  |           operations.forEach((ele) { | 
			
		
	
		
			
				
					|  |  |  |  |             print('${ele.lineNumber} : ${ele.commented}'); | 
			
		
	
		
			
				
					|  |  |  |  |           }); | 
			
		
	
		
			
				
					|  |  |  |  |           file!.readAsLines().then((lines) { | 
			
		
	
		
			
				
					|  |  |  |  |             operations.forEach((operation) { | 
			
		
	
		
			
				
					|  |  |  |  |               if (operation.commented && | 
			
		
	
		
			
				
					|  |  |  |  |                   !lines[operation.lineNumber - 1].startsWith(_commentReg)) | 
			
		
	
		
			
				
					|  |  |  |  |                 lines[operation.lineNumber - 1] = | 
			
		
	
		
			
				
					|  |  |  |  |                     '${' ' * operation.indent}// ${lines[operation.lineNumber - 1].substring(operation.indent)}'; | 
			
		
	
		
			
				
					|  |  |  |  |               else if (!operation.commented && | 
			
		
	
		
			
				
					|  |  |  |  |                   lines[operation.lineNumber - 1].startsWith(_commentReg)) | 
			
		
	
		
			
				
					|  |  |  |  |                 lines[operation.lineNumber - 1] = | 
			
		
	
		
			
				
					|  |  |  |  |                     lines[operation.lineNumber - 1].replaceFirst('// ', ''); | 
			
		
	
		
			
				
					|  |  |  |  |             }); | 
			
		
	
		
			
				
					|  |  |  |  |             print(lines.join('\n')); | 
			
		
	
		
			
				
					|  |  |  |  |             file!.deleteSync(); | 
			
		
	
		
			
				
					|  |  |  |  |             File(path.path).writeAsStringSync(lines.join('\n'), flush: true); | 
			
		
	
		
			
				
					|  |  |  |  |           }); | 
			
		
	
		
			
				
					|  |  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |  |           file!.renameSync(path.path + '.bak'); | 
			
		
	
		
			
				
					|  |  |  |  |           File(path.path).writeAsStringSync(sb.toString(), flush: true); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |  |     } catch (e) { | 
			
		
	
		
			
				
					|  |  |  |  |       if (!(e is FileSystemException)) { | 
			
		
	
		
			
				
					|  |  |  |  |         rethrow; | 
			
		
	
	
		
			
				
					|  |  |  | @ -117,3 +196,11 @@ void walkPath(FileSystemEntity path) { | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | class ReplaceOperation { | 
			
		
	
		
			
				
					|  |  |  |  |   int lineNumber; | 
			
		
	
		
			
				
					|  |  |  |  |   int indent; | 
			
		
	
		
			
				
					|  |  |  |  |   bool commented; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   ReplaceOperation(this.lineNumber, this.indent, this.commented); | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
	
		
			
				
					|  |  |  | 
 |